Skip to content

Repository files navigation

roboparty_dexhand — RP_Hand 6DOF 驱动

roboparty_dexhand 是面向 Linux 的 RP_Hand 6DOF 灵巧手 C++/Python 控制库,通过外部配置的 SocketCAN CAN-FD 接口进行通信。库提供统一的 HandDriver 工厂接口、运动控制和反馈读取能力。

本文命令在连接灵巧手的 Linux 主机或板子的 Bash 终端中执行。 首次使用按顺序完成:选择安装方式 → 加载环境 → 配置 CAN-FD → 配置反馈周期 → 运行 Python 示例或 ROS 节点。构建不需要连接硬件;回零和运动示例会驱动真机。

项目与安装方式

名称 含义
roboparty_dexhand 本源码项目,提供 C++ 驱动、Python 模块 dexhand_py 和配置工具
roboparty-dexhand 本驱动的 Debian 软件包名
roboparty-base Debian 驱动包依赖的 RoboParty 基础环境包;安装它不等于安装灵巧手驱动
/opt/roboparty RoboParty 软件包共用的安装目录,可以包含多个组件
roboparty_dexhand_ros 独立的 ROS 2 适配项目,调用本驱动并提供话题和服务

首次从本仓库部署,按下面的源码安装流程操作即可。 已经取得匹配目标系统的 驱动 .deb 及其依赖时,也可以选择 Debian 安装。两种方式提供同一项目的驱动, 但版本可能不同;每个终端只选择一种驱动环境。

安装方式 驱动安装位置 每次新开终端加载
本文的源码安装 ~/roboparty_dexhand/install/ source ~/roboparty_dexhand/setup.bash
Debian 包安装 /opt/roboparty/ source /opt/roboparty/setup.bash

源码目录中的 setup.bash 会查找相邻的 install/,设置 Python、命令行工具 和 CMake 的搜索路径。它不会编译驱动或启动硬件。源码安装无需安装 roboparty-base,也不会自动覆盖 /opt/roboparty 中的版本。

项目用途

使用本库可以在机器人应用中创建 RP_Hand 驱动、发送关节运动目标并读取 灵巧手反馈。日常使用顺序是先在系统中配置 CAN-FD,再按需完成一次反馈 周期配置,然后初始化驱动、控制关节,最后显式释放驱动资源。

支持范围

  • Linux x86-64 与 AArch64;
  • RP_Hand 6DOF,CAN-FD,CANopen node ID 为 1..127
  • Python 模块 dexhand_py 与 C++ 头文件 include/hand_driver.hpp
  • 一个进程使用一个活动的厂商 SDK 实例。

本部署只支持 RP_Hand 6DOF。唯一公开支持的模型值为 RP_HAND_6DOF=0。为保持 pybind 兼容性,RP_Hand 品牌发布前的枚举表示 仍被保留;同一个数值别名的 .namestr()repr() 可能显示品牌发布 前的规范标识符。这不表示安装了过时的软件包;普通代码应使用 HandModel.RP_HAND_6DOF,需要数值时使用 .value

从源码构建(Ubuntu 22.04 / Orange Pi)

源码安装和下文的 Debian 软件包安装任选一种。以下流程使用独立 CMake 构建, 不要求安装 ROS 2,也不需要连接灵巧手。已在 Orange Pi 的 Ubuntu 22.04 / AArch64、 系统 Python 3.10 环境验证;仓库也包含 Linux x86-64 对应的厂商 SDK。

1. 安装构建依赖

sudo apt update
sudo apt install git build-essential cmake python3-dev pybind11-dev libspdlog-dev libfmt-dev can-utils iproute2

需要支持 C++17 的编译器和 CMake 3.15 或更新版本。下文统一使用 /usr/bin/python3,避免虚拟环境中的 Python 与编译出的扩展版本不匹配。

2. 获取源码、编译和安装

首次下载(已有源码时跳过):

cd ~
git clone https://github.com/Roboparty/roboparty_dexhand.git

以下假定源码已放在 ~/roboparty_dexhand;如果放在其他目录,修改第一行。 命令在目标板上执行,无需交叉编译。安装到项目内的 install/,无需 sudo

cd ~/roboparty_dexhand

