一、前言

动作通信(Action)是 ROS2 中用于长时间任务交互的通信模型,兼具服务同步应答、话题持续反馈的优势,适用于机械臂运动、导航、累加计算等耗时任务。 本文从零搭建自定义 Action 消息,分别使用 C++、Python 实现动作服务端 + 客户端,完整复现「1~N 累加、实时进度反馈、任务取消、结果返回」全流程,全程附踩坑解决方案,适合 ROS2 初学者系统学习。

环境:华为云开发空间 ROS2 Jazzy

二、整体工程结构

robot_ws/src

├── base_interfaces_demo # 自定义Action消息包

├── cpp03_action # C++动作通信实现

└── py03_action # Python动作通信

三、第一步:自定义 Action 接口 base_interfaces_demo实现

3.1 创建功能包

cd ~/robot_ws/src
ros2 pkg create --build-type ament_cmake base_interfaces_demo --dependencies rclcpp rclcpp_action action_msgs
 
cd base_interfaces_demo
mkdir action
nano action/Progress.action
 

文件内容:

# 请求数据(客户端发给服务端)
int64 num
---
# 最终结果(任务完成后返回)
int64 sum
---
# 实时进度反馈(循环持续推送)
float64 progress
 

3.3 配置 package.xml

新增依赖与分组标签(编译报错核心修复点)

<buildtool_depend>rosidl_default_generators</buildtool_depend>
<depend>action_msgs</depend>
<member_of_group>rosidl_interface_packages</member_of_group>
 

3.4 配置 CMakeLists.txt

文件末尾添加接口生成代码,只保留 action 文件,规避 msg/srv 不存在报错

rosidl_generate_interfaces(${PROJECT_NAME}
  "action/Progress.action"
)
ament_export_dependencies(rosidl_default_runtime)

3.5 编译与验证接口

cd ~/robot_ws
colcon build --packages-select base_interfaces_demo
source install/setup.bash
# 校验action是否生成成功
ros2 interface show base_interfaces_demo/action/Progress
 

输出三段消息结构即代表自定义动作接口完成。

四、第二步:C++ 动作通信 cpp03_action

4.1 创建 C++ 功能包

# 创建工作空间并初始化包
cd ~/robot_ws/src
ros2 pkg create --build-type ament_cmake cpp03_action --dependencies rclcpp rclcpp_action base_interfaces_demo

# 进入包目录并创建标准ROS 2目录结构
cd cpp03_action
mkdir -p src
 

4.2 动作服务端 demo01_action_server.cpp

实现逻辑:接收数字、循环累加、实时推送进度、支持任务取消、返回总和 完整代码见文末资源,核心回调:

  1. handle_goal:校验请求数字,小于 1 拒绝任务
  2. handle_cancel:接收客户端取消指令
  3. execute:子线程执行累加,循环发布进度反馈
  4. handle_accepted:新开线程执行耗时任务,防止节点阻塞

4.3 动作客户端 demo02_action_client.cpp

实现逻辑:发送目标数字、监听服务端接收状态、打印实时进度、接收最终求和结果。

4.4 CMakeLists.txt 编译配置

find_package(rclcpp REQUIRED)
find_package(rclcpp_action REQUIRED)
find_package(base_interfaces_demo REQUIRED)

# 编译服务端
add_executable(demo01_action_server src/demo01_action_server.cpp)
ament_target_dependencies(demo01_action_server rclcpp rclcpp_action base_interfaces_demo)

# 编译客户端
add_executable(demo02_action_client src/demo02_action_client.cpp)
ament_target_dependencies(demo02_action_client rclcpp rclcpp_action base_interfaces_demo)

# 安装可执行文件
install(TARGETS demo01_action_server demo02_action_client DESTINATION lib/${PROJECT_NAME})

4.5 编译与双终端运行 

# 编译
cd ~/robot_ws
colcon build --packages-select cpp03_action
source install/setup.bash

终端 1(服务端)

ros2 run cpp03_action demo01_action_server

终端 2(客户端)

ros2 run cpp03_action demo02_action_client

运行效果:服务端持续打印进度,客户端同步输出百分比,最终输出55(1~10 累加结果)

五、第三步:Python 动作通信 py03_action

5.1 创建 Python 功能包

cd ~/robot_ws/src
ros2 pkg create --build-type ament_python py03_action --dependencies rclpy base_interfaces_demo

5.2 Python 服务端 demo01_action_server_py.py

逻辑与 C++ 完全对齐,通过ActionServer绑定执行回调,循环 sleep 模拟耗时计算,publish_feedback 推送进度。

5.3 Python 客户端 demo02_action_client_py.py

ActionClient实现三类回调:目标接收回调、实时进度回调、最终结果回调。

5.4 setup.py 注册可执行程序(Python 核心配置)

找到 entry_points 修改:

entry_points={
    'console_scripts': [
        'demo01_action_server_py = py03_action.demo01_action_server_py:main',
        'demo02_action_client_py = py03_action.demo02_action_client_py:main',
    ],
},

5.5 编译运行

cd ~/robot_ws
colcon build --packages-select py03_action
source install/setup.bash

终端 1:

ros2 run py03_action demo01_action_server_py

终端 2:

ros2 run py03_action demo02_action_client_py

六、运行结果与警告说明

6.1 正常运行输出

客户端持续打印10%、20%...100%,最终输出sum = 55,服务端同步打印每一步进度,任务完成提示。

6.2 常见警告解决方案

  1. 警告:may be more than one action server for the action 'get_sum' 原因:C++ 与 Python 服务端重名话题冲突 解决:Ctrl+C 关闭所有旧 ROS2 终端,重新只启动单版本服务端。
  2. 运行时报没有那个文件或目录 原因:未进入工作空间刷新环境变量 解决:cd ~/robot_ws && source install/setup.bash
  3. 编译提示msg/Student.msg不存在 原因:CMakeLists 中残留旧消息路径 解决:删除 msg、srv 相关配置,仅保留 action 文件。

七、Action 通信核心原理总结

  1. 通信三部分:Goal(请求目标)、Feedback(实时反馈)、Result(最终结果);
  2. 服务端使用独立子线程执行耗时任务,避免节点阻塞;
  3. 支持任务取消、参数校验、异步回调,适配长时运动类机器人任务;
  4. C++ 与 Python 接口逻辑完全一致,仅语法、API 调用存在差异。

八、完整踩坑清单

  1. 自定义 action 包必须添加<member_of_group>标签,否则编译直接报错;
  2. Python 包必须在 setup.py 注册 console_scripts,否则 ros2 run 找不到程序;
  3. 每次新开终端必须执行 source 刷新环境变量;
  4. 多套服务端同时运行会产生话题冲突警告,测试时仅保留一套;
  5. Action 依赖action_msgs,自定义消息包必须显式声明依赖;
  6. C++ 动作任务必须开子线程,否则 spin 阻塞无法接收新请求。

九、总结

本文完整实现 ROS2 Action 全链路开发,从自定义动作消息,到 C++、Python 双语言服务端客户端开发,覆盖编译、运行、排错全流程,适合课程作业、毕业设计、入门学习使用。整套代码可直接复制运行,无冗余依赖,适配 ROS2 Humble/Jazzy 全系版本。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