docs(nav): 阅读路径导航 + 数字统一
This commit is contained in:
@@ -1,67 +1,259 @@
|
||||
# cpp_custom_interface
|
||||
# cpp_custom_interface — C++ 自定义接口(.msg / .srv / .action)
|
||||
|
||||
ROS2 自定义接口演示包(C++)。属于 Level 1 基础机制第 10 块。
|
||||
> 学会自定义 ROS2 接口,跨包/跨语言共享数据结构。
|
||||
>
|
||||
> 预计学习时间:2-3 小时。
|
||||
|
||||
## 自定义接口
|
||||
---
|
||||
|
||||
| 类型 | 文件 | 字段 |
|
||||
|---|---|---|
|
||||
| `msg` | `SensorReading.msg` | header + sensor_id + unit + value |
|
||||
| `srv` | `GetCalibration.srv` | req: sensor_id / resp: intrinsic_matrix[9] + bias[3] + date + valid |
|
||||
| `action` | `MoveArm.action` | goal: target_pose + joint_names + scaling / feedback: progress + state / result: success + time |
|
||||
## 这是什么?
|
||||
|
||||
## 节点
|
||||
ROS2 自带的消息类型(`std_msgs/String`、`geometry_msgs/Twist`...)够用吗?不够。
|
||||
|
||||
- **`sensor_publisher_cpp`**: 周期性发布 `SensorReading`(正弦曲线模拟传感器读数)
|
||||
- **`calibration_server_cpp`**: 提供 `GetCalibration` 服务(返回模拟相机内参)
|
||||
- **`move_arm_server_cpp`**: 提供 `MoveArm` Action(5 阶段模拟移动)
|
||||
**做项目一定要自定义接口**,比如:
|
||||
- 机器人: `/robot_status.msg` (含电量、位置、状态)
|
||||
- 机械臂: `/MoveArm.action` (含目标位姿 + 反馈进度 + 结果)
|
||||
- 相机: `/CameraCalibration.srv` (含内外参矩阵)
|
||||
|
||||
## 关键概念
|
||||
**本包演示**:
|
||||
- `.msg` (消息,Topic 用): `SensorReading`(传感器读数)
|
||||
- `.srv` (服务): `GetCalibration`(获取标定数据)
|
||||
- `.action` (动作): `MoveArm`(机械臂运动)
|
||||
|
||||
| 概念 | 用途 |
|
||||
|---|---|
|
||||
| `rosidl_generate_interfaces` | 自动生成 C++ / Python 接口代码 |
|
||||
| `.msg` / `.srv` / `.action` | 接口定义文件 |
|
||||
| `rosidl_default_generators` | 构建时依赖 |
|
||||
| `rosidl_default_runtime` | 运行时依赖 |
|
||||
| `ament_cmake` | C++ 包构建类型 |
|
||||
---
|
||||
|
||||
## 运行
|
||||
## 🎯 学完之后你能做什么?
|
||||
|
||||
```bash
|
||||
# 启动所有自定义接口节点
|
||||
ros2 launch cpp_custom_interface custom_launch.py
|
||||
1. ✅ 定义 `.msg` / `.srv` / `.action` 文件
|
||||
2. ✅ 用 `rosidl_generate_interfaces` 生成 C++ / Python 代码
|
||||
3. ✅ 在自己的包里 include 生成的 C++ 头文件
|
||||
4. ✅ 跨包/跨语言用自定义类型通信
|
||||
|
||||
# CLI 调用服务
|
||||
ros2 service call /get_calibration cpp_custom_interface/srv/GetCalibration "{sensor_id: 'lidar_front'}"
|
||||
---
|
||||
|
||||
# CLI 发 Action goal
|
||||
ros2 action send_goal /move_arm cpp_custom_interface/action/MoveArm "{
|
||||
target_pose: {header: {frame_id: 'base_link'}, pose: {position: {x: 0.3, y: 0.0, z: 0.2}, orientation: {w: 1.0}}},
|
||||
joint_names: ['joint1','joint2','joint3'],
|
||||
max_velocity_scaling: 0.5,
|
||||
max_acceleration_scaling: 0.5
|
||||
}" --feedback
|
||||
## 📁 文件结构
|
||||
|
||||
# CLI 看自定义消息
|
||||
ros2 topic echo /sensor_reading
|
||||
```
|
||||
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
|
||||
|
||||
```bash
|
||||
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"
|
||||
```
|
||||
|
||||
### 订阅看消息(另开终端)
|
||||
|
||||
```bash
|
||||
ros2 topic echo /sensor_reading --once
|
||||
```
|
||||
|
||||
**预期输出**:
|
||||
```
|
||||
header:
|
||||
stamp:
|
||||
sec: ...
|
||||
nanosec: ...
|
||||
frame_id: imu_frame
|
||||
sensor_id: imu_0
|
||||
unit: rad/s
|
||||
value: 0.0
|
||||
```
|
||||
|
||||
### 启动标定服务(另开终端)
|
||||
|
||||
```bash
|
||||
ros2 run cpp_custom_interface calibration_server_cpp
|
||||
```
|
||||
|
||||
```bash
|
||||
# 调用服务
|
||||
ros2 service call /get_calibration cpp_custom_interface/srv/GetCalibration "{sensor_id: 'lidar_front'}"
|
||||
```
|
||||
|
||||
### 启动机械臂 Action(另开终端)
|
||||
|
||||
```bash
|
||||
ros2 run cpp_custom_interface move_arm_server_cpp
|
||||
```
|
||||
|
||||
```bash
|
||||
# 发 goal
|
||||
ros2 action send_goal --feedback /move_arm cpp_custom_interface/action/MoveArm "{max_velocity_scaling: 0.5}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 CMakeLists.txt 关键配置
|
||||
|
||||
```cmake
|
||||
# 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 必须加**:
|
||||
```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++
|
||||
|
||||
```cpp
|
||||
#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
|
||||
|
||||
```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`。
|
||||
|
||||
---
|
||||
|
||||
## 🧪 跑测试
|
||||
|
||||
```bash
|
||||
colcon test --packages-select cpp_custom_interface
|
||||
colcon test-result --all --verbose
|
||||
```
|
||||
|
||||
测试覆盖:
|
||||
**预期**:`cpp_custom_interface: gtest 3/3 ✓` 全部通过。
|
||||
|
||||
| 用例 | 内容 |
|
||||
|---|---|
|
||||
| `SensorReadingFields` | msg 字段构造正确 |
|
||||
| `GetCalibrationRequestResponse` | srv 字段 + 长度正确 |
|
||||
| `MoveArmGoalFeedbackResult` | action 三段都正确 |
|
||||
---
|
||||
|
||||
## 深度学习
|
||||
## 🔧 自己定义接口
|
||||
|
||||
- 编程规范:[`doc/CODING_STYLE.md`](../doc/CODING_STYLE.md)
|
||||
- 自定义接口:[`doc/16-custom-interfaces.md`](../doc/16-custom-interfaces.md)
|
||||
1. 在 `msg/`、`srv/`、`action/` 下新建 `.msg`/`.srv`/`.action` 文件
|
||||
2. 改 `CMakeLists.txt` 的 `MSG_FILES`/`SRV_FILES`/`ACTION_FILES` 列表
|
||||
3. `colcon build`
|
||||
4. 生成的代码在 `install/cpp_custom_interface/include/`(C++)或 `install/cpp_custom_interface/lib/python3.10/site-packages/`(Python)
|
||||
|
||||
---
|
||||
|
||||
## 📚 深入学习
|
||||
|
||||
- [doc/16-custom-interfaces.md](../../doc/16-custom-interfaces.md) — 自定义接口深度(嵌套 / 数组 / 常量)
|
||||
|
||||
---
|
||||
|
||||
## ⏭️ 下一个包
|
||||
|
||||
继续学 **[py_vision_demo](../py_vision_demo/README.md)** — 图像话题(cv_bridge + OpenCV)。
|
||||
|
||||
---
|
||||
|
||||
## 📍 学习路径导航
|
||||
|
||||
| ⏮ 上一个 | 🏠 当前位置 | ⏭ 下一个 |
|
||||
|---|---|---|
|
||||
| [py_params — Python Parameter](../py_params/README.md) | **cpp_custom_interface — C++ 自定义接口** | [py_vision_demo — Python 图像](../py_vision_demo/README.md) |
|
||||
|
||||
📍 完整 12 包学习顺序见 [主 README](../../README.md#-12-包推荐学习顺序)
|
||||
|
||||
Reference in New Issue
Block a user