ROS2 与边缘数据采集:灵巧手项目的主流架构
ROS2 是机器人软件中间件,不是操作系统,底层基于 DDS 去中心化通信。在工业机器人 / 灵巧手项目中,机载 Ubuntu(Jetson / 工控机)跑 ROS2 负责和灵巧手、传感器交互;同一台机器额外跑一个边缘采集程序,订阅 ROS2 话题,把数据预处理后上送云端——这是最主流的数据采集上云架构。本文从 ROS2 分层架构讲起,串联基础概念、采集实践、控制链路与重点踩坑。
一、ROS2 分层架构(从上到下,重点)
业务应用层(节点 Node:C++ rclcpp / Python rclpy / Java jros2client / Go rclgo)
↓
RCL 层(ROS Client Library,ROS 客户端通用抽象)
↓
RMW 层(ROS MiddleWare,ROS 中间件抽象层,屏蔽不同 DDS 实现)
↓
DDS 实现(FastDDS 默认、Cyclone DDS、RTI Connext)
↓
RTPS 有线协议(UDP 为主,网络数据包)
- RCL:ROS 通用客户端库,定义 Node、Publisher、Subscriber、Service、Action 这些统一接口;
- RMW:抽象层,把 ROS 接口和底层 DDS 解耦,可以随时切换 DDS 实现,上层业务代码不用改动;
- DDS:真正的底层通信中间件,负责节点自动发现、消息传输、QoS 策略;
👉 jros2client / rclgo,本质就是其他语言的 ROS2 客户端库,直接实现 ROS2 的通信语义,和 rclcpp/rclpy 节点互通。jros2client 本身自带 FastDDS 实现,Java 进程就是一个原生 DDS DomainParticipant,属于 ROS2 标准节点,不需要额外桥接程序。底层有线协议为 RTPS(DDSI-RTPS,UDP 为主,可 TCP)。
二、核心基础概念(和灵巧手项目强相关)
1. Node 节点
节点 = 独立进程,单一职责,一个功能一个节点,模块化解耦。
- 例子:灵巧手驱动节点、IMU 节点、相机节点、边缘采集节点(jros2client 这个 Java 程序本身就是一个 ROS2 Node);
- 同一个 Ubuntu 机载机上可以跑多个 Node;跨机器局域网也可以跑 Node,DDS 自动发现。
命令查看节点列表:
ros2 node list
2. Topic 话题(采集程序最常用,100Hz 关节状态就是 Topic)
发布 - 订阅 Pub/Sub,单向异步数据流。
- Publisher(发布方):灵巧手 C++ 驱动节点,持续往外推
JointState关节数据; - Subscriber(订阅方):Java 采集节点(jros2client)接收数据;
- 特点:一对多、多对多;发布者不用关心谁在订阅;
- 适合:持续流式传感器数据(关节角度、力矩、IMU、激光、触觉);
- 消息定义:
.msg文件,用 IDL 描述字段,自动生成 C++/Java/Go/Python 的实体类;sensor_msgs/msg/JointState就是标准消息; - QoS:每个 Topic 可以单独配置 QoS(可靠性、历史消息、超时)。100Hz 灵巧手数据流一般用
BEST_EFFORT尽力投递;指令类 Topic 用RELIABLE可靠传输。
3. Service 服务(一问一答,短同步请求)
Client / Server 模型,同步请求,单次应答。
- 场景:查询灵巧手状态、重置故障、读取参数;
- 不适合长时间任务,请求发出去,阻塞等待返回;
- 消息定义:
.srv,分 request 请求、response 应答两部分。
4. Action 动作(灵巧手抓取首选,长任务)
Client / Server,长时间执行任务 + 持续反馈 + 支持中途取消。
- 三部分:Goal(下发目标)、Feedback(过程实时反馈,比如抓取力矩变化)、Result(最终完成结果);
- 场景:下发抓取动作、控制手指运动轨迹;
Java 的 jros2client 可以作为 Action Client,向灵巧手驱动节点下发抓取 Goal,一边接收抓取过程力矩反馈。
5. Parameter 参数服务器
给节点配置参数(键值对)。
- 比如灵巧手的关节数量、IP 地址、EtherCAT 配置;
- 可以运行时动态读取 / 修改。
6. TF2 坐标变换系统(TF / TF_static)
维护机器人所有坐标系之间的空间变换关系。
- 手掌基座、各个手指连杆、相机坐标系;
/tf动态变换(随时间变化,手指运动),/tf_static静态不变(相机相对手掌固定);- 采集程序可以订阅 TF,拿到各个连杆空间位置。
7. Time 时间系统(采集项目重点)
ROS2 自带时间戳,放在 header.stamp;优先使用 ROS 消息内自带时间戳,不要使用 Java 本地系统时间,保证多传感器时序对齐。
- 真实硬件使用系统时钟;仿真可以使用仿真时钟。
三、Topic 常用示例(灵巧手)
| 话题 | 类型 | 频率 | 说明 |
|---|---|---|---|
/hand/joint_states | 关节状态(标准消息) | 100Hz | 最核心,必采集,几乎所有机械手都会发 |
/hand/joint_goal | 目标关节指令 | 可选订阅 | 一般只看,不转发上云 |
/hand/tactile | 触觉传感器 | 100Hz~200Hz | 如果带触觉传感器 |
/hand/status | 手的状态 / 故障告警(自定义消息) | 低频 1~10Hz | 手的状态 / 故障告警 |
采集频率说明: 100Hz = 1 秒 100 条,间隔 0.01s(10 毫秒)一条,常用 100Hz 或 200Hz。
四、采集实践
灵巧手 / 相机 / IMU / 激光雷达硬件
↓硬件驱动(串口/USB/EtherCAT)
ROS2 C++ 节点(驱动、控制、状态反馈)
↓DDS / RTPS
【同机】边缘采集服务(jros2client Java / rclgo Go)
↓MQTT / TLS
云端后端平台(Java,入库 TDengine、设备监控、任务管理)
- 降采样:100Hz 原始数据本地保留用于本地逻辑;云端只保留 20Hz 或 50Hz(每 2~5 条取一条);
- 过滤:只在抓取动作进行时才高频上传;空闲待机状态降低采样频率;
- 异常透传:力矩超限、故障消息不做降采样,实时优先上传;
- 时间对齐:统一使用 ROS 消息自带
header.stamp,不要用 Java 本地系统时间(避免时序错位,多传感器回放会出问题); - 数据打包:把同一时刻的关节 + 触觉打包成一条 JSON,MQTT 一次发送,减少 MQTT 小包数量。
五、控制链路
云端平台(Java 后端)
↓MQTT / TLS(下发抓取指令)
边缘 Java 采集服务(jros2client)
↓DDS / RTPS(发布目标 / 调用 Action)
ROS2 C++ 驱动节点(灵巧手驱动、实时闭环)
↓硬件总线(EtherCAT)
灵巧手硬件
六、完整工程结构(上层 + 硬件侧)
上层(边缘主机):边缘主机 → ROS2 + Controller Manager → Controller → Hardware Interface 插件(.so)
↑ ↓
Python / Java / Go Client(上层采集/监控/调度) C++ Client
↓
下层(硬件侧): 串口 / CAN / EtherCAT → MCU 嵌入式 C 固件 → 电机 / 编码器 / 力触觉传感器
ROS2 在下位机 / 硬件侧不做:直接做 MCU 底层电机驱动、硬件底层实时闭环(灵巧手底层伺服闭环依然在 C++ 节点甚至 MCU 里跑)。
七、工程配套工具(开发调试灵巧手会用到)
- Launch 文件(yaml):一次性批量启动多个节点(灵巧手驱动、robot_state_publisher 等),配置参数;
- rviz2:可视化工具,查看机器人模型、关节状态、点云、TF;
- ros2 cli 命令行:
ros2 topic echo查看话题数据,ros2 topic hz看话题频率(验证 100Hz 关节数据); - rosbag2:记录 / 回放所有话题数据,录制灵巧手抓取全过程,事后数据分析;
👉 边缘采集程序是实时上云;rosbag 是本地录制,两个不同用途。
八、ROS2 通信逻辑,与现有架构串联
机载 Ubuntu 上:
- C++ 驱动 Node:和灵巧手 EtherCAT 硬件交互,闭环力矩 / 位置控制;
- 驱动 Node 通过 DDS 发布
/hand/joint_states(100Hz)、触觉 Topic,提供 Service、Action; - Java 采集 Node(jros2client)作为 ROS2 原生节点,DDS 订阅话题,接收关节、力矩、触觉数据;
- Java 做数据清洗、降采样,MQTT 上传云端 TDengine;
- 云端下发抓取指令 → MQTT → Java 节点 → jros2client 调用 ROS2 Action Client → 灵巧手 C++ 驱动执行抓取;
所有节点之间语言无关,只要 DDS 同 Domain ID、消息定义一致,C++、Python、Java、Go 节点就可以自由互通。
九、ROS2 与 ROS1 的核心区别(面试常问)
- ROS1 中心化 Master,Master 挂掉整个系统瘫痪;TCP 通信,实时性差;
- ROS2 去中心化 DDS,节点 P2P 点对点;无中心节点,单点故障不影响整个系统;支持硬实时;
- ROS1 通信固定,ROS2 支持每个话题独立配置 QoS;
- ROS1 已经停止维护,灵巧手、工业新项目全部 ROS2(Humble、Jazzy 是主流 LTS 版本)。
十、ROS2 适合 / 不适合做什么
✅ 适合
- 机器人模块解耦、多节点通信;
- 传感器数据标准化、统一接口;
- 机械臂、灵巧手、移动机器人的感知、运动规划;
- 分布式多机机器人系统。
❌ 不适合
- 直接做 MCU 底层电机驱动;硬件底层实时闭环;
- 高并发大规模互联网后端(ROS2 是机器人框架,不是 Web 后端框架)。
十一、重点踩坑(结合边缘采集项目)
- Domain ID:所有 DDS 节点(C++ 驱动、jros2client)必须同一个 Domain ID,否则互相发现不了;
- QoS 不匹配:两边 Publisher 和 Subscriber QoS 策略不一致,会收不到消息(高频传感器 BEST_EFFORT,指令 RELIABLE);
- 时钟同步:多机部署必须 chrony 时间同步;单机载机也要统一 ROS 时间戳;
- 实时性:Java 节点(jros2client)不能做硬实时闭环,GC 停顿会导致灵巧手失控;只做采集、指令转发;
- 资源隔离:Jetson 算力有限,ROS2 驱动节点(实时控制)优先级高于采集节点,防止采集服务抢占 CPU 造成灵巧手抖动。
面试口述精简总结
ROS2 是机器人软件中间件,不是操作系统,底层基于 DDS 去中心化通信。它把机器人拆成多个独立 Node 节点,节点之间通过 Topic、Service、Action 三种方式通信;Topic 适合持续传感器数据流,Service 用于短查询,Action 用于抓取这类带反馈的长任务。在灵巧手项目中,Ubuntu 机载机上 C++ 驱动节点负责硬件实时控制,向外发布关节、力矩话题;我们的边缘 Java 采集程序使用 jros2client 作为 ROS2 节点,DDS 订阅话题,做数据预处理后 MQTT 上云;也可以通过 Action 下发抓取指令转发给驱动节点。同时支持 TF 坐标变换、rosbag 录包、rviz 可视化调试。