API(Python)

一、概述

fd_api 提供机器人外设(升降、头部、腰部、手部)的 Python 便捷接口封装。基于 ROS 2 rclpy 运行时, 通过简洁的 Python API 实现控制指令下发与状态读取 / 订阅。

核心模块

Control 控制类
升降 · 头部 · 腰部 · 手部
State 状态类
同步缓存读取 + 异步回调订阅
类型枚举
HeadType · HandType · HandBackend
角度转换
腰部编码器 ↔ 角度互转工具

架构分层

上层应用程序
from fd_api import Control, State
▼
fd_api Python 模块
Control · State · types · waist_angle
▼
ROS 2(rclpy)通信层
发布 Topic · 订阅 Topic
▼
机器人硬件外设
升降 · 头部 · 腰部 · 手部

二、安装与导入

编译构建

colcon build --packages-select fd_api

导入语句

from fd_api import State, Control, HeadType, HandType, HandBackend
from fd_api.waist_angle import waist_encoder_to_deg, waist_deg_to_encoder
使用前提:确保已在 ROS 2 工作空间下完成编译(colcon build), 并执行 source install/setup.bash 加载环境。

三、Python 类型定义

3.1 枚举类型

类型 枚举值 说明
HeadType kLower(0) · kUpper(1) 下头(yaw)/ 上头(pitch)
HandType kLeft(0) · kRight(1) · kBoth(2) 左手 / 右手 / 双手
HandBackend kRohand(0) · kInspire(1) · kBoth(2) RoHand 灵巧手 / Inspire 仿生灵巧手 / 双后端

3.2 腰部角度编码器转换

函数 转换 范围
waist_encoder_to_deg(enc) 编码器值 → 角度 (°) 编码器 262144 ~ 310000 → 角度 0° ~ 35°
waist_deg_to_encoder(deg) 角度 (°) → 编码器值 角度 0° ~ 35° → 编码器 262144 ~ 310000
说明:腰部编码器值与角度呈线性映射关系。 编码器 262144 对应 0°(后仰极限),310000 对应 35°(前倾极限)。

四、Control 控制接口

Control 类提供机器人外设的指令下发接口, 包含初始化、升降控制、头部控制、腰部控制、手部控制。

4.1 初始化

init(options_dict) 初始化控制节点。参数:node_name(节点名)、hand_backend(手后端类型)、hand_type(手类型)、waist_servo_id(腰部舵机 ID)、inspire_gripper_id(Inspire 夹爪 ID)
# === 初始化示例 ===
from fd_api import Control, State, HeadType, HandType, HandBackend

ctrl = Control()
ctrl.init({
    "node_name": "my_control",
    "hand_backend": HandBackend.kInspire,
    "hand_type": HandType.kBoth,
    "waist_servo_id": 3,
    "inspire_gripper_id": 1,
})
print("Control 初始化完成")

4.2 升降控制

lift_up(spd) 升降上升(速度模式),spd 为速度值
lift_down(spd) 升降下降(速度模式),spd 为速度值
lift_pos(spd, pos_mm) 升降位置控制,spd 速度,pos_mm 目标位置(毫米)
lift_stop() 升降停止
# === 升降速度控制示例 ===
# 上升:速度 0.05 m/s
ctrl.lift_up(0.05)
print("升降上升中...")

# 下降:速度 -0.05 m/s
ctrl.lift_down(0.05)
print("升降下降中...")

# 停止
ctrl.lift_stop()
print("升降已停止")
# === 升降位置控制示例 ===
ctrl.lift_pos(0.05, 200.0)  # 速度 0.05m/s, 目标位置 200mm
print("升降移动至 200mm 位置")
速度模式超时:升降速度模式(lift_up / lift_down)下, 须 周期发送(建议间隔 < 500ms),否则驱动自动停止。

4.3 头部控制

