init repo

This commit is contained in:
Brunsmeier
2026-07-16 14:56:43 +08:00
commit 111c9bab8a
25 changed files with 4289 additions and 0 deletions

717
README.md Normal file
View File

@ -0,0 +1,717 @@
# 触觉传感器与执行器控制系统 —— 使用手册
## 项目概述
本项目提供了一套完整的触觉传感器数据采集与执行器(舵机、直线电机)控制系统,包含底层 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 # 本文件
```