moveit2_servo 怎么接收相机调节指令(视觉伺服)

一、核心原理(一句话懂)

moveit2_servo 不吃 "轨迹",只吃 "速度增量指令" 相机 → 算出目标偏移 → 转成 TwistStamped(速度) → 发给 /servo_demo_node/delta_twist_cmdsmoveit2_servo 自动 IK + 避障 → 输出 /arm_controller/joint_trajectory

和你键盘控制完全同一路线,只是把键盘换成相机。


二、moveit2_servo 固定输入话题(必须记住)

ROS2 Humble + moveit2_servo 默认输入:

  • 笛卡尔(末端)指令: /servo_demo_node/delta_twist_cmds消息:geometry_msgs/TwistStamped

  • 关节指令: /servo_demo_node/delta_joint_cmds消息:moveit_msgs/JointJog

相机必须发 TwistStamped 到上面这个 topic!


三、相机 → moveit2_servo 完整流程(4 步)

1)相机输出:目标在相机坐标系的 3D 位姿

相机节点输出:

  • TF:camera_link → target
  • 或者话题:/target_pose(PoseStamped)

2)手眼标定(关键!)

必须知道:

  • base_link ↔ camera_link 的 TF(固定)
  • end_effector ↔ camera_link(眼在手上)

没有标定,坐标乱飘。

3)视觉 PID(把偏移 → 速度指令)

相机算出:

plaintext

复制代码
error_x, error_y, error_z (m)
error_rx, error_ry, error_rz (rad)

用简单 PID 转成 TwistStamped(速度)

plaintext

复制代码
linear.x  = Kp * error_x
linear.y  = Kp * error_y
linear.z  = Kp * error_z
angular.x = Kp * error_rx
...

4)发给 moveit2_servo(和你键盘完全一样)

ROS2 发布到:

plaintext

复制代码
/servo_demo_node/delta_twist_cmds

moveit2_servo 收到后:

  • 内部 IK
  • 碰撞检测
  • 限速
  • 输出:/arm_controller/joint_trajectory

四、直接可用的 ROS2 相机→servo 代码(极简)

python

运行

复制代码
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import TwistStamped, PoseStamped
from tf2_ros import TransformListener, Buffer
import math

class CameraToServo(Node):
    def __init__(self):
        super().__init__('camera_to_servo')
        # 发布给 servo
        self.pub = self.create_publisher(TwistStamped, '/servo_demo_node/delta_twist_cmds', 10)
        # 订阅相机目标位姿
        self.create_subscription(PoseStamped, '/target_pose', self.pose_cb, 10)

        self.tf_buffer = Buffer()
        self.tf_listener = TransformListener(self.tf_buffer, self)

        self.Kp = 0.5  # 速度增益,调这个

    def pose_cb(self, msg):
        try:
            # 把目标转到 base_link
            tf = self.tf_buffer.lookup_transform(
                'base_link', msg.header.frame_id, rclpy.time.Time()
            )
        except:
            return

        # 简化:直接拿误差做速度(PID你再加)
        err_x = msg.pose.position.x - tf.transform.translation.x
        err_y = msg.pose.position.y - tf.transform.translation.y
        err_z = msg.pose.position.z - tf.transform.translation.z

        twist = TwistStamped()
        twist.header.stamp = self.get_clock().now().to_msg()
        twist.header.frame_id = 'base_link'

        twist.twist.linear.x  = self.Kp * err_x
        twist.twist.linear.y  = self.Kp * err_y
        twist.twist.linear.z  = self.Kp * err_z
        # 旋转同理,这里省略

        self.pub.publish(twist)

def main():
    rclpy.init()
    Node = CameraToServo()
    rclpy.spin(Node)
    Node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

五、servo 参数必须开对(非常关键)

servo_params.yaml 确保:

yaml

复制代码
moveit_servo:
  ros__parameters:
    command_in_type: "twist_units"   # 接收Twist
    robot_link_command_frame: "base_link"  # 和相机统一
    scale:
      linear: 0.2   # 最大速度 m/s

六、最终数据流(你一眼看懂)

plaintext

复制代码
相机 → 目标位姿 → 视觉PID → TwistStamped
   ↓
/servo_demo_node/delta_twist_cmds
   ↓
moveit2_servo(IK+避障+限速)
   ↓
/arm_controller/joint_trajectory
   ↓
机械臂动
相关推荐
IT_陈寒5 分钟前
Redis主从切换竟让业务卡了3秒?这个坑我替你踩了
前端·人工智能·后端
byte轻骑兵6 分钟前
时序数据库选型全指南|大数据工业场景Apache IoTDB落地实操
大数据·数据库·人工智能·apache iotdb
微信ipad协议开发11 分钟前
保险代理人微信赋能:多号管理与客户跟进的自动化方案
微信·机器人
墨天梦14 分钟前
21-ReAct循环的完整实现
人工智能·自然语言处理
troy12818 分钟前
告别 Copilot?Codex、Claude Code、DeepSeek Harness、Kimi、ChatGPT 哪个更适合本地化部署,更有性价比?
人工智能·python·开源软件
AI的探索之旅19 分钟前
97 个 OpenCV 实例(二十九):三相机联合标定,把三只眼睛绑在一起
人工智能·opencv·计算机视觉
Data-Miner25 分钟前
商品ABC分类分析怎么用AI做?脚本复用+图表可编辑的一次完整实操
人工智能·数据分析·excel
不会就选b26 分钟前
算法日常・每日刷题--<贪心>17
算法
suaizai_27 分钟前
MCP协议实战:将工具迁移至进程外
人工智能
weixin_4462608527 分钟前
RAFT:面向故障排查智能体的有状态检索增强框架
人工智能