跳转至

研究方案

1295 个字 204 行代码 预计阅读时间 8 分钟

基于 F:\ROS\ocs2_ros2\ocs2_ros2 真实代码结构制定 目标:利用 OCS2-ROS2 实现四足机器人感知楼梯、规划步态、稳定上下楼


项目定位与技术路线总览

传感器感知(LiDAR/深度相机)
        │
        ▼
地形点云 → 平面分割(convex_plane_decomposition)
        │
        ▼
SegmentedPlanesTerrainModel(terrain接口)
        │
        ▼
SwingTrajectoryPlanner(感知版)落脚点规划 + 摆腿轨迹
        │
        ▼
OCS2 MPC(SQP求解器)—— 质心动力学 + 约束优化
        │
        ▼
关节力矩指令 → 机器人执行器

技术选择: - 求解器:SQPocs2_sqp)—— 实时性最好,适合含地形约束的问题 - 动力学模型:SRBD(Single Rigid Body Dynamics,task.info centroidalModelType 1) - 感知接入:复用 advance examples/ocs2_perceptive_anymal 中的 SegmentedPlanesTerrainModel + TerrainModel 接口 - 仿真环境:Gazebo / Isaac Sim(或先用 OCS2 内置 dummy 节点验证)


先修知识学习

理论基础

领域 核心内容 推荐资料
最优控制 LQR、DDP、SQP 基础 ETH Zurich OCS2 论文(Farshidian 2017)
质心动力学 SRBD 模型、角动量、ZMP Wensing & Orin 2013
步态规划 接触时序、摆腿轨迹 MIT Cheetah / ANYmal 相关论文
ROS2 节点 / 话题 / 服务 /launch ROS2 官方文档
Pinocchio 刚体动力学库 pinocchio 官方文档

代码基础

  • C++17(智能指针、lambda、模板)
  • Eigen 矩阵库
  • CMake / colcon 构建系统

环境搭建与编译

依赖安装

# Ubuntu 22.04 + ROS2 Humble
sudo apt install ros-humble-pinocchio
sudo apt install ros-humble-grid-map
pip install convex_plane_decomposition  # 或从源码编译

# 子模块初始化(重要!)
cd F:/ROS/ocs2_ros2/ocs2_ros2
git submodule update --init --recursive

编译顺序

cd ~/ros2_ws
# 将 ocs2_ros2 软链接或复制到 src/
colcon build --packages-up-to ocs2_legged_robot_ros --cmake-args -DCMAKE_BUILD_TYPE=RelWithDebInfo

首次运行验证

# 终端1:启动MPC节点(SQP求解器)
ros2 launch ocs2_legged_robot_ros legged_robot_sqp.launch.py

# 终端2:查看话题
ros2 topic list
# 应该看到 /legged_robot_mpc_observation, /legged_robot_mpc_policy 等

核心代码精读路线图(第 3-5 周)

