
别再只用Service了ROS1 Action通信保姆级教程从导航进度条到任务取消手把手教你实现带反馈的机器人任务当你的机器人正在执行一个长达10分钟的导航任务时突然发现目标点设置错误这时候如果只能干等着任务完成或者强行重启节点是不是觉得特别不优雅这就是为什么你需要掌握ROS1 Action通信——它能让机器人任务像手机APP下载文件一样既能实时显示进度条又能随时点击取消。1. 为什么Action通信是机器人开发的必备技能在真实的机器人应用场景中Service通信的局限性会变得越来越明显。想象一下这些常见情况机器人正在执行30分钟的仓库巡检任务管理员需要中途暂停任务检查某个货架机械臂正在进行复杂轨迹规划操作员希望实时了解当前计算进度自动驾驶车辆长距离导航时乘客想临时更改目的地Action通信三大核心优势实时反馈机制服务端可以持续向客户端发送任务执行进度任务可取消性客户端可以在任何时候请求终止正在执行的任务状态机管理内置PREEMPTED、SUCCEEDED等状态规范任务生命周期对比Service通信的一锤子买卖模式Action显然更适合现代机器人系统的交互需求。下面这个对比表更能说明问题特性Service通信Action通信任务中断不支持支持取消指令进度反馈无多阶段反馈适用场景快速原子操作长时间任务状态管理简单成功/失败完整状态机2. 搭建Action通信开发环境2.1 创建Action专用功能包不同于常规ROS包Action通信需要额外依赖actionlibcatkin_create_pkg robot_navigation_action roscpp actionlib std_msgs关键目录结构应包含robot_navigation_action/ ├── action/ │ └── Navigation.action ├── src/ │ ├── navigation_server.cpp │ └── navigation_client.cpp └── CMakeLists.txt2.2 定义自定义Action消息在action/Navigation.action中定义导航任务的通信协议# 目标定义 geometry_msgs/PoseStamped target_pose float32 speed_limit --- # 结果定义 float32 total_distance duration execution_time --- # 反馈定义 float32 completion_percentage geometry_msgs/Pose current_pose string current_status这个定义包含目标目标位姿和速度限制结果总行驶距离和耗时反馈完成百分比、当前位置和状态描述3. 实现带反馈的导航服务端3.1 构建SimpleActionServer服务端核心代码框架#include actionlib/server/simple_action_server.h #include robot_navigation_action/NavigationAction.h typedef actionlib::SimpleActionServerrobot_navigation_action::NavigationAction NavServer; void executeNavigation(const robot_navigation_action::NavigationGoalConstPtr goal, NavServer* server) { // 初始化导航任务 ros::Rate loop_rate(10); bool navigation_success true; // 模拟导航过程 for(int progress0; progress100; progress5) { // 检查是否收到取消请求 if(server-isPreemptRequested()) { server-setPreempted(); ROS_WARN(导航任务被用户取消); return; } // 构建反馈消息 robot_navigation_action::NavigationFeedback feedback; feedback.completion_percentage progress; // 此处应填充真实的当前位置数据 server-publishFeedback(feedback); loop_rate.sleep(); } // 任务完成 if(navigation_success) { robot_navigation_action::NavigationResult result; result.total_distance 15.7; // 模拟数据 server-setSucceeded(result); } }3.2 关键功能点实现进度反馈机制feedback.completion_percentage calculate_progress(); feedback.current_pose get_current_pose(); feedback.current_status get_nav_status(); server-publishFeedback(feedback);任务取消响应if(server-isPreemptRequested()) { stop_robot_movement(); // 实际项目中应调用停止函数 server-setPreempted(); return; }4. 开发智能交互客户端4.1 客户端核心架构#include actionlib/client/simple_action_client.h typedef actionlib::SimpleActionClientrobot_navigation_action::NavigationAction NavClient; // 反馈回调 void feedbackCB(const robot_navigation_action::NavigationFeedbackConstPtr feedback) { ROS_INFO(进度: %.1f%%, 当前位置: (%.2f, %.2f), feedback-completion_percentage, feedback-current_pose.pose.position.x, feedback-current_pose.pose.position.y); } // 主函数片段 NavClient client(robot_navigation, true); client.waitForServer(); robot_navigation_action::NavigationGoal goal; goal.target_pose build_target_pose(2.5, 3.0); // 设置目标位置 goal.speed_limit 0.5; // 设置速度限制 client.sendGoal(goal, doneCB, activeCB, feedbackCB);4.2 实现任务取消功能添加取消按钮处理逻辑void cancelNavigation() { if(client.getState() actionlib::SimpleClientGoalState::ACTIVE) { client.cancelGoal(); ROS_INFO(已发送取消指令); } else { ROS_WARN(当前没有正在执行的任务); } }5. 实战构建完整的导航任务系统5.1 系统集成测试流程启动ROS核心roscore启动导航服务端rosrun robot_navigation_action navigation_server启动客户端并发送目标rosrun robot_navigation_action navigation_client _x:3.0 _y:2.5测试取消功能新终端rostopic pub /navigation_cancel std_msgs/Empty {}5.2 常见问题排查指南问题现象可能原因解决方案客户端无法连接服务端节点名称不匹配检查action名称是否一致收不到反馈反馈频率过低增加publishFeedback调用频率取消请求无响应服务端未检查preempt添加isPreemptRequested检查客户端卡在waitForServer服务端未启动确认服务端正常运行6. 高级应用技巧6.1 多任务队列管理对于需要顺序执行多个导航点的情况可以实现任务队列std::queuegeometry_msgs::Pose nav_points; void sendNextGoal() { if(!nav_points.empty()) { auto next nav_points.front(); nav_points.pop(); robot_navigation_action::NavigationGoal goal; goal.target_pose next; client.sendGoal(goal, boost::bind(doneCBWithQueue, _1, _2)); } }6.2 结合RViz可视化反馈在反馈回调中添加可视化标记发布void feedbackCB(const robot_navigation_action::NavigationFeedbackConstPtr fb) { visualization_msgs::Marker marker; marker.header.frame_id map; marker.pose fb-current_pose.pose; marker_pub.publish(marker); }7. 性能优化与最佳实践反馈频率控制对于高频控制如机械臂建议50-100Hz反馈对于导航任务10-20Hz足够使用rosparam动态配置反馈频率param namefeedback_rate value15.0 /网络带宽优化只反馈必要数据对大尺寸消息如图像使用压缩或缩略图考虑使用共用内存减少拷贝开销错误处理增强try { // 导航核心逻辑 } catch (const std::exception e) { server-setAborted(result, e.what()); }