Как выбрать комплектующие для станка с ЧПУ

А можно…?

Отвечаю сразу — МОЖНО! Все можно! Только нужно ли?

«А можно вместо четырех шариковых блоков поставить на каретку два? Будет почти в два раза дешевле» — Можно! Но я поставил четыре, и вам советую.

«А можно заменить обычные профили станочными? Будет лучше» — Можно! В каком-то смысле действительно будет лучше. Скажем так, будет лучше ровно на столько, на сколько, к примеру, станут лучше «Жигули», если поставить на них семнадцатидюймовые колеса от «Мерседеса», Но дороже будет, это точно!

«А можно для увеличения прочности заменить не внушающие доверия алюминиевые профили хорошими стальными?» — Можно! Если удастся подобрать подходящие по размеру, и при условии замены шариковых направляющих на 20-й типоразмер. Кстати и ремни нужно взять потолще, и двигатели помощнее, и, чего там мелочиться, лучше сразу на ШВП перейти.

«А можно такой станок сделать размером 2х3 метра, и чтобы 10 мм фанеру пилил со скоростью 600 мм/мин.?» — Можно! Только профили нужно брать станочные и крепить их к стальным сварным рамам, и ремни заменить зубчатыми рейками и моторы брать с редукторами, и прочее по мелочам.

«А можно вместо дорогих шариковых направляющих применить обычные шарикоподшипники, чтобы все так же ездило?» — Можно! Ездить будет! Но я все-таки разорился на рельсы и дорогие линейные подшипники, сами догадайтесь почему.

«А можно вместо импортных шариковых линейных направляющих использовать наши, отечественные, мебельные, или компьютерные?» — Можно! См. ответ на предыдущий вопрос.

«А вот у меня нет ни дрели, ни ножовки по металлу. Как быть?» — Займите у соседа или купите… лучше сразу готовый станок.

«Хочу построить такой же станок как у вас. Не могли бы вы: дать мне готовые чертежи, ткнуть носом, где продаются все комплектующие, отвести за руку к дяде, который выточит нужные детали, оказать помощь в изготовлении, сборке и настройке станка, консультировать, отвечать на вопросы, и вообще, всячески содействовать?» — Мог бы, если у вас хватит денег на все это содействие.

Такие, вот, дела.

Задача

Вообще говоря, «на скорую руку» делаются бутерброды и салаты, романтический ужин можно соорудить на скорую руку, но не станок. Тем не менее, я вынес это словосочетание в заголовок статьи. Почему? Попробую объяснить.

«На скорую руку» это значит технологично для домашнего производства. Т.е. станок должен быть сконструирован так, чтобы его можно было изготовить, используя минимальный набор самых обычных слесарных инструментов. Буквально, если у вас в арсенале имеется электролобзик с пилкой по металлу, сверлильный станок, плашки-метчики и напильник, то этого должно быть достаточно. На худой конец, сгодится простая ножовка по металлу и дрель.

Кое-кто скажет: «Ну, ты загнул, товарищ! Так не бывает», и будет прав. Так действительно не бывает. Потому что, если фрезерные работы можно исключить полностью, то без элементарных токарных работ нам не обойтись, значит, работ этих должно быть совсем не много, все остальное – ручками, на кухне.

Ставя перед собой такую задачу, надо хорошо понимать, что осуществить задуманное можно только при условии широкого применения покупных комплектующих и стандартных алюминиевых профилей. Направляющие – этакие краеугольные камни портального гравировально-фрезерного станка — тоже придется купить, а они дорогие. Так что, «на скорую руку» не значит дешево!

И последнее соображение. «На скорую руку» ассоциируется с понятиями просто и быстро. Если с определением «просто» можно согласиться, то быстро вряд ли получится. Изготовление даже простых деталей может затянуться на неопределенный срок, но как говорится, «терпение и труд – все перетрут».

Подытожим:

  • Для фрезерования бальзы, фанеры, дерева, пластиков и тонких (до 2 мм) алюминиевых сплавов.
  • На линейных шариковых направляющих и зубчатых ремнях.
  • Рабочее поле не менее 1000х300х90.
  • Разрешение позиционирования не хуже 0,1 мм.
  • Скорость позиционирования не менее 2 м/мин.

Как я собирал чпу фрезер, и в каких моментах не стоит за мной повторять

Всем привет.

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

Изучая конструкции фрезерных станков, я понял, что они достаточно разнообразны, в аспекте количества осей, перемещения по ним материала и фрезера, и прочих тонкостей. Где-то, в одном станке работают несколько синхронизированных фрезеров, где-то используется сложная система рычагов, которая позволяет рассчитать положение по сложной формуле. Апофеозом конструкторской гениальности считаю вот такое:

Как выбрать комплектующие для станка с ЧПУ

Но вернемся к моей идее — она была в том, чтобы раскраивать листовой материал, и фрезеровать в 3d какие-то мягкие формы, например, полистирола.

Конструктив рамы был выбран из соображений жесткости треугольной формы (как водится, ее изменили уже на ходу):

