[3D-принтеры, DIY или Сделай сам, Программирование микроконтроллеров] Как управлять CNC-роутером, не привлекая внимания…
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Мой CNC-роутер служил верой и правдой два года, но что-то пошло не так слетела прошивка, а был это woodpecker 0.9.
Сначала я хотел ее просто перезалить, и, с этой целью раздобыл исходные коды Grbl CNC Project. Но любопытство пересилило и я погрузился в изучение этих исходников…
Построены они очень просто и логично, но какой же русский не любит быстрой езды как же можно пройти мимо возможности что-нибудь подковать улучшить! По мотивам того что получилось, эта короткая воскресная заметка.
Собственно идея контроллера для CNC-машины довольна проста и интересна. Есть несколько потоков обработки — один читает данные (gcode) и разбирает их, второй превращает команды в блоки исполнения и третий (stepper) собственно исполняет эти блоки. Вот об этом третьем потоке и пойдет речь.
Степпер имеет дело со списком отдельных команд вида — сделай (X,Y,Z) шагов для всех трёх (как минимум) шаговых двигателей, причем за указанное время и в заданном направлении (ну это так упрощенно). Надо сказать, что шаговый двигатель со своим драйвером довольно простая в управлении штука — задаешь (0 или 1) направление вращения и затем по положительному перепаду входа (0 -> 1) двигатель пытается сделать один шаг (а всего на оборот обычно 200 шагов). Данные уже подготовлены, так что надо просто как-то соотнести 3 целых числа с заданным временем.
В оригинале у автора использован контроллер atmega328p, но практически без изменений все легко переносится на arm (например, stm32). Но вот сам алгоритм не может не вызывать вопросов.
С одной стороны, использован весьма совершенный алгоритм Брезенхэма, а точнее его разновидность Adaptive Multi-Axis Step-Smoothing. Но с другой стороны, как-то это все сложно и главное, плавность хода шагового мотора и точность работы роутера прямо зависят от точности выдачи сигналов управления. В данном случае это обуславливается частотой на которой работает таймер и временем обработки прерываний — а это дает не более 40-50 кГц в лучшем случае, а обычно и того менее — ну то есть точность задания управления 20-50 мксек.
Но совершенно очевидно, что собственно нам нужно при обработке одной команды из буфера просто вычислить моменты переключения сигналов на выходном порту и эти моменты и производить переключения.
Так как я рассматривал переход на cortex-m (ну точнее на stm32h750, который я очень люблю и который очень подешевел), то такая задача может быть решена вовсе без привлечения CPU только лишь с использованием двух каналов DMA и одного 32-битного счетчика.
Идея очень проста. Пусть один канал по переполнению счетчика записывает новые данные на порт, а второй канал записывает новое максимальное значение счетчика (это разумно делать на первом же такте работы счетчика). Тогда для обработки команды из списка надо подготовить для массива из значений изменения для порта и интервалов ожидания между ними.
Получится что-то вроде такого.
Обработка по прерыванию — переключение на новый буфер (двойная буфферизация).
#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 МГц, минимальное время задержки два такта, но DMA не может переслать данные быстрее 50МГц, то есть между двумя командами на переключение порта можно положить (с учетом возможной занятости шины) 40 нсек (25МГц) — это в 1000 раз лучше исходной реализации!
С другой стороны, ширина порта — 16 бит, так что можно одновременно управлять 8 шаговыми двигателями вместо 3 еще бы знать зачем…
При этом заполнение собственно данных не вызывает проблем (с таким-то разрешением!) — простая линейная интерполяция по каждому двигателю отдельно с объединением (для оптимизации) событий ближе 40 нсек.
Собственно выводы.
В мастерской лежит готовый CNC-станок с размером 1.2 метра на 0.8 метра с двигателями и драйверами, но без контроллера. Похоже, надо завершить работу и попробовать на нем, насколько это будет эпично. Если сделаю — обязательно напишу продолжение. А пока я не понимаю, почему это контроллеры делают на atmega и они пищат на всех 3d-принтерах и cnc-роутерах на этих грубых прерываниях…
Ну и конечно, наверно имея мощь Cortex-M7, можно реализовать более плавное управление траекторией движения со всеми ограничениями, но это уже совсем другая статья.
===========
Источник:
habr.com
===========
Похожие новости:
- [Интернет вещей, Программирование микроконтроллеров, Разработка для интернета вещей, Разработка систем связи] MQTTv5.0: Обзор новых функций. Часть 2
- [DIY или Сделай сам, Космонавтика, Научно-популярное, Программирование микроконтроллеров] Per aspera ad astra, или как я строил ракету. Часть 2. Собираем альтиметр на STM32 и BMP280
- [C, Программирование микроконтроллеров, 3D-принтеры] Прошивка для фотополимерного LCD 3D-принтера своими руками. Часть 3
- [DIY или Сделай сам] Автоматический вечный календарь с подсветкой (перевод)
- [3D-принтеры, C, Программирование микроконтроллеров] Прошивка для фотополимерного LCD 3D-принтера своими руками. Часть 2
- [DIY или Сделай сам, Звук, Периферия, Производство и разработка электроники] Хорошо забытое новое: Falcon Acoustics возрождает DIY-акустику и продаёт колонки-конструктор за 150 000 рублей
- [3D-принтеры, C, Программирование микроконтроллеров] Прошивка для фотополимерного LCD 3D-принтера своими руками. Часть 1
- [DIY или Сделай сам, Видеокарты, Компьютерное железо] Добавление термопроводящей прокладки на обратную сторону платы снизило температуру чипов памяти в RTX 3080 на 8 градусов
- [Алгоритмы, Искусственный интеллект, Обработка изображений] В Photoshop появится функция на ИИ для замены неба
- [DIY или Сделай сам, Компьютерное железо] Энтузиаст собрал клавиатуру с 450 клавишами
Теги для поиска: #_3dprintery (3D-принтеры), #_diy_ili_sdelaj_sam (DIY или Сделай сам), #_programmirovanie_mikrokontrollerov (Программирование микроконтроллеров), #_cncrouter, #_mikrokontroller (микроконтроллер), #_algoritmy (алгоритмы), #_3dprintery (
3D-принтеры
), #_diy_ili_sdelaj_sam (
DIY или Сделай сам
), #_programmirovanie_mikrokontrollerov (
Программирование микроконтроллеров
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 17:57
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Мой CNC-роутер служил верой и правдой два года, но что-то пошло не так слетела прошивка, а был это woodpecker 0.9. Сначала я хотел ее просто перезалить, и, с этой целью раздобыл исходные коды Grbl CNC Project. Но любопытство пересилило и я погрузился в изучение этих исходников… Построены они очень просто и логично, но какой же русский не любит быстрой езды как же можно пройти мимо возможности что-нибудь подковать улучшить! По мотивам того что получилось, эта короткая воскресная заметка. Собственно идея контроллера для CNC-машины довольна проста и интересна. Есть несколько потоков обработки — один читает данные (gcode) и разбирает их, второй превращает команды в блоки исполнения и третий (stepper) собственно исполняет эти блоки. Вот об этом третьем потоке и пойдет речь. Степпер имеет дело со списком отдельных команд вида — сделай (X,Y,Z) шагов для всех трёх (как минимум) шаговых двигателей, причем за указанное время и в заданном направлении (ну это так упрощенно). Надо сказать, что шаговый двигатель со своим драйвером довольно простая в управлении штука — задаешь (0 или 1) направление вращения и затем по положительному перепаду входа (0 -> 1) двигатель пытается сделать один шаг (а всего на оборот обычно 200 шагов). Данные уже подготовлены, так что надо просто как-то соотнести 3 целых числа с заданным временем. В оригинале у автора использован контроллер atmega328p, но практически без изменений все легко переносится на arm (например, stm32). Но вот сам алгоритм не может не вызывать вопросов. С одной стороны, использован весьма совершенный алгоритм Брезенхэма, а точнее его разновидность Adaptive Multi-Axis Step-Smoothing. Но с другой стороны, как-то это все сложно и главное, плавность хода шагового мотора и точность работы роутера прямо зависят от точности выдачи сигналов управления. В данном случае это обуславливается частотой на которой работает таймер и временем обработки прерываний — а это дает не более 40-50 кГц в лучшем случае, а обычно и того менее — ну то есть точность задания управления 20-50 мксек. Но совершенно очевидно, что собственно нам нужно при обработке одной команды из буфера просто вычислить моменты переключения сигналов на выходном порту и эти моменты и производить переключения. Так как я рассматривал переход на cortex-m (ну точнее на stm32h750, который я очень люблю и который очень подешевел), то такая задача может быть решена вовсе без привлечения CPU только лишь с использованием двух каналов DMA и одного 32-битного счетчика. Идея очень проста. Пусть один канал по переполнению счетчика записывает новые данные на порт, а второй канал записывает новое максимальное значение счетчика (это разумно делать на первом же такте работы счетчика). Тогда для обработки команды из списка надо подготовить для массива из значений изменения для порта и интервалов ожидания между ними. Получится что-то вроде такого. Обработка по прерыванию — переключение на новый буфер (двойная буфферизация). #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 МГц, минимальное время задержки два такта, но DMA не может переслать данные быстрее 50МГц, то есть между двумя командами на переключение порта можно положить (с учетом возможной занятости шины) 40 нсек (25МГц) — это в 1000 раз лучше исходной реализации! С другой стороны, ширина порта — 16 бит, так что можно одновременно управлять 8 шаговыми двигателями вместо 3 еще бы знать зачем… При этом заполнение собственно данных не вызывает проблем (с таким-то разрешением!) — простая линейная интерполяция по каждому двигателю отдельно с объединением (для оптимизации) событий ближе 40 нсек. Собственно выводы. В мастерской лежит готовый CNC-станок с размером 1.2 метра на 0.8 метра с двигателями и драйверами, но без контроллера. Похоже, надо завершить работу и попробовать на нем, насколько это будет эпично. Если сделаю — обязательно напишу продолжение. А пока я не понимаю, почему это контроллеры делают на atmega и они пищат на всех 3d-принтерах и cnc-роутерах на этих грубых прерываниях… Ну и конечно, наверно имея мощь Cortex-M7, можно реализовать более плавное управление траекторией движения со всеми ограничениями, но это уже совсем другая статья. =========== Источник: habr.com =========== Похожие новости:
3D-принтеры ), #_diy_ili_sdelaj_sam ( DIY или Сделай сам ), #_programmirovanie_mikrokontrollerov ( Программирование микроконтроллеров ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 17:57
Часовой пояс: UTC + 5