G92-Grad + E-Korrektur
This commit is contained in:
86
EmergencyStopButton/EmergencyStopButton.md
Normal file
86
EmergencyStopButton/EmergencyStopButton.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# Emergency Stop Button — Erkenntnisse & Entscheidungen
|
||||
|
||||
## Hardware-Wahl
|
||||
|
||||
### ESP32-C3 Super Mini — abgelehnt
|
||||
Das kompakte Board hat **keinen Laderegler** (kein TP4056/MCP73831, kein JST-Akku-Anschluss).
|
||||
Zudem zieht eine dauerhaft leuchtende Power-LED 1–2 mA — selbst ohne WLAN-Betrieb würde ein kleiner Akku in wenigen Tagen leer sein.
|
||||
|
||||
### DFRobot FireBeetle 2 — gewählt
|
||||
- Integrierter Laderegler + JST-PH-2.0-Anschluss direkt am Board
|
||||
- Low-Power optimiert (ab Werk ~15 µA im Deep Sleep)
|
||||
- Kein Zusatz-Hardware nötig für Akkubetrieb
|
||||
|
||||
## Akku-Spezifikation für den FireBeetle 2
|
||||
|
||||
Suchbegriffe:
|
||||
- `LiPo Akku 3.7V JST PH2.0 2000mAh Schutzschaltung`
|
||||
- `Li-Po 1S 3.7V protected JST-PH 2.0mm 2000mAh`
|
||||
|
||||
Pflichtmerkmale:
|
||||
| Merkmal | Wert |
|
||||
|---|---|
|
||||
| Typ | LiPo / Li-Polymer, **1S** (1 Zelle) |
|
||||
| Spannung | **3,7 V** nominal |
|
||||
| Stecker | **JST PH, 2,0 mm Raster, 2-polig** |
|
||||
| Schutzschaltung | **Ja** (BMS/PCM) |
|
||||
| Kapazität | **2000 mAh** |
|
||||
|
||||
> **Achtung:** Polarität vor dem Einstecken mit Multimeter prüfen — JST-PH-Stecker sind nicht normiert. Sicherste Option: Akku direkt bei DFRobot kaufen.
|
||||
|
||||
## Architektur-Entscheidung: WiFi Light Sleep (Priorität: 250 ms Latenz)
|
||||
|
||||
Die **250 ms Latenz** vom Knopfdruck bis zum API-Call ist das primäre Ziel.
|
||||
|
||||
| Option | Latenz | Ø Strom | Laufzeit (2000 mAh) |
|
||||
|---|---|---|---|
|
||||
| **WiFi Light Sleep (DTIM=10)** | **150–250 ms** ✅ | ~1 mA | **~80 Tage** |
|
||||
| Deep Sleep + Reconnect | 600–1300 ms ❌ | ~0,02 mA | ~mehrere Jahre |
|
||||
|
||||
Deep Sleep scheidet aus: Der WiFi-Reconnect nach dem Aufwachen dauert 600–1300 ms — die 250-ms-Anforderung wird klar verfehlt.
|
||||
|
||||
## WiFi Light Sleep — Funktionsprinzip
|
||||
|
||||
Die CPU schläft, der WiFi-Stack bleibt aktiv. Mit DTIM=10 wacht der ESP32 alle ~1000 ms für 1–2 ms auf, um gepufferte Pakete vom Router abzuholen. Die Verbindungsassoziation bleibt erhalten.
|
||||
|
||||
Ein **GPIO-Interrupt** (Leitung auf GND) weckt den ESP32 in **1–5 ms** — der API-Call kann sofort abgesetzt werden, weil WiFi bereits verbunden ist.
|
||||
|
||||
## Latenzbudget
|
||||
|
||||
| Schritt | Zeit |
|
||||
|---|---|
|
||||
| Wakeup aus Light Sleep | 1–5 ms |
|
||||
| WiFi-Verbindung prüfen (bereits aktiv) | 0 ms |
|
||||
| HTTP-Request aufbauen | 20–50 ms |
|
||||
| TLS-Handshake (HTTPS) | 50–150 ms |
|
||||
| Server-Antwort | 20–50 ms |
|
||||
| **Gesamt** | **~100–250 ms** ✅ |
|
||||
|
||||
## Akkulaufzeit (WiFi Light Sleep, 2000 mAh)
|
||||
|
||||
```
|
||||
Durchschnittsstrom (DTIM=10, Taster selten gedrückt): ~1 mA
|
||||
Nutzbare Kapazität (80 %): 1600 mAh
|
||||
Selbstentladung LiPo: ~2 mAh/Tag
|
||||
|
||||
Laufzeit ≈ 1600 mAh / 1 mA ≈ 1600 h ≈ 67–80 Tage
|
||||
```
|
||||
|
||||
> Zum Vergleich: Mit 1000 mAh (alter Stand) waren es ~40 Tage.
|
||||
|
||||
## GPIO Wake-Up — technische Details
|
||||
|
||||
- **Pegel-Trigger** (kein Flanken-Trigger): die Leitung muss >ein paar ms auf GND bleiben.
|
||||
- **Pull-Up intern** aktivieren: im Ruhezustand HIGH, Ereignis zieht auf GND.
|
||||
- **Wake-fähige Pins** sind nur RTC/LP-GPIOs — im FireBeetle-2-Datenblatt prüfen.
|
||||
- API: `esp_sleep_enable_gpio_wakeup()` / `esp_light_sleep_start()`
|
||||
|
||||
## Vergleich: Alternative Deep-Sleep-Architektur (nicht für E-Stop geeignet)
|
||||
|
||||
Falls in einem anderen Projekt Latenz < 1 s ausreicht und Akkulaufzeit Monate betragen soll:
|
||||
|
||||
- Deep Sleep, WLAN nur 8–18 Uhr alle 30 min (20 WLAN-Verbindungen/Tag)
|
||||
- Zusätzlich GPIO-Wake für Ereignisse (innerhalb ~300 ms nach Aufwachen + Reconnect)
|
||||
- Laufzeit 2000 mAh: **~8–10 Monate** (Selbstentladung dominant)
|
||||
|
||||
Für den Emergency Stop Button ist diese Option **nicht geeignet**, da die WiFi-Reconnect-Zeit die 250-ms-Anforderung überschreitet.
|
||||
@@ -41,7 +41,7 @@ Tastendruck geweckt.
|
||||
|
||||
\begin{itemize}
|
||||
\item Latenz Knopfdruck $\rightarrow$ API-Call: \textbf{< 250\,ms}
|
||||
\item Stromversorgung: LiPo 1000\,mAh (kabellos, batteriebetrieben)
|
||||
\item Stromversorgung: LiPo 2000\,mAh (kabellos, batteriebetrieben)
|
||||
\item Möglichst lange Akkulaufzeit (Taster wird selten gedrückt, $\leq$1\,×/h)
|
||||
\item Einfache, wartungsarme Architektur
|
||||
\end{itemize}
|
||||
@@ -105,13 +105,17 @@ DTIM & Wakeup-Intervall & Ø Strom \\
|
||||
|
||||
Empfohlen: \texttt{DTIM=10} -- sparsamste Option, Verbindung bleibt stabil.
|
||||
|
||||
\subsection{Akkulaufzeit (1000 mAh LiPo)}
|
||||
\subsection{Akkulaufzeit (2000 mAh LiPo)}
|
||||
|
||||
Bei $\approx$1\,mA Durchschnittsstrom (DTIM=10, selten gedrückt):
|
||||
Bei $\approx$1\,mA Durchschnittsstrom (DTIM=10, selten gedrückt) und 80\,\% nutzbarer Kapazität:
|
||||
\[
|
||||
t = \frac{1000~\mathrm{mAh}}{1~\mathrm{mA}} \approx 40~\mathrm{Tage}
|
||||
t = \frac{1600~\mathrm{mAh}}{1~\mathrm{mA}} \approx 67\text{--}80~\mathrm{Tage}
|
||||
\]
|
||||
|
||||
Die \textbf{Latenz von 250\,ms} hat Vorrang vor maximaler Akkulaufzeit -- Deep Sleep scheidet
|
||||
daher aus (WiFi-Reconnect 600--1300\,ms). Mit 2000\,mAh und WiFi Light Sleep sind
|
||||
ca.\ 2,5 Monate Betrieb ohne Laden realistisch.
|
||||
|
||||
% -----------------------------------------------
|
||||
\section{Latenzbudget}
|
||||
|
||||
@@ -148,6 +152,27 @@ Adafruit HUZZAH32 Feather & MCP73831 & $\approx$20\,€ & gute Dokumentation \\
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
\subsection{Akku-Spezifikation}
|
||||
|
||||
Für den FireBeetle\,2 wird ein \textbf{1S LiPo mit JST-PH-2,0-Stecker und BMS} benötigt:
|
||||
|
||||
\begin{center}
|
||||
\begin{tabular}{ll}
|
||||
\toprule
|
||||
Merkmal & Wert \\
|
||||
\midrule
|
||||
Typ & LiPo / Li-Polymer, 1 Zelle (1S) \\
|
||||
Nennspannung & 3{,}7\,V (voll: 4{,}2\,V) \\
|
||||
Stecker & JST PH, 2{,}0\,mm Raster, 2-polig \\
|
||||
Schutzschaltung & Ja (BMS/PCM) -- Pflicht bei Deep-Sleep-Betrieb \\
|
||||
Kapazität & 2000\,mAh \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
\textbf{Achtung Polarität:} JST-PH-Stecker sind nicht normiert -- Polung vor dem
|
||||
Einstecken mit Multimeter prüfen. Sicherste Quelle: Akku direkt bei DFRobot kaufen.
|
||||
|
||||
\subsection{Schaltung}
|
||||
|
||||
\begin{lstlisting}
|
||||
@@ -155,7 +180,7 @@ ESP32 Taster
|
||||
GPIO 9 ---- [Taster] ---- GND
|
||||
(interner Pull-Up aktiv: HIGH = offen, LOW = gedrueckt)
|
||||
|
||||
LiPo 1000mAh ---- BAT+ / BAT- des Boards
|
||||
LiPo 2000mAh (JST PH 2.0, mit BMS) ---- BAT+ / BAT- des Boards
|
||||
\end{lstlisting}
|
||||
|
||||
Kein weiteres Bauteil nötig -- der interne Pull-Up des ESP32 reicht.
|
||||
|
||||
13
README.md
13
README.md
@@ -2,6 +2,17 @@
|
||||
|
||||
Dieses Projekt empfängt G-Code und Robotersteuerbefehle, berechnet Inverse Kinematik für einen mehrgliedrigen Roboterarm und leitet die resultierenden Achsenbefehle an mehrere GRBL/FluidNC-Telnet-Sender weiter.
|
||||
|
||||
## Einbindung ins Projekt
|
||||
|
||||
Der Driver steht zwischen Eingabe-Programmen (appInput oder appAutomasiation oder jede beliebige andere Eingabeform)
|
||||
welche die Eingabe steuert. Die Eingabe wird eben an den Driver weitergegeben. Hier im Driver werden die Welt-Koordinaten
|
||||
in Motor-Koordinaten umgerechnet, es werden die Motoren angesteuert.
|
||||
|
||||
<img src="doc/SoftwareModularisation.svg" width="30%" alt="Software Modularisierung">
|
||||
|
||||
Die Motor--Steuerung erfolgt (momentan) per GCode an FluidNC Driver--Boards. Diese arbeiten jeweils mit
|
||||
Motor-Koordinaten in den X, Y und Z-Achsen. Es werden mehrere FluidNC Boards unterstützt.
|
||||
|
||||
## Architektur
|
||||
|
||||
- `startRobot.js` startet zwei HTTPS-Server:
|
||||
@@ -28,7 +39,7 @@ Die Eingaben kommen per WebSocket an den HTTPS-Server und werden in `server/Inpu
|
||||
- Antwort: Positionsdaten des Roboters im JSON-Format.
|
||||
- G-Code-Befehle:
|
||||
- `G90`, `G91`, `G1`, `G28`
|
||||
- `G92` (wird intern als `M92` verarbeitet — setzt Motorposition ohne Bewegung)
|
||||
- `G92` setzt die Motorposition ohne Bewegung. Winkel (`Y`,`Z`,`A`,`B`,`C`) in **Grad** (G-Code-Konvention, wie FluidNC); `X` in mm; `E` = Greifer-Öffnung in mm (ab Null-Position eines Fingers), wird intern über die Greifer-Kopplung in `eMotor` umgerechnet. (`M92` macht dasselbe, erwartet die Winkel aber roh in **Radiant**.)
|
||||
- Messungen in `X`, `Y`, `Z`, `A`, `B`, `C`, `E`, `F`
|
||||
- `M1` für direkte Motor-Koordinaten
|
||||
- FCodes (Datei-/Programm-Befehle) — werden durch den Driver an `appRobotFileservice` weitergeleitet:
|
||||
|
||||
553
doc/Server_to_Robot.svg
Normal file
553
doc/Server_to_Robot.svg
Normal file
@@ -0,0 +1,553 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="185.6852mm"
|
||||
height="185.04396mm"
|
||||
viewBox="0 0 185.6852 185.04396"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.4.2 (ebf0e94, 2025-05-08)"
|
||||
sodipodi:docname="Server_to_Robot.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="0.7884049"
|
||||
inkscape:cx="418.56665"
|
||||
inkscape:cy="298.70438"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1129"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1"
|
||||
showguides="true">
|
||||
<sodipodi:guide
|
||||
position="104.23929,266.06288"
|
||||
orientation="0,-1"
|
||||
id="guide2"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<defs
|
||||
id="defs1">
|
||||
<marker
|
||||
style="overflow:visible"
|
||||
id="ArrowTriangleStylized"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto-start-reverse"
|
||||
inkscape:stockid="Stylized triangle arrow"
|
||||
markerWidth="0.80000001"
|
||||
markerHeight="0.80000001"
|
||||
viewBox="0 0 1 1"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always"
|
||||
preserveAspectRatio="xMidYMid">
|
||||
<path
|
||||
transform="scale(0.5)"
|
||||
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
|
||||
d="m 6,0 c -3,1 -7,3 -9,5 0,0 0,-4 2,-5 -2,-1 -2,-5 -2,-5 2,2 6,4 9,5 z"
|
||||
id="path4" />
|
||||
</marker>
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
style="color-interpolation-filters:sRGB"
|
||||
id="filter1"
|
||||
x="-0.30270667"
|
||||
y="-0.03584998"
|
||||
width="1.4504006"
|
||||
height="1.162455">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="1.4976689"
|
||||
id="feGaussianBlur1" />
|
||||
</filter>
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
style="color-interpolation-filters:sRGB"
|
||||
id="filter2"
|
||||
x="-0.0071527473"
|
||||
y="-0.027732722"
|
||||
width="1.0143055"
|
||||
height="1.0554654">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.24767946"
|
||||
id="feGaussianBlur2" />
|
||||
</filter>
|
||||
<marker
|
||||
style="overflow:visible"
|
||||
id="ArrowTriangleStylized-9"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto-start-reverse"
|
||||
inkscape:stockid="Stylized triangle arrow"
|
||||
markerWidth="0.80000001"
|
||||
markerHeight="0.80000001"
|
||||
viewBox="0 0 1 1"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always"
|
||||
preserveAspectRatio="xMidYMid">
|
||||
<path
|
||||
transform="scale(0.5)"
|
||||
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
|
||||
d="m 6,0 c -3,1 -7,3 -9,5 0,0 0,-4 2,-5 -2,-1 -2,-5 -2,-5 2,2 6,4 9,5 z"
|
||||
id="path4-0" />
|
||||
</marker>
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
style="color-interpolation-filters:sRGB"
|
||||
id="filter1-7"
|
||||
x="-0.62539401"
|
||||
y="-0.033621411"
|
||||
width="2.5964451"
|
||||
height="1.1841982">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="1.4976689"
|
||||
id="feGaussianBlur1-6" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-18.207626,-12.726111)">
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:#ffff00;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect3"
|
||||
width="268.13898"
|
||||
height="222.83389"
|
||||
x="-2.5991523"
|
||||
y="-0.36202425"
|
||||
rx="3.4391522"
|
||||
ry="3.640882" />
|
||||
<rect
|
||||
style="fill:none;stroke:#800000;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.363309"
|
||||
id="rect2-7-3-0-1-1-3-3"
|
||||
width="24.441923"
|
||||
height="27.052231"
|
||||
x="170.64005"
|
||||
y="158.19603"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="fill:none;stroke:#800000;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.363309"
|
||||
id="rect2-7-3-0-1-1-3-3-2"
|
||||
width="24.441923"
|
||||
height="27.052231"
|
||||
x="135.24863"
|
||||
y="155.13577"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:#800000;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.363309"
|
||||
id="rect2-7-3-0-1-1-3-3-2-3"
|
||||
width="24.441923"
|
||||
height="27.052231"
|
||||
x="140.22813"
|
||||
y="156.67696"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="opacity:1;fill:#ffffff;stroke:#008000;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.298561"
|
||||
id="rect2-1-7-2-0"
|
||||
width="22.543501"
|
||||
height="60.748863"
|
||||
x="174.14117"
|
||||
y="98.800468"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:#008000;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2-1-7"
|
||||
width="59.087742"
|
||||
height="61.460766"
|
||||
x="62.740757"
|
||||
y="99.263435"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="fill:none;stroke:#000080;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2-7"
|
||||
width="32.03553"
|
||||
height="27.052229"
|
||||
x="68.540405"
|
||||
y="55.081566"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="fill:none;stroke:#000080;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.25"
|
||||
id="rect2-7-1"
|
||||
width="34.888073"
|
||||
height="75.545448"
|
||||
x="66.882202"
|
||||
y="53.743294"
|
||||
ry="8.3898315" />
|
||||
<rect
|
||||
style="fill:none;stroke:#000080;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2-7-8"
|
||||
width="14.712612"
|
||||
height="27.052227"
|
||||
x="124.56292"
|
||||
y="54.991467"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="fill:none;stroke:#000080;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2-7-8-5"
|
||||
width="14.712612"
|
||||
height="27.052227"
|
||||
x="159.14595"
|
||||
y="54.767498"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="opacity:0.684327;fill:#ffffff;stroke:#000080;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none;filter:url(#filter2)"
|
||||
id="rect2-8"
|
||||
width="118.05676"
|
||||
height="30.448875"
|
||||
x="71.373299"
|
||||
y="42.542305"
|
||||
ry="8.5576286" />
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:#008000;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.586331"
|
||||
id="rect2-1-7-2"
|
||||
width="22.543501"
|
||||
height="60.748863"
|
||||
x="140.53279"
|
||||
y="98.616264"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="opacity:0.187638;fill:#ffffff;stroke:#000080;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2-3-8"
|
||||
width="36.781532"
|
||||
height="27.76413"
|
||||
x="27.882366"
|
||||
y="43.876053"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="fill:none;stroke:#800000;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2-7-3-0-1-1-3"
|
||||
width="24.441923"
|
||||
height="27.052231"
|
||||
x="82.887558"
|
||||
y="166.4115"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:#800000;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2-7-3-0-1-1"
|
||||
width="24.441923"
|
||||
height="27.052231"
|
||||
x="77.66507"
|
||||
y="170.46783"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="fill:none;stroke:#000080;stroke-width:0.5;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect1"
|
||||
width="177.95691"
|
||||
height="55.182091"
|
||||
x="18.457626"
|
||||
y="35.237286"
|
||||
ry="7.2152543" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:bold;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, Bold';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000080;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="23.82712"
|
||||
y="33.894917"
|
||||
id="text1"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';fill:#000080;stroke:none;stroke-width:0.5"
|
||||
x="23.82712"
|
||||
y="33.894917">server.schooltech.ch.</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:bold;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, Bold';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#008000;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="-143.19246"
|
||||
y="61.593941"
|
||||
id="text1-9"
|
||||
transform="rotate(-90)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1-1"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';fill:#008000;stroke:none;stroke-width:0.5"
|
||||
x="-143.19246"
|
||||
y="61.593941">MiniPC</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:bold;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, Bold';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;opacity:0.572347;fill:#008000;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="-140.84836"
|
||||
y="139.27716"
|
||||
id="text1-9-3"
|
||||
transform="rotate(-90)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1-1-2"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';fill:#008000;stroke:none;stroke-width:0.5"
|
||||
x="-140.84836"
|
||||
y="139.27716">MiniPc2</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:bold;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, Bold';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;opacity:0.308682;fill:#008000;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="-128.90205"
|
||||
y="173.23196"
|
||||
id="text1-9-3-8"
|
||||
transform="rotate(-90)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1-1-2-4"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:center;text-anchor:middle;fill:#008000;stroke:none;stroke-width:0.5"
|
||||
x="-128.90205"
|
||||
y="173.23196">Raspi 3</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:center;text-anchor:middle;fill:#008000;stroke:none;stroke-width:0.5"
|
||||
x="-128.90205"
|
||||
y="182.96658"
|
||||
id="tspan5">(ohne Video)</tspan></text>
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:#000080;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2"
|
||||
width="49.595745"
|
||||
height="27.76413"
|
||||
x="72.851173"
|
||||
y="43.900543"
|
||||
ry="7.2152543" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000080;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="81.393982"
|
||||
y="60.274261"
|
||||
id="text2"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2"
|
||||
style="fill:#000080;stroke:none;stroke-width:0.5"
|
||||
x="81.393982"
|
||||
y="60.274261">Portal UI</tspan></text>
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:#000080;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2-3"
|
||||
width="36.781532"
|
||||
height="27.76413"
|
||||
x="23.999027"
|
||||
y="55.154541"
|
||||
ry="7.2152543" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000080;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="31.118034"
|
||||
y="71.528259"
|
||||
id="text2-87"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2-4"
|
||||
style="fill:#000080;stroke:none;stroke-width:0.5"
|
||||
x="31.118034"
|
||||
y="71.528259">Admin</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;opacity:0.229581;fill:#000080;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="34.223759"
|
||||
y="52.143547"
|
||||
id="text2-87-1"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2-4-7"
|
||||
style="fill:#000080;stroke:none;stroke-width:0.5"
|
||||
x="34.223759"
|
||||
y="52.143547">Nginx</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000080;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="72.928909"
|
||||
y="79.513229"
|
||||
id="text2-8"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2-2"
|
||||
style="fill:#000080;stroke:none;stroke-width:0.5"
|
||||
x="72.928909"
|
||||
y="79.513229">Tunnel</tspan></text>
|
||||
<rect
|
||||
style="fill:none;stroke:#008000;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2-7-3"
|
||||
width="31.532143"
|
||||
height="25.70986"
|
||||
x="68.459602"
|
||||
y="101.92957"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="fill:none;stroke:#008000;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2-7-3-0"
|
||||
width="32.03553"
|
||||
height="27.052229"
|
||||
x="68.916672"
|
||||
y="130.88501"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:#800000;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2-7-3-0-1"
|
||||
width="24.441923"
|
||||
height="27.052231"
|
||||
x="70.099998"
|
||||
y="167.20209"
|
||||
ry="7.2152543" />
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:#008000;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2-1"
|
||||
width="44.058456"
|
||||
height="26.757345"
|
||||
x="74.350037"
|
||||
y="111.79094"
|
||||
ry="7.2152543" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#008000;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="82.053864"
|
||||
y="127.73859"
|
||||
id="text2-9"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2-8"
|
||||
style="fill:#008000;stroke:none;stroke-width:0.5"
|
||||
x="82.053864"
|
||||
y="127.73859">MainApp</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#008000;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="73.756584"
|
||||
y="109.90114"
|
||||
id="text2-8-6"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2-2-5"
|
||||
style="fill:#008000;stroke:none;stroke-width:0.5"
|
||||
x="73.756584"
|
||||
y="109.90114">Tunnel</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#008000;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="74.230339"
|
||||
y="148.89832"
|
||||
id="text2-8-6-5"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2-2-5-0"
|
||||
style="fill:#008000;stroke:none;stroke-width:0.5"
|
||||
x="74.230339"
|
||||
y="148.89832">Driver</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#008000;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="72.633484"
|
||||
y="178.56844"
|
||||
id="text2-8-6-5-4"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2-2-5-0-4"
|
||||
style="fill:#800000;stroke:none;stroke-width:0.5"
|
||||
x="72.633484"
|
||||
y="178.56844">Robot</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="fill:#800000;stroke:none;stroke-width:0.5"
|
||||
x="72.633484"
|
||||
y="188.26981"
|
||||
id="tspan3">board</tspan></text>
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:#000080;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2-5"
|
||||
width="22.780821"
|
||||
height="27.526825"
|
||||
x="128.87369"
|
||||
y="43.978241"
|
||||
ry="7.2152543" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000080;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="137.4165"
|
||||
y="60.184162"
|
||||
id="text2-7"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2-6"
|
||||
style="fill:#000080;stroke:none;stroke-width:0.5"
|
||||
x="137.4165"
|
||||
y="60.184162">UI</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000080;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="129.6226"
|
||||
y="79.75872"
|
||||
id="text2-8-1"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2-2-8"
|
||||
style="fill:#000080;stroke:none;stroke-width:0.5"
|
||||
x="129.6226"
|
||||
y="79.75872">T</tspan></text>
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:#000080;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect2-5-4"
|
||||
width="22.780821"
|
||||
height="27.526825"
|
||||
x="165.13467"
|
||||
y="43.754272"
|
||||
ry="7.2152543" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000080;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="171.99953"
|
||||
y="59.960194"
|
||||
id="text2-7-3"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2-6-1"
|
||||
style="fill:#000080;stroke:none;stroke-width:0.5"
|
||||
x="171.99953"
|
||||
y="59.960194">UI</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.7611px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;fill:#000080;stroke:none;stroke-width:0.499999;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="163.70226"
|
||||
y="79.199165"
|
||||
id="text2-8-1-2"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2-2-8-3"
|
||||
style="fill:#000080;stroke:none;stroke-width:0.5"
|
||||
x="163.70226"
|
||||
y="79.199165">T</tspan></text>
|
||||
<path
|
||||
style="opacity:0.677704;mix-blend-mode:normal;fill:none;stroke:#338000;stroke-width:5;stroke-linejoin:round;stroke-dasharray:none;marker-end:url(#ArrowTriangleStylized);filter:url(#filter1)"
|
||||
d="m 139.46805,20.675199 c 0,0 -22.67989,32.409972 -24.62856,38.778949 -4.89798,16.008385 -4.12484,30.729749 -3.84747,40.716632 0.28059,10.10266 1.18759,28.44197 -1.1865,39.86643 -1.8449,8.87791 -8.54281,20.88243 -8.54281,20.88243"
|
||||
id="path1"
|
||||
sodipodi:nodetypes="csssc" />
|
||||
<path
|
||||
style="opacity:0.270096;mix-blend-mode:normal;fill:none;stroke:#338000;stroke-width:5;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#ArrowTriangleStylized-9);filter:url(#filter1-7)"
|
||||
d="m 182.53306,26.969611 c -16.61161,54.420297 22.65849,44.720607 2.6103,128.616729"
|
||||
id="path1-8"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:11.2889px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;opacity:0.781457;fill:#338000;stroke:#00ffff;stroke-width:10;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="139.23076"
|
||||
y="20.200598"
|
||||
id="text4"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:11.2889px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, Bold';fill:#338000;stroke:none;stroke-width:10"
|
||||
x="139.23076"
|
||||
y="20.200598">User</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:11.2889px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, ';text-align:start;writing-mode:lr-tb;direction:ltr;text-anchor:start;opacity:0.781457;fill:#338000;fill-opacity:0.399281;stroke:#00ffff;stroke-width:10;stroke-linejoin:round;stroke-dasharray:none"
|
||||
x="176.33203"
|
||||
y="24.640509"
|
||||
id="text4-8"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4-6"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:11.2889px;font-family:'Times New Roman';-inkscape-font-specification:'Times New Roman, Bold';fill:#338000;fill-opacity:0.399281;stroke:none;stroke-width:10"
|
||||
x="176.33203"
|
||||
y="24.640509">User3</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:3.175px;text-align:center;text-anchor:middle;opacity:0.270096;fill:#ffffff;fill-opacity:0.553957;stroke:#338000;stroke-width:0.799999"
|
||||
x="173.63927"
|
||||
y="23.712084"
|
||||
id="text6"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6"
|
||||
style="stroke-width:0.8"
|
||||
x="173.63927"
|
||||
y="23.712084" /></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 24 KiB |
321
doc/SoftwareModularisation.svg
Normal file
321
doc/SoftwareModularisation.svg
Normal file
@@ -0,0 +1,321 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="254.71674mm"
|
||||
height="103.7089mm"
|
||||
viewBox="0 0 254.71674 103.7089"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
inkscape:version="1.4.2 (ebf0e94, 2025-05-08)"
|
||||
sodipodi:docname="SoftwareModularisation.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.73851712"
|
||||
inkscape:cx="624.22385"
|
||||
inkscape:cy="295.18612"
|
||||
inkscape:window-width="1710"
|
||||
inkscape:window-height="752"
|
||||
inkscape:window-x="122"
|
||||
inkscape:window-y="174"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2">
|
||||
<rect
|
||||
x="82.597954"
|
||||
y="404.86536"
|
||||
width="207.17191"
|
||||
height="81.243889"
|
||||
id="rect342" />
|
||||
<marker
|
||||
style="overflow:visible"
|
||||
id="ArrowTriangleStylized"
|
||||
refX="0"
|
||||
refY="0"
|
||||
orient="auto-start-reverse"
|
||||
inkscape:stockid="Stylized triangle arrow"
|
||||
markerWidth="0.80000001"
|
||||
markerHeight="0.80000001"
|
||||
viewBox="0 0 1 1"
|
||||
inkscape:isstock="true"
|
||||
inkscape:collect="always"
|
||||
preserveAspectRatio="xMidYMid">
|
||||
<path
|
||||
transform="scale(0.5)"
|
||||
style="fill:context-stroke;fill-rule:evenodd;stroke:context-stroke;stroke-width:1pt"
|
||||
d="m 6,0 c -3,1 -7,3 -9,5 0,0 0,-4 2,-5 -2,-1 -2,-5 -2,-5 2,2 6,4 9,5 z"
|
||||
id="path4" />
|
||||
</marker>
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
style="color-interpolation-filters:sRGB"
|
||||
id="filter1"
|
||||
x="-0.046015804"
|
||||
y="-0.087898715"
|
||||
width="1.1621232"
|
||||
height="1.3448635">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="1.4976689"
|
||||
id="feGaussianBlur1" />
|
||||
</filter>
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(36.090885,-5.8258868)">
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:#ffff00;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect1"
|
||||
width="322.79492"
|
||||
height="150.47044"
|
||||
x="-50.063141"
|
||||
y="0.81020516"
|
||||
rx="3.4391522"
|
||||
ry="3.640882" />
|
||||
<rect
|
||||
style="fill:none;fill-opacity:0.204013;stroke:#ff5555;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect1257"
|
||||
width="178.77321"
|
||||
height="59.471653"
|
||||
x="9.6731005"
|
||||
y="49.798553"
|
||||
ry="6.2628565" />
|
||||
<rect
|
||||
style="fill:#0000ff;fill-opacity:0.204013;stroke:#0000ff;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect234"
|
||||
width="77.743065"
|
||||
height="24.361881"
|
||||
x="40.125454"
|
||||
y="60.188179"
|
||||
ry="6.2628565" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="scale(0.26458333)"
|
||||
id="text340"
|
||||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect342);display:inline;fill:#000000;fill-opacity:1;stroke:#ff5555" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:9.61905px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.240477"
|
||||
x="52.229092"
|
||||
y="68.706116"
|
||||
id="text402"
|
||||
transform="scale(0.90888935,1.1002439)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan400"
|
||||
style="stroke-width:0.240477"
|
||||
x="52.229092"
|
||||
y="68.706116">RoboticsDriver</tspan></text>
|
||||
<rect
|
||||
style="fill:#0000ff;fill-opacity:0.204013;stroke:#0000ff;stroke-width:0.547466;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect234-4"
|
||||
width="31.870832"
|
||||
height="13.579219"
|
||||
x="29.924107"
|
||||
y="92.440994"
|
||||
ry="6.2544284" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:7.05556px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
|
||||
x="31.706272"
|
||||
y="101.74669"
|
||||
id="text402-5"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan400-9"
|
||||
style="font-size:7.05556px;stroke-width:0.264583"
|
||||
x="31.706272"
|
||||
y="101.74669">FluidNC</tspan></text>
|
||||
<rect
|
||||
style="fill:#0000ff;fill-opacity:0.204013;stroke:#0000ff;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect234-4-1"
|
||||
width="29.735825"
|
||||
height="13.597518"
|
||||
x="67.371765"
|
||||
y="92.798347"
|
||||
ry="6.2628565" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:7.05556px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
|
||||
x="68.78791"
|
||||
y="102.2177"
|
||||
id="text402-5-4"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan400-9-5"
|
||||
style="font-size:7.05556px;stroke-width:0.264583"
|
||||
x="68.78791"
|
||||
y="102.2177">FluidNC</tspan></text>
|
||||
<rect
|
||||
style="fill:#0000ff;fill-opacity:0.204013;stroke:#0000ff;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect234-4-1-3"
|
||||
width="29.735825"
|
||||
height="13.597518"
|
||||
x="106.22498"
|
||||
y="92.798347"
|
||||
ry="6.2628565" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:7.05556px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
|
||||
x="112.161"
|
||||
y="102.11319"
|
||||
id="text402-5-3-2"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan400-9-4-6"
|
||||
style="font-size:7.05556px;stroke-width:0.264583"
|
||||
x="112.161"
|
||||
y="102.11319">... </tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:7.05556px;line-height:1.25;font-family:sans-serif;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.264583"
|
||||
x="186.6279"
|
||||
y="76.870903"
|
||||
id="text1365"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1363"
|
||||
style="font-size:7.05556px;text-align:end;text-anchor:end;fill:#ff0000;stroke-width:0.264583"
|
||||
x="186.6279"
|
||||
y="76.870903">Info, Installation</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="font-size:7.05556px;text-align:end;text-anchor:end;fill:#ff0000;stroke-width:0.264583"
|
||||
x="186.6279"
|
||||
y="85.690353"
|
||||
id="tspan1367">& Management</tspan></text>
|
||||
<rect
|
||||
style="fill:#bcffbc;fill-opacity:1;stroke:#00ff00;stroke-width:0.57906;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect1369"
|
||||
width="46.882557"
|
||||
height="19.296309"
|
||||
x="18.31204"
|
||||
y="32.985142"
|
||||
ry="6.2467051" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
|
||||
x="20.270605"
|
||||
y="45.266979"
|
||||
id="text3141"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3139"
|
||||
style="stroke-width:0.264583"
|
||||
x="20.270605"
|
||||
y="45.266979">Eingabe</tspan></text>
|
||||
<rect
|
||||
style="fill:#bcffbc;fill-opacity:1;stroke:#00ff00;stroke-width:0.58073;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect1369-9"
|
||||
width="60.136616"
|
||||
height="19.294638"
|
||||
x="53.404377"
|
||||
y="7.1910405"
|
||||
ry="6.1369925" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
|
||||
x="55.362103"
|
||||
y="19.472044"
|
||||
id="text3141-8"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3139-7"
|
||||
style="stroke-width:0.264583"
|
||||
x="55.362103"
|
||||
y="19.472044">Programm</tspan></text>
|
||||
<rect
|
||||
style="fill:#bcffbc;fill-opacity:1;stroke:#00ff00;stroke-width:0.59402;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect1369-9-7"
|
||||
width="90.575684"
|
||||
height="20.620722"
|
||||
x="127.75317"
|
||||
y="6.1228967"
|
||||
ry="6.1341004" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
|
||||
x="133.28688"
|
||||
y="20.546833"
|
||||
id="text3141-8-4"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3139-7-5"
|
||||
style="stroke-width:0.264583"
|
||||
x="133.28688"
|
||||
y="20.546833">Automatisieren</tspan></text>
|
||||
<rect
|
||||
style="fill:#bcffbc;fill-opacity:1;stroke:#00ff00;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect1369-9-7-1"
|
||||
width="55.172501"
|
||||
height="18.177734"
|
||||
x="-35.826302"
|
||||
y="13.41999"
|
||||
ry="6.1533923" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:9.75471px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.243868"
|
||||
x="-36.601929"
|
||||
y="23.712566"
|
||||
id="text3141-8-4-3"
|
||||
transform="scale(0.92170774,1.0849426)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3139-7-5-9"
|
||||
style="stroke-width:0.243868"
|
||||
x="-36.601929"
|
||||
y="23.712566">Interaktion</tspan></text>
|
||||
<rect
|
||||
style="fill:#bcffbc;fill-opacity:1;stroke:#00ff00;stroke-width:0.572522;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect1369-0"
|
||||
width="45.814304"
|
||||
height="19.302847"
|
||||
x="138.13206"
|
||||
y="48.384411"
|
||||
ry="6.2488213" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
|
||||
x="140.09389"
|
||||
y="60.669518"
|
||||
id="text3141-7"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3139-6"
|
||||
style="stroke-width:0.264583"
|
||||
x="140.09389"
|
||||
y="60.669518">Anzeige</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
|
||||
x="196.68637"
|
||||
y="35.060978"
|
||||
id="text9629"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan9627"
|
||||
style="fill:#00ff00;stroke-width:0.264583"
|
||||
x="196.68637"
|
||||
y="35.060978">App</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
|
||||
x="-2.2734814"
|
||||
y="38.910786"
|
||||
id="text9629-1"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan9627-2"
|
||||
style="fill:#00ff00;stroke-width:0.264583"
|
||||
x="-2.2734814"
|
||||
y="38.910786">App</tspan></text>
|
||||
<path
|
||||
style="opacity:0.677704;mix-blend-mode:normal;fill:none;stroke:#338000;stroke-width:5;stroke-linejoin:round;stroke-dasharray:none;marker-end:url(#ArrowTriangleStylized);filter:url(#filter1)"
|
||||
d="m 30.489165,22.750961 c 39.165646,1.677077 80.639205,15.871211 80.435915,31.846606 -0.27243,21.408071 1.05382,18.470822 -9.37105,37.461762"
|
||||
id="path1-9"
|
||||
sodipodi:nodetypes="csc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -10809,3 +10809,205 @@
|
||||
2026-06-14T11:37:52.055Z ::ffff:127.0.0.1: M114
|
||||
2026-06-14T11:37:52.277Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-14T11:37:52.509Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:03:59.536Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:03:59.571Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:03:59.593Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:03:59.614Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:03:59.621Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:03:59.637Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:03:59.836Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:04:00.049Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:04:00.282Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:04:11.315Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:04:11.353Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:04:11.356Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:04:11.369Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:04:11.371Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:04:11.382Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:04:11.508Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:04:11.722Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:04:11.953Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:04:20.552Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:04:20.569Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:04:20.569Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:04:20.605Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:04:20.617Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:04:20.634Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:04:20.771Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:04:20.998Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:04:21.222Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:08:34.871Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:08:34.888Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:08:34.888Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:08:34.915Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:08:34.926Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:08:34.936Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:08:35.051Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:08:35.264Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:08:35.494Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:08:38.150Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:08:38.171Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:08:38.185Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:08:38.186Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:08:38.200Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:08:38.209Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:08:38.344Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:08:38.558Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:08:38.789Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:14:41.227Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:14:41.286Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:14:41.305Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:14:41.318Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:14:41.333Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:14:41.350Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:14:41.531Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:14:41.755Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:14:41.992Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:25:20.901Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:25:21.135Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:25:21.372Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:25:21.445Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:25:21.476Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:25:21.491Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:25:21.490Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:25:21.502Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:25:21.505Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:25:28.958Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:25:29.178Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:25:29.424Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:25:29.442Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:25:29.470Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:25:29.482Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:25:29.485Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:25:29.492Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:25:29.498Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:25:42.243Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:25:42.326Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:25:42.351Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:25:42.357Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:25:42.364Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:25:42.371Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:25:42.375Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:25:42.465Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:25:42.689Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:25:49.667Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:25:49.696Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:25:49.708Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:25:49.710Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:25:49.721Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:25:49.723Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:25:49.886Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:25:50.103Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:25:50.331Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:26:01.509Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:26:01.592Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:26:01.617Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:26:01.624Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:26:01.632Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:26:01.638Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:26:01.652Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:26:01.744Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:26:01.980Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:26:26.068Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:26:26.152Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:26:26.179Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:26:26.186Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:26:26.197Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:26:26.200Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:26:26.213Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:26:26.297Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:26:26.533Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:30:08.621Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:30:08.639Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:30:08.744Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:30:09.003Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:30:09.009Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:30:09.039Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:30:09.056Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:30:09.068Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:30:09.256Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:30:11.200Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:30:11.365Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:30:11.401Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:30:11.418Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:30:11.429Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:30:11.431Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:30:11.433Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:30:11.447Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:30:11.664Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:36:03.192Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:36:03.222Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:36:03.223Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:36:03.235Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:36:03.248Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:36:03.479Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:36:08.260Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:36:08.503Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:36:13.731Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:36:25.750Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:36:25.972Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:36:26.067Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:36:26.098Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:36:26.111Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:36:26.124Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:36:30.778Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:36:30.998Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:36:36.241Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:36:39.714Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:36:39.749Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:36:39.763Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:36:39.778Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:36:39.813Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:36:39.830Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:36:40.002Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:36:40.224Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:36:45.463Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:36:56.688Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:36:56.716Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:36:56.734Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:36:56.747Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:36:56.884Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:36:56.892Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:36:56.972Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:36:57.212Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:36:57.462Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:36:59.277Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:36:59.305Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:36:59.536Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:36:59.567Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:36:59.582Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:36:59.596Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:36:59.793Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:37:00.013Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:37:00.237Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:37:15.021Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:37:15.030Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:39:35.648Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:39:35.659Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:41:46.209Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:41:46.340Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:41:46.367Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:41:46.382Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:41:46.398Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:41:46.399Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:41:46.416Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:41:46.437Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:41:46.671Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:42:28.868Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:42:29.070Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:42:29.086Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:42:29.093Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:42:29.099Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:42:29.108Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:42:29.211Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:42:29.223Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:42:29.326Z ::ffff:127.0.0.1: G1 X1
|
||||
2026-06-25T16:42:31.618Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:42:31.633Z ::ffff:127.0.0.1: FList
|
||||
2026-06-25T16:42:31.636Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:42:31.669Z ::ffff:127.0.0.1: FPlus
|
||||
2026-06-25T16:42:31.684Z ::ffff:127.0.0.1: FLoad nichtda
|
||||
2026-06-25T16:42:31.695Z ::ffff:127.0.0.1: FShow
|
||||
2026-06-25T16:42:31.758Z ::ffff:127.0.0.1: M114
|
||||
2026-06-25T16:42:31.991Z ::ffff:127.0.0.1: G1 X1 Y2 Z3
|
||||
2026-06-25T16:42:32.218Z ::ffff:127.0.0.1: G1 X1
|
||||
|
||||
@@ -14762,3 +14762,49 @@
|
||||
2026-06-14T11:37:48.506Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-14T11:37:51.780Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-14T11:37:51.825Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:03:59.576Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:03:59.604Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:04:11.272Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:04:11.329Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:04:20.515Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:04:20.538Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:08:34.823Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:08:34.834Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:08:38.112Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:08:38.138Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:14:41.281Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:14:41.295Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:25:20.653Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:25:21.462Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:25:28.700Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:25:29.460Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:25:41.995Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:25:42.332Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:25:49.649Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:25:49.680Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:26:01.271Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:26:01.590Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:26:25.831Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:26:26.148Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:30:08.515Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:30:08.577Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:30:10.959Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:30:11.400Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:36:03.194Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:36:03.235Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:36:25.716Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:36:25.728Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:36:39.770Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:36:39.778Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:36:56.756Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:36:56.869Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:36:59.231Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:36:59.560Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:37:15.012Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:39:35.638Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:41:45.963Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:41:46.370Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:42:28.634Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:42:29.198Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:42:31.500Z ::ffff:127.0.0.1 : Ping
|
||||
2026-06-25T16:42:31.578Z ::ffff:127.0.0.1 : Ping
|
||||
|
||||
@@ -20,7 +20,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
document.getElementById('state-theta').textContent = fmt(p.b*180/Math.PI);
|
||||
document.getElementById('state-psi').textContent = fmt(p.c*180/Math.PI);
|
||||
|
||||
document.getElementById('state-e').textContent = fmt(m.e*180/Math.PI);
|
||||
// Greifer-Öffnung in mm (Workspace) — keine Grad-Umrechnung.
|
||||
document.getElementById('state-e').textContent = fmt(p.e);
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +34,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
document.getElementById('motor-b').textContent = fmt(m.b*180/Math.PI);
|
||||
document.getElementById('motor-c').textContent = fmt(m.c*180/Math.PI);
|
||||
|
||||
// Greifer-Motorwert (eMotor, abgeleitet aus e/b/c) — roh, wie motor-x.
|
||||
document.getElementById('motor-e').textContent = fmt(m.e);
|
||||
|
||||
})
|
||||
|
||||
@@ -40,19 +40,24 @@ class GCode{
|
||||
|
||||
|
||||
static getM114(robot){
|
||||
// position = Workspace (x/y/z in mm, a/b/c als Euler-Winkel phi/theta/psi in rad,
|
||||
// e = Greifer-Öffnung in mm).
|
||||
// motorCounts = die 7 Motor-Slots, inkl. e = eMotor (abgeleiteter Greifer-Motorwert,
|
||||
// NICHT die mm-Öffnung — die steht in position.e).
|
||||
let text = '{"position":{ "x":'+robot.x+
|
||||
', "y":'+robot.y+
|
||||
', "z":'+robot.z+
|
||||
', "a":' +robot.phi +
|
||||
', "b":' +robot.theta +
|
||||
', "c":' +robot.psi + '},' +
|
||||
', "c":' +robot.psi +
|
||||
', "e":' +(robot.e ?? 0) + '},' +
|
||||
'"motorCounts":{ "x":'+ robot.xMotor +
|
||||
', "y":'+ robot.alpha +
|
||||
', "z":'+ robot.beta +
|
||||
', "a":'+ robot.a +
|
||||
', "b":'+ robot.b +
|
||||
', "c":'+ robot.c +
|
||||
', "e":'+ (robot.e ?? 0) +
|
||||
', "e":'+ (robot.eMotor ?? 0) +
|
||||
'}}';
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -264,6 +264,21 @@ class RobotBase{
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Greifer-Öffnung (Workspace, `e` in mm) → Greifer-Motorwert (`eMotor`).
|
||||
*
|
||||
* Default: keine Kopplung (`eMotor = e`). Kinematiken, bei denen die Greifer-Sehne
|
||||
* mechanisch durchs Handgelenk läuft, überschreiben dies, um die Handgelenk-Winkel
|
||||
* herauszurechnen (siehe {@link Arm3SegmentLinearX}). Wird sowohl von
|
||||
* `calculateAngles3D()` als auch beim Setzen per G92/M92 genutzt — eine Quelle.
|
||||
*
|
||||
* @param {number} e Finger-Öffnung in mm (ab Null-Position)
|
||||
* @returns {number} zugehöriger Greifer-Motorwert
|
||||
*/
|
||||
gripperMotorFromOpening(e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rückwärts-Kinematik: Motorwinkel → Workspace-Koordinaten.
|
||||
*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* der Controller kennt nur strukturierte Befehle, keine rohen Textstrings.
|
||||
*/
|
||||
const GCodeParser = require('./GCodeParser');
|
||||
const { motorStateFromPorts } = require('./portInverse');
|
||||
const { motorStateFromPorts, D } = require('./portInverse');
|
||||
|
||||
class RobotController {
|
||||
|
||||
@@ -121,14 +121,31 @@ class RobotController {
|
||||
}
|
||||
|
||||
if (cmd === 'M92' || cmd === 'G92') {
|
||||
// Beide setzen die Motorposition ohne Bewegung, unterscheiden sich aber in den
|
||||
// Winkel-EINHEITEN:
|
||||
// G92 → GRAD (G-Code-Konvention für Rotationsachsen, wie FluidNC und die
|
||||
// "Position Motoren"-Anzeige in public/app.js). Intern sind die
|
||||
// Winkel-Slots in Radiant → Grad/D umrechnen (D = 180/π).
|
||||
// M92 → RADIANT, roh in die internen Slots (interne/Test-Variante).
|
||||
// X ist die lineare mm-Schiene, E die Greifer-Öffnung in mm (ab Null-Position
|
||||
// eines Fingers) — beide ohne Winkel-Umrechnung.
|
||||
const angScale = (cmd === 'G92') ? 1 / D : 1;
|
||||
robot.createMotorPosition();
|
||||
if (Number.isFinite(params.X)) { robot.xMotor = params.X; robot.xMotorChanged = true; }
|
||||
if (Number.isFinite(params.Y)) { robot.alpha = params.Y; robot.yMotorChanged = true; }
|
||||
if (Number.isFinite(params.Z)) { robot.beta = params.Z; robot.zMotorChanged = true; }
|
||||
if (Number.isFinite(params.A)) { robot.a = params.A; robot.aMotorChanged = true; }
|
||||
if (Number.isFinite(params.B)) { robot.b = params.B; robot.bMotorChanged = true; }
|
||||
if (Number.isFinite(params.C)) { robot.c = params.C; robot.cMotorChanged = true; }
|
||||
if (Number.isFinite(params.E)) { robot.e = params.E; robot.eMotorChanged = true; }
|
||||
if (Number.isFinite(params.Y)) { robot.alpha = params.Y * angScale; robot.yMotorChanged = true; }
|
||||
if (Number.isFinite(params.Z)) { robot.beta = params.Z * angScale; robot.zMotorChanged = true; }
|
||||
if (Number.isFinite(params.A)) { robot.a = params.A * angScale; robot.aMotorChanged = true; }
|
||||
if (Number.isFinite(params.B)) { robot.b = params.B * angScale; robot.bMotorChanged = true; }
|
||||
if (Number.isFinite(params.C)) { robot.c = params.C * angScale; robot.cMotorChanged = true; }
|
||||
// E nach B/C setzen: der Greifer-Motorwert hängt über die Kinematik-Kopplung
|
||||
// von b und c ab. robot.e = Finger-Öffnung (mm), eMotor = abgeleiteter Motorwert.
|
||||
// Ohne diese eMotor-Ableitung bliebe der Greiferwert stale (alte E-Inkonsistenz):
|
||||
// sendCommand() verschickt eMotor, nicht e.
|
||||
if (Number.isFinite(params.E)) {
|
||||
robot.e = params.E;
|
||||
robot.eMotor = robot.gripperMotorFromOpening(robot.e);
|
||||
robot.eMotorChanged = true;
|
||||
}
|
||||
|
||||
robot.calculatePositionFromMotorAngles();
|
||||
robot.sendCommand('G92');
|
||||
|
||||
@@ -95,7 +95,17 @@ class Arm3SegmentLinearX extends RobotBase {
|
||||
while(this.a > Math.PI){this.a -= 2*Math.PI}
|
||||
while(this.a < -Math.PI){this.a += 2*Math.PI}
|
||||
|
||||
this.eMotor = this.e - this.b - this.c;
|
||||
this.eMotor = this.gripperMotorFromOpening(this.e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Greifer-Kopplung dieses Arms: die Finger-Sehne läuft durchs Handgelenk, daher
|
||||
* ziehen Knick (`b`) und Dreh (`c`) am Greifer mit. `eMotor` kompensiert das, damit
|
||||
* die Finger-Öffnung `e` (mm, ab Null-Position eines Fingers) unabhängig von der
|
||||
* Handstellung bleibt. Einzige Quelle für diese Kopplung (auch via G92/M92 genutzt).
|
||||
*/
|
||||
gripperMotorFromOpening(e) {
|
||||
return e - this.b - this.c;
|
||||
}
|
||||
|
||||
calculatePositionFromMotorAngles(verbose = false) {
|
||||
|
||||
@@ -113,5 +113,22 @@ describe("Robot G92", () => {
|
||||
|
||||
// ("Wenn nur G92 x3 gegeben wird, dann wird trotzdem auch y und z gesendet. schlecht." );
|
||||
});
|
||||
|
||||
test("G92 E: Greifer-Öffnung (mm) → eMotor über Kopplung e - b - c", () => {
|
||||
const robot = new Robot(300, 300, 20);
|
||||
const D = 180 / Math.PI;
|
||||
|
||||
// B/C in Grad rein (→ intern Radiant), E in mm. eMotor muss aus e, b, c abgeleitet
|
||||
// werden — die Greifer-Sehne läuft durchs Handgelenk (Arm3SegmentLinearX-Kopplung).
|
||||
GCode.receiveGCode(robot, "G92 B30 C-45 E10");
|
||||
|
||||
expect(robot.b).toBeCloseTo(30 / D, 6); // 30° → rad
|
||||
expect(robot.c).toBeCloseTo(-45 / D, 6); // -45° → rad
|
||||
expect(robot.e).toBe(10); // mm, unverändert
|
||||
expect(robot.eMotor).toBeCloseTo(10 - robot.b - robot.c, 6); // = e - b - c
|
||||
|
||||
// Konsistenz: identische Kopplung wie der reguläre Bewegungspfad (calculateAngles3D).
|
||||
expect(robot.eMotor).toBeCloseTo(robot.gripperMotorFromOpening(robot.e), 12);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -204,7 +204,8 @@ describe('InfoServer', () => {
|
||||
const httpsOptions = { key, cert, passphrase: 'abcd' };
|
||||
|
||||
const sharedState = { connectedClients: [], lastCommands: [], lastPings: [] };
|
||||
const robot = { x: 10, y: 20, z: 30, phi: 0.1, theta: 0.2, psi: 0.3, xMotor: 0, alpha: 0, beta: 0, a: 0, b: 0, c: 0 };
|
||||
// e = Greifer-Öffnung (mm) → position.e; eMotor = Greifer-Motorwert → motorCounts.e.
|
||||
const robot = { x: 10, y: 20, z: 30, phi: 0.1, theta: 0.2, psi: 0.3, xMotor: 0, alpha: 0, beta: 0, a: 0, b: 0, c: 0, e: 2.5, eMotor: 7 };
|
||||
const senders = [];
|
||||
|
||||
server = createInfoServer(httpsOptions, sharedState, robot, GCode, senders);
|
||||
@@ -214,7 +215,8 @@ describe('InfoServer', () => {
|
||||
expect(statusCode).toBe(200);
|
||||
|
||||
const json = JSON.parse(body);
|
||||
expect(json.position).toEqual({ x: 10, y: 20, z: 30, a: 0.1, b: 0.2, c: 0.3 });
|
||||
expect(json.position).toEqual({ x: 10, y: 20, z: 30, a: 0.1, b: 0.2, c: 0.3, e: 2.5 });
|
||||
expect(json.motorCounts.e).toBe(7); // Motorwert (eMotor), nicht die mm-Öffnung
|
||||
});
|
||||
|
||||
test('returns 404 for unknown endpoints', async () => {
|
||||
|
||||
@@ -101,7 +101,7 @@ describe('InputWS API response routing', () => {
|
||||
a.send('M114');
|
||||
|
||||
const parsed = JSON.parse(await aReply);
|
||||
expect(parsed.position).toEqual({ x: 5, y: 6, z: 7, a: 0, b: 0, c: 0 });
|
||||
expect(parsed.position).toEqual({ x: 5, y: 6, z: 7, a: 0, b: 0, c: 0, e: 0 });
|
||||
expect(await bSilent).toBe(true);
|
||||
|
||||
a.close();
|
||||
@@ -123,8 +123,8 @@ describe('InputWS API response routing', () => {
|
||||
|
||||
const aParsed = JSON.parse(await aReply);
|
||||
const bParsed = JSON.parse(await bReply);
|
||||
expect(aParsed.position).toEqual({ x: 1, y: 2, z: 3, a: 0, b: 0, c: 0 });
|
||||
expect(bParsed.position).toEqual({ x: 1, y: 2, z: 3, a: 0, b: 0, c: 0 });
|
||||
expect(aParsed.position).toEqual({ x: 1, y: 2, z: 3, a: 0, b: 0, c: 0, e: 0 });
|
||||
expect(bParsed.position).toEqual({ x: 1, y: 2, z: 3, a: 0, b: 0, c: 0, e: 0 });
|
||||
expect(robot.sendCommand).toHaveBeenCalled();
|
||||
|
||||
a.close();
|
||||
|
||||
@@ -88,7 +88,7 @@ describe('InputWS', () => {
|
||||
|
||||
const message = await messagePromise;
|
||||
const parsed = JSON.parse(message);
|
||||
expect(parsed.position).toEqual({ x: 12, y: 34, z: 56, a: 1, b: 2, c: 3 });
|
||||
expect(parsed.position).toEqual({ x: 12, y: 34, z: 56, a: 1, b: 2, c: 3, e: 0 });
|
||||
expect(parsed.motorCounts).toBeDefined();
|
||||
|
||||
client.close();
|
||||
@@ -108,7 +108,7 @@ describe('InputWS', () => {
|
||||
|
||||
const message = await messagePromise;
|
||||
const parsed = JSON.parse(message);
|
||||
expect(parsed.position).toEqual({ x: 1, y: 2, z: 3, a: 0, b: 0, c: 0 });
|
||||
expect(parsed.position).toEqual({ x: 1, y: 2, z: 3, a: 0, b: 0, c: 0, e: 0 });
|
||||
expect(robot.sendCommand).toHaveBeenCalled();
|
||||
|
||||
client.close();
|
||||
|
||||
@@ -65,20 +65,38 @@ describe('RobotController (ToDo_6)', () => {
|
||||
expect(robot.sendCommand).toHaveBeenCalledWith('G92');
|
||||
});
|
||||
|
||||
test('applyCommand: G92 verhält sich identisch zu M92 (Bug 3)', () => {
|
||||
test('applyCommand: G92 interpretiert Winkel als Grad (→ rad), X bleibt mm', () => {
|
||||
const robot = createDummyRobot();
|
||||
robot.createMotorPosition = jest.fn();
|
||||
|
||||
// G92 nutzt die G-Code-Konvention (Grad). Intern landen die Winkel in Radiant,
|
||||
// X (lineare Schiene) bleibt unverändert in mm. Vgl. M92 oben (Roh-Radiant).
|
||||
RobotController.applyCommand(robot, { command: 'G92', params: { X: 5, Y: 0.5, A: 0.3 } });
|
||||
|
||||
const DEG2RAD = Math.PI / 180;
|
||||
expect(robot.createMotorPosition).toHaveBeenCalledTimes(1);
|
||||
expect(robot.xMotor).toBe(5);
|
||||
expect(robot.alpha).toBe(0.5);
|
||||
expect(robot.a).toBe(0.3);
|
||||
expect(robot.alpha).toBeCloseTo(0.5 * DEG2RAD, 10);
|
||||
expect(robot.a).toBeCloseTo(0.3 * DEG2RAD, 10);
|
||||
expect(robot.calculatePositionFromMotorAngles).toHaveBeenCalled();
|
||||
expect(robot.sendCommand).toHaveBeenCalledWith('G92');
|
||||
});
|
||||
|
||||
test('applyCommand: G92 E setzt Greifer-Öffnung (mm) und leitet eMotor ab', () => {
|
||||
const robot = createDummyRobot();
|
||||
robot.createMotorPosition = jest.fn();
|
||||
robot.b = 0.2; // Handgelenk-Knick
|
||||
robot.c = -0.5; // Hand-Dreher
|
||||
|
||||
// E ist mm (keine Grad/rad-Umrechnung). eMotor wird über die Greifer-Kopplung
|
||||
// aus e, b, c abgeleitet — sonst bliebe der an FluidNC gesendete Wert stale.
|
||||
RobotController.applyCommand(robot, { command: 'G92', params: { E: 10, B: 0.2 * (180 / Math.PI), C: -0.5 * (180 / Math.PI) } });
|
||||
|
||||
expect(robot.e).toBe(10);
|
||||
expect(robot.eMotor).toBeCloseTo(10 - robot.b - robot.c, 10); // = 10 - 0.2 - (-0.5) = 10.3
|
||||
expect(robot.sendCommand).toHaveBeenCalledWith('G92');
|
||||
});
|
||||
|
||||
test('applyCommand: ungültiger Befehl wird ignoriert', () => {
|
||||
const robot = createDummyRobot();
|
||||
RobotController.applyCommand(robot, null);
|
||||
|
||||
@@ -20,12 +20,17 @@ function createDummyRobot() {
|
||||
a: 0,
|
||||
b: 0,
|
||||
c: 0,
|
||||
eMotor: 0,
|
||||
|
||||
// Geometrie
|
||||
l1: 10,
|
||||
l2: 10,
|
||||
l3: 10,
|
||||
|
||||
// Greifer-Kopplung (RobotBase-Default: keine Kopplung). Konkrete Kinematiken
|
||||
// überschreiben dies; siehe Arm3SegmentLinearX.gripperMotorFromOpening.
|
||||
gripperMotorFromOpening(e) { return e - this.b - this.c; },
|
||||
|
||||
// Methoden → jest.fn erlaubt Call-Tracking
|
||||
calculateAngles3D: jest.fn(),
|
||||
calculatePositionFromMotorAngles: jest.fn(),
|
||||
|
||||
Reference in New Issue
Block a user