[Из песочницы] Делаем трехосевой фрезерный станок с число-программным управлением

Идея сделать станок дома руками не нова. Каждый кто задумывается над реализацией такого оборудования в домашних условиях, должен руководствоваться своим мотивом создания. Мне это необходимо, потому, что от природы у меня не на столько ровные руки, чтобы сделать хорошие, даже более или менее габаритные, детали, а часто возникает задача изготовить точную сложную деталь, с чем станок хорошо справится. Всегда хватает новых идеи и задумок для реализации, а времени не очень много.

6b0ba84d4d094bcfb68fb2d011b2a917.jpg

Коротко об авторе


Студент 4-го курса Белорусского государственного университета информатики и радиоэлектроники, факультета «Компьютерных систем и сетей», кафедры «Электронных вычислительных машин», специальности «Вычислительные машины системы и сети».


Спойлер


Полученный результат не претендует на звание станок года. Да, реализация контроллера ШД на микроконтроллере не очень хороший вариант. Да, станина из дерева, тоже не лучшее, что можно придумать. В тексте статьи будут пояснения и обоснования выборов. Не стоит забывать, что это всего лишь попытка что-то собрать, получить опыт и двигаться дальше.


Полученный фрезерный станок должен удовлетворять следующим условиям:

  • Иметь приемлемую рабочую область
  • Иметь приемлемую скорость движения по осям
  • Обрабатывать детали из дерева средней и высокой твердости. В идеале обрабатывать алюминий


Главное правило станков — жесткость. Чем выше жесткость станка, тем меньше вибраций, люфтов, проседаний, изгибов и прочих дефектов которые повлияют на качество обрабатываемой болванки. Так как станок будет изготавливаются полностью в домашних условиях, то единственным материалом который можно реально обработать в таком количестве дома и из которого получится сделать станину станка — дерево. Есть конечно разные виды. И за неимением большого капитала ибо студент для создания будет использовано все, что найдется. А это по сути доски на пробу сверлом довольно мягкого дерева. Хотя так же есть и небольшие листы фанеры. Чем богаты, то и будет использовано.

Так же стоит отметить на чем будет запущено управление станком. Есть один очень древний компьютер, берег его как раз примерно для таких целей. AMD Duron 1.2 ГГц, RAM 768 МБ, 64 МБ Video Mem, HDD 20ГБ. Как раз для этих целей сгодится. Управление будет под Linux CNC. Ибо Mach3 под Win не захотел толково работать. Ресурсов ему немного больше нужно.


Разработка станка будет разбита на несколько частей.

  • Разработка контроллера шагового двигателя
  • Разработка драйвера шагового двигателя
  • Разработка оптической развязки
  • Разработка планки питания


Стоит сразу сказать, что разработка механической части как таковая отсутствовала, ибо, нету столько опыта чтобы что-то разрабатывать и предвидеть. По этому разработка велась сразу на этапе сборки.

Разработка контроллера шагового двигателя


Контроллера шагового двигателя будет разработан на PIC микроконтроллере. Почему? Во-первых, нужно было окончательно усвоить как работают шаговые двигатели, во-вторых, так интереснее, в-третьих, та же готовая микросхема L297 стоила почему-то дороговато, и в итоге получалось собрать на микроконтроллере немного дешевле.

9c9aa2b267da4373b2e886d7623cf611.BMP

В качестве управляющего микроконтроллера был взят PIC16F630. Имеет минимум периферии и достаточное количество ног для управления. Порт C служит для прямого вывода управляющих импульсов. На пины A1, A2 заведены входные сигналы DIR, STEP. Пин A2 включен в режиме внешних прерываний, а DIR работает как обычный пин ввода. Контроллер запущен через кварц на 20 MHz.

Код был написан на С с использованием маленькой asm вставки и собран на CCS C компиляторе.

#include <16f630.h>
#case  
#FUSES NOWDT                    
#FUSES NOMCLR                   
#FUSES HS                     
#FUSES PUT                    
#FUSES BROWNOUT 

#use delay(clock = 20 MHz)                                                                                                                         
#use fast_io(C)                                                     
#opt 9  
                                
