319 lines
13 KiB
Markdown
319 lines
13 KiB
Markdown
# Tutorial: p5-wallplotter
|
||
|
||
Dieses Tutorial erklärt, wie du das Repository lädst, den Beispiel-Sketch lokal startest, den Wandplotter per USB verbindest und was Marlin mit G-code eigentlich macht.
|
||
|
||
**Kurzüberblick:** Der Browser zeichnet mit p5.js. Die Library `WallPlotter.js` wandelt Linien in G-code um und schickt ihn über **Web Serial** an die Steuerung. Dort läuft **Marlin** mit Polargraph-Kinematik: Kartesische Koordinaten (`X`/`Y` in Millimetern) werden in zwei Riemenlängen übersetzt, die die Motoren auf- und abwickeln.
|
||
|
||
Voraussetzungen:
|
||
|
||
- **Chrome** oder **Edge** (Web Serial gibt es nicht in Firefox oder Safari)
|
||
- Python 3
|
||
- USB-Kabel zum Plotter
|
||
- Plotter mit Stromversorgung (Steuerung + Motoren)
|
||
|
||
Web Serial funktioniert **nicht** über `file://`. Die Seite muss von `http://localhost` oder über HTTPS kommen.
|
||
|
||
---
|
||
|
||
## 1. Repository herunterladen
|
||
|
||
Das Projekt liegt hier:
|
||
|
||
[https://git.collectivemedia.space/martin/p5-wallplotter](https://git.collectivemedia.space/martin/p5-wallplotter)
|
||
|
||
Auf der Projektseite **Code → Download ZIP** (oder direkt [archive/main.zip](https://git.collectivemedia.space/martin/p5-wallplotter/archive/main.zip)). Archiv entpacken und in den Ordner `p5-wallplotter` wechseln.
|
||
|
||
### Was im Ordner liegt
|
||
|
||
```
|
||
p5-wallplotter/
|
||
├── lib/
|
||
│ ├── WallPlotter.js # p5-Library: Serial, G-code, Preview, Tasten
|
||
│ ├── README.md # Kurzüberblick + Beispiel
|
||
│ └── doc.md # API-Referenz
|
||
├── examples/
|
||
│ ├── zickzack/ # Einstiegsbeispiel
|
||
│ └── rechteck/ # Rechteck zeichnen
|
||
├── hardware.md # Motoren, Board, Geometrie
|
||
├── gcode.md # G-code in diesem Setup
|
||
└── tutorial.md # diese Anleitung
|
||
```
|
||
|
||
Es gibt kein `npm install`. Der Sketch lädt p5.js vom CDN; der Rest sind statische Dateien.
|
||
|
||
---
|
||
|
||
## 2. Umgebung starten
|
||
|
||
Ziel: einen lokalen HTTP-Server im Projektordner, danach den Sketch in Chrome/Edge öffnen.
|
||
|
||
### Linux
|
||
|
||
Im Projektordner:
|
||
|
||
```bash
|
||
cd p5-wallplotter
|
||
python3 -m http.server 8080
|
||
```
|
||
|
||
Browser: [http://localhost:8080/examples/zickzack/](http://localhost:8080/examples/zickzack/)
|
||
|
||
Server mit `Ctrl+C` beenden.
|
||
|
||
Für den USB-Port braucht dein Benutzer die Serial-Gruppe. Nach der Änderung einmal ab- und anmelden:
|
||
|
||
```bash
|
||
# Debian / Ubuntu
|
||
sudo usermod -aG dialout "$USER"
|
||
|
||
# Arch / CachyOS
|
||
sudo usermod -aG uucp "$USER"
|
||
```
|
||
|
||
Prüfen, ob das Board erscheint (SKR Mini E3 V3 als USB-CDC):
|
||
|
||
```bash
|
||
ls /dev/ttyACM* /dev/ttyUSB*
|
||
```
|
||
|
||
### Windows
|
||
|
||
1. Python von [python.org](https://www.python.org/downloads/) installieren. Beim Setup **Add python.exe to PATH** aktivieren.
|
||
2. PowerShell oder Eingabeaufforderung im Projektordner:
|
||
|
||
```powershell
|
||
cd p5-wallplotter
|
||
py -m http.server 8080
|
||
```
|
||
|
||
Falls `py` unbekannt ist: `python -m http.server 8080`.
|
||
|
||
3. Chrome oder Edge: [http://localhost:8080/examples/zickzack/](http://localhost:8080/examples/zickzack/)
|
||
|
||
Das Board erscheint in der Geräte-Manager-Ansicht unter **Anschlüsse (COM & LPT)** als virtueller COM-Port. Web Serial zeigt denselben Port im Verbindungsdialog. Extra-Treiber sind bei der SKR Mini E3 V3 meist nicht nötig; wenn der Port fehlt, USB-Kabel wechseln (manche Kabel sind nur Ladekabel) und den STM32 Virtual COM Port / WinUSB-Pfad prüfen.
|
||
|
||
### macOS
|
||
|
||
Im Terminal:
|
||
|
||
```bash
|
||
cd p5-wallplotter
|
||
python3 -m http.server 8080
|
||
```
|
||
|
||
**Chrome** oder **Edge** öffnen (nicht Safari): [http://localhost:8080/examples/zickzack/](http://localhost:8080/examples/zickzack/)
|
||
|
||
Der Port heisst typischerweise `/dev/cu.usbmodem…`. macOS hält einen Serial-Port oft fest, wenn der Tab nicht sauber schliesst. Seite neu laden oder den Tab schliessen, bevor du erneut verbindest — die Library gibt den Port beim Schliessen frei.
|
||
|
||
Falls `python3` fehlt: `xcode-select --install` oder Python über Homebrew.
|
||
|
||
### Browser-Check
|
||
|
||
- Chrome oder Edge, aktuelle Version
|
||
- `chrome://flags` nicht nötig; Web Serial ist standardmässig an
|
||
- Beim ersten Verbinden erscheint ein Port-Picker — das ist gewollt (Browser-Sicherheitsmodell)
|
||
|
||
---
|
||
|
||
## 3. Plotter anschliessen
|
||
|
||
### Hardware-Reihenfolge
|
||
|
||
1. **Strom** an die Steuerung (SKR Mini E3 V3, typisch 24 V). Motoren brauchen die Versorgungsspannung; USB allein reicht nicht zum Fahren.
|
||
2. **USB** von der Steuerung zum Rechner (Datenkabel).
|
||
3. Gondel hängt an beiden Riemen, Stift sitzt im Halter, Papier/Wand ist frei.
|
||
4. Sketch im Browser öffnen (localhost, siehe oben).
|
||
5. **Connect** klicken oder Taste **C**.
|
||
6. Im Dialog den Serial-Port der Steuerung wählen.
|
||
|
||
### Home setzen (wichtig)
|
||
|
||
Marlin kennt nach dem Einschalten **keine** absolute Wand-Position. Du sagst ihm, wo „jetzt“ der Ursprung ist. Die Pfeiltasten funktionieren erst nach dem ersten Home:
|
||
|
||
1. Taste **H** — Home an der **aktuellen** Gondelposition (`G92 X0 Y0`).
|
||
2. Mit den Pfeiltasten (Stift oben) zur **Mitte des Blattes** fahren.
|
||
3. Nochmals **H** — das setzt den Ursprung auf die Blattmitte.
|
||
|
||
Ohne Home bleibt Plot gesperrt.
|
||
|
||
### Not-Aus
|
||
|
||
Diese Firmware hat keinen `EMERGENCY_PARSER`. Ein Stopp im Browser bricht nur das *weitere Senden* ab; die bereits laufende `G1`-Fahrt läuft weiter. Für einen harten Stopp: **Strom trennen**.
|
||
|
||
---
|
||
|
||
## 4. Der Plotter und seine Teile
|
||
|
||
Der Wandplotter ist ein **Polargraph**: eine Gondel hängt an zwei Riemen, die oben links und rechts über Motoren und Umlenkrollen laufen. Es gibt keine X/Y-Schienen. Position entsteht allein aus den beiden Riemenlängen.
|
||
|
||
Baugruppen, Anschlüsse und Geometrie: [hardware.md](hardware.md).
|
||
|
||
---
|
||
|
||
## 5. Was Marlin mit G-code macht
|
||
|
||
### G-code in einem Satz
|
||
|
||
G-code ist die Kommandosprache von CNC- und 3D-Druck-Steuerungen: eine Textzeile, ein Befehl. Der Host (hier der Browser) schreibt Zeilen auf die serielle Schnittstelle. Marlin parst sie, plant Bewegung oder I/O, und antwortet mit `ok`, wenn der Befehl angenommen ist.
|
||
|
||
Beispiel einer Fahrt mit Stift unten:
|
||
|
||
```gcode
|
||
M280 P0 S30 ; Servo 0 auf 30° → Stift aufs Papier
|
||
G1 X120 Y-40 F2500 ; Gerade zu (120, −40) mm mit 2500 mm/min
|
||
M400 ; warten, bis die Bewegung wirklich fertig ist
|
||
```
|
||
|
||
### Der Weg einer Linie
|
||
|
||
```
|
||
p5 sketch
|
||
wp.draw(x, y) → nur in eine Warteschlange legen
|
||
wp.runPath(false) → nacheinander senden
|
||
│
|
||
▼
|
||
USB Serial, 115200 Baud
|
||
│
|
||
▼
|
||
Marlin auf der SKR
|
||
1. Zeile lesen, parsen
|
||
2. G1: Ziel in mm merken
|
||
3. inverse Kinematik: (X, Y) → (linke Riemenlänge, rechte Riemenlänge)
|
||
4. Planner: Beschleunigung, Segmentierung
|
||
5. Stepper-ISR: X- und Y-Treiber takten
|
||
6. "ok" zurück an den Browser
|
||
│
|
||
▼
|
||
WallPlotter wartet auf ok, schickt M400, erst dann den nächsten Punkt
|
||
```
|
||
|
||
**Test** (`runPath(true)`) bleibt im Browser: gleiche Pfadliste, nur Animation. Es geht kein G-code raus.
|
||
|
||
### Inverse Kinematik (Polargraph)
|
||
|
||
Ein kartesischer Drucker fährt Schlitten auf Schienen. Der Polargraph fährt **Riemenlängen**. Marlin rechnet für jedes Ziel:
|
||
|
||
```
|
||
linke Länge = hypot( X − linke_Rolle , Y − Rollenlinie )
|
||
rechte Länge = hypot( rechte_Rolle − X , Y − Rollenlinie )
|
||
```
|
||
|
||
In der Firmware entspricht das `HYPOT` in `inverse_kinematics`: X-Stepper = linke Länge, Y-Stepper = rechte Länge. Eine waagerechte Linie auf der Wand ist für die Motoren **keine** gleichmässige Rotation — beide Motoren ändern die Länge gekoppelt. Marlin zerlegt die kartesische Gerade intern in kurze Segmente (`DEFAULT_SEGMENTS_PER_SECOND`), damit die Kurve der Riemelängen der Geraden auf der Wand folgt.
|
||
|
||
Deshalb muss Home zur realen Geometrie passen. Falsches `G92` (z. B. Ursprung zu weit unter den Rollen) erzeugt den typischen **Bogen nach oben** bzw. eine konische Zeichnung: Marlin glaubt, die Gondel sei woanders, als sie hängt.
|
||
|
||
Befehlsliste: [gcode.md](gcode.md).
|
||
|
||
### Was Marlin nicht ist
|
||
|
||
Marlin ist keine Zeichen-App. Es weiss nichts von p5 oder deinem Sketch. Es bekommt nur Koordinaten und Servo-Winkel. Pfadplanung, Stiftlogik und die Vorschau liegen in `WallPlotter.js`. Die Firmware ist der Bewegungscontroller: parsen, in Riemenlängen umrechnen, Schritte erzeugen, `ok` sagen.
|
||
|
||
---
|
||
|
||
## 6. Eigenen Sketch schreiben
|
||
|
||
Kopiere den Ordner `examples/zickzack/` und öffne darin `sketch.js`. Den Rest (HTML, Buttons, Verbinden) kannst du lassen. Du änderst nur `drawPlot`: dort steht, was gezeichnet wird.
|
||
|
||
Koordinaten sind **Millimeter**, Ursprung = Home, **Y nach oben**.
|
||
|
||
Fertiges Rechteck: [examples/rechteck/](examples/rechteck/). Im Browser `http://localhost:8080/examples/rechteck/` öffnen. Nach dem Speichern die Seite neu laden (`F5`).
|
||
|
||
### Was `sketch.js` macht
|
||
|
||
`setup()` läuft einmal beim Start:
|
||
|
||
- `createCanvas` — Zeichenfläche im Browser, so gross wie das Fenster
|
||
- `parent('sketch-host')` — Canvas in die HTML-Seite einhängen
|
||
- `new WallPlotter({ … })` — Verbindung zum Plotter. `penUpGcode` / `penDownGcode` sind die Servo-Winkel für Stift hoch und runter
|
||
- `setSpeed(3000, 1500)` — Tempo in mm/min: zuerst leer fahren (Travel), dann zeichnen (Draw)
|
||
- `enableKeyInputs()` — Tastatur: C, H, Pfeile, …
|
||
- `enablePlotButtons()` — Buttons Connect, Plot, Test, Abort
|
||
|
||
`draw()` läuft dauernd (p5-Schleife): Hintergrund und HUD (`showInfos`).
|
||
|
||
`plot()` und `test()` rufen dieselbe Zeichnung auf. `false` = G-code an den Plotter, `true` = nur Vorschau im Browser.
|
||
|
||
### Die Zeichnung: `drawPlot`
|
||
|
||
```javascript
|
||
async function drawPlot(testOnly) {
|
||
const s = 200; // halbe Seitenlänge: 200 mm → Quadrat 400 × 400 mm
|
||
wp.startPath(); // alte Linie löschen, neue Liste beginnen
|
||
wp.move(-s, -s); // Stift hoch, zur unteren linken Ecke (−200, −200)
|
||
wp.draw(s, -s); // Stift runter, nach rechts unten (200, −200)
|
||
wp.draw(s, s); // nach rechts oben (200, 200)
|
||
wp.draw(-s, s); // nach links oben (−200, 200)
|
||
wp.draw(-s, -s); // zurück zur ersten Ecke, Rechteck zu
|
||
wp.move(0, 0); // Stift hoch, zurück zur Blattmitte
|
||
await wp.runPath(testOnly); // Liste abarbeiten: Test oder Plot
|
||
}
|
||
```
|
||
|
||
`move` und `draw` fahren noch nicht. Sie merken sich nur Punkte. `runPath` arbeitet die Liste der Reihe nach ab.
|
||
|
||
| Aufruf | Stift | Wohin |
|
||
|--------|--------|--------|
|
||
| `wp.move(x, y)` | oben | hinfahren, keine Linie |
|
||
| `wp.draw(x, y)` | unten | Linie vom letzten Punkt hierhin |
|
||
| `wp.wait(ms)` | — | Pause |
|
||
| `wp.startPath()` | — | Liste leeren |
|
||
| `wp.runPath(true)` | — | Vorschau (Test) |
|
||
| `wp.runPath(false)` | — | wirklich plotten |
|
||
|
||
Mehr Befehle: [lib/doc.md](lib/doc.md).
|
||
|
||
---
|
||
|
||
## 7. Tasten, Buttons, HUD
|
||
|
||
| Taste | Aktion |
|
||
|-------|--------|
|
||
| **C** | Verbinden / trennen (Port-Dialog) |
|
||
| **H** | Hier ist Home (`G92 X0 Y0`) — zuerst an der Gondel, nach dem Joggen nochmals in der Blattmitte |
|
||
| **T** | Test (Vorschau) |
|
||
| **A** | Abort: Test auf Start zurück |
|
||
| **P** | Stift umschalten |
|
||
| **0** | Nach `(0, 0)` fahren (Pen-up) |
|
||
| **← → ↑ ↓** | Joggen, Stift oben |
|
||
| **Shift + Pfeile** | Joggen, Stift unten |
|
||
| **+** / **-** | Schrittweite 1–100 mm |
|
||
| **S** | Plot stoppen / pausieren |
|
||
|
||
Buttons: **Connect**, **Plot** (wird Pause / Resume), **Test** (wird Stop), **Abort**.
|
||
|
||
Das HUD (unten und als Overlay) zeigt Verbindung, Home, Position, Stift, Serial-Log. Das Log rechts unten kannst du markieren — nützlich, wenn Marlin nicht mit `ok` antwortet.
|
||
|
||
---
|
||
|
||
## 8. Fehlerbehebung
|
||
|
||
| Symptom | Was prüfen |
|
||
|---------|------------|
|
||
| Kein Port-Dialog, oder „Serial not supported“ | Chrome oder Edge, nicht Firefox/Safari. Seite über `http://localhost:…`, nicht als Datei öffnen. |
|
||
| Port erscheint nicht | Strom der Steuerung an? Daten-USB-Kabel? Linux: Gruppe `dialout` oder `uucp`, neu einloggen. `ls /dev/ttyACM*`. Windows: Geräte-Manager → COM-Port. macOS: Tab schliessen und neu öffnen (Port oft blockiert). |
|
||
| Connect, aber keine Bewegung | Netzteil an der SKR einstecken (typisch 24 V). USB allein speist die Motoren nicht. Dann **H** drücken. Linker Motor an Buchse **X**, rechter an **Y**. |
|
||
| „Home not set“ | Zuerst **H**, dann zur Blattmitte joggen, nochmals **H**.
|
||
| Stift bleibt oben oder kratzt | `penUpGcode` / `penDownGcode` an den Servo anpassen (`S`-Winkel). Mit **P** testen. |
|
||
| Zeichnung bogenförmig / konisch | Home falsch: Gondel 80 cm unter den Rollen, dann `G92 X0 Y0`. Rollenabstand 1660 mm. |
|
||
| Motoren heiss, Schritte verloren | `M906 X1000 Y1000`. Riemen nicht zu straff. Tempo senken. |
|
||
| Plot hängt bei „waiting for Marlin ok“ | USB wackelt, Board reset, oder lange `G1` ohne `ok`. **Resume** nach Timeout; sonst USB neu stecken und Home neu setzen. |
|
||
| Stop im Browser, Gondel fährt weiter | Normal: laufendes `G1` wird nicht abgebrochen. Strom weg für Not-Aus. |
|
||
| macOS verbindet nur einmal | Seite komplett schliessen, Port freigeben, erneut **C**. |
|
||
| Beispiel sieht alt aus nach einem Update | Browser-Cache: hart neu laden (`Ctrl+Shift+R`) oder `?v=` an `WallPlotter.js` in der HTML erhöhen. |
|
||
|
||
Serial-Log im HUD lesen: Marlin-Fehler stehen dort als Text, nicht als Browser-Alert.
|
||
|
||
---
|
||
|
||
## 9. Mini-Ablauf zum Merken
|
||
|
||
1. ZIP herunterladen und entpacken.
|
||
2. `python3 -m http.server 8080` (Windows: `py -m http.server 8080`).
|
||
3. Chrome/Edge: `http://localhost:8080/examples/zickzack/`.
|
||
4. Plotter mit Strom und USB verbinden.
|
||
5. **C** → Port wählen.
|
||
6. **H** (aktuelle Position), zur Blattmitte joggen, nochmals **H**.
|
||
7. **Test**, dann **Plot**.
|
||
|
||
API-Referenz: [lib/doc.md](lib/doc.md). G-code: [gcode.md](gcode.md).
|