研究方案 ¶
约 1295 个字 204 行代码 预计阅读时间 8 分钟
基于
F:\ROS\ocs2_ros2\ocs2_ros2真实代码结构制定 目标:利用 OCS2-ROS2 实现四足机器人感知楼梯、规划步态、稳定上下楼
项目定位与技术路线总览 ¶
传感器感知(LiDAR/深度相机)
│
▼
地形点云 → 平面分割(convex_plane_decomposition)
│
▼
SegmentedPlanesTerrainModel(terrain接口)
│
▼
SwingTrajectoryPlanner(感知版)落脚点规划 + 摆腿轨迹
│
▼
OCS2 MPC(SQP求解器)—— 质心动力学 + 约束优化
│
▼
关节力矩指令 → 机器人执行器
技术选择: - 求解器:SQP(ocs2_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接口整体复用
调试与优化技巧 ¶
常见问题排查 ¶
问题 1:MPC 求解超时(>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_mapping 的 robot_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 |