You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

157 lines
7.2 KiB

# serial_handler.py
import serial
import time
from serial_init import SerialSharedData
from transform import transform_data
# 声明需要用到的全局变量(与主程序保持一致)
speed_adjustment = 100 # 初始值设为100,在50-100范围内
Trajectory_angle = 0
compensate_queue = None # 后续由主程序赋值
# 初始化全局共享数据实例
serial_shared = SerialSharedData()
# 串口接收线程函数,持续监听串口数据,解析0xFF坐标帧并更新补偿变量
def serial_receive_data(ser):
"""线程内持续接收串口数据,同步解析0xFF坐标帧并更新全局补偿变量"""
frame_header = 0xFF
frame_length = 7 # 0xFF + x(2) + y(2) + z(2)
while True:
try:
if not ser or not isinstance(ser, serial.Serial) or not ser.is_open:
time.sleep(0.1)
continue
if ser.in_waiting > 0:
data = ser.read(ser.in_waiting)
with serial_shared.lock:
serial_shared.buffer += data
serial_shared.cmd_buffer += data
# 在接收线程中解析0xFF坐标帧
with serial_shared.lock:
current_buf = serial_shared.buffer[:]
if len(current_buf) >= frame_length:
header_index = current_buf.find(bytes([frame_header]))
if header_index != -1 and header_index + frame_length <= len(current_buf):
# 提取完整帧并更新缓冲区
frame = current_buf[header_index:header_index+frame_length]
with serial_shared.lock:
serial_shared.buffer = serial_shared.buffer[header_index+frame_length:]
# 坐标解码
x_coord = (frame[1] << 8) | frame[2]
x_coord = x_coord - 0x10000 if x_coord & 0x8000 else x_coord
if x_coord>90:
x_coord = 90
elif x_coord<-90:
x_coord = -90
y_coord = (frame[3] << 8) | frame[4]
y_coord = y_coord - 0x10000 if y_coord & 0x8000 else y_coord
if y_coord>50:
y_coord = 50
elif y_coord<-50:
y_coord = -50
z_coord = (frame[5] << 8) | frame[6]
z_coord = z_coord - 0x10000 if z_coord & 0x8000 else z_coord
if z_coord>90:
z_coord = 90
elif z_coord<-90:
z_coord = -90
inc_x, inc_y, inc_z = transform_data(x_coord, y_coord, z_coord)
# 存入队列(覆盖旧值,确保取到最新)
if compensate_queue is not None and not compensate_queue.empty():
compensate_queue.get_nowait()
if compensate_queue is not None:
compensate_queue.put((inc_x, inc_y, inc_z))
print(f"接收线程解析更新 - x:{x_coord:.1f}, y:{y_coord:.1f}, z:{z_coord:.1f}")
except Exception as e:
print(f"串口接收线程错误: {str(e)}")
time.sleep(0.005)
# 从共享缓冲区读取指令帧,解析0xAA指令并返回指令内容(加锁确保线程安全)
def read_cmd_from_shared(timeout=1.0):
"""从共享缓冲区读取指令帧,解析0xAA指令并返回指令内容(加锁确保线程安全)"""
frame_header = 0xAA
cmd_length = 2 # 指令帧结构:0xAA(帧头) + 1字节指令值
start_time = time.time()
while (time.time() - start_time) < timeout:
# 加锁读取指令缓冲区
with serial_shared.lock:
current_cmd_buf = serial_shared.cmd_buffer[:]
if len(current_cmd_buf) >= cmd_length:
header_index = current_cmd_buf.find(bytes([frame_header]))
if header_index != -1:
# 提取完整指令帧
cmd_bytes = current_cmd_buf[header_index:header_index+cmd_length]
# 更新共享缓冲区(移除已处理指令)
with serial_shared.lock:
serial_shared.cmd_buffer = serial_shared.cmd_buffer[header_index+cmd_length:]
return cmd_bytes
time.sleep(0.01)
return None
# 处理特殊指令0xBB,更新全局参数并打印清晰信息
def handle_special_commands(PRESET_PARAMS):
global speed_adjustment, Trajectory_angle
bb_header = 0xBB
bb_frame_length = 2 # 0xBB + 1字节配置选择值(0-11)
# 初始化返回值(默认无选中配置)
selected_delay_map = None
selected_relay_config = None
# 加锁读取缓冲区,避免线程冲突
with serial_shared.lock:
current_cmd_buf = serial_shared.cmd_buffer[:]
# 处理0xBB指令(参数配置选择)
bb_index = current_cmd_buf.find(bytes([bb_header]))
if bb_index != -1 and bb_index + bb_frame_length <= len(current_cmd_buf):
# 提取完整的0xBB帧
bb_frame = current_cmd_buf[bb_index:bb_index+bb_frame_length]
# 解析配置选择值(1-12有效,对应PRESET_PARAMS的0-11索引)
config_select = bb_frame[1]
# 校验配置值范围(仅处理1-12,共12组)
if 1 <= config_select <= len(PRESET_PARAMS):
# 匹配预设参数项(索引 = 配置值 - 1)
selected_preset = PRESET_PARAMS[config_select - 1]
# 提取params并更新全局变量
speed_val, angle_val = selected_preset["params"]
if speed_val < 50:
speed_val = 50
if speed_val > 150:
speed_val = 150
if angle_val > 200:
angle_val = 200
speed_adjustment = speed_val
Trajectory_angle = angle_val
# 提取当前配置项对应的delay和relay配置(赋值给返回变量)
selected_delay_map = selected_preset["program_delay_map"]
selected_relay_config = selected_preset["relay_config"]
# 打印清晰的配置信息
print(f"=== 0xBB指令处理成功 ===")
print(f"配置选择值:{config_select}")
print(f"speed_adjustment: {speed_adjustment}%")
print(f"Trajectory_angle: {Trajectory_angle}")
print(f"已加载对应program_delay_map和relay_config配置")
# 移除已处理的帧(加锁更新缓冲区)
with serial_shared.lock:
serial_shared.cmd_buffer = serial_shared.cmd_buffer[bb_index+bb_frame_length:]
else:
# 无效配置值处理:清理帧但不更新参数
with serial_shared.lock:
serial_shared.cmd_buffer = serial_shared.cmd_buffer[bb_index+bb_frame_length:]
print(f"⚠️ 收到0xBB指令,配置选择值{config_select}无效(仅支持1-{len(PRESET_PARAMS)}")
# 返回选中的delay配置和relay配置(无选中则返回None)
return selected_delay_map, selected_relay_config