API(ROS2)
ROS2 接口说明
天链机器人 · 升降机构 / 头部关节 / 机械臂 / 力传感器接口定义
Topic · 消息类型 · CLI 示例一、概述
本文档涵盖机器人 ROS2 接口 的完整定义,包括升降机构、头部关节、机械臂和力传感器的 全部 Topic 及对应的 消息类型。
大部分关节驱动程序和 ROS2 节点运行于 机器人小脑(嵌入式实时控制器)上, 上位机通过 ROS2 Topic 发布控制指令并订阅状态数据,实现与机器人本体的实时通信。
通信采用 ROS2 标准的 发布/订阅(Publisher / Subscriber) 模式, 所有 Topic 均位于 /fd_robot/ 命名空间下,便于权限管理和多机器人区分。
自定义消息包:本文档中出现的
fd_msgs/ 类型由机器人驱动包提供, 编译时需确保 fd_msgs 包已包含在工作空间中。二、升降机构 ROS2 接口
2.1 控制模式
| 控制模式 | 说明 |
|---|---|
| 位置控制 | 基于原点的相对位置控制,先通过 position_set_speed_cmd 设置运动速度, 再通过 position_cmd 发送目标位置。 |
| 速度控制 | 需连续下发速度指令,若超过 500 ms 未收到新指令则自动停止。 |
2.2 Topic 列表
| 功能 | Topic | 消息类型 | 说明 |
|---|---|---|---|
| 速度控制 | /fd_robot/lifting_motor/velocity_cmd | std_msgs/Float32 | ±速度,单位 m/s |
| 设置位置速度 | /fd_robot/lifting_motor/position_set_speed_cmd | std_msgs/Float32 | 位置模式下先设置运动速度 |
| 位置控制 | /fd_robot/lifting_motor/position_cmd | std_msgs/Float32 | 相对原点位置 (m),范围 0 ~ 0.7 |
| 回原点 | /fd_robot/lifting_motor/home_cmd | std_msgs/Empty | — |
| 状态控制 | /fd_robot/lifting_motor/status | std_msgs/String | motor_stop / set_oring / encoder_exception_clear |
| 当前位姿 | /fd_robot/lifting_motor/current_pose | std_msgs/Float32 | 订阅当前位姿 (m) |
| 电机信息 | /fd_robot/lifting_motor/motor_info | fd_msgs/MotorInfoMsg | 含 pose / error_state / work_state |
2.3 Python Demo
速度控制
import rclpy
from rclpy.node import Node
from std_msgs.msg import Float32
node = Node("lift_demo")
pub = node.create_publisher(Float32, "/fd_robot/lifting_motor/velocity_cmd", 1)
msg = Float32()
msg.data = 0.05 # 0.05 m/s
pub.publish(msg)
node.get_logger().info("发布速度指令: 0.05 m/s")
位置控制(设置速度 + 目标位置)
from std_msgs.msg import Float32, String, Empty
# 设置原点
status_pub = node.create_publisher(String, "/fd_robot/lifting_motor/status", 1)
status_msg = String()
status_msg.data = "set_oring"
status_pub.publish(status_msg)
# 设置位置模式速度
speed_pub = node.create_publisher(Float32, "/fd_robot/lifting_motor/position_set_speed_cmd", 1)
speed_msg = Float32()
speed_msg.data = 0.05
speed_pub.publish(speed_msg)
# 移动到 0.3m
pos_pub = node.create_publisher(Float32, "/fd_robot/lifting_motor/position_cmd", 1)
pos_msg = Float32()
pos_msg.data = 0.3
pos_pub.publish(pos_msg)
停止 / 清除故障
# 停止
stop_msg = String()
stop_msg.data = "motor_stop"
status_pub.publish(stop_msg)
# 清除编码器故障
clear_msg = String()
clear_msg.data = "encoder_exception_clear"
status_pub.publish(clear_msg)
订阅当前位置和电机信息
def pose_cb(msg):
print(f"当前位置: {msg.data:.3f} m")
node.create_subscription(Float32, "/fd_robot/lifting_motor/current_pose", pose_cb, 10)
from fd_msgs.msg import MotorInfoMsg
def info_cb(msg):
if msg.motor_num > 0 and msg.pose:
print(f"电机: {msg.motor_name[0]}, 位置: {msg.pose[0]:.3f}")
node.create_subscription(MotorInfoMsg, "/fd_robot/lifting_motor/motor_info", info_cb, 5)
rclpy.spin_once(node, timeout_sec=0.5)
2.4 CLI 示例
# 速度控制 0.05m/s
ros2 topic pub /fd_robot/lifting_motor/velocity_cmd std_msgs/msg/Float32 "{data: 0.05}" --once
# 设置原点
ros2 topic pub /fd_robot/lifting_motor/status std_msgs/msg/String "{data: 'set_oring'}" --once
# 移动至 0.2m
ros2 topic pub /fd_robot/lifting_motor/position_set_speed_cmd std_msgs/msg/Float32 "{data: 0.05}" --once
ros2 topic pub /fd_robot/lifting_motor/position_cmd std_msgs/msg/Float32 "{data: 0.2}" --once
# 停止
ros2 topic pub /fd_robot/lifting_motor/status std_msgs/msg/String "{data: 'motor_stop'}" --once
2.5 FAQ
控制误差:±5 mm
行程范围:0 ~ 0.7 m
急停后等待:急停触发后需等待 20 s 方可再次操作
速度范围:0 ~ 0.2 m/s
三、头部关节 ROS2 接口
3.1 后端类型
| 后端 | 控制模式 | 说明 |
|---|---|---|
| DmHeadBackend | MIT 模式 | 需自主规划运动曲线,直接下发扭矩/位置/速度控制量 |
| HhHeadBackend | 舵机位置控制 | 舵机驱动,直接控制关节角度 |
3.2 通用话题
| 功能 | Topic | 消息类型 | 说明 |
|---|---|---|---|
| 当前位姿 | /fd_robot/head/current_pose | sensor_msgs/JointState | 读取当前位姿name: ["lower", "upper"]position: 弧度 (rad) |
| 关节角度控制 | /fd_robot/head_motor/cmd | sensor_msgs/JointState | 控制关节角度(弧度 rad) |
| 上头 pitch 控制 | /fd_robot/head_up_move | std_msgs/Float32 | 上头 pitch 角度(度) |
| 下头 yaw 控制 | /fd_robot/head_down_move | std_msgs/Float32 | 下头 yaw 角度(度) |
3.3 Python Demo (通用话题)
from sensor_msgs.msg import JointState
head_node = Node("head_demo")
# 发布关节控制指令
cmd_pub = head_node.create_publisher(JointState, "/fd_robot/head_motor/cmd", 10)
cmd_msg = JointState()
cmd_msg.name = ["lower", "upper"]
cmd_msg.position = [0.0, 0.1745] # rad
cmd_pub.publish(cmd_msg)
# 或使用角度快捷话题
from std_msgs.msg import Float32
up_pub = head_node.create_publisher(Float32, "/fd_robot/head_up_move", 10)
down_pub = head_node.create_publisher(Float32, "/fd_robot/head_down_move", 10)
up_pub.publish(Float32(data=10.0)) # 上头 10°
down_pub.publish(Float32(data=-15.0)) # 下头 -15°
# 订阅当前位姿
def pose_cb(msg):
for name, pos in zip(msg.name, msg.position):
print(f"{name}: {pos:.3f} rad")
head_node.create_subscription(JointState, "/fd_robot/head/current_pose", pose_cb, 10)
3.4 DM 电机私有话题(fd_* 机器人)
| 功能 | Topic | 消息类型 | 说明 |
|---|---|---|---|
| 使能 / 失能 | /fd_robot/dm_motor/enable_cmd | fd_msgs/EnableMsg | 使能或失能 DM 电机 |
| 工具控制 | /fd_robot/dm_motor/util_cmd | fd_msgs/DmUtilControlMsg | set_orig / alarm_clear / save_param |
| MIT 模式控制 | /fd_robot/dm_motor/mit_cmd | fd_msgs/DmMITControlMsg | 含 pose / vel / kp / kd / torque |
3.5 Python Demo (DM 电机)
from fd_msgs.msg import EnableMsg, DmUtilControlMsg, DmMITControlMsg
dm_node = Node("dm_demo")
# 使能 1 号电机
enable_pub = dm_node.create_publisher(EnableMsg, "/fd_robot/dm_motor/enable_cmd", 10)
enable_pub.publish(EnableMsg(servo_id=1, enable=1))
# MIT 模式控制
mit_pub = dm_node.create_publisher(DmMITControlMsg, "/fd_robot/dm_motor/mit_cmd", 10)
mit_msg = DmMITControlMsg()
mit_msg.servo_id = 1
mit_msg.pose = 0.1
mit_msg.vel = 0.0
mit_msg.kp = 5.0
mit_msg.kd = 0.15
mit_msg.torque = 0.0
mit_pub.publish(mit_msg)
3.6 CLI 示例
# 读取当前头部位姿
ros2 topic echo /fd_robot/head/current_pose
# 控制下头关节角度
ros2 topic pub -1 /fd_robot/head_motor/cmd sensor_msgs/msg/JointState "{name: ['lower'], position: [0.0]}"
# 上头 pitch 10°
ros2 topic pub -1 /fd_robot/head_up_move std_msgs/msg/Float32 "{data: 10.0}"
# 下头 yaw -15°
ros2 topic pub -1 /fd_robot/head_down_move std_msgs/msg/Float32 "{data: -15.0}"
3.7 FAQ
DM 电机:俯仰 25° ~ -15°,水平 ±45°
HH 舵机:俯仰 0° ~ 25°,水平 ±45°
四、机械臂 ROS2 接口
4.1 关节轨迹控制
| Topic | 消息类型 | 说明 |
|---|---|---|
| /tl_driver/joint_trajectory | trajectory_msgs/JointTrajectory | 双臂关节轨迹控制,支持 14 个关节 |
4.2 关节定义
共 14 个关节,按左右臂分组:
| 臂 | 关节名称 | ||||||
|---|---|---|---|---|---|---|---|
| 左臂 | left_tl_robot_joint1 | left_tl_robot_joint2 | left_tl_robot_joint3 | left_tl_robot_joint4 | left_tl_robot_joint5 | left_tl_robot_joint6 | left_tl_robot_joint7 |
| 右臂 | right_tl_robot_joint1 | right_tl_robot_joint2 | right_tl_robot_joint3 | right_tl_robot_joint4 | right_tl_robot_joint5 | right_tl_robot_joint6 | right_tl_robot_joint7 |
4.3 Python Demo
from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint
arm_node = Node("arm_traj_demo")
traj_pub = arm_node.create_publisher(JointTrajectory, "/tl_driver/joint_trajectory", 10)
traj_msg = JointTrajectory()
traj_msg.joint_names = [
"left_tl_robot_joint1", "left_tl_robot_joint2", "left_tl_robot_joint3",
"left_tl_robot_joint4", "left_tl_robot_joint5", "left_tl_robot_joint6",
"left_tl_robot_joint7"
]
point = JointTrajectoryPoint()
point.positions = [0.0, -0.5, -1.0, -1.5, 0.0, 0.5, 0.0]
point.time_from_start.sec = 2
point.time_from_start.nanosec = 0
traj_msg.points = [point]
traj_pub.publish(traj_msg)
4.4 CLI 示例
# 查看机械臂当前轨迹话题
ros2 topic list | grep trajectory
# 发送关节轨迹(示例:左臂关节1 至 0.5 rad)
ros2 topic pub /tl_driver/joint_trajectory trajectory_msgs/msg/JointTrajectory "{
joint_names: ['left_tl_robot_joint1'],
points: [{ positions: [0.5], time_from_start: { sec: 1, nanosec: 0 } }]
}" --once
轨迹规划:上位机需自行规划运动轨迹并下发
JointTrajectory 消息, 机械臂驱动节点负责执行轨迹跟踪。建议使用 ros2_control 或 MoveIt 2 进行上层轨迹规划。五、力传感器 ROS2 接口
5.1 六维力传感器
| Topic | 消息类型 | 说明 |
|---|---|---|
| /fd_robot/force_sensor/six_aix_force_sensor | fd_msgs/SixAixForceSensorMsg | 六维力传感器数据 |
消息字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| left_forces | float64[6] | 左侧六维力 (Fx, Fy, Fz, Mx, My, Mz) |
| right_forces | float64[6] | 右侧六维力 (Fx, Fy, Fz, Mx, My, Mz) |
| left_status | int8 | 左侧状态:0 正常,2 未连接 |
| right_status | int8 | 右侧状态:0 正常,2 未连接 |
5.2 拉压力传感器
| Topic | 消息类型 | 说明 |
|---|---|---|
| /fd_robot/force_sensor/pressure_sensor | fd_msgs/ForceSensorMsg | 拉压力传感器数据 |
消息字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
| sensor_name | string | 传感器名称 |
| forces | float64[] | 力数据数组 |
| status | int8 | 0 正常,2 通信异常 |
5.3 Python Demo
from fd_msgs.msg import SixAixForceSensorMsg, ForceSensorMsg
force_node = Node("force_demo")
def six_axis_cb(msg):
print(f"左: F=({msg.left_forces[0]:.1f}, {msg.left_forces[1]:.1f}, {msg.left_forces[2]:.1f}) N")
print(f" T=({msg.left_forces[3]:.1f}, {msg.left_forces[4]:.1f}, {msg.left_forces[5]:.1f}) Nm")
print(f"左状态: {'正常' if msg.left_status == 0 else '未连接'}")
force_node.create_subscription(SixAixForceSensorMsg,
\"/fd_robot/force_sensor/six_aix_force_sensor\", six_axis_cb, 10)
def pressure_cb(msg):
for name, force, status in zip(msg.sensor_name, msg.forces, msg.status):
print(f\"{name}: {force:.1f} N, 状态={'正常' if status == 0 else '异常'}\")
force_node.create_subscription(ForceSensorMsg,
\"/fd_robot/force_sensor/pressure_sensor\", pressure_cb, 10)
5.4 CLI 示例
# 查看六维力传感器数据
ros2 topic echo /fd_robot/force_sensor/six_aix_force_sensor
# 查看拉压力传感器数据
ros2 topic echo /fd_robot/force_sensor/pressure_sensor
力传感器数据频率:实际数据发布频率取决于传感器硬件配置和机器人小脑的通信周期, 建议在应用中根据时间戳判断数据的时效性。
六、注意事项
急停与恢复:升降机构急停触发后,需等待 20 秒方可再次下发控制指令, 请勿在急停后立即操作,以免造成硬件损坏。
速度控制超时:升降机构速度控制模式下,若超过 500 ms 未收到新的速度指令, 电机将自动停止。请确保控制程序以足够高的频率连续下发速度指令。
实机安全:在实机上操作前,请确认所有驱动节点已正常启动。 可通过
ros2 topic list 检查相关 Topic 是否已发布。Topic 命名空间:所有 Topic 均位于
/fd_robot/ 和 /tl_driver/ 命名空间下。 同一 ROS2 网络中仅应运行一套机器人节点,避免 Topic 冲突。自定义消息依赖:
fd_msgs/ 系列消息类型由机器人驱动包提供。 使用 colcon build 编译时,确保 fd_msgs 包已包含在工作空间中。DM 电机 MIT 模式:使用
/fd_robot/dm_motor/mit_cmd 时, 需自行规划运动曲线并设置合适的 kp / kd 参数, 不当的参数设置可能导致电机抖动或失控。机械臂轨迹规划:
trajectory_msgs/JointTrajectory 消息要求 上位机自行规划完整的运动轨迹。建议结合 MoveIt 2 或 自定义规划算法生成平滑的关节轨迹后下发。