Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
b53e371
docs: add repository contributor guide
liangshaoteng Jun 15, 2026
c869c35
fix: adapt SDK integration and tighten node startup
liangshaoteng Jun 15, 2026
e3a96d0
feat: add control GUI with model configuration
liangshaoteng Jun 15, 2026
29dcaaf
feat: show feedback state and touch heatmaps
liangshaoteng Jun 15, 2026
f9783a4
fix: deduplicate commands and auto-detect hand model
liangshaoteng Jun 15, 2026
d56424a
feat: add Modbus transport support
liangshaoteng Jun 15, 2026
3f0069a
refactor: normalize naming
liangshaoteng Jun 29, 2026
068ed65
ci: dependence linkerhand-cpp-sdk v2.1.8
liangshaoteng Jun 30, 2026
ad112a8
chore: remove examples package and update README
liangshaoteng Jun 30, 2026
27c56d9
refactor: rename GUI script to hand_control_gui
liangshaoteng Jun 30, 2026
6d20b38
fix: resolve publisher thread data race and guard exceptions
liangshaoteng Jun 30, 2026
fbd9e7b
feat: add per-model position slider defaults in hand_control_gui
liangshaoteng Jul 1, 2026
75a04d0
doc: update readme
liangshaoteng Jul 2, 2026
298c963
refactor: overhaul hand_control_gui layout, perf, and interactions
liangshaoteng Jul 8, 2026
43c2b6b
refactor: move logo.png under assets/ subdirectory
liangshaoteng Jul 8, 2026
f27d42d
refactor: overhaul hand_control_gui toolbar, sliders, and add copy-po…
liangshaoteng Jul 9, 2026
be68ea0
chore: bump launch defaults to SDK 2.1.8 and refresh model presets
liangshaoteng Jul 9, 2026
d4c4785
chore: shorten GUI copy-values link to "复制位置"
liangshaoteng Jul 9, 2026
9d2b6c2
docs: overhaul README with SDK/CAN setup, tests, and GUI screenshot
liangshaoteng Jul 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ jobs:

- name: Setup LinkerHand SDK
run: |
git clone --branch v1.1.7 https://github.com/linker-bot/linkerhand-cpp-sdk.git /tmp/sdk
git clone --depth 1 --branch v2.1.8 https://github.com/linker-bot/linkerhand-cpp-sdk.git /tmp/sdk
cd /tmp/sdk && mkdir build && cd build
cmake .. && make -j$(nproc) && make install && ldconfig
cmake .. -DBUILD_EXAMPLES=OFF && make install && ldconfig

