Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
114 changes: 71 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,11 @@ LinkerHand-CPP-SDK 由灵心巧手(北京)科技有限公司开发,提供
- [API 文档](#-api-文档)
- [通信协议](#-通信协议)
- [支持的型号](#-支持的型号)
- [网页示教器](#-网页示教器)
- [项目结构](#-项目结构)
- [示例程序列表](#-示例程序列表)
- [关节映射表](#-关节映射表)
- [故障排查](#-故障排查)
- [常见问题](#-常见问题)
- [贡献](#-贡献)
- [更新日志](#-更新日志)
- [故障排查与常见问题](#-故障排查与常见问题)
- [许可证](#-许可证)
- [联系我们](#-联系我们)

Expand Down Expand Up @@ -55,7 +53,7 @@ LinkerHand-CPP-SDK 由灵心巧手(北京)科技有限公司开发,提供
- 操作系统:Windows 10 / 11 (x64)
- 编译器:MinGW-w64 GCC 13+,线程模型需为 `win32`(`g++ -v` 查看 `Thread model`),或 MSVC(VS2017 / VS2019 / VS2022 任一,已实测 VS2017 消费 CI artifact 通过)
- CMake:建议 4.0+(已实测 4.0.3)
- 依赖:`PCAN-Basic` 与 mingw 运行时 DLL 已随发布包附带
- 依赖:`PCAN-Basic` 与 mingw 运行时 DLL 已随 SDK 附带


## 🚀 快速开始
Expand All @@ -69,7 +67,7 @@ cd linkerhand-cpp-sdk

### 2. 使用脚本构建

发布包内附 `build.sh`(Linux)与 `build.bat`(Windows)。
SDK 目录内附 `build.sh`(Linux)与 `build.bat`(Windows)。

| 选项 | 说明 |
|------|------|
Expand Down Expand Up @@ -105,6 +103,16 @@ build.bat # 编译
# Windows (无需操作)
```

**不想每次手动敲命令?** 用 `can-autocfg.sh` 一次性安装自动配置(systemd 模板服务 + udev 规则):接口**插入 / 开机时自动 up,关机 / 重启时自动干净 down**,并按设备能力自动识别经典 CAN 或 CAN-FD(FD 自动加 `dbitrate 5000000 fd on`)、设 `txqueuelen`、开 bus-off 自动恢复。

```bash
sudo ./can-autocfg.sh # 经典 1000000;FD 设备自动 dbitrate 5000000
sudo BITRATE=500000 ./can-autocfg.sh # 改经典 / 仲裁段波特率
sudo BITRATE=1000000 DBITRATE=2000000 ./can-autocfg.sh # 改 FD 数据段波特率
```

安装后无需再手动 `ip link set canX up`,开机 / 插入即自动配置。适用于 PEAK PCAN-USB / candleLight(gs_usb) 等 SocketCAN 适配器。

### 4. 运行示例程序

构建完成后,可执行文件位于 `build/bin/`:
Expand Down Expand Up @@ -136,10 +144,10 @@ touch main.cpp CMakeLists.txt
两种集成方式的目录布局:

```
# 解压即用(未安装 SDK,把发布包整个拷到工程内)
# 解压即用(未安装 SDK,把 SDK 目录整个拷到工程内)
demo/
├── CMakeLists.txt
├── linkerhand-cpp-sdk/ # 即本发布包
├── linkerhand-cpp-sdk/ # 即本 SDK 目录
└── main.cpp

# 已安装 SDK(系统级,find_package 即可找到)
Expand Down Expand Up @@ -197,7 +205,7 @@ project(my_app LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 解压即用:把发布包目录加进 CMake 搜索路径,无需安装。
# 解压即用:把 SDK 目录加进 CMake 搜索路径,无需安装。
# 等价命令行:cmake -S . -B build -DCMAKE_PREFIX_PATH=${CMAKE_SOURCE_DIR}/linkerhand-cpp-sdk
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/linkerhand-cpp-sdk")

Expand Down Expand Up @@ -274,6 +282,50 @@ cmake --build . -j
| LinkerHand O6 | CAN / Modbus | O6 series robotic hand |
| LinkerHand O20 | CAN-FD | O20 series robotic hand(不支持Linux aarch64) |

## 🌐 网页示教器

`webui/` 是一套开箱即用的网页控制界面,全型号(L6 / L7 / L10 / L20 / L21 / L25 / G20 / O6 / O20)通用,O20 走 CAN-FD。

> **`./build.sh -b` 编译完成后即可直接使用**,无需额外构建,`python3 webui/run.py` 起服务即用。

<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/images/webui-overview-dark.png">
<img alt="webui 主界面" src="docs/images/webui-overview-light.png">
</picture>

### 功能

- 按型号动态渲染**关节滑块**,实时位置回读
- **速度 / 力矩**设置与回读
- **触觉压感热力图**(含掌心,O6 / G20),维度按型号自适应
- **温度 / 故障**监控表(温度 >50 黄、>60 红,故障码非 0 红)
- 版本信息展示、明暗主题切换
- 在线连接:前端「设置」面板选择型号 / 侧别 / 通信方式,支持热重连与主动断开

### 运行

编译完成后,拉起对应总线、给手上电,启动服务即可:

```bash
./build.sh -b # 一次编译,webui 随之就绪
sudo ip link set can0 up type can bitrate 1000000 # CAN 型号;Modbus 见下
python3 webui/run.py # 起服务,型号/通信在前端「设置」里选
```

浏览器打开 `http://<本机IP>:8080/`。也可命令行直连指定型号:

```bash
python3 webui/run.py --model O6 --side left
python3 webui/run.py --model L10 --side left --channel can0
python3 webui/run.py --model O20 --side right # 厂商 CAN-FD 设备
python3 webui/run.py --model O20 --side right --channel socketcan:can0
python3 webui/run.py --model L10 --comm modbus --channel /dev/ttyUSB0
```

主要参数:`--model`(不填则在前端在线连接)、`--side left|right`、`--comm can|canfd|modbus`(缺省按型号自动)、`--channel`(CAN 接口名 / Modbus 串口)、`--host`(默认 `0.0.0.0`)、`--port`(默认 `8080`)。更多用法见 [`webui/README.md`](webui/README.md)。

> Modbus 型号需串口读写权限:`sudo chmod 0777 /dev/ttyUSB0` 或把用户加入 `dialout` 组。

## 📁 项目结构

```
Expand All @@ -300,13 +352,16 @@ linkerhand-cpp-sdk/
│ ├── mingw/ # Windows MinGW(.dll)
│ └── msvc/ # Windows MSVC(.dll / .lib)
├── examples/ # 示例源码(CAN / CAN-FD / Modbus)
├── webui/ # 网页示教器(浏览器控制界面)
├── docs/ # API-Reference / FAQ / TROUBLESHOOTING
│ └── images/ # 文档配图
├── cmake/ # find_package 用的 *-config.cmake
├── third_party/
│ ├── libcanbus/ # CAN / CAN-FD 驱动
│ └── PCAN_Basic/ # Windows PCAN 驱动
├── build.sh # 构建脚本(Linux)
├── build.bat # 构建脚本(Windows)
├── can-autocfg.sh # CAN/CAN-FD 自动激活/关闭(可选)
└── CMakeLists.txt # 顶层 CMake:聚合 examples + 安装规则
```

Expand Down Expand Up @@ -356,53 +411,27 @@ linkerhand-cpp-sdk/
"食指侧摆", "无名指侧摆", "小指侧摆", "拇指旋转"]
```

- L20
- G20
```
["拇指根部", "食指根部", "中指根部", "无名指根部", "小指根部",
"拇指侧摆", "食指侧摆", "中指侧摆", "无名指侧摆", "小指侧摆",
"拇指横摆", "预留", "预留", "预留", "预留",
"拇指尖部", "食指末端", "中指末端", "无名指末端", "小指末端"]
["大拇指根部", "食指根部", "中指根部","无名指根部","小拇指根部",
"大拇指侧摆","食指侧摆","中指侧摆","无名指侧摆","小拇指侧摆",
"大拇指横滚","大拇指指尖","食指指尖","中指指尖","无名指指尖","小拇指指尖"]
```

- L21 / L25
详细映射见 [`docs/API-Reference.md`](docs/API-Reference.md)。

## 🔧 故障排查
## 🔧 故障排查与常见问题

- [故障排查指南](docs/TROUBLESHOOTING.md) — 编译 / 运行时 / 通信 / API 使用 / 性能
- [常见问题解答](docs/FAQ.md) — 安装、使用、API、兼容性、性能
- [常见问题解答](docs/FAQ.md) — 安装、使用、接口选择、各型号关节数、性能等

如文档无法解决:

1. 在 [GitHub Issues](https://github.com/linker-bot/linkerhand-cpp-sdk/issues) 搜索同类问题
2. 提交新 Issue,附错误信息与复现步骤
3. 联系技术支持:<https://linkerbot.cn/aboutUs>

## ❓ 常见问题

快速答案见 [FAQ](docs/FAQ.md),覆盖:

- 如何安装与配置 SDK
- 如何选择通信接口
- 各型号关节数量
- 如何提升性能
- 如何获取技术支持

## 🤝 贡献

欢迎社区贡献:

1. Fork 本仓库
2. 创建特性分支:`git checkout -b feature/AmazingFeature`
3. 提交更改:`git commit -m 'feat: 新增 AmazingFeature'`
4. 推送:`git push origin feature/AmazingFeature`
5. 开启 Pull Request

更多贡献指南见 `CONTRIBUTING.md`(待创建)。

## 📝 更新日志

详细版本记录见 `CHANGELOG.md`(待创建)。

## 📄 许可证

本项目采用 [MIT 许可证](LICENSE)。
Expand All @@ -418,4 +447,3 @@ Copyright (c) 2026 灵心巧手(北京)科技有限公司
---

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

101 changes: 101 additions & 0 deletions can-autocfg.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/usr/bin/env bash
#
# CAN 自动配置安装脚本(适用于 PEAK PCAN-USB / candleLight(gs_usb) 等 SocketCAN 适配器)
#
# 作用:安装一个 systemd 模板服务 + udev 规则,使任意 canX 接口
# - 插入/开机时自动 up(按设备能力自动选 经典CAN 或 CANFD、设 txqueuelen、bus-off 自动恢复);
# - 关机/重启时自动干净 down,避免适配器接收通路卡死。
#
# 用法: sudo ./can-autocfg.sh # 经典 1000000;FD 设备自动 dbitrate 5000000
# sudo BITRATE=500000 ./can-autocfg.sh # 改经典/仲裁段波特率
# sudo BITRATE=1000000 DBITRATE=2000000 ./can-autocfg.sh # 改 FD 数据段波特率
#
set -euo pipefail

BITRATE="${BITRATE:-1000000}"
DBITRATE="${DBITRATE:-5000000}"
TXQUEUELEN="${TXQUEUELEN:-1024}"
RESTART_MS="${RESTART_MS:-100}"

if [ "$(id -u)" -ne 0 ]; then
echo "请用 sudo 运行: sudo ./can-autocfg.sh" >&2
exit 1
fi

IP_BIN="$(command -v ip || echo /usr/sbin/ip)"
HELPER=/usr/local/sbin/can-setup-up.sh
SERVICE=/etc/systemd/system/can-setup@.service
RULE=/etc/udev/rules.d/90-can-setup.rules

echo "[1/5] 写入能力判别启动脚本 $HELPER ..."
cat > "$HELPER" <<EOF
#!/usr/bin/env bash
# 由 can-autocfg.sh 生成:按设备能力自动以 经典CAN 或 CANFD 启动接口。
set -eu

IFACE="\${1:?usage: can-setup-up.sh <iface>}"
IP="$IP_BIN"
BITRATE="\${BITRATE:-$BITRATE}"
DBITRATE="\${DBITRATE:-$DBITRATE}"
RESTART_MS="\${RESTART_MS:-$RESTART_MS}"

# 干净起点
"\$IP" link set "\$IFACE" down 2>/dev/null || true

# FD 能力判别:仅 FD 控制器广播数据段时序常量 data_bittiming_const
# (DOWN 时即存在,与 max_mtu / 是否已 fd on 无关,厂商/驱动无关)
FDARGS=""
if "\$IP" -d -j link show "\$IFACE" | grep -q data_bittiming_const; then
FDARGS="dbitrate \$DBITRATE fd on"
fi

# restart-ms 容错:部分 FD 控制器(如 gs_usb)不支持 Bus-Off 自动恢复,失败则降级重试
"\$IP" link set "\$IFACE" type can bitrate "\$BITRATE" \$FDARGS restart-ms "\$RESTART_MS" 2>/dev/null \\
|| "\$IP" link set "\$IFACE" type can bitrate "\$BITRATE" \$FDARGS

"\$IP" link set "\$IFACE" up
EOF
chmod +x "$HELPER"

echo "[2/5] 写入模板服务 $SERVICE (bitrate=$BITRATE dbitrate=$DBITRATE) ..."
cat > "$SERVICE" <<EOF
[Unit]
Description=CAN %i setup (up on appear, clean down on shutdown)
BindsTo=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device

[Service]
Type=oneshot
RemainAfterExit=yes
Environment=BITRATE=$BITRATE DBITRATE=$DBITRATE RESTART_MS=$RESTART_MS
ExecStart=$HELPER %i
ExecStartPost=$IP_BIN link set %i txqueuelen $TXQUEUELEN
ExecStop=$IP_BIN link set %i down
EOF

echo "[3/5] 写入 udev 规则 $RULE ..."
cat > "$RULE" <<'EOF'
# 任何 CAN 网络接口出现时,自动启动对应的 can-setup@<iface> 实例
SUBSYSTEM=="net", ACTION=="add", KERNEL=="can*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="can-setup@$name.service"
EOF

echo "[4/5] 重新加载 systemd 与 udev ..."
systemctl daemon-reload
udevadm control --reload

echo "[5/5] 对已存在的 CAN 接口触发一次(无需重启即可生效)..."
for IFACE in $(ls /sys/class/net/ | grep -E '^can[0-9]+$' || true); do
echo " -> 触发 $IFACE"
udevadm trigger --action=add --subsystem-match=net --sysname-match="$IFACE" || true
done
sleep 2

echo
echo "===== 安装完成,当前 CAN 接口状态 ====="
for IFACE in $(ls /sys/class/net/ | grep -E '^can[0-9]+$' || true); do
systemctl is-active "can-setup@${IFACE}.service" >/dev/null 2>&1 \
&& echo " $IFACE : 服务 active" || echo " $IFACE : 服务未激活(检查日志)"
"$IP_BIN" -details link show "$IFACE" | sed -n '1p;3p' | sed 's/^/ /'
done
echo
echo "提示:以后无需手动 ip link set canX up,开机/插入即自动配置(经典/FD 自动识别)。"
36 changes: 36 additions & 0 deletions docs/API-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,42 @@ std::vector<std::vector<std::vector<uint8_t>>> getForce();

---

### 获取全掌压感点阵
```cpp
std::vector<std::vector<uint8_t>> getPalmForce();
```
**Description**:
获取手掌区域的触觉压感点阵。矩阵维度随掌部传感器类型而定:`TSSP_JZG` 为 20 行 × 28 列,`TSSP_HWK` 为 14 行 × 16 列。
**支持型号**:L6 / O6 / G20(其余型号返回空并提示不支持)。
**Returns**:
- 返回二维向量 `std::vector<std::vector<uint8_t>>`:外层为行、内层为列,每个元素为该传感单元的压感值(uint8_t)。

---

### 获取五指合力值
```cpp
std::vector<std::vector<uint8_t>> getFingerForceSum();
```
**Description**:
获取五根手指的法向合力值。每指分量数随传感器类型而定:`TSSP_JZG` 每指 3 个,`TSSP_HWK` 每指 1 个。
**支持型号**:G20(其余型号返回空并提示不支持)。
**Returns**:
- 返回二维向量 `std::vector<std::vector<uint8_t>>`:外层大小 = 5(五根手指),内层为该指的合力分量。

---

### 获取全掌合力值
```cpp
std::vector<uint8_t> getPalmForceSum();
```
**Description**:
获取整个手掌的法向合力值。分量数随传感器类型而定:`TSSP_JZG` 为 2 个,`TSSP_HWK` 为 1 个。
**支持型号**:G20(其余型号返回空并提示不支持)。
**Returns**:
- 返回一个 `std::vector<uint8_t>`,为手掌合力分量。

---

### 获取速度
```cpp
std::vector<uint8_t> getSpeed();
Expand Down
Loading
Loading