Темы



Сверлильный станок из 3D-принтера и конвертер карты сверления PCAD в G-Code

Здравствуйте, уважаемые хаброжители.
Сегодня я хочу поделиться небольшой наработкой, призванной конвертировать PCAD-овские карты сверления в G-код. Гибко, просто и open-source. Правда, прости-осспади, на Qt. Писать на нем, конечно, приятно, но вот деплоить и собирать чужие коды…

Часть первая. Механика.

Некоторое время назад я отложил свой проект по голове для приуса, и вот для чего:
Пока ждал микросхемы, пока эксперементировал со схемами, отчетливо понял, что я хочу изготавливать печатные платы дома. Да-да, есть опыт лазерно-утюжной технологии, и даже рисования лаком, но хотелось чего-то настоящего. Решено было использовать пленочный фоторезист и УФ-лампу для ногтей. Естественно, встала проблема сверления и металлизации отверстий. А получается она оттуда, что отверстия нужно металлизировать до того, как на плате протравятся дорожки. Иначе подать ток к каждому отверстию — целая история.
Получается, что ручное сверление отпадает, т.к. ориентироваться просто не по чем (бумажки с картами отверстий давайте не будем предлагать).
Решено было навесить на имеющийся 3D-принтер вместо Direct-головы — шпиндель, и так и жить. И вот тут появились решения, которыми я хотел бы сегодня поделиться.

Сменная головка для RepRap


Для того, чтобы можно было легко превращать принтер в сверлилку и обратно, решено было сделать головку разъемной. Бегунок, прикрученный к ремням — отдельно, а все остальное — съемное. Учитывая, что это не бог весть, какая сложность, отдельной статьей выкладывать смысла нет. Тут просто фото и ссылки на STL-модели, если кто захочет себе точно такую же. В архиве так же присутствуют SLDPRT-исходники, если что подправить. Качается медленно — спасибо ADSL от белтелекома, но лежать должно долго.

Результат получился вот таким:
7dbkeu1syr7kxkvvav4-kfbeyeg.jpeg

vycls3k6iheb70da3vjp-mkr6_4.jpeg

4s78vzislpsksrnupf9dlfi2yzu.jpeg

vrbtxrab-vqidu01ez17ipdzedq.jpeg

Головка-шпиндель


Тут все просто — после длительных попыток создать свой шпиндель, решил прикупить оный на AliExpress, и просто повесить на кронштейне. Фото нет, пока в процессе.

Генератор G-Code


А вот тут начинается самое интересное.
С присущим мне глобализмом я пробежался по имеющимся решениям, и понял, что каждое из них способно не только создать кучу проблем при разворачивании технологии дома, но и доставлять их регулярно и методично, вплоть до пенсии. Что не нравилось? Негибкость. Все они больше под станки, с предопределенными характеристиками шаблонов, и т.п. Да, дело не сложное. Но очень не хотелось однажды столкнуться с ситуацией, когда нужно чуть видоизменить алгоритм, и не иметь возможности это сделать. К примеру, не встречал тулзу, способную повернуть отверстия вокруг оси. А ведь после металлизации плату 1:1 не уложишь. Но это мысли на будущее. Пока мне это не нужно. Но уже можно. В целом, хотелось чего-то простого, легкого, гибкого и… работоспособного. Решил накропать самостоятельно.
В качестве базы были использованы библиотеки Qt 5.11. Приложение написано в консольном стиле. Архитектура приложения выполнена в linux-стиле.
На вход приложению подается файл DRL, выдернутый из PCAD при создании Geber-комплекта. (возможно, придется доработать парсер, если захочется скормить ему что-нибудь из AltiumDesigner. Но лично я для себя решил снести этого Альтиум-монстра от греха подальше. За что теперь он является в страшных снах, и не дает забыть собственное имя)
В качестве параметра указывается файл XML. Описанию формата этого файла будет посвящана вторая половина статьи. Этот файл, по сути, определяет механизм формирования G-Code (а на самом деле — любого текстового файла) для передачи его (G-кода) 3D-принтеру.

Механизм работы приложения