理解基础框架(basic examples/ocs2_legged_robot

必读文件清单(按顺序)

① 配置文件(最先读)

文件路径 重点内容
config/mpc/task.info MPC 时域 (1.0s)SQP 参数、状态权重 Q 矩阵、控制权重 R 矩阵、摩擦系数 (0.5)
config/command/gait.info 12 种步态定义:trot(0.7s 周期 )/static_walk/stance 等,modeSequence LF_RH 等含义
config/command/reference.info 站立高度 (comHeight=0.575m)、默认关节角度、初始模式序列

关键读点 — task.info

swing_trajectory_config {
  swingHeight  0.1      ← 摆腿高度,上楼梯需要增大至 0.15~0.20
  liftOffVelocity   0.2  ← 抬腿初速度
  touchDownVelocity -0.4 ← 落脚速度
}
mpc {
  timeHorizon  1.0      ← 预测时域,楼梯场景建议增到 1.5~2.0s
  mpcDesiredFrequency  50  ← MPC频率
  mrtDesiredFrequency  400 ← 控制频率
}

② 接口类(理解整体结构)

include/ocs2_legged_robot/LeggedRobotInterface.h
这是整个模块的入口,读懂以下方法: - setupOptimalConrolProblem() — 搭建OCP问题(代价+约束+动力学) - getBaseTrackingCost() — 读取Q/R矩阵 - getFrictionConeConstraint() — 摩擦锥约束(楼梯边缘关键) - loadGaitSchedule() — 加载步态

③ 步态相关

include/ocs2_legged_robot/gait/
├── Gait.h            ← 步态结构体(modeSequence + switchingTimes)
├── GaitSchedule.h    ← 步态调度器,管理步态切换
├── LegLogic.h        ← 从mode解析各腿接触状态(核心!)
└── MotionPhaseDefinition.h  ← STANCE/LF_RH等枚举定义

④ 落脚点规划(基础版)

include/ocs2_legged_robot/foot_planner/
├── SwingTrajectoryPlanner.h  ← 摆腿轨迹(Z方向位置+速度约束)
├── SplineCpg.h               ← 样条曲线中央模式生成器
└── CubicSpline.h             ← 三次样条

注意:基础版的 SwingTrajectoryPlanner::update() 只接受 terrainHeight(单一高度不支持感知地形,这是后续需要升级的核心。

⑤ 约束文件

include/ocs2_legged_robot/constraint/
├── FrictionConeConstraint.h         ← 摩擦锥(接触力必须在摩擦锥内)
├── ZeroForceConstraint.h            ← 摆动腿接触力为零
├── ZeroVelocityConstraintCppAd.h    ← 站立腿速度为零
└── NormalVelocityConstraintCppAd.h  ← 法向速度约束

理解感知版框架(advance examples/ocs2_perceptive_anymal

感知相关必读文件

⑥ 地形模型接口(核心抽象)

ocs2_switched_model_interface/include/.../terrain/TerrainModel.h
// 关键接口方法:
TerrainPlane getLocalTerrainAtPositionInWorldAlongGravity(positionInWorld);
// 给定世界坐标,返回该点下方的局部地形平面(法向量+位置)

ConvexTerrain getConvexTerrainAtPositionInWorld(positionInWorld);
// 返回凸多边形地形区域(用于落脚点约束)

vector3_t getHighestObstacleAlongLine(pos1, pos2);
// 返回摆腿路径上最高障碍点(楼梯台阶关键!)

std::vector<vector2_t> getHeightProfileAlongLine(pos1, pos2);
// 返回两点间高度剖面(用于调整摆腿高度)

⑦ 分段平面地形模型(楼梯感知的实现)

segmented_planes_terrain_model/include/
├── SegmentedPlanesTerrainModel.h    ← TerrainModel的具体实现
├── SegmentedPlanesTerrainModelRos.h ← ROS2订阅接口(订阅planar_terrain话题)
└── SegmentedPlanesSignedDistanceField.h ← SDF距离场

SegmentedPlanesTerrainModelRos 订阅 convex_plane_decomposition_msgs/PlanarTerrain,这是从点云地形分割算法输出的平面区域信息。

⑧ 感知版摆腿规划器

ocs2_switched_model_interface/include/.../foot_planner/SwingTrajectoryPlanner.h
对比基础版,感知版增加了: - updateTerrain(terrainModel) — 注入地形模型 - sdfMidswingMargin — 摆腿中间点与障碍的SDF安全距离 - selectNominalFootholdTerrain() — 在凸地形区域内选择落脚点 - getHighestObstacleAlongLine() — 自动调整摆腿高度越过楼梯台阶

项目实施步骤(第 5-16 周)

Phase 1:跑通基础四足仿真(第 5-6 周)

目标:在平地上跑通 legged_robot_sqp,理解数据流。

# Step 1: 编译
colcon build --packages-up-to ocs2_legged_robot_ros

# Step 2: 启动
ros2 launch ocs2_legged_robot_ros legged_robot_sqp.launch.py

# Step 3: 发送步态指令(在gait_command终端)
# 输入: trot

# Step 4: 发送目标位置(在robot_target终端)
# 输入: 1.0 0.0 0.0 0.0 (x y z yaw)

观察重点: - RViz中机器人运动是否符合预期 - 话题 /legged_robot_mpc_observation 的发布频率 - 终端中SQP求解时间(应 < 20ms)


Phase 2:接入感知地形模型(第 7-9 周)

安装地形感知依赖

# convex_plane_decomposition(ETH开源)
cd ~/ros2_ws/src
git clone https://github.com/leggedrobotics/convex_plane_decomposition.git
git clone https://github.com/leggedrobotics/grid_map.git
colcon build --packages-up-to convex_plane_decomposition

编译感知模块

colcon build --packages-up-to segmented_planes_terrain_model ocs2_anymal_mpc

理解数据流

LiDAR/深度相机
    │  PointCloud2
    ▼
elevation_mapping(高程图)
    │  GridMap(elevation layer)
    ▼
convex_plane_decomposition_ros
    │  PlanarTerrain.msg
    ▼
SegmentedPlanesTerrainModelRos::callback()
    │  SegmentedPlanesTerrainModel
    ▼
SwingTrajectoryPlanner::updateTerrain()
    │  感知落脚点选择
    ▼
MPC优化求解

需要修改的文件

修改 1:为 ocs2_legged_robot 添加地形接口

基础版 SwingTrajectoryPlanner 不支持地形,需要升级。有两个选择:

方案 A(推荐:直接复用 ocs2_switched_model_interface 的感知版 - 复制 advance examples/ocs2_perceptive_anymal/ 整个模块 - 将 Anymal 特定的 URDF/参数替换为你的机器人

方案 B:在现有 legged_robot 基础上添加地形支持

修改文件:basic examples/ocs2_legged_robot/include/ocs2_legged_robot/foot_planner/SwingTrajectoryPlanner.h

// 添加地形接口方法:
void updateTerrain(std::unique_ptr<TerrainModel> terrainModel);

// 修改 update() 方法签名:
void update(const ModeSchedule& modeSchedule,
            const feet_array_t<scalar_array_t>& liftOffHeightSequence,
            const feet_array_t<scalar_array_t>& touchDownHeightSequence);
            // 改为从地形模型动态获取高度

修改文件:basic examples/ocs2_legged_robot/src/foot_planner/SwingTrajectoryPlanner.cpp

// 核心改动:在计算摆腿高度时,查询地形模型
scalar_t getAdaptiveSwingHeight(size_t leg, scalar_t liftOffX, scalar_t touchDownX) {
    // 1. 获取摆腿路径上的最高障碍
    vector3_t liftOffPos = ...; // 从当前状态获取
    vector3_t touchDownPos = ...; // 从规划落脚点获取
    vector3_t highestObstacle = terrainModel_->getHighestObstacleAlongLine(liftOffPos, touchDownPos);
    
    // 2. 自适应摆腿高度 = max(默认高度, 障碍高度 + 安全余量)
    scalar_t safetyMargin = 0.05; // 5cm 安全余量
    return std::max(config_.swingHeight,
                    highestObstacle.z() - liftOffPos.z() + safetyMargin);
}

Phase 3:楼梯步态参数调整(第 9-11 周)

修改 task.info(关键参数调整)

文件:basic examples/ocs2_legged_robot/config/mpc/task.info

; === 楼梯场景参数修改 ===

swing_trajectory_config
{
  liftOffVelocity     0.3      ; 原0.2,增大抬腿速度
  touchDownVelocity  -0.3      ; 原-0.4,减小落脚冲击
  swingHeight         0.15     ; 原0.1,增大摆腿高度(楼梯台阶约0.18m)
  touchdownAfterHorizon  0.2
  swingTimeScale      0.15
}

mpc
{
  timeHorizon         1.5      ; 原1.0,增大预测时域覆盖至少一个完整步态
  mpcDesiredFrequency 50
  mrtDesiredFrequency 400
}

; 摩擦锥约束:楼梯表面可能不如平地,适当降低摩擦系数
frictionConeSoftConstraint
{
  frictionCoefficient  0.4    ; 原0.5,楼梯更保守
  mu                   0.1
  delta                5.0
}

; 状态权重调整:加强高度和姿态保持
Q
{
  scaling 1e+0
  (8,8)   800.0    ; p_base_z 原500,上楼梯高度追踪更重要
  (10,10) 300.0    ; theta_base_y 原200,俯仰角保持更重要
  (11,11) 300.0    ; theta_base_x 原200,滚转角保持更重要
}

添加 / 修改步态(gait.info)

文件:basic examples/ocs2_legged_robot/config/command/gait.info

; 为楼梯添加"慢速静态步行"步态
stair_walk
{
  modeSequence
  {
    [0]  LF_RF_RH   ; 抬左前腿,三腿支撑
    [1]  RF_LH_RH   ; 抬左后腿,三腿支撑
    [2]  LF_RF_LH   ; 抬右前腿,三腿支撑
    [3]  LF_LH_RH   ; 抬右后腿,三腿支撑
  }
  switchingTimes
  {
    [0]  0.0
    [1]  0.4         ; 每腿支撑0.4s(比static_walk的0.3s更慢,更稳)
    [2]  0.8
    [3]  1.2
    [4]  1.6
  }
}

修改 reference.info(楼梯高度跟踪)

文件:basic examples/ocs2_legged_robot/config/command/reference.info

; 机器人重心高度随楼梯台阶动态调整
; 需要在代码中实现动态comHeight更新(不是静态配置)
comHeight  0.575    ; 平地默认值,上楼梯时由reference_manager动态修改

Phase 4:落脚点规划与地形自适应(第 11-13 周)

实现楼梯落脚点选择器

新建文件include/ocs2_legged_robot/foot_planner/StairFootholdPlanner.h

namespace ocs2::legged_robot {

class StairFootholdPlanner {
public:
    struct Config {
        scalar_t stepWidth = 0.12;       // 足端横向间距
        scalar_t stepLength = 0.28;      // 步长(小于台阶深度)
        scalar_t safetyMarginFromEdge = 0.03; // 离台阶边缘安全距离
        scalar_t minStepHeight = 0.005;  // 低于此值认为是平地
    };

    // 核心方法:给定期望落脚位置和地形,返回安全落脚点
    vector3_t selectSafeFoothold(
        const vector3_t& nominalFoothold,
        const TerrainModel& terrain,
        size_t legIndex) const;

private:
    // 检查落脚点是否在平面区域内(不在台阶边缘)
    bool isFootholdSafe(const vector3_t& foothold,
                        const ConvexTerrain& localTerrain) const;

    Config config_;
};

} // namespace

修改参考管理器

修改文件include/ocs2_legged_robot/reference_manager/SwitchedModelReferenceManager.h

关键改动:在 modifyReferences() 中接收地形信息并动态调整: - 根据前方地形高度调整 comHeight(机器人重心高度) - 将地形信息传入 SwingTrajectoryPlanner


Phase 5:感知传感器接入(第 12-14 周)

传感器选型与驱动

推荐传感器方案

选项A(仿真):Gazebo深度相机 → depth_image_proc → PointCloud2
选项B(实物):Intel RealSense D435i → realsense2_driver → PointCloud2
选项C(实物):Velodyne VLP-16 LiDAR → velodyne_driver → PointCloud2

感知流水线搭建

# 安装高程图包
sudo apt install ros-humble-elevation-mapping

# 安装平面分割包(从源码)
cd ~/ros2_ws/src
git clone https://github.com/leggedrobotics/convex_plane_decomposition_ros.git
colcon build --packages-up-to convex_plane_decomposition_ros

新建 launch 文件launch/stair_climbing.launch.py

def generate_launch_description():
    return LaunchDescription([
        # 1. 机器人状态发布
        Node(package='robot_state_publisher', ...),

        # 2. 高程图构建
        Node(package='elevation_mapping',
             executable='elevation_mapping',
             parameters=[{'sensor_processor/type': 'structured_light',
                          'robot_base_frame_id': 'base'}]),

        # 3. 平面分割
        Node(package='convex_plane_decomposition_ros',
             executable='convex_plane_decomposition_node',
             parameters=[{'input_topic': '/elevation_map'}]),

        # 4. OCS2 MPC(感知版)
        Node(package='ocs2_legged_robot_ros',
             executable='legged_robot_sqp_mpc',
             parameters=[{'taskFile': task_file,
                          'enable_terrain': True}]),  # 新增地形开关

        # 5. 仿真/可视化
        Node(package='rviz2', ...),
    ])

Phase 6:仿真验证(第 14-16 周)

Gazebo 楼梯搭建

<!-- 在 Gazebo world 中添加楼梯模型 -->
<model name="staircase">
  <static>true</static>
  <!-- 5级台阶,每级高0.15m,深0.30m,宽1.2m -->
  <link name="step_0">
    <collision><geometry><box><size>1.2 0.30 0.15</size></box></geometry></collision>
    <visual>...</visual>
    <pose>0 0 0.075 0 0 0</pose>
  </link>
  <!-- ... step_1 到 step_4 ... -->
</model>

验证指标

指标 目标值 测试方法
上楼成功率 > 90% 运行 20
MPC 求解时间 < 20ms rostopic hz
机体俯仰角波动 < ±5° 录制 bag
落脚点精度 < 3cm 误差 与台阶中心比较

文件改动总览

需要精读但不改动的文件

core/ocs2_core/                    ← 理解数学基础
├── integration/                    ← ODE积分器
└── automatic_differentiation/      ← CppAD原理

mpc/ocs2_sqp/ocs2_sqp/            ← 理解SQP求解流程
robotics/ocs2_pinocchio/           ← 理解Pinocchio动力学

basic examples/ocs2_legged_robot/
├── include/ocs2_legged_robot/dynamics/     ← SRBD动力学(不改)
├── include/ocs2_legged_robot/gait/         ← 步态逻辑(精读)
└── include/ocs2_legged_robot/constraint/   ← 约束定义(理解)

advance examples/ocs2_perceptive_anymal/
├── ocs2_switched_model_interface/terrain/  ← TerrainModel接口(精读)
└── segmented_planes_terrain_model/         ← 具体实现(精读)

需要修改调参的文件

basic examples/ocs2_legged_robot/config/
├── mpc/task.info          ⭐⭐⭐ 最重要!修改swingHeight/timeHorizon/Q权重
├── command/gait.info      ⭐⭐  添加 stair_walk 步态
└── command/reference.info ⭐   修改comHeight(或动态调整)

需要新建 / 大改的文件

文件 改动内容 难度
foot_planner/SwingTrajectoryPlanner.cpp 添加地形感知摆腿高度自适应 ⭐⭐⭐⭐
reference_manager/SwitchedModelReferenceManager.cpp 接入地形模型,动态调整 comHeight ⭐⭐⭐⭐
LeggedRobotInterface.cpp 添加地形模块初始化 ⭐⭐⭐
launch/stair_climbing.launch.py 新建包含感知流水线的 launch ⭐⭐
foot_planner/StairFootholdPlanner.h/cpp 新建楼梯落脚点规划器 ⭐⭐⭐⭐

直接复用的文件(来自 perceptive_anymal

advance examples/ocs2_perceptive_anymal/
├── segmented_planes_terrain_model/   ← 整个包直接复用,只修改CMakeLists依赖
└── ocs2_switched_model_interface/
    └── terrain/                       ← TerrainModel接口整体复用

调试与优化技巧

常见问题排查

问题 1MPC 求解超时(>20ms)

; task.info 中降低求解精度
sqp {
  sqpIteration  1       ; 只迭代1次
  nThreads      4       ; 增加线程数
  dt            0.02    ; 增大时间步长(降低精度但加速)
}

问题 2:机器人上楼时摔倒

; 增大摆腿高度和降低速度
swing_trajectory_config {
  swingHeight     0.20   ; 增大
  swingTimeScale  0.20   ; 增大(减慢)
}
; 同时增大俯仰角权重
Q { (10,10) 400.0 }

问题 3:落脚点偏差大 - 检查 elevation_mappingrobot_pose_cache_size 参数 - 增大 previousFootholdFactor(利用上一次落脚点) - 检查传感器到机体的外参标定

性能优化

CppAD 代码生成加速:
  task.info: recompileLibrariesCppAd  false  (第一次设true生成,之后设false跳过)
  modelFolderCppAd  /tmp/ocs2  (确保路径可写)

多线程:
  sqp { nThreads 6 }  (根据CPU核数调整)

里程碑与时间规划

理论学习 + 环境搭建
跑通基础 legged_robot_sqp(平地trot)
阅读感知模块代码,理解TerrainModel接口
接入 convex_plane_decomposition 感知流水线
修改 SwingTrajectoryPlanner 支持地形自适应
调整 task.info 参数,实现楼梯步态
Gazebo楼梯仿真验证(上楼)
Gazebo仿真验证(下楼 + 连续上下)
性能优化 + 实验数据整理

参考论文与资源

类别 资源
OCS2 框架 Farshidian et al., "An Efficient Optimal Planning and Control Framework For Quadrupedal Locomotion", ICRA 2017
感知行走 Grandia et al., "Perceptive Locomotion through Nonlinear Model-Predictive Control", T-RO 2023
质心动力学 Wensing & Orin, "Generation of Dynamic Humanoid Behaviors", ICRA 2013
楼梯行走 Kim et al., "Stair Climbing for Legged Robots", RAL 2020
convex_plane_decomposition Fankhauser et al., "Robust Rough-Terrain Locomotion", ICRA 2018
代码仓库 legubiao/ocs2_ros2