第4章 直线插补(一):空间直线参数方程;位置插补原理;等时插补与等距插补
各位同学,欢迎来到轨迹插补的第一站。说实话,直线插补是所有插补算法里最基础、也最容易被轻视的一块。我见过不少新手,一上来就研究圆弧、样条,结果连直线都跑不直。嗯,咱们今天就把这块地基打牢。
4.1 空间直线参数方程——别再用y=kx+b了
先问个问题:在三维空间里,你怎么描述一条直线?
很多人的第一反应是y = kx + b。但你想过没有,这个方程只能描述二维平面里的直线,而且遇到垂直于x轴的直线直接就崩了——斜率无穷大,没法算。
在机器人运动控制里,我们面对的是三维空间。末端执行器要从A点走到B点,路径是空间中的一条直线。这时候,最优雅的表达方式就是参数方程。
设起点为 P₀(x₀, y₀, z₀),终点为 P₁(x₁, y₁, z₁)。那么直线上任意一点可以写成:
P(t) = P₀ + t · (P₁ - P₀), t ∈ [0, 1]
拆开写就是:
x(t) = x₀ + t · (x₁ - x₀)
y(t) = y₀ + t · (y₁ - y₀)
z(t) = z₀ + t · (z₁ - z₀)
这里t是一个无量纲参数。t=0时在起点,t=1时在终点。t从0到1连续变化,点就在直线上平滑移动。
核心理解:参数方程的本质是把「位置」和「进度」解耦了。t只关心「走了多少比例」,不关心实际走了多远。这个特性在后面做插补时会非常有用。
我个人习惯把 (P₁ - P₀) 称为方向向量,记作 D。那么直线方程就是 P(t) = P₀ + t·D。简洁,而且物理意义清晰。
4.2 位置插补原理——把连续路径切成离散点
机器人控制器是数字系统,它没法连续地走一条曲线。它只能一个点一个点地走。位置插补要做的,就是把理想连续路径离散成一系列路径点,然后让机器人依次经过这些点。
说白了,就是用折线逼近直线。但这里有个关键问题:怎么切?切多少刀?
我举个例子。假设直线长度100mm,你切了100段,每段1mm。机器人每1ms走一个点,那么走完需要100ms。如果你切了1000段,每段0.1mm,同样1ms走一个点,就需要1000ms。
你看,切得越密,路径越平滑,但耗时越长。这就是插补的核心矛盾:精度 vs 速度。
位置插补的数学基础就是参数方程。给定一个t值,就能算出一个位置点。插补算法的任务就是决定:t应该取哪些值?
这里引出两种经典策略:等时插补和等距插补。
4.3 等时插补——固定时间间隔,位置随缘
等时插补的思路很简单:每隔固定的时间 Δt,计算一个插补点。
假设插补周期 Δt = 1ms,总运动时间 T = 100ms,那么插补点数 N = T / Δt = 100。t的取值就是:
tᵢ = i / N, i = 0, 1, 2, ..., N
代入参数方程,得到每个点的位置:
Pᵢ = P₀ + (i/N) · (P₁ - P₀)
代码实现非常简单:
// 等时插补示例
void LinearInterpolation_Time(Pose start, Pose end, double totalTime, double dt) {
int N = (int)(totalTime / dt);
for (int i = 0; i <= N; i++) {
double t = (double)i / N;
double x = start.x + t * (end.x - start.x);
double y = start.y + t * (end.y - start.y);
double z = start.z + t * (end.z - start.z);
// 下发位置点给伺服
SendPosition(x, y, z);
}
}
我的经验:等时插补最大的优点是实现简单,CPU开销小。但有个坑——如果直线很长,相邻插补点之间的距离会很大,导致机器人运动不平稳。我曾经在一个码垛项目里用过等时插补,结果长距离移动时末端抖动明显,后来改成了等距插补才解决。
4.4 等距插补——固定步长,时间随缘
等距插补的思路反过来:固定相邻插补点之间的空间距离 Δs,然后反推t的取值。
直线总长 L = |P₁ - P₀|。设步长为 Δs,那么插补点数 N = L / Δs。第i个点对应的t值为:
tᵢ = i · Δs / L = i / N
你看,公式和等时插补一模一样!但区别在于:等时插补的N由时间决定,等距插补的N由距离决定。
代码实现:
// 等距插补示例
void LinearInterpolation_Distance(Pose start, Pose end, double stepSize) {
double L = Distance(start, end);
int N = (int)(L / stepSize);
for (int i = 0; i <= N; i++) {
double t = (double)i / N;
double x = start.x + t * (end.x - start.x);
double y = start.y + t * (end.y - start.y);
double z = start.z + t * (end.z - start.z);
SendPosition(x, y, z);
// 注意:这里需要根据实际运动速度控制发送间隔
Delay(stepSize / velocity);
}
}
避坑指南:我曾经在高速焊接项目里用过等距插补,结果发现一个问题——当机器人需要减速停止时,等距插补不会自动调整步长。最后一段距离如果步长太大,会直接冲过终点。解决方案是在终点附近做减速处理,或者改用带加减速的S形速度规划。这个后面章节会详细讲。
4.5 两种插补方式的对比
| 对比项 | 等时插补 | 等距插补 |
|---|---|---|
| 控制变量 | 时间间隔固定 | 空间步长固定 |
| 插补点数 | 由总时间决定 | 由总距离决定 |
| 长直线表现 | 点间距大,可能抖动 | 点间距均匀,运动平稳 |
| 短直线表现 | 点间距小,精度高 | 点数少,可能不够平滑 |
| 实现复杂度 | 简单 | 中等(需处理速度匹配) |
| 适用场景 | 短距离、低速运动 | 长距离、高速运动 |
你想想看,实际项目中怎么选?我的建议是:先看运动距离。如果直线长度小于50mm,等时插补完全够用。如果超过200mm,优先考虑等距插补。当然,工业级控制器通常会把两者结合——用等距保证精度,用等时保证实时性。
4.6 本章知识体系
下面这张图总结了本章的核心逻辑,我建议你多看几遍,把关系理清楚。
这张图把本章的知识脉络串起来了。从参数方程出发,到插补原理,再到两种具体实现策略。你如果能把这个逻辑链条印在脑子里,后面学圆弧插补、样条插补就会轻松很多。
本章小结:直线插补看似简单,但它是所有插补算法的基础。参数方程是工具,插补原理是思想,等时和等距是两种具体实现。没有孰优孰劣,只有合不合适。我建议你动手写一写代码,跑几个不同长度的直线,感受一下两种方式的差异。纸上得来终觉浅,绝知此事要躬行。
公众号:蓝海资料掘金营,微信deep3321