EPEngineering and Projects双臂轮式机器人单臂 7 关节 夹爪ROS2 Topic 交互协议硬件构成移动底盘轮式【本次只做状态反馈不展开底盘控制话题】左机械臂7 个转动关节 夹爪1 个执行器位置开合右机械臂7 个转动关节 夹爪1 个执行器位置开合总计71 71 16 个运动轴通信模式ROS2 TopicPub/Sub单向流式目标指令下发订阅实时状态反馈发布适用控制器 ↔ ROS2 上层规划 / 感知节点之间数据流一、话题总览表表格话题名称方向消息类型作用QoS 推荐/robot/arm/target_joint_posROS 上层 → 机器人控制器controller 订阅sensor_msgs/msg/JointState双臂 夹爪 目标关节位置指令下发RELIABLEdepth10/robot/arm/real_joint_state机器人控制器 → ROS 上层controller 发布sensor_msgs/msg/JointState双臂 夹爪 实际关节位置、速度、力矩反馈BEST_EFFORTdepth20高频/robot/arm/ee_pose机器人控制器 → ROS 上层controller 发布geometry_msgs/msg/PoseArray左右臂末端执行器位姿x,y,z,qx,qy,qz,qwBEST_EFFORTdepth20/robot/arm/system_status机器人控制器 → ROS 上层controller 发布自定义消息robot_msgs/msg/RobotArmStatus整机 / 双臂 / 夹爪运行状态、错误码、使能、报警RELIABLEdepth10说明关节命名规范非常关键JointState 依赖 name 数组一一对应所有话题时间戳统一使用header.stamp rclpy.Clock().now()关节顺序固定上下发必须完全一致否则索引错乱二、关节命名定义固定顺序所有 JointState 共用这套 name 列表左手臂arm_left_j1 ~ arm_left_j7左夹爪arm_left_gripper右手臂arm_right_j1 ~ arm_right_j7右夹爪arm_right_gripper[ arm_left_j1, arm_left_j2, arm_left_j3, arm_left_j4, arm_left_j5, arm_left_j6, arm_left_j7, arm_left_gripper, arm_right_j1, arm_right_j2, arm_right_j3, arm_right_j4, arm_right_j5, arm_right_j6, arm_right_j7, arm_right_gripper ]单位约定旋转关节位置 rad速度 rad/s夹爪位置单位 m开合行程0 闭合max 全开可按需改为归一化 0~1速度 m/s1. 下发指令话题/robot/arm/target_joint_posMsg 类型sensor_msgs/msg/JointState消息结构std_msgs/msg/Header header string[] name # 上面16个关节名称数组 float64[] position # 目标关节位置长度16 float64[] velocity # 【可选】目标关节速度限制长度16如不使用填充0 float64[] effort # 不使用全部填0参数说明header.frame_id可填base_link基座坐标系name必须严格按上面顺序控制器校验 name 数组不匹配拒绝执行position[]目标关节位置arm_left_j1~j7目标角度 radarm_left_gripper夹爪目标开合位置右臂同理velocity[]可选每个关节最大限速若控制器不支持目标速度规划该数组全部置 0effort力矩指令本方案不使用填充 0使用约束频率建议50~200Hz由控制器接收超时丢包判定如超过 200ms 无新指令控制器触发停机 / 保持原位安全策略上层规划必须做关节限位、碰撞自检后再下发目标位置2. 关节实时反馈话题/robot/arm/real_joint_stateMsg 类型sensor_msgs/msg/JointState消息结构std_msgs/msg/Header header string[] name float64[] position # 实际关节位置 rad / m float64[] velocity # 实际关节实时速度 rad/s / m/s float64[] effort # 实际关节输出力矩 Nm参数说明name 数组和下发话题完全一致position传感器读取的当前关节实际位置velocity关节实时运行速度effort关节电机输出力矩用于碰撞检测、负载监控发布频率100~200HzBEST_EFFORT允许少量丢包用途上层做闭环监控、状态可视化、卡尔曼滤波、碰撞检测3. 双臂末端位姿反馈话题/robot/arm/ee_poseMsg 类型geometry_msgs/msg/PoseArraystd_msgs/msg/Header header geometry_msgs/msg/Pose[] poses数组顺序固定poses [0] 左臂末端poses [1] 右臂末端geometry_msgs/msg/Pose geometry_msgs/msg/Point position float64 x, y, z # 末端坐标单位m坐标系 base_link geometry_msgs/msg/Quaternion orientation float64 qx, qy, qz, qw # 姿态四元数参数说明header.frame_id base_linkposes 数组长度固定 2发布频率同关节状态100~200HzBEST_EFFORT适用上层运动规划、视觉抓取、笛卡尔空间监控该位姿由控制器正解算出上报ROS 端不需要重复正解备选方案如果需要附带末端力 / 扭矩可以改用自定义 Msg包含 wrench当前需求只需要位置姿态PoseArray 足够。4. 机器人整机状态话题/robot/arm/system_status自定义消息robot_msgs/msg/RobotArmStatus需要新建 ros2 包robot_msgs创建 msg 文件 RobotArmStatus.msgRobotArmStatus.msgstd_msgs/msg/Header header # 全局使能 bool robot_enable # true机器人使能可接收运动指令false抱闸锁定 uint8 error_code # 全局错误码0正常非0为故障 string error_msg # 错误文本描述 # 左臂状态 bool arm_left_enable uint8 arm_left_error bool arm_left_gripper_ready float64 arm_left_gripper_force # 夹爪夹持力反馈 # 右臂状态 bool arm_right_enable uint8 arm_right_error bool arm_right_gripper_ready float64 arm_right_gripper_force # 运行模式 uint8 mode # 0: IDLE 空闲 # 1: JOINT_CTRL 关节位置控制模式 # 2: CART_CTRL 笛卡尔控制模式 # 3: FAULT 故障停机 # 4: BRAKE_LOCK 抱闸锁定 # 安全信号 bool safety_stop # 急停信号 true急停触发 bool collision_detected # 碰撞检测标志错误码定义uint8表格码含义0正常1通信超时2关节超限3电机故障4温度告警5急停触发6夹爪故障7碰撞报警发布频率10~50HzRELIABLE状态变更立即推送不允许丢包。自定义消息编译说明在robot_msgs包CMakeLists.txt开启 rosidl_generate_interfaces加入msg/RobotArmStatus.msgpackage.xml 添加依赖rosidl_default_generators geometry_msgs std_msgscolcon build 编译后source 环境即可在代码中 importrobot_msgs/msg/RobotArmStatus三、推荐 QoS 配置ROS2建议代码中显式创建 QoS不要依赖默认避免跨节点 QoS 不匹配收不到消息# 高速关节数据流BEST_EFFORT from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSHistoryPolicy qos_high_freq QoSProfile( reliabilityQoSReliabilityPolicy.BEST_EFFORT, historyQoSHistoryPolicy.KEEP_LAST, depth20 ) # 指令/状态消息RELIABLE qos_reliable QoSProfile( reliabilityQoSReliabilityPolicy.RELIABLE, historyQoSHistoryPolicy.KEEP_LAST, depth10 )/robot/arm/target_joint_pos→ qos_reliable/robot/arm/real_joint_state→ qos_high_freq/robot/arm/ee_pose→ qos_high_freq/robot/arm/system_status→ qos_reliable四、数据流时序上层规划节点 → 发布/robot/arm/target_joint_pos目标关节位置控制器订阅目标执行关节伺服控制控制器循环采集电机编码器 → 填充real_joint_state发布控制器内部正解计算双臂末端位姿 → 发布ee_pose控制器采集故障、使能、急停、夹持力 → 发布system_status上层节点订阅 3 路反馈做轨迹监控、安全判断、可视化rviz五、RViz 可视化支持real_joint_state直接供给RobotModel插件展示双臂 夹爪模型ee_pose可用 PoseArray 插件显示两个末端坐标系system_status可通过 rqt_topic/rqt_multiplot 查看状态与报警六、可选扩展话题按需增加/robot/arm/target_ee_pose笛卡尔目标位姿下发PoseArray笛卡尔控制模式/robot/arm/gripper_cmd单独夹爪指令如果需要独立控制夹爪不和关节一起下发/robot/arm/joint_torque单独力矩反馈话题如果 JointState.effort 不够七、示例 Python 代码片段控制器侧订阅目标 发布关节状态import rclpy from rclpy.node import Node from sensor_msgs.msg import JointState from geometry_msgs.msg import PoseArray, Pose, Point, Quaternion from robot_msgs.msg import RobotArmStatus from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSHistoryPolicy JOINT_NAMES [ arm_left_j1,arm_left_j2,arm_left_j3,arm_left_j4,arm_left_j5,arm_left_j6,arm_left_j7,arm_left_gripper, arm_right_j1,arm_right_j2,arm_right_j3,arm_right_j4,arm_right_j5,arm_right_j6,arm_right_j7,arm_right_gripper ] qos_reliable QoSProfile(reliabilityQoSReliabilityPolicy.RELIABLE, historyQoSHistoryPolicy.KEEP_LAST, depth10) qos_high QoSProfile(reliabilityQoSReliabilityPolicy.BEST_EFFORT, historyQoSHistoryPolicy.KEEP_LAST, depth20) class ArmControllerNode(Node): def __init__(self): super().__init__(arm_controller_node) # 订阅目标关节指令 self.target_joint_sub self.create_subscription( JointState, /robot/arm/target_joint_pos, self.target_joint_cb, qos_reliable ) # 发布实时关节状态 self.joint_state_pub self.create_publisher(JointState, /robot/arm/real_joint_state, qos_high) # 发布末端位姿 self.ee_pose_pub self.create_publisher(PoseArray, /robot/arm/ee_pose, qos_high) # 发布系统状态 self.status_pub self.create_publisher(RobotArmStatus, /robot/arm/system_status, qos_reliable) self.timer self.create_timer(0.01, self.publish_loop) # 100Hz def target_joint_cb(self, msg:JointState): # 收到上层下发目标关节位置送入底层伺服控制器 self.get_logger().info(fRecv target joints, len{len(msg.position)}) def publish_loop(self): # 1. 发布JointState反馈 js_msg JointState() js_msg.header.stamp self.get_clock().now().to_msg() js_msg.header.frame_id base_link js_msg.name JOINT_NAMES # 此处替换为控制器读取的真实position/velocity/effort js_msg.position [0.0]*16 js_msg.velocity [0.0]*16 js_msg.effort [0.0]*16 self.joint_state_pub.publish(js_msg) # 2. 发布双臂末端PoseArray pose_arr PoseArray() pose_arr.header.stamp self.get_clock().now().to_msg() pose_arr.header.frame_id base_link # 左臂末端pose poseL Pose(positionPoint(x0.5,y0.0,z0.3), orientationQuaternion(qx0,qy0,qz0,qw1)) poseR Pose(positionPoint(x-0.5,y0.0,z0.3), orientationQuaternion(qx0,qy0,qz0,qw1)) pose_arr.poses [poseL, poseR] self.ee_pose_pub.publish(pose_arr) # 3. 发布系统状态 status_msg RobotArmStatus() status_msg.header.stamp self.get_clock().now().to_msg() status_msg.robot_enable True status_msg.error_code 0 status_msg.mode 1 self.status_pub.publish(status_msg) def main(): rclpy.init() node ArmControllerNode() rclpy.spin(node) rclpy.shutdown() if __name__ __main__: main()