6.1 KiB
6.1 KiB
cpp_custom_interface — C++ 自定义接口(.msg / .srv / .action)
学会自定义 ROS2 接口,跨包/跨语言共享数据结构。
预计学习时间:2-3 小时。
这是什么?
ROS2 自带的消息类型(std_msgs/String、geometry_msgs/Twist...)够用吗?不够。
做项目一定要自定义接口,比如:
- 机器人:
/robot_status.msg(含电量、位置、状态) - 机械臂:
/MoveArm.action(含目标位姿 + 反馈进度 + 结果) - 相机:
/CameraCalibration.srv(含内外参矩阵)
本包演示:
.msg(消息,Topic 用):SensorReading(传感器读数).srv(服务):GetCalibration(获取标定数据).action(动作):MoveArm(机械臂运动)
🎯 学完之后你能做什么?
- ✅ 定义
.msg/.srv/.action文件 - ✅ 用
rosidl_generate_interfaces生成 C++ / Python 代码 - ✅ 在自己的包里 include 生成的 C++ 头文件
- ✅ 跨包/跨语言用自定义类型通信
📁 文件结构
src/cpp_custom_interface/
├── msg/SensorReading.msg # 消息定义
├── srv/GetCalibration.srv # 服务定义
├── action/MoveArm.action # 动作定义
├── include/cpp_custom_interface/ # 生成的头文件会被装到这里
├── src/
│ ├── sensor_publisher.cpp/hpp # 发布自定义 msg 的 Publisher
│ ├── calibration_server.cpp/hpp # 自定义 srv 的 Server
│ └── move_arm_server.cpp/hpp # 自定义 action 的 Server
├── test/test_custom_interfaces.cpp # 测试生成的接口
├── CMakeLists.txt # ⭐ 关键:rosidl_generate_interfaces
└── package.xml
📖 接口定义文件格式
.msg(SensorReading.msg)
std_msgs/Header header # 用其他包的消息类型
string sensor_id
string unit
float64 value
类型:string、int32、float64、bool、嵌套其他 msg/...
.srv(GetCalibration.srv)
string sensor_id # 请求字段
---
float64[9] intrinsic_matrix # 响应字段
float64[3] bias
string calibration_date
bool valid
--- 上是请求,下面是响应。
.action(MoveArm.action)
# Goal
float64 max_velocity_scaling
---
# Result
bool success
string error_message
float64 total_time_sec
---
# Feedback
float32 progress
string current_state
三段分别是 Goal / Result / Feedback。
🚀 跑起来
启动自定义 Publisher
source /opt/ros/humble/setup.bash
source /root/ros2_ws/install/setup.bash
ros2 run cpp_custom_interface sensor_publisher_cpp
预期输出:
[INFO] [sensor_publisher]: SensorPublisher started: topic="/sensor_reading"
订阅看消息(另开终端)
ros2 topic echo /sensor_reading --once
预期输出:
header:
stamp:
sec: ...
nanosec: ...
frame_id: imu_frame
sensor_id: imu_0
unit: rad/s
value: 0.0
启动标定服务(另开终端)
ros2 run cpp_custom_interface calibration_server_cpp
# 调用服务
ros2 service call /get_calibration cpp_custom_interface/srv/GetCalibration "{sensor_id: 'lidar_front'}"
启动机械臂 Action(另开终端)
ros2 run cpp_custom_interface move_arm_server_cpp
# 发 goal
ros2 action send_goal --feedback /move_arm cpp_custom_interface/action/MoveArm "{max_velocity_scaling: 0.5}"
📖 CMakeLists.txt 关键配置
# 1) 定义接口文件
set(MSG_FILES "msg/SensorReading.msg")
set(SRV_FILES "srv/GetCalibration.srv")
set(ACTION_FILES "action/MoveArm.action")
# 2) 生成 C++ + Python 代码(关键!)
rosidl_generate_interfaces(${PROJECT_NAME}
${MSG_FILES} ${SRV_FILES} ${ACTION_FILES}
DEPENDENCIES std_msgs geometry_msgs
)
# 3) 链接生成的 typesupport 库
rosidl_get_typesupport_target(cpp_typesupport
${PROJECT_NAME} "rosidl_typesupport_cpp")
target_link_libraries(${LIBRARY_NAME} ${cpp_typesupport})
# 4) 包必须 <member_of_group>rosidl_interface_packages</member_of_group>
package.xml 必须加:
<member_of_group>rosidl_interface_packages</member_of_group>
<buildtool_depend>rosidl_default_generators</buildtool_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
📖 在自己的代码里使用生成的接口
C++
#include "cpp_custom_interface/msg/sensor_reading.hpp"
#include "cpp_custom_interface/srv/get_calibration.hpp"
#include "cpp_custom_interface/action/move_arm.hpp"
// 使用消息类型
auto msg = cpp_custom_interface::msg::SensorReading();
msg.sensor_id = "imu_0";
msg.value = 1.23;
// Publisher
auto pub = create_publisher<cpp_custom_interface::msg::SensorReading>("topic", 10);
Python
from cpp_custom_interface.msg import SensorReading
from cpp_custom_interface.srv import GetCalibration
from cpp_custom_interface.action import MoveArm
msg = SensorReading()
msg.sensor_id = 'imu_0'
注意:Python 包名是 cpp_custom_interface.msg 而不是 cpp_custom_interface/msg。
🧪 跑测试
colcon test --packages-select cpp_custom_interface
colcon test-result --all --verbose
预期:cpp_custom_interface: gtest 3/3 ✓ 全部通过。
🔧 自己定义接口
- 在
msg/、srv/、action/下新建.msg/.srv/.action文件 - 改
CMakeLists.txt的MSG_FILES/SRV_FILES/ACTION_FILES列表 colcon build- 生成的代码在
install/cpp_custom_interface/include/(C++)或install/cpp_custom_interface/lib/python3.10/site-packages/(Python)
📚 深入学习
- doc/16-custom-interfaces.md — 自定义接口深度(嵌套 / 数组 / 常量)
⏭️ 下一个包
继续学 py_vision_demo — 图像话题(cv_bridge + OpenCV)。
📍 学习路径导航
| ⏮ 上一个 | 🏠 当前位置 | ⏭ 下一个 |
|---|---|---|
| py_params — Python Parameter | cpp_custom_interface — C++ 自定义接口 | py_vision_demo — Python 图像 |
📍 完整 12 包学习顺序见 主 README