在 ROS 2 项目中,Launch 文件是连接代码与运行时的桥梁。它将可执行节点、参数文件、话题重映射等资源组织在一个可复现的启动脚本中。对于本推理包而言,理解 inference.launch.py 及其引用的 YAML 配置文件,是让你的机器人从"编译成功"走向"实际动起来"的第一道门槛。本篇将带你逐层拆解启动链路:从 Python Launch 的语法骨架,到 YAML 参数如何被节点解析并转化为实时控制行为,再到不同预设配置(行走、起身、舞蹈等)的切换方式。
Sources: inference.launch.py, package.xml
Launch 文件结构解析
本项目使用 ROS 2 标准的 Python Launch System。启动脚本位于 launch/inference.launch.py,其核心逻辑非常简洁:构造一个 LaunchDescription,其中包含一个 Node 动作,指向推理可执行文件并注入参数文件。
def generate_launch_description():
configs = [
os.path.join(
get_package_share_directory("inference"),
"config",
"inference.yaml",
),
]
return LaunchDescription(
[
Node(
package="inference",
executable="inference_node",
name="inference_node",
parameters=configs,
output="screen",
),
]
)
文件中的关键元素如下表所示:
| 字段 | 值 | 含义 |
|---|---|---|
package |
"inference" |
目标功能包的名称,Launch 系统会据此在 ament 索引中查找资源 |
executable |
"inference_node" |
要启动的可执行文件名 |
name |
"inference_node" |
节点在 ROS 2 图中的逻辑名称,会覆盖 rclcpp 内部的默认名 |
parameters |
[...inference.yaml] |
加载到节点的 ROS 2 参数文件列表,支持传入多个 YAML |
output |
"screen" |
将标准输出打印到终端 |
初学者需要特别注意:parameters 字段接收的是一个列表,这意味着你可以同时传入多个 YAML 文件,后面的值会覆盖前面的同名参数。当前默认仅加载 config/inference.yaml。若你在修改配置后发现行为没有变化,请检查是否对 install 空间下的 YAML 做了更新(ROS 2 运行时读取的是安装后的副本,而非源码目录)。
Sources: inference.launch.py, CMakeLists.txt
配置文件体系总览
本项目的配置分为两条独立线索:推理参数(由 launch 文件传入节点)与 机器人硬件参数(由源码硬编码路径加载)。下表展示了 config/ 目录中各 YAML 的用途对比:
| 配置文件 | 模型数量 | 是否含 Motion | 特殊观测源 | 典型使用场景 |
|---|---|---|---|---|
inference.yaml |
1 | 否 | 无 | 标准行走 |
inference_amp.yaml |
1 | 否 | 无 | AMP 风格行走,速度范围更大 |
inference_getup.yaml |
2 | 是(起身) | motion_pos, motion_vel |
跌倒后自动起身 |
inference_beyondmimic.yaml |
4 | 是(wave/dance/punch) | motion_pos, motion_vel |
手柄切换多动作表演 |
inference_interrupt.yaml |
1 | 否 | interrupt |
支持外部中断动作覆盖 |
inference_attn_enc.yaml |
1 | 否 | perception |
带地形感知的注意力策略 |
robot.yaml |
— | — | — | IMU、电机、关节零点与限位 |
推理参数的 YAML 文件共享同一套语法格式:根节点必须为 inference_node:,其下嵌套 ros__parameters:,再之下才是具体参数键值。robot.yaml 则采用扁平结构,由 RobotInterface 直接解析,无需经过 ROS 2 参数系统。
Sources: inference.yaml, robot.yaml
启动流程与文件依赖
当你在工作空间中执行 ros2 launch inference inference.launch.py 时,系统会按照以下顺序完成初始化:
flowchart TD
A[ros2 launch inference inference.launch.py] --> B[Python Launch 解析 LaunchDescription]
B --> C[定位 install/share/inference/config/inference.yaml]
C --> D[启动 inference_node 进程]
D --> E[InferenceNode 构造函数]
E --> F[load_config: 读取 ROS 2 参数]
E --> G[RobotInterface 加载 config/robot.yaml]
F --> H[setup_model: 加载 ONNX 模型并校验输入维度]
G --> I[初始化 CAN/Serial 硬件]
H --> J[启动 inference 线程]
I --> K[启动 control 线程]
J --> L[等待手柄/服务触发运行]
K --> L
上述流程中有两个关键校验点会在启动阶段直接抛出异常并终止程序:一是 YAML 中 model_names 的长度必须与 obs_layouts、frame_stacks、obs_stack_orders 严格一致;二是 ONNX 模型的输入维度必须与 obs_layout 推导出的总维度(含 frame_stack 倍增)完全匹配。因此,修改 YAML 后务必重新构建并安装,否则节点将在启动时崩溃。
Sources: inference_node.hpp, ros_interface.cpp, inference_node.cpp
核心参数分类详解
YAML 中的参数可按作用域分为 全局参数(所有策略共享)与 策略级参数(每个策略独立)。初学者最容易混淆的是策略级数组的长度必须与 model_names 的长度对齐。
策略级参数(数组,长度 = model_names 数量)
| 参数名 | 类型 | 说明 |
|---|---|---|
model_names |
string[] |
ONNX 模型文件名,位于 models/ 目录 |
motion_names |
string[] |
动作参考文件名,位于 motions/ 目录;为空字符串表示无动作参考 |
obs_layouts |
string[] |
主观测布局描述,语法为 name:size, name:size, ... |
extra_obs_layouts |
string[] |
额外观测布局(如感知特征),可选 |
frame_stacks |
int[] |
时序帧堆叠数量;1 表示不堆叠,10 表示保留最近 10 帧 |
obs_stack_orders |
string[] |
堆叠维度顺序,frame_major 或 obs_major |
obs_layouts 中支持的观测源名称如下表所示。每个名称后跟的 size 必须与模型训练时的观测维度严格对应:
| 观测源名称 | 维度含义 | 出现场景 |
|---|---|---|
ang_vel |
机体角速度(3D) | 所有策略 |
gravity_b |
机体坐标系下的重力方向(3D) | 所有策略 |
cmd_vel |
线速度/角速度指令(3D) | 所有策略 |
dof_pos |
关节位置(23) | 所有策略 |
dof_vel |
关节速度(23) | 所有策略 |
last_action |
上一时刻动作输出(23) | 所有策略 |
motion_pos |
参考动作关节位置(23) | 含 motion 的策略 |
motion_vel |
参考动作关节速度(23) | 含 motion 的策略 |
interrupt |
中断标志位(1) | 中断模式策略 |
perception |
外部感知数据(如地形,187) | 注意力编码器策略 |
Sources: ros_interface.cpp, obs_manager.cpp
全局运行参数
| 参数名 | 典型值 | 功能说明 |
|---|---|---|
dt |
0.004 |
控制线程周期(秒),对应 250 Hz |
decimation |
5 |
推理相对于控制的降采样倍数;推理频率 = 1 / (dt × decimation),即 50 Hz |
act_alpha |
1.0 |
动作平滑系数;1.0 为完全响应新动作,越小越平滑 |
intra_threads |
1 |
ONNX Runtime 内部算子线程数;设为 1 可减少实时抖动 |
joint_num |
23 |
机器人关节总数,必须与硬件和模型一致 |
action_scale |
0.25 |
模型原始输出到目标关节偏移的缩放系数 |
clip_actions |
100.0 |
动作输出的绝对值上限 |
clip_observations |
100.0 |
观测值在送入 ONNX 前的绝对值上限 |
gravity_z_upper |
-0.5 |
摔倒检测阈值;当机体重力向量 z 分量大于此值时节点自动关闭 |
dt 与 decimation 共同决定了系统的实时节奏:控制线程以 dt 为周期向电机发送指令,推理线程以 dt × decimation 为周期执行 ONNX 推理并更新目标动作。初学者在更换策略模型时,必须确保这两个值与训练时的控制频率一致,否则会出现时序失配。
Sources: inference_node.cpp, inference_node.cpp
机器人映射与安全参数
| 参数名 | 类型 | 说明 |
|---|---|---|
usd2urdf |
int[] |
USD 训练环境中的关节索引到 URDF/实际电机索引的置换映射 |
joint_default_angle |
double[] |
各关节的默认站姿角度(弧度),共 23 个 |
joint_limits |
double[] |
各关节的 [min, max] 限位对,共 46 个值;超出即触发保护停机 |
clip_cmd |
double[] |
手柄/指令速度限制 [x_min, x_max, y_min, y_max, yaw_min, yaw_max] |
obs_scales_* |
float |
各观测项的归一化缩放系数,通常保持 1.0 |
usd2urdf 是一个极易出错但至关重要的映射。训练环境(如 Isaac Gym/Sim)中的关节顺序通常与真实机器人电机的物理编号不同。该数组的每个元素 usd2urdf[i] 表示:将模型输出的第 i 个动作值,作用到实际机器人的第 usd2urdf[i] 号关节上。修改此数组前,建议对照训练代码中的关节定义表逐项核对。
Sources: inference.yaml, ros_interface.cpp
如何切换预设配置
项目内置了多种行为模式,切换方式仅需修改 launch 文件中的 configs 列表。例如,如果你想启动"起身模式",将 inference.launch.py 中的配置路径替换即可:
configs = [
os.path.join(
get_package_share_directory("inference"),
"config",
"inference_getup.yaml", # 将 inference.yaml 替换为所需的配置文件
),
]
下表展示了不同场景推荐的配置文件:
| 你想让机器人做什么 | 推荐配置文件 | 需要额外资源 |
|---|---|---|
| 基础站立与行走 | inference.yaml |
policy.onnx |
| 高速/风格化行走 | inference_amp.yaml |
policy_amp.onnx |
| 跌倒后自动起身 | inference_getup.yaml |
policy.onnx + policy_getup.onnx + getup.npz |
| 表演 wave / dance / punch | inference_beyondmimic.yaml |
对应 4 个 ONNX + 3 个 NPZ |
| 支持外部中断动作 | inference_interrupt.yaml |
policy_interrupt.onnx |
| 带地形感知的行走 | inference_attn_enc.yaml |
policy_attn_enc.onnx + 外部 elevation 话题 |
修改后,执行 colcon build --packages-select inference 重新安装配置文件,再运行 launch 命令。
Sources: inference.launch.py, CMakeLists.txt
启动前检查清单
在按下回车键运行 ros2 launch 之前,建议对照以下清单进行确认:
- 可执行文件名一致:确认
CMakeLists.txt中add_executable生成的目标名,与 launch 文件中executable字段匹配。若构建系统生成的名称与 launch 中不一致,启动会报executable not found。 - 模型文件存在:
models/目录中包含 YAML 中model_names列出的全部.onnx文件。 - 动作文件存在:若使用
motion_names,确认motions/目录中有对应的.npz文件。 - 数组长度对齐:
obs_layouts、frame_stacks、obs_stack_orders的长度必须等于model_names的长度。motion_names和extra_obs_layouts可以为空,若不为空则长度也必须对齐。 - 关节维度一致:
joint_num、usd2urdf、joint_default_angle、joint_limits的长度/维度必须与真实机器人匹配。 - 硬件接口就绪:确认
robot.yaml中的can0~can3或串口设备已正常初始化。
Sources: ros_interface.cpp
下一步
完成启动配置的学习后,你已经能够让机器人进入初始化状态。为了深入理解启动之后系统内部发生了什么,建议按照以下顺序继续阅读:
- 如果你想知道推理节点启动后,控制线程与推理线程如何协同工作,请阅读 实时双线程设计与调度策略。
- 如果你想搞懂
obs_layouts中的观测源在代码里是如何被组装、归一化和堆叠的,请阅读 观测值组装、归一化与帧堆叠。 - 如果你需要添加新的 ONNX 模型或修改观测输入,请阅读 新增观测源与模型适配指南。
- 如果你对手柄按键映射或 ROS 2 话题接口感到好奇,请阅读 手柄与指令控制入门 与 ROS 2 话题与服务接口。