如何在不引起注意的情况下操作CNC铣床...

我的CNC路由器忠实地服务了两年,但是出了点问题,固件崩溃了,它是啄木鸟0.9。



起初,我只是想重新上传它,为此,我获得了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扫描-然后我们通常会非常想念...所



提出的算法用于消除此错误,而对于超级轧机等则完全没有。



All Articles