-
Notifications
You must be signed in to change notification settings - Fork 12
Mod Nodes
本文说明 BXI ROS 2 控制框架中,一个 Mod 如何在自己的 mod.yaml 里声明、启动和
管理辅助 ROS 2 节点。这里的“Mod 子节点”特指顶层 nodes: 字段中的节点,例如相机
发布器、感知节点或通信桥接节点。
本文不是整个工作区的 ROS 2 节点清单,也不是 states: 状态清单,更不是 inference
推理类清单。若你的 Mod 只有动作状态,不需要额外的 ROS 2 发布者或订阅者,可以完全
不写 nodes:。
| 项目 | 位置或含义 |
|---|---|
| 所属项目 |
src/bxi_example_py_elf3/ 中的 BXI Mod 框架 |
| 配置入口 | 每个 Mod 自己的 <mod目录>/mod.yaml 顶层 nodes: 字段 |
| 公共类型 |
bxi_example_py_elf3/framework/mod_api/node.py 中的 NodeBuildContext
|
| 运行时实现 |
bxi_example_py_elf3/framework/runtime/mod_nodes.py 中的 ModNodeManager
|
| 管理范围 | 节点创建、按状态启停、独立进程、参数、重映射、异常重启和关闭 |
一个真实例子是 mods/com.bxi.normal_depth/mod.yaml:
com.bxi.normal_depth Mod
├── nodes.depth_camera_publisher # 发布深度图像的辅助 ROS 2 节点
│ └── auto_depth_node:create_node
└── states.normal_depth # 消费深度图像并计算机器人动作的控制状态
两者职责不同:depth_camera_publisher 负责产生 ROS 图像,normal_depth 是控制状态;
Mod 节点管理器根据 lifecycle 决定前者何时启动和停止。这一页讲的是上图的 nodes
分支。关于 states 请阅读自定义状态,关于完整 Mod 结构请阅读
Mod 系统。
Mod API 1.2 支持三种节点运行时,同时复用相同的生命周期、参数、重启和展示字段:
-
python:Mod 内的 Python 工厂,返回一个rclpy.Node。 -
executable:Mod 内随包分发的原生可执行文件,适用于 C++ ROS 2 节点。 -
ros:通过 ament index 查找已安装 ROS 2 包中的可执行文件,行为等价于ros2 run。
使用 executable 或 ros 的 Mod 应声明当前公共 API 范围 api: ">=2,<3"。
nodes:
detector:
runtime: executable
entrypoint: detector_node
execution: process
lifecycle: state
states: [detect]
arguments: [--device, "0"]
namespace: /vision
remappings:
image: /camera/image_raw
params:
threshold: 0.5
enabled: true
manifest:
label: C++ 检测节点
runtime_requirements:
python: []
ros:
- package: sensor_msgs
system: []
restart:
max_attempts: 3
delay: 1.0字段说明:
-
runtime:python、executable或ros。为兼容旧 Mod,省略时默认为python。 -
entrypoint:其格式由runtime决定,具体见下文。 -
execution:Python 节点支持in_process和process;原生节点必须是process。原生节点省略该字段时默认使用process。 -
lifecycle:mod表示随 Mod 常驻,state表示仅在states指定的状态 活跃或预加载时运行。 -
arguments:放在可执行文件之后、--ros-args之前的普通程序参数。 -
namespace:空字符串或以/开头的绝对 ROS namespace。 -
remappings:ROS 名称重映射表。 -
params:节点参数。原生节点会收到自动生成的标准 ROS 2 参数文件。 -
restart:仅适用于进程节点,沿用现有退出监控和重启策略。
所有原生节点都会收到框架生成的唯一节点名。实际命令形如:
<executable> <arguments...> --ros-args \
-r __node:=com_example_detector_detector \
-r __ns:=/vision \
-r image:=/camera/image_raw \
--params-file <temporary-file>
临时参数文件由节点管理器持有,在管理器关闭时删除。
nodes:
camera:
runtime: python
entrypoint: camera_node:create_node
execution: process
lifecycle: mod
arguments: []
namespace: ""
remappings: {}
params:
fps: 30
manifest:
label: Python 相机节点Python 工厂通过 NodeBuildContext 获得 node_name、params、arguments、
namespace 和 remappings。Python 工厂负责在构造 rclpy.Node 时使用这些值。
一个 Mod 可以同时携带多个平台的同名二进制:
com.example.detector/
├── mod.yaml
├── bin/
│ ├── linux-x86_64/
│ │ └── detector_node
│ └── linux-aarch64/
│ └── detector_node
└── vendor/
└── lib/
├── linux-x86_64/
└── linux-aarch64/
对应清单只写平台无关的文件名:
runtime: executable
entrypoint: detector_node运行时使用与 runtime_platform_tag() 相同的平台标签,自动解析
bin/<platform>/<entrypoint>。不会回退到其他平台。文件缺失或没有执行权限时,
节点状态为 unavailable,其他可用节点仍可继续加载。
entrypoint 必须是相对于平台 bin 目录的安全路径;绝对路径、.. 和解析后
逃出该目录的符号链接都会被拒绝。Mod 私有动态库放在
vendor/lib/<platform>/,该目录会被优先加入子进程的 LD_LIBRARY_PATH。
nodes:
detector:
runtime: ros
entrypoint: detector_package:detector_node
execution: process
lifecycle: mod
arguments: []
namespace: ""
remappings: {}
params: {}
manifest:
label: 系统检测节点运行时通过 ament index 获取包前缀,并直接执行
<prefix>/lib/detector_package/detector_node。直接执行避免了监管 ros2 run
包装进程,停止和异常重启仍由同一个 Mod 节点管理器负责。