ROS2 Jazzy + C++ 实战路线——进阶学习3

继"ROS2 Jazzy + C++ 实战路线------基础学习2"继续学习

ROS2 工程里常见的是:

复制代码
代码负责逻辑
参数负责配置
Launch负责启动

1. Parameter:节点自己的配置项

Parameter 就是:

Node 运行时使用的配置。

比如:

复制代码
source_type = axis
primary_port = 7014
publish_rate = 50

Node 内部会读取这些参数。

以后你的动捕节点:

复制代码
mocap_driver_node

可能有:

复制代码
source_type
primary_port
backup_port
queue_capacity
publish_rate

这样代码不用改,只改参数。


2. YAML:把一堆 Parameter 放到文件里

比如:

复制代码
mocap_driver:
  ros__parameters:
    source_type: "axis"
    primary_port: 7014
    backup_port: 7015
    publish_rate: 50.0

这个文件可能叫:

复制代码
mocap.yaml

你可以理解:

复制代码
Parameter
= 单个配置

YAML
= 一堆配置保存成文件

这对真实项目非常重要,因为机器人通常有几十甚至几百个参数。


3. Launch:负责把整个系统启动起来

现在假设系统有三个节点:

复制代码
mocap_driver_node
gmr_retarget_node
robot_output_node

不用 Launch 的话:

复制代码
终端1:启动动捕
终端2:启动GMR
终端3:启动输出

很麻烦。

所以 ROS2 有 Launch:

复制代码
Launch
  ↓
一次启动多个 Node

例如:

复制代码
humanoid.launch.py

里面描述:

复制代码
启动 mocap_driver
启动 gmr_retarget
启动 robot_output
加载 YAML

最终你只需要:

复制代码
ros2 launch humanoid_bringup humanoid.launch.py

整个系统就起来了。


4. 三者关系一定要搞懂

复制代码
              Launch
                ↓
        ┌───────┼────────┐
        ↓       ↓        ↓
     Node A   Node B   Node C
        ↓
   加载 Parameter
        ↓
       YAML

准确一点是:

复制代码
YAML
  ↓
提供参数
  ↓
Launch
  ↓
把参数交给 Node
  ↓
Node 根据参数运行

这是非常典型的 ROS2 工程结构。


5. bringup 是什么?

以后你会经常看到:

复制代码
xxx_bringup

比如:

复制代码
humanoid_bringup

它通常不是核心算法。

主要负责:

复制代码
Launch
Config
系统启动
节点组合

所以你看到:

复制代码
xxx_bringup

可以直接想到:

这个包负责把整个系统拉起来。

这是 ROS2 项目里很常见的组织方式。


9. 为什么 Parameter 不是什么东西都能改?

这里提前建立一个概念。

有些参数:

复制代码
日志等级
阈值
滤波参数

运行时改可能没问题。

但有些:

复制代码
设备类型
EtherCAT网卡
模型文件
底层驱动

通常更适合:

复制代码
启动之前配置

而不是系统运行过程中随便改。

所以:

Parameter 是配置机制,不代表所有参数都应该动态修改。


10. 到现在 ROS2 大框架已经越来越完整

你已经知道:

复制代码
Workspace
│
├── Package
│
├── Node
│
├── Topic
│
├── Service
│
├── Action
│
├── Parameter
│
├── Interface
│
├── YAML
└── Launch

它们各自解决的问题:

东西 解决什么
Node 谁来干活
Topic 持续数据怎么传
Service 一问一答
Action 长任务
msg/srv/action 数据格式
Parameter 节点怎么配置
YAML 配置怎么保存
Launch 整个系统怎么启动

这张表比目前写多少代码更重要。

继续。现在讲 第 11 课:rosbag2 + ROS2 调试工具体系,还是只抓大框架和必要命令。

1. rosbag2 是什么

你可以把它理解成:

ROS2 的"数据录像机"。

它可以把 Topic 上的数据录下来,之后再回放。

比如真实机器人运行时:

复制代码
Axis
  ↓
/mocap/human_pose
  ↓
GMR

你可以同时录:

复制代码
/mocap/human_pose

以后即使没有 Axis,也能:

复制代码
rosbag2 回放
    ↓
/mocap/human_pose
    ↓
GMR

所以它特别适合:

复制代码
复现问题
调算法
分析掉帧
离线测试
保存实验数据

对你的动捕链路尤其重要。


2. 最必要的几个命令

录一个 Topic:

复制代码
ros2 bag record /mocap/human_pose

录多个:

复制代码
ros2 bag record \
  /mocap/human_pose \
  /g1/joint_targets

录全部 Topic:

复制代码
ros2 bag record -a

查看 bag 信息:

复制代码
ros2 bag info <bag目录>

回放:

复制代码
ros2 bag play <bag目录>

现在不需要记参数细节。

只要理解:

复制代码
record = 录
info   = 看
play   = 放

3. rosbag2 为什么对算法开发很重要

比如某次机器人出现异常:

复制代码
第 2 分钟
突然动作抖动

如果没有录数据:

复制代码
问题过去了
↓
很难重现

有 rosbag2:

复制代码
真实运行
↓
记录传感器、状态、控制目标
↓
保存
↓
办公室重新播放
↓
分析

这就是机器人开发里非常典型的流程。


4. 它还能帮你把"硬件"和"算法"分开

比如正常流程:

复制代码
真实动捕设备
     ↓
mocap_driver
     ↓
GMR

调 GMR 时不一定需要每次都接真实设备。

可以:

复制代码
以前录好的 bag
      ↓
播放
      ↓
GMR

于是:

复制代码
硬件团队
和
算法团队

可以相对独立工作。

这就是为什么 rosbag2 不只是"录像工具",也是一个非常重要的测试工具。


5. ROS2 调试工具整体框架

以后遇到问题,不要一上来就看源码。

先用 ROS2 自带工具观察系统。

你重点记这几类:

想看什么 命令
有哪些 Node ros2 node list
Node 在干什么 ros2 node info
有哪些 Topic ros2 topic list
Topic 类型和连接 ros2 topic info
Topic 数据 ros2 topic echo
Topic 频率 ros2 topic hz
参数 ros2 param
接口定义 ros2 interface show
数据录制/回放 ros2 bag

这张表以后比背 API 更实用。


6. 一个实际排查思路

例如:

GMR 没有输出。

不要马上改代码。

先检查:

复制代码
1. mocap_driver 在不在?
        ↓
ros2 node list

2. /mocap/human_pose 在不在?
        ↓
ros2 topic list

3. 有没有数据?
        ↓
ros2 topic echo

4. 频率正常吗?
        ↓
ros2 topic hz

5. GMR 有没有订阅?
        ↓
ros2 topic info

6. 输入正常但没输出?
        ↓
再去看 GMR

这个思维非常重要:

先判断问题在哪一层,再看代码。


7. ROS2 系统调试其实是在看"数据流"

以后你的系统:

复制代码
传感器
 ↓
Driver
 ↓
Topic
 ↓
算法
 ↓
Topic
 ↓
控制
 ↓
机器人

你要学会逐段确认:

复制代码
这里有没有数据?
↓
数据类型对不对?
↓
频率对不对?
↓
谁发布?
↓
谁订阅?

这和你之前排查动捕掉帧时做"源端 → GMR → 输出端计数守恒"其实是同一种工程思路。


8. 到这里,ROS2"通信与工程工具"这一层基本完整

目前你已经掌握整体:

复制代码
Node
↓
Topic / Service / Action
↓
Interface
↓
Parameter + YAML
↓
Launch
↓
rosbag2
↓
调试命令

下一块开始进入机器人本体相关内容:

复制代码
TF2
↓
URDF
↓
RViz2

这一块非常重要,因为前面学的是:

程序之间怎么通信。

下一块开始学:

机器人各个坐标系、Link、Joint、模型之间是什么关系。

9. TF2 是什么?

一句话:

TF2 用来管理机器人不同坐标系之间的空间关系。

比如一个人形机器人:

复制代码
world
  ↓
base_link
  ↓
torso
  ↓
head
  ↓
camera_link
  ↓
camera optical frame

每个东西都有自己的"坐标系"。

TF2 就负责告诉 ROS2:

复制代码
camera 相对于 head 在哪里?
head 相对于 torso 在哪里?
torso 相对于 base_link 在哪里?
base_link 相对于 world 在哪里?

10. TF2 最核心的东西:TF Tree

你以后经常看到:

复制代码
             base_link
             /      \
         left_leg   right_leg
            ↓          ↓
          foot        foot

              ↓
            torso
              ↓
             head
              ↓
           camera

这叫:

TF Tree,坐标变换树。

它描述整个机器人各部分之间的空间关系。


11. TF2 最重要的两个概念

你暂时只记:

静态 TF

两个坐标系之间基本不会变化。

例如:

复制代码
head
 ↓
camera

相机固定安装在头部。

这种关系通常是:

复制代码
static transform

动态 TF

两个坐标系之间会不断变化。

例如:

复制代码
base_link
 ↓
left_foot

机器人走路的时候:

复制代码
位置变化
姿态变化

所以需要不断更新。TF2 最终解决什么问题?

你以后可以用一句话解释:

