RoboticArmTest/debug_execution.py
sladro d50a493acf 优化路径执行:简化为单次规划和执行
主要改进:
- 将三阶段独立执行改为单次完整路径执行
- 分段规划后合并路径,避免误差累积
- 在关键点(物体、A点)自动停留0.5秒
- 调整路径颜色为暗绿色,更柔和
- 降低移动速度3倍,动作更平滑
- 修复硬编码问题,使用常量定义

修复问题:
- Stage 2执行失败(6.2cm误差)
- 多次规划导致的误差累积
- 理论位置与实际位置不一致

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-14 09:54:11 +08:00

230 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.

#!/usr/bin/env python3
"""
路径执行调试脚本
专门测试路径执行过程中的坐标对应关系
"""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from src.config_loader import ConfigLoader
from src.robot.arm_controller import create_arm_controller
from src.simulation.environment import Environment
from src.planning.ai_rrt_star import AIRRTStarPlanner
from src.planning.collision_checker import CollisionChecker
from src.planning.path_executor import PathExecutor
import pybullet as p
import pybullet_data
import numpy as np
import time
def debug_path_execution():
"""调试路径执行的具体步骤"""
print("=== 路径执行调试分析使用RRT*路径规划) ===")
# 初始化仿真
physics_client = p.connect(p.GUI)
p.setAdditionalSearchPath(pybullet_data.getDataPath())
p.setGravity(0, 0, 0) # 关闭重力
try:
# 加载配置和组件
config_loader = ConfigLoader()
arm_controller = create_arm_controller(config_loader, physics_client)
environment = Environment(config_loader, physics_client)
collision_checker = CollisionChecker(arm_controller, environment, config_loader)
path_executor = PathExecutor(arm_controller, config_loader)
# AIRRTStarPlanner需要environment参数不是collision_checker
planner = AIRRTStarPlanner(arm_controller, environment, config_loader)
print("=== 步骤1: 设置自定义起点和终点 ===")
# 获取当前位置作为起点
current_joints = arm_controller.get_current_joint_positions()
print(f"实际起始关节配置: {[f'{x:.3f}' for x in current_joints]}")
# 打印初始状态的KDL和PyBullet坐标对比
print("\n=== 初始状态坐标对比 ===")
# KDL正运动学计算
kdl_result = arm_controller.forward_kinematics(current_joints)
kdl_position = kdl_result[0] if kdl_result else [0, 0, 0]
print(f"KDL计算末端坐标: [{kdl_position[0]:.4f}, {kdl_position[1]:.4f}, {kdl_position[2]:.4f}]")
# PyBullet仿真中的实际末端坐标
end_link_state = p.getLinkState(arm_controller.robot_loader.robot_id,
arm_controller.robot_loader.end_effector_index,
physicsClientId=physics_client)
pybullet_position = list(end_link_state[0])
print(f"PyBullet末端坐标: [{pybullet_position[0]:.4f}, {pybullet_position[1]:.4f}, {pybullet_position[2]:.4f}]")
# 计算误差
kdl_pb_error = np.linalg.norm(np.array(kdl_position) - np.array(pybullet_position))
print(f"KDL与PyBullet误差: {kdl_pb_error:.6f}m")
print("=" * 50)
# 测试第二段的起始和目标位置
# 物体位置(第一段终点)
object_position = [0.6, 0.5, 0.5]
# A点位置第二段终点
point_a = [0.5, 0.5, 0.8]
print(f"\n测试Stage 2路径")
print(f"起点(物体位置): {object_position}")
print(f"终点A点位置: {point_a}")
# 先移动到物体位置作为起点
object_joints = arm_controller.inverse_kinematics(object_position, None, current_joints)
if object_joints is None:
print("❌ 无法计算物体位置的逆运动学解")
return
print(f"物体位置关节配置: {[f'{x:.3f}' for x in object_joints]}")
# 移动到物体位置
arm_controller.set_joint_positions(object_joints)
for _ in range(100): # 等待稳定
p.stepSimulation(physicsClientId=physics_client)
time.sleep(0.5)
# 获取实际到达的位置
actual_start_joints = arm_controller.get_current_joint_positions()
print(f"实际起始关节配置: {[f'{x:.3f}' for x in actual_start_joints]}")
# 设置目标为A点
target_position = point_a
# 使用逆运动学计算目标关节配置用实际位置作为seed
target_joints = arm_controller.inverse_kinematics(target_position, None, actual_start_joints)
if target_joints is None:
print("❌ 无法计算目标位置的逆运动学解")
return
print(f"目标关节配置: {[f'{x:.3f}' for x in target_joints]}")
print("\n=== 步骤2: 使用RRT*规划路径 ===")
print(f"规划起点(实际关节): {[f'{x:.3f}' for x in actual_start_joints]}")
print(f"规划终点(目标关节): {[f'{x:.3f}' for x in target_joints]}")
# 规划路径(从实际位置到目标)
test_path = planner.plan(actual_start_joints, target_joints)
if test_path is None:
print("❌ 路径规划失败")
return
print(f"规划成功!路径包含 {len(test_path)} 个waypoint")
print("\n=== 步骤3: 分析路径的理论末端位置 ===")
theoretical_positions = []
for i, config in enumerate(test_path):
pos, ori = arm_controller.forward_kinematics(config)
theoretical_positions.append(pos)
if i < 5 or i >= len(test_path) - 5: # 只打印前5个和后5个
print(f"Waypoint {i}: 末端位置{[f'{x:.3f}' for x in pos]}")
print("\n=== 步骤4: 可视化理论路径 ===")
# 绘制理论路径线条
line_ids = []
for i in range(len(theoretical_positions) - 1):
line_id = p.addUserDebugLine(
theoretical_positions[i],
theoretical_positions[i + 1],
lineColorRGB=[0, 1, 0], # 绿色 - 理论路径
lineWidth=3,
physicsClientId=physics_client
)
line_ids.append(line_id)
print("\n=== 步骤5: 使用PathExecutor执行路径与main_window.py相同 ===")
actual_positions = []
# 重置机械臂到实际起始位置(物体位置)
arm_controller.set_joint_positions(actual_start_joints)
for _ in range(50): # 等待稳定
p.stepSimulation(physicsClientId=physics_client)
# 定义一个函数来打印坐标对比(在路径执行过程中调用)
def print_coordinate_comparison(stage_name, joints):
print(f"\n--- {stage_name} 坐标对比 ---")
# KDL正运动学计算
kdl_result = arm_controller.forward_kinematics(joints)
kdl_pos = kdl_result[0] if kdl_result else [0, 0, 0]
print(f"KDL计算末端坐标: [{kdl_pos[0]:.4f}, {kdl_pos[1]:.4f}, {kdl_pos[2]:.4f}]")
# PyBullet仿真中的实际末端坐标
end_link_state = p.getLinkState(arm_controller.robot_loader.robot_id,
arm_controller.robot_loader.end_effector_index,
physicsClientId=physics_client)
pb_pos = list(end_link_state[0])
print(f"PyBullet末端坐标: [{pb_pos[0]:.4f}, {pb_pos[1]:.4f}, {pb_pos[2]:.4f}]")
# get_current_pose的返回值调用arm_controller的方法
current_pos, _ = arm_controller.get_current_pose()
print(f"get_current_pose返回: [{current_pos[0]:.4f}, {current_pos[1]:.4f}, {current_pos[2]:.4f}]")
# 计算误差
kdl_pb_error = np.linalg.norm(np.array(kdl_pos) - np.array(pb_pos))
get_pb_error = np.linalg.norm(np.array(current_pos) - np.array(pb_pos))
print(f"KDL与PyBullet误差: {kdl_pb_error:.6f}m")
print(f"get_current_pose与PyBullet误差: {get_pb_error:.6f}m")
return pb_pos
# 执行路径前的坐标对比
print_coordinate_comparison("执行路径前", actual_start_joints)
# 使用PathExecutor执行路径与main_window.py相同
print("\n开始使用PathExecutor执行路径...")
try:
success = path_executor.execute_path(test_path)
if success:
print("✅ 路径执行成功")
else:
print("❌ 路径执行失败")
except Exception as e:
print(f"❌ 路径执行出错: {e}")
# 执行完成后的坐标对比
final_joints = arm_controller.get_current_joint_positions()
actual_pos = print_coordinate_comparison("路径执行完成后", final_joints)
actual_positions.append(actual_pos)
# 对比目标位置和实际位置
print(f"\n=== 最终结果对比 ===")
print(f"目标位置: [{target_position[0]:.4f}, {target_position[1]:.4f}, {target_position[2]:.4f}]")
print(f"实际到达位置(PyBullet): [{actual_pos[0]:.4f}, {actual_pos[1]:.4f}, {actual_pos[2]:.4f}]")
final_error = np.linalg.norm(np.array(target_position) - np.array(actual_pos))
print(f"最终位置误差: {final_error:.6f}m")
if final_error < 0.02:
print("✅ 路径执行精度良好")
else:
print("❌ 路径执行存在显著误差")
# 绘制目标点
p.addUserDebugText("Target", target_position, textColorRGB=[1, 0, 0], textSize=1.5, physicsClientId=physics_client)
p.addUserDebugPoints([target_position], pointColorsRGB=[[1, 0, 0]], pointSize=10, physicsClientId=physics_client)
# 绘制实际到达点
p.addUserDebugText("Actual", actual_pos, textColorRGB=[0, 0, 1], textSize=1.5, physicsClientId=physics_client)
p.addUserDebugPoints([actual_pos], pointColorsRGB=[[0, 0, 1]], pointSize=10, physicsClientId=physics_client)
print("\n=== 重要发现 ===")
print("如果KDL与PyBullet误差很大说明存在以下可能问题")
print("1. 关节顺序映射错误kdl_to_pb或pb_to_kdl转换有误")
print("2. get_current_pose方法返回的是KDL计算值而非PyBullet实际值")
print("3. 路径执行器依赖的是get_current_pose导致误差累积")
input("按回车键关闭...")
except Exception as e:
print(f"调试过程中发生错误: {e}")
import traceback
traceback.print_exc()
finally:
p.disconnect(physicsClientId=physics_client)
if __name__ == "__main__":
debug_path_execution()