第四章:电子齿轮与电子凸轮
说实话,搞多轴同步控制这么多年,我觉得最实用的两个概念就是电子齿轮和电子凸轮。很多刚入行的朋友一听到这两个词就头大,觉得是啥高深莫测的东西。其实说白了,它们就是让多个轴“商量着来”的两种方式。
我刚开始做项目那会儿,遇到一个四轴同步的案子,客户要求三个从轴跟着主轴走,但比例还不一样。我当时第一反应是用机械齿轮箱,后来被老工程师骂了一顿——现在都什么年代了,还用机械?电子齿轮了解一下?
嗯,从那以后我就彻底爱上了这两个东西。今天咱们就把它们掰开揉碎了讲清楚。
4.1 电子齿轮:让轴与轴之间保持固定比例
电子齿轮,说白了就是让从轴的位置或速度,与主轴保持一个固定的比例关系。你主轴转一圈,从轴转两圈,或者主轴走10mm,从轴走5mm——这就是电子齿轮干的事。
它的数学表达很简单:
从轴位置 = 主轴位置 × 齿轮比
但实际工程中,我们通常用电子齿轮比(Electronic Gear Ratio, EGR)来表示:
EGR = 从轴脉冲数 / 主轴脉冲数
举个例子,主轴编码器每转输出10000个脉冲,你希望从轴每转只输出5000个脉冲,那齿轮比就是0.5。
核心要点:电子齿轮只解决“比例同步”问题,不解决“相位同步”问题。如果你需要两个轴在特定位置对齐,那得用电子凸轮。
4.2 电子凸轮:让轴与轴之间按任意曲线运动
电子凸轮就比电子齿轮灵活多了。它允许你定义任意的主轴-从轴位置关系曲线。说白了,就是一张“映射表”——主轴走到某个位置,从轴必须走到对应的位置。
我做过一个包装机项目,需要让切刀在物料到达的瞬间完成切割。如果用电子齿轮,切刀速度跟传送带速度成比例,但切刀位置永远对不齐。用电子凸轮就简单了——我定义一条曲线,让切刀在物料到达时刚好落下,其他时间快速回位。
电子凸轮的核心数据结构是一个查找表(LUT):
主轴位置 | 从轴位置
0 | 0
100 | 50
200 | 200
300 | 100
400 | 0
实际运行时,控制器根据当前主轴位置,查表插值得到从轴目标位置。插值方式一般有线性插值和样条插值两种。
我的经验:线性插值简单高效,但曲线不够平滑。样条插值平滑性好,但计算量大。我一般建议:如果主轴速度变化不大,用线性插值就够了;如果主轴频繁加减速,用样条插值更稳。
4.3 应用场景对比
| 特性 | 电子齿轮 | 电子凸轮 |
|---|---|---|
| 同步关系 | 固定比例 | 任意曲线 |
| 相位控制 | 不支持 | 支持 |
| 实现复杂度 | 低 | 中高 |
| 典型应用 | 传送带同步、多轴联动 | 飞剪、追剪、包装机 |
| 实时性要求 | 中等 | 高 |
你看这个表就明白了——电子齿轮适合“粗同步”,电子凸轮适合“精同步”。
4.4 代码实现:电子齿轮
下面是一个简单的电子齿轮实现,用C语言写的,跑在STM32上。我习惯把齿轮比用分数形式存储,避免浮点运算带来的精度问题。
// 电子齿轮结构体
typedef struct {
int32_t master_pos; // 主轴位置
int32_t slave_pos; // 从轴位置
int32_t ratio_num; // 齿轮比分子
int32_t ratio_den; // 齿轮比分母
int32_t error_acc; // 误差累积
} ElectronicGear_t;
// 初始化
void EG_Init(ElectronicGear_t *eg, int32_t num, int32_t den) {
eg->master_pos = 0;
eg->slave_pos = 0;
eg->ratio_num = num;
eg->ratio_den = den;
eg->error_acc = 0;
}
// 更新函数,每次主轴更新时调用
void EG_Update(ElectronicGear_t *eg, int32_t master_delta) {
eg->master_pos += master_delta;
// 计算理论从轴增量
int32_t target_delta = (master_delta * eg->ratio_num) / eg->ratio_den;
// 误差补偿
eg->error_acc += (master_delta * eg->ratio_num) % eg->ratio_den;
if (eg->error_acc >= eg->ratio_den) {
target_delta += 1;
eg->error_acc -= eg->ratio_den;
} else if (eg->error_acc <= -eg->ratio_den) {
target_delta -= 1;
eg->error_acc += eg->ratio_den;
}
eg->slave_pos += target_delta;
}
注意:我曾经在一个项目中忽略了误差累积,结果运行半小时后从轴位置偏了整整一圈。后来加了误差补偿才解决。这个细节很多人会忽略,但实际工程中非常关键。
4.5 代码实现:电子凸轮
电子凸轮的实现稍微复杂一些。核心是查表和插值。下面是一个线性插值的实现:
// 凸轮曲线点
typedef struct {
int32_t master_pos;
int32_t slave_pos;
} CamPoint_t;
// 凸轮表
typedef struct {
CamPoint_t *points;
uint32_t point_count;
int32_t cycle_length; // 主轴周期长度
} ElectronicCam_t;
// 线性插值查表
int32_t EC_GetSlavePos(ElectronicCam_t *cam, int32_t master_pos) {
// 取模,处理周期循环
master_pos = master_pos % cam->cycle_length;
if (master_pos < 0) master_pos += cam->cycle_length;
// 二分查找
uint32_t left = 0, right = cam->point_count - 1;
while (right - left > 1) {
uint32_t mid = (left + right) / 2;
if (cam->points[mid].master_pos <= master_pos) {
left = mid;
} else {
right = mid;
}
}
// 线性插值
CamPoint_t *p0 = &cam->points[left];
CamPoint_t *p1 = &cam->points[right];
int32_t dx = p1->master_pos - p0->master_pos;
if (dx == 0) return p0->slave_pos;
int32_t dy = p1->slave_pos - p0->slave_pos;
int32_t offset = master_pos - p0->master_pos;
// 使用定点数计算,避免浮点
return p0->slave_pos + (dy * offset) / dx;
}
这段代码看起来简单,但实际工程中要注意几个坑:
- 边界处理:主轴位置刚好等于某个点时,要保证查表不出错
- 周期对齐:凸轮曲线一般是周期性的,取模操作要小心负数
- 插值精度:如果曲线变化剧烈,线性插值可能不够,得用样条
4.6 知识体系结构图
下面这张图是我自己画的,把电子齿轮和电子凸轮的核心逻辑串起来了。你看一眼就能明白它们的关系:
4.7 避坑指南
做电子齿轮和电子凸轮项目,有几个坑我踩过,你们注意一下:
- 齿轮比不要用浮点数:我曾经用float存齿轮比,跑了几个小时误差累积到不可接受。后来改用分数形式,问题解决。
- 凸轮曲线要平滑:如果曲线有突变,从轴会剧烈抖动。我一般用五次样条做平滑处理。
- 注意主轴速度变化:电子凸轮查表时,如果主轴速度变化太快,插值可能跟不上。这时候需要做速度前馈。
- 周期边界要处理好:凸轮曲线在周期边界处容易产生跳变,我习惯在边界处加一段过渡曲线。
一个小技巧:调试电子凸轮时,先把曲线画出来看看。我一般用Python的matplotlib把凸轮曲线、速度曲线、加速度曲线都画出来,确认没问题再下到控制器里。这样能省很多调试时间。
好了,电子齿轮和电子凸轮的核心内容就这些。你想想看,其实它们并不复杂——一个固定比例,一个任意曲线。选哪个,取决于你的应用场景。精度要求高、需要相位对齐的,上电子凸轮;只是简单比例同步的,电子齿轮就够了。
我在实际项目中,经常把两者结合起来用——主轴用电子齿轮驱动多个从轴做粗同步,再用电子凸轮做精定位。效果非常好。