ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

6-DOF机械臂力控实战:力/位混合控制与阻抗控制详解

6-DOF机械臂力控实战:力/位混合控制与阻抗控制详解 1. 从位置控制到力控为什么6-DOF机械臂必须跨过这道坎做过机械臂的人都有一个共同的体会让机械臂走到一个指定位置不难难的是让它“恰到好处”地接触环境。纯位置控制下机械臂只知道“我要到那里去”完全不知道“到了之后该用多大力”。一旦末端执行器碰到刚性表面位置环还在拼命消除误差力矩会瞬间飙到危险值——轻则工件划伤重则减速器过载报警。这就是6-DOF机械臂在笛卡尔空间做力/位混合控制和阻抗控制的核心动机。所谓6-DOF指的是机械臂在空间中拥有六个独立运动自由度通常对应三个位置自由度加三个姿态自由度。六个关节串联起来末端可以在三维空间里任意定位和定向。但“能到”和“能做好”是两码事尤其在装配、打磨、抛光、插拔连接器这类任务中末端必须同时满足位置约束和力约束位置控制单独扛不住。力/位混合控制Hybrid Force/Position Control和阻抗控制Impedance Control是解决这类问题的两条主流路线。前者把笛卡尔空间的六个维度拆开一部分方向做位置控制另一部分方向做力控制后者不硬拆方向而是让机械臂末端表现得像一个弹簧-阻尼-质量系统通过调节刚度、阻尼参数来间接管理接触力。两条路线各有适用场景实际项目中经常混着用。这篇文章面向的是已经上手过ROS机械臂基础控制、跑通过MoveIt或类似规划框架、但一碰到接触任务就头疼的开发者。我会从方案选型逻辑讲起把笛卡尔空间的力/位混合控制和阻抗控制的实现细节拆开配上参数计算、代码骨架和踩坑记录。无论你用的是AR3、Piper、Panda还是自研的六轴臂底层逻辑是通的。2. 方案选型力/位混合控制与阻抗控制到底怎么选2.1 两种控制范式的本质差异力/位混合控制的核心思想是“分而治之”。在笛卡尔空间中任务空间被分解为两个正交子空间位置控制子空间和力控制子空间。用一个对角矩阵S来选通S的对角线元素为1的方向做位置控制为0的方向做力控制。比如拧螺丝时沿着螺丝轴向做力控制保持恒定压紧力垂直于轴向的五个方向做位置控制保持对中。阻抗控制的思路完全不同。它不区分“哪些方向控力、哪些方向控位”而是给机械臂末端定义一个期望的动态关系末端受到外力时应该像弹簧一样产生位移像阻尼器一样消耗振动。数学上就是目标阻抗模型M_d * (x_ddot - x_d_ddot) B_d * (x_dot - x_d_dot) K_d * (x - x_d) F_ext其中M_d、B_d、K_d分别是期望的惯性、阻尼、刚度矩阵x是实际位置x_d是期望位置F_ext是环境施加的外力。控制器通过调整关节力矩让末端实际表现符合这个方程。选型的关键在于任务特性。如果任务对某些方向的位置精度要求极高同时对另一些方向的力有明确要求力/位混合控制更直接。如果任务环境刚度不确定、或者需要柔顺交互比如人机协作、不确定表面的跟踪阻抗控制更合适。2.2 什么场景下选哪种方案我整理了一张选型对照表方便你快速判断任务特征推荐方案理由轴孔装配轴向力控径向位控力/位混合控制方向约束明确可精确分配曲面打磨需要跟踪未知轮廓阻抗控制环境刚度变化大柔顺性更重要插拔连接器有明确插入方向力/位混合控制插入方向力控其余位控人机协作需要安全交互阻抗控制低刚度设置天然安全拧螺丝力矩闭环力/位混合控制旋转轴力矩控制位置约束明确擦拭桌面法向力恒定两者均可阻抗更简单阻抗参数调节直观实际项目中纯用一种方案的情况很少。我做过一个连接器插拔项目插入阶段用力/位混合控制保证对中精度插入后切换到阻抗控制吸收位置误差效果比单一方案好很多。2.3 硬件前提你的机械臂能不能做力控不是所有6-DOF机械臂都能做力控。力/位混合控制和阻抗控制都要求机械臂具备关节力矩输出能力或者至少能感知末端接触力。常见配置有三种第一种是关节力矩传感器方案每个关节内置力矩传感器能直接测量关节力矩。Panda机械臂就是这种配置力控性能最好但价格高。第二种是末端六维力/力矩传感器方案在法兰盘处安装力传感器测量末端受力。这是最常见的改造方案AR3、Piper等机械臂都可以加装。第三种是无传感器方案通过电机电流估算力矩精度最差但成本最低适合对力控精度要求不高的场景。注意如果你用的是总线舵机机械臂大多数舵机只提供位置反馈不提供力矩反馈。这种情况下做力控需要额外加装末端力传感器或者选择支持电流反馈的舵机型号。3. 笛卡尔空间力/位混合控制的实现细节3.1 任务空间分解与选择矩阵设计力/位混合控制的第一步是定义选择矩阵S。这个矩阵是6x6的对角矩阵对角线上的1表示该方向做位置控制0表示做力控制。比如Z轴方向做力控其余方向做位控S就是S diag(1, 1, 0, 1, 1, 1)但实际任务中约束方向往往不在世界坐标系的坐标轴上。比如斜面打磨力控方向是斜面的法线方向。这时候需要先做坐标变换把任务空间旋转到约束坐标系下。具体做法是定义一个约束坐标系其Z轴沿约束方向。计算该坐标系相对于世界坐标系的旋转矩阵R_c。然后选择矩阵变为S_task R_c * S * R_c^T这样就把选择矩阵从约束坐标系映射回了世界坐标系。代码实现时我通常先构造旋转矩阵再做矩阵乘法。import numpy as np def build_selection_matrix(constraint_normal, position_dims): constraint_normal: 约束方向单位向量 (3,) position_dims: 做位置控制的维度索引列表 # 构造约束坐标系 z_axis constraint_normal / np.linalg.norm(constraint_normal) # 找一个不与z轴平行的向量 if abs(z_axis[0]) 0.9: x_axis np.cross([1, 0, 0], z_axis) else: x_axis np.cross([0, 1, 0], z_axis) x_axis x_axis / np.linalg.norm(x_axis) y_axis np.cross(z_axis, x_axis) R_c np.column_stack([x_axis, y_axis, z_axis]) # 构造约束坐标系下的选择矩阵 S np.zeros((6, 6)) for i in range(6): if i in position_dims: S[i, i] 1.0 # 旋转到世界坐标系 R_6 np.zeros((6, 6)) R_6[:3, :3] R_c R_6[3:, 3:] R_c S_world R_6 S R_6.T return S_world这段代码的关键在于旋转矩阵的构造。约束坐标系的Z轴沿约束方向X轴和Y轴在约束平面内。选择矩阵在约束坐标系下是对角的旋转到世界坐标系后变成非对角矩阵但物理意义不变。3.2 力控方向的位置补偿与力指令生成力控方向上的控制逻辑和位置控制完全不同。位置控制是“误差驱动”力控制是“力误差驱动”。具体来说力控方向上的期望位置不是固定的而是根据力误差积分出来的。假设Z轴做力控期望接触力F_d实际接触力F_m。力误差e_f F_d - F_m。力控方向的位置修正量delta_z K_fp * e_f K_fi * integral(e_f)这个delta_z叠加到原始期望位置上作为位置控制器的输入。也就是说力控外环产生位置修正位置内环执行修正后的位置指令。这种“外环力控内环位控”的结构在工业中很常见因为大多数机械臂的位置环已经调好了不需要改动底层。力控参数K_fp和K_fi的整定有讲究。K_fp太大容易振荡太小响应慢。我的经验是先从纯比例开始K_fp设为环境刚度的倒数乘以一个系数。比如环境刚度约10000 N/mK_fp可以从0.0001开始试逐步增大到出现轻微振荡再回调30%。积分项K_fi用来消除稳态力误差。但积分项会引入相位滞后在接触刚度大的场景下容易不稳定。我通常把K_fi设为K_fp的0.01到0.1倍并且加积分限幅。3.3 位置控制方向的轨迹规划与约束位置控制方向上的轨迹规划和纯位置控制没有本质区别但要注意力控方向的位置修正不能破坏位置控制方向的精度。也就是说力控方向的位置补偿量应该只在力控方向上生效不能泄漏到位置控制方向。实现上力控方向的位置修正量要经过选择矩阵的“补矩阵”过滤。补矩阵S_bar I - S其中I是单位矩阵。修正量delta_x经过S_bar过滤后只保留力控方向的分量。def compute_position_correction(force_error, S, K_fp, K_fi, integral_error): # 力控方向的位置修正 delta K_fp * force_error K_fi * integral_error # 补矩阵过滤只保留力控方向 S_bar np.eye(6) - S delta_filtered S_bar delta return delta_filtered这个过滤步骤很关键。我见过有项目忘了做过滤结果力控方向的位置修正泄漏到了位置控制方向导致末端在位置控制方向上抖动精度直接崩掉。3.4 关节空间力矩映射与重力补偿笛卡尔空间算出来的控制量最终要映射到关节空间。对于力控方向需要把笛卡尔空间的期望力通过雅可比矩阵的转置映射为关节力矩tau_force J^T * F_desired其中J是机械臂的雅可比矩阵F_desired是笛卡尔空间期望力向量。这个映射关系来自虚功原理末端力做的功等于关节力矩做的功。但这里有个坑雅可比矩阵是位形相关的在奇异位形附近J^T会出问题。实际实现时我通常对雅可比矩阵做阻尼最小二乘处理或者在奇异位形附近降低力控增益。重力补偿是另一个必须处理的环节。机械臂自身重量会产生关节力矩如果不补偿力传感器读到的力包含重力分量力控精度无从谈起。重力补偿的做法是根据机械臂的动力学模型计算当前位形下各关节的重力力矩然后从电机输出力矩中减去。def gravity_compensation(q, robot_model): q: 关节角度 robot_model: 包含质量和质心信息的模型 tau_g np.zeros(len(q)) for i in range(len(q)): # 计算第i个关节之后所有连杆的重力力矩 for j in range(i, len(q)): # 获取连杆j的质心位置和重量 com robot_model.get_link_com(q, j) mass robot_model.get_link_mass(j) # 计算重力对关节i的力矩 tau_g[i] robot_model.gravity_torque(q, i, com, mass) return tau_g实际项目中重力补偿模型不需要特别精确误差在5%以内通常可以接受。但如果你的机械臂负载变化大比如抓取不同重量的工件重力补偿模型需要包含负载质量。4. 阻抗控制的参数整定与实操要点4.1 阻抗模型的离散化实现阻抗控制的核心是让末端表现得像一个弹簧-阻尼-质量系统。连续域的阻抗方程前面已经给出但实际控制器是离散运行的需要把连续方程离散化。我用得最多的是后向差分法。设控制周期为T速度x_dot和加速度x_ddot的离散近似为x_dot[k] (x[k] - x[k-1]) / T x_ddot[k] (x[k] - 2*x[k-1] x[k-2]) / T^2代入阻抗方程整理后得到x[k]的递推公式x[k] (M_d/T^2 B_d/T K_d)^(-1) * (F_ext[k] M_d*(2*x[k-1] - x[k-2])/T^2 B_d*x[k-1]/T K_d*x_d)这个递推公式可以直接在代码里实现。M_d、B_d、K_d是6x6的对角矩阵通常取对角形式即每个方向独立设置参数。class ImpedanceController: def __init__(self, M_d, B_d, K_d, dt): self.M_d M_d self.B_d B_d self.K_d K_d self.dt dt self.x_prev None self.x_prev2 None def update(self, x_d, F_ext): if self.x_prev is None: self.x_prev x_d.copy() self.x_prev2 x_d.copy() # 计算阻抗参数矩阵 A self.M_d / self.dt**2 self.B_d / self.dt self.K_d b (F_ext self.M_d (2*self.x_prev - self.x_prev2) / self.dt**2 self.B_d self.x_prev / self.dt self.K_d x_d) x np.linalg.solve(A, b) self.x_prev2 self.x_prev.copy() self.x_prev x.copy() return x这段代码里A矩阵的求逆是每次控制周期都要做的如果M_d、B_d、K_d是常数对角矩阵可以预先算好逆矩阵省去在线求逆的开销。4.2 刚度、阻尼、惯性参数的物理意义与整定阻抗参数整定是阻抗控制最考验经验的地方。三个参数各有明确的物理意义刚度K_d决定末端“有多硬”。K_d越大末端越不容易被推动位置跟踪越准但接触力越大。K_d越小末端越柔顺接触力越小但位置精度越差。对于精密装配K_d通常设在1000到5000 N/m对于人机协作K_d设在100到500 N/m。阻尼B_d决定末端“有多黏”。B_d越大振动衰减越快但响应变慢。B_d太小会导致末端在接触时振荡。工程上常用临界阻尼比来整定B_d 2 * sqrt(K_d * M_d)。实际取值在临界阻尼的0.7到1.5倍之间。惯性M_d决定末端“有多重”。M_d越大末端对外力的加速度响应越慢运动越平滑。M_d太小会导致高频抖动。通常M_d取机械臂末端等效质量的一半到两倍。我整理了一个参数整定速查表场景K_d (N/m)B_d (N·s/m)M_d (kg)说明精密装配3000-5000100-2001-3高刚度位置精度优先曲面跟踪500-150030-800.5-2中等刚度兼顾跟踪和柔顺人机协作100-50010-400.5-1.5低刚度安全优先插拔连接器1000-200050-1001-2中等刚度吸收位置误差整定顺序建议先设M_d为末端等效质量再根据期望刚度设K_d最后按临界阻尼公式算B_d。然后微调如果接触时振荡增大B_d或减小K_d如果响应太慢减小B_d或增大K_d。4.3 环境刚度估计与自适应调整阻抗控制的一个难点是环境刚度未知。如果环境刚度远大于K_d末端几乎推不动力控效果差如果环境刚度远小于K_d末端一碰就飞容易失稳。解决办法是在线估计环境刚度。最简单的方法是用力/位移数据做递推最小二乘K_env F_ext / (x - x_env)其中x_env是环境未变形时的位置。实际实现时在接触瞬间记录位置x_contact之后每次采样计算K_env的估计值用低通滤波平滑。class EnvironmentStiffnessEstimator: def __init__(self, alpha0.1): self.alpha alpha self.K_env None self.x_contact None def update(self, x, F_ext): if self.x_contact is None and np.linalg.norm(F_ext) 1.0: self.x_contact x.copy() return if self.x_contact is not None: delta_x x - self.x_contact if np.linalg.norm(delta_x) 1e-6: K_new np.linalg.norm(F_ext) / np.linalg.norm(delta_x) if self.K_env is None: self.K_env K_new else: self.K_env (1 - self.alpha) * self.K_env self.alpha * K_new有了环境刚度估计就可以自适应调整阻抗参数。常用的策略是让K_d正比于K_env的平方根这样在不同刚度环境下都能保持稳定的接触力。4.4 从笛卡尔空间到关节空间的力矩映射阻抗控制器输出的是笛卡尔空间的期望位置x但机械臂需要的是关节力矩。这里有两种实现路径第一种是位置型阻抗控制把x作为位置指令发给关节位置控制器由位置控制器驱动机械臂。这种方案实现简单但阻抗特性受位置控制器带宽限制柔顺效果打折扣。第二种是力矩型阻抗控制直接计算笛卡尔空间的期望力F K_d*(x - x_d) B_d*(x_dot - x_d_dot)然后通过J^T映射为关节力矩。这种方案阻抗特性更准确但需要关节力矩控制接口。我两种都做过。位置型方案在UR系列机械臂上效果不错因为UR的位置控制器带宽够高。力矩型方案在Panda上效果更好因为Panda支持关节力矩直接控制。力矩映射的代码骨架def impedance_torque_control(x, x_dot, x_d, x_d_dot, F_ext, J, robot_model): # 计算笛卡尔空间期望力 F_desired K_d (x_d - x) B_d (x_d_dot - x_dot) F_ext # 映射到关节力矩 tau J.T F_desired # 加上重力补偿 tau gravity_compensation(q, robot_model) return tau注意F_ext的符号。如果力传感器测量的是环境施加在末端上的力那么阻抗控制器需要产生一个相反的力来平衡。实际调试时先不加F_ext项让机械臂在自由空间运动确认阻抗特性正常后再加接触力项。5. 实操过程从零搭建力控系统的完整流程5.1 硬件连接与传感器标定假设你用的是末端六维力传感器方案。第一步是机械安装力传感器安装在机械臂法兰和末端执行器之间。安装时要注意传感器的坐标系方向通常传感器侧面有标记X轴和Y轴在法兰平面内Z轴沿法兰轴向。第二步是电气连接力传感器通过网线或串口连接到控制电脑。大多数力传感器厂商提供ROS驱动包配置好IP和端口就能读到数据。第三步是传感器标定。标定分两步零点标定和重力补偿标定。零点标定很简单机械臂末端悬空不接触任何物体采集1000个样本取平均作为零点偏移。但要注意零点标定必须在机械臂上电且温度稳定后进行力传感器对温度漂移敏感。重力补偿标定复杂一些。机械臂末端安装好工具后让机械臂在多个姿态下静止记录每个姿态下的力传感器读数和对应的关节角度。然后用最小二乘拟合出工具的重力和质心位置。def calibrate_gravity(poses, force_readings): poses: 每个姿态的旋转矩阵列表 force_readings: 每个姿态的力读数列表 A [] b [] for R, F in zip(poses, force_readings): # F R * G offset A.append(np.hstack([R, np.eye(3)])) b.append(F) A np.vstack(A) b np.hstack(b) # 最小二乘求解 x, _, _, _ np.linalg.lstsq(A, b, rcondNone) gravity x[:3] offset x[3:] return gravity, offset标定完成后每次读取力传感器数据都要先减去重力分量和零点偏移得到真实的接触力。5.2 ROS节点架构与话题设计我习惯把力控系统拆成几个独立的ROS节点每个节点负责一个明确的功能force_sensor_node读取力传感器原始数据发布/force_sensor/raw话题gravity_compensation_node订阅原始数据和关节角度发布补偿后的接触力到/force_sensor/compensatedhybrid_controller_node订阅补偿后的力和当前位姿计算位置修正量发布到/cartesian_correctionimpedance_controller_node订阅补偿后的力和当前位姿计算阻抗控制输出发布到/cartesian_impedance_outputrobot_interface_node订阅修正量或阻抗输出通过J^T映射为关节力矩发送给机械臂这种架构的好处是每个节点可以独立调试。比如你可以先单独测试力传感器节点确认数据正常后再测试重力补偿节点逐步往上搭。话题消息类型我通常自定义一个CartesianWrench消息包含力和力矩各三个分量float64 force_x float64 force_y float64 force_z float64 torque_x float64 torque_y float64 torque_z控制周期方面力控外环通常跑在100Hz到500Hz。力传感器采样率一般能到1000Hz但控制周期不需要那么快。我一般设200Hz兼顾响应速度和计算负载。5.3 控制参数调试的实操记录参数调试是最耗时的环节。我记录了一个典型项目的调试过程初始参数K_fp 0.0001K_fi 0.00001K_d 2000B_d 100M_d 1.0。第一次测试机械臂在自由空间运动正常接触刚性表面后力控方向出现明显振荡力波动范围±15N期望力20N。分析振荡说明阻尼不足或刚度太高。先把K_d从2000降到1000振荡幅度减小到±8N但仍然不收敛。第二次调整增大B_d从100到200振荡幅度降到±3N但响应变慢接触后需要约1秒才能稳定到期望力。第三次调整把K_fp从0.0001增到0.0002响应加快到0.5秒稳定但出现轻微超调。把K_fi从0.00001增到0.00005稳态误差从2N降到0.5N。最终参数K_fp 0.0002K_fi 0.00005K_d 1000B_d 200M_d 1.0。力控精度±1N响应时间0.5秒满足装配要求。这个调试过程说明一个规律先调内环阻抗参数K_d、B_d、M_d让接触稳定再调外环力控参数K_fp、K_fi提高力控精度和响应速度。顺序反了会事倍功半。5.4 从仿真到实机的迁移验证在实机上直接调力控参数风险很大一不小心就撞坏工件或机械臂。我通常先在Gazebo或Webots里做仿真验证。仿真环境搭建的要点机械臂模型要包含关节力矩接口环境模型要设置合理的接触刚度和阻尼。Gazebo里用contact标签设置接触参数刚度通常设10000到100000 N/m阻尼设10到100 N·s/m。仿真验证通过后迁移到实机时要注意几点仿真里的接触刚度和实际环境刚度往往差一个数量级所以K_d和B_d需要重新整定。仿真里的传感器没有噪声实机力传感器有噪声需要加低通滤波。仿真里的通信延迟为零实机有1到10ms的延迟控制周期要留余量。我的做法是仿真里把参数调到稳定后实机上先把所有增益降到仿真值的30%确认稳定后再逐步往上加。这个过程通常需要半天到一天。6. 常见问题与排查技巧实录6.1 力控方向振荡的排查思路力控方向振荡是最常见的问题。排查顺序如下第一步检查力传感器数据是否正常。把机械臂静止看力读数是否稳定。如果读数本身就在跳先解决传感器噪声问题。常见原因是传感器供电不稳或接地不良。第二步检查重力补偿是否准确。让机械臂在多个姿态下静止看补偿后的力读数是否接近零。如果偏差大重新做重力补偿标定。第三步检查控制周期是否稳定。用ros2 topic hz查看控制话题的发布频率如果频率波动大说明计算负载不稳定需要优化代码或提高控制周期。第四步调整阻抗参数。按前面说的顺序先增大B_d再减小K_d最后调整K_fp和K_fi。我整理了一个振荡排查速查表现象可能原因解决方法高频小幅振荡阻尼不足增大B_d低频大幅振荡刚度太高减小K_d接触瞬间冲击惯性太小增大M_d稳态力波动积分增益太大减小K_fi响应迟钝刚度太低或阻尼太大增大K_d或减小B_d力控方向漂移重力补偿不准重新标定重力6.2 接触力超调的抑制方法接触力超调是指末端刚接触环境时力瞬间超过期望值再回落。超调太大可能损坏工件。抑制超调的方法有几种第一种是接触检测与软启动。在力传感器读数超过阈值时暂停位置指令等力稳定后再启动力控。这样可以避免接触瞬间的冲击。第二种是变增益策略。接触初期用低刚度接触稳定后切换到高刚度。这样接触瞬间柔顺稳定后精度高。第三种是前馈补偿。根据环境刚度估计值提前计算接触时的期望位置偏移减少位置误差。我通常组合使用第一种和第二种。接触检测阈值设2到5N软启动时间0.2到0.5秒。变增益的切换条件用接触力误差误差小于1N时切换到高刚度。6.3 奇异位形附近的力控失稳6-DOF机械臂在奇异位形附近雅可比矩阵降秩J^T映射会出问题。表现是力控方向突然失稳关节力矩飙高。解决办法是阻尼最小二乘。把J^T替换为J^T * (J * J^T lambda^2 * I)^(-1)其中lambda是阻尼系数。lambda越大奇异位形附近越稳定但力控精度越低。def damped_pseudo_inverse(J, lambda_0.01): 阻尼最小二乘伪逆 JJT J J.T return J.T np.linalg.inv(JJT lambda_**2 * np.eye(JJT.shape[0]))lambda的取值需要权衡。太小起不到阻尼作用太大影响精度。我通常设0.01到0.1根据机械臂的奇异位形分布调整。另外在轨迹规划阶段就尽量避开奇异位形。如果任务必须经过奇异位形附近降低力控增益或者切换到纯位置控制通过奇异区域。6.4 通信延迟对力控稳定性的影响力控系统对通信延迟敏感。从力传感器采样到关节力矩输出整个链路的延迟如果超过控制周期的10%就可能引起振荡。延迟来源有几个力传感器采样延迟通常1到5ms、ROS话题传输延迟1到3ms、控制器计算延迟1到5ms、关节驱动器响应延迟1到10ms。总延迟可能到10到20ms。减小延迟的方法用实时内核跑控制节点减少调度延迟用共享内存代替网络传输减少通信延迟优化代码减少计算时间提高控制频率但要注意频率太高会放大延迟的影响。我实测下来控制周期200Hz5ms时总延迟控制在2ms以内比较稳定。如果延迟超过5ms需要降低力控增益。6.5 不同机械臂平台的适配经验不同机械臂平台的力控适配差异很大。我做过AR3、Piper和Panda三个平台记录一些经验AR3机械臂用的是步进电机关节力矩控制精度有限。做力控时位置型阻抗控制比力矩型效果好因为步进电机的位置控制比较准。力控精度约±2N适合中等精度任务。Piper机械臂用的是总线舵机支持电流反馈。通过电流估算关节力矩精度比AR3好一些。但舵机的力矩控制带宽有限阻抗参数不能设太高。力控精度约±1N。Panda机械臂用的是关节力矩传感器力控性能最好。力矩型阻抗控制效果很好力控精度能到±0.5N。但Panda的关节力矩控制接口需要额外配置不是开箱即用的。提示如果你用的是3D打印机械臂或DIY平台力控精度受机械刚度限制。3D打印件有弹性会引入额外的柔顺性阻抗参数需要相应调整。我的经验是把K_d设低一些B_d设高一些补偿机械柔性的影响。7. 从单臂到双臂力控系统的扩展思路单臂力控跑通后很自然的想法是扩展到双臂。双臂力控的难点在于协调两个机械臂同时接触同一个工件时力控目标需要协调否则会互相“打架”。我做过一个双臂装配项目两个Piper机械臂协同插拔一个连接器。控制架构是主从式主臂做力/位混合控制从臂做阻抗控制跟随主臂。主臂的力控方向是插入方向从臂的阻抗刚度设得很低只提供支撑力。双臂力控的通信要求更高。两个机械臂的控制周期必须同步否则力控会互相干扰。我用的是ROS2的实时通信控制周期1ms同步误差控制在0.1ms以内。另一个扩展方向是力控与视觉的融合。力传感器提供接触力信息视觉提供位置信息两者互补。比如在曲面跟踪任务中视觉提供粗略的曲面位置力控提供精确的法向力控制。这种融合方案我在一个打磨项目中用过效果比单用力控好很多。视觉和力控的融合架构通常是视觉节点发布曲面法线方向力控节点根据法线方向调整选择矩阵。视觉更新频率低30Hz力控频率高200Hz两者用不同的频率运行通过话题通信。8. 参数整定与调试的独家经验8.1 力控系统调试的“三步法”我总结了一个力控调试的三步法适用于大多数场景第一步静态测试。机械臂静止末端接触刚性表面手动施加外力观察力传感器读数和关节力矩输出。确认力控方向正确、重力补偿准确、无异常振荡。第二步动态测试。机械臂在力控方向上做小幅往复运动频率从0.1Hz逐步增加到1Hz。观察力跟踪误差和相位滞后。如果误差随频率增大而显著增大说明力控带宽不够需要提高控制频率或调整参数。第三步任务测试。在实际任务场景下运行完整流程记录力控精度、响应时间、稳定性。根据任务要求微调参数。这三步的顺序不能乱。静态测试没过就做动态测试问题会混在一起很难定位。8.2 力传感器选型与安装的注意事项力传感器选型要考虑量程、精度、带宽三个指标。量程方面通常选期望接触力的5到10倍。比如期望接触力20N选100N到200N量程的传感器。精度方面选满量程的0.1%到1%。带宽方面至少是控制频率的2倍200Hz控制频率需要400Hz以上带宽的传感器。安装方面力传感器要尽量靠近末端执行器减少工具重量对测量的影响。传感器和法兰之间要加绝缘垫避免电气干扰。线缆要固定好避免运动时拉扯传感器。注意力传感器对侧向力和力矩的耦合敏感。如果末端执行器有偏心负载会在传感器上产生额外的力矩。这种情况下需要做全维力补偿不能只补偿重力。8.3 控制周期与滤波器的匹配控制周期和滤波器参数需要匹配。力传感器原始数据有噪声需要低通滤波。滤波器截止频率通常设控制频率的1/5到1/10。比如200Hz控制频率滤波器截止频率设20到40Hz。滤波器阶数也有讲究。一阶滤波器相位滞后小但衰减慢。二阶滤波器衰减快但相位滞后大。我通常用二阶巴特沃斯滤波器截止频率设30Hz在200Hz控制频率下相位滞后约10度可以接受。from scipy.signal import butter, filtfilt def design_lowpass_filter(cutoff, fs, order2): nyquist fs / 2 normal_cutoff cutoff / nyquist b, a butter(order, normal_cutoff, btypelow) return b, a # 使用示例 b, a design_lowpass_filter(cutoff30, fs200, order2) force_filtered filtfilt(b, a, force_raw)注意filtfilt是零相位滤波需要离线数据。在线控制时用lfilter但会有相位滞后。如果相位滞后影响稳定性可以改用一阶滤波器。8.4 力控系统的安全保护策略力控系统必须有安全保护否则一旦失控可能造成损坏。我通常设置三层保护第一层是力限幅。力控方向的期望力不超过安全阈值通常设期望力的1.5到2倍。超过阈值时控制器自动降低增益或切换到位置控制。第二层是位置限幅。力控方向的位置修正量不超过安全范围通常设±5到10mm。超过范围时停止力控报警提示。第三层是急停。检测到异常力比如超过量程的80%或异常速度时立即切断电机使能机械臂自由停止。这三层保护在代码里都要实现不能只靠上层逻辑。我见过有项目只做了力限幅结果位置修正量累积过大机械臂撞到了限位。9. 写在最后一些踩坑之后的体会力控系统调试最耗时的不是写代码而是理解“力”和“位置”之间的耦合关系。纯位置控制下位置误差和力矩输出是解耦的力控下两者通过环境刚度耦合在一起。环境刚度一变整个系统的动态特性就变了。所以力控参数没有“一劳永逸”的整定值换一个工件、换一个环境参数可能就要重调。我的经验是先把阻抗参数调稳再调力控参数先做静态测试再做动态测试先在仿真里验证再上实机。这个顺序看起来慢实际上最快。跳过任何一步后面都要花更多时间补回来。另外力传感器是力控系统的“眼睛”它的质量直接决定力控性能。如果预算允许尽量选好的力传感器。我见过太多项目在传感器上省钱结果调试时间翻倍得不偿失。最后分享一个小技巧在力控方向上加一个很小的抖动信号比如0.5Hz、0.1mm的正弦波可以帮助系统“感知”环境刚度的变化。这个抖动幅度很小不影响任务精度但能让力控系统更快适应环境变化。我在曲面跟踪任务里用这个方法效果不错。
返回列表