diff --git a/src/Robotic_arm/main.py b/src/Robotic_arm/main.py index 5146c30326..4185cee6e0 100644 --- a/src/Robotic_arm/main.py +++ b/src/Robotic_arm/main.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ -机械臂关节精度性能优化控制器(修复geom标签viscous属性错误版) -核心修复:移除geom标签无效viscous属性,迁移至joint标签damping属性,保证XML Schema合规 +机械臂关节运动性能优化控制器 +核心优化:定位精度、运动平滑性、负载抗干扰、刚度阻尼自适应 +兼容Mujoco仿真,修复geom/ joint属性违规问题 """ import sys @@ -15,22 +16,22 @@ import mujoco from datetime import datetime -# ====================== 全局配置(精度优化专用) ====================== -# 系统适配(Windows优先,降低系统干扰影响精度) +# ====================== 全局配置(性能优化核心参数) ====================== +# 系统适配与性能优化(降低干扰,提升控制实时性) if os.name == 'nt': try: kernel32 = ctypes.windll.kernel32 kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7) os.system('chcp 65001 >nul 2>&1') - kernel32.SetThreadPriority(kernel32.GetCurrentThread(), 1) + kernel32.SetThreadPriority(kernel32.GetCurrentThread(), 1) # 提升线程优先级 except Exception as e: print(f"⚠️ Windows系统优化失败(不影响核心功能): {e}") - # 强制单线程,避免多线程竞争导致控制延迟,影响精度 - os.environ['OMP_NUM_THREADS'] = '1' - os.environ['MKL_NUM_THREADS'] = '1' - os.environ['NUMEXPR_NUM_THREADS'] = '1' +# 强制单线程,避免多线程竞争导致控制延迟 +os.environ['OMP_NUM_THREADS'] = '1' +os.environ['MKL_NUM_THREADS'] = '1' +os.environ['NUMEXPR_NUM_THREADS'] = '1' -# Mujoco Viewer兼容 +# Mujoco Viewer兼容配置 MUJOCO_NEW_VIEWER = False try: from mujoco import viewer @@ -42,9 +43,10 @@ except ImportError as e: print(f"⚠️ Mujoco Viewer导入失败(无法可视化): {e}") -# 核心参数配置 +# 关节基础参数(5自由度机械臂,可按需扩展) JOINT_COUNT = 5 JOINT_NAMES = ["joint1", "joint2", "joint3", "joint4", "joint5"] +# 关节角度限制(rad) JOINT_LIMITS_RAD = np.array([ [-np.pi, np.pi], # joint1(基座) [-np.pi / 2, np.pi / 2], # joint2(大臂) @@ -52,100 +54,72 @@ [-np.pi / 2, np.pi / 2], # joint4(小臂) [-np.pi / 2, np.pi / 2], # joint5(末端) ], dtype=np.float64) +# 关节运动性能限制(避免超调与过载) JOINT_MAX_VELOCITY_RAD = np.array([1.0, 0.8, 0.8, 0.6, 0.6], dtype=np.float64) -JOINT_MAX_ACCEL_RAD = np.array([2.0, 1.6, 1.6, 1.2, 1.2], dtype=np.float64) # 最大加速度(精度优化:限制加减速避免超调) +JOINT_MAX_ACCEL_RAD = np.array([2.0, 1.6, 1.6, 1.2, 1.2], dtype=np.float64) JOINT_MAX_TORQUE = np.array([15.0, 12.0, 10.0, 8.0, 5.0], dtype=np.float64) -# 刚度配置(兼容之前的优化,不影响精度) +# 刚度自适应配置(提升定位精度与抗干扰能力) STIFFNESS_PARAMS = { 'base_stiffness': np.array([200.0, 180.0, 150.0, 120.0, 80.0]), 'load_stiffness_gain': 1.8, 'error_stiffness_gain': 1.5, 'min_stiffness': np.array([100.0, 90.0, 75.0, 60.0, 40.0]), 'max_stiffness': np.array([300.0, 270.0, 225.0, 180.0, 120.0]), - 'stiffness_smoothing': 0.05, + 'stiffness_smoothing': 0.05, # 刚度平滑更新,避免运动抖动 } -# 阻尼与惯量配置(优化:将粘性摩擦参数整合至joint damping) -DAMPING_INERTIA_PARAMS = { - 'base_damping': np.array([8.0, 7.0, 6.0, 5.0, 3.0]), # 基础阻尼(对应原粘性摩擦需求) - 'viscous_damping_gain': np.array([1.2, 1.1, 1.1, 1.0, 1.0]), # 粘性阻尼增益,补充原有viscous效果 - 'damping_stiffness_ratio': 0.04, - 'armature_inertia': np.array([0.5, 0.4, 0.3, 0.2, 0.1]), +# 阻尼自适应配置(粘性阻尼整合,提升运动平滑性) +DAMPING_PARAMS = { + 'base_damping': np.array([8.0, 7.0, 6.0, 5.0, 3.0]), # 基础阻尼 + 'viscous_damping_gain': np.array([1.2, 1.1, 1.1, 1.0, 1.0]), # 粘性阻尼增益 + 'damping_stiffness_ratio': 0.04, # 阻尼与刚度匹配系数 + 'min_damping': np.array([4.0, 3.5, 3.0, 2.5, 1.5]), + 'max_damping': np.array([16.0, 14.0, 12.0, 10.0, 6.0]), } -# 仿真配置(精度优化:更小步长+更高控制频率,提升控制分辨率) -SIMULATION_TIMESTEP = 0.0005 # 微步长,降低离散化误差 -CONTROL_FREQUENCY = 2000 # 高频控制,提升响应精度 +# 仿真与控制性能配置(高频控制提升精度,微步长降低离散误差) +SIMULATION_TIMESTEP = 0.0005 # 仿真微步长 +CONTROL_FREQUENCY = 2000 # 控制频率(2000Hz,高频实时控制) CONTROL_TIMESTEP = 1.0 / CONTROL_FREQUENCY -FPS = 60 +FPS = 60 # 可视化帧率(不影响控制性能) SLEEP_TIME = 1.0 / FPS -EPS = 1e-9 # 更小误差阈值,提升精度判断准确性 -RUNNING = True -SIMULATION_START_TIME = None - -# 高精度PD+前馈控制参数(核心精度优化) -PRECISION_PD_PARAMS = { - 'kp_base': 120.0, # 更高比例增益,提升静态定位精度 - 'kd_base': 8.0, # 优化阻尼增益,抑制振动超调 - 'kp_load_gain': 1.8, # 负载下增益放大,维持精度 - 'kd_load_gain': 1.5, # 负载下阻尼优化,防止震荡 - 'ff_gain': 0.7, # 前馈增益,补偿动态误差 - 'max_vel': JOINT_MAX_VELOCITY_RAD.copy(), - 'max_accel': JOINT_MAX_ACCEL_RAD.copy() +RUNNING = True # 仿真运行标志 + +# PD+前馈控制参数(核心运动精度优化) +PD_FEEDFORWARD_PARAMS = { + 'kp_base': 120.0, # 比例增益(提升静态定位精度) + 'kd_base': 8.0, # 微分增益(抑制运动振动) + 'kp_load_gain': 1.8, # 负载下比例增益放大 + 'kd_load_gain': 1.5, # 负载下微分增益放大 + 'ff_vel_gain': 0.7, # 速度前馈增益(补偿动态误差) + 'ff_accel_gain': 0.5, # 加速度前馈增益(提升动态响应) } -# 负载配置 -LOAD_PARAMS = { - 'end_effector_mass': 0.5, - 'joint_loads': np.zeros(JOINT_COUNT), - 'max_allowed_load': 2.0, - 'load_smoothing_factor': 0.05 # 更小平滑系数,提升负载检测精度 -} - -# 误差补偿配置(核心精度优化:移除geom的viscous配置,保留摩擦系数用于误差计算) +# 误差补偿配置(多维度补偿,消除系统误差) ERROR_COMPENSATION_PARAMS = { - 'backlash_error': np.array([0.001, 0.001, 0.002, 0.002, 0.003]), # 关节间隙误差(rad) - 'friction_coeff': np.array([0.1, 0.08, 0.08, 0.06, 0.06]), # 静摩擦力系数(仅用于误差补偿计算) - 'gravity_compensation': True, # 是否启用重力误差补偿 - 'comp_smoothing': 0.02, # 误差补偿平滑系数,避免突变 + 'backlash_error': np.array([0.001, 0.001, 0.002, 0.002, 0.003]), # 关节间隙误差 + 'friction_coeff': np.array([0.1, 0.08, 0.08, 0.06, 0.06]), # 静摩擦系数 + 'gravity_compensation': True, # 重力误差补偿 + 'comp_smoothing': 0.02, # 补偿量平滑 } -# 轨迹规划配置(精度优化:梯形速度规划参数) -TRAJECTORY_PLANNING_PARAMS = { - 'traj_type': 'trapezoidal', # 梯形速度规划,无超调 - 'acceleration_time': 0.2, # 加速时间 - 'deceleration_time': 0.2, # 减速时间 - 'position_tol': 1e-5, # 位置公差(rad),高精度定位判定 - 'velocity_tol': 1e-4 # 速度公差(rad/s),平稳停止判定 +# 轨迹规划配置(梯形速度规划,无超调平滑运动) +TRAJECTORY_PARAMS = { + 'traj_type': 'trapezoidal', + 'position_tol': 1e-5, # 位置公差(高精度定位判定) + 'velocity_tol': 1e-4, # 速度公差(平稳停止判定) + 'accel_time_ratio': 0.2, # 加速时间占比 + 'decel_time_ratio': 0.2, # 减速时间占比 } -# 精度监测配置 -PRECISION_MONITOR_PARAMS = { - 'log_precision_data': True, - 'log_path': 'arm_joint_precision_log.txt', - 'max_allowed_position_error': np.deg2rad(0.1), # 最大允许定位误差(0.1度) - 'max_allowed_trajectory_error': np.deg2rad(0.2) # 最大允许轨迹跟踪误差(0.2度) -} -# 可靠性配置(兼容之前的优化) -RELIABILITY_PARAMS = { - 'stall_detection_threshold': 0.005, # 更高灵敏度,提升异常检测精度 - 'stall_duration_threshold': 1.0, - 'overload_duration_threshold': 2.0, - 'max_angle_error': np.deg2rad(10.0), - 'auto_reset_on_error': True, - 'log_reliability_data': True, - 'reliability_log_path': 'arm_reliability_log.txt' -} - - -# ====================== 信号处理(优雅退出,避免精度数据丢失) ====================== +# ====================== 信号处理(优雅退出,保护数据) ====================== def signal_handler(sig, frame): global RUNNING if not RUNNING: sys.exit(0) - print("\n⚠️ 收到退出信号,正在优雅退出(保存精度日志+清理资源)...") + print("\n⚠️ 收到退出信号,正在优雅退出(保存日志+清理资源)...") RUNNING = False @@ -153,24 +127,22 @@ def signal_handler(sig, frame): signal.signal(signal.SIGTERM, signal_handler) -# ====================== 工具函数(精度优化专用) ====================== +# ====================== 工具函数(性能优化辅助) ====================== def get_mujoco_id(model, obj_type, name): - """兼容所有Mujoco版本的ID查询(容错增强,提升精度稳定性)""" + """兼容Mujoco版本的ID查询,提升代码鲁棒性""" if model is None: return -1 type_map = { 'joint': mujoco.mjtObj.mjOBJ_JOINT, 'actuator': mujoco.mjtObj.mjOBJ_ACTUATOR, 'site': mujoco.mjtObj.mjOBJ_SITE, - 'body': mujoco.mjtObj.mjOBJ_BODY, 'geom': mujoco.mjtObj.mjOBJ_GEOM } obj_type_int = type_map.get(obj_type, mujoco.mjtObj.mjOBJ_JOINT) try: - obj_id = mujoco.mj_name2id(model, int(obj_type_int), str(name)) - return obj_id if obj_id >= 0 else -1 + return mujoco.mj_name2id(model, int(obj_type_int), str(name)) except Exception as e: - print(f"⚠️ 查询{obj_type} {name} ID失败: {e}") + print(f"⚠️ 查询{obj_type} {name} ID失败: {e}") return -1 @@ -180,7 +152,7 @@ def deg2rad(degrees): degrees = np.array(degrees, dtype=np.float64) return np.deg2rad(degrees) except Exception as e: - print(f"⚠️ 角度转换失败: {e}") + print(f"⚠️ 角度转换失败: {e}") return 0.0 if np.isscalar(degrees) else np.zeros(JOINT_COUNT, dtype=np.float64) @@ -190,63 +162,48 @@ def rad2deg(radians): radians = np.array(radians, dtype=np.float64) return np.rad2deg(radians) except Exception as e: - print(f"⚠️ 弧度转换失败: {e}") + print(f"⚠️ 弧度转换失败: {e}") return 0.0 if np.isscalar(radians) else np.zeros(JOINT_COUNT, dtype=np.float64) -def write_precision_log(content, log_path=PRECISION_MONITOR_PARAMS['log_path']): - """写入精度日志(记录误差数据,便于精度分析与优化)""" - if not PRECISION_MONITOR_PARAMS['log_precision_data']: - return - try: - with open(log_path, 'a', encoding='utf-8') as f: - timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] # 毫秒级时间戳,提升日志精度 - f.write(f"[{timestamp}] {content}\n") - except Exception as e: - print(f"⚠️ 写入精度日志失败: {e}") - - -def write_reliability_log(content, log_path=RELIABILITY_PARAMS['reliability_log_path']): - """写入可靠性日志(兼容之前的优化)""" - if not RELIABILITY_PARAMS['log_reliability_data']: - return +def write_perf_log(content, log_path="arm_joint_perf.log"): + """写入运动性能日志,便于后续分析优化""" try: with open(log_path, 'a', encoding='utf-8') as f: - timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] f.write(f"[{timestamp}] {content}\n") except Exception as e: - print(f"⚠️ 写入可靠性日志失败: {e}") + print(f"⚠️ 写入性能日志失败: {e}") def trapezoidal_velocity_planner(start_pos, target_pos, max_vel, max_accel, dt): """ - 梯形速度规划(精度优化核心:无超调平滑轨迹生成) + 梯形速度轨迹规划(核心平滑运动优化,无超调) :param start_pos: 起始位置(rad) :param target_pos: 目标位置(rad) :param max_vel: 最大速度(rad/s) :param max_accel: 最大加速度(rad/s²) :param dt: 时间步长(s) - :return: 规划的位置序列、速度序列 + :return: 规划位置序列、速度序列 """ pos_error = target_pos - start_pos total_distance = abs(pos_error) - if total_distance < TRAJECTORY_PLANNING_PARAMS['position_tol']: + if total_distance < TRAJECTORY_PARAMS['position_tol']: return np.array([target_pos]), np.array([0.0]) - # 计算梯形速度规划关键参数 + # 计算梯形轨迹关键参数 accel_phase_vel = max_vel accel_phase_dist = (accel_phase_vel ** 2) / (2 * max_accel) total_accel_decel_dist = 2 * accel_phase_dist + direction = np.sign(pos_error) - # 判定运动阶段(是否存在匀速阶段) pos_list = [] vel_list = [] current_pos = start_pos current_vel = 0.0 - direction = np.sign(pos_error) if total_distance <= total_accel_decel_dist: - # 无匀速阶段:加速到最大速度前即开始减速 + # 无匀速阶段:加速后立即减速 max_reached_vel = np.sqrt(total_distance * max_accel) accel_time = max_reached_vel / max_accel total_time = 2 * accel_time @@ -293,116 +250,82 @@ def trapezoidal_velocity_planner(start_pos, target_pos, max_vel, max_accel, dt): vel_list.append(current_vel) t += dt - # 最后强制设置为目标位置,消除累积误差 + # 强制收尾,消除累积误差 pos_list[-1] = target_pos vel_list[-1] = 0.0 return np.array(pos_list), np.array(vel_list) -# ====================== 机械臂模型生成(修复geom标签viscous属性,高精度配置) ====================== -def create_arm_model_with_precision(): +# ====================== 机械臂模型生成(性能优化+合规配置) ====================== +def create_arm_model(): """ - 生成高精度机械臂XML模型(彻底修复Schema违规错误,兼容所有Mujoco版本) - 核心修复: - 1. 移除所有geom标签的viscous属性(该属性不被geom支持,消除Schema违规) - 2. 保留geom标签的friction属性(3个值,合法支持静摩擦功能) - 3. 将粘性摩擦需求迁移至joint标签的damping属性(合法归属),通过粘性阻尼增益补充效果 - 4. 优化joint标签的damping参数,确保与原有粘性摩擦需求一致 + 生成高性能机械臂Mujoco XML模型 + 核心优化: + 1. 移除geom无效viscous属性,消除Schema违规 + 2. joint标签配置damping,整合粘性阻尼效果 + 3. 高精度接触参数,降低运动干扰 + 4. 合理惯量配置,提升控制响应速度 """ - end_effector_mass = LOAD_PARAMS['end_effector_mass'] - link1_geom_mass = 0.8 - link2_geom_mass = 0.6 - link3_geom_mass = 0.6 - link4_geom_mass = 0.4 - link5_geom_mass = 0.2 - - base_stiffness = STIFFNESS_PARAMS['base_stiffness'] - base_damping = DAMPING_INERTIA_PARAMS['base_damping'] - viscous_damping_gain = DAMPING_INERTIA_PARAMS['viscous_damping_gain'] - armature_inertia = DAMPING_INERTIA_PARAMS['armature_inertia'] + end_effector_mass = 0.5 + link_masses = [0.8, 0.6, 0.6, 0.4, 0.2] friction_coeffs = ERROR_COMPENSATION_PARAMS['friction_coeff'] - - # 计算最终关节阻尼(基础阻尼 + 粘性阻尼增益,等效原有viscous效果) - joint_damping = base_damping * viscous_damping_gain + joint_damping = DAMPING_PARAMS['base_damping'] * DAMPING_PARAMS['viscous_damping_gain'] xml = f""" - - + -