From cc2a6ac41e64bf5075e762e151292f4249aa2647 Mon Sep 17 00:00:00 2001 From: Havoc <2993167370@qq.com> Date: Wed, 28 May 2025 23:07:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=97=A5=E5=BF=97=E6=96=87?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E5=A2=9E=E5=8A=A0=E5=8F=8C=E8=BD=A8=E8=BF=B9?= =?UTF-8?q?=E7=BA=BF=E6=A3=80=E6=B5=8B=E7=9A=84=E8=AF=A6=E7=BB=86=E8=B0=83?= =?UTF-8?q?=E8=AF=95=E4=BF=A1=E6=81=AF=E5=92=8C=E7=BB=93=E6=9E=9C=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=EF=BC=8C=E5=90=8C=E6=97=B6=E5=88=A0=E9=99=A4=E8=BF=87?= =?UTF-8?q?=E6=97=B6=E7=9A=84=E5=9B=BE=E5=83=8F=E6=96=87=E4=BB=B6=E4=BB=A5?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AD=98=E5=82=A8=E3=80=82=E5=A2=9E=E5=BC=BA?= =?UTF-8?q?=E4=BA=86=E5=AF=B9=E4=B8=8D=E5=90=8C=E8=B7=AF=E5=86=B5=E7=9A=84?= =?UTF-8?q?=E5=A4=84=E7=90=86=E8=83=BD=E5=8A=9B=EF=BC=8C=E6=8F=90=E5=8D=87?= =?UTF-8?q?=E4=BA=86=E6=A3=80=E6=B5=8B=E5=87=86=E7=A1=AE=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- base_move/center_on_dual_tracks.py | 268 ++++++++++++++++++ logs/robot_2025-05-28.log | 37 +++ .../result_image_20250513_162556.png | Bin 58629 -> 0 bytes .../test/result_image_20250514_024347.png | Bin 60479 -> 0 bytes test/test_image.py | 73 +++++ test/test_offline_centering.py | 243 ++++++++++++++++ test_center_on_tracks.py | 101 +++++++ 7 files changed, 722 insertions(+) create mode 100644 base_move/center_on_dual_tracks.py delete mode 100644 res/path/test/result_image_20250513_162556.png/result_image_20250513_162556.png delete mode 100644 res/path/test/result_image_20250514_024347.png create mode 100644 test/test_image.py create mode 100644 test/test_offline_centering.py create mode 100644 test_center_on_tracks.py diff --git a/base_move/center_on_dual_tracks.py b/base_move/center_on_dual_tracks.py new file mode 100644 index 0000000..629c670 --- /dev/null +++ b/base_move/center_on_dual_tracks.py @@ -0,0 +1,268 @@ +import math +import time +import sys +import os + +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from utils.log_helper import LogHelper, get_logger, section, info, debug, warning, error, success, timing +from utils.detect_dual_track_lines import detect_dual_track_lines, auto_detect_dual_track_lines + +def center_on_dual_tracks(ctrl, msg, max_time=15, max_deviation=10.0, observe=False, + mode=11, gait_id=26, step_height=[0.06, 0.06], + stone_path_mode=None): + """ + 控制机器狗仅使用Y轴移动调整到双轨道线的中间位置 + + 参数: + ctrl: Robot_Ctrl 对象,包含里程计信息 + msg: robot_control_cmd_lcmt 对象,用于发送命令 + max_time: 最大调整时间(秒),默认为15秒 + max_deviation: 允许的最大偏差(像素),当偏差小于此值时认为已居中,默认为10像素 + observe: 是否输出中间状态信息和可视化结果,默认为False + mode: 控制模式,默认为11 + gait_id: 步态ID,默认为26 + step_height: 抬腿高度,默认为[0.06, 0.06] + stone_path_mode: 是否使用石板路模式,None表示自动检测,True或False表示强制使用或不使用 + + 返回: + bool: 是否成功调整到中心位置 + """ + section("开始双轨道居中", "轨道居中") + + # 设置移动命令基本参数 + msg.mode = mode + msg.gait_id = gait_id + msg.duration = 0 # wait next cmd + msg.step_height = step_height + + # 记录起始时间 + start_time = time.time() + + # 记录起始位置 + start_position = list(ctrl.odo_msg.xyz) + if observe: + debug(f"起始位置: {start_position}", "位置") + # 在起点放置绿色标记 + if hasattr(ctrl, 'place_marker'): + ctrl.place_marker(start_position[0], start_position[1], start_position[2] if len(start_position) > 2 else 0.0, 'green', observe=True) + + # PID控制参数 - 仅使用比例控制以避免过冲 + kp = 0.003 # 比例系数 - 较小的值以获得平滑的移动 + + # 帧间滤波参数 + filter_size = 5 # 滤波队列大小 + deviation_queue = [] # 偏差值队列 + + # 统计变量 + detection_success_count = 0 + detection_total_count = 0 + + # 稳定计数器 - 连续几次在中心位置才认为稳定 + stable_count = 0 + required_stable_count = 3 + + # 开始调整循环 + while time.time() - start_time < max_time: + # 获取当前图像 + image = ctrl.image_processor.get_current_image() + + # 检测双轨道线 + detection_total_count += 1 + + if stone_path_mode is None: + # 自动检测模式 + center_info, left_info, right_info = auto_detect_dual_track_lines(image, observe=observe, save_log=True) + else: + # 指定模式 + center_info, left_info, right_info = detect_dual_track_lines(image, observe=observe, save_log=True, stone_path_mode=stone_path_mode) + + if center_info is not None: + detection_success_count += 1 + + # 获取当前偏差 + current_deviation = center_info["deviation"] + + # 添加到队列 + deviation_queue.append(current_deviation) + if len(deviation_queue) > filter_size: + deviation_queue.pop(0) + + # 计算滤波后的偏差值 (去除最大和最小值后的平均) + if len(deviation_queue) >= 3: + filtered_deviations = sorted(deviation_queue)[1:-1] if len(deviation_queue) > 2 else deviation_queue + filtered_deviation = sum(filtered_deviations) / len(filtered_deviations) + else: + filtered_deviation = current_deviation + + if observe: + debug(f"原始偏差: {current_deviation:.1f}px, 滤波后: {filtered_deviation:.1f}px", "偏差") + + # 判断是否已经居中 + if abs(filtered_deviation) <= max_deviation: + stable_count += 1 + if observe: + info(f"已接近中心,稳定计数: {stable_count}/{required_stable_count}", "居中") + + if stable_count >= required_stable_count: + # 已经稳定在中心位置 + if observe: + success(f"成功居中,最终偏差: {filtered_deviation:.1f}px", "完成") + break + else: + # 不在中心,重置稳定计数 + stable_count = 0 + + # 计算横向移动速度 (只使用y轴移动) + # 注意:偏差为正表示需要向左移动(y轴正方向),偏差为负表示需要向右移动(y轴负方向) + lateral_velocity = kp * filtered_deviation + + # 限制横向移动速度 + max_lateral_velocity = 0.3 # 最大横向速度 (米/秒) + lateral_velocity = max(-max_lateral_velocity, min(max_lateral_velocity, lateral_velocity)) + + if observe: + debug(f"横向移动速度: {lateral_velocity:.3f}m/s", "控制") + + # 设置速度命令 - 只使用y轴移动,不前进和转向 + msg.vel_des = [0, lateral_velocity, 0] # [前进速度, 侧向速度, 角速度] + + # 发送命令 + msg.life_count += 1 + ctrl.Send_cmd(msg) + else: + warning("未检测到双轨道线", "警告") + + # 如果已经有了一些有效的检测,暂时停止移动 + if len(deviation_queue) > 0: + msg.vel_des = [0, 0, 0] + msg.life_count += 1 + ctrl.Send_cmd(msg) + + if observe: + warning("暂停移动,等待有效检测", "暂停") + else: + # 如果一开始就没有检测到,可以尝试小范围搜索 + if detection_total_count < 10: + if detection_total_count % 2 == 0: + # 向右搜索 + msg.vel_des = [0, -0.1, 0] + else: + # 向左搜索 + msg.vel_des = [0, 0.1, 0] + + msg.life_count += 1 + ctrl.Send_cmd(msg) + + if observe: + debug("搜索轨道线...", "搜索") + else: + # 超过一定次数仍未检测到,停止搜索 + msg.vel_des = [0, 0, 0] + msg.life_count += 1 + ctrl.Send_cmd(msg) + + if observe: + error("无法检测到轨道线,放弃调整", "失败") + break + + # 短暂延时 + time.sleep(0.05) + + # 停止移动 + ctrl.base_msg.stop() + + # 计算最终位置与起始位置的变化 + final_position = ctrl.odo_msg.xyz + dx = final_position[0] - start_position[0] + dy = final_position[1] - start_position[1] + + if observe: + # 在终点放置红色标记 + if hasattr(ctrl, 'place_marker'): + ctrl.place_marker(final_position[0], final_position[1], final_position[2] if len(final_position) > 2 else 0.0, 'red', observe=True) + + info(f"横向移动距离: {abs(dy):.3f}米", "统计") + + # 显示检测成功率 + if detection_total_count > 0: + detection_rate = (detection_success_count / detection_total_count) * 100 + info(f"轨迹检测成功率: {detection_rate:.1f}% ({detection_success_count}/{detection_total_count})", "统计") + + # 判断是否成功 + success = False + if time.time() - start_time >= max_time: + if observe: + warning("超过最大调整时间", "超时") + else: + # 如果因为已稳定在中心而退出循环,则认为成功 + if stable_count >= required_stable_count: + success = True + + return success + +def center_and_follow_dual_tracks(ctrl, msg, distance, speed=0.5, max_centering_time=15, observe=False, + mode=11, gait_id=26, step_height=[0.06, 0.06], + stone_path_mode=None): + """ + 先居中到双轨道线中间,然后沿轨道线行走指定距离 + + 参数: + ctrl: Robot_Ctrl 对象,包含里程计信息 + msg: robot_control_cmd_lcmt 对象,用于发送命令 + distance: 目标前进距离(米) + speed: 前进速度(米/秒),默认为0.5米/秒 + max_centering_time: 最大居中调整时间(秒),默认为15秒 + observe: 是否输出中间状态信息和可视化结果,默认为False + mode: 控制模式,默认为11 + gait_id: 步态ID,默认为26 + step_height: 抬腿高度,默认为[0.06, 0.06] + stone_path_mode: 是否使用石板路模式,None表示自动检测 + + 返回: + bool: 是否成功完成居中和轨道跟随 + """ + section("开始双轨道居中和跟随", "轨道任务") + + # 第一步:居中到轨道中间 + if observe: + info("步骤1: 调整到轨道中间", "居中") + + centering_success = center_on_dual_tracks( + ctrl, msg, + max_time=max_centering_time, + observe=observe, + mode=mode, + gait_id=gait_id, + step_height=step_height, + stone_path_mode=stone_path_mode + ) + + if not centering_success: + if observe: + error("居中调整失败,无法继续跟随轨道", "失败") + return False + + # 第二步:沿轨道跟随指定距离 + if observe: + info(f"步骤2: 沿轨道前进 {distance:.2f}米", "跟随") + + # 导入轨道跟随函数 + from base_move.follow_dual_tracks import follow_dual_tracks + + following_success = follow_dual_tracks( + ctrl, msg, + speed=speed, + target_distance=distance, + observe=observe, + mode=mode, + gait_id=gait_id, + step_height=step_height + ) + + if observe: + if following_success: + success("成功完成轨道居中和跟随任务", "完成") + else: + warning("轨道跟随未完全成功", "警告") + + return following_success \ No newline at end of file diff --git a/logs/robot_2025-05-28.log b/logs/robot_2025-05-28.log index ed18f9d..70e42b6 100644 --- a/logs/robot_2025-05-28.log +++ b/logs/robot_2025-05-28.log @@ -500,3 +500,40 @@ 2025-05-28 22:51:32 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.89 2025-05-28 22:51:33 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250528_225133_573204.jpg 2025-05-28 22:51:33 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250528_225133_573204', 'center_point': (872, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 539.8450926202986, 'right_track_mid_x': 1405.6136261449096, 'track_width': 865.768533524611, 'center_slope': -0.13454341879828116, 'stone_path_mode': True} +2025-05-28 23:01:24 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-28 23:01:26 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-28 23:01:28 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-28 23:01:30 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 65 条直线 +2025-05-28 23:01:32 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 8 条垂直线 +2025-05-28 23:01:34 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.92 +2025-05-28 23:01:36 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250528_230136_236353.jpg +2025-05-28 23:01:36 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250528_230136_236353', 'center_point': (852, 1080), 'deviation': -2.2737367544323206e-13, 'left_track_mid_x': 397.0, 'right_track_mid_x': 1351.5, 'track_width': 954.5, 'center_slope': -0.16286380575687864, 'stone_path_mode': False} +2025-05-28 23:01:36 | DEBUG | utils.log_helper - 🐞 增强对比度和颜色检测 +2025-05-28 23:01:38 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-28 23:01:40 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-28 23:01:42 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-28 23:01:44 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 127 条直线 +2025-05-28 23:01:46 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 30 条垂直线 +2025-05-28 23:01:48 | DEBUG | utils.log_helper - 🐞 步骤4.5: 合并后找到 9 条垂直线 +2025-05-28 23:01:50 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.96 +2025-05-28 23:01:52 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250528_230152_516789.jpg +2025-05-28 23:01:52 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250528_230152_516789', 'center_point': (838, 1080), 'deviation': -2.2737367544323206e-13, 'left_track_mid_x': 409.3663817066892, 'right_track_mid_x': 1378.603238665647, 'track_width': 969.2368569589578, 'center_slope': -0.16918184085806812, 'stone_path_mode': True} +2025-05-28 23:01:52 | DEBUG | utils.log_helper - 🐞 增强对比度和颜色检测 +2025-05-28 23:01:54 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-28 23:01:56 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-28 23:01:58 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-28 23:02:00 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 127 条直线 +2025-05-28 23:02:02 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 30 条垂直线 +2025-05-28 23:02:04 | DEBUG | utils.log_helper - 🐞 步骤4.5: 合并后找到 9 条垂直线 +2025-05-28 23:02:06 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.96 +2025-05-28 23:02:08 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250528_230208_672297.jpg +2025-05-28 23:02:08 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250528_230208_672297', 'center_point': (838, 1080), 'deviation': -2.2737367544323206e-13, 'left_track_mid_x': 409.3663817066892, 'right_track_mid_x': 1378.603238665647, 'track_width': 969.2368569589578, 'center_slope': -0.16918184085806812, 'stone_path_mode': True} +2025-05-28 23:02:08 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-28 23:02:10 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-28 23:02:12 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-28 23:02:14 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 65 条直线 +2025-05-28 23:02:16 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 8 条垂直线 +2025-05-28 23:02:18 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.92 +2025-05-28 23:02:20 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250528_230220_810282.jpg +2025-05-28 23:02:20 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250528_230220_810282', 'center_point': (852, 1080), 'deviation': -2.2737367544323206e-13, 'left_track_mid_x': 397.0, 'right_track_mid_x': 1351.5, 'track_width': 954.5, 'center_slope': -0.16286380575687864, 'stone_path_mode': False} +2025-05-28 23:02:20 | INFO | utils.log_helper - ℹ️ 选择石板路模式结果 diff --git a/res/path/test/result_image_20250513_162556.png/result_image_20250513_162556.png b/res/path/test/result_image_20250513_162556.png/result_image_20250513_162556.png deleted file mode 100644 index 93946352d52c6978c86315c0772944c7148ffa8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58629 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

