244 lines
8.1 KiB
Python
244 lines
8.1 KiB
Python
|
|
import time
|
|||
|
|
from pymodbus.client import ModbusTcpClient
|
|||
|
|
from pymodbus.pdu import ExceptionResponse
|
|||
|
|
|
|||
|
|
# 定义 Modbus TCP 相关参数
|
|||
|
|
MODBUS_IP = "192.168.11.210"
|
|||
|
|
MODBUS_PORT = 6000
|
|||
|
|
|
|||
|
|
# 定义各部分数据地址范围
|
|||
|
|
TOUCH_SENSOR_BASE_ADDR_PINKY = 3000 # 小拇指
|
|||
|
|
TOUCH_SENSOR_END_ADDR_PINKY = 3369
|
|||
|
|
|
|||
|
|
TOUCH_SENSOR_BASE_ADDR_RING = 3370 # 无名指
|
|||
|
|
TOUCH_SENSOR_END_ADDR_RING = 3739
|
|||
|
|
|
|||
|
|
TOUCH_SENSOR_BASE_ADDR_MIDDLE = 3740 # 中指
|
|||
|
|
TOUCH_SENSOR_END_ADDR_MIDDLE = 4109
|
|||
|
|
|
|||
|
|
TOUCH_SENSOR_BASE_ADDR_INDEX = 4110 # 食指
|
|||
|
|
TOUCH_SENSOR_END_ADDR_INDEX = 4479
|
|||
|
|
|
|||
|
|
TOUCH_SENSOR_BASE_ADDR_THUMB = 4480 # 大拇指
|
|||
|
|
TOUCH_SENSOR_END_ADDR_THUMB = 4899
|
|||
|
|
|
|||
|
|
TOUCH_SENSOR_BASE_ADDR_PALM = 4900 # 掌心
|
|||
|
|
TOUCH_SENSOR_END_ADDR_PALM = 5123
|
|||
|
|
|
|||
|
|
# Modbus 每次最多读取寄存器的数量
|
|||
|
|
MAX_REGISTERS_PER_READ = 125
|
|||
|
|
|
|||
|
|
|
|||
|
|
def read_register_range(client, start_addr, end_addr):
|
|||
|
|
"""
|
|||
|
|
批量读取指定地址范围内的寄存器数据。
|
|||
|
|
"""
|
|||
|
|
register_values = []
|
|||
|
|
# 分段读取寄存器
|
|||
|
|
for addr in range(start_addr, end_addr + 1, MAX_REGISTERS_PER_READ * 2):
|
|||
|
|
current_count = min(MAX_REGISTERS_PER_READ, (end_addr - addr) // 2 + 1)
|
|||
|
|
response = client.read_holding_registers(address=addr, count=current_count)
|
|||
|
|
|
|||
|
|
if isinstance(response, ExceptionResponse) or response.isError():
|
|||
|
|
print(f"读取寄存器 {addr} 失败: {response}")
|
|||
|
|
register_values.extend([0] * current_count)
|
|||
|
|
else:
|
|||
|
|
register_values.extend(response.registers)
|
|||
|
|
|
|||
|
|
return register_values
|
|||
|
|
|
|||
|
|
def format_finger_data(finger_name, data):
|
|||
|
|
"""
|
|||
|
|
格式化四指触觉数据。
|
|||
|
|
"""
|
|||
|
|
result = {}
|
|||
|
|
|
|||
|
|
if finger_name != "大拇指":
|
|||
|
|
# 四指格式
|
|||
|
|
if len(data) < 185:
|
|||
|
|
print(f"{finger_name} 数据长度不足,至少185个数据,实际:{len(data)}")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
idx = 0
|
|||
|
|
# 指端数据 3x3
|
|||
|
|
result['tip_end'] = [data[idx + i*3: idx + (i+1)*3] for i in range(3)]
|
|||
|
|
idx += 9
|
|||
|
|
|
|||
|
|
# 指尖触觉数据 12x8
|
|||
|
|
result['tip_touch'] = [data[idx + i*8: idx + (i+1)*8] for i in range(12)]
|
|||
|
|
idx += 96
|
|||
|
|
|
|||
|
|
# 指腹触觉数据 10x8
|
|||
|
|
result['finger_pad'] = [data[idx + i*8: idx + (i+1)*8] for i in range(10)]
|
|||
|
|
idx += 80
|
|||
|
|
else:
|
|||
|
|
# 大拇指格式
|
|||
|
|
if len(data) < 210:
|
|||
|
|
print(f"{finger_name} 数据长度不足,至少210个数据,实际:{len(data)}")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
idx = 0
|
|||
|
|
# 指端数据 3x3
|
|||
|
|
result['tip_end'] = [data[idx + i*3: idx + (i+1)*3] for i in range(3)]
|
|||
|
|
idx += 9
|
|||
|
|
|
|||
|
|
# 指尖触觉数据 12x8
|
|||
|
|
result['tip_touch'] = [data[idx + i*8: idx + (i+1)*8] for i in range(12)]
|
|||
|
|
idx += 96
|
|||
|
|
|
|||
|
|
# 指中触觉数据 3x3
|
|||
|
|
result['middle_touch'] = [data[idx + i*3: idx + (i+1)*3] for i in range(3)]
|
|||
|
|
idx += 9
|
|||
|
|
|
|||
|
|
# 指腹触觉数据 12x8
|
|||
|
|
finger_pad = [data[idx + i*8: idx + (i+1)*8] for i in range(12)]
|
|||
|
|
idx += 96
|
|||
|
|
|
|||
|
|
# 指腹触觉数据行元素反转
|
|||
|
|
# finger_pad = [row[::-1] for row in finger_pad]
|
|||
|
|
# 指腹触觉数据行顺序反转
|
|||
|
|
#finger_pad.reverse()
|
|||
|
|
|
|||
|
|
result['finger_pad'] = finger_pad
|
|||
|
|
|
|||
|
|
return result
|
|||
|
|
|
|||
|
|
def format_palm_data(data):
|
|||
|
|
"""
|
|||
|
|
格式化掌心数据为14x8矩阵,然后转置为8x14矩阵。
|
|||
|
|
"""
|
|||
|
|
expected_len = 14 * 8
|
|||
|
|
if len(data) < expected_len:
|
|||
|
|
print(f"掌心数据长度不足,至少{expected_len}个数据,实际:{len(data)}")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
# 生成原始矩阵(14行8列)
|
|||
|
|
palm_matrix = [data[i*8:(i+1)*8] for i in range(14)]
|
|||
|
|
|
|||
|
|
# 转置矩阵
|
|||
|
|
transposed = list(map(list, zip(*palm_matrix)))
|
|||
|
|
|
|||
|
|
return transposed
|
|||
|
|
|
|||
|
|
|
|||
|
|
def print_formatted_finger_data(finger_name, formatted_data):
|
|||
|
|
if formatted_data is None:
|
|||
|
|
print(f"{finger_name} 数据格式化失败")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
print(f"--- {finger_name} 指端指端数据 (3x3) ---")
|
|||
|
|
for row in formatted_data.get('tip_end', []):
|
|||
|
|
print(row)
|
|||
|
|
|
|||
|
|
print(f"--- {finger_name} 指尖触觉数据 (12x8) ---")
|
|||
|
|
for row in formatted_data.get('tip_touch', []):
|
|||
|
|
print(row)
|
|||
|
|
|
|||
|
|
if finger_name == "大拇指":
|
|||
|
|
if 'middle_touch' in formatted_data:
|
|||
|
|
print(f"--- {finger_name} 指中触觉数据 (3x3) ---")
|
|||
|
|
for row in formatted_data['middle_touch']:
|
|||
|
|
print(row)
|
|||
|
|
else:
|
|||
|
|
print(f"{finger_name} 指中触觉数据缺失")
|
|||
|
|
|
|||
|
|
print(f"--- {finger_name} 指腹触觉数据 ({'12x8' if finger_name == '大拇指' else '10x8'}) ---")
|
|||
|
|
for row in formatted_data.get('finger_pad', []):
|
|||
|
|
print(row)
|
|||
|
|
|
|||
|
|
def print_formatted_palm_data(palm_data):
|
|||
|
|
if palm_data is None:
|
|||
|
|
print("掌心数据格式化失败")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
print("--- 掌心数据 (8x14) ---")
|
|||
|
|
for row in palm_data:
|
|||
|
|
print(row)
|
|||
|
|
|
|||
|
|
def read_firmware_version(client):
|
|||
|
|
"""
|
|||
|
|
读取固件版本,返回十六进制字符串 地址14
|
|||
|
|
"""
|
|||
|
|
response = client.read_holding_registers(address=14, count=1)
|
|||
|
|
if isinstance(response, ExceptionResponse) or response.isError():
|
|||
|
|
print(f"读取固件版本失败:{response}")
|
|||
|
|
return None
|
|||
|
|
else:
|
|||
|
|
reg_value = response.registers[0]
|
|||
|
|
# 转换为16进制字符串
|
|||
|
|
hex_str = format(reg_value, '04X') # 4位,补零
|
|||
|
|
return hex_str
|
|||
|
|
|
|||
|
|
def read_multiple_registers():
|
|||
|
|
client = ModbusTcpClient(MODBUS_IP, port=MODBUS_PORT)
|
|||
|
|
client.connect()
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
while True:
|
|||
|
|
start_time = time.time()
|
|||
|
|
|
|||
|
|
# 读取各部分数据
|
|||
|
|
pinky_register_values = read_register_range(
|
|||
|
|
client,
|
|||
|
|
TOUCH_SENSOR_BASE_ADDR_PINKY,
|
|||
|
|
TOUCH_SENSOR_END_ADDR_PINKY
|
|||
|
|
)
|
|||
|
|
ring_register_values = read_register_range(
|
|||
|
|
client,
|
|||
|
|
TOUCH_SENSOR_BASE_ADDR_RING,
|
|||
|
|
TOUCH_SENSOR_END_ADDR_RING
|
|||
|
|
)
|
|||
|
|
middle_register_values = read_register_range(
|
|||
|
|
client,
|
|||
|
|
TOUCH_SENSOR_BASE_ADDR_MIDDLE,
|
|||
|
|
TOUCH_SENSOR_END_ADDR_MIDDLE
|
|||
|
|
)
|
|||
|
|
index_register_values = read_register_range(
|
|||
|
|
client,
|
|||
|
|
TOUCH_SENSOR_BASE_ADDR_INDEX,
|
|||
|
|
TOUCH_SENSOR_END_ADDR_INDEX
|
|||
|
|
)
|
|||
|
|
thumb_register_values = read_register_range(
|
|||
|
|
client,
|
|||
|
|
TOUCH_SENSOR_BASE_ADDR_THUMB,
|
|||
|
|
TOUCH_SENSOR_END_ADDR_THUMB
|
|||
|
|
)
|
|||
|
|
palm_register_values = read_register_range(
|
|||
|
|
client,
|
|||
|
|
TOUCH_SENSOR_BASE_ADDR_PALM,
|
|||
|
|
TOUCH_SENSOR_END_ADDR_PALM
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
end_time = time.time()
|
|||
|
|
frequency = 1 / (end_time - start_time) if end_time > start_time else float('inf')
|
|||
|
|
|
|||
|
|
# 格式化数据
|
|||
|
|
pinky_formatted = format_finger_data("小拇指", pinky_register_values)
|
|||
|
|
ring_formatted = format_finger_data("无名指", ring_register_values)
|
|||
|
|
middle_formatted = format_finger_data("中指", middle_register_values)
|
|||
|
|
index_formatted = format_finger_data("食指", index_register_values)
|
|||
|
|
thumb_formatted = format_finger_data("大拇指", thumb_register_values)
|
|||
|
|
palm_formatted = format_palm_data(palm_register_values)
|
|||
|
|
|
|||
|
|
# 打印格式化数据
|
|||
|
|
print_formatted_finger_data("小拇指", pinky_formatted)
|
|||
|
|
print_formatted_finger_data("无名指", ring_formatted)
|
|||
|
|
print_formatted_finger_data("中指", middle_formatted)
|
|||
|
|
print_formatted_finger_data("食指", index_formatted)
|
|||
|
|
print_formatted_finger_data("大拇指", thumb_formatted)
|
|||
|
|
print_formatted_palm_data(palm_formatted)
|
|||
|
|
|
|||
|
|
print(f"读取频率:{frequency:.2f} Hz")
|
|||
|
|
print("\n" + "="*40 + "\n")
|
|||
|
|
|
|||
|
|
firmware_version_int = read_firmware_version(client)
|
|||
|
|
if firmware_version_int is not None:
|
|||
|
|
print(f"固件版本:{firmware_version_int}")
|
|||
|
|
|
|||
|
|
finally:
|
|||
|
|
client.close()
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
read_multiple_registers()
|