本文以无人机集群通信为例,从零创建一个 ROS 2 自定义消息接口包 onboard_msgs,其中包含两类消息:OnboardCommand(下发命令)和 OnboardState(上报状态)。整个过程分五步:创建接口包、编写 .msg、配置 CMakeLists.txt、配置 package.xml、编译验证。

适用环境:

  • ROS 2 Humble,Linux + bash;
  • 已创建工作空间 ~/ros2_ws,并包含 src 目录;
  • 构建工具 colcon,构建类型 ament_cmake。

一、创建接口包

1
2
3
4
5
cd ~/ros2_ws/src
ros2 pkg create onboard_msgs \
--build-type ament_cmake \
--dependencies rosidl_default_generators \
--license Apache-2.0

--dependencies 后面填写消息定义所需的依赖,其中 rosidl_default_generators 是必须的。

进入包目录,创建存放消息的文件夹:

1
2
cd onboard_msgs
mkdir -p msg

二、定义消息

msg/OnboardCommand.msg:

1
2
3
uint16 target_id   # 目标无人机编号
string name # 命令名称
string params # 命令参数(JSON 格式)

msg/OnboardState.msg:

1
2
3
4
5
6
7
uint16 uav_id     # 无人机编号

float64 lat_deg # 纬度
float64 lon_deg # 经度
float64 alt_msl # 平均海平面高度

float32 battery # 电量百分比

完成后的包结构(节选):

1
2
3
4
5
6
onboard_msgs/
├─ CMakeLists.txt
├─ package.xml
└─ msg/
├─ OnboardCommand.msg
└─ OnboardState.msg

三、配置 CMakeLists.txt

在包根目录的 CMakeLists.txt 中加入以下关键内容(保留模板中已有的行):

1
2
3
4
5
6
7
8
9
10
11
12
13
cmake_minimum_required(VERSION 3.8)
project(onboard_msgs)

find_package(ament_cmake REQUIRED)
find_package(rosidl_default_generators REQUIRED)

# 声明需要生成的接口
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/OnboardCommand.msg"
"msg/OnboardState.msg"
)

ament_package()

四、配置 package.xml

确保依赖和接口组声明完整:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>onboard_msgs</name>
<version>0.0.1</version>
<description>TO DO</description>
<maintainer email="you@example.com">Your Name</maintainer>
<license>Apache-2.0</license>

<!-- 构建工具 -->
<buildtool_depend>ament_cmake</buildtool_depend>
<!-- 用于生成接口代码 -->
<buildtool_depend>rosidl_default_generators</buildtool_depend>

<!-- 运行期 -->
<!-- 用于供其它包调用接口 -->
<depend>rosidl_default_runtime</depend>

<!-- 用于声明该功能包是一个消息接口功能包,必须包含 -->
<member_of_group>rosidl_interface_packages</member_of_group>

<export>
<build_type>ament_cmake</build_type>
</export>
</package>

五、编译与验证

在工作空间根目录编译,并加载环境:

1
2
3
cd ~/ros2_ws
colcon build --packages-select onboard_msgs
source install/setup.bash

确认接口已经生成:

1
ros2 interface list | grep onboard_msgs

查看具体定义:

1
2
ros2 interface show onboard_msgs/msg/OnboardCommand
ros2 interface show onboard_msgs/msg/OnboardState

六、用命令行试发消息

用 ros2 topic pub 和 ros2 topic echo 快速检查消息格式和编解码是否正常。发布一条命令到 /uav/cmd:

1
2
ros2 topic pub /uav/cmd onboard_msgs/msg/OnboardCommand \
'{target_id: 1, name: "Takeoff", params: "{\"alt\": 5.0}"}'

回显无人机状态(需要已有节点发布到 /uav/state):

1
ros2 topic echo /uav/state onboard_msgs/msg/OnboardState

在 bash 中传 JSON 时要注意双引号转义,也可以改用 YAML 多行写法避免转义错误。

七、在其他包中使用

使用这些消息的 C++ 包,需要在自己的 CMakeLists.txt 中加入:

1
2
3
4
5
6
7
8
9
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(onboard_msgs REQUIRED)

add_executable(my_node src/my_node.cpp)
ament_target_dependencies(my_node rclcpp onboard_msgs)
install(TARGETS my_node DESTINATION lib/${PROJECT_NAME})

ament_package()

并在 package.xml 中添加:

1
<depend>onboard_msgs</depend>

八、常见错误

现象 原因与处理
新增的消息没有生成 没有加进 rosidl_generate_interfaces,补上后重新 colcon build
其他包找不到生成的类型 package.xml 缺少 <depend>rosidl_default_runtime</depend>
终端找不到接口定义 编译后没有 source install/setup.bash
命令行发布 JSON 报错 引号转义错误;外层用单引号、内部双引号转义,或改用 YAML
多机话题互相干扰 为每架无人机使用不同的命名空间,如 /uav1/..、/uav2/..

参考