# 触觉传感器与执行器控制系统 —— 使用手册 ## 项目概述 本项目提供了一套完整的触觉传感器数据采集与执行器(舵机、直线电机)控制系统,包含底层 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:` | 舵机1角度(0-180) | `OK:S1` | | `S2:` | 舵机2角度(0-180) | `OK:S2` | | `CFG:` | 构型切换(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 # 本文件 ```