head_pos(head_type, pos_deg) 头部角度控制,head_type 为 HeadType,pos_deg 为目标角度(度)
head_stop(head_type) 头部停止
头部类型 运动方向 角度范围
HeadType.kLower 下头(yaw — 左右旋转) -45° ~ +45°
HeadType.kUpper 上头(pitch — 俯仰) -15° ~ +25°
# === 头部控制示例 ===
# 下头(yaw)转到 30 度
ctrl.head_pos(HeadType.kLower, 30.0)
print("下头转到 30°")

# 上头(pitch)转到 10 度
ctrl.head_pos(HeadType.kUpper, 10.0)
print("上头转到 10°")

# 停止下头
ctrl.head_stop(HeadType.kLower)
print("下头已停止")
自动限幅:头部角度超出范围时将自动限幅至边界值。

4.4 腰部控制

waist_front(spd, acc, dec) 腰部前倾(速度模式),参数:速度、加速度、减速度
waist_back(spd, acc, dec) 腰部后仰(速度模式),参数:速度、加速度、减速度
waist_pos(spd, acc, dec, pos_deg) 腰部位置控制,pos_deg 为目标角度(度),范围 0°~35°
waist_stop() 腰部停止
# === 腰部控制示例 ===
# 速度模式:前倾
ctrl.waist_front(720, 100, 100)
print("腰部前倾中...")

# 速度模式:后仰
ctrl.waist_back(720, 100, 100)
print("腰部后仰中...")

# 位置模式:转到 15 度
ctrl.waist_pos(720, 100, 100, 15.0)
print("腰部转至 15°")

# 停止
ctrl.waist_stop()
print("腰部已停止")
角度范围:腰部位置控制范围为 0°~35°,超出将自动限幅。

4.5 手部控制

hand_move(hand_type, value) 手部动作控制,hand_type 为 HandType,value 为数值列表 [v1, v2, ...]
hand_stop(hand_type) 手部停止
手后端 value 说明
RoHand 6 个数值,对应各自由度位置
Inspire 取首值作为夹爪开合控制
# === 手部控制示例 ===
# RoHand 手部:传入 6 个关节值
ctrl.hand_move(HandType.kLeft, [0.0, 0.5, 0.3, 0.1, 0.0, 0.0])
print("左手动作已发送")

# Inspire 夹爪:取首值控制开合
ctrl.hand_move(HandType.kRight, [500.0])
print("右手夹爪已控制")

# 停止左手
ctrl.hand_stop(HandType.kLeft)
print("左手已停止")
手后端选择:通过 init() 的 hand_backend 参数指定, 可选 HandBackend.kRohand、HandBackend.kInspire 或 HandBackend.kBoth。

五、State 状态接口

State 类提供机器人外设状态的读取与订阅功能。 支持同步缓存读取与异步回调订阅两种模式。

5.1 初始化

init(options_dict) 初始化状态节点。参数:node_name(节点名)、callback_thread_count(回调线程数)、waist_servo_id(腰部舵机 ID)、inspire_gripper_id(Inspire 夹爪 ID)
# === State 初始化示例 ===
state = State()
state.init({
    "node_name": "my_state",
    "callback_thread_count": 2,
    "waist_servo_id": 3,
    "inspire_gripper_id": 1,
})
print("State 初始化完成")

5.2 同步读取接口

方法 返回值 说明
lift_get_current_pos() float 读取升降当前位置 (mm)
head_get_current_pos(type) float 读取头部当前位置 (deg),type 为 HeadType
waist_get_current_pos() float 读取腰部当前位置 (deg)
hand_get_current_pos(type) list[float] 读取手部当前位置,type 为 HandType
# === 同步读取状态示例 ===
lift_pos = state.lift_get_current_pos()
print(f"当前升降位置: {lift_pos:.1f} mm")

head_lower = state.head_get_current_pos(HeadType.kLower)
print(f"下头角度: {head_lower:.1f} deg")

head_upper = state.head_get_current_pos(HeadType.kUpper)
print(f"上头角度: {head_upper:.1f} deg")

waist_pos = state.waist_get_current_pos()
print(f"腰部角度: {waist_pos:.1f} deg")