1. Читается и распознается формат DRL (который М48 или Excellon). В результате получаются инструменты, содержащие список дырок, которые этими инструментами сверлятся.
2. С полученными из п.1 данными мы идем в XML, ищем там ноду script, и попросту исполняем все, что там написано. Есть пяток операторов, а большего нам и не нужно.
3. В процессе исполнения п.2 случались операторы print. Результат печатается на выходной поток.

Часть вторая. Формат XML-файла


Для того, чтобы сделать программу максимально гибкой, была использована библиотека ScriptEngine. Сам чуточку ошалел от того, что теперь реально можно сделать при конфигурации. Основной постулат таков: есть много вычисляемых параметров, работа с которыми ведется максимально прозрачно: текст передается модулю ScriptEngine, и используется результат. Та же ситуация происходит, если в шаблоне G-Code встретится комбинация ${бла-бла-бла}. При этом все, что внутри фигурных скобок, будет передано на вычисление, а весь шаблон заменен результатом.

Исходные коды

Пример файла для моего принтера

        
                
                
                
        
        
                
                
        
        
                
                
                
                
                
                
                
                
                
                
                
        
        
        
        
                G90 ;${var hcnt=holesCount;var tcnt=toolsCount;"Hello"}
                M117 Homing
                G28 X Y
                M117 Move Z to travel
                G0 X${minX} Y${minY}
                M76
                G92 Z${ZTravelValue}
        
        
                G0 Z${ZChangeToolValue}
                M104 S0 ; disable spindle
                G0 X0 Y220
                M117 Drill finished
                M300 S600 P1
                ; Stats:
                ; Holes : ${holesCount}
                ; Tools : ${toolsCount}
        
        
                ; Tools rest: ${tcnt--}
                G0 Z${ZChangeToolValue}
                G0 X100 Y0
                M104 S0 ; disable spindle
                M117 Change tool to ${description}
                M300 S600 P1
                M76 ; pause job
                M117 Drilling
                M104 S100 ; enable spindle
                G28 X
        
        
                ; Holes rest: ${hcnt--}
                ; Percent rest: ${var percent=Math.round(hcnt*100/holesCount); percent}%
                M73 P${100-percent}
                G0 Z${ZTravelValue}
                G0 X${Math.round(x*100)/100} Y${Math.round(y*100)/100}
                G0 Z${ZDrillValue}
                G0 Z${ZTravelValue}
        
        
        <script>
        
        
        
        
        
        
        
        
        
                
                
                
                
                        
                        
                        
                
        
        
</script>



На самом деле, ничего сложного нет, если вчитаться. Но давайте разберем посекционно:

 
                
        


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

 
                
        

Функции. Ну, точнее, функция. Пока она, предопределенная, одна: вычисление реального диаметра сверла для металлизированных отверстий. Известно, что металлизация крадет диаметр, и это частенько приводит к казусам при попытке просунуть ногу компонента 0,8, которая не лезет в отверстие, заложенное, как 0,9. Чтобы не возиться с этим при проектировании я решил добавить этот функционал.
Смысл этой секции — определить функции, которые может использовать конвертер для определенных целей. Эти функции нельзя (пока?) использовать самостоятельно.

 
                
        

Сверла. Тут нужно сделать отсылку к команде скрипта «align tools», про которую ниже. Каждый элемент этой секции определяет ячейку, в которую будут собраны все инструменты, распознанные во входном файле. Идея такова, что частенько при проектировании случаются дюймовые диаметры, и множество инструментов с их значениями 0,478…0,492… и т.д. Чтобы не возиться с ними, мы задаем обязательные параметры range_min и range_max. Обязателен так же признак металлизации. Ноды XML просматриваются последовательно, и как только очередной инструмент из DRL подходит под определение — нода признается подходящей.
Можно задавать любые другие параметры в ноде. Их значение можно будет позже использовать в шаблонах.
Вы можете задать позицию в пенале или координаты, где захватить сверло, если у вас станок с автосменой инструмента. А можете описать инструмент буквами для вывода на экран принтера, если у вас, как у меня, Marlin и ручная смена сверл.

 
        
                G90 ;${var hcnt=holesCount;var tcnt=toolsCount;"Hello"}
                M117 Homing
                G28 X Y
                M117 Move Z to travel
                G0 X${minX} Y${minY}
                M76
                G92 Z${ZTravelValue}
        

