update distance estismate by laser, both distance value are uploaded
This commit is contained in:
14
app.yaml
14
app.yaml
@@ -1,8 +1,20 @@
|
|||||||
id: t11
|
id: t11
|
||||||
name: t11
|
name: t11
|
||||||
version: 1.0.3
|
version: 1.1.1
|
||||||
author: t11
|
author: t11
|
||||||
icon: ''
|
icon: ''
|
||||||
desc: t11
|
desc: t11
|
||||||
files:
|
files:
|
||||||
|
- app.yaml
|
||||||
|
- at_client.py
|
||||||
|
- config.py
|
||||||
|
- hardware.py
|
||||||
|
- laser_manager.py
|
||||||
|
- logger_manager.py
|
||||||
- main.py
|
- main.py
|
||||||
|
- network.py
|
||||||
|
- ota_manager.py
|
||||||
|
- power.py
|
||||||
|
- time_sync.py
|
||||||
|
- version.py
|
||||||
|
- vision.py
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ ADC_LASER_THRESHOLD = 3000
|
|||||||
MODULE_ADDR = 0x00
|
MODULE_ADDR = 0x00
|
||||||
LASER_ON_CMD = bytes([0xAA, MODULE_ADDR, 0x01, 0xBE, 0x00, 0x01, 0x00, 0x01, 0xC1])
|
LASER_ON_CMD = bytes([0xAA, MODULE_ADDR, 0x01, 0xBE, 0x00, 0x01, 0x00, 0x01, 0xC1])
|
||||||
LASER_OFF_CMD = bytes([0xAA, MODULE_ADDR, 0x01, 0xBE, 0x00, 0x01, 0x00, 0x00, 0xC0])
|
LASER_OFF_CMD = bytes([0xAA, MODULE_ADDR, 0x01, 0xBE, 0x00, 0x01, 0x00, 0x00, 0xC0])
|
||||||
|
DISTANCE_QUERY_CMD = bytes([0xAA, MODULE_ADDR, 0x00, 0x20, 0x00, 0x01, 0x00, 0x00, 0x21]) # 激光测距查询命令
|
||||||
|
DISTANCE_RESPONSE_LEN = 13 # 激光测距响应数据长度(字节)
|
||||||
DEFAULT_LASER_POINT = (640, 480) # 默认激光中心点
|
DEFAULT_LASER_POINT = (640, 480) # 默认激光中心点
|
||||||
|
|
||||||
# ==================== 视觉检测配置 ====================
|
# ==================== 视觉检测配置 ====================
|
||||||
|
|||||||
179
laser_manager.py
179
laser_manager.py
@@ -6,6 +6,7 @@
|
|||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import binascii
|
||||||
from maix import time, camera
|
from maix import time, camera
|
||||||
import threading
|
import threading
|
||||||
import config
|
import config
|
||||||
@@ -31,7 +32,7 @@ class LaserManager:
|
|||||||
self._calibration_result = None
|
self._calibration_result = None
|
||||||
self._calibration_lock = threading.Lock()
|
self._calibration_lock = threading.Lock()
|
||||||
self._laser_point = None
|
self._laser_point = None
|
||||||
|
self._laser_turned_on = False
|
||||||
self._initialized = True
|
self._initialized = True
|
||||||
|
|
||||||
# ==================== 状态访问(只读属性)====================
|
# ==================== 状态访问(只读属性)====================
|
||||||
@@ -107,20 +108,23 @@ class LaserManager:
|
|||||||
if logger:
|
if logger:
|
||||||
logger.info(f"[LASER] 写入字节数: {written}")
|
logger.info(f"[LASER] 写入字节数: {written}")
|
||||||
|
|
||||||
time.sleep_ms(50) # 增加等待时间,让模块有时间响应
|
return None
|
||||||
|
|
||||||
|
# TODO: 暂时去掉这个等待
|
||||||
# 读取回包
|
# 读取回包
|
||||||
resp = hardware_manager.distance_serial.read(20)
|
# print("before read:", time.ticks_ms())
|
||||||
if resp:
|
# resp = hardware_manager.distance_serial.read(len=20,timeout=10)
|
||||||
if logger:
|
# print("after read:", time.ticks_ms())
|
||||||
logger.info(f"[LASER] 收到回包 ({len(resp)}字节): {resp.hex()}")
|
# if resp:
|
||||||
if resp == config.LASER_ON_CMD:
|
# if logger:
|
||||||
if logger:
|
# logger.info(f"[LASER] 收到回包 ({len(resp)}字节): {resp.hex()}")
|
||||||
logger.info("✅ 激光开启指令已确认")
|
# if resp == config.LASER_ON_CMD:
|
||||||
else:
|
# if logger:
|
||||||
if logger:
|
# logger.info("✅ 激光开启指令已确认")
|
||||||
logger.warning("🔇 无回包(可能正常或模块不支持回包)")
|
# else:
|
||||||
return resp
|
# if logger:
|
||||||
|
# logger.warning("🔇 无回包(可能正常或模块不支持回包)")
|
||||||
|
# return resp
|
||||||
|
|
||||||
def turn_off_laser(self):
|
def turn_off_laser(self):
|
||||||
"""发送指令关闭激光"""
|
"""发送指令关闭激光"""
|
||||||
@@ -147,17 +151,18 @@ class LaserManager:
|
|||||||
if logger:
|
if logger:
|
||||||
logger.info(f"[LASER] 写入字节数: {written}")
|
logger.info(f"[LASER] 写入字节数: {written}")
|
||||||
|
|
||||||
time.sleep_ms(50) # 增加等待时间
|
|
||||||
|
|
||||||
# 读取回包
|
# 读取回包
|
||||||
resp = hardware_manager.distance_serial.read(20)
|
# resp = hardware_manager.distance_serial.read(20)
|
||||||
if resp:
|
# if resp:
|
||||||
if logger:
|
# if logger:
|
||||||
logger.info(f"[LASER] 收到回包 ({len(resp)}字节): {resp.hex()}")
|
# logger.info(f"[LASER] 收到回包 ({len(resp)}字节): {resp.hex()}")
|
||||||
else:
|
# else:
|
||||||
if logger:
|
# if logger:
|
||||||
logger.warning("🔇 无回包")
|
# logger.warning("🔇 无回包")
|
||||||
return resp
|
# return resp
|
||||||
|
# 不用读回包
|
||||||
|
return None
|
||||||
|
|
||||||
def flash_laser(self, duration_ms=1000):
|
def flash_laser(self, duration_ms=1000):
|
||||||
"""闪一下激光(用于射箭反馈)"""
|
"""闪一下激光(用于射箭反馈)"""
|
||||||
@@ -223,6 +228,134 @@ class LaserManager:
|
|||||||
result = self._calibration_result
|
result = self._calibration_result
|
||||||
self._calibration_result = None
|
self._calibration_result = None
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def parse_bcd_distance(self, bcd_bytes: bytes) -> float:
|
||||||
|
"""将 4 字节 BCD 码转换为距离(米)"""
|
||||||
|
if len(bcd_bytes) != 4:
|
||||||
|
return 0.0
|
||||||
|
try:
|
||||||
|
hex_string = binascii.hexlify(bcd_bytes).decode()
|
||||||
|
distance_int = int(hex_string)
|
||||||
|
return distance_int / 1000.0
|
||||||
|
except Exception as e:
|
||||||
|
logger = logger_manager.logger
|
||||||
|
if logger:
|
||||||
|
logger.error(f"[LASER] BCD 解析失败: {e}")
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
def read_distance_from_laser_sensor(self) -> float:
|
||||||
|
"""发送测距指令并返回距离(米)"""
|
||||||
|
from hardware import hardware_manager
|
||||||
|
logger = logger_manager.logger
|
||||||
|
|
||||||
|
if hardware_manager.distance_serial is None:
|
||||||
|
if logger:
|
||||||
|
logger.error("[LASER] distance_serial 未初始化")
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 清空缓冲区
|
||||||
|
try:
|
||||||
|
hardware_manager.distance_serial.read(-1)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
# 打开激光
|
||||||
|
|
||||||
|
self.turn_on_laser()
|
||||||
|
self._laser_turned_on = True
|
||||||
|
time.sleep_ms(40) # 需要一定时间让激光稳定
|
||||||
|
# 发送测距查询命令
|
||||||
|
hardware_manager.distance_serial.write(config.DISTANCE_QUERY_CMD)
|
||||||
|
# time.sleep_ms(500) # 测试结果:这里的等待没有用!
|
||||||
|
self.turn_off_laser()
|
||||||
|
self._laser_turned_on = False
|
||||||
|
|
||||||
|
# 这里的等待才是有效的!大概350ms能读到数据
|
||||||
|
# 循环读取响应,最多等待500ms
|
||||||
|
start_time = time.ticks_ms()
|
||||||
|
max_wait_ms = 500
|
||||||
|
response = None
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# 检查是否超时
|
||||||
|
elapsed_ms = time.ticks_diff(start_time,time.ticks_ms())
|
||||||
|
print("elapsed_ms:", elapsed_ms)
|
||||||
|
if elapsed_ms >= max_wait_ms:
|
||||||
|
if logger:
|
||||||
|
logger.warning(f"[LASER] 读取超时 ({elapsed_ms}ms),未收到完整响应")
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
# 尝试读取数据
|
||||||
|
response = hardware_manager.distance_serial.read(config.DISTANCE_RESPONSE_LEN)
|
||||||
|
|
||||||
|
# 如果读到完整数据,立即返回
|
||||||
|
if response and len(response) == config.DISTANCE_RESPONSE_LEN:
|
||||||
|
elapsed_ms = time.ticks_diff(start_time,time.ticks_ms())
|
||||||
|
if logger:
|
||||||
|
logger.debug(f"[LASER] 收到响应 ({elapsed_ms}ms)")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 如果还没超时,短暂等待后继续尝试
|
||||||
|
time.sleep_ms(10) # 每次循环等待10ms,避免CPU占用过高
|
||||||
|
|
||||||
|
# 验证响应格式
|
||||||
|
if response and len(response) == config.DISTANCE_RESPONSE_LEN:
|
||||||
|
if response[3] != 0x20:
|
||||||
|
if response[0] == 0xEE:
|
||||||
|
err_code = (response[7] << 8) | response[8]
|
||||||
|
if logger:
|
||||||
|
logger.warning(f"[LASER] 模块错误代码: {hex(err_code)}")
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
# 解析BCD码距离
|
||||||
|
bcd_bytes = response[6:10]
|
||||||
|
distance_value_m = self.parse_bcd_distance(bcd_bytes)
|
||||||
|
signal_quality = (response[10] << 8) | response[11]
|
||||||
|
|
||||||
|
if logger:
|
||||||
|
logger.debug(f"[LASER] 测距成功: {distance_value_m:.3f} m, 信号质量: {signal_quality}")
|
||||||
|
return distance_value_m
|
||||||
|
|
||||||
|
if logger:
|
||||||
|
logger.warning(f"[LASER] 无效响应: {response.hex() if response else 'None'}")
|
||||||
|
return 0.0
|
||||||
|
except Exception as e:
|
||||||
|
logger = logger_manager.logger
|
||||||
|
if logger:
|
||||||
|
logger.error(f"[LASER] 读取激光测距失败: {e}")
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
def quick_measure_distance(self) -> float:
|
||||||
|
"""
|
||||||
|
快速激光测距:打开激光 → 测距 → 关闭激光
|
||||||
|
激光开启时间最小化(约500-600ms),尽量不让用户觉察到
|
||||||
|
返回距离(米),失败返回0.0
|
||||||
|
"""
|
||||||
|
logger = logger_manager.logger
|
||||||
|
self._laser_turned_on = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
|
||||||
|
# 等待激光稳定(最小延迟)
|
||||||
|
# time.sleep_ms(50)
|
||||||
|
|
||||||
|
# 读取距离
|
||||||
|
distance_m = self.read_distance_from_laser_sensor()
|
||||||
|
|
||||||
|
return distance_m
|
||||||
|
except Exception as e:
|
||||||
|
if logger:
|
||||||
|
logger.error(f"[LASER] 快速测距异常: {e}")
|
||||||
|
return 0.0
|
||||||
|
finally:
|
||||||
|
# 确保激光关闭
|
||||||
|
if self._laser_turned_on:
|
||||||
|
try:
|
||||||
|
self.turn_off_laser()
|
||||||
|
except Exception as e:
|
||||||
|
if logger:
|
||||||
|
logger.error(f"[LASER] 关闭激光失败: {e}")
|
||||||
|
|
||||||
|
|
||||||
# 创建全局单例实例
|
# 创建全局单例实例
|
||||||
|
|||||||
Reference in New Issue
Block a user