- name: Build Workspace
id: build_step
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
build
install
log
log
.vscode/
src/linker_hand_cpp_ros2/scripts/_*
CLAUDE.md
155 changes: 103 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ LinkerHand-CPP-ROS2 是灵心巧手科技有限公司开发,基于 LinkerHand-
- [环境要求](#-环境要求)
- [快速开始](#-快速开始)
- [话题详情](#-话题详情)
- [使用示例](#-使用示例)
- [控制 GUI](#️-控制-gui)
- [许可证](#-许可证)
- [联系我们](#-联系我们)
- [更新日志](#-更新日志)
Expand All @@ -24,69 +24,104 @@ LinkerHand-CPP-ROS2 是灵心巧手科技有限公司开发,基于 LinkerHand-

- **操作系统**: Linux (Ubuntu 20.04+ 推荐)
- **架构**: x86_64
- **编译器**: GCC 7.0+ 或 Clang 5.0+
- **编译器**: GCC 7.0+ 或 Clang 6.0+(C++17)
- **CMake**: 3.15+
- **依赖**: ROS2 (推荐 Foxy 或 Humble)、[linkerhand-cpp-sdk](https://github.com/linker-bot/linkerhand-cpp-sdk/releases/tag/v1.1.7)
- **依赖**: ROS2 (推荐 Foxy 或 Humble)、[linkerhand-cpp-sdk v2.1.8](https://github.com/linker-bot/linkerhand-cpp-sdk/releases/tag/v2.1.8)、`nlohmann_json`
- **GUI 可选依赖**: `python3-tk`、`rclpy`(用于 `hand_control_gui.py`)

> 注:本项目仅支持linkerhand-cpp-sdk v1.1.7及以下版本
> 注:CI 已适配 linkerhand-cpp-sdk v2.1.8;O20 依赖 CAN-FD,当前 ROS2 节点仍以普通 CAN 为主,暂未完成 O20 实机运行适配。Modbus 通信当前仅支持 O6 / L7 / L10。


## 🚀 快速开始

#### 下载

git clone https://github.com/linker-bot/linkerhand-cpp-ros2.git

#### 安装 SDK

先安装匹配版本的 [linkerhand-cpp-sdk v2.1.8](https://github.com/linker-bot/linkerhand-cpp-sdk/releases/tag/v2.1.8)(见其 README)。本仓库通过 `find_package(linkerhand-cpp-sdk 2.0 CONFIG REQUIRED)` 引用;节点的 RPATH 会指向 `${linkerhand-cpp-sdk_LIBRARY_DIR}`,SDK 位置变更后需要重新 `colcon build`。

#### 编译

cd linkerhand-cpp-ros2/
colcon build
colcon build # 全量构建
colcon build --packages-select linker_hand_cpp_ros2 # 仅构建核心节点包

#### 配置XML文件
#### 启动 CAN 设备

```bash
节点通过 SocketCAN 打开 `can0` / `can1` 等接口。使用前需先把 CAN 通道拉起(`CAN_BITRATE` 与 launch 参数保持一致):

sudo ip link set can0 down 2>/dev/null
sudo ip link set can0 up type can bitrate 1000000

> Modbus 通信当前仅支持 O6 / L7 / L10;O20 依赖 CAN-FD,暂未完成 O20 实机运行适配。

#### 配置 XML 文件

`launch/run.xml` 用于双手同时启动,`launch/run_left.xml` 用于仅启动单手。以 `run.xml` 为例(省略部分与实际默认值对齐):

```xml
<?xml version="1.0" encoding="utf-8"?>
<launch>
<!-- 参数声明 -->
<arg name="VERSION" default="1.1.6" description="版本号"/>
<arg name="VERSION" default="2.1.8" description="SDK版本号"/>

<!-- 左手配置 -->
<arg name="LEFT_HAND_EXISTS" default="true" description="是否存在左手"/>
<arg name="LEFT_TOUCH" default="true" description="是否有压力传感器"/>
<arg name="LEFT_JOINTS" default="L10" description="左手型号 L7 \ L10 \ L20 \ L21 \ L25"/>
<arg name="LEFT_CANBUS" default="can0" description="can0 \ can1"/>
<arg name="LEFT_HAND_EXISTS" default="true" description="是否存在左手"/>
<arg name="LEFT_TOUCH" default="true" description="是否有压力传感器"/>
<arg name="LEFT_JOINTS" default="G20" description="左手型号 L6 \ L7 \ L10 \ L20 \ L21 \ L25 \ O6 \ O20 \ G20"/>
<arg name="LEFT_COMM_TYPE" default="CAN" description="通信方式 CAN \ MODBUS(仅 O6/L7/L10)"/>

<!-- 右手配置 -->
<arg name="RIGHT_HAND_EXISTS" default="false" description="是否存在右手"/>
<arg name="RIGHT_TOUCH" default="false" description="是否有压力传感器"/>
<arg name="RIGHT_JOINTS" default="L10" description="右手型号 L7 \ L10 \ L20 \ L21 \ L25"/>
<arg name="RIGHT_CANBUS" default="can0" description="can0 \ can1"/>
<arg name="RIGHT_TOUCH" default="true" description="是否有压力传感器"/>
<arg name="RIGHT_JOINTS" default="L6" description="右手型号 L6 \ L7 \ L10 \ L20 \ L21 \ L25 \ O6 \ O20 \ G20"/>
<arg name="RIGHT_COMM_TYPE" default="CAN" description="通信方式 CAN \ MODBUS(仅 O6/L7/L10)"/>

<!-- 通用配置 -->
<arg name="HAND_SPEED" default="100" description="关节速度 0 ~ 255"/>
<arg name="HAND_EFFORT" default="200" description="关节扭矩 0 ~ 255"/>
<arg name="HAND_SPEED" default="255" description="关节速度 0 ~ 255"/>
<arg name="HAND_EFFORT" default="255" description="关节扭矩 0 ~ 255"/>
<arg name="CAN_BITRATE" default="1000000" description="CAN 波特率"/>

......

</launch>
```

> 手动打开CAN设备后,执行launch会自动检测左手或右手CAN通道。

#### 运行

source install/setup.bash
ros2 launch linkerhand_cpp_ros2 run.xml
# 双手(按 run.xml 默认配置启动)
ros2 launch linker_hand_cpp_ros2 run.xml
# 仅左手
ros2 launch linker_hand_cpp_ros2 run_left.xml
# 覆盖某个参数的示例
ros2 launch linker_hand_cpp_ros2 run.xml LEFT_JOINTS:=L10 LEFT_CANBUS:=can1

#### 测试与静态检查

colcon test && colcon test-result --verbose

项目已禁用 cpplint / uncrustify / copyright / xmllint,主要走 `ament_lint_auto` 剩余检查。


## 📚 话题详情

| 话题名称 | I/O | 消息类型 | 描述 |
| :--- | :--- | :--- | :--- |
| /left_hand_control | Input | sensor_msgs/msg/JointState | 左手控制指令 |
| /left_hand_settings | Input | sensor_msgs/msg/String | 左手设置指令 |
| /left_hand_settings | Input | std_msgs/msg/String | 左手设置指令 |
| /left_hand_touch | Output | std_msgs/msg/Float32MultiArray | 左手触觉传感器数据 |
| /left_hand_state | Output | sensor_msgs/msg/JointState | 左手关节状态 |
| /left_hand_info | Output | std_msgs/msg/String | 左手基本信息 |
| /right_hand_control | Input | sensor_msgs/msg/JointState | 左手控制指令 |
| /right_hand_settings | Input | sensor_msgs/msg/String | 右手设置指令 |
| /right_hand_touch | Output | std_msgs/msg/Float32MultiArray | 左手触觉传感器数据 |
| /right_hand_state | Output | sensor_msgs/msg/JointState | 左手关节状态 |
| /right_hand_info | Output | std_msgs/msg/String | 左手基本信息 |
| /right_hand_control | Input | sensor_msgs/msg/JointState | 右手控制指令 |
| /right_hand_settings | Input | std_msgs/msg/String | 右手设置指令 |
| /right_hand_touch | Output | std_msgs/msg/Float32MultiArray | 右手触觉传感器数据 |
| /right_hand_state | Output | sensor_msgs/msg/JointState | 右手关节状态 |
| /right_hand_info | Output | std_msgs/msg/String | 右手基本信息 |


针对以上话题的具体字段及其详细描述如下表所示:
Expand All @@ -113,11 +148,15 @@ LinkerHand-CPP-ROS2 是灵心巧手科技有限公司开发,基于 LinkerHand-
```bash
L7: ["大拇指弯曲", "大拇指横摆","食指弯曲", "中指弯曲", "无名指弯曲","小拇指弯曲","拇指旋转"]

L6/O6: ["拇指根部", "拇指侧摆", "食指根部", "中指根部", "无名指根部", "小指根部"]

L10: ["拇指根部", "拇指侧摆","食指根部", "中指根部", "无名指根部","小指根部","食指侧摆","无名指侧摆","小指侧摆","拇指旋转"]

L20: ["拇指根部", "食指根部", "中指根部", "无名指根部","小指根部","拇指侧摆","食指侧摆","中指侧摆","无名指侧摆","小指侧摆","拇指横摆","预留","预留","预留","预留","拇指尖部","食指末端","中指末端","无名指末端","小指末端"]

L21: ["大拇指根部", "食指根部", "中指根部","无名指根部","小拇指根部","大拇指侧摆","食指侧摆","中指侧摆","无名指侧摆","小拇指侧摆","大拇指横滚","预留","预留","预留","预留","大拇指中部","预留","预留","预留","预留","大拇指指尖","食指指尖","中指指尖","无名指指尖","小拇指指尖"]
G20: ["大拇指根部", "食指根部", "中指根部","无名指根部","小拇指根部","大拇指侧摆","食指侧摆","中指侧摆","无名指侧摆","小拇指侧摆","大拇指横滚","大拇指指尖","食指指尖","中指指尖","无名指指尖","小拇指指尖"]

L21: ["大拇指根部", "食指根部", "中指根部","无名指根部","小拇指根部","大拇指侧摆","食指侧摆","中指侧摆","无名指侧摆","小拇指侧摆","大拇指横滚","预留","预留","预留","预留","大拇指中部","预留","预留","预留","预留","大拇指指尖"]

L25: ["大拇指根部", "食指根部", "中指根部","无名指根部","小拇指根部","大拇指侧摆","食指侧摆","中指侧摆","无名指侧摆","小拇指侧摆","大拇指横滚","预留","预留","预留","预留","大拇指中部","食指中部","中指中部","无名指中部","小拇指中部","大拇指指尖","食指指尖","中指指尖","无名指指尖","小拇指指尖"]
```
Expand All @@ -130,17 +169,7 @@ L25: ["大拇指根部", "食指根部", "中指根部","无名指根部","小

```bash
# 清除故障码
$ ros2 topic pub /left_hand_setting std_msgs/msg/String "data: '{\"setting_cmd\": \"clear_faults\"}'"

# 设置电流
$ ros2 topic pub /left_hand_setting std_msgs/msg/String "data: '{\"setting_cmd\": \"set_electric_current\", \"params\": {\"electric_current\": 50}}'"

# 使能
$ ros2 topic pub /left_hand_setting std_msgs/msg/String "data: '{\"setting_cmd\": \"enable\"}'"

# 失能
$ ros2 topic pub /left_hand_setting std_msgs/msg/String "data: '{\"setting_cmd\": \"disable\"}'"

$ ros2 topic pub /left_hand_settings std_msgs/msg/String "data: '{\"setting_cmd\": \"clear_faults\"}'"
```


Expand Down Expand Up @@ -179,7 +208,11 @@ data: 'Hand direction: Left hand
```
- 压感数据 /left_hand_touch

注意:反馈数据为一个一维数组,长度为360,由每个手指的压感数据组成。单个指头压感数据长度是72(6*12矩阵),每个手指压感数据需要单独拆分。(仅适用点阵式传感器)
注意:反馈数据为一个一维数组,长度按型号区分:
- 常规型号:长度 360,5 指 × 72(6×12 矩阵)/指;
- O6:长度 200,5 指 × 40(4×10 矩阵)/指。

每个手指压感数据需要自行按指拆分。仅适用点阵式传感器。

```bash
$ ros2 topic echo /left_hand_touch
Expand All @@ -195,20 +228,34 @@ data:
- '...'
```

## 💡 使用示例
## 🎛️ 控制 GUI

`hand_control_gui.py` 提供基于 tkinter 的可视化面板:拖动线性滑块直接下发 `JointState`,同时显示 `state` / `touch` / `info` 反馈(含触觉热力图)。它只依赖标准话题,可与任意 `run.xml` 场景配合。

| 序号 | 文件名称 | 描述 |
| :--- | :-------- | :--------------------------------------------- |
| 1 | src/examples/src/action_group_show_l7 | L7型号手指舞示例 |
| 2 | src/examples/src/action_group_show_l10 | L10型号手指舞示例 |
| 3 | src/examples/src/action_group_show_l20 | L20型号手指舞示例 |
| 4 | src/examples/src/loop_l20 | L20型号手势张开握拳示例 |
| 5 | src/examples/src/show_ok_l20 | L20型号手势ok示例 |
| 6 | src/examples/src/show_surround_index_finger_l20 | L20型号单指手势示例 |
| 7 | src/examples/src/show_wave_l20 | L20型号wave手势示例 |
| 8 | src/examples/src/action_group_show_l25 | L25型号手指舞示例 |
| 9 | src/examples/src/loop_l25 | L25型号手势张开握拳示例 |
<p align="center">
<img src="src/linker_hand_cpp_ros2/assets/hand_control_gui.png" alt="hand_control_gui 截图" width="820"/>
</p>

```bash
source install/setup.bash
# 自动从 /linker_hand_{side}_node 读取 HAND_JOINTS 型号参数
ros2 run linker_hand_cpp_ros2 hand_control_gui.py
# 或显式指定型号
ros2 run linker_hand_cpp_ros2 hand_control_gui.py --side right --model L10
```

功能界面:

- **顶部**:型号 / 侧别 下拉框;「实时」开关(打开后按 `--rate` 周期 (默认60hz) 把当前滑块值发布出去)。
- **中部左**:反馈面板 —— `位置` / `速度` / `力矩` 三行数值,下方是 5 指触觉热力图;型号切换会自动重建。
- **中部右**:控制面板 —— 通过顶部 tab 在 `位置` / `速度` / `力矩` 之间切换;点击或拖动线条即可调整(0–255);右侧 Spinbox 支持精确输入。
- **底部右下**:`复制位置值` 链接,把当前所有关节位置以 `"255, 255, 255, ..."` 的形式写入剪贴板。

常用参数:`--side left|right`、`--model L6|O6|L7|L10|L20|L21|L25|G20|O20`、`--rate <Hz>`、`--no-live`(禁用自动发布,仅调试用)。

初始位置:`hand_control_gui.py` 中的 `POSITION_DEFAULTS` 按型号定制(默认全 255);`G20` 使用 `[255, 255, 255, 255, 255, 255, 130, 125, 125, 125, 255, 255, 255, 255, 255, 255]` 作为张开手掌的安全初值。

依赖 `python3-tk` 与 `rclpy`。

## 📄 许可证

Expand All @@ -224,8 +271,12 @@ Copyright (c) 2026 灵心巧手(北京)科技有限公司

## 📝 更新日志

详细的版本更新记录请参考 [CHANGELOG.md](CHANGELOG.md)(待创建)。
详细的版本更新记录请查看 [`git log`](https://github.com/linker-bot/linkerhand-cpp-ros2/commits/main) 或本地执行:

```bash
git log --oneline --decorate
```

---

**注意**: 使用前请确保设备已正确连接并配置好通信接口。
**注意**: 使用前请确保设备已正确连接并配置好通信接口。
Loading
Loading