init repo
This commit is contained in:
228
tactile_sensor_daq.py
Normal file
228
tactile_sensor_daq.py
Normal file
@ -0,0 +1,228 @@
|
||||
import threading
|
||||
import time
|
||||
import numpy as np
|
||||
from enum import Enum
|
||||
# 导入官方例程的底层依赖
|
||||
from class_ch341 import *
|
||||
from class_sensorcmd import *
|
||||
from class_finger import *
|
||||
|
||||
# === 配置区域 ===
|
||||
DEF_MAX_FINGER_NUM = 3 # 修改为 3 个传感器 (Finger 0, 1, 2)
|
||||
PCA_ADDR = 0x70 # I2C 多路复用器地址
|
||||
SAMPLE_RATE_MS = 10 # 采样间隔 (ms),10ms = 100Hz
|
||||
|
||||
|
||||
class EnumCh341ConnectStatus(Enum):
|
||||
CH341_CONNECT_INIT = 0
|
||||
CH341_CONNECT_OPEN = 1
|
||||
CH341_CONNECT_SET_SPEED = 2
|
||||
CH341_CONNECT_SAMPLE_START = 3
|
||||
CH341_CONNECT_CHECK = 4
|
||||
CH341_CONNECT_SAMPLE_STOP = 5
|
||||
|
||||
|
||||
class TactileSensorDAQ:
|
||||
def __init__(self):
|
||||
# 1. 硬件初始化
|
||||
self.ch341 = ClassCh341()
|
||||
self.fingers = list()
|
||||
# 初始化3个传感器对象,ID从2开始 (假设硬件拨码是 2,3,4)
|
||||
for i in range(DEF_MAX_FINGER_NUM):
|
||||
self.fingers.append(ClassFinger(4 + i, self.ch341))
|
||||
|
||||
# 2. 状态机变量
|
||||
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_INIT
|
||||
self.ch341CheckTimer = 0
|
||||
self.pcaAddr = PCA_ADDR
|
||||
self.syncTimer = 0
|
||||
|
||||
# 3. 数据容器 (核心修改)
|
||||
# 12维数据: [F0_U1_Fn, F0_U1_Ft, F0_U2_Fn, F0_U2_Ft, F1..., F2...]
|
||||
self.raw_data = np.zeros(12, dtype=np.float32) # 实时读取值
|
||||
self.offset = np.zeros(12, dtype=np.float32) # 去皮偏移量
|
||||
self.clean_data = np.zeros(12, dtype=np.float32) # 输出值 (Raw - Offset)
|
||||
|
||||
# 4. 线程控制
|
||||
self.running = False
|
||||
self.lock = threading.Lock() # 线程锁,保证读取安全
|
||||
self.thread = None
|
||||
|
||||
def _set_sensor_enable(self, idx):
|
||||
"""控制 I2C 多路复用器通道"""
|
||||
_pack = list()
|
||||
_pack.append(idx)
|
||||
self.ch341.write(self.pcaAddr, _pack)
|
||||
|
||||
def _update_state_machine(self):
|
||||
"""维持 CH341 连接状态机 (原 logic 的简化版)"""
|
||||
if self.connectStatus == EnumCh341ConnectStatus.CH341_CONNECT_INIT:
|
||||
if self.ch341.init():
|
||||
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_OPEN
|
||||
|
||||
elif self.connectStatus == EnumCh341ConnectStatus.CH341_CONNECT_OPEN:
|
||||
if self.ch341.open():
|
||||
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_SET_SPEED
|
||||
else:
|
||||
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_INIT
|
||||
|
||||
elif self.connectStatus == EnumCh341ConnectStatus.CH341_CONNECT_SET_SPEED:
|
||||
if self.ch341.set_speed(self.ch341.IIC_SPEED_400):
|
||||
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_SAMPLE_START
|
||||
else:
|
||||
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_SAMPLE_START # Retry
|
||||
|
||||
elif self.connectStatus == EnumCh341ConnectStatus.CH341_CONNECT_SAMPLE_START:
|
||||
# 连接建立成功,进入读取循环
|
||||
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_CHECK
|
||||
|
||||
elif self.connectStatus == EnumCh341ConnectStatus.CH341_CONNECT_CHECK:
|
||||
# 这里的检查逻辑放入主循环中执行
|
||||
pass
|
||||
|
||||
def _read_hardware(self):
|
||||
"""读取所有传感器数据的核心函数"""
|
||||
connectedSensorChan = 0
|
||||
|
||||
# 临时列表存储本轮读取的数据
|
||||
temp_data_buffer = []
|
||||
|
||||
for fingerIndex in range(len(self.fingers)):
|
||||
# 1. 切通道
|
||||
self._set_sensor_enable(1 << (self.fingers[fingerIndex].pcaIdx))
|
||||
connectedSensorChan |= 1 << (self.fingers[fingerIndex].pcaIdx)
|
||||
|
||||
current_finger = self.fingers[fingerIndex]
|
||||
|
||||
# 2. 检查连接与读取
|
||||
if not current_finger.connect:
|
||||
if current_finger.checkSensor():
|
||||
print(f"[System] Finger {fingerIndex} Connected!")
|
||||
else:
|
||||
current_finger.capRead()
|
||||
|
||||
# 3. 提取数据 (这是修改的关键!)
|
||||
# 假设每个传感器有 ydds_num (通常是2) 个单元
|
||||
# 这里的 nf 和 tf 应该是数组
|
||||
for unit_i in range(current_finger.projectPara.ydds_num):
|
||||
# 提取法向力 Fn
|
||||
fn = current_finger.readData.nf[unit_i]
|
||||
# 提取切向力 Ft
|
||||
ft = current_finger.readData.tf[unit_i]
|
||||
|
||||
temp_data_buffer.append(fn)
|
||||
temp_data_buffer.append(ft)
|
||||
|
||||
# 4. 更新共享内存
|
||||
if len(temp_data_buffer) == 12: # 确保数据完整
|
||||
with self.lock:
|
||||
self.raw_data = np.array(temp_data_buffer, dtype=np.float32)
|
||||
# 计算去皮后的数据
|
||||
self.clean_data = self.raw_data - self.offset
|
||||
# 简单滤波:置零负值噪声
|
||||
# self.clean_data[self.clean_data < 0] = 0
|
||||
|
||||
# 5. 同步逻辑 (保持原厂逻辑,防止电容漂移)
|
||||
if (time.time() - self.syncTimer) > 1.0: # 1秒同步一次
|
||||
self.syncTimer = time.time()
|
||||
self._set_sensor_enable(connectedSensorChan)
|
||||
for f in self.fingers:
|
||||
if f.connect:
|
||||
f.snsCmd.setSensorSync(0)
|
||||
break
|
||||
|
||||
def _thread_worker(self):
|
||||
"""后台线程主循环"""
|
||||
while self.running:
|
||||
# 1. 维护连接
|
||||
if self.connectStatus != EnumCh341ConnectStatus.CH341_CONNECT_CHECK:
|
||||
self._update_state_machine()
|
||||
time.sleep(0.1)
|
||||
continue
|
||||
|
||||
# 2. 读取数据
|
||||
start_time = time.time()
|
||||
try:
|
||||
self._read_hardware()
|
||||
except Exception as e:
|
||||
print(f"Read Error: {e}")
|
||||
|
||||
# 3. 检查连接心跳 (保持原厂逻辑)
|
||||
self.ch341CheckTimer += (time.time() - start_time) * 1000
|
||||
if self.ch341CheckTimer >= 1000:
|
||||
self.ch341CheckTimer = 0
|
||||
if not self.ch341.connectCheck():
|
||||
print("CH341 Disconnected!")
|
||||
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_INIT
|
||||
|
||||
# 4. 控制采样率
|
||||
elapsed = (time.time() - start_time) * 1000
|
||||
sleep_time = (SAMPLE_RATE_MS - elapsed) / 1000.0
|
||||
if sleep_time > 0:
|
||||
time.sleep(sleep_time)
|
||||
|
||||
# === 用户API ===
|
||||
|
||||
def start(self):
|
||||
"""启动采集"""
|
||||
if self.running: return
|
||||
self.running = True
|
||||
self.thread = threading.Thread(target=self._thread_worker)
|
||||
self.thread.daemon = True
|
||||
self.thread.start()
|
||||
print("Tactile Sensor System Started.")
|
||||
|
||||
def stop(self):
|
||||
"""停止采集"""
|
||||
self.running = False
|
||||
if self.thread:
|
||||
self.thread.join()
|
||||
self.ch341.disconnect()
|
||||
print("Tactile Sensor System Stopped.")
|
||||
|
||||
def tare(self):
|
||||
"""去皮:将当前读数设为零点"""
|
||||
print("Taring sensors... please wait.")
|
||||
time.sleep(1) # 等待数据稳定
|
||||
with self.lock:
|
||||
self.offset = np.copy(self.raw_data)
|
||||
print("Tare complete.")
|
||||
|
||||
def get_data(self):
|
||||
"""获取最新的12维力数据"""
|
||||
with self.lock:
|
||||
return np.copy(self.clean_data)
|
||||
|
||||
|
||||
# === 调试代码 (直接运行此文件测试) ===
|
||||
if __name__ == "__main__":
|
||||
sensor = TactileSensorDAQ()
|
||||
sensor.start()
|
||||
|
||||
try:
|
||||
# 等待连接稳定
|
||||
print("Waiting for sensors to connect...")
|
||||
time.sleep(3)
|
||||
|
||||
sensor.tare() # 初始去皮
|
||||
|
||||
while True:
|
||||
data = sensor.get_data()
|
||||
log_str = ""
|
||||
for i in range(3): # 遍历 3 个手指
|
||||
base_idx = i * 4
|
||||
# 为了显示简洁,我们将 Unit1 和 Unit2 的 Fn 相加,作为一个总压力显示
|
||||
# 你也可以根据需要显示全部细节
|
||||
f_n_total = data[base_idx] + data[base_idx + 2]
|
||||
f_t_total = data[base_idx + 1] + data[base_idx + 3]
|
||||
|
||||
log_str += f"F{i}: N={f_n_total:.1f} T={f_t_total:.1f} | "
|
||||
|
||||
print(log_str)
|
||||
# === 修改结束 ===
|
||||
|
||||
|
||||
time.sleep(0.1) # 打印频率
|
||||
|
||||
except KeyboardInterrupt:
|
||||
sensor.stop()
|
||||
Reference in New Issue
Block a user