Как выбрать комплектующие для станка с ЧПУ

Плюс такой конструкции в том, что станок занимает меньше места, и намного проще установка на него нового листа. Бонус — стружка падает вниз (но ее все равно надо отводить, так что это не очень важно).

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

Как выбрать комплектующие для станка с ЧПУ

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

Жесткий каркас станка с горизонтальным столом.
Жесткий каркас станка с горизонтальным столом.

Механика. На оси Z установлена ШВП (шарико-винтовая передача).

ШВП
ШВП

ШВП обеспечивает максимальную точность позиционирования инструмента, но медленное перемещение. Имея серводвигатели, которые раскручиваются до серьезных оборотов, это не проблема, а у шаговых двигателей таки есть предел разумного использования. Но есть и еще одна проблема с винтом. Будучи свободным, на больших длинах он деформируется, плюс у него есть инерция, и имеет место явление резонанса. Поэтому я решил остальные 2 оси X,Y делать на зубчатой рейке, что на текущий момент считаю ошибкой. Дело в том, что в интернете мало информации, и только недавно в широкой продаже в РФ появились готовые подвижные гайки с редукторами для ШВП — это, по идее, решает проблему инерции винта (но не резонанса).

Как выбрать комплектующие для станка с ЧПУ

Что касается передачи на зубчатой рейке, с ней все неплохо, кроме одного — люфты. Они возникают из-за точности исполнения, и неточности установки. Та рейка, которую я купил, была дешевой и тонкой, поэтому испытывает деформации. Не советую делать так.

Фрезер. Я решил для начала взять чего попроще, с воздушным охлаждением (и так по сей день и оставил). Это, конечно, kress. Дешево, и со вкусом. Видел в интернете схемы переделки на цифровое управление оборотами шпинделя, и даже пневмо автосмену (!) инструмента kress — то есть в случае чего можно ловко наколхозить, и будет как у взрослых дядь на станках за $100K.

Про другие станки:  Самодельный режущий плоттер для пленки - МозгоЧины

Что по механике. Ось X — внезапно это та, по которой ездит Z (хотя как по мне, логичней чтоб по Y), двигается ШД с планетарным редуктором. По дурости, я умудрился свернуть шляпки двух болтов, и поэтому там 2 из 4, но ничего. Шестерня зафиксирована на конус фиксатор резьбы неразъемный.

Как выбрать комплектующие для станка с ЧПУ

Ось Y Устроена сложнее. Там тоже редуктор, но червячный, итальянский, далее полуоси через карданы от Волги, и на концах еще ременные редуктора. Очень важно застопорить эти редуктора на зубчатой рейке, чтоб не было люфта. По какой-то причине, я решил, что мебельные лифты подойдут (нет). При фрезеровании сила противодействия такая, что лифт отжимает насколько, что перескакивает шестерня. Пришлось поверх этого колхозить прижимающий эксцентрик.

Как выбрать комплектующие для станка с ЧПУ
Как выбрать комплектующие для станка с ЧПУ

Вообще, ось Z — самое мощное что есть в станке, все остальное, фактически на соплях. Изначально, правда, я вообще хотел взять могучую металлическую балку к качестве X, зафиксировать ее на бетонных колоннах, и гонять под ней подвижный стол — но по причине пыли, от этого решения пришлось отказаться, станок стал более традиционным и переехал в отдельную комнату. Вот эта балка, лежит во дворе под снегом (от нее уже отрезаны куски болгаркой в хозяйственных целях). Если вы решите заняться сооружением промышленных девайсов дома, вряд ли и вы избежите переделок.

Вот так это должно было быть в первом варианте
Вот так это должно было быть в первом варианте
Как выбрать комплектующие для станка с ЧПУ

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

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

Как выбрать комплектующие для станка с ЧПУ

На сладкое я решил оставить электронику. У меня была назойливая идея — запихнуть все в системный блок от компа (и протянуть туда канал чистого воздуха из другой комнаты), и я ее успешно реализовал, но с оговоркой — драйвера под всасывающий вентилятор встали впритык на 3 оси. Как можете видеть, монтаж на стяжках четкий, блок можно поворачивать на 90% не переживая.

Как выбрать комплектующие для станка с ЧПУ