TF2 管理机器人系统中不同坐标系之间随时间变化的位姿关系,并提供坐标转换。

这句话已经足够工程化。TF2 常用工具

现在先知道名字:

复制代码
ros2 run tf2_tools view_frames

用于查看 TF Tree。

以及:

复制代码
ros2 run tf2_ros tf2_echo frame_a frame_b

查看两个坐标系之间的变换。

例如:

复制代码
ros2 run tf2_ros tf2_echo base_link camera_link

意思:

查看 camera_linkbase_link 之间的关系。

不用现在背参数。


11. TF2 和 URDF 的关系

这一点非常重要。

接下来我们会学:

复制代码
URDF

你可以先理解:

复制代码
URDF
= 描述"机器人长什么样"

TF2
= 描述"机器人现在各部分在哪里"

例如 URDF 描述:

复制代码
base_link
   ↓
torso
   ↓
head
   ↓
camera

以及:

复制代码
Joint
Link
尺寸
惯量
碰撞模型

而机器人真正运行时:

复制代码
TF2

告诉你:

复制代码
现在 head 在哪里?
现在 camera 在哪里?
现在 left_foot 在哪里?

所以:

复制代码
URDF
+
TF2

是机器人模型和空间关系的核心组合。


12. 再往后就是 RViz2

当你有:

复制代码
URDF
+
TF2

就可以在:

复制代码
RViz2

里把机器人显示出来。

最终类似:

复制代码
        ROS2

         ↓

       URDF
         ↓
      Robot Model
         ↓
        TF2
         ↓
       RViz2
         ↓
   看到机器人当前姿态

RViz2 本质上就是:
ROS2 的三维可视化和调试工具。

复制代码
                 ROS2

                  │
       ┌──────────┴──────────┐
       ↓                     ↓
    通信系统               机器人描述
       │                     │
 Topic / Service          URDF
 Action / msg               │
       │                     ↓
 Parameter                 TF2
 Launch                     │
 rosbag2                    ↓
       │                   RViz2
       └──────────┬──────────┘
                  ↓
             机器人系统

13. URDF

URDF = 告诉 ROS2:机器人由哪些零件组成,这些零件之间怎么连接。

例如一个机械臂:

复制代码
base
 ↓
link1
 ↓
link2
 ↓
link3
 ↓
end_effector

一个人形机器人:

复制代码
                 head
                  │
                torso
              /      \
        left_arm     right_arm
           │            │
       left_hand     right_hand

                │
              pelvis
             /      \
       left_leg    right_leg
           │          │
       left_foot   right_foot

URDF 就是在描述这些东西。


14. URDF 最核心的两个东西

你现在只需要牢牢记住:

复制代码
Link
Joint

比如:

复制代码
头
躯干
大腿
小腿
脚
手臂

都可以看成 Link。

例如:

复制代码
<link name="base_link"/>
<link name="left_thigh"/>
<link name="left_shin"/>
<link name="left_foot"/>

就是定义了几个刚体。


例如:

复制代码
pelvis
   │
 hip joint
   │
left_thigh

这里:

复制代码
pelvis
  ↓
joint
  ↓
left_thigh

Joint 描述:

两个 Link 之间是什么关系,以及能不能动、怎么动。


15. Joint 有哪些类型?

ROS2 里面常见的:

复制代码
fixed
revolute
continuous
prismatic

你现在先理解前三个。

fixed

固定不动。

复制代码
base
 │
 └── camera

比如机器人身体上的固定相机。


revolute

旋转关节。

例如:

复制代码
大腿
 │
 ● ← 髋关节
 │
小腿

机械臂关节、人形机器人关节,大量都是这种。


continuous

也是旋转,但可以无限旋转。

比如:

复制代码
轮子

所以看到:

复制代码
joint

你的第一反应应该是:

"这是在描述两个 Link 怎么连接、怎么运动。"


16. 一个最小 URDF

你不用现在研究 XML 语法,只看结构:

复制代码
<robot name="demo">

  <link name="base_link"/>

  <link name="link1"/>

  <joint name="joint1" type="revolute">

    <parent link="base_link"/>

    <child link="link1"/>

    <origin xyz="0 0 0.1" rpy="0 0 0"/>

    <axis xyz="0 0 1"/>

  </joint>

</robot>

整体关系就是:

复制代码
base_link
    │
    │ joint1
    ↓
  link1

其中:

复制代码
parent = 父 Link
child  = 子 Link

这个概念以后 TF2 会一直遇到。


17. URDF 还有三个重要东西

一个 Link 不只是"名字"。

通常还会描述:

复制代码
visual
collision
inertial

visual

机器人"长什么样"。

比如:

复制代码
机器人身体模型
机械臂模型
脚模型

