力位混合控制:自然约束与人工约束、选择矩阵、力控与位控的切换逻辑

力位混合控制,这个名字听起来挺唬人的。说白了,就是让机器人一边用力干活,一边还得管好自己的位置。我最早接触这个概念是在做打磨抛光项目的时候,那时候我就想:能不能让机器人既保证接触力稳定,又不把工件给怼飞了?嗯,力位混合控制就是干这个的。

自然约束与人工约束

要理解力位混合,得先搞清楚两个概念:自然约束和人工约束。这是Mason在1981年提出来的,到现在依然是这个领域的基石。

自然约束,是环境强加给机器人的限制。你想想看,当机器人的末端执行器贴在桌面上时,它能不能往桌面里钻?不能。能不能沿着桌面法线方向自由移动?也不能。这些就是自然约束。它们由几何接触关系决定,跟你的控制算法无关。

举个例子,我在做装配任务时,轴要插入孔里。轴在孔内的径向移动就是自然约束——它被孔壁限制住了。但轴向的移动是自由的,只要你不撞到底。

人工约束,则是我们人为设定的控制目标。比如,在打磨时,我们希望法向力保持10N。这个10N不是环境强制的,是我们自己想要的。又比如,在跟踪轨迹时,我们希望切向速度是0.1m/s,这也是人工约束。

这里有个关键点:自然约束和人工约束必须互补。什么意思?

  • 在自然约束限制自由度的方向上,我们做力控
  • 在自然约束允许自由度的方向上,我们做位控

我踩过这个坑。有一次做力控抛光,我在法线方向既做了力控又做了位置限制,结果两个控制器打架,系统直接抖成筛子。后来才明白,自然约束已经限制了法向位置,你再去控制位置就是画蛇添足。

核心原则:自然约束和人工约束在同一个自由度上不能同时存在。一个自由度上,要么是自然约束(环境限制),要么是人工约束(控制目标),不能两者兼得。

选择矩阵:谁干活谁休息

选择矩阵,就是用来分配每个自由度上到底谁说了算。它是一个对角矩阵,对角线上的元素是0或1。

  • S = diag(s₁, s₂, ..., s₆),sᵢ ∈ {0, 1}
  • sᵢ = 1:这个自由度做位置控制
  • sᵢ = 0:这个自由度做力控制

等等,你可能会问:为什么1是位置控制,0是力控制?其实反过来也行,只是约定俗成。我个人习惯用1表示位置控制,因为位置控制是默认的,力控制是特殊情况。

来看一个实际的例子。假设我们要做平面打磨,工具在Z方向接触工件,在X和Y方向移动。

自由度 自然约束 人工约束 选择矩阵S
X平移 自由 位置控制(轨迹跟踪) 1
Y平移 自由 位置控制(轨迹跟踪) 1
Z平移 受限(接触面) 力控制(恒力10N) 0
绕X旋转 自由 位置控制(姿态保持) 1
绕Y旋转 自由 位置控制(姿态保持) 1
绕Z旋转 自由 位置控制(姿态保持) 1

你看,只有Z方向的选择矩阵元素是0,其他都是1。这意味着只有Z方向做力控,其他五个自由度都做位置控。

实战技巧:选择矩阵不是一成不变的。在装配过程中,随着接触状态的变化,选择矩阵需要动态切换。比如,轴插入孔前,Z方向是位置控制;插入后,Z方向就要切换成力控制,防止撞底。

力控与位控的切换逻辑

切换逻辑,说白了就是什么时候该用力控,什么时候该用位控。这取决于任务阶段和接触状态。

常见的切换策略有三种:

  1. 基于接触检测的切换

这是最直观的方法。当检测到接触力超过阈值时,从位控切到力控。我在做精密装配时就用这个:

if (|F_z| > F_threshold) {
    // 检测到接触,切换到力控
    S[2] = 0;  // Z方向力控
    F_desired = 5.0;  // 目标力5N
} else {
    // 自由空间,位置控制
    S[2] = 1;  // Z方向位控
    X_desired = X_target;
}

