Language / 语言: English | 中文
CAPO-LeggedRobotOdometry is a ROS 2 (Humble) proprioceptive odometry / state-estimation repository for biped / quadruped / wheel-legged robots on Ubuntu 22.04.
It provides high-accuracy odometry using only IMU + joint encoders + foot contact/force signals, without requiring cameras or LiDAR.
In 3D closed-loop trials (a 200 m horizontal and 15 m vertical loop), Astrall point-foot robot A achieves 0.1638 m horizontal error and 0.219 m vertical error; for wheel-legged robot B, the corresponding errors are 0.2264 m and 0.199 m.
At the repository level, fusion_estimator_node.cpp is mainly the ROS2 wrapper (topics, parameters, message conversion, publishing), while the actual fusion-estimation algorithm lives in FusionEstimator/ as a portable, pure C++ implementation. This makes it straightforward to port the estimator to ROS1, non-ROS2 applications, or embedded platforms.
In addition, the Matlab/ folder provides a MATLAB + MEX example that compiles and calls the same C++ estimator core for offline validation, algorithm analysis, and cross-platform reuse.
Contact-Anchored Proprioceptive Odometry for Quadruped Robots (arXiv:2602.17393)
If you use this repository in research, please consider citing the paper.
To help readers quickly validate the pipeline, we provide two Go2-EDU trial datasets, including real-world videos and the corresponding ROS bag topics/messages required by this node, enabling fast reproduction and sanity checks.
- Download (Google Drive): https://drive.google.com/drive/folders/1FfVO69rfmUu6B9crPhZCfKf9wFnV4L7n?usp=sharing
Note: the IMU on this Go2-EDU platform exhibits noticeable yaw drift, so the odometry accuracy is generally worse than the results reported for Astrall robots A and B in the paper.
| Category | Description |
|---|---|
| Biped / Quadruped / Wheel-Legged Unified | Online contact-set switching; stance legs are detected automatically, supporting fast transitions between standing and walking. |
| Full 3D & Planar 2D | Publishes both 6DoF odometry (SMX/Odom) and a gravity-flattened 2D odometry (SMX/Odom_2D). |
| No Exteroception Required | Works without cameras or LiDAR; only IMU, joint encoders, and foot contact/force signals are required. |
| Portable Pure C++ Core | The estimator core is isolated in FusionEstimator/, making it easier to reuse outside ROS2. |
| MATLAB / MEX Validation | The Matlab/ folder demonstrates how to compile and invoke the same C++ core from MATLAB. |
| Runtime Tuning | Key parameters can be adjusted through config.yaml, and platform-dependent thresholds can be tuned for different robots. |
| Scope | Repository | Summary |
|---|---|---|
| Low-level / Drivers | https://github.com/ShineMinxing/Ros2Go2Base | DDS bridge, Unitree SDK2 control, pointcloud→LaserScan, TF utilities |
| Odometry | CAPO-LeggedRobotOdometry (this repo) | Pure proprioceptive fusion, publishes SMX/Odom / SMX/Odom_2D |
| SLAM / Mapping | https://github.com/ShineMinxing/Ros2SLAM | Integrations for Cartographer 3D, KISS-ICP, FAST-LIO2, Point-LIO |
| Voice / LLM | https://github.com/ShineMinxing/Ros2Chat | Offline ASR + OpenAI Chat + TTS |
| Vision | https://github.com/ShineMinxing/Ros2ImageProcess | Camera pipelines, spot / face / drone detection |
| Gimbal Tracking | https://github.com/ShineMinxing/Ros2AmovG1 | Amov G1 gimbal control and tracking |
| Tools | https://github.com/ShineMinxing/Ros2Tools | Bluetooth IMU, joystick mapping, gimbal loop, data logging |
⚠️ Clone as needed. If you only need state estimation, this repository is sufficient. For mapping, it is natural to pair it withRos2SLAMandRos2Go2Base.
CAPO-LeggedRobotOdometry/
├── CMakeLists.txt
├── package.xml
├── config.yaml
├── fusion_estimator_node.cpp # ROS2 node wrapper: params / topics / odom publishing
├── FusionEstimator/ # pure C++ fusion-estimation core (portable)
│ ├── Estimators/
│ ├── fusion_estimator.h
│ ├── LowlevelState.h
│ ├── SensorBase.cpp
│ ├── SensorBase.h
│ ├── Sensor_IMU.cpp
│ ├── Sensor_IMU.h
│ ├── Sensor_Legs.cpp
│ ├── Sensor_Legs.h
│ └── Readme.md
├── Matlab/ # MATLAB + MEX example for calling the C++ core
│ ├── build_mex.m
│ ├── fusion_estimator.m
│ ├── fusion_estimator_mex.cpp
│ ├── MPXY150Z10.csv
│ └── MWXY150Z10.csv
├── Plotjuggler.xml # PlotJuggler layout / visualization helper
└── Readme.md
This repository is intentionally split into two layers:
fusion_estimator_node.cpp is responsible for:
- reading parameters from
config.yaml - subscribing to ROS2 topics
- converting ROS messages into estimator inputs
- invoking the fusion-estimation core
- publishing
nav_msgs/Odometry
FusionEstimator/ contains the actual estimation logic:
- IMU handling
- leg kinematics / leg sensors
- contact-anchored fusion logic
- estimator state update
- reusable C++ interfaces
Because this part is pure C++, it can be reused in:
- ROS1
- non-ROS Linux applications
- embedded / custom runtime systems
- MATLAB via MEX
Matlab/ is not required for ROS2 runtime, but it is useful when you want to:
- validate the estimator offline
- replay data in MATLAB
- compare C++ results with MATLAB scripts
- reuse the same
FusionEstimator/core without ROS2
The table below lists the main parameters used by the ROS2 node. See config.yaml for the full file and comments.
| Parameter | Typical Value | Meaning |
|---|---|---|
sub_imu_topic |
SMX/Go2IMU |
IMU topic |
sub_joint_topic |
SMX/Go2Joint |
joint state topic |
sub_mode_topic |
SMX/SportCmd |
reset / mode topic |
pub_odom_topic |
SMX/Odom |
6DoF odometry output |
pub_odom2d_topic |
SMX/Odom_2D |
planar odometry output |
odom_frame |
odom |
odometry frame |
base_frame |
base_link |
body frame |
base_frame_2d |
base_link_2D |
planar body frame |
imu_data_enable |
true |
enable IMU input |
leg_pos_enable |
true |
enable leg-position kinematics |
leg_vel_enable |
true |
enable leg-velocity kinematics |
leg_ori_enable |
false |
enable kinematics-based yaw correction |
leg_ori_init_weight |
0.001 |
initial weight of orientation correction |
leg_ori_time_wight |
1000.0 |
time-related growth weight for orientation correction |
leg_velcke_enable |
false |
enable IKVel-CKF / CAPO-CKE |
foot_force_threshold |
20.0 |
contact threshold |
min_stair_height |
0.08 |
minimum stair-height hypothesis used by the estimator |
Notes:
- The exact values are platform-dependent.
- Some fields in
config.yamlmay be experimental, legacy, or intended for specific branches / workflows.- If you port only the pure C++ core, you usually need to keep only the estimator-relevant fields and can drop ROS2-specific naming.
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
git clone --depth 1 https://github.com/ShineMinxing/CAPO-LeggedRobotOdometry.git
cd ~/ros2_ws
colcon build --packages-select fusion_estimator
source install/setup.bash
ros2 run fusion_estimator fusion_estimator_nodeIf you want to use optional sample CSV files or large assets, you may need Git LFS:
sudo apt update
sudo apt install git-lfs
git lfs install
cd ~/ros2_ws/src/CAPO-LeggedRobotOdometry
git lfs pullNote: in some versions of this repository, the node loads
config.yamlthrough a hard-coded--params-filepath insidefusion_estimator_node.cpp. If your local workspace path differs, update that path and rebuild.
/fusion_estimator_node (rclcpp)
├─ Publishes
│ • SMX/Odom nav_msgs/Odometry (odom → base_link)
│ • SMX/Odom_2D nav_msgs/Odometry (odom → base_link_2D)
├─ Subscribes
│ • SMX/Go2IMU sensor_msgs/Imu
│ • SMX/Go2Joint std_msgs/Float64MultiArray
│ layout:
│ data[0..11] = 12 joint positions q
│ data[12..23] = 12 joint velocities dq
│ data[24..27] = 4 foot-force / contact-related values
│ • SMX/SportCmd std_msgs/Float64MultiArray
│ reset example:
│ data[0] == 25140000 → estimator reset
└─ TF is typically published by another node / utility if needed
-
Contact detection
Detect stance legs from force / threshold logic. -
Forward kinematics
Compute foot-end position / velocity in the body frame from joint measurements. -
Contact anchoring
Record touchdown footfall points and use them as intermittent world-frame constraints during stance. -
Height stabilization
Use support-plane height logic and confidence decay to reduce long-horizon elevation drift. -
Optional IKVel-CKF (CAPO-CKE)
Suppress encoder-induced velocity spikes and obtain smoother leg-end velocity estimates. -
Optional yaw stabilization
Use multi-contact geometric consistency to reduce IMU yaw drift during prolonged standing. -
2D projection
Publish a planar odometry (SMX/Odom_2D) by flattening roll / pitch while preserving yaw and planar motion.
For full derivations, please refer to the paper.
If you do not need ROS2, the reusable part is mainly under FusionEstimator/.
A typical migration path is:
- keep the estimator core in
FusionEstimator/ - replace ROS2 message subscriptions with your own sensor interface
- prepare IMU, joint position / velocity, and contact / force inputs
- call the estimator core from your own loop
- export odometry to your target middleware / runtime
This design is useful for:
- ROS1 migration
- embedded deployment
- offline replay tools
- MATLAB / simulation analysis
- custom robotics middleware
The Matlab/ folder provides an additional example for compiling the C++ estimator core into a MATLAB MEX module.
Typical workflow:
cd Matlab
build_mex
fusion_estimatorFiles in this folder:
build_mex.m— build script for MEX compilationfusion_estimator_mex.cpp— MEX bridge wrapping the C++ estimator corefusion_estimator.m— MATLAB-side usage / validation exampleMPXY150Z10.csv,MWXY150Z10.csv— sample data for offline tests
This is especially useful when you want to:
- verify C++ estimator behavior in MATLAB
- compare offline results quickly
- reuse the same
FusionEstimator/implementation without ROS2 - debug algorithm changes before reintegrating them into the ROS2 node
A Plotjuggler.xml file is included in the repository for convenient visualization and debugging with PlotJuggler.
You can use it to inspect:
- odometry outputs
- IMU-related signals
- joint / force-related channels
- estimator behavior during walking, standing, or reset events
- Paper (arXiv): https://arxiv.org/abs/2602.17393
- Technical notes (Notion): https://www.notion.so/Ros2Go2-1e3a3ea29e778044a4c9c35df4c27b22
- ROS1 reference implementation: https://github.com/ShineMinxing/FusionEstimation
| Affiliation | |
|---|---|
| sunminxing20@mails.ucas.ac.cn | Institute of Optics and Electronics, CAS |
This repository is under active development. Issues and PRs are welcome.
语言 / Language: English | 中文
CAPO-LeggedRobotOdometry 是面向 双足 / 四足 / 轮足 机器人的 ROS 2(Humble) 本体状态估计 / 里程计算法仓库,可在 Ubuntu 22.04 上运行。
本仓库仅依赖 IMU + 关节编码器 + 足端接触/力信号 即可输出高精度里程计,不依赖相机或激光雷达。
在 3D 闭环运动实验(水平 200 m、竖直 15 m)中:Astrall 公司的点足机器人 A 的水平与竖直误差分别为 0.1638 m 和 0.219 m;轮足机器人 B 的对应误差分别为 0.2264 m 和 0.199 m。
从工程结构上看,fusion_estimator_node.cpp 主要负责 ROS2 封装层(参数、Topic、消息转换、发布),而真正的融合估计算法位于 FusionEstimator/ 中,并且实现为 纯 C++、可移植 的核心模块。因此它不仅能用于 ROS2,也便于迁移到:
- ROS1
- 非 ROS2 平台
- 嵌入式 / 自定义运行环境
另外,仓库中的 Matlab/ 文件夹额外提供了 MATLAB + MEX 混合编译并调用 FusionEstimator 中 C++ 核心代码 的示例,方便离线验证、算法分析和跨平台复用。
Contact-Anchored Proprioceptive Odometry for Quadruped Robots(arXiv:2602.17393)
如果本仓库对你的研究有帮助,欢迎引用论文。
为便于大家快速验证本仓库的有效性,我们提供了 Go2-EDU 的两段示例数据,包含实拍录像以及可直接用于本节点的 ROS bag topic / message,用于快速复现与 sanity check。
- 数据下载(Google Drive):https://drive.google.com/drive/folders/1FfVO69rfmUu6B9crPhZCfKf9wFnV4L7n?usp=sharing
说明:该 Go2-EDU 平台的 IMU yaw 漂移较明显,因此里程计精度通常会劣于论文中 Astrall 机器人 A 与 B 的实验结果。
| 类别 | 说明 |
|---|---|
| 双足 / 四足 / 轮足统一支持 | 运行中自动识别支撑足,支持站立、行走和形态切换。 |
| 全 3D + 平面 2D | 同时发布 6DoF 里程计 SMX/Odom 与压平后的 SMX/Odom_2D。 |
| 零依赖外部感知 | 不依赖相机或激光雷达,仅依赖本体传感器。 |
| 纯 C++ 可移植核心 | FusionEstimator/ 中是独立的纯 C++ 融合估计实现,便于脱离 ROS2 使用。 |
| MATLAB / MEX 联调 | Matlab/ 中给出了用 MATLAB 混编调用同一套 C++ 核心的示例。 |
| 参数可调 | config.yaml 中的关键参数和阈值可按平台进行调整。 |
| 范畴 | 仓库 | 功能简介 |
|---|---|---|
| 底层驱动 | https://github.com/ShineMinxing/Ros2Go2Base | DDS 桥、Unitree SDK2 控制、点云→Scan、TF 工具 |
| 里程计 | CAPO-LeggedRobotOdometry(本仓库) | 纯本体多传感器融合,发布 SMX/Odom / SMX/Odom_2D |
| SLAM / 建图 | https://github.com/ShineMinxing/Ros2SLAM | 集成 Cartographer 3D、KISS-ICP、FAST-LIO2、Point-LIO 等 |
| 语音 / LLM | https://github.com/ShineMinxing/Ros2Chat | 离线 ASR + OpenAI Chat + 语音合成 |
| 图像处理 | https://github.com/ShineMinxing/Ros2ImageProcess | 相机、光点 / 人脸 / 无人机检测 |
| 吊舱跟随 | https://github.com/ShineMinxing/Ros2AmovG1 | Amov G1 吊舱控制与目标跟踪 |
| 工具集 | https://github.com/ShineMinxing/Ros2Tools | 蓝牙 IMU、手柄映射、吊舱闭环、数据记录等 |
⚠️ 按需克隆:如果只做状态估计,本仓库即可独立使用;如果要建图,通常可以配合Ros2SLAM和Ros2Go2Base一起使用。
CAPO-LeggedRobotOdometry/
├── CMakeLists.txt
├── package.xml
├── config.yaml
├── fusion_estimator_node.cpp # ROS2 节点封装:参数 / Topic / 里程计发布
├── FusionEstimator/ # 纯 C++ 融合估计算法核心(可移植)
│ ├── Estimators/
│ ├── fusion_estimator.h
│ ├── LowlevelState.h
│ ├── SensorBase.cpp
│ ├── SensorBase.h
│ ├── Sensor_IMU.cpp
│ ├── Sensor_IMU.h
│ ├── Sensor_Legs.cpp
│ ├── Sensor_Legs.h
│ └── Readme.md
├── Matlab/ # MATLAB + MEX 调用 C++ 核心的示例
│ ├── build_mex.m
│ ├── fusion_estimator.m
│ ├── fusion_estimator_mex.cpp
│ ├── MPXY150Z10.csv
│ └── MWXY150Z10.csv
├── Plotjuggler.xml # PlotJuggler 可视化配置
└── Readme.md
本仓库有意分成两层:
fusion_estimator_node.cpp 主要负责:
- 从
config.yaml读取参数 - 订阅 ROS2 Topic
- 将 ROS 消息转换为估计器输入
- 调用融合估计算法核心
- 发布
nav_msgs/Odometry
FusionEstimator/ 中包含真正的估计逻辑,例如:
- IMU 数据处理
- 腿部运动学 / 腿部传感器建模
- 接触锚定约束
- 融合估计状态更新
- 可复用的 C++ 接口
因为这里是纯 C++ 实现,所以它不仅能在 ROS2 中使用,也很适合迁移到:
- ROS1
- 非 ROS2 的 Linux 程序
- 嵌入式 / 自定义系统
- MATLAB MEX
- 离线回放与仿真验证
Matlab/ 文件夹不是 ROS2 运行必须的,但在以下场景里很有用:
- 做离线数据验证
- 在 MATLAB 中回放与分析估计结果
- 快速对比 C++ 结果与 MATLAB 脚本
- 不依赖 ROS2 直接复用同一套
FusionEstimator/核心
下面列出当前 ROS2 节点最常用的参数。完整注释请查看 config.yaml。
| 参数名 | 常见取值 | 说明 |
|---|---|---|
sub_imu_topic |
SMX/Go2IMU |
IMU 订阅 Topic |
sub_joint_topic |
SMX/Go2Joint |
关节状态订阅 Topic |
sub_mode_topic |
SMX/SportCmd |
复位 / 模式 Topic |
pub_odom_topic |
SMX/Odom |
全 3D 里程计输出 |
pub_odom2d_topic |
SMX/Odom_2D |
平面里程计输出 |
odom_frame |
odom |
里程计坐标系 |
base_frame |
base_link |
机体坐标系 |
base_frame_2d |
base_link_2D |
平面机体坐标系 |
imu_data_enable |
true |
是否启用 IMU |
leg_pos_enable |
true |
是否启用腿部位置运动学 |
leg_vel_enable |
true |
是否启用腿部速度运动学 |
leg_ori_enable |
false |
是否启用基于运动学的航向修正 |
leg_ori_init_weight |
0.001 |
姿态修正初始权重 |
leg_ori_time_wight |
1000.0 |
姿态修正随时间增长的权重 |
leg_velcke_enable |
false |
是否启用 IKVel-CKF / CAPO-CKE |
foot_force_threshold |
20.0 |
触地阈值 |
min_stair_height |
0.08 |
最小台阶高度假设 |
说明:
- 具体参数需要根据机器人平台做调整。
config.yaml中有些字段可能用于实验、兼容旧版本,或特定分支。- 如果你只移植
FusionEstimator/纯 C++ 核心,一般只需要保留估计器真正需要的参数,不必保留 ROS2 命名相关字段。
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
git clone --depth 1 https://github.com/ShineMinxing/CAPO-LeggedRobotOdometry.git
cd ~/ros2_ws
colcon build --packages-select fusion_estimator
source install/setup.bash
ros2 run fusion_estimator fusion_estimator_node如果你需要示例 CSV 或大文件资源,可以安装 Git LFS:
sudo apt update
sudo apt install git-lfs
git lfs install
cd ~/ros2_ws/src/CAPO-LeggedRobotOdometry
git lfs pull说明:某些版本中,
fusion_estimator_node.cpp会通过硬编码的--params-file路径加载config.yaml。如果你的本地工作空间路径不同,需要先修改该路径并重新编译。
/fusion_estimator_node (rclcpp)
├─ 发布
│ • SMX/Odom nav_msgs/Odometry (odom → base_link)
│ • SMX/Odom_2D nav_msgs/Odometry (odom → base_link_2D)
├─ 订阅
│ • SMX/Go2IMU sensor_msgs/Imu
│ • SMX/Go2Joint std_msgs/Float64MultiArray
│ 数据布局:
│ data[0..11] = 12 个关节位置 q
│ data[12..23] = 12 个关节速度 dq
│ data[24..27] = 4 个足端力 / 接触相关数值
│ • SMX/SportCmd std_msgs/Float64MultiArray
│ 复位示例:
│ data[0] == 25140000 → 复位估计器
└─ 若需要 TF,一般由其他节点 / 工具单独发布
-
触地检测
基于足端力 / 阈值逻辑判定支撑腿。 -
前向运动学
根据关节测量计算足端在机身坐标系中的位置与速度。 -
落足点锚定
在触地时记录落足点,在支撑期将接触点作为世界系间歇约束。 -
高度稳定
利用支撑平面高度逻辑与置信度衰减来降低长时程高度漂移。 -
可选 IKVel-CKF(CAPO-CKE)
抑制编码器速度尖峰,使足端速度估计更平滑。 -
可选航向稳定
利用多接触几何一致性来减小原地站立时的 IMU yaw 漂移。 -
2D 投影
压平 roll / pitch,保留 yaw 与平面运动,发布SMX/Odom_2D。
完整推导请参考论文。
如果你不需要 ROS2,真正可复用的主体主要就是 FusionEstimator/。
一个典型迁移流程是:
- 保留
FusionEstimator/下的纯 C++ 核心 - 用你自己的传感器接口替换 ROS2 订阅
- 准备 IMU、关节位置 / 速度、触地 / 足端力输入
- 在你的主循环中调用估计器
- 将输出接到你的中间件 / 控制系统
这对以下场景很有帮助:
- ROS1 迁移
- 嵌入式部署
- 离线数据回放
- MATLAB / 仿真验证
- 自定义机器人软件框架
Matlab/ 文件夹提供了一个额外示例,用来把 FusionEstimator/ 中的纯 C++ 核心编译成 MATLAB 可调用的 MEX 模块。
典型流程如下:
cd Matlab
build_mex
fusion_estimator该文件夹中的主要文件:
build_mex.m:MEX 编译脚本fusion_estimator_mex.cpp:MEX 桥接文件,负责封装 C++ 估计器核心fusion_estimator.m:MATLAB 侧调用示例MPXY150Z10.csv、MWXY150Z10.csv:离线测试用示例数据
这部分特别适合以下需求:
- 在 MATLAB 中验证 C++ 融合器行为
- 快速做离线结果对比
- 不依赖 ROS2 复用同一套
FusionEstimator/ - 在把修改重新合回 ROS2 节点之前,先做算法调试
仓库中附带了 Plotjuggler.xml,可用于 PlotJuggler 的快速可视化与调试。
你可以用它观察:
- 里程计输出
- IMU 相关信号
- 关节 / 足端力相关量
- 站立、行走、复位过程中的估计器行为
| 主题 | 链接 |
|---|---|
| 纯里程计建图(形态切换) | ![]() |
| 室内行走(误差 0.5%–1%) | ![]() |
| 爬楼梯(高度误差 < 5 cm) | ![]() |
| 户外行走(380 m,误差 3.3%) | ![]() |
| 语音交互 + 地图导航 | ![]() |
| 人脸识别跟踪 + 光点跟踪 | ![]() |
| AR 眼镜头部运动跟随 | ![]() |
| YOLO 无人机识别与跟随 | ![]() |
| 吊舱 + 固定相机协同 | ![]() |
| 多种 SLAM 方法集成 | ![]() |
- 论文(arXiv):https://arxiv.org/abs/2602.17393
- 技术笔记(Notion):https://www.notion.so/Ros2Go2-1e3a3ea29e778044a4c9c35df4c27b22
- ROS1 参考实现:https://github.com/ShineMinxing/FusionEstimation
| 邮箱 | 单位 |
|---|---|
| sunminxing20@mails.ucas.ac.cn | 中国科学院光电技术研究所 |
本仓库持续开发中,欢迎 Issue / PR 交流与贡献。









