Pull to refresh

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

Periphery 3D printers
Здравствуйте, уважаемые хаброжители.

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

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


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

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

Решено было навесить на имеющийся 3D-принтер вместо Direct-головы — шпиндель, и так и жить. И вот тут появились решения, которыми я хотел бы сегодня поделиться.

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


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

Результат получился вот таким:









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


Тут все просто — после длительных попыток создать свой шпиндель, решил прикупить оный на 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 встретится комбинация ${бла-бла-бла}. При этом все, что внутри фигурных скобок, будет передано на вычисление, а весь шаблон заменен результатом.

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

Пример файла для моего принтера
<xml>
	<variables>
		<var name="ZChangeToolValue" value="30"/>
		<var name="ZTravelValue" value="10"/>
		<var name="ZDrillValue" value="0"/>
	</variables>
	<functions>
		<!--
			predefined function with single parameter:
			a - source (requested) diameter
			returns - suggested tool diameter for give requested after halvanic
			if function nod defined, it assumed return=a
		-->
		<plate_increase_dia f="a+0.2"/>
	</functions>
	<tools>
		<!--
			"tool" node defines a real drill tool for make a hole
			Depends on your technical process you can set up different
			tools for plated or not holes or join same holes in single tool.
			Required parameters for tool are:
			1. range_min,range_max - diameters range to assign holes for this tool
			You can joun different diameters (f.ex. 0.31-0.4) to single tool
			2. plated="yes|no|both" - defines plated property to
			Other parameters are optional and can be used later in G-Code patterns.
			For example, you can define tool position or toolbox coords for the tool.
		-->
		<tool description="0,3mm" range_min="0" range_max="0.3" plated="both" position="0" />
		<tool description="0,4mm" range_min="0.3" range_max="0.4" plated="both" position="1" />
		<tool description="0,5mm" range_min="0.4" range_max="0.5" plated="both" position="2" />
		<tool description="0,6mm" range_min="0.5" range_max="0.6" plated="both" position="3" />
		<tool description="0,7mm" range_min="0.6" range_max="0.7" plated="both" position="4" />
		<tool description="0,8mm" range_min="0.7" range_max="0.8" plated="both" position="5" />
		<tool description="0,9mm" range_min="0.8" range_max="0.9" plated="both" position="6" />
		<tool description="1,0mm" range_min="0.9" range_max="1.0" plated="both" position="7" />
		<tool description="1,1mm" range_min="1.0" range_max="1.1" plated="both" position="8" />
		<tool description="1,2mm" range_min="1.1" range_max="5" plated="both" position="9" />
	</tools>
	<patterns>
	<!-- in any pattern you can use any variable from context where it's printing
		Example (used inside 'tool' loop type):
			Mnnn Please, change tool to ${description} ; message to lcd
			Mnnn ; pause
		Note : here ${description} is optional tag defined in <tool> node
		Use this example outsite the tool loop will cause calculation error.
	-->
	<pattern name="start">
		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}
	</pattern>
	<pattern name="finish">
		G0 Z${ZChangeToolValue}
		M104 S0 ; disable spindle
		G0 X0 Y220
		M117 Drill finished
		M300 S600 P1
		; Stats:
		; Holes : ${holesCount}
		; Tools : ${toolsCount}
	</pattern>
	<pattern name="set_tool">
		; 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
	</pattern>
	<pattern name="go_drill">
		; 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}
	</pattern>
	</patterns>
	<script>
	<!--
		"assign tools". No parameters
		Just assign all tools declared in
		DRL-file to tools described in <tools> node.
		For each DRL-defined tool will be selected FIRST compatible
		tool from <tools> node. I.e. if range 0.3..0.8 will be defined early,
		<tool> node for diameter 0.4..0.5 will never be assigned.
		Except 'plated' property will be different.
	-->
	<command verb="assign tools" />
	<!--
		"assign tools". No parameters
		Join all DRL-file tools, assigned to same tool here
		to one tool (also holes)
		Just avoid multiply changing physical tool to same
	-->
	<command verb="join tools" />
	<!--
		"offset".
		Offset ALL holes by defined values
		xoffs, yoffs - values to offset. Before offset will be calculated
		i.e. here you can use global variables.
	-->
	<command verb="offset" xoffs="-minX+10" yoffs="-minY+10"/>
	<!--
		loop for each DRL-tool (assigned and joined before).
		Context inside will be filled also with tool's properties and
		node's parameters
	-->
	<command verb="print" pattern="start"/>
	<loop type="tools">
		<command verb="print" pattern="set_tool"/>
		<command verb="print context" line_begin=";"/>
		<!--
			loop for each hole inside the tool.
			Context inside will be filled also with hole's properties(x&y) and
			node's parameters
		-->
		<loop type="toolholes">
			<command verb="print" pattern="go_drill"/>
			<!--
				"print context".
				Anwhere in script you can use this verb.
				It inserts all context variables available.
				Usefull for debug but completely useless for
				normal work
			-->
			<command verb="жprint context" line_begin=";"/>
		</loop>
	</loop>
	<command verb="print" pattern="finish"/>
