Cómo operar un enrutador CNC sin llamar la atención ...

Mi enrutador CNC funcionó fielmente durante dos años, pero algo salió mal, el firmware se apagó y era el pájaro carpintero 0.9.



Al principio, solo quería volver a cargarlo, y para este propósito obtuve los códigos fuente para el Proyecto Grbl CNC. Pero la curiosidad venció y me sumergí en el estudio de estas fuentes ...



construyen una muy sencilla y lógica, pero lo ruso no le gusta conducir rápido ya que es posible pasar por alto la posibilidad de que un zapato mejore! Basado en lo que pasó, este breve post dominical.



En realidad, la idea de un controlador para una máquina CNC es bastante simple e interesante. Hay varios subprocesos de procesamiento: uno lee datos (gcode) y los analiza, el segundo convierte los comandos en bloques de ejecución y el tercero (paso a paso) realmente ejecuta estos bloques. Se discutirá esta tercera corriente.



El paso a paso se ocupa de una lista de comandos individuales de la forma: tome (X, Y, Z) pasos para los tres (al menos) motores paso a paso, y durante un tiempo específico y en una dirección específica (bueno, esto es muy simplista). Debo decir que un motor paso a paso con su controlador es algo bastante simple de controlar: usted establece (0 o 1) la dirección de rotación y luego el motor intenta dar un paso con una caída de entrada positiva (0 -> 1) (y generalmente hay 200 pasos por revolución). Los datos ya están preparados, por lo que solo necesita correlacionar de alguna manera los 3 enteros con el tiempo dado.



En el original, el autor usó el controlador atmega328p, pero prácticamente sin cambios, todo se transfiere fácilmente a arm (por ejemplo, stm32). Pero el algoritmo en sí no puede dejar de plantear preguntas.



Por un lado, se utiliza un algoritmo de Bresenham muy perfecto, o más bien su versión de Adaptive Multi-Axis Step-Smoothing. Pero, por otro lado, de alguna manera todo es complicado y, lo más importante, la suavidad del motor paso a paso y la precisión del enrutador dependen directamente de la precisión de las señales de control. En este caso, esto se debe a la frecuencia a la que opera el temporizador y al tiempo de procesamiento de la interrupción, y esto no da más de 40-50 kHz en el mejor de los casos, y generalmente incluso menos, bueno, es decir, la precisión de la configuración del control es de 20-50 microsegundos.



Pero es bastante obvio que cuando procesamos un comando desde el búfer, solo necesitamos calcular los momentos de cambio de señal en el puerto de salida y estos momentos y hacer el cambio.



Como estaba considerando cambiarme a cortex-m (bueno, más precisamente, a stm32h750, que me encanta y que se ha vuelto muy más barato), esta tarea se puede resolver sin involucrar a la CPU, solo usando dos canales DMA y un contador de 32 bits.



La idea es muy simple. Deje que un canal escriba nuevos datos en el puerto en caso de desbordamiento del contador, y el segundo canal escribe un nuevo valor máximo de contador (es razonable hacer esto en el primer ciclo de reloj del contador). Luego, para procesar el comando de la lista, debe prepararse para una matriz de valores de cambio para el puerto y los tiempos de espera entre ellos.



Resultará algo como esto.



Manejo de interrupciones: cambio a un nuevo búfer (doble búfer).



#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;
}


Puede iniciar de esta manera:



       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;


Bueno, el comienzo es:



        program_down(NULL);


¿Qué hace? Calculemos usando el ejemplo del mismo stm32h750. El temporizador (TIM2) opera allí a una frecuencia de 200 MHz, la latencia mínima es de dos ciclos de reloj, pero DMA no puede enviar datos más rápido que 50 MHz, es decir, entre dos comandos para cambiar el puerto, puede poner (teniendo en cuenta el posible empleo del bus) 40 nseg (25 MHz) - esto es 1000 veces mejor que la implementación original.



Por otro lado, el ancho del puerto es de 16 bits, por lo que puede controlar simultáneamente 8 motores paso a paso en lugar de 3 , todavía sabría por qué ...



En este caso, completar los datos en sí no causa problemas (¡con tal o cual resolución!): Interpolación lineal simple para cada motor por separado con combinando (para optimización) eventos más cercanos a 40 nseg.



Las conclusiones reales.



En el taller hay una máquina CNC terminada de 1,2 metros por 0,8 metros con motores y drivers, pero sin controlador. Parece que tenemos que terminar el trabajo y probar lo épico que será. Si lo hago, definitivamente escribiré una secuela. Mientras tanto, no entiendo por qué los controladores hacen esto en atmega y chirrían en todas las impresoras 3d y enrutadores cnc en estas interrupciones bruscas ...



Y, por supuesto, probablemente teniendo el poder de Cortex-M7, puede implementar un control de trayectoria más suave con todas las restricciones , pero ese es un artículo completamente diferente.



PD Aparentemente, es necesario dar algún ejemplo hipotético de por qué es tan importante disponer de tan poco tiempo.



Supongamos que la máquina necesita moverse 100 mm en X y 11 mm en Y, y el software lo dividió todo en secciones de aceleración y movimiento uniforme: hay muchas secciones de 100 pasos por 11 pasos y se recorren a la velocidad máxima, que corresponda a 10 kHz. Bueno, 10 pasos en Y encajarán exactamente en 100 pasos en X, pero pueden ocurrir problemas con el 11 - se puede omitir, ya que causa una duplicación de la frecuencia. Como resultado, el movimiento será de 100 mm en X y de 10 a 11 mm en Y. Y esto es con movimiento lineal, donde, de hecho, incluso las restricciones sobre las aceleraciones y velocidades permitidas son simples. ¿Y si se hace en zigzag? Bueno, por ejemplo, hay un barrido de un área de 100 por 110 mm en 10 pasadas, entonces generalmente perdemos mucho ... El



algoritmo propuesto se usa para eliminar este error, y no en absoluto para súper molinos, etc.



All Articles