#define DIR             PIN_A1                                                             
#define CLK             PIN_A2   
#define LED             PIN_A0                                
                                                                          
#zero_ram       
                             
//half step array     
const int steps[256] =    
{                 
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,                                                                                         
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,                                                                                          
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,                                                                                          
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,                                                                                          
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,                                                                                          
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,                                                                                          
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,                                                                                          
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101,
        0b00000100,0b00000110,0b00000010,0b00001010,0b00001000,0b00001001,0b00000001,0b00000101                                                                                             
};                                                         
             
unsigned int8 nowStep = 0;        
                                                                                                                 
#INT_TIMER1                                                     
void LoadDrop_isr()      
{                                                                           
        output_c(0);              
}                                                                                                          
                                                                                                       
#INT_EXT                    
void clk_isr()
{                                    
   //input_state(DIR) ? nowStep++ : nowStep--;                                                 
        #asm asis              
        BTFSC  05.1 
        INCF   nowStep,F         
        BTFSS  05.1                                                      
        DECF   nowStep,F    
        #endasm             
                    
        output_c(steps[nowStep]);
        set_timer1(0);          
}                                       
                                                                                                                                                    
void main()                                                                                                                                  
{                            
        output_a(0);                         
        input_a();  
                
        set_tris_c(0);                    
        output_c(0);  
                                   
        setup_comparator(NC_NC_NC_NC);                        
        setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);                       
        set_timer1(0);                                                          
                                  
        ext_int_edge(L_TO_H);    
                                                                  
        enable_interrupts(INT_TIMER1);             
        enable_interrupts(INT_EXT);                   
        enable_interrupts(GLOBAL);  
                                                                            
        unsigned int16 blinkCounter = 0; 
                     
        MAIN_LOOP:                    
                                          
                 if(!blinkCounter++)              
                        output_toggle(LED);        
                                        
        goto MAIN_LOOP;                                                                                                                                                      
}                                               


Для описания кода, проще будет начать с логики работы контроллера. При запуске контроллера происходит начальная настройка железа и включение прерываний. Номер шага хранится в беззнаковой 8-и битной переменной nowStep и в начале номер равен нулю. Далее запускается вечный цикл программы в MAIN_LOOP в котором происходит просто моргание светодиодом подключенного к пину A0. Для чего? Во-первых, видно что камень не подвис, во-вторых, спецэффекты! Пин А2 настроен на внешнее прерывание по восходящему фронту. Когда на ноге будет зарегистрировано событие, будет обработано прерывание INT_EXT в котором происходит переключение следующего шага. Для вывода следующего шага происходит инкремент или декремент указателя шага nowStep в зависимости от входного DIR. Затем из массива шагов steps из позиции nowStep целиком в порт выводится новая комбинация коммутации обмоток двигателя. Так же, в начале инициализации микроконтроллера происходит настройка и запуск таймера 1. Этот таймер сбрасывает выходные сигналы, чтобы предотвратить перегрев двигателей. Таймер сбрасывает выходные сигналы через примерно 100 мс после выставления сигнала. То есть это сугубо мера предосторожности.

В симуляции удалось достичь периода сигнала CLK в 15 мкс, что соответствует частоте в 66.(6) КГц. Для первого раза не плохо, я думаю, хотя, дальнейшая оптимизация возможна.

Разработка драйвера шагового двигателя


Тут далеко идти не придется. Схема типовая. Драйвер построен на базе готового драйвера L298N.

7111a941b9a94635a5975269be324934.BMP

Зачем резисторы R1 — R4? Честно сказать, я не знаю. Изначально в документации идет схема в связке с L297, вся связь без резисторов. Однако в интернете находил схемы с резисторами на линиях. Посмотрел на блок-схему в даташите на L298N. Все INPUT линии заходят на инверсный вход И элемента. Ничего случится не должно и без резисторов. Но я решил не рисковать и на всякий случай вставить, на этот раз. Много хуже не будет, упадет крутизна фронта на входе.

В остальном схема повторяет ту, что дана в даташите.

Разработка оптической развязки


Плата опторазвязки служит для защиты управляющей машины, в данном случае компьютера, от силовой части станка. Так, что если что-то начнет дымиться со стороны станка, оно додымит только до платы опторазвязки и минимизирует ущерб.

