# 触觉传感器与执行器控制系统 —— 使用手册

## 项目概述

本项目提供了一套完整的触觉传感器数据采集与执行器（舵机、直线电机）控制系统，包含底层 I2C 通信驱动、传感器数据解析、多指数据采集、串口执行器控制、手柄/键盘遥控以及数据记录等功能模块。

### 系统架构

```
┌──────────────────────────────────────────────────────┐
│                   应用层 (Application)                 │
│  demo_auto_grasp.py  test_dof_control.py             │
│  gamepad_remote.py   gamepad_remote_new_pcb.py        │
│  keyboard_remote_new_pcb.py  data_logger.py            │
│  grasp_network_model.py                                │
├──────────────────────────────────────────────────────┤
│                 数据采集层 (DAQ Layer)                  │
│  cap_read.py  tactile_sensor_daq.py                   │
├──────────────────────────────────────────────────────┤
│                 驱动抽象层 (Driver Layer)               │
│  class_finger.py  class_sensorcmd.py  sensorPara.py   │
│  class_ch341.py   serial_robot_driver.py               │
├──────────────────────────────────────────────────────┤
│                 硬件层 (Hardware)                       │
│  CH341 (USB-I2C)    STM32F103 (Serial)                │
│  触觉传感器          舵机 / 直线电机                    │
└──────────────────────────────────────────────────────┘
```

---

## 目录