А вот теперь оцените всю прелесть скрипт-машины! Шаблоны. Конвертер, как я уже говорил, работает с шаблонами просто: ищет все кусочки вида ${…}, и отправляет в скрипт-машину. А там-то JS-подобный язык. Поэтому, собственно, можно даже чуточку программировать. В данном примере можно видеть, как при выводе шаблона start мы сначала определили пару переменных, которым присвоили значения глобальных. Ну, а лишь потом написали константу, которая и будет значением выполнения этого куска.

Когда этот шаблон будет выведен в выходной файл, мы увидим:

G90 ;Hello
M117 Homing
G28 X Y
M117 Move Z to travel
G0 X10 Y10
M76
G92 Z10

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

         ; Holes rest: ${hcnt--}
                ; Percent rest: ${var percent=Math.round(hcnt*100/holesCount); percent}%
                M73 P${100-percent}


да-да… каждый раз, печатая комментарий Holes rest, мы будем декрементировать значение hcnt. А она, как мы помним, была определена, пока мы печатали start, а, стало быть, находится контекстом выше. А потом будем вычислять переменную percent, чтобы после использовать ее в другом куске — при передаче ее в команду M73 (эта команда заставляет марлин подвинуть полоску прогресса). G-Код, сгенерированный этим фрагментом:

; Holes rest: 6
; Percent rest: 13%
M73 P87

кстати, toolsCount, minX — это предопределенные имена глобальных переменных.
Отмечу, что имена шаблонов не предопределены, т.е. вы можете использовать любые. Шаблон будет распечатан, когда в скрипте встретится команда print и его имя.

<script>
        

И основа — секция script


Внутри секции могут встречаться ноды с именами command и loop.

Формат ноды command:

 


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

Формат ноды loop:


.....



цикл — это секция, содержимое которой будет исполнено для каждого элемента, определенного типом цикла. Их два (пока):
tools — цикл выполнится для каджого инструмента, и
toolholes — цикл выполнится для каждой дырки, предназначенной для сверления этим инструментом. Очевидно, что цикл toolholes может быть только вложенным в tools.
При этом при выполнении вложенного цикла доступны все переменные для текущего инструмента. Зачем? Не знаю. Просто рассказал.

Операторы


assign tools
Параметры: нет.
Проводит присвоение каждому сверлу из исходного файла инструмента из XML. Без него большинство других действий не имеют смысла.

join tools
Параметры: нет.
Больше организационный — объединяет все инструменты, которым был присвоен один и тот же из XML-файла. Имеет смысл сразу после assign tools, но я решил дать возможность пользователю сделать свои операции.

offset
Параметры:
xoffs, yoffs — значения смещений. Работает скрипт-машина.
Смещает все отверстия на указанные значения. Да, часто так бывает, что плата разводится далеко не в начале координат.

print
Параметр:
pattern Название шаблона.
Печатает шаблон с указанным названием на выходной поток.

print context
Параметры:
line_begin, line_end — начало и конец каждой строки.
Отладочная штука — позволяет в любом месте вывести на выход все доступные в данный момент переменные и их значения. Каждая переменная выводится отдельной строкой, начало и конец указаны в параметрах

Предопределенные имена глобальных переменных.

holesCount, toolsCount — я очень, очень, очень надеюсь, что смысл этих переменных в пояснении не нуждается. Да-да. Это количество инструментов и количество отверстий.
minX, maxX, minY, maxY — и этих тоже. Нет, ну на всякий случай — это координаты поля сверления. Все дырочки находятся внутри этого прямоугольника. Пересчитывается после команды offset.

Заключение


Вот, собственно, постарался вкратце, но максимально полно описать сотворенную тулзу.

Честно говоря, пока пытался представить сценарии использования, я отчетливо представлял себе, сколько раз проявится татаро-монгольское иго на землях русских (есть мнение, что именно они принесли нам мат).
Отсюда вопрос: стоит ли заморочится, и сделать простенькую веб-страничку, куда можно вставить вход и скрипт, и получить готовый G-Code, минуя стадии сборки из исходников?

© Habrahabr.ru