主要用于显示。


collision

机器人"碰撞用什么形状"。

例如真实机器人腿可能非常复杂:

复制代码
      █████
     ███████
       ███
      ████

但是碰撞检测没必要这么复杂。

可以简化成:

复制代码
   ┌─────┐
   │     │
   │     │
   └─────┘

这样计算更快。


inertial

物理属性。

比如:

复制代码
质量
质心
惯量

这个在 MuJoCo / Gazebo / 物理仿真 里面特别重要。

所以可以简单记:

复制代码
visual    → 看起来什么样

collision → 碰撞怎么算

inertial  → 物理属性

URDF

描述:

机器人是什么结构。

例如:

复制代码
base_link
   ↓
torso
   ↓
head
   ↓
camera_link

TF2

描述:

这些坐标系当前是什么空间关系。

例如:

复制代码
base_link
    ↓
head
    ↓
camera_link

机器人运动以后:

复制代码
camera_link

的位置和姿态会发生变化。

TF2 就负责表达这种变化。

复制代码
robot_state_publisher

它可以简单理解成:

根据 URDF + 关节状态,把机器人的 TF 关系发布出来。

整体:

复制代码
             URDF
               │
               ↓
      robot_state_publisher
               │
               ↓
              TF2
               │
               ↓
             RViz2

所以你现在应该建立这个认识:

复制代码
URDF
 ↓
机器人结构

robot_state_publisher
 ↓
把结构转换成 TF

TF2
 ↓
管理坐标系关系

RViz2
 ↓
把机器人显示出来

18. 那 joint_state 又是什么?

这个概念也很重要。

假设机器人有:

复制代码
left_hip
left_knee
left_ankle

现在机器人实际运动:

复制代码
left_hip   = 0.2 rad
left_knee  = 0.8 rad
left_ankle = -0.3 rad

这些就是:

Joint State(关节状态)

简单理解:

复制代码
URDF
 ↓
告诉 ROS:
"机器人有哪些关节"

Joint State
 ↓
告诉 ROS:
"这些关节现在转到了哪里"

robot_state_publisher
 ↓
根据这些信息计算 TF

19. Xacro 是什么?

实际机器人一般不会直接手写一个几千行的 URDF。

因为太痛苦。

所以会出现:

复制代码
Xacro

你可以暂时理解成:

Xacro = 给 URDF 加上"变量、宏、复用"的工具。

比如机器人左右腿结构非常类似:

复制代码
left_leg
right_leg

如果直接 URDF 写两遍,会非常重复。

Xacro 可以把公共结构抽出来。

所以实际项目经常是:

复制代码
xxx.xacro
     ↓
生成
     ↓
URDF

你以后看机器人 ROS2 项目时,看到:

复制代码
urdf/
├── robot.urdf
├── robot.xacro
├── arm.xacro
├── leg.xacro
└── sensor.xacro

不要慌。

本质还是在描述:

复制代码
Link
+
Joint
+
机器人结构

现在可以形成一个完整 ROS2 机器人软件框架:

复制代码
                    ROS2
                     │
       ┌─────────────┼─────────────┐
       │             │             │
     Topic        Service        Action
       │
       ↓
   节点之间通信


             机器人模型
                 │
                URDF
                 ↓
               TF2
                 ↓
              RViz2


             机器人控制
                 │
            ros2_control
                 ↓
             Controller
                 ↓
             Hardware
                 ↓
               电机
相关推荐
Logintern091 小时前
“以一致的顺序获取锁“是预防死锁最核心、最有效的手段
python·postgresql·锁机制
甲维斯1 小时前
ZCode 19号更新来了,偷偷上传问题“已修复”?!
人工智能
zhangfeng11331 小时前
《从“人工适配“到“智能生成“:KernelSwift 跨国产芯片算子迁移全栈方案解读》 —— 强调范式跃迁和跨硬件属性,适合偏架构分析的写法
人工智能·算法·华为·ai编程·npu
0+1111 小时前
算法 --滑动窗口
c++·算法·leetcode
是Dream呀1 小时前
Harness 工程:让 Agent 真正把任务做完
人工智能·分布式·缓存·agent
stolentime2 小时前
(有原题)CSP-S2026第一轮试题(附答案解析、markdown源码)
c++·csp
打工仔折腾 AI2 小时前
Prometheus 告警推钉钉:从单群 Webhook 到跨网络 Alertmanager 实战
人工智能·后端·python·性能优化
人工智能AI技术2 小时前
LLM 应用的 Bulkhead 设计
人工智能
Ivanqhz2 小时前
Ping-Pong 双缓冲
开发语言·人工智能·python·深度学习·mlir