cmake -S . -B build \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_INSTALL_PREFIX="$PWD/install" \
  -DPython3_EXECUTABLE=/usr/bin/python3 \
  -DCMAKE_DISABLE_FIND_PACKAGE_ament_cmake=TRUE \
  -DBUILD_TESTING=OFF \
  -DDEXHAND_ENABLE_VCAN_TESTS=OFF &&
cmake --build build --parallel 4 &&
cmake --install build

CMAKE_DISABLE_FIND_PACKAGE_ament_cmake=TRUE 将本流程固定为独立 CMake 构建, 即使终端已加载 ROS 环境,也不会额外要求 ament 的检查工具;它不影响后续 ROS 节点导入 dexhand_py。通过 colcon 构建本驱动时不要使用此选项。 BUILD_TESTING=OFF 关闭软件测试构建;上述命令只编译和安装,不会访问硬件。

成功时应看到:

  • 编译完成,没有错误;
  • 安装输出路径位于 ~/roboparty_dexhand/install/Up-to-date 表示已有文件是最新的,属于正常结果。

源码更新后可重复执行整段命令。内存不足导致编译进程被杀死时,将编译的 --parallel 4 调小为 --parallel 1

3. 加载环境并验证安装

每次新开 Bash 终端都要加载一次环境。setup.bash 按自身位置寻找同目录下的 install/,可以从任意工作目录加载;重复加载不会重复追加路径。

source ~/roboparty_dexhand/setup.bash

/usr/bin/python3 -c 'import dexhand_py; print(dexhand_py.__file__)'
/usr/bin/python3 -c 'from dexhand_py import HandModel; print(HandModel.RP_HAND_6DOF.value)'
roboparty-dexhand-config --help

第一条 Python 命令应输出本项目 install/ 下的 dexhand_py*.so 路径, 第二条应输出 0,最后一条应显示 feedback-period show/apply 的用法。 以上步骤验证模块和 CLI 能正常加载,不会连接或使能灵巧手。

安装内容包括 install/bin/ 中的 CLI、install/include/ 中的 C++ 头文件、 以及 install/lib/ 中的驱动库、厂商 SDK、CMake package config 和 pythonX.Y/site-packages/ 中的 Python 扩展。X.Y 由构建时 Python 决定, 无需手写到环境变量中。

4. 构建完成后如何使用

  • 直接用 Python 控制:加载上述环境后,用 /usr/bin/python3 运行应用。 接手前先完成下文的 CAN-FD 设置和反馈周期配置,再执行 Python 示例。 模块成功导入不代表接线、通信及真实运动已经验收通过。
  • 用于 ROS 2roboparty_dexhand_ros 在节点进程内直接导入 dexhand_py, 不需要另起一个驱动服务。先加载 ROS 2 环境,再加载本项目 setup.bash, 最后加载 ROS 工作空间的 install/setup.bash。接下来按 ROS 包 README 构建并启动;本仓库不包含 ROS 节点。
  • 硬件验收:见 VALIDATION.md。该文档使用软件包安装路径, 源码安装时应将其中的 source /opt/roboparty/setup.bash 替换为 source ~/roboparty_dexhand/setup.bash,并使用 /usr/bin/python3

常见构建和加载问题

现象 处理方式
CMake 找不到 pybind11、spdlog、fmt 或 Python 开发文件 确认第 1 步的开发包安装成功,再重新配置
CMake 提示源目录与缓存不一致 项目移动或复制后,改用新的构建目录,如 -B build-local,后续编译和安装也使用该目录
setup.bash 提示安装目录不存在或找不到唯一模块 先完成安装;脚本要求项目的 install/ 下恰好有一个 dexhand_py*.so。更换 Python 版本后,先移走旧安装目录再重新安装
ModuleNotFoundError: dexhand_py 在运行应用的同一终端重新 source 环境,并使用 /usr/bin/python3
模块来自其他安装目录或无法加载动态库 检查输出的模块路径,确认加载的是本次安装;不要单独拷贝 Python 扩展,需保留完整安装目录

Debian 软件包安装