hand_pos = state.hand_get_current_pos(HandType.kLeft)
print(f"左手位置: {hand_pos}")

5.3 异步订阅接口

方法 返回值 说明
lift_sub_current_pos(callback) sub_id 订阅升降位置变化
head_sub_current_pos(callback) sub_id 订阅头部位置变化
waist_sub_current_pos(callback) sub_id 订阅腰部位置变化
hand_sub_current_pos(type, callback) sub_id 订阅手部位置变化,type 为 HandType
# === 异步订阅状态示例 ===
def on_lift_pos(mm):
    print(f"升降位置更新: {mm:.1f} mm")

sub_id = state.lift_sub_current_pos(on_lift_pos)
print(f"已订阅升降位置, sub_id={sub_id}")

# 取消订阅
state.unsubscribe(sub_id)
print("已取消订阅")
回调线程安全:异步订阅的回调函数在独立线程池中执行, 注意回调函数内部的线程安全性。订阅返回 sub_id 可用于取消订阅。

5.4 取消订阅

unsubscribe(sub_id) 取消指定 ID 的订阅,返回 bool 表示是否成功

5.5 完整使用示例

# === 完整示例:初始化 → 控制 → 读取 → 订阅 ===
import time
from fd_api import Control, State, HeadType, HandType, HandBackend

def main():
    # 1. 初始化 Control
    ctrl = Control()
    ctrl.init({
        "node_name": "demo_control",
        "hand_backend": HandBackend.kInspire,
        "hand_type": HandType.kBoth,
        "waist_servo_id": 3,
        "inspire_gripper_id": 1,
    })

    # 2. 初始化 State
    state = State()
    state.init({
        "node_name": "demo_state",
        "callback_thread_count": 2,
        "waist_servo_id": 3,
        "inspire_gripper_id": 1,
    })

    # 3. 控制示例
    ctrl.lift_up(0.05)       # 升降上升
    time.sleep(1)
    ctrl.lift_stop()         # 停止升降

    ctrl.head_pos(HeadType.kLower, 30.0)   # 下头转 30°
    ctrl.waist_pos(720, 100, 100, 10.0)    # 腰部转 10°
    ctrl.hand_move(HandType.kLeft, [0.0, 0.5, 0.3])  # 左手动作

    # 4. 状态读取
    lift_mm = state.lift_get_current_pos()
    print(f"升降位置: {lift_mm:.1f} mm")

    head_deg = state.head_get_current_pos(HeadType.kLower)
    print(f"下头角度: {head_deg:.1f} deg")

    # 5. 异步订阅
    def on_lift(mm):
        print(f"升降位置更新: {mm:.1f} mm")

    sub_id = state.lift_sub_current_pos(on_lift)
    time.sleep(0.5)
    state.unsubscribe(sub_id)

    print("Demo 运行完毕")

if __name__ == "__main__":
    main()

六、测试工具

fd_api 包内含一个 Python 交互测试节点,可用于验证各接口功能:

# 编译
colcon build --packages-select fd_api

# 运行测试节点
ros2 run fd_api api_test_node_for_python_api.py
测试内容:该测试节点覆盖 Control 初始化、升降、头部、腰部、手部控制, 以及 State 初始化、同步读取、异步订阅等主要接口路径。

七、注意事项

① 速度模式须周期发送:升降速度模式(lift_up / lift_down)下, 驱动在约 500ms 内未收到新速度命令会自动停止, 上位机须 周期性调用(建议间隔 < 500ms)。
② 头部角度自动限幅:head_pos() 传入的角度值若超出范围, 驱动将自动限幅至边界值。
HeadType.kLower:-45° ~ +45°
HeadType.kUpper:-15° ~ +25°
③ 腰部位置控制范围:waist_pos() 的 pos_deg 参数 有效范围为 0°~35°,超出将自动限幅。
④ 实机运行前确认:请确认机器人外设节点已启动且机器人处于安全状态, 避免意外动作导致损坏或伤害。
天链机器人(成都)有限责任公司