Там, где в оригинале должны стоять CD и жесткие диски, располагаются драйвера, на них я поставил втягивающий вентилятор, и будучи осведомленным о пыли, к нему протянул вентканал и гофру из соседней комнаты (теперь не помешает также щель или клапан на улицу, так как избыток давления, очевидно, тупо выдавливает через дверные щели (это ощущается). В передней и нижней части размещены блоки питания драйверов (несложно понять, что один из них запитывает 2 драйвера, и теоретически можно запихнуть в системный блок все 5 драйверов, купив мощный БП, поскольку отбор максимальной мощности вряд ли будет со всех 5 одновременно, а во время удержания потребляемая мощность ШД не очень большая).

В задней нижней зоне, над материнкой, располагается плата управления, в которую по идее должны заходить 5*4=20 входов только с драйверов, но часть из них идет на один вход, так что все ок. Остальные выводы нужны на всякое — на концевики, питание шпинделя, его обороты (если бы они были цифровыми).

Как выбрать комплектующие для станка с ЧПУ

Прямо из ввода 220В в системный блок я сделал питание монитора и пылесоса, чтоб не плодить 10 выключателей (клемы Wago слева внизу).

По факту, для раскроя материала станок пригоден более чем — да, где-то на рейке может вылезти небольшой люфт, но когда толщина материала пару мм, и тонкая фреза с такой же в пару мм высотой рабочей кромки, это не играет особой роли. С длинными фрезами для 3D фрезерования есть вопросы (они и существенно дороже раскройных), я подумываю об усилении оси X и переводе всех осей на ШВП, но это дело будущего.

Как выбрать комплектующие для станка с ЧПУ

Что хотелось бы сказать в завершение. Если вас что гнетет какая-то идея, а допустим, ваша жена против, следуйте велению своего сердца. Если оно говорит, что надо закончить проект, так и поступайте (если оно говорит — беспрекословно слушаться жену, возможно, это тоже разумный путь).

Всем удачи!

P.S. Пишите в ЛС, на youtube и т.д., если вас сильно интересует тот или иной вопрос.

Проводка зубчатого ремня

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

Концы ремня закрепим на раме. Одну прижимную планку зафиксируем жестко, а другая будет иметь возможность перемещаться для натяжения ремня в пределах расстояния между соседними зубьями, т.е. в пределах 5 мм. Зубчатое колесо, как обычно, насаживается на вал мотора.

Чем же такой способ лучше кольцевого ремня? Да, хотя бы тем, что расход ремня в два раза меньше, натягивать проще, экономия на зубчатых колесах, которые дорогие и их надо покупать вместе с ремнем. Ролики с осями можно подобрать готовые. В общем есть в таком решении плюсы. А минусы? Не знаю….

Кабели от моторов таскать за порталом? Так их все равно таскать от осей Y и Z, плюс-минус несколько проводов – не принципиально. Вес портала увеличится? Увеличится. И это, наверно, единственный минус, о котором стоит говорить. Цена вопроса 1,5…2 кг (вес моторов)

и/или 100 долларов США (длинный ремень и дополнительные зубчатые колеса). Я выбрал экономию денег, а не веса. При таких размерах портала экономия двух килограммов его массы существенного выигрыша не дает. В конце концов, при использовании зубчатых реек моторы стоят именно на каретках.

Ремень надо брать с относительно мелким зубом. Я выбрал любезный моему сердцу ремень от хвостовой балки модели вертолета «Раптор 50». Он имеет шаг зубьев 5 мм. Зубчатое колесо тоже от этого вертолета. Его диаметр (по средней линии зубьев) 14 мм.

Значит при включении двигателя в полушаговом режиме (400 шагов на оборот) перемещение каретки на один шаг будет 3,14*16/400 = 0,11 мм. Это больше, чем задумано. В микрошаге (1:6) перемещение на шаг получается 0,042 мм. То, что надо. И хотя «не тянущийся» ремень все равно чуть-чуть тянется, зато в ремне отсутствует накопленная ошибка, которая всегда присутствует в ходовом винте.

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

Устанавливаем все это дело на раму и проверяем, как ездит. Ездит хорошо!

Про другие станки:  Комплектующие для самодельного станка ЧПУ из Китая | Пикабу

Собственно, это почти все с рамой. Осталось «причесать», придать изделию «товарный вид» и установить столешницу.

Проектирование станка с чпу. часть 2. постановка задачи

Итак, первый шаг – определить круг изделий, которые будут производиться на станке. Это даст возможность вычленить следующие параметры размеры рабочего поля. Размеры поля соответственно дадут представление о возможном весе станка и его габаритах. Рабочее поле не должно существенно превышать необходимое.

  1. Обрабатываемые материалы и режимы обработки. Эти данные следует использовать, чтобы вычислить такую информацию как планируемый к использованию инструмент. Очень важно тщательно определить минимальный и максимальный тип и размер фрез, это затем скажется на выборе шпинделя, а он, в свою очередь, обуславливает всю остальную конструкцию станка. Надо определить вид и размер фрез, будут ли использоваться резьбонарезные головки или точное позиционирование инструмента, потребуется ли автоматическая смена, будут ли использоваться шпиндели с инструментальными конусами или достаточно цангового зажима типа ER и т.п.
  2. Усилия резания на фрезе. Максимальное усилие резания на фрезе обязательно необходимо если не знать более-менее точно, то как минимум иметь интуитивное представление о нём. Усилия резания — параметр, исходя из которого определяется жесткость, т.е. важнейшая характеристика будущего станка. Станок с недостаточной жесткостью будет выдавать некачественную поверхность, ломать фрезы, изнашивать шпиндели и направляющие, с избыточной жесткостью – будет дорогим, громоздким и экономически неэффективным.
  3. Модель или хотя бы тип и размер шпинделя. Он достаточно определенно вытекает из предыдущих 2 пунктов. Под разные шпиндели – разные станки!
  4. Комплектация станка. От обрабатываемых материалов зависит, нужна ли будет система защиты направляющих от стружки/пыли, подача СОЖ, вытяжка для удаление продуктов резания и т.п. Скажем, для деревообрабатывающих станков практически невозможно работать без вытяжки, но не нужна СОЖ, а для станков по алюминию – наоборот, для станков по алюминию защита направляющих желательна, но в целом опциональна, а для станков по чугуну – просто необходима, и т.д.
  5. Количество осей. В зависимости от требований к изделиям станок может быть 3-осевым, 4-осевым (с 1 поворотной осью), 5-осевым (с 2 поворотными осями). Число осей также сильно влияет на конструкцию станка, его сложность и стоимость.
  6. Ход по осям и вылет шпинделя. Эти данные на данном этапе определяются примерно, без особой точности, для получения модели действующих сил в первом приближении.

Создание станка с чпу из доступных деталей с минимум слесарной работы

Продолжаем обзор деятельности нашего

Хакспейс-клуба

.

Мы давно мечтали купить в наш клуб ЧПУ станок. Но решили его сделать сами. С нуля, начиная от железа и кончая программного обеспечение (прошивка контроллера и управляющая программа). И у нас это получилось.

Детали для станка старались выбирать из доступных в свободной продаже, многие из которых даже не требуют дополнительной слесарной обработки.

Как выбрать комплектующие для станка с ЧПУ

Контроллер мы выбрали Arduino Mega 2560 и что бы много не думать, драйвер шаговых двигателей использовали RAMPS 1.4 (как у RepRap 3D принтера).

Как выбрать комплектующие для станка с ЧПУ

Программу контроллера писали по алгоритму метода конечных автоматов. Последний раз я о нем слышал лет 20 назад в институте, не помню по какому предмету изучали. Это была очень удачная идея. Код получился маленький и легко расширяемый без потери читабельности (если в дальнейшем понадобится не только оси XYZ, или использовать другой G-код). Программа контроллера принимает с USB порта G-код и, собственно, дает команду двигателям осей XYZ двигаться в заданном направлении. Кто не знает, G-код — это последовательность конструкций типа G1X10Y20Z10, которая говорит станку переместится по оси X на 10 мм, Y на 20 мм и Z на 10 мм. На самом деле, в G-коде много различных конструкций (например, G90 — используется абсолютная система координат, G91 — относительная) и много модификаций самого кода. В интернете много о нем описано.

Подробнее остановлюсь на описание скетча (прошивка контроллера).

Вначале в описании переменных прописываем, к какому выходу контроллера будет подключены двигатели и концевые выключатели.

В этом коде метода конечных автоматов переменная принимает значение ждать с USB порта первый байт, во второй конструкции case производится проверка наличия данных и переменная _s принимает значение get_cmd. Т.е считать данные с порта.

 switch(_s){
  case begin_cmd:         Serial.println("&"); //038
                          //to_begin_coord();
                          n_t=0;
                          _s=wait_first_byte;
                          len=0;
                          break;
                          
  case wait_first_byte:   if(Serial.available()){
                              Serial.print(">");
                             _s=get_cmd;
                              c_i=0;
                           }
                          break;

Далее считываем все, что есть в порту, переменная _s устанавливается в get_tag; т.е. переходим на прием буквенного значение G – кода.

case get_cmd:           c=Serial.read();
                          if(c!=-1){
                              if(c=='~'){
                                _s=get_tag;
                                c_i=0;
                                n_t=0;
                                break;
                              }
                           Serial.print(c);
                           if((c>=97)&&(c<=122))
                             c-=32;
                           if( (c==32)||(c==45)||(c==46)||((c>=48)&&(c<=57))||((c>=65)&&(c<=90)) ){
                             cmd[c_i  ]=c;
                             len  ;
                           }
                          }
                          break;

Ну и так далее.

полный код можно посмотреть здесь.

#include <Stepper.h>
#define STEPS 48
//#define SHAG 3.298701
#define STEP_MOTOR 1
double koefx = 1.333333;
double koefy = 1.694915;
Stepper stepper0(STEPS, 5, 4, 6, 3);
Stepper stepper1(STEPS, 8, 9, 10, 11);
Stepper stepper2(STEPS, 13, 12, 7, 2);
int x,y,x1,m;
int motor;
int inPinX = 15;                   // кнопка на входе 22
int inPinY = 14;                   // кнопка на входе 23
int inPinZ = 24;                   // кнопка на входе 24
int x_en = 62;
int x_dir = 48;
int x_step = 46;
int y_en = 56;
int y_dir = 61;
int y_step = 60;
const int begin_cmd=1;
const int wait_first_byte=2;
const int wait_cmd=3;
const int get_cmd=4;
const int test_cmd=5;
const int get_word=6;
const int get_tag=7;
const int get_val=8;
const int compilation_cmd=9;
const int run_cmd=10;
int abs_coord=1;
const int _X=1;
const int _Y=2;
//const int =10;
//const int =11;
//const int =12;


int _s=begin_cmd;
const int max_len_cmd=500;
char cmd[max_len_cmd];
char tag[100][20];
char val[100][20];
int n_t=0;
int c_i=0;
char c;
int i,j;
int amount_G=0;
int len=0;
char*trash;
int n_run_cmd=0;
int g_cmd_prev; //ya предыдущее значение G
class _g_cmd{
public:
_g_cmd(){
 reset();
}
int n; //ya
int g;
double x;
double y;
double z;
void reset(void){
 n=g=x=y=z=99999;
}
};
double _x,_y,_z;
double cur_abs_x,cur_abs_y,cur_abs_z; //ya stoyalo int
int f_abs_coord=1;

_g_cmd g_cmd[100];

void setup()
{

  stepper0.setSpeed(150);
  stepper1.setSpeed(150);
  stepper2.setSpeed(1000);
  Serial.begin(9600);
  pinMode(inPinX, INPUT);
  pinMode(inPinY, INPUT);
  pinMode(inPinZ, INPUT);
  pinMode(x_en, OUTPUT);
  pinMode(x_dir, OUTPUT);
  pinMode(x_step, OUTPUT);
  pinMode(y_en, OUTPUT);
  pinMode(y_dir, OUTPUT);
  pinMode(y_step, OUTPUT);
  digitalWrite(x_en, 1);
  digitalWrite(y_en, 1);
   to_begin_coord();
  //UNIimpstep(12,13,2,7,3,1000);
  //UNIimpstep(12,13,2,7,3,-1000);
}

void to_begin_coord(void)
{
 impstep(_X,-10000,1);
 impstep(_Y,-10000,1);
 cur_abs_x=cur_abs_y=cur_abs_z=0;
}

void loop()
{
  switch(_s){
  case begin_cmd:         Serial.println("&"); //038
                          //to_begin_coord();
                          n_t=0;
                          _s=wait_first_byte;
                          len=0;
                          break;
                          
  case wait_first_byte:   if(Serial.available()){
                              Serial.print(">");
                             _s=get_cmd;
                              c_i=0;
                           }
                          break;
                          
  case get_cmd:           c=Serial.read();
                          if(c!=-1){
                              if(c=='~'){
                                _s=get_tag;
                                c_i=0;
                                n_t=0;
                                break;
                              }
                           Serial.print(c);
                           if((c>=97)&&(c<=122))
                             c-=32;
                           if( (c==32)||(c==45)||(c==46)||((c>=48)&&(c<=57))||((c>=65)&&(c<=90)) ){
                             cmd[c_i  ]=c;
                             len  ;
                           }
                          }
                          break;

 
  case get_tag:           while((c_i<len)&&(cmd[c_i]<=32)) c_i  ;
                          i=0;
                          while((c_i<len)&&(cmd[c_i]>=65)){
                             tag[n_t][i]=cmd[c_i];
                             i  ;
                             c_i  ;
                             while((c_i<len)&&(cmd[c_i]<=32)) c_i  ;
                          }
                          if(i==0){
                            Serial.println("er2 cmd - 'no tag'");
                            _s=begin_cmd;
                            break;
                          }
                          tag[n_t][i]=0;
                          _s=get_val;
                          break;
                          
  case get_val:           while((c_i<len)&&(cmd[c_i]<=32)) c_i  ;
                          i=0;
                          while((c_i<len)&& ( (cmd[c_i]=='.')||(cmd[c_i]=='-')||((cmd[c_i]>=48)&&(cmd[c_i]<=57)) ) ){
                             val[n_t][i]=cmd[c_i];
                             i  ;
                             c_i  ;
                             while((c_i<len)&&(cmd[c_i]<=32)) c_i  ;
                          }
                          if(i==0){
                            Serial.println("er3 cmd - 'no val'");
                            _s=begin_cmd;
                            break;
                          }
                          val[n_t][i]=0;
                          n_t  ;
                          _s=get_tag;
                          
                          if(c_i>=len)
                              _s=compilation_cmd;
                          break;
                        
  case compilation_cmd:   Serial.println("");
                          Serial.print("compilation cmd,input (");
                          Serial.print(n_t);
                          Serial.println("): ");

                          for(i=0;i<n_t;i  ){
                            Serial.print(i);
                            Serial.print("=");
                            Serial.print(tag[i]);
                            Serial.print("(");
                            Serial.print(val[i]);
                            Serial.println(")");
                          }
                          for (int k=0; k<=j; k  )
                          {
                          g_cmd[k].reset();
                          }
                         j=0;
                         i=0;

                         while(i<n_t){
                          if(tag[i][0]=='N'){
                           g_cmd[j].n=(int)strtod(val[i],&trash);
                           i  ;
                           while((i<n_t)&&(tag[i][0]!='N')){ //(g_cmd[j].g==1)&&
                                if(tag[i][0]=='G'){
                                   g_cmd[j].g=(int)strtod(val[i],&trash);
                                   g_cmd_prev = g_cmd[j].g;
                                }
                                else { g_cmd[j].g = g_cmd_prev;
                                }
                            if(tag[i][0]=='X')
                               g_cmd[j].x=(double)strtod(val[i],&trash);
                            if(tag[i][0]=='Y')
                               g_cmd[j].y=(double)strtod(val[i],&trash);
                            if(tag[i][0]=='Z')
                               g_cmd[j].z=(double)strtod(val[i],&trash);
                            i  ;
                           }//while((i<n_t)&&(tag[i]!="G"))
                           j  ;
                          }//if(tag[i]=="G")
                          else i  ;
                         }//while(i<n_t)
                         amount_G=j;

                        Serial.print("compilation cmd,output (");
                        Serial.print(amount_G);
                        Serial.println("): ");
                  
                         for(j=0;j<amount_G;j  ){
                            Serial.print(j);
                            Serial.print("=");
                            Serial.print("N");Serial.print(g_cmd[j].n);Serial.print(" ");
                            Serial.print("G");Serial.print(g_cmd[j].g);Serial.print(" ");
                            Serial.print("X");Serial.print(g_cmd[j].x);Serial.print(" ");
                            Serial.print("Y");Serial.print(g_cmd[j].y);Serial.print(" ");
                            Serial.print("Z");Serial.print(g_cmd[j].z);Serial.println(" ");
                         }
                         
                         n_run_cmd=0;
                         _s=run_cmd;
                         break;

  case run_cmd:          
                         Serial.print("run cmd [");
                         Serial.print("N");Serial.print(g_cmd[n_run_cmd].n);Serial.print(" ");
                         Serial.print("G");Serial.print(g_cmd[n_run_cmd].g);Serial.print(" ");
                         Serial.print("X");Serial.print(g_cmd[n_run_cmd].x);Serial.print(" ");
                         Serial.print("Y");Serial.print(g_cmd[n_run_cmd].y);Serial.print(" ");
                         Serial.print("Z");Serial.print(g_cmd[n_run_cmd].z);Serial.print(" ");
                         Serial.println("]");

                         int f_cmd_coord=0;
                         if(g_cmd[n_run_cmd].g==90){
                            f_abs_coord=1;
                            f_cmd_coord=1;
                            Serial.println("change to ABS coord");
                         }
                         if(g_cmd[n_run_cmd].g==91){
                            f_abs_coord=0;
                            f_cmd_coord=1;                            
                            Serial.println("change to REL coord");
                         }
                         Serial.print("cur_abs(");Serial.print(cur_abs_x);Serial.print(",");Serial.print(cur_abs_y);Serial.print(",");Serial.print(cur_abs_z);Serial.println(")");
                         if(f_cmd_coord){if(  n_run_cmd>=amount_G) _s=begin_cmd; break;}
                         
                         if(f_abs_coord){
                            Serial.println("zdes kosjak G90 ABS");
                            if (g_cmd[n_run_cmd].x==99999)
                            _x=0;
                            else
                           _x=g_cmd[n_run_cmd].x-cur_abs_x;
                            if (g_cmd[n_run_cmd].y==99999)
                            _y=0;
                            else
                           _y=g_cmd[n_run_cmd].y-cur_abs_y;
                           if (g_cmd[n_run_cmd].z==99999)
                            _z=0;
                            else
                           _z=g_cmd[n_run_cmd].z-cur_abs_z;
                           
                         }else{
                           Serial.println("normalno G91 REL");
                           _x=g_cmd[n_run_cmd].x;
                           _y=g_cmd[n_run_cmd].y;
                           _z=g_cmd[n_run_cmd].z;                         
                         }

                         if((_x==0)&&(_y==0)&&(_z==0)){
                           Serial.println("exit: _x=0,_y=0,_z=0");
                           if(  n_run_cmd>=amount_G) _s=begin_cmd; break;
                         }
                         
                        // _x=_x*koefx;
                        // _y=_y*koefy;
                         //_z=_z*koef;
                         double max_l=abs(_x); //ya
                         if(abs(_y)>max_l)
                             max_l=abs(_y);
                         if(abs(_z)>max_l)
                             max_l=abs(_z);
                         double unit_scale=90; // steps in 1.0
                         double unit_len=max_l*unit_scale,unit_step;
                         double px=0,py=0,pz=0,x=0,y=0,z=0,kx,ky,kz;
                         int all_x_steps=0,all_y_steps=0,all_z_steps=0;
                         kx=_x/unit_len;
                         ky=_y/unit_len;
                         kz=_z/unit_len;
                    //     Serial.print("unit_len - "); Serial.print(unit_len); Serial.print(" _x- "); Serial.print(_x); Serial.print(" max_l- "); Serial.println(max_l);
                    //     Serial.print("kx=");Serial.print(kx);Serial.print(" ky=");Serial.print(ky);Serial.print(" kz=");Serial.println(kz); 
                         if((kx==0)&&(ky==0)&&(kz==0)){if(  n_run_cmd>=amount_G) _s=begin_cmd; break;}
                         for(unit_step=0;unit_step<unit_len;unit_step  ){

                          if((abs(x-px)*unit_scale)>=1){
                            impstep(_X,STEP_MOTOR*kx/abs(kx),1);  //stepper0.step(STEP_MOTOR*kx/abs(kx));
                            //Serial.print("x_step ");Serial.println(kx/abs(kx));
                            all_x_steps  ;
                            px=x;
                          }
                          if((abs(y-py)*unit_scale)>=1){
                            impstep(_Y,STEP_MOTOR*ky/abs(ky),1); //stepper1.step(STEP_MOTOR*ky/abs(ky));
                            //Serial.print("y_step ");Serial.println(ky/abs(ky));
                            all_y_steps  ;
                            py=y;
                          }
                          if((abs(z-pz)*unit_scale)>=1){
                            UNIimpstep(12,13,2,7,3,10*kz/abs(kz)); //stepper2.step(STEP_MOTOR*kz/abs(kz)); 
                            //Serial.print("z_step ");Serial.println(kz/abs(kz));
                            all_z_steps  ;
                            pz=z;
                          }
                          x =kx; y =ky; z =kz;
                       //   Serial.print(unit_step);Serial.print("  :  ");
                        //  Serial.print(x);Serial.print("  |  ");Serial.print(y);Serial.print("  |  ");Serial.println(z);                          
                         }
                          Serial.println("-----------------------------------------");
                          Serial.print("all_steps(");Serial.print(all_x_steps);Serial.print(",");Serial.print(all_y_steps);Serial.print(",");Serial.print(all_z_steps);Serial.print(")");
                          cur_abs_x =_x; cur_abs_y =_y; cur_abs_z =_z;                         
                          Serial.print("cur_abs(");Serial.print(cur_abs_x);Serial.print(",");Serial.print(cur_abs_y);Serial.print(",");Serial.print(cur_abs_z);Serial.println(")");
                          Serial.println("-----------------------------------------");   
                         
                         if(  n_run_cmd>=amount_G) _s=begin_cmd;
                            
 }//switch(_s)
}

char end_button(int coord)
{
  int but=0;
  
  if(coord==_X)
      but=digitalRead(inPinX);
  if(coord==_Y)
      but=digitalRead(inPinY);
  
  if(but){
   if(coord==_X)
       Serial.println("[ X out of range ]"); 
   if(coord==_Y)
       Serial.println("[ Y out of range ]"); 
  }
  return but;
}
   
char impstep(int coord,int kol,int f_test_coord)
{
  int IN_en,IN_dir,IN_step,pause;
  pause=2; //35
  switch(coord){
   case _X:  IN_en=x_en; IN_dir=x_dir; IN_step=x_step;
     digitalWrite(IN_en, 0);
     break;
   case _Y:  IN_en=y_en; IN_dir=y_dir; IN_step=y_step;
     digitalWrite(IN_en, 0);
     break;
    }
  if(!f_test_coord)
     Serial.println("[ break step ]");
  //delay(100);
  if (kol<0)
    for (int i=0; i<=abs(kol); i  ){
    if(f_test_coord&&end_button(coord)){
      impstep(coord,200,0);
      return 0;
    }
    digitalWrite(IN_dir, LOW);
    digitalWrite(IN_step, HIGH);
    delay(pause);
    digitalWrite(IN_step, LOW);
    delay(pause);
  }else
    for (int i=0; i <= kol; i  ){
      if(f_test_coord&&end_button(coord)){
        impstep(coord,200,0);
        return 0;
      }
    digitalWrite(IN_dir, HIGH);
    digitalWrite(IN_step, HIGH);
    delay(pause);
    digitalWrite(IN_step, LOW);
    delay(pause);
    }
    digitalWrite(IN_en, 1);
    return 1;
  }

void UNIimpstep(int IN1,int IN2,int IN3,int IN4,int pause,int kol)
{
      //delay(100);
  if (kol<0)
    for (int i=0; i<=abs(kol); i  ){
         digitalWrite(IN1, 0);
    digitalWrite(IN2, 1);
    digitalWrite(IN3, 0);
    digitalWrite(IN4, 0);
    delay(pause);
    digitalWrite(IN1, 1);
    digitalWrite(IN2, 0);
    digitalWrite(IN3, 0);
    digitalWrite(IN4, 0);
    delay(pause);
    digitalWrite(IN1, 0);
    digitalWrite(IN2, 0);
    digitalWrite(IN3, 0);
    digitalWrite(IN4, 1);
    delay(pause);
    digitalWrite(IN1, 0);
    digitalWrite(IN2, 0);
    digitalWrite(IN3, 1);
    digitalWrite(IN4, 0);
     delay(pause);
   }
   else
    for (int i=0; i <= kol; i  ){
    digitalWrite(IN1, 1);
    digitalWrite(IN2, 0);
    digitalWrite(IN3, 0);
    digitalWrite(IN4, 0);
    delay(pause);
    digitalWrite(IN1, 0);
    digitalWrite(IN2, 1);
    digitalWrite(IN3, 0);
    digitalWrite(IN4, 0);
    delay(pause);
    digitalWrite(IN1, 0);
    digitalWrite(IN2, 0);
    digitalWrite(IN3, 1);
    digitalWrite(IN4, 0);
    delay(pause);
    digitalWrite(IN1, 0);
    digitalWrite(IN2, 0);
    digitalWrite(IN3, 0);
    digitalWrite(IN4, 1);
    delay(pause);
 }
}

Про другие станки:  Токарный станок с ЧПУ 16А20Ф3 после капремонта купить по выгодной цене. Продажа станков 16А20Ф3 после капремонта с доставкой в Москве, по всей России и СНГ | Станочный Мир

Завершается конечный автомат конструкцией case run_cmd: где собственно и подается управляющий сигнал на двигатель. Управлением двигателем можно было бы использовать библиотеку #include <Stepper.h> но мы написали свою функцию(char impstep -для биполярного двигателя, void UNIimpstep — униполярного ), что бы можно было не ждать пока один двигатель отработает, что бы послать сигнал другому. Ну и на будущее, отдельная процедура позволит гибче использовать возможностями шагового двигателя. Например, если будем использовать другой драйвер двигателя программно задавать полушаг или шаг двигателя. В нынешнем исполнении с RAMPS получается 1/16 шага. Если кому интересно, про управление шаговыми двигателями можно отдельную статью часами писать.

Теперь немного о железе.

Как выбрать комплектующие для станка с ЧПУ

Двигатели использовали 17HS8401, самые мощные из NEMA17, которые смогли на ebay найти. Там же купили подшипники и оптические концевики.

Как выбрать комплектующие для станка с ЧПУ
Все остальное отечественное, родное. Оригинальная идея с направляющими, сделали их из длинных хромированных ручек для мебели, они как раз диаметром 12 мм под подшипники, длиной они продаются до метра, и прочности вполне хватает. В торцах ручек просверлили отверстия и метчиком нарезали резьбу. Это позволило просто болтом надежно соединить направляющие с несущим конструктивом. Для оси Z так вообще ручку прикрепили к пластине конструктива целиком, Вал продается в любом строительном магазине как шпилька с резьбой любого диаметра. Мы использовали на 8 мм. Соответственно и гайки 8 мм. Гайку с подшипником и несущим конструктивом оси Y соединили с помощью соединительной скобы. Скобы купили в специализированном магазине для витрин. Видели наверно такие хромированные конструкции в магазинах стоят на которых галстуки или рубашки висят, вот там используются такие скобы для соединения хромированных трубок. Двигатель соединили с валом муфтой, которую сделали из куска стального прута диаметром 14мм, просверлив по центру отверстие и пару отверстий сбоку, для зажимания винтами. Можно не заморачиваться и купить готовые на ebay по запросу cnc coupling их куча выпадает. Несущий конструктив нам вырубили на гильотине за 1000 р. Сборка всего этого заняло не много времени и получили на выходе вот такой станок, на фото еще не установлены концевики, контроллер и не установлен двигатель фрезы.

Как выбрать комплектующие для станка с ЧПУ

Точность получилась просто изумительная, во-первых шаговый двигатель шагает 1/16 шага, во-вторых вал с мелкой резьбой. Когда в станок вставили ручку вместо фрезы, он нарисовал сложную фигуру, потом еще несколько раз обвел эту фигуру, а на рисунке видно как будто он один раз рисовал, под лупой рассматривали пытались другую линию найти. Жесткость станка тоже хорошая. Шатается только в пошипниках в допустимых пределах их собственого допуска и посадки. Немного шатается еще по оси Y, ну здесь я думаю конструктив оси Z надо доработать.

Фото получилось не качественное, на заднем плане стекло отражает. Не знаю какой я конструктор станка, но фотограф я просто никакой. Вот чуть получше.

Как выбрать комплектующие для станка с ЧПУ

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

Программа написана на Microsoft Visual C , использовалась библиотеки:

Module: SERIALPORT.H
Purpose: Declaration for an MFC wrapper class for serial ports
Copyright 1999 by PJ Naughter. All rights reserved.
Программа еще сырая, ну в двух словах используем

port.Open(8, 9600, CSerialPort::NoParity, 8, CSerialPort::OneStopBit, CSerialPort::XonXoffFlowControl);
для открытия порта
port.Write(text, l); - запись в порт
port.Read(sRxBuf, LEN_BUF); - чтение порта.

Использовался еще стандартный компонент msflexgrid таблица, в которую в реальном времени заносится выполняемый в настоящий момент G-код. Т.е. эта программа просто открывает готовый G-код и маленькими порциями запихивает его в контроллер.

Исходный код управляющей программы можно посмотреть здесь github.com/konstantin1970/cnc.git
Для понимания добавлю еще, что стандартный windows hyperterminal или putty делает то-же самое, запихивает данные в контроллер.
Сам G-код можно сделать в любой CAD/CAM системе например, мне понравился ARTCAM.

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

Надеюсь, сможем и в дальнейшем делиться своими разработками с вами уважаемые хаброчитатели.

1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (1 оценок, среднее: 5,00 из 5)
Загрузка...

Добавить комментарий

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

Войти