本节适用于已取得与目标系统、CPU 架构、Python 版本匹配的软件包的用户。 下面以 Ubuntu 22.04 / ARM64 为例。需要 roboparty-dexhandroboparty-base (>= 1.0.0);后者需预先安装或可从你配置的 RoboParty 软件源取得。 这些包不是 Ubuntu 默认软件源的通用依赖,若没有软件包或软件源,请使用上面的 源码安装方式。不要将 ARM64 包安装到 x86-64 主机。

先在终端进入存放 .deb 的目录。以下要求当前目录恰好有一个匹配的驱动包:

(
  shopt -s nullglob
  deb_candidates=(./roboparty-dexhand_*_arm64.deb)
  if (( ${#deb_candidates[@]} != 1 )); then
    printf 'expected exactly one ARM64 package, found %d\n' \
      "${#deb_candidates[@]}" >&2
    exit 1
  fi
  sudo apt install "${deb_candidates[0]}"
)

安装完成后,每个新终端加载环境并检查实际使用的模块:

source /opt/roboparty/setup.bash
/usr/bin/python3 -c 'from dexhand_py import HandDriver, HandModel; import dexhand_py; print(dexhand_py.__file__)'
roboparty-dexhand-config --help
dpkg-query -W roboparty-dexhand roboparty-base

模块路径应位于 /opt/roboparty/。若环境脚本不存在,检查基础环境包是否安装完整; 若提示找不到 dexhand_py,检查驱动包是否安装以及 Python 版本是否匹配。 不要通过加载源码版环境来掩盖软件包安装问题。

Linux CAN-FD 设置

需要支持 CAN-FD 的适配器、正确的设备供电和接线。普通 CAN 适配器不能替代 CAN-FD。先查看系统提供的接口:

ip -brief link

can0 只是接口名称示例,请按实际端口修改。接口不存在时,先检查适配器、 连接和 Linux 驱动。配置前停止使用该接口的其他程序;下面的 down 会中断 整个接口上的通信。已由系统正确配置的接口可以跳过配置,直接检查状态。

CAN-FD 接口由系统或部署脚本在库外配置。下面以 can0 为例,设置名义 速率 1 Mbps、数据速率 5 Mbps、采样点和同步跳转宽度后启动接口:

sudo ip link set can0 down
sudo ip link set can0 type can \
  bitrate 1000000 sample-point 0.8 sjw 4 \
  dbitrate 5000000 dsample-point 0.75 dsjw 2 fd on
sudo ip link set can0 txqueuelen 10000
sudo ip link set can0 up
ip -details -statistics link show can0

将命令中的 can0 替换为实际连接灵巧手的物理接口。库只使用已存在的 SocketCAN 接口,永远不会替应用配置速率、采样点、队列长度或接口状态。 预期看到接口 UP、CAN <FD>bitrate 1000000dbitrate 5000000。 双手分别连接 can0can3 时,两者都需要配置;将上面各条命令中的 can0 替换为 can3 再执行一次。上述配置不是持久化设置,重启或重新插拔后应重新检查。

首次配置反馈频率

新设备、替换设备、恢复出厂设置的设备,或当前配置未知的设备,需要完成一次 反馈周期配置;普通每次启动不需要重复执行。操作前先停止其他手控制进程, 然后执行:

roboparty-dexhand-config feedback-period apply --interface can0 --node-id 1 --milliseconds 20 --save

只给灵巧手本体断电再上电,然后执行查询:

roboparty-dexhand-config feedback-period show --interface can0 --node-id 1

查询结果中六个轴的 raw value 都必须是 200。如果有轴需要改变, apply --save 会写入六个目标值并保存;如果六个轴已经都是 200,CLI 会报告 result=already-compliant,不会重复写入或保存。无论哪种结果, 都要给灵巧手本体断电再上电,然后运行上面的 show 进行确认。20 ms 表示两个反馈类型各自以 50 Hz 发送,因此合计约为 100 帧/秒。正常的 init_hand() 永远不会写入或修改持久化反馈周期参数。 双手需要分别配置和查询;右手使用 can3 时,将上述命令的 --interface can0 替换为 --interface can3--node-id 必须与对应设备一致。

Python 使用

以下是可直接复制到 Bash 执行的单手示例。先加载所选安装方式的环境,完成 CAN-FD 和反馈周期配置,并停止 ROS 节点及其他手控制程序。 示例控制 can0 上 node ID 为 1 的手;其他接线请修改代码中的接口和 ID。

运行会使能、回零,再将六关节移动到目标位置并返回零位。 确认目标位置 1200 和速度 2000 适合实际机构、负载,运动范围内无障碍物,并准备好硬件 停止手段。失败时停止排查,不要绕过回零继续发送位置命令。

home_wait_time=5.0 是最大超时,不是固定等待。驱动收到回零后的新鲜 0x50 位置反馈和 0x5A 状态反馈后,会检查六轴均已停止、无报警且接近 零位,并立即返回;超时则初始化失败并禁用电机。仅软件进程重启、手本体 没有掉电且零位可信时,可用 init_hand(True, False, 0.0) 快速恢复,不应 重复执行回零。

/usr/bin/python3 - <<'PYTHON'
import time

from dexhand_py import HandDriver, HandModel


CAN_INTERFACE = "can0"
TARGET_POSITION = 1200
TARGET_VELOCITY = 2000


def read_positions(hand, label):
    positions = [hand.get_now_position(joint) for joint in range(1, 7)]
    values = " ".join(
        f"joint{joint}={position}"
        for joint, position in enumerate(positions, start=1)
    )
    print(f"{label}: {values}")


hand = HandDriver.create_hand(
    "RP_Hand", "canfd", CAN_INTERFACE, HandModel.RP_HAND_6DOF, 1
)
initialized = False
try:
    if not hand.init_hand(True, True, 5.0):
        raise RuntimeError("init_hand failed")
    initialized = True

    hand.check_health()
    total, active = hand.get_dof()
    if active != 6:
        raise RuntimeError(f"unexpected active DOF: {active} (total={total})")
    alarms = [hand.get_now_alarm(joint) for joint in range(1, 7)]
    if any(alarm != 0 for alarm in alarms):
        raise RuntimeError(f"nonzero joint alarms: {alarms}")

    hand.set_move_no_home(0)
    for joint in range(1, 7):
        hand.set_target_position(joint, TARGET_POSITION)
        hand.set_position_velocity(joint, TARGET_VELOCITY)
    hand.move_motors(0)
    time.sleep(1.0)
    read_positions(hand, "target")

    for joint in range(1, 7):
        hand.set_target_position(joint, 0)
        hand.set_position_velocity(joint, TARGET_VELOCITY)
    hand.move_motors(0)
    time.sleep(1.0)
    read_positions(hand, "zero")
finally:
    if initialized:
        try:
            hand.set_move_no_home(0)
        finally:
            hand.deinit_hand()
    else:
        hand.deinit_hand()
PYTHON

预期终端打印 targetzero 两组位置,同时观察实际动作。读数是驱动缓存, 固定等待时间不保证所有设备都已完成运动;完整反馈验收见 VALIDATION.md

选择 CAN 接口

interface 字符串决定 Linux 将数据发送到哪个 SocketCAN 接口。使用 can0can1can2can3 时,只需把工厂参数或上面示例中的 CAN_INTERFACE 改成对应名称;库不会自动探测或选择端口。端口必须已经 连接到目标灵巧手并完成 CAN-FD 配置。

双手使用

支持的双手部署方式是每只手使用一个 OS 进程。厂商 SDK 每个进程只支持 一个活动实例,接收回调也是进程级资源。每个进程必须明确指定对应接口和 node ID,不能在一个 Python 进程中创建两个活动的手实例。

需要现成的双手启动命令时,使用 roboparty_dexhand_ros。 该项目会分别启动左右手节点,默认接口为 can0can3;请先完成其 README 中的 ROS 安装和构建步骤。纯 Python 应用则将单手控制逻辑分别运行在两个进程中。

C++ 使用

最小生命周期示例只使用公共头文件中的接口。它会初始化(包括正常回零)、 检查状态并释放驱动,不设置目标位置,也不调用 move_motors()。真实硬件 会启用并回零;运行前确认工作空间已清空。以下为嵌入 C++ 应用的 API 示例,不是可直接粘贴到终端的命令:

#include <hand_driver.hpp>

int main() {
    auto hand = HandDriver::create_hand("RP_Hand", "canfd", "can0", HAND_RP_HAND_6DOF, 1);

    int result = 1;
    try {
        if (hand->init_hand(true, true, 5.0)) {
            hand->check_health();
            int total = 0;
            int active = 0;
            hand->get_dof(total, active);
            bool alarms_clear = true;
            for (int joint = 1; joint <= 6; ++joint) {
                if (hand->get_now_alarm(joint) != 0) alarms_clear = false;
            }
            result = (active == 6 && alarms_clear) ? 0 : 1;
        }
    } catch (...) {
        hand->deinit_hand();
        throw;
    }

    hand->deinit_hand();
    return result;
}

主要 API

以下是 HandDriver 的公共 Python/C++ API。C++ 方法使用 hand->method(), Python 方法使用 hand.method()

  • 创建与生命周期:create_hand()init_hand(enable_motors, home_motors, home_wait_time)deinit_hand()。工厂参数依次为 hand_typeinterface_typeinterfacehand_modelcanfd_node_id;本部署使用 "RP_Hand""canfd" 和 C++ 模型常量 HAND_RP_HAND_6DOF;Python 使用 HandModel.RP_HAND_6DOF。注意:对已初始化的驱动,重复 init_hand() 仅在参数完全一致时幂等返回 true;参数不同 (例如先以 enable_motors=false 初始化、再请求 true)会返回 false,此时应先 deinit_hand() 再重新初始化。 home_wait_time 是回零确认的最大超时;满足反馈条件会提前返回,传入 0.0 则保留不等待、不验证回零结果的兼容行为。
  • 枚举名称按语言区分:Python 使用 HandCommType.CANFDHandModel.RP_HAND_6DOF;C++ 使用 HandCommType::CANFDHAND_RP_HAND_6DOF。RP_Hand 品牌发布前版本中的标识符仍保持源码兼容, 但新代码应使用上述公共名称。
  • 运动执行:move_motors(finger_id=0)stop_motors(finger_id=0)home_motors(finger_id=0) 的默认 finger_id0,表示广播到全部 关节。set_enable(finger_id, enable) 必须显式传入 finger_id,但传入 0 仍表示广播;set_move_no_home(enable) 没有 finger_id,只接受 1(允许未完成回零时运动)或 0(要求先完成回零)。
  • 目标参数:set_target_position(finger_id, position)(编码器计数)、 set_target_angle(finger_id, angle)(角度)、 set_position_velocity(finger_id, velocity)(计数/秒)、 set_max_current(finger_id, current)(mA)。这些方法需要明确的 finger_id,没有默认值;按公共/厂商约定传入 0 表示广播到全部关节。 本手册示例仍显式使用关节 1..6,以便逐关节检查和控制。
  • 反馈与状态:get_now_position(finger_id)get_now_angle(finger_id)get_now_status(finger_id)get_now_current(finger_id)get_now_alarm(finger_id)clear_alarm(finger_id)clear_alarm(0) 清除全部关节报警;其他读取方法按指定关节返回缓存值。
  • 设备信息与健康:Python 中 total, active = hand.get_dof() 返回总关节数 和活动关节数;C++ 中使用 int total, active; hand->get_dof(total, active);get_can_name() 返回接口名,check_health() 在驱动故障时抛出异常。

必须遵守的运行注意事项

  • 启动控制程序前,先在库外配置并拉起目标 SocketCAN CAN-FD 接口;node ID 必须与实际灵巧手一致,并避免同一总线上出现冲突的 node ID。
  • 首次或配置未知的手必须先完成 20 ms 反馈周期配置并确认六个 raw value 都为 200;配置命令执行期间不要运行其他手控制进程。
  • init_hand() 返回 false 或抛出异常时,不要继续发送运动命令。运动前 根据实际机构确认目标位置、速度、负载和安全边界。
  • 每个成功创建的驱动都必须显式调用 deinit_hand();不要把 Python 对象 销毁或 C++ 智能指针析构当作清理替代方案。
  • 双手使用时保持一手一进程,并在每个进程中明确传入自己的 interface 和 node ID。

License

RoboParty 编写的源代码采用 GPL-3.0。仓库内捆绑的厂商 SDK 头文件和二进制 文件保留其自身的许可与再分发边界;相关说明请参阅 thirdparty/README.md

About

CAN-FD driver and Python bindings for Roboparty dexterous hands

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages