diff --git a/src/Robotic_arm/main.py b/src/Robotic_arm/main.py index 27818121d4..5146c30326 100644 --- a/src/Robotic_arm/main.py +++ b/src/Robotic_arm/main.py @@ -1,13 +1,8 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ -机械臂关节刚度与可靠性优化控制器 -核心优化: -1. 关节刚度分层配置+自适应调节(负载/误差驱动) -2. 全方位可靠性保障(卡死检测/过载保护/异常复位/容错处理) -3. 刚度-阻尼-惯量匹配优化,降低振动与干扰 -4. 全状态监控与日志记录,便于故障追溯 -5. 兼容新旧Mujoco版本,无XML语法错误 +机械臂关节精度性能优化控制器(修复geom标签viscous属性错误版) +核心修复:移除geom标签无效viscous属性,迁移至joint标签damping属性,保证XML Schema合规 """ import sys @@ -20,8 +15,8 @@ import mujoco from datetime import datetime -# ====================== 全局配置(刚度+可靠性专用) ====================== -# 系统适配(Windows优先,极致CPU优化) +# ====================== 全局配置(精度优化专用) ====================== +# 系统适配(Windows优先,降低系统干扰影响精度) if os.name == 'nt': try: kernel32 = ctypes.windll.kernel32 @@ -30,7 +25,7 @@ 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' @@ -48,81 +43,109 @@ print(f"⚠️ Mujoco Viewer导入失败(无法可视化): {e}") # 核心参数配置 -# 关节基础配置(按重要性分层:1>2>3>4>5) JOINT_COUNT = 5 JOINT_NAMES = ["joint1", "joint2", "joint3", "joint4", "joint5"] JOINT_LIMITS_RAD = np.array([ - [-np.pi, np.pi], # joint1(基座,最高刚度) - [-np.pi / 2, np.pi / 2], # joint2(大臂,高刚度) - [-np.pi / 2, np.pi / 2], # joint3(中臂,中高刚度) - [-np.pi / 2, np.pi / 2], # joint4(小臂,中刚度) - [-np.pi / 2, np.pi / 2], # joint5(末端,低刚度) + [-np.pi, np.pi], # joint1(基座) + [-np.pi / 2, np.pi / 2], # joint2(大臂) + [-np.pi / 2, np.pi / 2], # joint3(中臂) + [-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_TORQUE = np.array([15.0, 12.0, 10.0, 8.0, 5.0], 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, # 刚度变化平滑系数,防止突变 + '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, } -# 阻尼与惯量匹配配置(刚度配套优化,提升可靠性) +# 阻尼与惯量配置(优化:将粘性摩擦参数整合至joint damping) DAMPING_INERTIA_PARAMS = { - 'base_damping': np.array([8.0, 7.0, 6.0, 5.0, 3.0]), # 基准阻尼(与刚度匹配) - 'damping_stiffness_ratio': 0.04, # 阻尼-刚度匹配比,保证运动平稳 - 'armature_inertia': np.array([0.5, 0.4, 0.3, 0.2, 0.1]), # 关节惯量补偿 + '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]), } -# 仿真配置(可靠性优化:小步长提升控制稳定性) -SIMULATION_TIMESTEP = 0.001 # 更小步长,降低控制误差 -CONTROL_FREQUENCY = 1000 # 更高控制频率,提升响应可靠性 +# 仿真配置(精度优化:更小步长+更高控制频率,提升控制分辨率) +SIMULATION_TIMESTEP = 0.0005 # 微步长,降低离散化误差 +CONTROL_FREQUENCY = 2000 # 高频控制,提升响应精度 CONTROL_TIMESTEP = 1.0 / CONTROL_FREQUENCY FPS = 60 SLEEP_TIME = 1.0 / FPS -EPS = 1e-8 +EPS = 1e-9 # 更小误差阈值,提升精度判断准确性 RUNNING = True SIMULATION_START_TIME = None -# PD控制参数(与刚度/阻尼联动) -PD_PARAMS = { - 'kp_base': 80.0, - 'kd_base': 5.0, - 'kp_load_gain': 1.5, - 'kd_load_gain': 1.2, - 'max_vel': JOINT_MAX_VELOCITY_RAD.copy() +# 高精度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() } -# 负载配置(与刚度联动优化) +# 负载配置 LOAD_PARAMS = { 'end_effector_mass': 0.5, 'joint_loads': np.zeros(JOINT_COUNT), 'max_allowed_load': 2.0, - 'load_smoothing_factor': 0.1 + '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, # 误差补偿平滑系数,避免突变 +} + +# 轨迹规划配置(精度优化:梯形速度规划参数) +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),平稳停止判定 +} + +# 精度监测配置 +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.01, # 关节卡死判定阈值(速度<此值且扭矩>90%) - '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, # 是否记录可靠性日志 - 'log_path': 'arm_reliability_log.txt' # 日志保存路径 + '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 @@ -130,9 +153,9 @@ 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 = { @@ -152,7 +175,7 @@ def get_mujoco_id(model, obj_type, name): def deg2rad(degrees): - """角度转弧度(容错增强,可靠性保障)""" + """角度转弧度(高精度转换,容错增强)""" try: degrees = np.array(degrees, dtype=np.float64) return np.deg2rad(degrees) @@ -162,7 +185,7 @@ def deg2rad(degrees): def rad2deg(radians): - """弧度转角度(容错增强,可靠性保障)""" + """弧度转角度(高精度转换,容错增强)""" try: radians = np.array(radians, dtype=np.float64) return np.rad2deg(radians) @@ -171,8 +194,20 @@ def rad2deg(radians): return 0.0 if np.isscalar(radians) else np.zeros(JOINT_COUNT, dtype=np.float64) -def write_reliability_log(content, log_path=RELIABILITY_PARAMS['log_path']): - """写入可靠性日志(核心:记录异常状态,便于追溯)""" +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 try: @@ -183,95 +218,189 @@ def write_reliability_log(content, log_path=RELIABILITY_PARAMS['log_path']): print(f"⚠️ 写入可靠性日志失败: {e}") -# ====================== 机械臂模型生成(刚度配置+无XML错误) ====================== -def create_arm_model_with_stiffness(): +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: 规划的位置序列、速度序列 + """ + pos_error = target_pos - start_pos + total_distance = abs(pos_error) + if total_distance < TRAJECTORY_PLANNING_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 + + # 判定运动阶段(是否存在匀速阶段) + 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 + + t = 0.0 + while t < total_time + dt: + if t <= accel_time: + # 加速阶段 + current_vel = max_accel * t * direction + current_pos = start_pos + 0.5 * max_accel * (t ** 2) * direction + else: + # 减速阶段 + delta_t = t - accel_time + current_vel = (max_reached_vel - max_accel * delta_t) * direction + current_pos = start_pos + (max_reached_vel * accel_time - 0.5 * max_accel * (delta_t ** 2)) * direction + pos_list.append(current_pos) + vel_list.append(current_vel) + t += dt + else: + # 有匀速阶段:加速→匀速→减速 + accel_time = max_vel / max_accel + uniform_dist = total_distance - total_accel_decel_dist + uniform_time = uniform_dist / max_vel + total_time = 2 * accel_time + uniform_time + + t = 0.0 + while t < total_time + dt: + if t <= accel_time: + # 加速阶段 + current_vel = max_accel * t * direction + current_pos = start_pos + 0.5 * max_accel * (t ** 2) * direction + elif t <= accel_time + uniform_time: + # 匀速阶段 + current_vel = max_vel * direction + delta_t = t - accel_time + current_pos = start_pos + (accel_phase_dist + max_vel * delta_t) * direction + else: + # 减速阶段 + delta_t = t - (accel_time + uniform_time) + current_vel = (max_vel - max_accel * delta_t) * direction + delta_pos = accel_phase_dist - 0.5 * max_accel * (delta_t ** 2) + current_pos = start_pos + (total_distance - delta_pos) * direction + pos_list.append(current_pos) + 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(): """ - 生成带关节刚度配置的机械臂XML模型(兼容所有Mujoco版本) - 1. 按关节层级配置基准刚度、阻尼、惯量,实现刚度分层 - 2. 移除所有违规XML属性,保证无语法错误 - 3. 几何与质量配置优化,提升仿真可靠性 + 生成高精度机械臂XML模型(彻底修复Schema违规错误,兼容所有Mujoco版本) + 核心修复: + 1. 移除所有geom标签的viscous属性(该属性不被geom支持,消除Schema违规) + 2. 保留geom标签的friction属性(3个值,合法支持静摩擦功能) + 3. 将粘性摩擦需求迁移至joint标签的damping属性(合法归属),通过粘性阻尼增益补充效果 + 4. 优化joint标签的damping参数,确保与原有粘性摩擦需求一致 """ end_effector_mass = LOAD_PARAMS['end_effector_mass'] - # 连杆geom质量(兼容新旧Mujoco版本) 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'] + friction_coeffs = ERROR_COMPENSATION_PARAMS['friction_coeff'] + + # 计算最终关节阻尼(基础阻尼 + 粘性阻尼增益,等效原有viscous效果) + joint_damping = base_damping * viscous_damping_gain xml = f""" - + + -