#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 激光管理器模块 提供激光控制、校准等功能 """ import json import os from maix import time, camera import threading import config from logger_manager import logger_manager class LaserManager: """激光控制管理器(单例)""" _instance = None def __new__(cls): if cls._instance is None: cls._instance = super(LaserManager, cls).__new__(cls) cls._instance._initialized = False return cls._instance def __init__(self): if self._initialized: return # 私有状态 self._calibration_active = False self._calibration_result = None self._calibration_lock = threading.Lock() self._laser_point = None self._initialized = True # ==================== 状态访问(只读属性)==================== @property def calibration_active(self): """是否正在校准""" return self._calibration_active @property def laser_point(self): """当前激光点""" return self._laser_point # ==================== 业务方法 ==================== def load_laser_point(self): """从配置文件加载激光中心点,失败则使用默认值""" try: if "laser_config.json" in os.listdir("/root"): with open(config.CONFIG_FILE, "r") as f: data = json.load(f) if isinstance(data, list) and len(data) == 2: self._laser_point = (int(data[0]), int(data[1])) logger = logger_manager.logger if logger: logger.debug(f"[INFO] 加载激光点: {self._laser_point}") return self._laser_point else: raise ValueError else: self._laser_point = config.DEFAULT_LASER_POINT except: self._laser_point = config.DEFAULT_LASER_POINT return self._laser_point def save_laser_point(self, point): """保存激光中心点到配置文件""" try: with open(config.CONFIG_FILE, "w") as f: json.dump([point[0], point[1]], f) self._laser_point = point return True except Exception as e: logger = logger_manager.logger if logger: logger.error(f"[LASER] 保存激光点失败: {e}") return False def turn_on_laser(self): """发送指令开启激光,并读取回包(部分模块支持)""" from hardware import hardware_manager logger = logger_manager.logger if hardware_manager.distance_serial is None: if logger: logger.error("[LASER] distance_serial 未初始化") return None # 打印调试信息 if logger: logger.info(f"[LASER] 发送开启命令: {config.LASER_ON_CMD.hex()}") # 清空接收缓冲区 try: hardware_manager.distance_serial.read(-1) # 清空缓冲区 except: pass # 发送命令 written = hardware_manager.distance_serial.write(config.LASER_ON_CMD) if logger: logger.info(f"[LASER] 写入字节数: {written}") time.sleep_ms(50) # 增加等待时间,让模块有时间响应 # 读取回包 resp = hardware_manager.distance_serial.read(20) if resp: if logger: logger.info(f"[LASER] 收到回包 ({len(resp)}字节): {resp.hex()}") if resp == config.LASER_ON_CMD: if logger: logger.info("✅ 激光开启指令已确认") else: if logger: logger.warning("🔇 无回包(可能正常或模块不支持回包)") return resp def turn_off_laser(self): """发送指令关闭激光""" from hardware import hardware_manager logger = logger_manager.logger if hardware_manager.distance_serial is None: if logger: logger.error("[LASER] distance_serial 未初始化") return None # 打印调试信息 if logger: logger.info(f"[LASER] 发送关闭命令: {config.LASER_OFF_CMD.hex()}") # 清空接收缓冲区 try: hardware_manager.distance_serial.read(-1) except: pass # 发送命令 written = hardware_manager.distance_serial.write(config.LASER_OFF_CMD) if logger: logger.info(f"[LASER] 写入字节数: {written}") time.sleep_ms(50) # 增加等待时间 # 读取回包 resp = hardware_manager.distance_serial.read(20) if resp: if logger: logger.info(f"[LASER] 收到回包 ({len(resp)}字节): {resp.hex()}") else: if logger: logger.warning("🔇 无回包") return resp def flash_laser(self, duration_ms=1000): """闪一下激光(用于射箭反馈)""" try: self.turn_on_laser() time.sleep_ms(duration_ms) self.turn_off_laser() except Exception as e: logger = logger_manager.logger if logger: logger.error(f"闪激光失败: {e}") def find_red_laser(self, frame, threshold=150): """在图像中查找最亮的红色激光点(基于 RGB 阈值)""" w, h = frame.width(), frame.height() img_bytes = frame.to_bytes() max_sum = 0 best_pos = None for y in range(0, h, 2): for x in range(0, w, 2): idx = (y * w + x) * 3 r, g, b = img_bytes[idx], img_bytes[idx+1], img_bytes[idx+2] if r > threshold and r > g * 2 and r > b * 2: rgb_sum = r + g + b if rgb_sum > max_sum: max_sum = rgb_sum best_pos = (x, y) return best_pos def calibrate_laser_position(self): """执行一次激光校准:拍照 → 找红点 → 保存坐标""" time.sleep_ms(80) cam = camera.Camera(640, 480) frame = cam.read() pos = self.find_red_laser(frame) if pos: self.save_laser_point(pos) return pos return None def start_calibration(self): """开始校准(公共方法)""" with self._calibration_lock: if self._calibration_active: return False self._calibration_active = True self._calibration_result = None return True def stop_calibration(self): """停止校准(公共方法)""" with self._calibration_lock: self._calibration_active = False def set_calibration_result(self, result): """设置校准结果(内部方法)""" with self._calibration_lock: self._calibration_result = result def get_calibration_result(self): """获取并清除校准结果(内部方法)""" with self._calibration_lock: result = self._calibration_result self._calibration_result = None return result # 创建全局单例实例 laser_manager = LaserManager() # ==================== 向后兼容的函数接口 ==================== def load_laser_point(): """加载激光点(向后兼容接口)""" return laser_manager.load_laser_point() def save_laser_point(point): """保存激光点(向后兼容接口)""" return laser_manager.save_laser_point(point) def turn_on_laser(): """开启激光(向后兼容接口)""" return laser_manager.turn_on_laser() def turn_off_laser(): """关闭激光(向后兼容接口)""" return laser_manager.turn_off_laser() def flash_laser(duration_ms=1000): """闪激光(向后兼容接口)""" return laser_manager.flash_laser(duration_ms) def find_red_laser(frame, threshold=150): """查找红色激光点(向后兼容接口)""" return laser_manager.find_red_laser(frame, threshold) def calibrate_laser_position(): """校准激光位置(向后兼容接口)""" return laser_manager.calibrate_laser_position()