Merge branch 'main' of ssh://120.27.199.238:222/Havoc420mac/mi-task into main
This commit is contained in:
		
						commit
						a8574fc1db
					
				@ -202,7 +202,7 @@ def calculate_distance_to_line(edge_info, camera_height, camera_tilt_angle_deg=0
 | 
			
		||||
    
 | 
			
		||||
    return final_distance
 | 
			
		||||
 | 
			
		||||
def move_to_hori_line(ctrl, msg, target_distance=0.5, observe=False):
 | 
			
		||||
def move_to_hori_line(ctrl, msg, target_distance=0.5, observe=False, scan_qrcode=False, qr_check_interval=0.5):
 | 
			
		||||
    """
 | 
			
		||||
    控制机器人校准并移动到横向线前的指定距离
 | 
			
		||||
    
 | 
			
		||||
@ -211,25 +211,56 @@ def move_to_hori_line(ctrl, msg, target_distance=0.5, observe=False):
 | 
			
		||||
    msg: robot_control_cmd_lcmt 对象,用于发送命令
 | 
			
		||||
    target_distance: 目标位置与横向线的距离(米),默认为0.5米
 | 
			
		||||
    observe: 是否输出中间状态信息和可视化结果,默认为False
 | 
			
		||||
    scan_qrcode: 是否在移动过程中扫描QR码,默认为False
 | 
			
		||||
    qr_check_interval: QR码检查间隔时间(秒),默认为0.5秒
 | 
			
		||||
    
 | 
			
		||||
    返回:
 | 
			
		||||
    bool: 是否成功到达目标位置
 | 
			
		||||
    bool or tuple: 如果scan_qrcode为False,返回bool表示是否成功到达目标位置;
 | 
			
		||||
                  如果scan_qrcode为True,返回(bool, str)元组,表示(是否成功到达目标位置, QR码扫描结果)
 | 
			
		||||
    """
 | 
			
		||||
    # 启动异步QR码扫描(如果需要)
 | 
			
		||||
    qr_result = None
 | 
			
		||||
    if scan_qrcode:
 | 
			
		||||
        # 确保image_processor存在
 | 
			
		||||
        if not hasattr(ctrl, 'image_processor') or ctrl.image_processor is None:
 | 
			
		||||
            print("警告: 无法启用QR码扫描,image_processor不存在")
 | 
			
		||||
            scan_qrcode = False
 | 
			
		||||
        else:
 | 
			
		||||
            # 启动异步扫描
 | 
			
		||||
            try:
 | 
			
		||||
                ctrl.image_processor.start_async_scan(interval=0.2)
 | 
			
		||||
                print("已启动异步QR码扫描")
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                print(f"启动QR码扫描失败: {e}")
 | 
			
		||||
                scan_qrcode = False
 | 
			
		||||
    
 | 
			
		||||
    # 首先校准到水平
 | 
			
		||||
    print("校准到横向线水平")
 | 
			
		||||
    aligned = align_to_horizontal_line(ctrl, msg, observe=observe)
 | 
			
		||||
    
 | 
			
		||||
    if not aligned:
 | 
			
		||||
        print("无法校准到横向线水平,停止移动")
 | 
			
		||||
        if scan_qrcode:
 | 
			
		||||
            ctrl.image_processor.stop_async_scan()
 | 
			
		||||
            return False, None
 | 
			
		||||
        return False
 | 
			
		||||
    
 | 
			
		||||
    # 校准后检查是否已经扫描到QR码
 | 
			
		||||
    if scan_qrcode:
 | 
			
		||||
        qr_data, scan_time = ctrl.image_processor.get_last_qr_result()
 | 
			
		||||
        if qr_data:
 | 
			
		||||
            qr_result = qr_data
 | 
			
		||||
            print(f"🔍 校准过程中已扫描到QR码: {qr_data}")
 | 
			
		||||
    
 | 
			
		||||
    # 检测横向线
 | 
			
		||||
    # image = cv2.imread("current_image.jpg")  # TEST
 | 
			
		||||
    image = ctrl.image_processor.get_current_image()
 | 
			
		||||
    edge_point, edge_info = detect_horizontal_track_edge(image, observe=observe)
 | 
			
		||||
    
 | 
			
		||||
    if edge_point is None or edge_info is None:
 | 
			
		||||
        print("无法检测到横向线,停止移动")
 | 
			
		||||
        if scan_qrcode:
 | 
			
		||||
            ctrl.image_processor.stop_async_scan()
 | 
			
		||||
            return False, qr_result
 | 
			
		||||
        return False
 | 
			
		||||
    
 | 
			
		||||
    # 获取相机高度
 | 
			
		||||
@ -240,6 +271,9 @@ def move_to_hori_line(ctrl, msg, target_distance=0.5, observe=False):
 | 
			
		||||
    
 | 
			
		||||
    if current_distance is None:
 | 
			
		||||
        print("无法计算到横向线的距离,停止移动")
 | 
			
		||||
        if scan_qrcode:
 | 
			
		||||
            ctrl.image_processor.stop_async_scan()
 | 
			
		||||
            return False, qr_result
 | 
			
		||||
        return False
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
@ -250,6 +284,9 @@ def move_to_hori_line(ctrl, msg, target_distance=0.5, observe=False):
 | 
			
		||||
    
 | 
			
		||||
    if abs(distance_to_move) < 0.05:  # 如果已经很接近目标距离
 | 
			
		||||
        print("已经达到目标距离,无需移动")
 | 
			
		||||
        if scan_qrcode:
 | 
			
		||||
            ctrl.image_processor.stop_async_scan()
 | 
			
		||||
            return True, qr_result
 | 
			
		||||
        return True
 | 
			
		||||
    
 | 
			
		||||
    # 设置移动命令
 | 
			
		||||
@ -289,8 +326,9 @@ def move_to_hori_line(ctrl, msg, target_distance=0.5, observe=False):
 | 
			
		||||
    distance_moved = 0
 | 
			
		||||
    start_time = time.time()
 | 
			
		||||
    timeout = move_time + 1  # 超时时间设置为预计移动时间加1秒
 | 
			
		||||
    last_qr_check_time = 0
 | 
			
		||||
    
 | 
			
		||||
    # 监控移动距离,但不执行减速(改用stop_smooth)
 | 
			
		||||
    # 监控移动距离,并在移动过程中检查QR码(如果启用)
 | 
			
		||||
    while distance_moved < abs(distance_to_move) * 0.95 and time.time() - start_time < timeout:
 | 
			
		||||
        # 计算已移动距离
 | 
			
		||||
        current_position = ctrl.odo_msg.xyz
 | 
			
		||||
@ -298,6 +336,16 @@ def move_to_hori_line(ctrl, msg, target_distance=0.5, observe=False):
 | 
			
		||||
        dy = current_position[1] - start_position[1]
 | 
			
		||||
        distance_moved = math.sqrt(dx*dx + dy*dy)
 | 
			
		||||
        
 | 
			
		||||
        # 检查QR码扫描结果(如果启用)
 | 
			
		||||
        if scan_qrcode:
 | 
			
		||||
            current_time = time.time()
 | 
			
		||||
            if current_time - last_qr_check_time >= qr_check_interval:
 | 
			
		||||
                qr_data, scan_time = ctrl.image_processor.get_last_qr_result()
 | 
			
		||||
                if qr_data and scan_time > start_time:  # 确保是在移动开始后的扫描结果
 | 
			
		||||
                    qr_result = qr_data
 | 
			
		||||
                    print(f"🔍 在移动过程中扫描到QR码: {qr_data}")
 | 
			
		||||
                last_qr_check_time = current_time
 | 
			
		||||
        
 | 
			
		||||
        if observe and time.time() % 0.5 < 0.02:  # 每0.5秒左右打印一次
 | 
			
		||||
            print(f"已移动: {distance_moved:.3f}米, 目标: {abs(distance_to_move):.3f}米")
 | 
			
		||||
            
 | 
			
		||||
@ -319,8 +367,24 @@ def move_to_hori_line(ctrl, msg, target_distance=0.5, observe=False):
 | 
			
		||||
        if hasattr(ctrl, 'place_marker'):
 | 
			
		||||
            ctrl.place_marker(end_position[0], end_position[1], end_position[2] if len(end_position) > 2 else 0.0, 'red', observe=True)
 | 
			
		||||
    
 | 
			
		||||
    # 如果没有提供图像处理器或图像验证失败,则使用里程计数据判断
 | 
			
		||||
    return abs(distance_moved - abs(distance_to_move)) < 0.1  # 如果误差小于10厘米,则认为成功
 | 
			
		||||
    # 移动完成后再检查一次QR码扫描结果
 | 
			
		||||
    if scan_qrcode:
 | 
			
		||||
        qr_data, scan_time = ctrl.image_processor.get_last_qr_result()
 | 
			
		||||
        if qr_data and (qr_result is None or scan_time > last_qr_check_time):
 | 
			
		||||
            qr_result = qr_data
 | 
			
		||||
            print(f"🔍 移动完成后最终扫描到QR码: {qr_data}")
 | 
			
		||||
        
 | 
			
		||||
        # 停止异步扫描
 | 
			
		||||
        ctrl.image_processor.stop_async_scan()
 | 
			
		||||
    
 | 
			
		||||
    # 判断移动是否成功
 | 
			
		||||
    move_success = abs(distance_moved - abs(distance_to_move)) < 0.1  # 如果误差小于10厘米,则认为成功
 | 
			
		||||
    
 | 
			
		||||
    # 根据scan_qrcode参数返回不同格式的结果
 | 
			
		||||
    if scan_qrcode:
 | 
			
		||||
        return move_success, qr_result
 | 
			
		||||
    else:
 | 
			
		||||
        return move_success
 | 
			
		||||
 | 
			
		||||
def arc_turn_around_hori_line(ctrl, msg, angle_deg=90, left=True, target_distance=0.2, observe=False):
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,13 @@
 | 
			
		||||
import time
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
import math
 | 
			
		||||
 | 
			
		||||
# 添加父目录到路径,以便能够导入utils
 | 
			
		||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 | 
			
		||||
from base_move.move_base_hori_line import move_to_hori_line, arc_turn_around_hori_line
 | 
			
		||||
from base_move.move_base_hori_line import move_to_hori_line, arc_turn_around_hori_line, align_to_horizontal_line
 | 
			
		||||
from utils.detect_track import detect_horizontal_track_edge
 | 
			
		||||
from base_move.move_base_hori_line import calculate_distance_to_line
 | 
			
		||||
 | 
			
		||||
observe = True
 | 
			
		||||
 | 
			
		||||
@ -16,7 +19,20 @@ def run_task_1(ctrl, msg):
 | 
			
		||||
    arc_turn_around_hori_line(ctrl, msg, angle_deg=85, left=False, observe=observe)
 | 
			
		||||
    
 | 
			
		||||
    print('😺 task 1 - 2')
 | 
			
		||||
    move_to_hori_line(ctrl, msg, target_distance=1, observe=observe)
 | 
			
		||||
    # 使用内置的QR码扫描功能执行移动
 | 
			
		||||
    move_success, qr_result = move_to_hori_line(
 | 
			
		||||
        ctrl=ctrl,
 | 
			
		||||
        msg=msg,
 | 
			
		||||
        target_distance=1,
 | 
			
		||||
        observe=observe,
 | 
			
		||||
        scan_qrcode=True,  # 启用QR码扫描
 | 
			
		||||
        qr_check_interval=0.3  # 每0.3秒检查一次QR码结果
 | 
			
		||||
    )
 | 
			
		||||
    
 | 
			
		||||
    if qr_result:
 | 
			
		||||
        print(f"🎯 成功扫描到QR码: {qr_result}")
 | 
			
		||||
    else:
 | 
			
		||||
        print("⚠️ 未能扫描到任何QR码")
 | 
			
		||||
 | 
			
		||||
    print('😺 task 1 - 3')
 | 
			
		||||
    arc_turn_around_hori_line(ctrl, msg, angle_deg=180, target_distance=0.4, left=True, observe=observe)
 | 
			
		||||
@ -27,4 +43,26 @@ def run_task_1(ctrl, msg):
 | 
			
		||||
    move_to_hori_line(ctrl, msg, observe=observe)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 保留move_with_qr_scan函数作为备份,如果需要特殊处理可以使用
 | 
			
		||||
def move_with_qr_scan(ctrl, msg, target_distance=0.5, observe=False):
 | 
			
		||||
    """
 | 
			
		||||
    结合移动到指定位置和 QR 码扫描功能的函数,使用异步扫描
 | 
			
		||||
    
 | 
			
		||||
    参数:
 | 
			
		||||
        ctrl: Robot_Ctrl 对象
 | 
			
		||||
        msg: 机器人控制消息对象
 | 
			
		||||
        target_distance: 目标距离
 | 
			
		||||
        observe: 是否打印调试信息
 | 
			
		||||
    """
 | 
			
		||||
    # 直接使用内置的扫描功能
 | 
			
		||||
    return move_to_hori_line(
 | 
			
		||||
        ctrl=ctrl,
 | 
			
		||||
        msg=msg, 
 | 
			
		||||
        target_distance=target_distance,
 | 
			
		||||
        observe=observe,
 | 
			
		||||
        scan_qrcode=True,
 | 
			
		||||
        qr_check_interval=0.3
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,9 @@ from cv_bridge import CvBridge
 | 
			
		||||
import cv2
 | 
			
		||||
from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSHistoryPolicy
 | 
			
		||||
from qreader import QReader
 | 
			
		||||
from threading import Thread
 | 
			
		||||
from threading import Thread, Lock
 | 
			
		||||
import time
 | 
			
		||||
import queue
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ImageSubscriber(Node):
 | 
			
		||||
@ -45,6 +47,15 @@ class ImageProcessor:
 | 
			
		||||
        self.qreader = QReader()
 | 
			
		||||
        self.spin_thread = None
 | 
			
		||||
        self.running = True
 | 
			
		||||
        
 | 
			
		||||
        # 异步 QR 码扫描相关
 | 
			
		||||
        self.scan_thread = None
 | 
			
		||||
        self.image_queue = queue.Queue(maxsize=3)  # 限制队列大小,只保留最新的图像
 | 
			
		||||
        self.scan_lock = Lock()
 | 
			
		||||
        self.last_qr_result = None
 | 
			
		||||
        self.last_qr_time = 0
 | 
			
		||||
        self.is_scanning = False
 | 
			
		||||
        self.enable_async_scan = False
 | 
			
		||||
    
 | 
			
		||||
    def run(self):
 | 
			
		||||
        self.spin_thread = Thread(target=self._spin)
 | 
			
		||||
@ -59,6 +70,7 @@ class ImageProcessor:
 | 
			
		||||
    
 | 
			
		||||
    def destroy(self):
 | 
			
		||||
        self.running = False
 | 
			
		||||
        self.stop_async_scan()
 | 
			
		||||
        if self.spin_thread:
 | 
			
		||||
            self.spin_thread.join()
 | 
			
		||||
        self.image_subscriber.destroy_node()
 | 
			
		||||
@ -69,8 +81,72 @@ class ImageProcessor:
 | 
			
		||||
    def decode_qrcode(self, img = None):
 | 
			
		||||
        if img is None:
 | 
			
		||||
            img = self.get_current_image()
 | 
			
		||||
        if img is None:
 | 
			
		||||
            return None
 | 
			
		||||
        decoded_info = self.qreader.detect_and_decode(image=img)
 | 
			
		||||
        return decoded_info[0]
 | 
			
		||||
        if decoded_info and len(decoded_info) > 0:
 | 
			
		||||
            return decoded_info[0]
 | 
			
		||||
        return None
 | 
			
		||||
    
 | 
			
		||||
    def start_async_scan(self, interval=0.3):
 | 
			
		||||
        """
 | 
			
		||||
        启动异步 QR 码扫描
 | 
			
		||||
        
 | 
			
		||||
        参数:
 | 
			
		||||
            interval: 扫描间隔,单位秒
 | 
			
		||||
        """
 | 
			
		||||
        if self.scan_thread is not None and self.scan_thread.is_alive():
 | 
			
		||||
            print("异步扫描已经在运行中")
 | 
			
		||||
            return
 | 
			
		||||
        
 | 
			
		||||
        self.enable_async_scan = True
 | 
			
		||||
        self.is_scanning = False
 | 
			
		||||
        self.scan_thread = Thread(target=self._async_scan_worker, args=(interval,))
 | 
			
		||||
        self.scan_thread.daemon = True  # 设为守护线程,主线程结束时自动结束
 | 
			
		||||
        self.scan_thread.start()
 | 
			
		||||
        print("启动异步 QR 码扫描线程")
 | 
			
		||||
    
 | 
			
		||||
    def stop_async_scan(self):
 | 
			
		||||
        """停止异步 QR 码扫描"""
 | 
			
		||||
        self.enable_async_scan = False
 | 
			
		||||
        if self.scan_thread and self.scan_thread.is_alive():
 | 
			
		||||
            self.scan_thread.join(timeout=1.0)
 | 
			
		||||
            print("异步 QR 码扫描线程已停止")
 | 
			
		||||
    
 | 
			
		||||
    def _async_scan_worker(self, interval):
 | 
			
		||||
        """异步扫描工作线程"""
 | 
			
		||||
        last_scan_time = 0
 | 
			
		||||
        
 | 
			
		||||
        while self.enable_async_scan and self.running:
 | 
			
		||||
            current_time = time.time()
 | 
			
		||||
            
 | 
			
		||||
            # 按指定间隔扫描
 | 
			
		||||
            if current_time - last_scan_time >= interval:
 | 
			
		||||
                img = self.get_current_image()
 | 
			
		||||
                if img is not None:
 | 
			
		||||
                    try:
 | 
			
		||||
                        self.is_scanning = True
 | 
			
		||||
                        qr_data = self.decode_qrcode(img)
 | 
			
		||||
                        self.is_scanning = False
 | 
			
		||||
                        
 | 
			
		||||
                        with self.scan_lock:
 | 
			
		||||
                            if qr_data:
 | 
			
		||||
                                self.last_qr_result = qr_data
 | 
			
		||||
                                self.last_qr_time = current_time
 | 
			
		||||
                                print(f"异步扫描到 QR 码: {qr_data}")
 | 
			
		||||
                    except Exception as e:
 | 
			
		||||
                        self.is_scanning = False
 | 
			
		||||
                        print(f"异步 QR 码扫描出错: {e}")
 | 
			
		||||
                
 | 
			
		||||
                last_scan_time = current_time
 | 
			
		||||
            
 | 
			
		||||
            # 短暂休眠避免占用过多 CPU
 | 
			
		||||
            time.sleep(0.05)
 | 
			
		||||
    
 | 
			
		||||
    def get_last_qr_result(self):
 | 
			
		||||
        """获取最后一次成功扫描的 QR 码结果"""
 | 
			
		||||
        with self.scan_lock:
 | 
			
		||||
            return self.last_qr_result, self.last_qr_time
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
""" DEBUG """
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user