![[具身智能-103]:ROS中的话题、服务、动作三种通信模式下的各自的消息定义](http://pic.xiahunao.cn/yaotu/[具身智能-103]:ROS中的话题、服务、动作三种通信模式下的各自的消息定义)
在 ROS 2 中消息定义 (Message Definition)是节点间通信的“契约”。无论使用话题 (Topic)、服务 (Service) 还是动作 (Action)通信双方必须对数据的结构字段名、类型、顺序有完全一致的理解。ROS 2 使用一种语言无关的接口定义语言 (IDL)文件后缀分别为.msg、.srv和.action。构建系统 (colcon) 会根据这些定义文件自动生成 C、Python 等语言的代码类。1. 话题通信 (Topics) -.msg模式发布/订阅 (Publish/Subscribe)单向流式数据。文件后缀.msg特点结构简单仅包含数据字段没有请求/响应概念。定义示例Person.msgmsg# 自定义消息人员信息 string name uint8 age float32 height bool is_student int32[] scores # 动态数组 geometry_msgs/msg/Pose pose # 嵌套其他包的消息关键字段类型表格类型类别具体类型说明基本类型bool,byte,char布尔值8位整数整数uint8,int8,uint16,int16,uint32,int32,uint64,int64无符号/有符号整数浮点float32,float64单精度/双精度浮点数字符串stringUTF-8 字符串时间time,duration时间点时长数组type[]动态长度数组 (如int32[])定长数组type[N]固定长度数组 (如float32[3])嵌套package/msg/Type引用其他包的消息常量定义 (Constants)可以在.msg文件中定义常量编译后成为类的静态成员。msguint8 CHILD 0 uint8 ADULT 1 uint8 ELDERLY 2 uint8 status # 状态字段取值应为上述常量之一2. 服务通信 (Services) -.srv模式请求/响应 (Request/Response)同步双向通信。文件后缀.srv特点文件分为两部分用---分隔。上半部分是请求 (Request)下半部分是响应 (Response)。定义示例AddTwoInts.srvsrv# 请求部分两个加数 int64 a int64 b --- # 响应部分求和结果 int64 sum定义示例GetMap.srv(复杂场景)srv# 请求不需要参数或者只需要一个标志位 bool full_resolution --- # 响应返回整个地图数据 nav_msgs/msg/OccupancyGrid map bool success string message工作机制客户端发送Request数据结构。服务端接收Request处理逻辑。服务端返回Response数据结构。通信结束。3. 动作通信 (Actions) -.action模式目标/反馈/结果 (Goal/Feedback/Result)异步长时任务。文件后缀.action特点文件分为三部分用---分隔。分别对应目标 (Goal)、反馈 (Feedback)和结果 (Result)。定义示例Fibonacci.actionaction# 1. Goal (目标): 客户端发送给服务端指定任务参数 int32 order --- # 2. Feedback (反馈): 服务端在执行过程中周期性发送汇报进度 int32[] sequence --- # 3. Result (结果): 任务完成后发送一次包含最终产出 int32[] sequence工作机制发送目标 (Send Goal): 客户端发送Goal(如移动到坐标 X)。执行与反馈: 服务端开始执行并周期性发送Feedback(如当前进度 50%, 当前位置 Y)。客户端可随时取消目标。返回结果: 任务完成成功或失败服务端发送Result(如最终位置 Z, 状态码)。三种数据的区别Goal: 任务的输入参数 (类似 Service 的 Request)。Feedback: 中间状态频率高数据量通常较小 (如进度条、实时误差)。Result: 最终产出只在结束时发送一次 (类似 Service 的 Response)。4. 如何在功能包中使用自定义消息假设你创建了一个名为my_interfaces的功能包来存放这些定义。步骤 1: 修改package.xml添加必要的依赖以支持消息生成。xmldependrosidl_default_generators/depend exec_dependrosidl_default_runtime/exec_depend member_of_grouprosidl_interface_packages/member_of_group步骤 2: 修改CMakeLists.txt告诉构建系统哪些文件需要生成代码。cmakefind_package(rosidl_default_generators REQUIRED) # 声明要生成的消息、服务、动作 rosidl_generate_interfaces(${PROJECT_NAME} msg/Person.msg srv/AddTwoInts.srv action/Fibonacci.action # 如果依赖其他包的消息如 geometry_msgs需在此处声明 DEPENDENCIES geometry_msgs )步骤 3: 编译bashcolcon build source install/setup.bash步骤 4: 在代码中使用编译后生成的代码位于install/package_name/lib/python3.../site-packages/package_name/msg/(Python) 或include/package_name/msg/(C)。Python 示例:pythonfrom my_interfaces.msg import Person from my_interfaces.srv import AddTwoInts from my_interfaces.action import Fibonacci # 创建消息实例 p Person() p.name Alice p.age 25C 示例:#include my_interfaces/msg/person.hpp #include my_interfaces/srv/add_two_ints.hpp #include my_interfaces/action/fibonacci.hpp // 创建消息实例 my_interfaces::msg::Person p; p.name Alice; p.age 25;5. 三种模式的对比总结表格特性话题 (Topic).msg服务 (Service).srv动作 (Action).action通信模型发布/订阅 (多对多)请求/响应 (一对一)目标/反馈/结果 (一对一可取消)方向单向 (流式)双向 (同步阻塞)双向 (异步非阻塞)文件结构纯数据字段请求---响应目标---反馈---结果适用场景传感器数据、状态广播、控制指令流瞬间完成的查询、设置参数、触发开关长时间运行的任务 (导航、抓取)、需进度反馈的任务实时性高 (尽力而为不保证到达)中 (等待响应可能阻塞)中/低 (关注任务最终状态)是否可取消否否 (除非超时)是(Action 的核心特性)最佳实践建议复用标准消息尽量使用std_msgs,geometry_msgs,sensor_msgs,nav_msgs等官方包中定义的消息不要重复造轮子。接口包分离将自定义的.msg,.srv,.action放在独立的包中 (如my_robot_interfaces)让算法包和驱动包只依赖这个接口包。这样可以避免循环依赖也方便分发。命名清晰字段名使用snake_case(如motor_speed)消息文件名使用PascalCase(如MotorStatus.msg)。避免过度嵌套虽然支持嵌套但过深的嵌套会增加序列化/反序列化的开销且使数据结构难以阅读。注释在定义文件中充分利用#注释说明字段的单位 (如m/s,rad) 和取值范围这对使用者至关重要。