开发板STM32 三轴联动 带插补 加减速 源代码 MDK 源码 分别基于STM32F1和ST...
开发板STM32 三轴联动 带插补 加减速 源代码 MDK 源码 分别基于STM32F1和STM32F4两套的三轴联动插补(直线圆弧两种带)加减速的源码,基于国外写的脱机简易雕刻机源码的项目修改,添加了大量的中文注释,可以很好帮助大家学习这个源码。开发板STM32 三轴联动 带插补 加减速 源代码 MDK 源码 分别基于STM32F1和STM32F4两套的三轴联动插补(直线圆弧两种带)加减速的源码
开发板STM32 三轴联动 带插补 加减速 源代码 MDK 源码 分别基于STM32F1和STM32F4两套的三轴联动插补(直线圆弧两种带)加减速的源码,基于国外写的脱机简易雕刻机源码的项目修改,添加了大量的中文注释,可以很好帮助大家学习这个源码。
最近在捣鼓三轴运动控制系统,发现网上有个基于STM32的脱机雕刻机项目挺有意思。原版代码是国外开发者写的,但咱们团队把它扒拉过来魔改了一波——不仅移植到F1和F4两个平台,还往源码里怼了上万字的中文注释,现在连刚入门的小白都能看明白那些骚操作。
先看工程结构,项目里最带劲的是这个运动控制核心:
// 三轴联动主控函数(F4版本用DSP库加速)
void Motion_Core_Update(void)
{
// 实时计算剩余步数
int32_t steps_remaining = max(max(x_steps, y_steps), z_steps);
// 动态调整脉冲频率(核心加速算法)
if (steps_remaining > 200) {
current_freq = max_freq; // 全速飙车模式
} else {
current_freq = sqrt(2 * accel * steps_remaining); // 减速曲线计算
}
TIM_SetAutoreload(STEP_TIMER, SystemCoreClock / current_freq / 2);
}
这段代码里藏着速度变化的灵魂。当剩余步数足够多时直接满速跑,接近终点时用平方根函数做平滑减速,实测效果比某些商用驱动器还丝滑。
直线插补的实现比想象中简单粗暴:
void Line_Interp(int32_t target[], float feedrate)
{
// 计算各轴总步数
x_steps = labs(target[X] - current_pos[X]);
y_steps = labs(target[Y] - current_pos[Y]);
z_steps = labs(target[Z] - current_pos[Z]);
// 取最大步数作为基准
step_count = max(x_steps, max(y_steps, z_steps));
// 步进增量计算(避免浮点运算)
x_inc = (target[X] - current_pos[X]) << 16 / step_count;
y_inc = (target[Y] - current_pos[Y]) << 16 / step_count;
z_inc = (target[Z] - current_pos[Z]) << 16 / step_count;
// 启动加减速调度器
Accel_Engine_Start(step_count);
}
这里用定点数运算替代浮点,F1版本直接硬算,F4版则用Q格式处理。看到那个<<16操作没?这其实是用65536作为定点数精度,既保证计算速度又不会溢出。
开发板STM32 三轴联动 带插补 加减速 源代码 MDK 源码 分别基于STM32F1和STM32F4两套的三轴联动插补(直线圆弧两种带)加减速的源码,基于国外写的脱机简易雕刻机源码的项目修改,添加了大量的中文注释,可以很好帮助大家学习这个源码。
圆弧插补就有点东西了,核心算法改编自Bresenham圆算法:
// 圆弧插补状态机
typedef struct {
int32_t x, y;
int32_t d;
uint8_t quadrant;
uint16_t over90_flag;
} Arc_State;
void Arc_Interp(Arc_State *arc)
{
while(arc->d <= 0) {
step_X(); // 输出X轴脉冲
arc->d += 2 * arc->x + 1;
arc->x++;
if(arc->d > 0) {
step_Y(); // 输出Y轴脉冲
arc->d += 2 * (arc->y - arc->x) + 1;
arc->y--;
}
// 处理象限切换
if(arc->x > arc->y && !arc->over90_flag) {
arc->quadrant++;
arc->over90_flag = 1;
}
}
}
这状态机跑起来跟贪吃蛇似的,通过误差项d的正负决定移动方向。代码里藏了个象限切换的骚操作,处理超过90度的圆弧时自动跳转,实测画圆精度能控制在±2个脉冲内。
F1和F4两套代码最大的区别在定时器配置上。F1用标准库操作TIM3:
// F1的定时器初始化(72MHz主频)
void STEP_TIM_Init(void)
{
TIM_TimeBaseInitTypeDef timer;
timer.TIM_Prescaler = 0; // 不分频
timer.TIM_CounterMode = TIM_CounterMode_Up;
timer.TIM_Period = 7200; // 初始10kHz
TIM_TimeBaseInit(TIM3, &timer);
TIM_Cmd(TIM3, ENABLE);
}
而F4用HAL库+HALTIMOCStartDMA玩起了高级操作:
// F4的DMA脉冲发射(168MHz主频)
void STEP_DMA_Start(void)
{
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIM_OC_Start_DMA(&htim1, TIM_CHANNEL_2, (uint32_t*)pulse_buffer, PULSE_BUF_SIZE);
}
F4的DMA传输配合预装载缓冲,实测脉冲频率能飚到200kHz不带丢步的。不过要注意,用DMA时GPIO必须配置为复用推挽模式,否则输出波形会变方波它二舅——方不起来。
源码里最实用的其实是这个加速度曲线生成器:
// 梯形加减速参数生成
void Accel_Engine_Calc(int32_t total_steps)
{
// 计算加速段步数
uint32_t accel_steps = (max_freq * max_freq) / (2 * accel);
if(total_steps > 2 * accel_steps) {
// 完整梯形:加速-匀速-减速
cruise_steps = total_steps - 2 * accel_steps;
} else {
// 三角波模式:只有加减速
accel_steps = total_steps / 2;
cruise_steps = 0;
}
// 生成速度曲线表
for(int i=0; i<accel_steps; i++){
speed_table[i] = sqrt(2 * accel * i); // 加速段
}
}
这个算法妙在自动识别运动距离是否够跑完加速+匀速+减速三个阶段。当总步数太少时自动切换成三角波模式,实测在小距离移动时明显比固定梯形加速流畅。
想跑起来这套代码,记得改这几个地方:
- 在motor_pin.h里配置实际使用的GPIO引脚
- 根据机械结构调整stepspermm参数
- F4版本需要开启FPU和DSP库
- 定时器中断优先级要设为最高
最后说个坑:原版代码的圆弧插补只支持XY平面,要搞三维螺旋插补得自己改插补算法。不过拿这个做基础来魔改,比从头写至少省两个月咖啡钱。源码包里带了激光雕刻和CNC两种配置示例,拿烙铁的时候小心别把开发板烫出烤肉味就行。

更多推荐
所有评论(0)