起初,我只是想重新上传它,为此,我获得了Grbl CNC项目的源代码。但是好奇心克服了,我投入了对这些资源的研究……
它们建立了一个非常简单和合乎逻辑的方法,但是
实际上,用于CNC机床的控制器的想法非常简单和有趣。有多个处理线程-一个读取数据(gcode)并对其进行解析,第二个将命令转换为执行块,第三个(步进器)实际执行这些块。将讨论此第三流。
步进器处理以下形式的单个命令列表-对所有三个(至少)步进电机并在指定的时间和指定的方向上执行(X,Y,Z)步(很简单)。我必须说,带有驱动器的步进电机非常容易控制-设置(0或1)旋转方向,然后电机尝试通过正输入差动(0-> 1)步进(通常每转200步)。数据已经准备好了,因此您只需要将3个整数与给定时间相关联即可。
在最初,作者使用了atmega328p控制器,但实际上几乎所有内容都可以轻松转移到手臂(例如stm32)。但是算法本身不得不提出问题。
一方面,使用了非常完善的布雷森汉姆算法,或者说是自适应多轴步进平滑算法的版本。但是,另一方面,这一切都很复杂,最重要的是,步进电机的平滑度和路由器的精度直接取决于控制信号的精度。在这种情况下,这是由于计时器的工作频率和中断处理时间所致-充其量最多不会超过40-50 kHz,通常甚至更少-很好,也就是说,控制设置精度为20-50微秒。
但是,很明显,实际上,当处理来自缓冲区的一个命令时,我们只需要计算输出端口上的切换信号的力矩以及这些力矩,然后执行切换即可。
自从我考虑切换到cortex-m(更确切地说是切换到stm32h750以来,我非常喜欢它并且变得非常便宜),所以仅使用两个DMA通道和一个32位计数器就可以完全解决这一任务而无需占用CPU。
这个想法很简单。让一个通道在计数器溢出时将新数据写入端口,第二个通道写入新的最大计数器值(在计数器的第一个时钟周期进行此操作是合理的)。然后,要从列表中处理命令,您需要为端口及其之间的超时准备一系列更改值。
结果会是这样。
中断处理-切换到新缓冲区(双缓冲)。
#define MAX_PGM 32
typedef struct _pgm_buffer {
uint32_t data[MAX_PGM];
uint32_t delta[MAX_PGM];
} pgm_buffer;
pgm_buffer buf[2];
uint32_t current_buf = 1;
uint32_t flags = 0;
void program_down(DMA_HandleTypeDef *_hdma) {
TIM2->CR1 &= ~TIM_CR1_CEN;
if ((flags & BUF_RUNNING) == 0)
return;
current_buf ^= 1;
DMA1_Channel5->CCR &= ~1;
DMA1_Channel2->CCR &= ~1;
DMA1_Channel5->CNDTR = MAX_PGM;
DMA1_Channel2->CNDTR = MAX_PGM;
DMA1_Channel5->CMAR = (uint32_t) (buf[current_buf].delta);
DMA1_Channel2->CMAR = (uint32_t) (buf[current_buf].data);
DMA1_Channel5->CCR |= 1;
DMA1_Channel2->CCR |= 1;
TIM2->CNT = 0;
TIM2->ARR = 8;
TIM2->EGR |= TIM_EGR_UG;
TIM2->CR1 |= TIM_CR1_CEN;
}
您可以通过以下方式启动:
HAL_DMA_RegisterCallback(&hdma_tim2_up, HAL_DMA_XFER_CPLT_CB_ID,
program_down);
HAL_DMA_Start_IT(&hdma_tim2_up, buf, &GPIOA->BSRR, MAX_PGM);
DMA1_Channel5->CCR &= ~1;
DMA1_Channel5->CPAR = &TIM2->ARR;
DMA1_Channel5->CCR |= 1;
TIM2->CCR1 = 1;
TIM2->DIER |= TIM_DIER_UDE | TIM_DIER_CC1DE;
flags |= BUF_RUNNING;
好,开始是:
program_down(NULL);
它有什么作用?让我们使用相同的stm32h750的示例进行计算。计时器(TIM2)在那里以200 MHz的频率运行,最小延迟为两个时钟周期,但是DMA不能发送高于50 MHz的数据,也就是说,在两个用于切换端口的命令之间,您可以(考虑到可能的总线使用)将40 ns(25 MHz)设置为-比原始实施好1000倍!
另一方面,端口宽度为16位,因此您可以同时控制8台步进电机,而不是3台,
在这种情况下,填写实际数据不会引起问题(具有这样的分辨率!)-每个电机的简单线性插值分别通过组合(用于优化)小于40纳秒的事件。
实际结论。
在车间中,有一台尺寸为1.2米x 0.8米的成品CNC机床,带有电动机和驱动器,但没有控制器。看来我们需要完成这项工作,并尝试它将达到史诗般的水平。如果这样做,我一定会写续集。同时,我不明白为什么控制器要在atmega上执行此操作,并且在这些粗略中断上会在所有3d打印机和cnc路由器上发出吱吱声……
当然,可能拥有Cortex-M7的功能,您可以在所有限制下实现更平滑的轨迹控制,但这是完全不同的文章。
PS显然,有必要给出一些假设示例,为什么拥有这么短的时间如此重要。
假设机器需要在X轴上移动100毫米,在Y轴上移动11毫米,然后软件将其全部分为加速和匀速运动部分-有很多步长为11步的100步长段,它们以最大速度运行,使其对应于10 kHz。好吧,Y的10步正好适合X的100步,但是第11步可能会遇到麻烦-可以跳过,因为它会导致频率加倍。结果,X轴的移动量为100毫米,Y轴的移动量为10到11毫米。这是线性运动,实际上,甚至对允许的加速度和速度的限制也很简单。并且如果它以锯齿形完成?好吧,例如,在10道次扫描中有110毫米的区域被100扫描-然后我们通常会非常想念...所
提出的算法用于消除此错误,而对于超级轧机等则完全没有。