# 16 · 自定义接口 (.msg / .srv / .action) 完全指南 > **目标**: 理解 ROS2 自定义接口的设计原理、文件格式、rosidl 工具链、能独立写 .msg / .srv / .action。 --- ## 目录 - [1. 为什么需要自定义](#1-为什么需要自定义) - [2. .msg 文件格式](#2-msg-文件格式) - [3. .srv 文件格式](#3-srv-文件格式) - [4. .action 文件格式](#4-action-文件格式) - [5. rosidl_generate_interfaces](#5-rosidl_generate_interfaces) - [6. CMakeLists.txt + package.xml 配置](#6-cmakeliststxt--packagexml-配置) - [7. C++ / Python 使用](#7-c--python-使用) - [8. 设计原则](#8-设计原则) - [9. 推荐阅读](#9-推荐阅读) --- ## 1. 为什么需要自定义 ROS2 标准消息(`std_msgs` / `sensor_msgs` / `geometry_msgs`)覆盖了 80% 场景,但有些项目特定需求: - 工业传感器读数(温度 + 压力 + 校准日期) - 机器人状态(电量 + 温度 + 故障码) - 业务动作(下单 + 支付 + 物流) 这些都需要**项目特定**的自定义接口。 ## 2. .msg 文件格式 ``` # 注释(以 # 开头) # 字段 ``` 字段类型: | ROS 类型 | C++ 类型 | Python 类型 | |---|---|---| | `bool` | `bool` | `bool` | | `int8`/`int16`/`int32`/`int64` | `int8_t`/... | `int` | | `uint8`/.../`uint64` | `uint8_t`/... | `int` | | `float32`/`float64` | `float`/`double` | `float` | | `string` | `std::string` | `str` | | `time`/`duration` | `builtin_interfaces::msg::Time` | `Time` | | 其他消息类型 | `pkg::msg::Type` | `pkg.msg.Type` | | `type[]` | `std::vector` | `List[T]` | | `type[3]` | `std::array` | `Tuple[T,T,T]` | 示例: `msg/SensorReading.msg` ``` std_msgs/Header header string sensor_id string unit float64 value ``` ## 3. .srv 文件格式 ``` # Request 字段(--- 上) --- # Response 字段(--- 下) ``` 示例: `srv/GetCalibration.srv` ``` string sensor_id --- float64[9] intrinsic_matrix float64[3] bias string calibration_date bool valid ``` ## 4. .action 文件格式 ``` # Goal 字段(第 1 段) --- # Result 字段(第 2 段) --- # Feedback 字段(第 3 段) ``` 示例: `action/MoveArm.action` ``` geometry_msgs/PoseStamped target_pose string[] joint_names float32 max_velocity_scaling float32 max_acceleration_scaling --- bool success string error_message float64 total_time_sec --- float32 progress string current_state ``` ## 5. rosidl_generate_interfaces ROS2 用 `rosidl` 自动从 .msg/.srv/.action 生成 C++ / Python 代码: ```cmake find_package(rosidl_default_generators REQUIRED) rosidl_generate_interfaces(${PROJECT_NAME} "msg/SensorReading.msg" "srv/GetCalibration.srv" "action/MoveArm.action" DEPENDENCIES std_msgs geometry_msgs ADD_LINTER_TESTS ) ``` 生成位置: - C++ 头文件:`install//include//msg/.hpp` - Python 模块:`install//lib/python3.10/site-packages//msg/.py` ## 6. CMakeLists.txt + package.xml 配置 **`package.xml` 必备**: ```xml rosidl_default_generators rosidl_default_runtime rosidl_interface_packages ``` **`CMakeLists.txt` 顺序**: ```cmake find_package(ament_cmake REQUIRED) find_package(rosidl_default_generators REQUIRED) find_package(std_msgs REQUIRED) find_package(geometry_msgs REQUIRED) rosidl_generate_interfaces(${PROJECT_NAME} ...) ament_target_dependencies(${PROJECT_NAME}_core rclcpp "rosidl_typesupport_cpp") rosidl_target_interfaces(${PROJECT_NAME}_core ${PROJECT_NAME} "rosidl_typesupport_cpp") ``` ## 7. C++ / Python 使用 ### C++ ```cpp #include "cpp_custom_interface/msg/sensor_reading.hpp" auto msg = cpp_custom_interface::msg::SensorReading(); msg.sensor_id = "imu_0"; msg.value = 1.234; publisher_->publish(msg); ``` ### Python ```python from cpp_custom_interface.msg import SensorReading msg = SensorReading() msg.sensor_id = 'imu_0' msg.value = 1.234 publisher.publish(msg) ``` ## 8. 设计原则 | 原则 | 说明 | |---|---| | **优先标准接口** | 90% 场景用 `std_msgs` / `sensor_msgs` | | **字段 snake_case + 单位后缀** | `velocity_mps` 而不是 `v` | | **Header 必备** | 任何有"时间戳"的消息都加 `std_msgs/Header` | | **数组 vs 单值** | `float64[]` 用于多维数据,单值用 `float64` | | **不要嵌指针** | 用 ID (`string object_id`) 而非 `string&` | | **字段命名清晰** | `target_pose` 不是 `tp`,`max_velocity_scaling` 不是 `v_max` | | **Result 加 success + error_message** | client 知道成功还是失败 | ## 9. 推荐阅读 - [ROS2 自定义接口官方教程](https://docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Custom-ROS2-Interfaces.html) - [REP-127: ROS Message 标准](https://www.ros.org/reps/rep-0127.html) - [rosidl 文档](https://design.ros2.org/articles/legacy_interface_definition.html) - [`cpp_custom_interface` 包](../src/cpp_custom_interface/README.md) — 本仓库的演示 --- --- ## 📖 阅读路径导航 > 💡 这是仓库 `doc/` 下所有文档的推荐阅读顺序。[返回 README 总导航](../README.md#-23-篇文档怎么读) > > ⏱ **本文预计阅读时间**: 40 分钟 > 📍 **当前位置**: 第 7 / 24 篇 - ⏮ **上一篇**: [参数系统深度](../15-params.md) - ⏭ **下一篇**: [Lifecycle Node](../17-lifecycle.md)