但这里有个坑:阈值设得太小容易误触发,设得太大又可能已经撞上了。我建议阈值设为额定接触力的20%-30%,同时加一个滤波,防止噪声干扰。

  1. 基于状态机的切换

对于复杂的任务,比如装配,用状态机来管理切换更靠谱。每个状态对应一组选择矩阵和控制器参数。

enum AssemblyState {
    APPROACH,   // 接近阶段:位控
    CONTACT,    // 接触阶段:力控
    INSERT,     // 插入阶段:力控+位控混合
    DONE        // 完成
};

void assembly_control(AssemblyState state) {
    switch(state) {
        case APPROACH:
            S = diag(1,1,1,1,1,1);  // 全位置控制
            break;
        case CONTACT:
            S = diag(1,1,0,1,1,1);  // Z方向力控
            F_desired = 2.0;        // 轻柔接触
            break;
        case INSERT:
            S = diag(1,1,0,1,1,1);  // 保持Z方向力控
            F_desired = 10.0;       // 增大插入力
            break;
        case DONE:
            S = diag(1,1,1,1,1,1);  // 回到位置控制
            break;
    }
}

我曾经在一个轴孔装配项目中,状态机写了7个状态。每个状态的切换条件都经过上百次测试才稳定下来。嗯,调试过程很痛苦,但结果很值得。

  1. 连续平滑切换

硬切换会导致力或位置的突变。更优雅的做法是用一个平滑函数来过渡。比如用sigmoid函数:

// 平滑切换函数
double smooth_transition(double t, double t_start, double t_end) {
    double x = (t - t_start) / (t_end - t_start);
    x = clamp(x, 0.0, 1.0);
    return 1.0 / (1.0 + exp(-10.0 * (x - 0.5)));
}

// 在切换过程中,选择矩阵连续变化
double alpha = smooth_transition(t, 2.0, 2.5);  // 2秒到2.5秒完成切换
S[2] = alpha;  // 从0(力控)渐变到1(位控)

注意:平滑切换虽然减少了冲击,但会引入一段时间的混合控制状态。这段时间内,位置和力都不完全受控。我建议切换时间控制在0.3-0.5秒,太短没效果,太长容易出问题。

力位混合控制的完整框架

说了这么多,我们来画一张图,把整个逻辑串起来。

力位混合控制框架 任务规划 自然约束分析 人工约束设定 选择矩阵 S 生成 位置控制 (S=1) 力控制 (S=0) 控制输出 (τ) 图:力位混合控制的核心流程

这张图展示了力位混合控制的完整流程。从任务规划开始,先分析自然约束,再设定人工约束,然后生成选择矩阵,最后分别计算位置控制和力控制的输出,合并成最终的关节力矩。

实际项目中的避坑指南

我曾经在一个打磨项目中,力位混合控制怎么调都不对。后来发现是选择矩阵搞反了——我把力控和位控的自由度弄颠倒了。检查了三天才找到问题,那叫一个郁闷。

这里给大家几个实用建议:

  • 先做仿真验证:在真机运行前,先用MATLAB或Simulink仿真跑一遍。我习惯把选择矩阵的每个元素都打印出来,肉眼检查一遍。
  • 力控方向加软限位:力控自由度虽然不做位置控制,但还是要加一个位置软限位,防止意外情况导致机器人飞车。
  • 切换时注意积分器:PID控制器的积分项在切换时容易出问题。我建议在切换瞬间把积分项清零,或者用条件积分。
  • 调试时先低速:第一次跑力位混合控制,速度设到正常值的10%。确认没问题了再慢慢提速。

总结一下:力位混合控制的核心就是搞清楚每个自由度上,到底是环境说了算(自然约束),还是我们说了算(人工约束)。选择矩阵就是分配权力的工具。切换逻辑则是根据任务阶段动态调整这个分配。搞懂了这三件事,力位混合控制就入门了。

公众号:蓝海资料掘金营,微信deep3321