</script>
</xml>



И версия этого же файла после практических испытаний
<xml>
	<variables>
                <var name="ZChangeToolValue" value="10"/>
                <var name="ZTravelValue" value="2"/>
                <var name="ZDrillValue" value="-3"/>
                <var name="FeedHorizontal" value="24000"/>
                <var name="FeedDown" value="100"/>
                <var name="FeedFree" value="2000"/>
                <var name="StartOffsX" value="20"/>
                <var name="StartOffsY" value="20"/>
                <var name="ZZeroPosition" value="0.1"/>
                <var name="first" value="0"/>
        </variables>
	<functions>
		<!--
			predefined function with single parameter:
			a - source (requested) diameter
			returns - suggested tool diameter for give requested after halvanic
			if function nod defined, it assumed return=a
		-->
                <plate_increase_dia f="a+0.3"/>
	</functions>
	<tools>
		<!--
			"tool" node defines a real drill tool for make a hole
			Depends on your technical process you can set up different
			tools for plated or not holes or join same holes in single tool.
			Required parameters for tool are:
			1. range_min,range_max - diameters range to assign holes for this tool
			You can joun different diameters (f.ex. 0.31-0.4) to single tool
			2. plated="yes|no|both" - defines plated property to
			Other parameters are optional and can be used later in G-Code patterns.
			For example, you can define tool position or toolbox coords for the tool.
		-->
		<tool description="0,3mm" range_min="0" range_max="0.3" plated="both" position="0" />
		<tool description="0,4mm" range_min="0.3" range_max="0.4" plated="both" position="1" />
		<tool description="0,5mm" range_min="0.4" range_max="0.5" plated="both" position="2" />
		<tool description="0,6mm" range_min="0.5" range_max="0.6" plated="both" position="3" />
		<tool description="0,7mm" range_min="0.6" range_max="0.7" plated="both" position="4" />
		<tool description="0,8mm" range_min="0.7" range_max="0.8" plated="both" position="5" />
		<tool description="0,9mm" range_min="0.8" range_max="0.9" plated="both" position="6" />
		<tool description="1,0mm" range_min="0.9" range_max="1.0" plated="both" position="7" />
		<tool description="1,1mm" range_min="1.0" range_max="1.1" plated="both" position="8" />
		<tool description="1,2mm" range_min="1.1" range_max="5" plated="both" position="9" />
	</tools>
	<patterns>
	<!-- in any pattern you can use any variable from context where it's printing
		Example (used inside 'tool' loop type):
			Mnnn Please, change tool to ${description} ; message to lcd
			Mnnn ; pause
		Note : here ${description} is optional tag defined in <tool> node
		Use this example outsite the tool loop will cause calculation error.
	-->
        <pattern name="start1">
        ; Start
        </pattern>
        <pattern name="set_tool1">
        ; Set tool ${description}
        </pattern>
        <pattern name="finish1">
        ; Finish
        </pattern>
        <pattern name="go_drill1">
        ; Drill X${Math.round(x*100)/100} Y${Math.round(y*100)/100}
        </pattern>
        <pattern name="start">
                ;${var hcnt=holesCount;var tcnt=toolsCount;"Hello"}
		M117 Homing
                G28
                G0 Z0 F${FeedFree}
                G92 Z1.6
        </pattern>
	<pattern name="finish">
                G0 Z${ZChangeToolValue} F${FeedFree}
                M400
                M5 ; disable spindle
                G0 X0 Y220 F${FeedHorizontal}
		M117 Drill finished
                M300 S600 P100
		; Stats:
		; Holes : ${holesCount}
		; Tools : ${toolsCount}
	</pattern>
	<pattern name="set_tool">
		; Tools rest: ${tcnt--}
                G0 Z${ZChangeToolValue} F${FeedFree}
                M400
                G0 X100 Y0 F${FeedHorizontal}
                M117 Stopping spindle
                M5 ; disable spindle
		M117 Change tool to ${description}
                M300 S600 P100
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M25
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                G28 X Y
                G0 X${StartOffsX-1} Y${StartOffsX-1} Z${ZTravelValue} F${FeedHorizontal}
                G0 Z${ZZeroPosition} F${FeedFree}
                M117 Check zero-hole
                M300 S600 P100
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M25
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                M400 ; This strange line is just crutch to prevent Marlin from read-n-exec other commands begore do pause
                G92 Z${ZZeroPosition} F${FeedDown}
                M117 Starting spindle
                M3 ; enable spindle
                G0 Z${ZDrillValue} F${FeedDown/3}
                G0 Z${ZTravelValue} F${FeedFree}
                M117 Drilling
                M117 Starting spindle
                M3 ; enable spindle
	</pattern>
	<pattern name="go_drill">
		; Holes rest: ${hcnt--}
		; Percent rest: ${var percent=Math.round(hcnt*100/holesCount); percent}%
		M73 P${100-percent}
                M117 Drilling X${Math.round(x*100)/100} Y${Math.round(y*100)/100} Z${ZTravelValue}
                G0 Z${ZTravelValue} F${FeedFree}
                G0 X${(Math.round(x*100)/100)-2} Y${(Math.round(y*100)/100)-2}  F${FeedHorizontal}
                G0 X${Math.round(x*100)/100} Y${Math.round(y*100)/100}  F${FeedHorizontal}
                M400
                G0 Z${Math.round((ZZeroPosition+0.2)*100)/100} F${FeedFree}
                G0 Z${Math.round((ZZeroPosition-0.3)*100)/100} F${FeedDown/10}
                G0 Z${ZDrillValue} F${FeedDown}
                M117 Return
                G0 Z${ZTravelValue} F${FeedFree}
        </pattern>
        <pattern name="second_time">
            ; ${var hcnt=holesCount;var tcnt=toolsCount;"SECOND!!!"}
        </pattern>
        </patterns>
	<script>
	<!--
		"assign tools". No parameters
		Just assign all tools declared in
		DRL-file to tools described in <tools> node.
		For each DRL-defined tool will be selected FIRST compatible
		tool from <tools> node. I.e. if range 0.3..0.8 will be defined early,
		<tool> node for diameter 0.4..0.5 will never be assigned.
		Except 'plated' property will be different.
	-->
	<command verb="assign tools" />
	<!--
		"assign tools". No parameters
		Join all DRL-file tools, assigned to same tool here
		to one tool (also holes)
		Just avoid multiply changing physical tool to same
	-->
	<command verb="join tools" />
	<!--
		"offset".
		Offset ALL holes by defined values
		xoffs, yoffs - values to offset. Before offset will be calculated
		i.e. here you can use global variables.
	-->
        <command verb="offset" xoffs="-minX+StartOffsX" yoffs="-minY+StartOffsY"/>
	<!--
		loop for each DRL-tool (assigned and joined before).
		Context inside will be filled also with tool's properties and
		node's parameters
	-->
        <command verb="sort tools"/>
        <command verb="print" pattern="start"/>
        <loop type="tools">
                <condition content="first++==0">
                    <command verb="print" pattern="set_tool"/>
                </condition>
		<command verb=";print context" line_begin=";"/>
		<!--
			loop for each hole inside the tool.
			Context inside will be filled also with hole's properties(x&y) and
			node's parameters
		-->
		<loop type="toolholes">
                        <command verb="print" pattern="go_drill"/>
			<!--
				"print context".
				Anwhere in script you can use this verb.
				It inserts all context variables available.
				Usefull for debug but completely useless for
				normal work
			-->
			<command verb=";print context" line_begin=";"/>
		</loop>
	</loop>
        <condition content="first=0">
            <command verb=";dummy"/>
        </condition>
        <command verb="print" pattern="second_time"/>
        <loop type="tools">
            <condition content="first++>0">
                <command verb="print" pattern="set_tool"/>
                <command verb=";print context" line_begin=";"/>
                <!--
                        loop for each hole inside the tool.
                        Context inside will be filled also with hole's properties(x&y) and
                        node's parameters
                -->
                <loop type="toolholes">
                        <command verb="print" pattern="go_drill"/>
                        <!--
                                "print context".
                                Anwhere in script you can use this verb.
                                It inserts all context variables available.
                                Usefull for debug but completely useless for
                                normal work
                        -->
                        <command verb=";print context" line_begin=";"/>
                </loop>
            </condition>
        </loop>
        <command verb="print" pattern="finish"/>
