目录
一,API:应用程序接口(上层代码)
在ROS 2中:
// 这些就是ROS 2的API:
patrol_client_->async_send_request(request); // "发送请求"按钮
create_service<Patrol>("patrol", callback); // "创建服务"按钮
create_publisher<Twist>("/cmd_vel", 10); // "发布消息"按钮
二,完整通信流程详解(连接+请求+网传+处理+响应)
1. 服务发现阶段:自动匹配连接(连接)
在客户端初始化时:
// 后台自动执行的发现过程
while(!patrol_client_->wait_for_service(1s)) {
RCLCPP_INFO("寻找patrol服务提供者...");
}
-
广播探测:客户端在网络中发送:"谁提供了patrol服务?"
-
服务响应:服务端回应:"我在这里!IP:192.168.1.10, Port:12345"
-
建立连接:双方交换通信参数,建立直接连接
2. 客户端请求发送阶段:智能数据封装(请求)
当你调用:
patrol_client_->async_send_request(request, callback_function);
底层序列化过程:
C++对象 → 序列化 → 网络字节流 → 传输 → 反序列化 → C++对象
-
你的
request对象被自动序列化为二进制数据 -
添加消息头:服务名、时间戳、数据类型等元数据
-
通过TCP/UDP协议打包发送
3. 网络传输阶段:DDS的强大威力(网传)
客户端 → [rclcpp] → [rcl] → [ROS 2中间件] → [DDS] → 网络传输
4. 服务处理阶段:自动回调触发(处理)
服务端接收过程:
-
接收网络数据包
-
自动反序列化为
Patrol::Request对象 -
自动调用你的lambda回调函数
-
你直接处理C++对象,无需关心网络细节
5. 响应返回阶段:完整闭环(响应)
// 你在回调函数中简单设置响应
response->result = Patrol::Response::SUCCESS;
// ROS 2自动处理后续所有网络传输
三,DDS:ROS 2的通信基石
DDS数据分发服务是ROS2采用的底层通信框架,它是一个工业标准的实时数据通信中间件。
DDS的核心优势
1. 自动发现机制
-
零配置网络:节点自动发现彼此,无需手动配置IP和端口
-
动态加入/退出:新节点加入时自动被现有网络发现
-
主题匹配:基于主题名的自动连接建立
2. 服务质量(QoS)控制
DDS提供丰富的QoS策略:
| QoS策略 | 功能描述 | 应用场景 |
|---|---|---|
| 可靠性 | 确保信息不丢失 | 关键指令传输 |
| 持久性 | 为新订阅者保留历史消息 | 状态跟新 |
| 截止时间 | 保证最大延迟 | 实时控制 |
| 存货策略 | 检测检点离线 | 系统监控 |
3. 灵活的通信模式
// DDS支持的通信模式
1. 发布-订阅(Topics) // 一对多通信
2. 请求-响应(Services) // 同步双向通信
3. 动作(Actions) // 异步长时任务
4. 参数服务(Parameters) // 配置管理
四,实际网络数据流分析
客户端发送请求时的数据流:
-
应用层:你的
request->target_x = 5.0 -
序列化层:转换为二进制:
0x40A00000(5.0的IEEE754表示) -
传输层:添加DDS头:主题ID、时间戳、QoS设置
-
网络层:IP分组、路由选择
-
物理层:以太网帧传输
服务端接收时的逆向过程:
-
物理层:接收网络帧
-
网络层:IP包重组
-
传输层:DDS消息解析
-
反序列化层:二进制 → C++对象
-
应用层:你的
request->target_x恢复为5.0
五,为什么选择DDS?
传统ROS 1的问题:
-
🔴 中心化的Master节点(单点故障)
-
🔴 有限的QoS控制
-
🔴 较弱的实时性能
-
🔴 跨网络通信复杂
ROS 2 + DDS的优势:
-
🟢 去中心化架构(无单点故障)
-
🟢 丰富的QoS策略
-
🟢 真正的实时性能
-
🟢 无缝跨网络通信
-
🟢 工业级可靠性
六,TCP/UDP/IP协议栈
两种传输层协议比较
| 特性 | TCP(传输控制协议) | UDP(用户数据报协议) |
|---|---|---|
| 可靠性 | ✅ 保证不丢失 | ❌ 可能丢失 |
| 顺序性 | ✅ 保证顺序 | ❌ 可能乱序 |
| 速度 | ⚡ 较慢(要确认) | 🚀 很快(直接发) |
| 连接 | 🤝 需要建立连接 | 🎯 无连接 |
| 适用场景 | 重要数据(指令、状态) | 实时数据(视频、传感器) |
七,底层序列化过程
原始对象(你的C++代码):
request->target_x = 5.0f; // 这是一个浮点数
request->target_y = 3.14f; // 这是另一个浮点数
序列化步骤:
步骤1:转换数字格式
5.0 → IEEE 754标准 → 0x40A00000
3.14 → IEEE 754标准 → 0x4048F5C3
步骤2:添加信封信息(消息头)
┌──────────────────────────────────┐
│ 消息头 │
│ - 消息类型: Patrol_Request │
│ - 消息长度: 8字节 │
│ - 时间戳: 2023-12-19 10:30:00 │
└──────────────────────────────────┘
│ 消息体 │
│ - target_x: 0x40A00000 │
│ - target_y: 0x4048F5C3 │
└──────────────────────────────────┘
步骤3:网络传输
[二进制数据] → 网络电缆 → 目标计算机
步骤4:反序列化(接收端)
0x40A00000 → 解析为IEEE 754 → 5.0
0x4048F5C3 → 解析为IEEE 754 → 3.14
// 重新构建成C++对象
request->target_x = 5.0f; // 完美还原!
request->target_y = 3.14f; // 完美还原!
为什么需要这么复杂?
-
不同机器不同格式:
-
Intel CPU:小端序(0x00 00 A0 40)
-
ARM CPU:可能大端序(0x40 A0 00 00)
-
ROS 2自动处理这种差异
-
-
网络只认识0和1:
-
不能直接传输C++对象、指针、类方法
-
必须转换成通用的二进制格式
-
-
跨语言通信:
-
C++发的数据,Python节点要能理解
-
需要统一的序列化格式
-
总结:通信的全景图
你的ROS代码(API调用)
↓
ROS 2库(提供简单API)
↓
序列化(C++对象 → 二进制)
↓
TCP/UDP传输(选择可靠性)
↓
IP路由(找到目标地址)
↓
网络传输(电信号/无线波)
↓
反序列化(二进制 → C++对象)
↓
对方ROS代码收到数据
3531

被折叠的 条评论
为什么被折叠?