1. [环境准备](#1-环境准备)
2. [模块说明](#2-模块说明)
3. [快速开始](#3-快速开始)
4. [底层驱动详解](#4-底层驱动详解)
5. [数据采集模块](#5-数据采集模块)
6. [执行器控制](#6-执行器控制)
7. [遥控模块](#7-遥控模块)
8. [数据记录](#8-数据记录)
9. [神经网络模型](#9-神经网络模型)
10. [STM32 固件](#10-stm32-固件)
11. [硬件接线](#11-硬件接线)
12. [常见问题](#12-常见问题)

---

## 1. 环境准备

> **重要：请严格按照以下顺序操作，先安装驱动，再安装 Python 依赖。**

### 1.1 CH341 驱动安装（必须首先完成）

CH341 是 USB 转 I2C 芯片，用于与触觉传感器通信。**使用本项目前，必须先安装此驱动**，否则传感器无法被电脑识别。

#### Windows

1. 在项目根目录下找到压缩包 **`CH341驱动（先卸载再安装）.zip`**，将其解压。
2. **如果之前安装过其它版本的 CH341 驱动，请先卸载**。
3. 运行解压后的 `CH341PAR.exe`，按照提示完成安装。
4. 安装完成后，将传感器通过 CH341 转接板连接电脑 USB，系统会自动识别设备。

> 驱动安装后，项目代码会自动加载 `lib/ch341/CH341DLLA64.DLL`，无需额外配置。

#### Linux

1. 将 `lib/ch341/libch347.so` 放置到系统库路径或项目目录下。

2. 配置 udev 规则（将 `john` 替换为你的用户名）：
```bash
# 将用户添加到 dialout 组
sudo usermod -a -G dialout john

# 创建 udev 规则文件
sudo bash -c 'echo "SUBSYSTEM==\"usbmisc\", ATTRS{idVendor}==\"1a86\", ATTRS{idProduct}==\"5512\", MODE=\"0666\", GROUP=\"dialout\"" > /etc/udev/rules.d/ch341.rules'

# 重载规则
sudo udevadm control --reload-rules
sudo udevadm trigger
```

3. 重新插拔 CH341 设备，或重启计算机使 udev 规则生效。

### 1.2 Python 依赖

推荐使用 Python 3.8 及以上版本。安装依赖：

```bash
pip install pyserial numpy pygame keyboard torch
```

各模块依赖说明：

| 模块 | 依赖 |
|------|------|
| 底层驱动 (class_ch341, class_sensorcmd, class_finger) | 无额外依赖 |
| 数据采集 (cap_read, tactile_sensor_daq) | numpy |
| 串口执行器 (serial_robot_driver) | pyserial |
| 手柄遥控 (gamepad_remote, gamepad_remote_new_pcb) | pyserial, pygame |
| 键盘遥控 (keyboard_remote_new_pcb) | pyserial, keyboard, numpy |
| 数据记录 (data_logger) | numpy |
| 神经网络 (grasp_network_model) | torch (PyTorch) |

> **说明：** 如果仅使用传感器数据读取功能（cap_read、tactile_sensor_daq），只需安装 `numpy`。执行器控制、遥控、神经网络等模块可按需安装对应依赖。

---

## 2. 模块说明

### 2.1 文件清单

| 文件名 | 功能说明 |
|--------|----------|
| `class_ch341.py` | CH341 USB-I2C 底层驱动，封装 I2C 读写、速度设置、INT 引脚控制 |
| `class_sensorcmd.py` | 传感器 I2C 命令协议，封装所有传感器配置与读取命令 |
| `class_finger.py` | 传感器（手指）数据解析，包含电容/力数据读取与协议解析 |
| `sensorPara.py` | 传感器参数定义（通道数、力单元数、数据格式等） |
| `cap_read.py` | 基础电容读取入口，支持单指/多指数据采集与实时可视化 |
| `tactile_sensor_daq.py` | 多指触觉传感器数据采集模块（线程安全，支持去皮） |
| `serial_robot_driver.py` | 串口执行器驱动，控制舵机和直线电机 |
| `stm32f103_drv8870_servo_main.c` | STM32F103 下位机固件源码 |
| `demo_auto_grasp.py` | 演示程序：触觉反馈自动抓取任务 |
| `gamepad_remote.py` | 游戏手柄遥控程序 |
| `gamepad_remote_new_pcb.py` | 新 PCB 版手柄遥控（支持 ACK 协议和自检） |
| `keyboard_remote_new_pcb.py` | 新 PCB 版键盘遥控（支持力反馈与压力计算） |
| `test_dof_control.py` | 自由度独立控制测试 |
| `data_logger.py` | CSV 数据记录器 |
| `grasp_network_model.py` | 条件抓取网络模型（Conditional MLP） |
| `接线说明.txt` | 硬件接线参考 |
| `新PCB控制实施方案.md` | 新 PCB 控制系统实施方案 |
| `CH341驱动（先卸载再安装）.zip` | CH341 驱动程序压缩包，使用前必须先解压安装 |
| `传感器iic地址和转接板位置定义.png` | I2C 地址与接口位置对照图 |

---

## 3. 快速开始

### 3.1 仅读取单个传感器数据

```bash
python cap_read.py
```

运行前可在 `cap_read.py` 中修改传感器连接数量：

```python
DEF_MAX_FINGER_NUM = 1  # 需要连接的手指数量，最大5个
```

输出数据包括：
- `capChannelDat`：电容通道原始值
- `nf[i]`：第 i 个单元的法向力
- `tf[i]`：第 i 个单元的切向力
- `tfDir[i]`：第 i 个单元的切向力方向
- `sProxCapData`：自电容接近值
- `mProxCapData`：互电容接近值

### 3.2 读取多个传感器数据（100Hz）

```python
from tactile_sensor_daq import TactileSensorDAQ

sensor = TactileSensorDAQ()
sensor.start()

# 等待传感器连接稳定
import time
time.sleep(3)
sensor.tare()  # 去皮

while True:
    data = sensor.get_data()  # 获取 12 维力数据
    print(data)
    time.sleep(0.1)
```

### 3.3 控制执行器（串口）

```python
from serial_robot_driver import RobotDriver

robot = RobotDriver(port='COM9')
robot.motor_open()      # 直线电机张开
robot.motor_close()     # 直线电机闭合
robot.motor_stop()      # 停止
robot.set_servo(1, 90)  # 舵机1转到90度
robot.set_config(0)     # 构型0（初始位）
robot.close()
```

### 3.4 命令行快速测试

```bash
# 测试通信
python gamepad_remote_new_pcb.py --port COM9 --cmd PING

# 硬件自检
python gamepad_remote_new_pcb.py --port COM9 --test

# 手柄遥控
python gamepad_remote_new_pcb.py --port COM9

# 键盘遥控
python keyboard_remote_new_pcb.py --port COM9
```

---

## 4. 底层驱动详解

### 4.1 class_ch341.py —— CH341 I2C 通信驱动

封装 CH341 USB-I2C 转换芯片的操作。

**主要接口：**

```python
from class_ch341 import ClassCh341

ch341 = ClassCh341()

# 初始化并打开设备
ch341.init()                          # 加载 DLL/SO 库
ch341.open()                          # 打开 USB 设备

# 设置 I2C 速度
ch341.set_speed(ch341.IIC_SPEED_400)  # 20/100/400/750 kHz

# I2C 读写
ch341.write(addr, data_list)          # 向从机地址写入数据列表
ch341.read(addr, data_list)           # 从从机地址读取数据到列表

# 连接检查
ch341.connectCheck()                  # 返回 True/False

# 断开
ch341.disconnect()
```

### 4.2 class_sensorcmd.py —— 传感器命令协议

封装与触觉传感器 MCU 的 I2C 命令协议。

**主要接口：**

```python
from class_sensorcmd import ClassSensorCmd

snsCmd = ClassSensorCmd(ch341)

# 地址管理
snsCmd.getAddr(addr)             # 读取传感器 I2C 地址
snsCmd.setAddr(old_addr, new)    # 设置新地址

# 传感器配置
snsCmd.setSensorSendType(addr, 0)      # 设置数据发送类型为原始值
snsCmd.setSensorCapOffset(addr, offset) # 设置电容采集时序偏移

# 读取数据
snsCmd.getSensorCapData(addr, buf)     # 读取电容数据
snsCmd.getSensorProjectIdex(addr)      # 读取项目编号

# 同步
snsCmd.setSensorSync(addr)             # 多传感器同步
```

### 4.3 sensorPara.py —— 传感器参数定义

定义了传感器项目的参数结构和具体参数值。

```python
from sensorPara import finger_params, FingerParamTS, DynamicYddsU16Ts

# finger_params 包含所有支持的传感器类型
# 目前支持:
#   - 项目2: "通用手指", 8通道, 1个三维力单元
#   - 项目17: "两指-大包", 16通道, 2个三维力单元
```

如需添加新的传感器型号，在 `sensorPara.py` 中追加 `FingerParamTS` 条目即可。

### 4.4 class_finger.py —— 传感器数据解析

管理单个传感器（手指）的连接状态和数据读取。

```python
from class_finger import ClassFinger, capData

finger = ClassFinger(pca_idx=2, ch341=ch341)

# 检查传感器连接
if finger.checkSensor():
    print("Sensor connected")

# 读取数据
finger.capRead()

# 访问数据
finger.readData.channelCapData  # 电容通道原始值
finger.readData.nf[i]           # 第i个单元的法向力
finger.readData.tf[i]           # 第i个单元的切向力
finger.readData.tfDir[i]        # 第i个单元的切向力方向
finger.readData.sProxCapData    # 自电容接近值
finger.readData.mProxCapData    # 互电容接近值
```

---

## 5. 数据采集模块

### 5.1 cap_read.py —— 基础电容读取

最简单直接的传感器数据读取入口。内部维护 CH341 连接状态机，定时轮询读取电容数据，并通过 TCP Socket 发送到 VOFA+ 等调试工具进行实时可视化。

**配置参数：**

```python
DEF_MAX_FINGER_NUM = 1   # 连接手指数量 (1-5)
DEF_GET_CAP_MS = 30      # 读取间隔 (ms)
DEF_CDC_SYNC_MS = 1000   # 电容同步间隔 (ms)，多传感器时使用
```

**运行：**

```bash
python cap_read.py
```

数据通过 Socket 发送到 `127.0.0.1:1347`（VOFA+ 默认端口）。

### 5.2 tactile_sensor_daq.py —— 多指触觉传感器 DAQ

线程安全的传感器数据采集模块，支持 3 个手指、12 维力数据输出，含去皮（tare）功能。

```python
from tactile_sensor_daq import TactileSensorDAQ

sensor = TactileSensorDAQ()
sensor.start()        # 启动后台采集线程
sensor.tare()         # 去皮：将当前读数归零
data = sensor.get_data()  # 获取 12 维 numpy 数组 [F0_U1_Fn, F0_U1_Ft, F0_U2_Fn, ...]
sensor.stop()         # 停止采集
```

**数据格式**（12 维 float32）：

| 索引 | 含义 |
|------|------|
| 0-1  | 手指0-单元1: 法向力(Fn), 切向力(Ft) |
| 2-3  | 手指0-单元2: 法向力(Fn), 切向力(Ft) |
| 4-5  | 手指1-单元1: 法向力(Fn), 切向力(Ft) |
| 6-7  | 手指1-单元2: 法向力(Fn), 切向力(Ft) |
| 8-9  | 手指2-单元1: 法向力(Fn), 切向力(Ft) |
| 10-11| 手指2-单元2: 法向力(Fn), 切向力(Ft) |

**配置参数：**

```python
DEF_MAX_FINGER_NUM = 3     # 传感器数量
SAMPLE_RATE_MS = 10        # 采样间隔 (ms)，默认 100Hz
```

---

## 6. 执行器控制

### 6.1 serial_robot_driver.py —— 串口执行器驱动

通过串口（USB-TTL）向 STM32 下位机发送 ASCII 命令，控制直线电机和舵机。

```python
from serial_robot_driver import RobotDriver

robot = RobotDriver(port='COM9', baud=115200)

# 直线电机控制
robot.motor_open()    # 张开
robot.motor_close()   # 闭合
robot.motor_stop()    # 停止

# 舵机控制
robot.set_servo(1, 90)   # 舵机1转到90度
robot.set_servo(2, 120)  # 舵机2转到120度

# 构型切换（组合动作）
robot.set_config(0)   # 初始构型: S1=90, S2=90
robot.set_config(1)   # 错位构型: S1=30, S2=150
robot.set_config(2)   # 对握构型: S1=120, S2=60

robot.close()
```

### 6.2 串口通信协议

上位机向 STM32 发送 ASCII 命令（以 `\r\n` 结尾），STM32 回复 `OK:` 或 `ERR:` 确认。

| 命令 | 功能 | 回复 |
|------|------|------|
| `PING` | 通信测试 | `OK:PONG` |
| `M:OPEN` | 直线电机张开 | `OK:M:OPEN` |
| `M:CLOSE` | 直线电机闭合 | `OK:M:CLOSE` |
| `M:STOP` | 直线电机停止 | `OK:M:STOP` |
| `S1:<angle>` | 舵机1角度(0-180) | `OK:S1` |
| `S2:<angle>` | 舵机2角度(0-180) | `OK:S2` |
| `CFG:<mode>` | 构型切换(0/1/2) | `OK:CFG` |

### 6.3 gamepad_remote_new_pcb.py —— 新 PCB 版执行器驱动

相比 `serial_robot_driver.py`，增加了 ACK 确认、命令行参数、自检等功能。

```bash
# 单条命令
python gamepad_remote_new_pcb.py --port COM9 --cmd PING
python gamepad_remote_new_pcb.py --port COM9 --cmd S1:90

# 硬件自检
python gamepad_remote_new_pcb.py --port COM9 --test

# 不等待 ACK (适用于简单固件)
python gamepad_remote_new_pcb.py --port COM9 --no-ack
```

---

## 7. 遥控模块

### 7.1 gamepad_remote.py —— 手柄遥控

使用 Xbox/兼容游戏手柄远程控制执行器。

**按键映射：**

| 按键 | 功能 |
|------|------|
| A | 构型0（初始） |
| B | 构型1（错位） |
| X | 构型2（对握） |
| LB 长按 | 直线电机张开 |
| RB 长按 | 直线电机闭合 |
| 松开 LB/RB | 电机停止 |
| BACK | 急停切换 |
| START | 退出 |

**运行：**

```bash
python gamepad_remote.py
```

默认连接 COM9，可在代码中修改 `port` 变量。

### 7.2 keyboard_remote_new_pcb.py —— 键盘遥控

使用键盘远程控制执行器，同时读取触觉传感器数据，支持力反馈自动抓取。

**按键映射：**

| 按键 | 功能 |
|------|------|
| q | 构型0（初始） |
| w | 构型1（错位） |
| e | 构型2（对握） |
| ← 长按 | 直线电机闭合 |
| → 长按 | 直线电机张开 |
| 空格 | 急停/恢复 |
| Esc | 退出 |

**主要功能：**
- 按下闭合键持续闭合，松开自动停止并打印执行时间
- 实时显示接触压力（KPa）
- 支持急停保护和构型切换

**运行：**

```bash
python keyboard_remote_new_pcb.py --port COM9
python keyboard_remote_new_pcb.py --port COM9 --test          # 自检模式
python keyboard_remote_new_pcb.py --port COM9 --contact-area-mm2 240  # 自定义接触面积
```

---

## 8. 数据记录

### data_logger.py —— CSV 数据记录器

将触觉传感器数据记录为 CSV 文件，自动创建 `data/` 目录并以时间戳命名。

```python
from data_logger import DataLogger

logger = DataLogger(filename_prefix="experiment_01")

# 记录一行数据
# sensor_data: 12维触觉数据
# config_id: 构型ID (0/1/2)
# label_vector: 标签 [x, y, theta]
logger.log(sensor_data=sensor.get_data(), config_id=1, label_vector=[0.0, 5.5, -2.0])
```

**CSV 格式：**

| Timestamp | Config_ID | F0_U1_Fn | F0_U1_Ft | ... | Label_X | Label_Y | Label_Theta |
|-----------|-----------|----------|----------|-----|---------|---------|-------------|

---

## 9. 神经网络模型

### grasp_network_model.py —— 条件抓取网络 (CondGraspNet)

一个条件 MLP 网络，输入 12 维触觉数据 + 3 维构型编码，输出 3 维偏差预测 [ΔX, ΔY, Δθ]。

**网络结构：**

```
Input(15) → FC(64)+BN+ReLU → FC(128)+BN+ReLU → FC(64)+ReLU → Output(3)
```

**使用示例：**

```python
from grasp_network_model import CondGraspNet
import torch

model = CondGraspNet()
tactile_data = torch.randn(8, 12)    # Batch=8, 12维触觉
config_ids = torch.tensor([0,0,1,1,2,2,0,2])  # 构型ID
predictions = model(tactile_data, config_ids)  # [8, 3] 输出
```

**单元测试：**

```bash
python grasp_network_model.py
```

---

## 10. STM32 固件

### stm32f103_drv8870_servo_main.c

STM32F103C8T6 下位机固件，负责接收上位机串口命令并控制硬件。

**硬件映射：**

| 功能 | STM32引脚 | 说明 |
|------|-----------|------|
| USART1 TX | PA9 | 连接 USB-TTL RXD |
| USART1 RX | PA10 | 连接 USB-TTL TXD |
| 直线电机 IN1 | PB12 | 连接 DRV8870 IN1 |
| 直线电机 IN2 | PB13 | 连接 DRV8870 IN2 |
| 舵机1 PWM | PB11 | TIM2_CH4, 50Hz |
| 舵机2 PWM | PB10 | TIM2_CH3, 50Hz |

**CubeMX 配置要点：**

- TIM2: Prescaler=71, Counter Period=19999, 产生 50Hz PWM
- USART1: 115200 8N1
- 需开启 TIM2 重映射（AFIO Remap）

**集成方法：**

将 `stm32f103_drv8870_servo_main.c` 中的用户代码集成到 CubeMX 生成的工程：

```c
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    MX_TIM2_Init();

    app_init();     // 初始化舵机和电机

    while (1) {
        app_loop(); // 主循环：处理串口命令 + 看门狗
    }
}
```

**安全特性：**

- 1 秒无指令自动停止直线电机（通信丢失保护）
- 命令超长自动拒绝

### 调试顺序

1. 仅给 PCB/STM32 上电（不接电机和舵机）
2. `python gamepad_remote_new_pcb.py --port COM9 --cmd PING` → 应返回 `OK:PONG`
3. 用示波器测舵机 PWM 信号：
   - `S1:0` → PB11 约 0.5ms 高电平
   - `S1:90` → PB11 约 1.5ms 高电平
   - `S1:180` → PB11 约 2.5ms 高电平
4. 测直线电机控制引脚：
   - `M:OPEN` → PB12=高, PB13=低
   - `M:CLOSE` → PB12=低, PB13=高
   - `M:STOP` → PB12=低, PB13=低
5. 信号确认正确后，接舵机独立 5V 电源
6. 最后接直线电机电源和负载

---

## 11. 硬件接线

### 11.1 传感器接线（CH341 USB-I2C）

传感器通过 I2C 转接板连接，转接板通过 CH341 芯片与 PC 的 USB 连接。

I2C 地址与转接板接口位置为固定对应关系，详见 `传感器iic地址和转接板位置定义.png`。

### 11.2 执行器接线（USB-TTL + STM32）

```
USB-TTL         STM32F103C8T6
  3.3V    →     3.3V
  GND     →     GND
  TXD     →     PA10 (RXD)
  RXD     →     PA9  (TXD)

STM32           外设
  PB12    →     DRV8870 IN1
  PB13    →     DRV8870 IN2
  PB11    →     舵机1 信号线 (A0绿)
  PB10    →     舵机2 信号线 (A1橙)
  GND     →     舵机 GND
  GND     →     直线电机 GND
```

详见 `接线说明.txt`。

### 11.3 供电注意事项

- MG996R 舵机不可由 STM32 板载 5V 供电，需使用独立 5V 3A 以上电源
- 舵机电源 GND、直线电机电源 GND、STM32 GND 必须共地
- DRV8870 的 VM 电压须匹配直线电机额定电压
- 直线电机首次测试建议只点动 0.5s，防止方向相反或机械顶死
- 如果 M:OPEN 和 M:CLOSE 方向相反，可在固件中交换 PB12/PB13 输出逻辑，或交换电机两线

---

## 12. 常见问题

### Q: 运行 cap_read.py 提示 "ch341加载失败"？

A: 检查 `lib/ch341/` 目录下是否有对应平台的库文件：
- Windows: `CH341DLLA64.DLL`
- Linux: `libch347.so`

并确保已安装 CH341 驱动程序。

### Q: 传感器无法连接？

A:
1. 确认传感器已上电 3 秒以上再运行程序
2. 检查 I2C 地址是否与转接板接口匹配
3. 运行后查看终端输出，程序会自动尝试匹配地址

### Q: 手柄遥控无法识别手柄？

A:
1. 确保手柄已通过蓝牙/USB 连接并被系统识别
2. Windows 下可在"控制面板→设备和打印机"中验证
3. 确保安装了 pygame 库

### Q: 串口命令无响应？

A:
1. 确认 COM 口号正确（Windows 在设备管理器中查看）
2. 确认波特率为 115200
3. 用 `--cmd PING` 测试基本通信
4. 检查 USB-TTL 的 TXD/RXD 是否交叉连接

### Q: 如何修改采样频率？

A: 修改对应文件中的配置参数：
- `cap_read.py`: `DEF_GET_CAP_MS`
- `tactile_sensor_daq.py`: `SAMPLE_RATE_MS`

### Q: 如何支持更多传感器型号？

A: 在 `sensorPara.py` 的 `finger_params` 列表中追加 `FingerParamTS` 参数定义。传感器会自动根据项目编号匹配对应参数。

---

## 项目文件结构

```
HandControl/
├── class_ch341.py              # CH341 I2C 底层驱动
├── class_sensorcmd.py           # 传感器 I2C 命令协议
├── class_finger.py              # 传感器数据解析
├── sensorPara.py                # 传感器参数定义
├── cap_read.py                  # 基础电容读取入口
├── tactile_sensor_daq.py        # 多指触觉传感器 DAQ
├── serial_robot_driver.py       # 串口执行器驱动
├── gamepad_remote.py            # 手柄遥控
├── gamepad_remote_new_pcb.py    # 新 PCB 手柄遥控
├── keyboard_remote_new_pcb.py   # 新 PCB 键盘遥控
├── demo_auto_grasp.py           # 演示：自动抓取任务
├── test_dof_control.py          # 自由度独立控制测试
├── data_logger.py               # CSV 数据记录器
├── grasp_network_model.py       # 抓取预测神经网络
├── stm32f103_drv8870_servo_main.c  # STM32 固件
├── lib/ch341/                   # CH341 驱动库
│   ├── CH341DLLA64.DLL
│   ├── CH341DLLA64.LIB
│   ├── ch341_lib.h
│   └── libch347.so
├── 接线说明.txt                  # 硬件接线参考
├── 新PCB控制实施方案.md           # 控制系统实施方案
├── 传感器iic地址和转接板位置定义.png  # I2C 地址图
└── README.md                    # 本文件
```
