你好,亲爱的habrozhitel。
今天,我想分享一些旨在将PCAD的钻探卡转换为G代码的基础。 灵活,简单和开源。 是的,对不起,ospadi,在Qt上。 当然,在上面写东西是很好的,但是可以部署和收集其他人的代码...
第一部分 力学。
前段时间,我推迟了我的项目以争取奖品,为此:
当我在等待芯片时,在尝试电路时,我清楚地意识到,我想在家中制作印刷电路板。 是的,是的,在激光熨烫技术,甚至用清漆进行绘图方面都有经验,但是我想要一些真实的东西。 决定对指甲使用薄膜光致抗蚀剂和紫外线灯。 自然地,出现了钻孔和电镀孔的问题。 从那里可以看出,在板上蚀刻走线之前,需要对孔进行金属化处理。 否则,将电流施加到每个孔是一个完整的故事。
事实证明,手动钻孔消失了,因为 根本没有什么可浏览的(我们不提供带孔卡的纸张)。
决定将主轴悬挂在现有的3D打印机上而不是Direct-head上,并像这样生活。 这里有我今天想分享的解决方案。
RepRap的可互换头
为了轻松地将打印机变成钻头,反之亦然,决定使打印头可拆卸。 固定在皮带上的滑块是分开的,其他所有部件都是可移动的。 鉴于这不是一个好消息,这是多么困难,所以没有必要单独发表文章。 如果有人想要做完全一样的话,这里只是照片和
STL模型的链接。 归档文件还包含SLDPRT源(如果需要修复)。 摇曳缓慢-感谢Beltelecom的ADSL,但这应该需要很长时间。
结果是这样的:




主轴头
这里的一切都很简单-经过长时间尝试创建自己的主轴,我决定在AliExpress上购买主轴,然后将其挂在支架上。 在此过程中没有照片。
G代码生成器
从这里开始乐趣。
凭借我固有的全球化精神,我审阅了可用的解决方案,并意识到它们中的每一个不仅会在家庭中部署技术时造成一系列问题,而且还会有条不紊地有条不紊地交付解决方案,直至退休。 你不喜欢什么 僵硬。 所有这些都更适合机器,具有模板的预定义特性等。 是的,事情并不复杂。 但是我真的不想有一天遇到这样的情况:您需要稍微修改算法,而又不能这样做。 例如,我还没有看到可以绕轴旋转孔的工具。 但是在金属化之后,您将无法放置1:1:1的电路板。 但是这些都是对未来的想法。 我还不需要 但这已经是可能的。 总的来说,我想要一种简单,轻便,灵活和高效的东西。 我决定自己撒些东西。
Qt 5.11库用作基础。 该应用程序以控制台样式编写。 该应用程序的体系结构是Linux风格的。
创建Geber-kit时,该应用程序会收到从PCAD中提取的DRL文件。 (如果您想从AltiumDesigner中获取解析器,则可能需要修改解析器。但是对我自己而言,我个人决定将这个Altium怪物从罪恶中解救出来。现在他梦in以求,不能让我忘记自己的名字了。)
XML文件被指定为参数。 该文件的格式将在文章的后半部分中进行描述。 实际上,此文件确定了生成G代码(实际上是任何文本文件)并将其(G代码)传输到3D打印机的机制。
应用程序的机制
- 读取并识别DRL格式(为M48或Excellon )。 结果是工具包含使用这些工具钻出的孔的列表。
- 使用从项目1获得的数据,我们转到XML,在此处查找脚本节点,然后简单地执行在那里编写的所有内容。 有五个运算符,但我们不需要更多。
- 在执行步骤2的过程中,出现了打印语句。 结果打印在输出流上。
第二部分 XML文件格式
为了使程序尽可能灵活,使用了ScriptEngine库。 现在,该配置实际上可以完成的工作使自己有些不知所措。 主要假设是:有许多计算参数要尽可能透明地处理:将文本传递给ScriptEngine模块,然后使用结果。 如果在G代码模板中找到组合$ {blah blah blah},则会发生相同的情况。 此外,大括号内的所有内容都将传递给计算,整个模板将被结果替换。
我的打印机的样本文件<xml> <variables> <var name="ZChangeToolValue" value="30"/> <var name="ZTravelValue" value="10"/> <var name="ZDrillValue" value="0"/> </variables> <functions> <plate_increase_dia f="a+0.2"/> </functions> <tools> <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> <pattern name="start"> G90 ;${var hcnt=holesCount;var tcnt=toolsCount;"Hello"} M117 Homing G28 XY 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> <command verb="assign tools" /> <command verb="join tools" /> <command verb="offset" xoffs="-minX+10" yoffs="-minY+10"/> <command verb="print" pattern="start"/> <loop type="tools"> <command verb="print" pattern="set_tool"/> <command verb="print context" line_begin=";"/> <loop type="toolholes"> <command verb="print" pattern="go_drill"/> <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> <plate_increase_dia f="a+0.3"/> </functions> <tools> <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> <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 XY 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> <command verb="assign tools" /> <command verb="join tools" /> <command verb="offset" xoffs="-minX+StartOffsX" yoffs="-minY+StartOffsY"/> <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 type="toolholes"> <command verb="print" pattern="go_drill"/> <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 type="toolholes"> <command verb="print" pattern="go_drill"/> <command verb=";print context" line_begin=";"/> </loop> </condition> </loop> <command verb="print" pattern="finish"/> </script> </xml>
实际上,如果您阅读,没有什么复杂的。 但是让我们逐节分析:
<variables> <var name=" " value=" "/> </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>
演习。 在这里,您需要参考“对齐工具”脚本命令,有关此命令的信息如下。 本部分的每个元素都定义一个单元格,将在该单元格中收集输入文件中识别的所有工具。 这个想法是,在设计时经常会发生英寸直径,并且许多工具的值分别为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 XY M117 Move Z to travel G0 X${minX} Y${minY} M76 G92 Z${ZTravelValue} </pattern>
现在,欣赏脚本机器的所有魅力! 模板。 就像我已经说过的那样,该转换器只使用模板即可:它搜索$ {...}形式的所有片段,并将其发送到脚本机。 并且有一种类似于JS的语言。 因此,实际上,您甚至可以编写一些程序。 在此示例中,您可以看到在显示开始模式时如何首先定义一对分配了全局值的变量。 好吧,只有到那时,他们才写一个常量,这将是这段代码执行的价值。
当此模板输出到输出文件时,我们将看到:
G90 ;Hello M117 Homing G28 XY 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值。 我们记得,它是在键入开始时确定的,因此位于上面的上下文中。 然后,我们将计算百分比变量,以便在以后的另一段中使用它(将其传递给M73命令时(此命令将迫使marlin移动进度条))。 该片段生成的G代码:
; Holes rest: 6 ; Percent rest: 13% M73 P87
顺便说一句,toolsCount,minX是全局变量的预定义名称。
我注意到模板名称不是预定义的,即 您可以使用任何。 当脚本中遇到打印命令及其名称时,将打印该模板。
<script> <command verb="assign tools" />
基础是脚本部分
具有名称命令和循环的节点可以在部分中找到。
命令节点格式:
<command verb=" " .... ... />
动作声明是为数不多的运算符之一。 每个选项的说明如下。 正如您已经了解的,可以在模板中使用的任何其他对象都可以对它们进行补充。
循环节点格式:
<loop type=" "> ..... </loop>
循环是一个节,其内容将针对由循环类型确定的每个元素执行。 其中有两个(目前):
工具 -将为每个工具执行一个循环,并且
工具孔-将为使用此工具进行钻孔的每个孔执行一个循环。 显然,
工具 孔循环只能嵌套在
工具中 。
同时,执行嵌套循环时,当前工具的所有变量均可用。 怎么了 我不知道 刚刚被告知。
经营者
分配工具选项:无。
从XML的源工具文件分配每个钻取。 没有它,其他大多数动作将毫无意义。
连接工具选项:无。
更具组织性-结合了从XML文件分配了相同工具的所有工具。 使用分配工具后,这很有意义,但我决定让用户有机会进行操作。
排序工具参数:无(尚未)。
通过增加直径对钻头进行分类
抵销参数:
xoffs,yoffs-偏移值。 脚本机正在运行。
将所有孔移动到指定值。 是的,经常发生电路板在原点不远的情况。
打印参数:
pattern模式的名称。
在输出流上打印具有指定名称的模板。
打印上下文参数:
line_begin,line_end-每行的开始和结束。
调试事物-允许您在输出中的任何位置输出所有当前可用的变量及其值。 每个变量都显示在单独的行中,开始和结束在参数中指定
全局变量的预定义名称。
holeCount,toolsCount-我真的非常希望这些变量的含义不需要解释。 是的是的 这是工具的数量和孔的数量。
minX,maxX,minY,maxY-等等 。 不,很好,以防万一,这些是钻探区域的坐标。 所有孔都在此矩形内。 在offset命令后重新计算。
结论
实际上,在这里,我试图简要地但尽可能完整地描述所创建的塔尔扎。
老实说,当我试图想象使用场景时,我清楚地想象到塔塔尔-蒙古轭在俄罗斯土地上会出现多少次(据信它们为我们带来了打击垫)。
因此,问题是:值得混淆,并制作一个简单的网页,您可以在其中插入输入和脚本,并获得完整的G代码,而绕过源头的汇编阶段?UPD:
感谢那些投票的人。
我把它洗干净了 。 还有...是的:我写道网页会很简单? 如果某人不太懒惰,无法将其全部带入更美观的外观,请在PM中添加HTML。