Схема достаточно габаритная, так что кликайте чтобы увидеть фул сайз.

683e541826bf402cb3600af4cdae69a7.BMP

Изначально были взяты оптопары 4N25. Ибо подумал, что 60 кГц вытянет любая сегодняшняя оптопара. Но на деле, нет, не вытянули, не успевали. По этому в результате пришлось заменить на 6N135, у которых быстродействие значительно выше (до 2MHz по даташиту). По пинам они не совместимы напрямую, однако, удалось их вставить без переделки платы целиком. Новой схемы я не делал, думаю, кому захочется, тот сможет переразвести плату самостоятельно.

Как и должно быть, питание схемы разделено на две части, со стороны станка и стороны компьютера. Со стороны компьютера питание подается через USB кабель, это его единственное назначение. Со стороны станка уже любая связка проводов на 5 В.

Разработка планки питания


Так же, так как делалось все не монолитом, а мелкими блоками, то нужно было развести больше проводов чем обычно для питания и для сигналов. По-этому для упрощения разводки я решил сделать отдельную маленькую планку с коннекторами для разводки питания по линиям 12 В и 5 В.

8dbd473b3a564317a62690cdb4dfeea6.BMP

Планка питания содержит по шесть коннекторов для линий 5 В и 12 В, а так же два отдельных коннектора для подключения кулеров.


Так как фотографировать начинал не с самого начала, да и написание статьи не планировалось, то многие шаги сборки отсутствуют, однако те что есть я покажу. Все фото в этом разделе кликабельны.

Изготовление драйвера шагового двигателя


Перенес рисунок ЛУТом:

ccd2f7964c3a40d5bafcb6dbda745d18.jpg

Вытравил и залудил:

ba94e763a5844cfe8de4a8c2861ddf14.jpg

Просверлил:

79d2d6278f38499ca18524efbfdd3f65.jpg

Запаял:

89a8f9d47c614d42a9eba503d1b8b639.jpg

5c2250e65a2c430ea2623a0a0a67f0af.jpg

Далее нужно было повторить успех еще для 2-х осей:

65c133e9141a434b88a25ae8983c5a00.jpg

Изготовление платы оптической развязки


a6b8d8580fa34e71b7e5da8dff87fabd.jpg

Перенес ЛУТом и поправил маркером:

9a4563c34ae14873ad7bace00ab1bdc6.jpg

Вытравил:

0ce22ecab11f4f18a4f76d52a36be815.jpg

14adb447bc8f4a5d9f5d20d20bad338c.jpg

Залудил:

fc2ca7cbb33d4c60b022657fbbae53c6.jpg

В сборе вся электроника:

5d75c9660b214fbd9cb04f973338bb69.jpg

354935414bc3479b86469e8590fb91be.jpg

3e2ba274966240db85f7f749159c98b1.jpg

Сборка станка


Станок собирался из фанеры 10 мм толщиной и 18 мм досок. При сборке использовались мебельные направляющие, лучше на первый раз ничего не нашел, а обрабатывать хотя бы те же металлические уголки психологически не был готов.

Сначала была такая конструкция:

a7624b17dc4045a593cabaf73c7e3a22.jpg

56d36e33eec647d08161e4ed993cdadc.jpg

Первый вариант оси Z:

865583307c5e454d8c0921c7bb59568f.jpg

Но как я сейчас понимаю, это вообще никуда не годилось, все ездило, шаталось. В общем, ни о какой жесткости и речи не было.
Последовала другая попытка:

c0a870b3b6ca407eb4f8242627e05236.jpg

47641620928a414ab7e953ab4903a351.jpg

В ходе которой оси X и Y были вынесены на отдельную площадку и превратились в подвижный стол:

b1490140733d4fd88e6e4f6d02b034d6.jpg

Уже было лучше, но все равно очень далеко от чего-то не шатающегося. В итоге пришел к такому варианту:

c4367dac0a684b9793be4971e6081ba8.jpg

Однако ось Z все еще слишком сильно дергалась и прогибалась. На этот раз я сел и хорошо подумал и уже занялся некоторым проектированием. В итоге получилась такая конструкция:

