Hallo, lieber Habrozhitel.
Heute möchte ich ein paar Grundlagen für die Umwandlung von PCAD-Bohrkarten in G-Code teilen. Flexibel, einfach und Open Source. Richtig, sorry, ospadi, auf Qt. Es ist natürlich schön, darauf zu schreiben, aber die Codes anderer Leute bereitzustellen und zu sammeln ...
Teil Eins Die Mechanik.
Vor einiger Zeit habe ich mein Projekt für einen Prius auf den Kopf gestellt, und dafür:
Während ich auf Chips wartete und mit Schaltkreisen experimentierte, wurde mir klar, dass ich zu Hause Leiterplatten herstellen möchte. Ja, ja, es gibt Erfahrung in der Laserbügeltechnologie und sogar im Zeichnen mit Lack, aber ich wollte etwas Reales. Es wurde beschlossen, einen Filmphotolack und eine UV-Lampe für Nägel zu verwenden. Natürlich trat das Problem beim Bohren und Plattieren von Löchern auf. Und von dort stellt sich heraus, dass die Löcher metallisiert werden müssen, bevor die Schienen auf die Platte geätzt werden. Ansonsten ist das Anlegen eines Stroms an jedes Loch eine ganze Geschichte.
Es stellt sich heraus, dass das manuelle Bohren verschwindet, weil Es gibt einfach nichts zu navigieren (bieten wir kein Papier mit Hole Cards an).
Es wurde beschlossen, eine Spindel anstelle eines Direktkopfs an einen vorhandenen 3D-Drucker zu hängen und so zu leben. Und hier gibt es Lösungen, die ich heute teilen möchte.
Austauschbarer Kopf für RepRap
Um den Drucker leicht in einen Bohrer zu verwandeln und umgekehrt, wurde beschlossen, den Kopf abnehmbar zu machen. Der an den Riemen befestigte Schieber ist separat und alles andere ist abnehmbar. Da dies keine gute Nachricht ist, was für eine Schwierigkeit, macht es keinen Sinn, einen separaten Artikel zu erstellen. Hier sind nur Fotos und Links zu
STL-Modellen , wenn jemand genau das Gleiche tun möchte. Das Archiv enthält auch SLDPRT-Quellen, falls etwas behoben werden muss. Es schwankt langsam - dank ADSL von Beltelecom, aber es sollte lange dauern.
Das Ergebnis ist wie folgt:




Spindelkopf
Hier ist alles einfach - nach langen Versuchen, meine eigene Spindel zu erstellen, entschied ich mich, eine bei AliExpress zu kaufen und sie einfach an die Halterung zu hängen. Kein Foto, währenddessen.
G-Code Generator
Und hier beginnt der Spaß.
Mit meinem inhärenten Globalismus ging ich die verfügbaren Lösungen durch und erkannte, dass jeder von ihnen nicht nur eine Reihe von Problemen beim Einsatz von Technologie zu Hause verursachen kann, sondern diese auch regelmäßig und methodisch bis zur Pensionierung liefert. Was hat dir nicht gefallen? Inflexibilität. Alle sind eher für Maschinen gedacht, mit vordefinierten Eigenschaften von Vorlagen usw. Ja, die Sache ist nicht kompliziert. Aber ich wollte wirklich nicht eines Tages auf eine Situation stoßen, in der Sie den Algorithmus leicht modifizieren müssen und dies nicht können. Zum Beispiel habe ich kein Werkzeug gesehen, das Löcher um eine Achse drehen kann. Nach der Metallisierung können Sie jedoch keine 1: 1-Platte verlegen. Aber das sind Gedanken für die Zukunft. Ich brauche es noch nicht. Aber es ist schon möglich. Im Allgemeinen wollte ich etwas Einfaches, Leichtes, Flexibles und ... Effizientes. Ich beschloss, alleine zu streuen.
Die Qt 5.11-Bibliotheken wurden als Basis verwendet. Die Anwendung ist im Konsolenstil geschrieben. Die Architektur der Anwendung ist im Linux-Stil erstellt.
Die Anwendung erhält beim Erstellen des Geber-Kits eine DRL-Datei, die aus dem PCAD gezogen wird. (Möglicherweise müssen Sie den Parser ändern, wenn Sie ihm etwas von AltiumDesigner geben möchten. Aber für mich persönlich habe ich beschlossen, dieses Altium-Monster von der Sünde zu befreien. Für das, was er jetzt in schrecklichen Träumen ist und mich meinen eigenen Namen nicht vergessen lässt).
Eine XML-Datei wird als Parameter angegeben. Das Format dieser Datei wird in der zweiten Hälfte des Artikels beschrieben. Diese Datei bestimmt tatsächlich den Mechanismus zum Generieren des G-Codes (und tatsächlich jeder Textdatei) zum Übertragen (G-Code) auf einen 3D-Drucker.
Der Mechanismus der Anwendung
- Das DRL-Format (M48 oder Excellon ) wird gelesen und erkannt. Das Ergebnis sind Werkzeuge, die eine Liste von Löchern enthalten, die mit diesen Werkzeugen gebohrt werden.
- Mit den aus Punkt 1 erhaltenen Daten gehen wir zu XML, suchen dort nach dem Skriptknoten und führen einfach alles aus, was dort geschrieben ist. Es gibt fünf Betreiber, aber wir brauchen nicht mehr.
- Während der Ausführung von Schritt 2 traten Druckanweisungen auf. Das Ergebnis wird im Ausgabestream gedruckt.
Teil Zwei XML-Dateiformat
Um das Programm so flexibel wie möglich zu gestalten, wurde die ScriptEngine-Bibliothek verwendet. Er selbst ist ein wenig überwältigt von dem, was jetzt wirklich mit der Konfiguration gemacht werden kann. Das Hauptpostulat lautet: Es gibt viele berechnete Parameter, die so transparent wie möglich behandelt werden: Der Text wird an das ScriptEngine-Modul übergeben und das Ergebnis wird verwendet. Die gleiche Situation tritt auf, wenn die Kombination $ {bla bla bla} in der G-Code-Vorlage gefunden wird. Darüber hinaus wird alles in den geschweiften Klammern an die Berechnung übergeben und die gesamte Vorlage durch das Ergebnis ersetzt.
Beispieldatei für meinen Drucker<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>
Und die Version derselben Datei nach praktischen Tests <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>
In der Tat gibt es nichts Kompliziertes, wenn Sie es lesen. Aber lassen Sie uns Abschnitt für Abschnitt analysieren:
<variables> <var name=" " value=" "/> </variables>
Wie der Name schon sagt, können wir im Abschnitt Variablen eine beliebige Menge globaler Variablen definieren. Sie beeinflussen den Betrieb des Programms in keiner Weise, bis sie sich in einem berechneten Ausdruck treffen.
<functions> <plate_increase_dia f="a+0.2"/> </functions>
Funktionen Genauer gesagt, eine Funktion. Bisher ist eines vorbestimmt: die Berechnung des tatsächlichen Durchmessers des Bohrers für metallisierte Löcher. Es ist bekannt, dass die Metallisierung den Durchmesser stiehlt, und dies führt häufig zu Zwischenfällen, wenn versucht wird, das Bein der 0,8-Komponente zu kleben, das nicht in das als 0,9 verlegte Loch geht. Um dies beim Entwerfen nicht zu stören, habe ich beschlossen, diese Funktionalität hinzuzufügen.
In diesem Abschnitt werden die Funktionen festgelegt, die der Konverter für bestimmte Zwecke verwenden kann. Diese Funktionen können (noch?) Nicht unabhängig voneinander verwendet werden.
<tools> <tool description="0,3mm" range_min="0" range_max="0.3" plated="both" position="0" /> </tools>
Bohrer. Hier müssen Sie auf den Skriptbefehl "Tools ausrichten" verweisen, über den unten gesprochen wird. Jedes Element dieses Abschnitts definiert eine Zelle, in der alle in der Eingabedatei erkannten Werkzeuge gesammelt werden. Die Idee ist, dass beim Entwerfen häufig Zolldurchmesser auftreten und viele Werkzeuge mit Werten von 0,478 ... 0,492 ... usw. Um nicht mit ihnen herumzuspielen, setzen wir die
erforderlichen Parameter range_min und range_max.
Ein Zeichen der Metallisierung ist ebenfalls erforderlich. XML-Knoten werden nacheinander gescannt, und sobald das nächste Tool aus der DRL zur Definition passt, wird der Knoten als geeignet erkannt.
Sie können beliebige andere Parameter im Knoten einstellen. Ihr Wert kann später in Vorlagen verwendet werden.
Sie können die Position im Federmäppchen oder die Koordinaten festlegen, an denen der Bohrer erfasst werden soll, wenn Sie eine Maschine mit einem Werkzeug zum automatischen Ändern haben. Und Sie können das Werkzeug mit Buchstaben für die Anzeige auf dem Druckerbildschirm beschreiben, wenn Sie wie ich Marlin und einen manuellen Bohrerwechsel haben.
<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>
Und jetzt schätzen Sie den Charme einer Skriptmaschine! Vorlagen. Der Konverter arbeitet, wie ich bereits sagte, einfach mit Vorlagen: Er sucht nach allen Teilen des Formulars $ {...} und sendet es an die Skriptmaschine. Und es gibt eine JS-ähnliche Sprache. Daher können Sie sogar ein wenig programmieren. In diesem Beispiel können Sie sehen, wie wir beim Anzeigen des Startmusters zunächst ein Variablenpaar definiert haben, dem globale Werte zugewiesen wurden. Nun, erst dann haben sie eine Konstante geschrieben, die der Wert der Ausführung dieses Stückes sein wird.
Wenn diese Vorlage in die Ausgabedatei ausgegeben wird, sehen wir:
G90 ;Hello M117 Homing G28 XY M117 Move Z to travel G0 X10 Y10 M76 G92 Z10
Nun, ich kann mich nicht rühmen. Bewerten Sie das Stück aus der Schablone zum Bohren jedes Lochs:
; Holes rest: ${hcnt--} ; Percent rest: ${var percent=Math.round(hcnt*100/holesCount); percent}% M73 P${100-percent}
Ja ... jedes Mal, wenn wir einen Kommentar zu Holes Rest eingeben, verringern wir den hcnt-Wert. Und es wurde, wie wir uns erinnern, während der Eingabe von start ermittelt und befindet sich daher im obigen Kontext. Und dann berechnen wir die prozentuale Variable, um sie anschließend in einem anderen Teil zu verwenden - wenn wir sie an den Befehl M73 übergeben (dieser Befehl zwingt Marlin, den Fortschrittsbalken zu verschieben). Von diesem Fragment erzeugter G-Code:
; Holes rest: 6 ; Percent rest: 13% M73 P87
Übrigens sind toolsCount, minX vordefinierte Namen globaler Variablen.
Ich stelle fest, dass die Vorlagennamen nicht vordefiniert sind, d. H. Sie können jede verwenden. Die Vorlage wird gedruckt, wenn der Druckbefehl und sein Name im Skript gefunden werden.
<script> <command verb="assign tools" />
Und die Basis ist der Skriptabschnitt
Knoten mit dem Befehl names und der Schleife befinden sich in einem Abschnitt.
Befehlsknotenformat:
<command verb=" " .... ... />
Eine Aktionsanweisung ist einer der wenigen Operatoren. Die Optionen für jede sind unten beschrieben. Sie können durch andere ergänzt werden, die, wie Sie bereits verstanden haben, in Vorlagen verwendet werden können.
Schleifenknotenformat:
<loop type=" "> ..... </loop>
Eine Schleife ist ein Abschnitt, dessen Inhalt für jedes Element ausgeführt wird, das durch den Schleifentyp bestimmt wird. Es gibt zwei davon (vorerst):
Werkzeuge - Für jedes Werkzeug wird eine Schleife ausgeführt, und
Werkzeuglöcher - Für jedes Loch, das zum Bohren mit diesem Werkzeug vorgesehen ist, wird ein Zyklus ausgeführt. Offensichtlich kann die
Werkzeuglochschleife nur in
Werkzeugen verschachtelt
werden .
Gleichzeitig sind beim Ausführen einer verschachtelten Schleife alle Variablen für das aktuelle Tool verfügbar. Warum? Weiß nicht. Gerade erzählt.
Betreiber
Werkzeuge zuweisenOptionen: keine.
Weist jeden Drill aus der Quell-Tool-Datei aus XML zu. Ohne sie sind die meisten anderen Aktionen bedeutungslos.
Werkzeuge verbindenOptionen: keine.
Organisatorischer - kombiniert alle Tools, die aus der XML-Datei gleich zugewiesen wurden. Es ist direkt nach dem Zuweisen von Tools sinnvoll, aber ich habe beschlossen, dem Benutzer die Möglichkeit zu geben, seine Operationen auszuführen.
Werkzeuge sortierenParameter: (noch) keine.
Sortiert Bohrer durch Erhöhen des Durchmessers
VersatzParameter:
xoffs, yoffs -
Offsetwerte . Die Skriptmaschine wird ausgeführt.
Verschiebt alle Löcher auf die angegebenen Werte. Ja, es kommt oft vor, dass das Board am Ursprung nicht weit voneinander entfernt ist.
druckenParameter:
Muster Der Name des Musters.
Druckt eine Vorlage mit dem angegebenen Namen im Ausgabestream.
Kontext druckenParameter:
line_begin, line_end - der Anfang und das Ende jeder Zeile.
Debugging-Funktion - Ermöglicht die Ausgabe aller derzeit verfügbaren Variablen und ihrer Werte an einer beliebigen Stelle in der Ausgabe. Jede Variable wird in einer separaten Zeile angezeigt, Anfang und Ende werden in den Parametern angegeben
Vordefinierte Namen globaler Variablen.
holeCount, toolsCount - Ich hoffe wirklich, wirklich, wirklich, dass die Bedeutung dieser Variablen keiner Erklärung bedarf. Ja Ja. Dies ist die Anzahl der Werkzeuge und die Anzahl der Löcher.
minX, maxX, minY, maxY - und diese auch. Nein, nur für den Fall, dies sind die Koordinaten des Bohrfeldes. Alle Löcher befinden sich in diesem Rechteck. Nach dem Offset-Befehl neu berechnet.
Fazit
Tatsächlich habe ich hier versucht, die geschaffene Tulza kurz, aber so vollständig wie möglich zu beschreiben.
Ehrlich gesagt, als ich versuchte, mir Nutzungsszenarien vorzustellen, stellte ich mir klar vor, wie oft das tatarisch-mongolische Joch in russischen Ländern auftauchen würde (es wird angenommen, dass sie uns die Matte gebracht haben).
Daher die Frage: Lohnt es sich, verwirrt zu sein und eine einfache Webseite zu erstellen, auf der Sie die Eingabe und das Skript einfügen und den fertigen G-Code erhalten können, wobei Sie die Montagephasen von der Quelle umgehen?UPD:
Vielen Dank an diejenigen, die abgestimmt haben.
Ich habe es abgewaschen . Und ... ja: Ich habe geschrieben, dass die Webseite einfach sein wird? Wenn jemand nicht zu faul ist, um alles ästhetischer zu gestalten, werfen Sie HTML in PM.