ROS2 Action 踩坑实战:从 “找不到 action 符号” 到完整计数 Demo 通跑
2026/7/8 11:42:15
网站开发
最近在学习 ROS2 动作通信 Action照着教程写了一套数字累加 Demo刚写完代码 VSCode 直接报红在文档 Count.action 中找不到符号踩了编译、依赖、环境刷新一大堆坑。 今天就结合自己实操截图一边排错一边从零拆解 Action 服务端 客户端完整工程新手看完能避开 90% ROS2 接口编译问题。先看我的工程截图 左侧资源管理器是标准action_demo功能包包含自定义 action 消息、服务端 / 客户端 python 脚本中间是Count.action三段式消息定义右侧分服务端、客户端两份业务代码下方终端已经成功跑通 action_server 节点日志正常输出「动作通信服务端启动完成」。二、先搞懂ROS2 Action 到底是什么很多初学者分不清 Topic、Service、Action一句话区分Topic单向流式数据持续发布无应答传感器数据、图像流Service同步一问一答短任务执行完立刻返回无中途反馈开关设备、查询参数Action异步长时任务三大核心数据段Goal客户端下发任务目标比如本次要计数到多少Feedback任务运行中实时推送进度当前计数值Result任务全部结束返回最终结果累加总和 额外支持中途取消任务机器人导航、机械臂运动、长时图像处理全都依赖 Action。三、从零搭建 action_demo 功能包1. 包目录结构plaintextcolcon_ws/src/action_demo ├── action/ │ └── Count.action # 自定义动作接口文件 ├── scripts/ │ ├── action_server.py # 服务端执行计数任务 │ └── action_client.py # 客户端下发计数目标 ├── include/action_demo ├── package.xml └── setup.py2. 自定义 Count.action 接口文件路径action/Count.actionaction# Goal客户端发送目标数字 int32 target_num --- # Result任务完成后返回总和 int32 total_sum --- # Feedback运行中实时反馈当前数字 int32 current_num三段内容用---分隔顺序不能乱这是 ROS2 固定语法。3. Action 服务端完整代码 action_server.pypython运行#!/usr/bin/env python3 import rclpy from rclpy.node import Node from rclpy.action import ActionServer, GoalResponse, CancelResponse from action_demo.action import Count import time class CountActionServer(Node): def __init__(self): super().__init__(count_action_server) # 实例化动作服务绑定四类回调 self.action_server ActionServer( self, Count, count_action, goal_callbackself.goal_cb, cancel_callbackself.cancel_cb, execute_callbackself.execute_cb ) self.get_logger().info(动作通信服务端启动完成) # 收到目标请求判断是否接收任务 def goal_cb(self, goal_req): self.get_logger().info(f收到计数目标{goal_req.target_num}) return GoalResponse.ACCEPT # 客户端发起取消时触发 def cancel_cb(self, goal_handle): self.get_logger().warn(收到任务取消指令) return CancelResponse.ACCEPT # 核心业务逻辑循环计数、推送进度、返回结果 def execute_cb(self, goal_handle): target goal_handle.request.target_num total 0 feedback Count.Feedback() for num in range(1, target 1): # 检测取消信号 if goal_handle.is_cancel_requested: goal_handle.canceled() self.get_logger().info(任务已取消直接退出) return Count.Result() total num feedback.current_num num # 实时推送进度给客户端 goal_handle.publish_feedback(feedback) self.get_logger().info(f运行进度{num}) time.sleep(1) # 任务正常完成 goal_handle.succeed() res Count.Result() res.total_sum total self.get_logger().info(f计数完成总和{total}) return res def main(): rclpy.init() server CountActionServer() rclpy.spin(server) rclpy.shutdown() if __name__ __main__: main()4. Action 客户端完整代码 action_client.pypython运行#!/usr/bin/env python3 import rclpy from rclpy.node import Node from rclpy.action import ActionClient from action_demo.action import Count class CountActionClient(Node): def __init__(self): super().__init__(count_action_client) self.action_client ActionClient(self, Count, count_action) # 下发计数目标 def send_task(self, target): self.action_client.wait_for_server() goal Count.Goal() goal.target_num target # 异步发送目标绑定进度回调 future self.action_client.send_goal_async(goal, feedback_callbackself.feedback_cb) future.add_done_callback(self.goal_response_cb) # 实时接收服务端进度反馈 def feedback_cb(self, fb_msg): self.get_logger().info(f客户端收到进度{fb_msg.feedback.current_num}) # 服务端确认是否接收任务 def goal_response_cb(self, future): handle future.result() if not handle.accepted: self.get_logger().error(任务被服务端拒绝) return self.get_logger().info(任务已受理等待执行结果...) res_future handle.get_result_async() res_future.add_done_callback(self.result_cb) # 任务结束打印最终累加结果 def result_cb(self, future): res future.result().result self.get_logger().info(f最终累加总和{res.total_sum}) def main(): rclpy.init() client CountActionClient() # 设置目标累加到10 client.send_task(10) rclpy.spin(client) rclpy.shutdown() if __name__ __main__: main()四、功能包配置文件修改报错根源就在这1. package.xml 必须补全依赖缺少下面任意一条都会出现「找不到 Count.action 符号」报错xml!-- 编译工具依赖 -- buildtool_dependament_python/buildtool_depend buildtool_dependrosidl_default_generators/buildtool_depend !-- 运行依赖 -- dependrclpy/depend dependaction_msgs/depend !-- 接口运行依赖 -- exec_dependrosidl_default_runtime/exec_depend member_of_grouprosidl_interface_packages/member_of_group2. setup.py 注册可执行文件方便用ros2 run直接启动节点python运行entry_points{ console_scripts: [ action_server scripts.action_server:main, action_client scripts.action_client:main ], },五、重点排坑VSCode 提示 “在文档 Count.action 中找不到符号”对应截图里编辑器报错我踩过 3 个核心原因逐个排查坑 1修改 action 文件后没有重新编译.action属于自定义接口修改后必须重新生成代码否则 python 无法识别接口 解决命令bash运行cd ~/colcon_ws colcon build --packages-select action_demo source install/setup.bash坑 2没有刷新环境变量编译完必须执行source install/setup.bash新开终端也要重新 source否则系统找不到编译生成的消息接口。截图里终端第一行就是执行 source 刷新环境。坑 3package.xml 缺少 rosidl 编译依赖如果没加rosidl_default_generatorscolcon 不会自动把 action 文件转换成 python 接口直接全代码报红。坑 4文件夹 / 文件名大小写不匹配ROS2 接口区分大小写文件夹必须叫action文件Count.action不能写成 count.action。六、编译 完整运行流程和截图操作完全对应进入工作空间编译 刷新环境bash运行cd ~/colcon_ws colcon build --packages-select action_demo source install/setup.bash终端 1启动 Action 服务端截图中正在运行的节点bash运行ros2 run action_demo action_server终端输出日志[INFO] [1783339717.748088624] [action server]: 动作通信服务端启动完成新开终端 2刷新环境启动客户端下发任务bash运行source install/setup.bash ros2 run action_demo action_client运行日志效果服务端持续每秒打印当前计数进度客户端同步接收实时数字全部计数结束后两端打印 1~10 累加总和 55客户端可添加取消逻辑随时中断计数任务。七、Action 开发核心回调总结goal_callback校验、接收客户端下发的任务目标cancel_callback处理客户端取消请求execute_callback服务端核心业务循环publish 反馈数据feedback_callback客户端实时接收进度做进度展示所有通信基于异步 Future不会阻塞节点自旋多任务并发更稳定。八、学习总结Action 是 ROS2 长时任务专用通信方式自带进度反馈、取消机制自定义.action接口必须重新 colcon 编译 source否则编辑器报符号缺失开发流程定义 action 消息→配置 package 依赖→编写服务端 / 客户端→编译刷新→分终端运行调试本套计数 Demo 可直接复用拓展到机器人导航、机械臂点位运动、视觉识别等大型项目。