</script>
</xml>



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

	<variables>
		<var name="Название переменной" value="Значение переменной"/>
	</variables>

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

	<functions>
		<plate_increase_dia f="a+0.2"/>
	</functions>

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

Смысл этой секции — определить функции, которые может использовать конвертер для определенных целей. Эти функции нельзя (пока?) использовать самостоятельно.

	<tools>
		<tool description="0,3mm" range_min="0" range_max="0.3" plated="both" position="0" />
	</tools>

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

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

	<patterns>
	<pattern name="start">
		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}
	</pattern>

А вот теперь оцените всю прелесть скрипт-машины! Шаблоны. Конвертер, как я уже говорил, работает с шаблонами просто: ищет все кусочки вида ${...}, и отправляет в скрипт-машину. А там-то 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>
	<command verb="assign tools" />

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


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

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

	<command verb="оператор действия" .... параметры для оператора ... />

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

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

<loop type="тип цикла">
.....
</loop>

цикл — это секция, содержимое которой будет исполнено для каждого элемента, определенного типом цикла. Их два (пока):

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

Операторы


assign tools
Параметры: нет.

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

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

sort tools
Параметры: нет (пока).
Сортирует сверла по возрастанию диаметров

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

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

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

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


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

Заключение


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

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

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

UPD:
Спасибо проголосовавшим. Запилил. И… да: я же писал, что веб-страничка будет простенькой? Если кому-нибудь будет не лень привести это все в более эстетический вид — бросайте HTML в личку.
Only registered users can participate in poll. Log in, please.
Есть ли потребность запилить веб-версию этой утилиты
10.81% Да, буду пользоваться постоянно 4
43.24% Да, хотелось бы использовать время от времени 16
21.62% Нет, мне проще собрать, и работать локально 8
24.32% Нет, этот функционал совершенно не интересен 9
37 users voted. 17 users abstained.
Tags:
Hubs:
Total votes 14: ↑14 and ↓0 +14
Views 6.6K
Comments Comments 46