当前位置: 首页 > news >正文

MoveIt Servo 如何通过 FollowJointTrajectoryControllerHandle Action Server 通信

一、通信架构图

text

MoveIt Servo (moveit_servo node) ↓ MoveItSimpleControllerManager (插件管理器) ↓ FollowJointTrajectoryControllerHandle (您看到的这个类) ↓ [内部创建 Action Client] ↓ ROS 2 Action Client (自动生成) ↓ [通过 ROS 2 Action 协议] ↓ 您的 Action Server (myrobot_driver) ↓ 真实硬件

二、关键通信机制

1.Action Client 的创建

FollowJointTrajectoryControllerHandle在初始化时会创建 Action Client:

cpp

// 构造函数中(未显示但存在) FollowJointTrajectoryControllerHandle::FollowJointTrajectoryControllerHandle( rclcpp::Node::SharedPtr node, const std::string& name, const std::string& action_namespace) { // 创建 Action Client,连接到您的 Server controller_action_client_ = rclcpp_action::create_client< control_msgs::action::FollowJointTrajectory>( node, action_namespace // 例如: "arm_controller/follow_joint_trajectory" ); }

2.发送轨迹的核心代码

cpp

bool FollowJointTrajectoryControllerHandle::sendTrajectory( const moveit_msgs::msg::RobotTrajectory& trajectory) { // 1. 检查连接状态 if (!isConnected()) { RCLCPP_ERROR("Action client not connected to action server"); return false; } // 2. 构建 Goal control_msgs::action::FollowJointTrajectory::Goal goal = goal_template_; goal.trajectory = trajectory.joint_trajectory; // 填充轨迹数据 goal.multi_dof_trajectory = trajectory.multi_dof_joint_trajectory; // 3. 设置回调函数(接收 Server 的响应) send_goal_options.goal_response_callback = [this](goal_handle) { if (!goal_handle) RCLCPP_WARN("Goal request rejected"); // Server 拒绝 else RCLCPP_INFO("Goal request accepted!"); // Server 接受 }; // 4. 异步发送 Goal 到您的 Action Server auto current_goal_future = controller_action_client_->async_send_goal( goal, send_goal_options); // 5. 等待 Server 响应 current_goal_ = current_goal_future.get(); return true; }

三、完整的通信流程

步骤1:初始化阶段

cpp

// MoveIt 启动时加载配置 // controllers.yaml 内容: // arm_controller: // action_ns: arm_controller/follow_joint_trajectory ← 您的 Server 名称 // type: FollowJointTrajectory // FollowJointTrajectoryControllerHandle 创建 Action Client // 连接到您的 Server: /arm_controller/follow_joint_trajectory

步骤2:Servo 运行时

cpp

// MoveIt Servo 持续运行,当需要发送轨迹时: // 1. Servo 调用 getControllerHandle("arm_controller") // 2. 获得 FollowJointTrajectoryControllerHandle 实例 // 3. 调用 sendTrajectory() 方法 // 4. 该方法通过 Action Client 发送到您的 Server

步骤3:您的 Server 接收并处理

cpp

// 您的 Action Server 代码 class FollowJointTrajectoryAction : public rclcpp::Node { // 这个回调会被触发 void execute(const std::shared_ptr<GoalHandle> goal_handle) { auto goal = goal_handle->get_goal(); auto points = goal->trajectory.points; // 接收轨迹点 // 执行轨迹... for (const auto& point : points) { send_to_motors(point.positions); // 发送给电机 } // 返回成功结果 auto result = std::make_shared<FollowJointTrajectory::Result>(); result->error_code = FollowJointTrajectory::Result::SUCCESSFUL; goal_handle->succeed(result); } };

四、数据流转详解

MoveIt Servo → Action Client

cpp

// MoveIt Servo 生成的轨迹 moveit_msgs::msg::RobotTrajectory trajectory; trajectory.joint_trajectory.joint_names = {"joint1", "joint2", ...}; trajectory.joint_trajectory.points[0].positions = {0.1, 0.2, 0.3, ...}; // ↓ sendTrajectory() 转换 control_msgs::action::FollowJointTrajectory::Goal goal; goal.trajectory = trajectory.joint_trajectory; // 直接赋值 // ↓ Action Client 序列化并发送 controller_action_client_->async_send_goal(goal, ...);

Action Client → 您的 Server

cpp

// ROS 2 中间件传输 // Topic: /arm_controller/follow_joint_trajectory/_action/send_goal // 您的 Server 接收 void handle_goal(const Goal::SharedPtr goal) { // goal->trajectory.points 包含所有轨迹点 }

五、连接验证方法

1.检查 Action Client 连接状态

cpp

// 在您的代码中添加调试信息 bool isConnected() { if (!controller_action_client_->wait_for_action_server(std::chrono::seconds(1))) { RCLCPP_ERROR(LOGGER, "Cannot connect to your Action Server!"); return false; } return true; }

2.监控通信

bash

# 查看所有 Action ros2 action list # 应该看到: # /arm_controller/follow_joint_trajectory ← 您的 Server # 监控 Action 消息 ros2 topic echo /arm_controller/follow_joint_trajectory/_action/status

六、您的 Server 需要满足的要求

必须实现的接口

cpp

class YourActionServer { // 1. 必须提供正确的 Action 名称 action_server_ = create_server<FollowJointTrajectory>( this, "arm_controller/follow_joint_trajectory", // ← 必须匹配配置 ... ); // 2. 必须正确处理关节名称 bool handle_goal(goal) { // 检查关节名称是否匹配 if (goal->trajectory.joint_names != expected_joints) { return REJECT; // 返回 INVALID_JOINTS 错误码 } return ACCEPT; } // 3. 必须正确执行轨迹(所有点,不只是最后一个) void execute(goal_handle) { for (const auto& point : goal->trajectory.points) { // 执行每个点 move_to_position(point.positions); // 等待到达 sleep(point.time_from_start); } result->error_code = SUCCESSFUL; goal_handle->succeed(result); } };

七、通信时序图

text

MoveIt Servo FollowJointTrajectoryControllerHandle Your Action Server | | | |--sendTrajectory()------>| | | |--async_send_goal()---------------->| | | | | |<--goal_response_callback-----------| |<--return true-----------| | | | | | | | (执行轨迹) | | | | |<--result (succeed/abort)-----------| | | | | |--controllerDoneCallback()--------->| | | |

八、关键点总结

组件作用关键代码
FollowJointTrajectoryControllerHandleMoveIt 侧的客户端async_send_goal(goal)
controller_action_client_ROS 2 Action Client连接到您的 Server
sendTrajectory()发送轨迹的接口被 MoveIt Servo 调用
controllerDoneCallback()接收执行结果处理 Server 返回的结果

九、完整的工作示例

cpp

// 1. 您的 Server 启动 ros2 run myrobot_driver myrobot_driver_node // 2. MoveIt Servo 启动(自动创建 Action Client) ros2 launch moveit_servo servo.launch.py // 3. 当用户在 RViz 中拖动末端执行器时: // - MoveIt Servo 计算轨迹 // - 调用 sendTrajectory() // - Action Client 发送到您的 Server // - 您的 Server 执行并返回结果 // - controllerDoneCallback() 记录结果

结论:FollowJointTrajectoryControllerHandle是 MoveIt 与您的 Action Server 之间的直接通信桥梁。它通过 ROS 2 Action 协议,自动将 MoveIt 规划的轨迹发送到您的 Server,无需您修改任何 MoveIt 代码。只要您的 Server 实现了标准的FollowJointTrajectoryAction 接口,并且 Action 名称匹配,通信就会自动建立。

http://www.jsqmd.com/news/642412/

相关文章:

  • 了解电爪分类与核心参数,靠谱电爪品牌挑选实用方法 - 品牌2026
  • 2026年中高考将至!揭秘好用的提分技巧,这家权威机构不容错过!
  • ITensors——一个聪明的张量网络库(4)
  • 【多模态大模型知识蒸馏实战指南】:3步压缩ViT+CLIP模型,推理速度提升4.7倍、参数量减少89%(附PyTorch可复现代码)
  • 光伏MPPT专题(2)【讲解】基于改进扰动观察法的光伏MPPT最大功率跟踪算法(自适应步长、大步长、小步长对比)
  • ai coding到底选什么模型?claude,gpt,glm,gemin,KIMI K2.5,MiniMax-M2.7底怎么选,最全总结
  • Samhelper(Sam helper 下载)
  • ITensors——一个聪明的张量网络库(1)
  • ITensors——一个聪明的张量网络库(2)
  • 解决PyTorch与TorchVision版本冲突:从依赖管理到环境隔离的实战指南
  • bootstrap怎么给图片添加滤镜效果
  • OWL ADVENTURE新手教程:像玩游戏一样轻松玩转图像识别AI
  • 2026重庆学历提升机构实力排行榜:Top7深度测评,帮你精准避坑 - 商业科技观察
  • XSLT Apply: 实用技巧与深入解析
  • 搜索效果提升300%的多模态实战方案(工业级部署白皮书首次公开)
  • Python爬虫实战:用Requests+正则搞定马蜂窝景点评论,数据直接存TXT
  • 从零部署Orbbec Gemini2:ROS2 Humble环境下的驱动配置与多话题数据解析
  • RDP Wrapper终极指南:3步解锁Windows家庭版远程桌面完整功能
  • 基于西门子HyperLynx与Flotherm联合进行PCB焦耳热仿真的技术解析与实战指南
  • apache-seatunnel使用手册
  • SP4523锂电池充放电 SOC
  • 洞悉电爪性能特点与应用:2026年优质电爪品牌甄选实用指南 - 品牌2026
  • 终极BT下载加速指南:免费提升下载速度的完整教程
  • 多智能体五大协调模式入门到精通(非常详细),看这篇就够了!
  • 【AIAgent可靠性黄金法则】:SITS2026权威发布的5大不可妥协要素(20年架构师亲验)
  • 【数据结构与算法】第45篇:跳跃表(Skip List)
  • ITensors——一个聪明的张量网络库(3)
  • 从“AI仿生人”到“原创音乐人”:普通人如何用AI写歌、发歌、赚钱
  • 网页游戏市场每日分析|二级市场传奇页游平台排名|602游戏平台
  • JDK安装及JRE说明