i-Y>(APBiF38D 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 diff --git a/test/test_image.py b/test/test_image.py new file mode 100644 index 0000000..54aeba5 --- /dev/null +++ b/test/test_image.py @@ -0,0 +1,73 @@ +import cv2 +import os +from utils.detect_dual_track_lines import detect_dual_track_lines, auto_detect_dual_track_lines + +# 图片路径 +image_path = "res/path/image_20250514_024347.png" + +# 确保图片存在 +if not os.path.exists(image_path): + print(f"图片 {image_path} 不存在!") + exit(1) + +# 先尝试普通模式 +print("正在使用普通模式检测...") +center_info, left_track_info, right_track_info = detect_dual_track_lines( + image_path, + observe=True, # 设置为True以查看处理过程和结果 + delay=2000, # 增加显示时间以便观察 + save_log=True, + stone_path_mode=False +) + +if center_info: + print("\n普通模式检测结果:") + print(f"中心点: {center_info['point']}") + print(f"偏差: {center_info['deviation']:.2f}") + print(f"斜率: {center_info['slope']:.2f}") + print(f"轨道宽度: {center_info['track_width']:.2f}") +else: + print("普通模式检测失败") + +# 再尝试石板路模式 +print("\n正在使用石板路模式检测...") +center_info, left_track_info, right_track_info = detect_dual_track_lines( + image_path, + observe=True, + delay=2000, + save_log=True, + stone_path_mode=True +) + +if center_info: + print("\n石板路模式检测结果:") + print(f"中心点: {center_info['point']}") + print(f"偏差: {center_info['deviation']:.2f}") + print(f"斜率: {center_info['slope']:.2f}") + print(f"轨道宽度: {center_info['track_width']:.2f}") +else: + print("石板路模式检测失败") + +# 最后尝试自动检测模式 +print("\n正在使用自动检测模式...") +center_info, left_track_info, right_track_info = auto_detect_dual_track_lines( + image_path, + observe=True, + delay=2000, + save_log=True +) + +if center_info: + print("\n自动检测模式结果:") + print(f"中心点: {center_info['point']}") + print(f"偏差: {center_info['deviation']:.2f}") + print(f"斜率: {center_info['slope']:.2f}") + print(f"轨道宽度: {center_info['track_width']:.2f}") + print(f"使用石板路模式: {center_info['stone_path_mode']}") +else: + print("自动检测模式失败") + +# 等待用户按键关闭窗口 +print("\n按任意键退出...") +cv2.waitKey(0) +cv2.destroyAllWindows() \ No newline at end of file diff --git a/test/test_offline_centering.py b/test/test_offline_centering.py new file mode 100644 index 0000000..9a4ee48 --- /dev/null +++ b/test/test_offline_centering.py @@ -0,0 +1,243 @@ +import sys +import os +import time +import argparse +import cv2 +import numpy as np +import math + +sys.path.append(os.path.dirname(os.path.abspath(__file__))) +from utils.log_helper import LogHelper, get_logger, section, info, debug, warning, error, success, timing +from utils.detect_dual_track_lines import detect_dual_track_lines, auto_detect_dual_track_lines + +def simulate_center_on_dual_tracks(image_path, max_iterations=50, max_deviation=10.0, observe=True, stone_path_mode=None): + """ + 模拟机器狗仅使用Y轴移动调整到双轨道线的中间位置 + + 参数: + image_path: 图像路径 + max_iterations: 最大迭代次数 + max_deviation: 允许的最大偏差(像素),当偏差小于此值时认为已居中 + observe: 是否输出中间状态信息和可视化结果 + stone_path_mode: 是否使用石板路模式,None表示自动检测 + + 返回: + bool: 是否成功调整到中心位置 + """ + section("开始模拟双轨道居中", "离线模拟") + + # 确保图像存在 + if not os.path.exists(image_path): + error(f"图像不存在: {image_path}", "失败") + return False + + # 加载原始图像 + original_image = cv2.imread(image_path) + if original_image is None: + error(f"无法加载图像: {image_path}", "失败") + return False + + # 获取图像尺寸 + height, width = original_image.shape[:2] + center_x = width // 2 + + # 创建图像平移函数 + def shift_image(img, shift_x): + """水平平移图像,模拟机器人横向移动""" + M = np.float32([[1, 0, shift_x], [0, 1, 0]]) + return cv2.warpAffine(img, M, (width, height)) + + # PID控制参数 - 仅使用比例控制以避免过冲 + kp = 0.3 # 比例系数 + + # 帧间滤波参数 + filter_size = 5 + deviation_queue = [] + + # 统计变量 + detection_success_count = 0 + detection_total_count = 0 + + # 稳定计数器 + stable_count = 0 + required_stable_count = 3 + + # 当前横向位置偏移量(模拟机器人位置) + current_offset = 0 + + # 创建可视化窗口 + if observe: + cv2.namedWindow("模拟居中", cv2.WINDOW_NORMAL) + cv2.resizeWindow("模拟居中", 800, 600) + + # 开始模拟调整循环 + for iteration in range(max_iterations): + # 应用当前偏移创建模拟图像 + shifted_image = shift_image(original_image, current_offset) + + # 检测双轨道线 + detection_total_count += 1 + + if stone_path_mode is None: + # 自动检测模式 + center_info, left_info, right_info = auto_detect_dual_track_lines(shifted_image, observe=observe, delay=500 if observe else 1) + else: + # 指定模式 + center_info, left_info, right_info = detect_dual_track_lines(shifted_image, observe=observe, delay=500 if observe else 1, stone_path_mode=stone_path_mode) + + if center_info is not None: + detection_success_count += 1 + + # 获取当前偏差 + current_deviation = center_info["deviation"] + + # 添加到队列 + deviation_queue.append(current_deviation) + if len(deviation_queue) > filter_size: + deviation_queue.pop(0) + + # 计算滤波后的偏差值 + if len(deviation_queue) >= 3: + filtered_deviations = sorted(deviation_queue)[1:-1] if len(deviation_queue) > 2 else deviation_queue + filtered_deviation = sum(filtered_deviations) / len(filtered_deviations) + else: + filtered_deviation = current_deviation + + if observe: + debug(f"迭代 {iteration+1}/{max_iterations}: 原始偏差: {current_deviation:.1f}px, 滤波后: {filtered_deviation:.1f}px", "偏差") + + # 判断是否已经居中 + if abs(filtered_deviation) <= max_deviation: + stable_count += 1 + if observe: + info(f"已接近中心,稳定计数: {stable_count}/{required_stable_count}", "居中") + + if stable_count >= required_stable_count: + # 已经稳定在中心位置 + if observe: + success(f"成功居中,最终偏差: {filtered_deviation:.1f}px", "完成") + # 在结果图像上显示成功信息 + result_image = shifted_image.copy() + cv2.putText(result_image, f"成功居中! 偏差: {filtered_deviation:.1f}px", (50, 50), + cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) + cv2.imshow("模拟居中", result_image) + cv2.waitKey(0) + break + else: + # 不在中心,重置稳定计数 + stable_count = 0 + + # 计算横向移动量 + lateral_move = kp * filtered_deviation + + # 限制单次移动量 + max_move = 50 # 最大单次移动像素数 + lateral_move = max(-max_move, min(max_move, lateral_move)) + + # 更新当前偏移 + current_offset += lateral_move + + if observe: + debug(f"横向移动: {lateral_move:.1f}px, 当前总偏移: {current_offset:.1f}px", "控制") + else: + warning(f"迭代 {iteration+1}/{max_iterations}: 未检测到双轨道线", "警告") + + # 显示当前模拟状态 + if observe: + # 在模拟图像上显示当前信息 + info_image = shifted_image.copy() + cv2.putText(info_image, f"迭代: {iteration+1}/{max_iterations}", (50, 50), + cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 255), 2) + + if center_info: + # 如果成功检测,显示偏差信息 + cv2.putText(info_image, f"偏差: {filtered_deviation:.1f}px", (50, 90), + cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) + # 绘制居中目标 + cv2.line(info_image, (center_x, 0), (center_x, height), (0, 0, 255), 1) + else: + # 如果检测失败,显示警告 + cv2.putText(info_image, "未检测到轨道线", (50, 90), + cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2) + + cv2.imshow("模拟居中", info_image) + key = cv2.waitKey(100) + if key == 27: # ESC键退出 + break + + # 清理资源 + if observe: + cv2.destroyAllWindows() + + # 显示检测成功率 + if detection_total_count > 0: + detection_rate = (detection_success_count / detection_total_count) * 100 + info(f"轨迹检测成功率: {detection_rate:.1f}% ({detection_success_count}/{detection_total_count})", "统计") + + # 判断是否成功 + success_flag = False + if iteration >= max_iterations - 1: + if observe: + warning("超过最大迭代次数", "超时") + else: + # 如果因为已稳定在中心而退出循环,则认为成功 + if stable_count >= required_stable_count: + success_flag = True + + return success_flag + +def main(): + """ + 测试离线双轨道线居中功能 + """ + # 解析命令行参数 + parser = argparse.ArgumentParser(description='测试离线双轨道线居中功能') + parser.add_argument('--image', type=str, default="res/path/image_20250514_024347.png", + help='测试图像路径') + parser.add_argument('--iterations', type=int, default=50, + help='最大迭代次数,默认为50') + parser.add_argument('--stone_path', action='store_true', + help='强制使用石板路模式') + parser.add_argument('--normal_path', action='store_true', + help='强制使用普通路径模式') + args = parser.parse_args() + + # 初始化日志 + LogHelper.init('offline_dual_track_centering') + section("离线双轨道线居中测试", "开始") + + try: + # 确定使用哪种模式 + stone_path_mode = None # 默认自动检测 + if args.stone_path: + stone_path_mode = True + info("强制使用石板路模式", "模式") + elif args.normal_path: + stone_path_mode = False + info("强制使用普通路径模式", "模式") + else: + info("使用自动检测模式", "模式") + + # 执行离线模拟 + success = simulate_center_on_dual_tracks( + args.image, + max_iterations=args.iterations, + observe=True, + stone_path_mode=stone_path_mode + ) + + # 显示结果 + if success: + success("测试成功完成", "结果") + else: + warning("测试未完全成功", "结果") + + except KeyboardInterrupt: + warning("用户中断测试", "中断") + except Exception as e: + error(f"测试过程中发生异常: {str(e)}", "异常") + + section("离线双轨道线居中测试", "结束") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test_center_on_tracks.py b/test_center_on_tracks.py new file mode 100644 index 0000000..2f81ec7 --- /dev/null +++ b/test_center_on_tracks.py @@ -0,0 +1,101 @@ +import sys +import os +import time +import argparse + +sys.path.append(os.path.dirname(os.path.abspath(__file__))) +from utils.log_helper import LogHelper, get_logger, section, info, debug, warning, error, success, timing + +def main(): + """ + 测试双轨道线居中功能 + """ + # 解析命令行参数 + parser = argparse.ArgumentParser(description='测试双轨道线居中功能') + parser.add_argument('--distance', type=float, default=0.0, + help='居中后要前进的距离(米),默认为0,即仅执行居中操作') + parser.add_argument('--speed', type=float, default=0.5, + help='前进速度(米/秒),默认为0.5') + parser.add_argument('--max_time', type=float, default=15.0, + help='最大居中时间(秒),默认为15秒') + parser.add_argument('--stone_path', action='store_true', + help='强制使用石板路模式') + parser.add_argument('--normal_path', action='store_true', + help='强制使用普通路径模式') + args = parser.parse_args() + + # 初始化日志 + LogHelper.init('dual_track_centering') + section("双轨道线居中测试", "开始") + + try: + # 导入机器人控制模块 + from robot_controller import RobotCtrl + + # 初始化机器人控制器 + ctrl = RobotCtrl(observe=True) + msg = ctrl.initialize() + + if msg is None: + error("初始化机器人控制器失败", "失败") + return + + info("机器人控制器初始化成功", "初始化") + + # 等待机器人准备就绪 + time.sleep(1) + + # 确定使用哪种模式 + stone_path_mode = None # 默认自动检测 + if args.stone_path: + stone_path_mode = True + info("强制使用石板路模式", "模式") + elif args.normal_path: + stone_path_mode = False + info("强制使用普通路径模式", "模式") + else: + info("使用自动检测模式", "模式") + + # 导入双轨道线居中模块 + from base_move.center_on_dual_tracks import center_on_dual_tracks, center_and_follow_dual_tracks + + # 执行居中操作 + if args.distance > 0: + # 居中后沿轨道前进 + info(f"执行居中并前进 {args.distance} 米,速度 {args.speed} m/s", "任务") + success = center_and_follow_dual_tracks( + ctrl, msg, + distance=args.distance, + speed=args.speed, + max_centering_time=args.max_time, + observe=True, + stone_path_mode=stone_path_mode + ) + else: + # 仅执行居中 + info("仅执行居中操作", "任务") + success = center_on_dual_tracks( + ctrl, msg, + max_time=args.max_time, + observe=True, + stone_path_mode=stone_path_mode + ) + + # 显示结果 + if success: + success("测试成功完成", "结果") + else: + warning("测试未完全成功", "结果") + + # 清理资源 + ctrl.cleanup() + + except KeyboardInterrupt: + warning("用户中断测试", "中断") + except Exception as e: + error(f"测试过程中发生异常: {str(e)}", "异常") + + section("双轨道线居中测试", "结束") + +if __name__ == "__main__": + main() \ No newline at end of file