【实践项目】Action 通信控制海龟机器人移动到指定位置

张开发
2026/4/14 4:40:54 15 分钟阅读

分享文章

【实践项目】Action 通信控制海龟机器人移动到指定位置
一、实践任务总览1. 实践目的掌握ROS Action 通信的完整开发流程自定义 action 消息 Server Client实现长时任务的异步控制发送目标位置 → 海龟移动 →实时反馈当前位置→ 到达后返回最终结果对比理解 Topic / Service / Action 的适用场景掌握机器人长时控制的核心编程方法。2. 核心需求通过 ROS Action 通信机制控制海龟机器人从当前位置移动到指定目标位置并在移动过程中实时反馈当前位置信息。客户端Client 发送海龟目标坐标 (x,y,θ)服务器Server 接收目标控制海龟匀速运动实时反馈运动过程中每秒实时反馈海龟当前位置结果返回到达目标点距离0.1后结束任务并返回结果。技术特点异步执行不阻塞客户端进度可视实时查看海龟移动过程可扩展性支持任务取消3. 实践环境ROS 版本Melodic兼容 Noetic/Kinetic功能包turtlemove依赖roscpp rospy std_msgs actionlib actionlib_msgs turtlesim二、实践流程总步骤1. 创建功能包 → 2. 自定义 .action 消息 → 3. 配置编译文件 → 4. 编写 Server/Client 代码 → 5. 编译工程 → 6. 分步启动测试roscore → 海龟模拟器 → Server → Client三、分步实现详细可直接复现第一步创建工作空间与功能包# 1. 创建工作空间已创建可跳过 mkdir -p ~/workspace_hzq/src cd ~/workspace_hzq/src catkin_init_workspace # 2. 创建功能包 turtlemove带全依赖 catkin_create_pkg turtlemove roscpp rospy std_msgs actionlib actionlib_msgs turtlesim第二步自定义 Action 消息核心1. 创建 action目录cd ~/workspace_hzq/src/turtlemove mkdir action cd action2. 创建turtleMove.action文件touch turtleMove.action gedit turtleMove.action3. 写入消息定义三部分Goal → Result → Feedback# Goal客户端发送的目标位置 float64 turtle_target_x float64 turtle_target_y float64 turtle_target_theta --- # Result服务端最终返回的结果 float64 turtle_final_x float64 turtle_final_y float64 turtle_final_theta --- # Feedback服务端实时反馈的当前位置 float64 present_turtle_x float64 present_turtle_y float64 present_turtle_theta# Goal部分客户端发送的目标位置 float64 turtle_target_x # 目标x坐标 float64 turtle_target_y # 目标y坐标 float64 turtle_target_theta # 目标角度 --- # Result部分服务器返回的最终位置 float64 turtle_final_x # 最终x坐标 float64 turtle_final_y # 最终y坐标 float64 turtle_final_theta # 最终角度 --- # Feedback部分服务器实时反馈的当前位置 float64 present_turtle_x # 当前x坐标 float64 present_turtle_y # 当前y坐标 float64 present_turtle_theta # 当前角度第三步配置编译文件必须正确1. 配置package.xml添加消息生成与 action 依赖直接替换为以下内容buildtool_dependcatkin/buildtool_depend build_dependroscpp/build_depend build_dependrospy/build_depend build_dependstd_msgs/build_depend build_dependmessage_generation/build_depend build_dependactionlib/build_depend build_dependactionlib_msgs/build_depend build_export_dependroscpp/build_export_depend build_export_dependrospy/build_export_depend build_export_dependstd_msgs/build_export_depend build_export_dependmessage_generation/build_export_depend build_export_dependactionlib/build_export_depend build_export_dependactionlib_msgs/build_export_depend exec_dependroscpp/exec_depend exec_dependrospy/exec_depend exec_dependstd_msgs/exec_depend exec_dependmessage_runtime/exec_depend exec_dependactionlib/exec_depend exec_dependactionlib_msgs/exec_depend2. 配置CMakeLists.txt打开后按顺序添加以下配置# 1. find_package 添加依赖 find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs actionlib actionlib_msgs turtlesim message_generation ) # 2. 声明 action 文件 add_action_files( FILES turtleMove.action ) # 3. 生成消息依赖 generate_messages( DEPENDENCIES std_msgs actionlib_msgs ) # 4. catkin_package 运行依赖 catkin_package( LIBRARIES turtlemove CATKIN_DEPENDS roscpp rospy std_msgs message_runtime actionlib actionlib_msgs )编译后生成的头文件第四步编写 C 代码1. 服务端turtleMoveserver.cpp路径~/workspace_hzq/src/turtlemove/src功能接收目标 → 订阅海龟位姿 → 发布速度指令 → 实时反馈 → 到达结束#include ros/ros.h #include actionlib/server/simple_action_server.h #include turtlemove/turtleMoveAction.h #include turtlesim/Pose.h #include geometry_msgs/Twist.h #include cmath typedef actionlib::SimpleActionServerturtlemove::turtleMoveAction Server; struct Myturtle { float x; float y; float theta; }turtle_current_pose, turtle_target_pose; ros::Publisher vel_pub; // 订阅海龟当前位置 void poseCallback(const turtlesim::PoseConstPtr msg) { turtle_current_pose.x msg-x; turtle_current_pose.y msg-y; turtle_current_pose.theta msg-theta; } // Action 执行回调核心 void execute(const turtlemove::turtleMoveGoalConstPtr goal, Server* as) { turtlemove::turtleMoveFeedback feedback; ROS_INFO(【Server】收到目标开始移动); // 读取目标 turtle_target_pose.x goal-turtle_target_x; turtle_target_pose.y goal-turtle_target_y; turtle_target_pose.theta goal-turtle_target_theta; geometry_msgs::Twist cmd_vel; float distance; // 循环移动 while(ros::ok()) { ros::Rate rate(1); // 1秒更新一次 // 计算角度差与线速度 float angle_diff atan2(turtle_target_pose.y - turtle_current_pose.y, turtle_target_pose.x - turtle_current_pose.x) - turtle_current_pose.theta; cmd_vel.angular.z 1.0 * angle_diff; cmd_vel.linear.x 0.2 * sqrt(pow(turtle_target_pose.x - turtle_current_pose.x, 2) pow(turtle_target_pose.y - turtle_current_pose.y, 2)); // 计算与目标距离 distance sqrt(pow(turtle_target_pose.x - turtle_current_pose.x, 2) pow(turtle_target_pose.y - turtle_current_pose.y, 2)); // 发布速度 vel_pub.publish(cmd_vel); // 发布实时反馈 feedback.present_turtle_x turtle_current_pose.x; feedback.present_turtle_y turtle_current_pose.y; feedback.present_turtle_theta turtle_current_pose.theta; as-publishFeedback(feedback); ROS_INFO(距离目标: %.2f, distance); // 到达目标 if(distance 0.1) { cmd_vel.linear.x 0; cmd_vel.angular.z 0; vel_pub.publish(cmd_vel); break; } rate.sleep(); } ROS_INFO(【Server】海龟已到达目标); as-setSucceeded(); // 任务成功结束 } int main(int argc, char** argv) { setlocale(LC_CTYPE, zh_CN.utf8); ros::init(argc, argv, turtleMove_server); ros::NodeHandle nh; // 订阅位姿 发布速度 ros::Subscriber pose_sub nh.subscribe(/turtle1/pose, 10, poseCallback); vel_pub nh.advertisegeometry_msgs::Twist(/turtle1/cmd_vel, 10); // 启动 Action Server Server server(nh, turtleMove, boost::bind(execute, _1, server), false); server.start(); ROS_INFO(【Server】已启动等待客户端目标...); ros::spin(); return 0; }2. 客户端turtleMoveClient.cpp功能发送目标 → 接收实时反馈 → 接收最终结果 → 关闭节点#include ros/ros.h #include actionlib/client/simple_action_client.h #include turtlemove/turtleMoveAction.h typedef actionlib::SimpleActionClientturtlemove::turtleMoveAction Client; // 任务完成回调 void doneCb(const actionlib::SimpleClientGoalState state, const turtlemove::turtleMoveResultConstPtr result) { ROS_INFO(【Client】任务完成); ros::shutdown(); } // 任务激活回调 void activeCb() { ROS_INFO(【Client】目标已发送服务器开始执行); } // 接收反馈回调 void feedbackCb(const turtlemove::turtleMoveFeedbackConstPtr feedback) { ROS_INFO(当前位置x%.2f, y%.2f, theta%.2f, feedback-present_turtle_x, feedback-present_turtle_y, feedback-present_turtle_theta); } int main(int argc, char** argv) { setlocale(LC_CTYPE, zh_CN.utf8); ros::init(argc, argv, turtleMove_client); // 创建客户端 Client client(turtleMove, true); ROS_INFO(【Client】等待服务器启动...); client.waitForServer(); // 发送目标(8,8,0) turtlemove::turtleMoveGoal goal; goal.turtle_target_x 8.0; goal.turtle_target_y 8.0; goal.turtle_target_theta 0.0; // 发送并绑定回调 client.sendGoal(goal, doneCb, activeCb, feedbackCb); ros::spin(); return 0; }配置CMakeLists.txt# 5. 编译可执行文件 链接库 add_executable(turtleMoveserver src/turtleMoveserver.cpp) add_executable(turtleMoveClient src/turtleMoveClient.cpp) add_dependencies(turtleMoveserver ${PROJECT_NAME}_gencpp) add_dependencies(turtleMoveClient ${PROJECT_NAME}_gencpp) target_link_libraries(turtleMoveserver ${catkin_LIBRARIES}) target_link_libraries(turtleMoveClient ${catkin_LIBRARIES})第五步编译工程cd ~/workspace_hzq catkin_make source devel/setup.bash四、运行测试固定顺序终端 1启动 ROS 核心roscore终端 2启动海龟模拟器rosrun turtlesim turtlesim_node终端 3启动 Action 服务端Servercd ~/workspace_hzq source devel/setup.bash rosrun turtlemove turtleMoveserver终端 4启动 Action 客户端Clientcd ~/workspace_hzq source devel/setup.bash rosrun turtlemove turtleMoveClient五、预期运行效果时间线展示时间节点状态输出内容0sServer 启动等待客户端目标1sClient 启动发送目标 (8,8)2sServer 开始运动实时打印距离目标、当前位置2~15s持续运动Client 每秒刷新海龟坐标15s 左右到达目标距离0.1停止运动16s任务结束Server/Client 均提示完成5.1 预期输出[INFO] [时间戳]: 正在等待Action服务器启动... [INFO] [时间戳]: 服务器已连接准备发送目标 [INFO] [时间戳]: 目标已被服务器接受开始执行 [INFO] [时间戳]: 当前位置: (5.544445, 5.544445, 0.000000) [INFO] [时间戳]: 当前位置: (6.172003, 5.811345, 0.791681) ... [INFO] [时间戳]: 海龟机器人移动已结束 finished ! [INFO] [时间戳]: 最终位置: (7.936444, 7.922065, 0.886679)服务器输出[INFO] [时间戳]: 服务器已启动 [INFO] [时间戳]: 海龟机器人 开始启动 [INFO] [时间戳]: 与目标点距离: 3.472680 [INFO] [时间戳]: 与目标点距离: 2.851629 ... [INFO] [时间戳]: 与目标点距离: 0.100565 [INFO] [时间戳]: 与目标点距离: 0.080291 [INFO] [时间戳]: 海龟机器人移动已结束 server六、核心知识点总结Action 三要素Goal客户端目标Feedback实时进度Result最终结果Action 角色Server执行任务 反馈 回结果Client发目标 收反馈 收结果本实践核心价值实现了机器人长时运动的完整控制逻辑目标下发 → 过程监控 → 结果确认是导航、机械臂控制的基础模型。

更多文章