mi-task/base_move/turn_degree.py
havoc420ubuntu 268d52155d refactor(task_2_5): simplify and restructure task execution
- Remove unused imports and simplify code structure
- Add direction parameter to run_task_2_5 function for flexibility
- Adjust turn_degree parameters for better accuracy
- Comment out unused alternative execution paths
2025-05-25 08:34:13 +00:00

247 lines
10 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
# 创建本模块特定的日志记录器
logger = get_logger("旋转控制")
def turn_degree(ctrl, msg, degree=90, absolute=False, precision=False):
"""
结合里程计实现精确稳定的旋转指定角度
参数:
ctrl: Robot_Ctrl 对象,包含里程计信息
msg: robot_control_cmd_lcmt 对象,用于发送命令
degree: 要旋转的角度正值表示逆时针负值表示顺时针默认为90度
absolute: 是否绝对角度,默认为 False
precision: 是否启用高精度模式,该模式下会使用更慢的速度和更细致的微调,默认为 False
返回:
Bool: 是否成功旋转到指定角度
"""
# 将角度转换为弧度
target_rad = math.radians(degree)
# 获取当前朝向
current_yaw = ctrl.odo_msg.rpy[2]
# 计算目标朝向
if absolute:
target_yaw = target_rad
else:
target_yaw = current_yaw + target_rad
# 标准化目标角度到 [-pi, pi] 范围
if target_yaw > math.pi:
target_yaw -= 2 * math.pi
if target_yaw < -math.pi:
target_yaw += 2 * math.pi
# 定义允许的误差范围(弧度)
# 如果是精确模式,使用更小的误差阈值
limit = 0.05
# 计算最短旋转方向和距离
def circle_dist(target, location):
value1 = abs(target - location)
value2 = 2 * math.pi - value1
direction1 = 1 if target > location else 0 # 1为逆时针0为顺时针
# 计算两个方向哪个距离更短
if value1 < value2:
return direction1, value1
else:
return 1 - direction1, value2
# 获取旋转方向和距离
direction, dist = circle_dist(target_yaw, current_yaw)
info(f"开始旋转: 当前角度={math.degrees(current_yaw):.2f}°, 目标角度={math.degrees(target_yaw):.2f}°", "旋转")
if abs(dist) > limit:
# 主要转向
const_int = 2470 # 转1.57弧度约需2470的duration值
# 精确模式下使用更小的旋转速度
turn_speed = 0.3 if precision else 0.5
# 如果角度很小且使用精确模式,进一步降低速度
if precision and abs(dist) < 0.2: # 约11.5度
turn_speed = 0.2
# 设置转向命令
msg.mode = 11 # Locomotion模式
msg.gait_id = 26 # 自变频步态
msg.vel_des = [0, 0, turn_speed if direction > 0 else -turn_speed] # 转向速度
# 精确模式下延长转向时间以保证稳定性
duration_factor = 1.2 if precision else 1.0
msg.duration = int(const_int * abs(dist) * duration_factor)
msg.step_height = [0.06, 0.06] # 抬腿高度
msg.life_count += 1
# 发送命令
ctrl.Send_cmd(msg)
debug(f"发送旋转命令:方向={'逆时针' if direction > 0 else '顺时针'}, 速度={turn_speed}, 持续时间={msg.duration}", "旋转")
# 等待转向完成
# 精确模式下增加等待时间
wait_factor = 1.3 if precision else 1.0
wait_time = 7 * abs(dist) / 1.57 * wait_factor
debug(f"等待旋转完成: {wait_time:.2f}", "时间")
# 精确模式下使用实时监控而不是固定等待时间
if abs(dist) > 0.1: # 对于较大角度
start_time = time.time()
last_yaw = current_yaw
stable_count = 0
timeout = wait_time + 3 # 增加超时保护
# 实时监控旋转进度
while time.time() - start_time < timeout:
time.sleep(0.1) # 频繁检查
current_yaw_now = ctrl.odo_msg.rpy[2]
# 计算已旋转角度
rotated = abs(current_yaw_now - last_yaw)
if rotated > math.pi:
rotated = 2 * math.pi - rotated
# 如果旋转速度很小(几乎停止)
if rotated < 0.01: # 约0.6度
stable_count += 1
else:
stable_count = 0
last_yaw = current_yaw_now
# 如果机器人稳定一段时间,认为旋转完成
if stable_count >= 3:
debug(f"检测到旋转已稳定,提前结束等待", "旋转")
break
# 每0.5秒打印一次进度
elapsed = time.time() - start_time
if int(elapsed * 2) % 2 == 0:
remaining_yaw = target_yaw - current_yaw_now
# 标准化到 [-pi, pi]
if remaining_yaw > math.pi:
remaining_yaw -= 2 * math.pi
if remaining_yaw < -math.pi:
remaining_yaw += 2 * math.pi
debug(f"旋转进度: {elapsed:.1f}s/{wait_time:.1f}s, 剩余角度: {math.degrees(remaining_yaw):.2f}°", "进度")
else:
# 非精确模式使用固定等待时间
time.sleep(wait_time)
# 获取当前角度
current_yaw = ctrl.odo_msg.rpy[2]
info(f"主要转向完成: 当前角度={math.degrees(current_yaw):.2f}°, 目标角度={math.degrees(target_yaw):.2f}°", "角度")
# 计算剩余误差
remaining_dist = target_yaw - current_yaw
if remaining_dist > math.pi:
remaining_dist -= 2 * math.pi
elif remaining_dist < -math.pi:
remaining_dist += 2 * math.pi
# 精细调整(如果误差大于限制)
if abs(remaining_dist) > limit:
warning(f"剩余误差: {math.degrees(remaining_dist):.2f}°, 需要进行微调", "角度")
# 进行微调
const_int_tiny = 1200 if not precision else 1000 # 精确模式下使用更小的系数
# 精确模式下使用更小的微调速度
fine_turn_speed = 0.3 if precision else 0.5
# 如果剩余误差很小,进一步降低速度
if abs(remaining_dist) < 0.1: # 约5.7度
fine_turn_speed = 0.15
# 设置微调命令
msg.mode = 11
msg.gait_id = 26
msg.vel_des = [0, 0, fine_turn_speed if remaining_dist > 0 else -fine_turn_speed]
# 精确模式下使用更长的微调时间
duration_factor = 1.25 if precision else 1.0
msg.duration = int(const_int_tiny * abs(remaining_dist) * duration_factor)
msg.step_height = [0.06, 0.06]
msg.life_count += 1
# 发送命令
ctrl.Send_cmd(msg)
debug(f"发送微调命令:方向={'逆时针' if remaining_dist > 0 else '顺时针'}, 速度={fine_turn_speed}, 持续时间={msg.duration}", "旋转")
# 精确模式下等待更长时间
wait_time = 5 if not precision else 7
time.sleep(wait_time)
# 获取最终角度
final_yaw = ctrl.odo_msg.rpy[2]
info(f"微调完成: 最终角度={math.degrees(final_yaw):.2f}°, 目标角度={math.degrees(target_yaw):.2f}°", "角度")
final_error = abs(target_yaw - final_yaw)
if final_error > math.pi:
final_error = 2 * math.pi - final_error
# 判断是否成功达到目标
if final_error <= limit:
success(f"旋转成功,误差在允许范围内: {math.degrees(final_error):.2f}°", "成功")
return True
else:
warning(f"旋转完成,但误差超出允许范围: {math.degrees(final_error):.2f}° > {math.degrees(limit):.2f}°", "警告")
# 在精确模式下,如果误差仍然很大,尝试第二次微调
if precision and final_error > limit * 2:
info("尝试第二次微调", "精确")
# 计算第二次微调角度
second_adj = target_yaw - final_yaw
if second_adj > math.pi:
second_adj -= 2 * math.pi
elif second_adj < -math.pi:
second_adj += 2 * math.pi
# 降低微调速度
very_fine_speed = 0.1
# 设置第二次微调命令
msg.mode = 11
msg.gait_id = 26
msg.vel_des = [0, 0, very_fine_speed if second_adj > 0 else -very_fine_speed]
msg.duration = int(800 * abs(second_adj)) # 使用更小的系数
msg.step_height = [0.06, 0.06]
msg.life_count += 1
# 发送命令
ctrl.Send_cmd(msg)
debug(f"第二次微调:旋转{math.degrees(second_adj):.2f}°", "精确")
# 等待第二次微调完成
time.sleep(3)
# 获取最终结果
final_final_yaw = ctrl.odo_msg.rpy[2]
final_final_error = abs(target_yaw - final_final_yaw)
if final_final_error > math.pi:
final_final_error = 2 * math.pi - final_final_error
if final_final_error <= limit:
success(f"第二次微调成功,最终误差: {math.degrees(final_final_error):.2f}°", "成功")
return True
else:
warning(f"两次微调后仍有误差: {math.degrees(final_final_error):.2f}°", "警告")
# 如果误差已经比第一次小,算作改进
return final_final_error < final_error
return False
success("旋转成功完成", "完成")
return True