16c19da1817141f580e225d25fd4d846.JPG

В качестве направляющих использованы равнополочные алюминиевые уголки с полкой 25 мм и толщиной 2 мм. Стальных не смог найти. Они были бы много раз лучше. Направляющие промышленного изготовления, конечно, все равно не идут ни в какое сравнение.

Подвижная каретка:

f35c6c614f364f669247a089feed0ff3.jpg

3bf87a6c21d54909b2b0160b2300296a.jpg

В сборе новая ось Z:

6c21f5c48ba24679a84c9d6ce08f3146.jpg

b41cee6bdf0f4c9993782afaaa47d02f.jpg

Результат. Можно заметить, что собранная ось, и конструкция в целом, все же отличается даже от спроектированной. Все же совместить и центрировать ось когда из точных инструментов у тебя только штангенциркуль и ручная дрель довольно не простая задача. По этому пришлось передумывать и экспериментировать на ходу:

311f3a00453a45f5a1b803240fa4af5e.jpg

ac4f4558bf6e4205b9b77ca3f40a8a71.jpg

Пробы что-то выфрезеровать:

Даже с таким большим количеством если, даже с такой несовершенной конструкцией получилось создать что-то рабочее и полученный результат меня впечатлил.

Управляющий компьютер


Управляющее ПО станков с ЧПУ должно работать на системах реального времени, чтобы генерировать точно синхронизированные сигналы. По-этому, Windows не очень хорошо для этого подходит. Конечно, для правильной работы написаны драйвера которые решают эту проблему, но ресурсов обычно это требует больше, а стабильность такой системы ниже чем систем реального времени.
Обработка велась под управлением LinuxCNC. Установка и настройка не должна вызвать больших трудностей. На сайте программы уже есть готовые билды так и исходники для гурманов. Существует несколько способов установки: на уже установленную систему или с нуля вместе с настроенной ОС. Я выбрал второй вариант, так как не на столько опытен в работе с Linux, и времени было маловато, чтобы разбираться с процессом пропатчивания. Второй вариант представляет из себя обычный Debian дистрибутив с RTC ядром и уже установленным LinuxCNC.

После установки необходимо настроить оси станков: маппинг сигналов, скорости движения, величины ускорения и прочее. В результате получится выходной файл для запуска, который, при запуске, покажет саму программу управления станком с заданными параметрами.


В итоге проделанной работы осталось как много впечатлений, так и вопросов и задач для улучшения полученного станка.

  1. Повысить напряжение питания двигателей с 12 В до их рабочих 24 В
  2. Укрепить конструкцию, а в идеале подготовить новый проект станка с предварительным полным проектированием
  3. Добавить концевые переключатели и кнопку аварийной остановки
  4. Провести оптимизацию работы контроллеров ШД
  5. Пересобрать электронику станка на одной плате за исключением платы опторазвязки
  6. Заменить шпиндель станка на соответствующий целям. То есть высоко оборотистый и более мощный двигатель, чем текущий китайский гравер.
  7. Заменить двигатель на оси Z, так как текущий двигатель меньше по мощности и самый нагруженный


Полученный станок обладает рабочей областью больше 270 мм по осям X и Y, и около 150 мм по Z. Скорости перемещения по осям X и Y больше 500 мм/с, а по Z 300 мм/с. Это при 12 В рабочего напряжения. То есть половина от их рабочих характеристик. Есть куда расти.

Что можно сказать с уверенностью — это того стоило. Как минимум с одной задачей станок справится хорошо уже сейчас: вырезание плат. Можно забыть о травлении и ЛУТ. У вырезания плат есть, конечно, свои недостатки, но лучше иметь альтернативы, чем единственный вариант. На видео работы было видно как станок фрезой 3 мм фрезеровал букву М, может и с малой скоростью подачи и слоями по 0.1 мм, но это тоже результат.

Выкладывать какие-то исходники или PCB плат не вижу особого смысла пока что. Станок не получился пригодным для каких-либо серьезных нагрузок или достаточно устойчивым и уникальным. Однако, это не последняя попытка что либо сделать и готовится следующая итерация разработки, надеюсь, более качественная.

© Geektimes