# Strido — vollständige Dokumentation > Strido ist ein offener Vierbeiner-Roboter mit 12 Freiheitsgraden: druckbares CAD, geprüfte Montage, Teilekatalog und Shop, Elektronik und Verkabelung, ESP32-S3-Firmware, ROS 2, Simulation und Reinforcement Learning sowie ein Technik-Wiki. # KI-Assistent und Agenten {#ai-assistant-and-agents} > **Status:** Der Assistent antwortet über Cortex Keyring aus dieser Dokumentation (Englisch und Deutsch); dasselbe Wissen steht Coding-Agenten über einen MCP-Server, einen Agent Skill und `llms.txt` offen. Antworten sind generiert: Prüfen Sie Zahlen auf der verlinkten Seite, bevor Sie schneiden, crimpen oder Strom anlegen. ## Den Assistenten fragen {#ask-the-assistant} Die Leiste am unteren Rand jeder Seite ist der Assistent. | Aktion | So geht's | |---|---| | Öffnen | Auf die Leiste klicken oder `/` außerhalb eines Textfelds drücken (`Ctrl K` / `⌘ K` bleibt die Seitensuche) | | Fragen | Tippen und `Enter` drücken (`Shift Enter` für eine neue Zeile); er weiß, auf welcher Seite Sie sind | | Etwas zeigen | Screenshot oder Foto einfügen (`Ctrl V` / `⌘ V`), Bilder oder Textdateien auf die Seite ziehen oder die Büroklammer nutzen; ein langer eingefügter Text wird zum Anhang | | Offen halten | Anheften: Er wird beim Lesen zur Seitenleiste rechts; lösen, um ihn wieder schweben zu lassen | | Verkleinern | `Esc` oder die Einklapp-Schaltfläche reduziert ihn auf die kleine Leiste | | Unterhaltungen | Auf den Titel klicken für den Verlauf: neue beginnen (`Alt N`), wechseln, umbenennen oder löschen | | Stoppen | Die Stopp-Schaltfläche beendet eine Antwort; der bereits geschriebene Teil bleibt erhalten | Er durchsucht die Dokumentation, liest die nötigen Seiten und verlinkt sie in seiner Antwort; auf der deutschen Seite antwortet er auf Deutsch. Fotos Ihres Aufbaus sind willkommen: Er vergleicht sie mit den Montageschritten und der Verkabelungsliste. **Ihre Daten:** Unterhaltungen und Anhänge speichert der Assistenzdienst nur für Ihr Konto, bis Sie sie löschen. **Verfügbarkeit:** Der Assistent läuft über das Cortex-Keyring-Abonnement des Betreibers; zeigt die Leiste ein Schloss, ist er für Ihr Konto nicht verfügbar. ## Die Wissensbasis im eigenen Agenten nutzen {#use-the-knowledge-base-in-your-own-agent} Die Dokumentation ist für Sprachmodelle und Coding-Agenten in drei Formen veröffentlicht. ### MCP-Server {#mcp-server} Der MCP-Server ist `https://strido.cortex.a2olabs.com/mcp`. Agenten melden sich mit einem persönlichen Cortex-App-Token an (standardmäßig 90 Tage gültig): ```sh cortex --json api post /api/v1/apps/strido/tokens --data '{"label":"my agent"}' # prints {"id", "token": "cxu_...", "expiresAt"} export STRIDO_TOKEN=cxu_... # keep it out of files you share claude mcp add --transport http strido https://strido.cortex.a2olabs.com/mcp --header "Authorization: Bearer $STRIDO_TOKEN" ``` Codex: `[mcp_servers.strido]` mit `url = "https://strido.cortex.a2olabs.com/mcp"` und `bearer_token_env_var = "STRIDO_TOKEN"` in `~/.codex/config.toml` eintragen. Werkzeuge: | Werkzeug | Liefert | |---|---| | `search_docs` | die passendsten Abschnitte (Titel, Link, Ausschnitt), Englisch oder Deutsch | | `read_page` | eine ganze Seite oder einen Abschnitt als Markdown | | `list_pages` | die Seitenübersicht mit Links | | `search_parts` | Stücklistenzeilen mit Menge, Preis, Shop und Produktdaten | `cortex api delete /api/v1/apps/strido/tokens/` widerruft das Token. ### Agent Skill mit der vollständigen Dokumentation {#agent-skill-with-the-full-documentation} [Skill herunterladen (ZIP)](/downloads/strido-skill.zip) (oder mit dem Token: `curl -H "Authorization: Bearer $STRIDO_TOKEN" -o strido-skill.zip https://strido.cortex.a2olabs.com/api/agent/strido-skill.zip`) und in das Skill-Verzeichnis Ihres Agenten entpacken (Claude Code: `~/.claude/skills/`, Codex: `~/.agents/skills/`). Er enthält `strido/SKILL.md` und jede Seite auf Englisch und Deutsch unter `references/`, sodass ein Agent offline antworten kann; laden Sie ihn nach einem Release neu. ### llms.txt {#llms-txt} | Datei | Inhalt | |---|---| | [/llms.txt](/llms.txt) | Verzeichnis aller Seiten mit Link ([Deutsch](/de/llms.txt)) | | [/llms-full.txt](/llms-full.txt) | alle Seiten in einer Markdown-Datei ([Deutsch](/de/llms-full.txt)) | Die Seite braucht eine Cortex-Anmeldung: Menschen laden die Dateien im Browser herunter; Agenten nutzen den MCP-Server oder holen dieselben Dateien mit dem App-Token unter `/api/agent/` (`llms.txt`, `llms-full.txt`, `de/llms.txt`, `de/llms-full.txt`). --- # Architektur {#architecture} > **Status:** beschreibt das Repository im gebauten Zustand (0.2). Die Schichtregeln werden durch import-linter erzwungen (`make layers`). ## System {#system} ```mermaid flowchart TB subgraph Robot["Roboter"] PI["Raspberry Pi 5
ROS 2 Jazzy: Gait / Policy, mcu_bridge, LiDAR, Kamera"] <-->|"USB CDC · COBS + CRC16"| MCU["XIAO ESP32-S3 Firmware
200-Hz-Servoschleife · Watchdog · Not-Aus · Abschaltung"] MCU -->|I²C| PCA["PCA9685 → 12 Servos"] MCU -->|I²C| SENS["LSM6DSOX IMU · INA260"] MCU -->|SPI| LCD["2-Zoll-LCD-Gesicht"] end subgraph Dev["Entwicklungsrechner"] CAD["strido-cad
STEP → Teile → Baugruppe"] --> VER["strido-verify
Durchdringung · Bewegungsbereich · Passungen · Freigang · Sensoren · Elektronik"] CAD --> MOD["Modelle: URDF/xacro · MJCF · Meshes"] VER --> PUB["strido-publish
Druckpaket · Stückliste · Anleitung · Buch-PDF · Renderings · GLB"] MOD --> SIM["strido-sim
MuJoCo-Gehen · Gym-Umgebung · PPO"] MOD --> NTX["strido-ntx
NT-X-Katalog-Assets · serieller RobotPort"] PUB --> SITE["docs-site (VitePress, Englisch + Deutsch)
Teilekatalog · 3D-Ansicht · Anleitungen · KI-Leiste"] SITE --> AST["assistant
Chat-API · MCP · Cortex Keyring"] WS["strido-workspace
CLI · Hardware-MCP-Server"] --> VER end SIM -->|"policy.npz"| PI NTX -->|"gleiches MCU-Protokoll"| MCU CORE["strido-core
Geometrie · Beinkinematik · Gait · Protokoll · Policy-Laufzeit"] CORE -.-> PI CORE -.-> SIM CORE -.-> CAD CORE -.-> NTX ``` ## Aufbau des Repositorys {#repository-layout} | Pfad | Inhalt | Maßgebliche Quelle | |---|---|---| | `hardware/` | Versionierte Hardwaredaten: Kinematik, Gelenkgrenzen, Befestigungselemente, Stückliste, Elektronik, Toleranzen, Kontaktregeln, Montagekorrekturen; das Druckpaket (`print/`) | YAML-Quellen; `print/` und `joint_limits.yaml` werden generiert | | `packages/strido-core` | Laufzeitbibliothek des Roboters (nur numpy + pyserial): läuft auf dem Pi, in ROS 2, in der Simulation und im Tooling | Code | | `packages/strido-cad` | CAD-Pipeline: STEP-Registrierung, Kinematikextraktion, Strido-Teile (CadQuery), Herstellermodelle, Befestigungselemente, Posen, Code- und Modellgenerierung | Code + `hardware/` | | `packages/strido-verify` | Physische Verifikation: Durchdringung, Bewegungsbereich, Passungen und Toleranzen, Freigang in Bewegung, Sensorsichtfeld, Elektronik | Code + `hardware/verification/` | | `packages/strido-publish` | Stücklisten-Optimierer, Druckpaket, Montageanleitung, Katalog- & Buch-PDF, Renderings, Web-3D-Ansicht | Code | | `packages/strido-sim` | MuJoCo-Gehdemo, Gymnasium-Umgebung, PPO-Training/-Evaluierung | Code | | `packages/strido-ntx` | NT-X-Erweiterung: Katalog-Assets, Steh-Skill, serieller `RobotPort` | Code; Assets generiert | | `src/strido_workspace` | `strido`-CLI und der `strido-hardware`-MCP-Server | Code | | `firmware/strido_esp32s3` | PlatformIO-Firmware; `lib/strido_core` ist portabel und nativ getestet | Code; `geometry_generated.h` generiert | | `ros2/` | ROS-2-Pakete: Beschreibung (generiert), Bringup, Steuerung | Code | | `models/` | MuJoCo-Modelle (generiert) und veröffentlichte Policies | generiert | | `docs/`, `requirements/` | Kanonische Dokumentation; `docs/{bom,assembly,catalog,viewer,verification}` werden generiert | Markdown | | `docs-site/` | VitePress-Seite; `content/{docs,requirements,de,public/*}` sind synchronisierte Kopien (deutsche Seiten aus `i18n/` gerendert) | Seitencode | | `i18n/` | Deutsche Übersetzungskataloge, einer je veröffentlichter Seite und Datendatei (`i18n/README.md`) | Übersetzungen | | `assistant/` | Assistenzdienst hinter der KI-Leiste: Unterhaltungen, Doku-Suche, MCP-Server für Agenten | Code | | `skills/strido/` | Agent Skill für die Dokumentation (auch als ZIP mit jeder Seite) | Markdown | | `upstream/yertle/` | Unverändertes Yertle-Design und -Software von Upstream (Referenz) | Upstream | | `.harness/` | Engineering-Harness-Submodul (Agenten, Hooks, Prüfungen) | Upstream-Harness | ## Paketschichtung {#package-layering} ```mermaid flowchart TD WS["strido_workspace"] --> PUB["strido_publish"] --> VER["strido_verify"] --> CAD["strido_cad"] --> CORE["strido (core)"] SIM["strido_sim"] --> CORE NTX["strido_ntx"] --> CORE ``` Verträge (`pyproject.toml`, `[tool.importlinter]`): Der Kern importiert niemals Tooling; publish → verify → cad → core ist eine strikte Schichtreihenfolge; Simulation und NT-X-Adapter ziehen niemals den CAD-Stack nach (sie laufen dort, wo CadQuery nicht installiert ist). ## Datenfluss einer Hardwareänderung {#data-flow-of-a-hardware-change} ```mermaid sequenceDiagram participant Dev as Entwickler / Agent participant YAML as hardware/*.yaml · parts.py participant CAD as strido_cad participant VER as strido_verify participant PUB as strido_publish Dev->>YAML: Teil, Platzierung, Befestigungselement oder Grenze ändern Dev->>CAD: make cad (Kinematik, Grenzen, Bindungen, Modelle) CAD->>VER: make verify (Durchdringung, Bewegungsbereich, Passungen, Freigang, Sensoren) VER-->>Dev: Fehler → Geometrie korrigieren, niemals eine Regel lockern Dev->>PUB: make publish (Druckpaket, Stückliste, Anleitung, Renderings, 3D-Ansicht, Buch) PUB-->>Dev: make bom schlägt fehl, wenn ein CAD-Teil nicht käuflich ist ``` ## Schnittstellen {#interfaces} | Schnittstelle | Definition | Nutzer | |---|---|---| | MCU-Leitungsprotokoll | `packages/strido-core/src/strido/protocol.py` ⇄ `firmware/.../protocol.h` (COBS + CRC16, 12 × float32-Gelenksollwerte, 103-Byte-Zustandsnutzlast) | ROS 2 `mcu_bridge`, `strido-cli`, NT-X `StridoSerialPort` | | Gelenkkonvention | Go2-Namen und -Vorzeichen, Reihenfolge FL, FR, RL, RR × Hüfte/Oberschenkel/Unterschenkel | Firmware, ROS 2, MuJoCo, NT-X | | ROS-2-Topics | [Software](software.md) | teleop, Nav2, NT-X rosbridge | | NT-X | `RobotSpec` + MJCF + Skill (Katalog-Assets), `RobotPort` (Registry-Adapter `strido-serial`) | NT-X-Harness und Studio | | Hardwarewissen | `strido-hardware`-MCP-Tools / `strido`-CLI | Coding-Agenten, Menschen | --- # Montageanleitung {#assembly-manual} Generiert aus der verifizierten CAD-Baugruppe durch `strido_publish.manual`: Jedes im CAD modellierte gedruckte Teil, Kaufteil und Befestigungselement erscheint in genau einer Teilebox (Kabel werden in den Schritten gezeichnet, in denen sie verlegt werden; ihre Längen stehen in der [Zuschnittliste](../verification/wiring.md#cut-list), Verbrauchsmaterial im [Shop](../shop.md)). Die Bein-Schritte zeigen das linke Vorderbein; bauen Sie alle vier (Mengen gelten pro Bein). Hervorgehobene Teile sind im Schritt neu; Pfeile zeigen, wohin sie gehören. ## Schritt 0 – Bevor Sie beginnen {#step-0} * Drucken Sie jedes Teil der [Druckliste](../../hardware/print/print_list.md) (am einfachsten: das [Druckpaket](../print-kit.md) mit den fertigen Druckplatten). Entfernen Sie Stützen und Brims; prüfen Sie die Passung von Lagern (625ZZ, 633ZZ, 6805-2RS) und Gleitlagerbuchsen vor der Montage. * Verkabelung: Jedes Kabel ist in den Schritten gezeichnet, in denen es installiert wird; die Längen stehen in der [Zuschnittliste](../verification/wiring.md#cut-list) und die Baureihenfolge unter [Elektronik › Kabelbaum](../electronics.md#wiring-harness). Stellen Sie beide UBECs auf 6,0 V ein und messen Sie sie, bevor ein Servo angeschlossen wird. * **Zentrieren Sie alle 12 Servos**, bevor Sie ein Servohorn montieren. Aufbau auf der Werkbank: XIAO (geflasht mit `firmware/strido_esp32s3`) per USB am Computer, PCA9685 an I²C mit seinem OE-Pull-up, Servoversorgung aus einem UBEC mit 6,0 V (oder einem 6-V-Labornetzteil) an die roten/schwarzen Drähte des Servos, Signal an den PCA9685-Kanal, den er verwenden wird. Führen Sie `strido-cli --port center` aus (1500 µs auf jedem Kanal; funktioniert ohne den INA260 und bricht mit einem Fehler ab, wenn der Controller nicht ansteuert). Ein zentrierter Servo ist die Montagereferenz: Hüfte Bein senkrecht, Femur 45° nach hinten, Kniekurbel 35°. * Werkzeug: Innensechskantschlüssel 1,5 / 2,0 / 2,5 mm, Steckschlüssel 4,0 / 5,0 / 5,5 mm, Seitenschneider, Lötkolben und Lötzinn, Multimeter, Crimpzange für Dupont, mittelfeste Schraubensicherung für Schrauben in Metall-Servohörner. * Schrauben in gedruckte Löcher, die als *selbstschneidend* markiert sind: drehen, bis sie anliegen, nie mit vollem Drehmoment. Metall-Metall-Schrauben (Servohörner): ein Tropfen mittelfeste Schraubensicherung. ## Schritt 1 – Elektronikdeck vorbereiten {#step-1} ![Schritt 1](../../../docs/assembly/img/step_01.png)
1×Elektronikdeck (gedruckt)
1×LSM6DSOX-IMU
2×M2.5-Sechskantmutter (ISO 4032)
10×M2.5 × 5 Zylinderschraube mit Innensechskant (ISO 4762)
2×M2.5 × 6 Zylinderschraube mit Innensechskant (ISO 4762)
3×M2 × 5 Zylinderschraube mit Innensechskant (ISO 4762)
10×M2.5 × 6 Abstandsbolzen I-I (Messing)
3×M2 × 8 Abstandsbolzen I-I (Messing)
1. Drücken Sie die LSM6DSOX-IMU in ihre Tasche (Chipseite oben, STEMMA-Stecker nach hinten) und befestigen Sie sie mit zwei M2.5 × 6 Schrauben von oben und M2.5-Muttern darunter. 2. Befestigen Sie die Abstandsbolzen von unten mit M2.5 × 5 Schrauben: 8 Abstandsbolzen M2.5, 6 mm lang (Raspberry Pi 5 und PCA9685) und 2 weitere für den INA260. 3. Befestigen Sie 3 Abstandsbolzen M2, 8 mm lang, für den 5-V-Spannungsregler mit M2 × 5 Schrauben von unten. 4. Die Schraubenköpfe sitzen in den Senkungen unter dem Deck. Nicht zu fest anziehen: Das Deck ist in der Mitte 3 mm dick. ## Schritt 2 – Rahmen des Chassis {#step-2} ![Schritt 2](../../../docs/assembly/img/step_02.png)
2×Innerer Schulterrahmen (gedruckt)
2×Seitlicher Rumpfträger (gedruckt)
8×M3-Sechskantmutter (ISO 4032)
8×M3 × 10 Zylinderschraube mit Innensechskant (ISO 4762)
1. Schieben Sie das vorbereitete Deck in die Nuten beider seitlicher Rumpfträger. 2. Schließen Sie den Rahmen mit den beiden inneren Schulterrahmen: 8 × M3 × 10 Schrauben mit Sechskantmuttern (Mutterseite innen im Schacht). 3. Prüfen Sie, dass der Rahmen flach auf dem Tisch liegt und sich das Deck nicht bewegen kann. ## Schritt 3 – Hüftservos {#step-3} ![Schritt 3](../../../docs/assembly/img/step_03.png)
4×Servo SPT5435LV-180W
16×M3-Sechskantmutter (ISO 4032)
16×M3 × 10 Zylinderschraube mit Innensechskant (ISO 4762)
1. Zentrieren Sie alle zwölf Servos, bevor Sie ein Servohorn oder einen Servo montieren (siehe Schritt 0). 2. Setzen Sie die vier Hüftservos von der Schachtseite durch die inneren Schulterrahmen ein; die Abtriebswellen zeigen nach außen (vorderes Paar nach vorne, hinteres Paar nach hinten). 3. Befestigen Sie jeden Servo mit 4 × M3 × 10 Schrauben und Sechskantmuttern durch die Servolaschen (insgesamt 16). 4. Führen Sie die Servokabel in den Schacht, sie laufen später zum vorderen und hinteren Hohlraum. ## Schritt 4 – Hüftlager und Schulterrahmen {#step-4} ![Schritt 4](../../../docs/assembly/img/step_04.png)
1×Unterer Schulterrahmen vorne (gedruckt)
1×Unterer Schulterrahmen hinten (gedruckt)
2×Äußerer Schulterrahmen (gedruckt)
2×Oberer Schulterrahmen (gedruckt)
4×Kugellager 625ZZ
32×M3-Sechskantmutter (ISO 4032)
16×M3 × 10 Zylinderschraube mit Innensechskant (ISO 4762)
1. Drücken Sie zwei 625ZZ-Lager in jeden äußeren Schulterrahmen (insgesamt 4). 2. Montieren Sie äußere, obere und untere Schulterrahmen vorne und hinten mit 16 × M3 × 10 Schrauben und Sechskantmuttern. 3. Verwenden Sie die unteren Schulterrahmen von Strido: `lower_shoulder_frame_front` und `_rear` haben das zusätzliche Vorbohrloch für den Servobus-Halter. 4. Drücken Sie jetzt M3-Muttern in die Muttertaschen, solange sie erreichbar sind: 6 oben auf den oberen Schulterrahmen und 8 unter den unteren Schulterrahmen für die Schalenschrauben (Schritte 21 und 22) sowie 2 weitere oben auf den vorderen oberen Schulterrahmen für die Kamerabasis (Schritt 18). ## Schritt 5 – Servo-Strombus und Bewegungscontroller {#step-5} ![Schritt 5](../../../docs/assembly/img/step_05.png)
1×Servobus-Halter vorne (gedruckt)
1×Servobus-Halter hinten (gedruckt)
1×Seeed XIAO ESP32-S3
8×WAGO 221-415
2×M3 × 12 Zylinderschraube mit Innensechskant (ISO 4762)
1. Klipsen Sie vier WAGO-221-415-Klemmen in jeden Servobus-Halter. 2. Schrauben Sie jeden Halter mit einer M3 × 12 Schraube an seinen unteren Schulterrahmen (selbstschneidend in das gedruckte Vorbohrloch). 3. Setzen Sie den XIAO ESP32-S3 in den vorderen Hohlraum, USB-C zum Schacht (Schaumklebeband). ## Schritt 6 – Servo-UBECs {#step-6} ![Schritt 6](../../../docs/assembly/img/step_06.png)
2×Hobbywing UBEC-10A
1. Lassen Sie beide UBEC-Ausgangs-Jumper offen (6,0 V). Messen Sie 6,0 V, bevor ein Servo angeschlossen wird. 2. Kleben Sie je einen UBEC mit Schaumklebeband in jede Seitentasche neben dem Akkuschacht, hochkant auf der langen Kante, Leitungen zum Deck. ## Schritt 7 – Platinen auf dem Deck {#step-7} ![Schritt 7](../../../docs/assembly/img/step_07.png)
1×INA260-Power-Monitor
1×PCA9685-Servotreiber
1×Pololu D36V50F5 5-V-Spannungsregler
1×Pololu #2813 Tasterschalter
1×Raspberry Pi 5 + Active Cooler
10×M2.5 × 5 Zylinderschraube mit Innensechskant (ISO 4762)
3×M2 × 5 Zylinderschraube mit Innensechskant (ISO 4762)
1. Raspberry Pi 5 mit Active Cooler: Anschlüsse nach vorne, 4 × M2.5 × 5 Schrauben. 2. PCA9685: Löten Sie zuerst den 2,2-kΩ-OE-Pull-up (OE an VCC an der Stiftleiste, Verkabelung W20), montieren Sie ihn dann mit den Servo-Stiftleisten zur rechten Seite, 4 × M2.5 × 5 Schrauben. Lassen Sie seine V+-Klemme unbeschaltet. 3. INA260 (zuerst A0 brücken, Adresse 0x41): 2 × M2.5 × 5 Schrauben. Pololu D36V50F5: 3 × M2 × 5 Schrauben. 4. Pololu-Tasterschalter auf Schaumklebeband im rechten Seitenstreifen, seine zwei 5-mm-Schraubklemmen angelötet (VIN/GND und VOUT/GND). ## Schritt 8 – Bein-Servomodul (×4 Beine) {#step-8} ![Schritt 8](../../../docs/assembly/img/step_08.png)
1×Hüftlagerbolzen (gedruckt)
1×Linke Servohalterung (gedruckt) – nur Bein RR
1×Linke Servohalterung fl (gedruckt) – nur Bein FL
1×Rechte Servohalterung (gedruckt) – nur Bein RL
1×Rechte Servohalterung fr (gedruckt) – nur Bein FR
1×Obere Halteklammer der Servohalterung (gedruckt)
2×Servo SPT5435LV-180W
8×M3 × 10 Zylinderschraube mit Innensechskant (ISO 4762)
2×M3 × 20 Zylinderschraube mit Innensechskant (ISO 4762)
1. Bauen Sie ein Bein nach dem anderen; die Zeichnung zeigt das linke Vorderbein. Linkes Vorder- und rechtes Hinterbein verwenden die *linke* Servohalterung, rechtes Vorder- und linkes Hinterbein die *rechte*. Die Vorderbeine verwenden die Strido-Varianten `left_servo_mount_fl` / `right_servo_mount_fr` (zusätzliches Vorbohrloch für den Hüftdrehpunkt). 2. Montieren Sie den Oberschenkelservo und den Knieservo mit 8 × M3 × 10 Schrauben durch die Servolaschen in der Servohalterung und schließen Sie sie dann mit der oberen Halteklammer: 2 × M3 × 20 Schrauben. 3. Drücken Sie den Hüftlagerbolzen in die Halterung; das Hüft-Scheibenhorn wird in Schritt 13 montiert. ## Schritt 9 – Oberschenkel (×4 Beine) {#step-9} ![Schritt 9](../../../docs/assembly/img/step_09.png)
1×Femur (gedruckt)
1×Femur-Servoverbinder (gedruckt)
1×25T-Aluminium-Scheibenhorn
4×M3 × 20 Zylinderschraube mit Innensechskant (ISO 4762)
1×M3 × 8 Zylinderschraube mit Innensechskant (ISO 4762)
1. Befestigen Sie den Femur und den Femur-Servoverbinder mit 4 × M3 × 20 Schrauben an einem 25T-Aluminium-Scheibenhorn. 2. Stecken Sie bei zentriertem Oberschenkelservo das Servohorn so auf die Verzahnung, dass der Femur 45° nach hinten zeigt (Montagereferenz), und befestigen Sie es mit der M3 × 8 Zentralschraube. ## Schritt 10 – Kniekurbel (×4 Beine) {#step-10} ![Schritt 10](../../../docs/assembly/img/step_10.png)
1×Linke Schulter (gedruckt) – nur Beine FL, RL
1×Rechte Schulter (gedruckt) – nur Beine FR, RR
1×Kugellager 6805-2RS
1×25T-Aluminium-Armhorn
1×M3 × 8 Zylinderschraube mit Innensechskant (ISO 4762)
1. Drücken Sie das 6805-2RS-Lager in die Schulterkurbel (linke oder rechte Version je Bein) und setzen Sie sie über den Femur-Servoverbinder: Sie dreht sich frei um die Oberschenkelachse. 2. Stecken Sie bei zentriertem Knieservo das 25T-Aluminium-Armhorn bei 35° auf seine Verzahnung (Montagereferenz) und befestigen Sie es mit der M3 × 8 Zentralschraube. ## Schritt 11 – Unterschenkel (×4 Beine) {#step-11} ![Schritt 11](../../../docs/assembly/img/step_11.png)
1×Fuß-Distanzstück (gedruckt)
1×Innere Tibia (gedruckt)
1×Äußere Tibia (gedruckt)
2×Kugellager 633ZZ
3×M3-Sicherungsmutter (Nylonring) (DIN 985)
2×M3 × 10 Zylinderschraube mit Innensechskant (ISO 4762)
2×M3 × 12 Zylinderschraube mit Innensechskant (ISO 4762)
1×M3 × 20 Zylinderschraube mit Innensechskant (ISO 4762)
2×M3-Unterlegscheibe (ISO 7089)
1. Drücken Sie zwei 633ZZ-Lager in die Tibia-Hälften. 2. Verbinden Sie innere und äußere Tibia mit 2 × M3 × 12 Schrauben und Sicherungsmuttern; klemmen Sie das Fuß-Distanzstück mit der M3 × 20 Schraube und Sicherungsmutter. 3. Montieren Sie die Knieachse: 2 × M3 × 10 Schrauben mit Unterlegscheiben von beiden Seiten durch den Femur. ## Schritt 12 – Knie-Koppelgetriebe (×4 Beine) {#step-12} ![Schritt 12](../../../docs/assembly/img/step_12.png)
1×Kurze Koppel (gedruckt)
1×Steife lange Koppel (gedruckt)
4×Gleitlager 3×5×5 (Paar)
1×M3-Sicherungsmutter (Nylonring) (DIN 985)
1×M3 × 16 Zylinderschraube mit Innensechskant (ISO 4762)
3×M3 × 25 Zylinderschraube mit Innensechskant (ISO 4762)
1×M3-Unterlegscheibe (ISO 7089)
1. Drücken Sie zwei 3 × 5 × 5 Gleitlager in jedes Koppelauge (8 pro Bein). 2. Verbinden Sie die Koppeln wie gezeichnet: 2 × M3 × 25 Kurbelbolzen durch die Schulterkurbel, die M3 × 16 Schraube mit Unterlegscheibe am Armhorn und 1 × M3 × 25 mit Sicherungsmutter an der Tibia. 3. Ziehen Sie die Sicherungsmuttern nur an, bis das Gelenk spielfrei ist: Die Koppeln müssen unter ihrem Eigengewicht schwingen. ## Schritt 13 – Beine montieren {#step-13} ![Schritt 13](../../../docs/assembly/img/step_13.png)
4×25T-Aluminium-Scheibenhorn
4×M3 × 10 Zylinderschraube mit Innensechskant (ISO 4762)
12×M3 × 8 Zylinderschraube mit Innensechskant (ISO 4762)
4×M3-Unterlegscheibe (ISO 7089)
1. Befestigen Sie an jedem Beinmodul ein Scheibenhorn mit 2 × M3 × 8 Schrauben. 2. Stecken Sie bei zentriertem Hüftservo das Bein auf die Verzahnung des Hüftservos (Bein senkrecht) und befestigen Sie es mit der M3 × 8 Zentralschraube. 3. Setzen Sie die Hüftdrehpunktschraube (M3 × 10 mit Unterlegscheibe) durch das 625-Lager in den Hüftlagerbolzen. ## Schritt 14 – Stromeingang {#step-14} ![Schritt 14](../../../docs/assembly/img/step_14.png)
1×ATO-Sicherungshalter
1×XT60H Buchse
1. Schneiden Sie jeden Draht auf seine Länge laut Zuschnittliste zu ([Verkabelungsprüfung](../verification/wiring.md#cut-list)); abisolieren, verzinnen und jede Lötstelle mit Schrumpfschlauch versehen. 2. Akkueingang: Löten Sie W01 (14 AWG rot) und W04 (14 AWG schwarz) an eine XT60H mit Buchsenkontakten (prüfen Sie die Kontaktregel unter [Elektronik](../electronics.md#xt60-contact-rule-the-loop-key-must-never-fit-the-battery)) und legen Sie sie in die Tasche neben dem Akku unter dem Deck, Haube nach hinten. Schieben Sie Spiralschlauch über W01 (es ist ungesichert). 3. Masse-Sternpunkt daneben: Spleißen Sie W04 an die schwarzen Eingänge beider UBECs (14 AWG) und an die Logikmasse (18 AWG schwarz, weiter zum GND des Schalters). 4. Hauptsicherung: Kürzen Sie beide Leitungen eines 25-A-Inline-Halters auf 20 mm, spleißen Sie W01 an die eine und W02 an die andere, legen Sie den Halter auf den hinteren WAGO-Bus, die Leitungen durch die Öffnungen des inneren und äußeren Rahmens nach außen, und binden Sie ihn am oberen Schulterrahmen fest. Noch keine Sicherung einsetzen. 5. W02 und W03 (zu beiden roten UBEC-Eingängen, unter dem Deck gespleißt) enden hinter dem hinteren äußeren Rahmen: Sie werden in Schritt 19 an den Arming-Port gelötet. W09 (18 AWG rot, Logikversorgung) läuft von dort durch den hinteren Hohlraum und über das Deck zum VIN des Schalters; sein anderes Ende wartet auf den Logik-Sicherungshalter (Schritt 19). ## Schritt 15 – Servokabel und Servobus {#step-15} ![Schritt 15](../../../docs/assembly/img/step_15.png)
1. Servokabel von Oberschenkel und Knie: Binden Sie jedes an der markierten Stelle (nahe der Hüftachse) an seiner Servohalterungsplatte fest, lassen Sie die freie Schlaufe (vorne: 30 mm Oberschenkel, 32 mm Knie; hinten: 22 mm; sie nimmt die Hüftbewegung auf) und binden Sie es erneut am Schulterrahmen (Oberschenkel) oder am Bus-Halter (Knie) fest. 2. Klipsen Sie jedes WAGO-Paar vor dem Klemmen aus seinem Halter (die XIAO-Plattform blockiert die Hebel in Schacht 0). Lösen Sie am Kabelbinder die roten und braunen Drähte vom Servokabel, schneiden Sie sie auf die Länge laut Zuschnittliste, isolieren Sie 11 mm ab und klemmen Sie sie in das WAGO-Paar des Beins: Rot in die obere Klemme (V+), Braun in die untere (GND), Anschlüsse Hüfte 1, Oberschenkel 2, Knie 3; setzen Sie das Paar wieder ein. Die Servokabel der Hüfte teilen sich an der Öffnung des inneren Rahmens. 3. Schneiden Sie den orangen Signaldraht auf seine Länge laut Zuschnittliste (gemessen ab dem Kabelbinder), crimpen Sie einen Dupont-Buchsenkontakt, schieben Sie ihn in ein 1-poliges Gehäuse und stecken Sie es auf den PWM-Pin seines PCA9685-Kanals (Kanalbelegung unter [Elektronik](../electronics.md#pin-maps)). 4. UBEC-Ausgänge (W05 vorne, W06 hinten): mit 18 AWG verlängern in Anschluss 0 von Schacht 0. Brücken W07/W08: 18 AWG von Anschluss 4 in Schacht 0 zu Anschluss 0 in Schacht 1, V+ und GND getrennt entlang der WAGO-Stirnseiten. ## Schritt 16 – Logik- und Signalverkabelung {#step-16} ![Schritt 16](../../../docs/assembly/img/step_16.png)
1. 18 AWG: Schalter VOUT an INA260 VIN+ (W10, rot), INA260 VIN- an den VIN des Spannungsreglers (W11, rot), Schalter GND an den GND des Spannungsreglers (W24, schwarz; die Schraubklemme des INA260 nimmt nur VIN+ und VIN- auf). 2. W12: vier 22-AWG-Drähte vom VOUT/GND des Spannungsreglers, Dupont-Crimpkontakte am Pi-Ende. Lassen Sie sie abgesteckt: Sie kommen erst nach der Versorgungsprüfung in Schritt 20 auf die Pi-Stiftleiste. 3. I²C: W17 (3V3, GND, SDA, SCL) und W20 (D3 an OE) sind 22-AWG-Drähte, an die XIAO-Pins gelötet und für die linke PCA9685-Stiftleiste gecrimpt (Dupont). STEMMA-QT-Kabel: rechte PCA9685-Stiftleiste zur IMU (W18), IMU zum INA260-Anschluss (W19). 4. USB: unterer Pi-Anschluss zum XIAO (W14, Überlänge falten und im vorderen Hohlraum festbinden). Optional W22: Pi GPIO 26 an das OFF-Pad des Schalters (22 AWG, Dupont-Crimpkontakt am Pi, am Schalter gelötet). ## Schritt 17 – Frontdisplay {#step-17} ![Schritt 17](../../../docs/assembly/img/step_17.png)
1×Displayhalter (gedruckt)
1×Frontschale Display (gedruckt)
1×Waveshare 2"-LCD (ST7789)
4×M2 × 5 Zylinderschraube mit Innensechskant (ISO 4762)
2×M3 × 10 Zylinderschraube mit Innensechskant (ISO 4762)
1. Setzen Sie das 2-Zoll-LCD von innen in das Fenster der Frontschale, Bildschirm nach außen, Stiftleiste nach unten. 2. Befestigen Sie den Halter mit 4 × M2 × 5 Schrauben an den Sechskantbolzen des LCD und dann mit 2 × M3 × 10 (selbstschneidend) an den Domen der Schale. 3. Stecken Sie das Displaykabel (W21, beim LCD mitgeliefert) in das Display, führen Sie es durch die Öffnung des äußeren Schulterrahmens und löten Sie seine 8 Drähte an die XIAO-Pins (kein Platz für Dupont-Gehäuse unter dem oberen Schulterrahmen); falten Sie die Überlänge (Zuschnittliste) und binden Sie sie an der Öffnung fest. ## Schritt 18 – Frontkamera {#step-18} ![Schritt 18](../../../docs/assembly/img/step_18.png)
1×Kamerahalter-Basis (gedruckt)
1×Kamera-Neigeplatte (gedruckt)
1×Camera Module 3 Wide
1×M3-Sicherungsmutter (Nylonring) (DIN 985)
4×M2-Sechskantmutter (ISO 4032)
4×M2 × 10 Zylinderschraube mit Innensechskant (ISO 4762)
2×M3 × 12 Zylinderschraube mit Innensechskant (ISO 4762)
1×M3 × 40 Zylinderschraube mit Innensechskant (ISO 4762)
1. Befestigen Sie das Camera Module 3 Wide an der Neigeplatte: 4 × M2 × 10 Schrauben, M2-Muttern hinter der Platte. 2. Hängen Sie die Neigeplatte mit der M3 × 40 Drehpunktschraube und einer Sicherungsmutter zwischen die Wangen der Basis; ziehen Sie an, bis die Kamera ihren Winkel hält (15° nach unten ist die Referenz). 3. Stecken Sie das 300-mm-Kamera-Flachbandkabel (W16) in CAM/DISP 0 des Pi, führen Sie es durch beide Öffnungen der Schulterrahmen und durch den Schlitz der Frontschale nach oben zur Kamera; falten Sie die Überlänge flach (ohne Knicke). Setzen Sie dann die Frontschale auf und schrauben Sie Kamerabasis und Schale mit 2 × M3 × 12 an den oberen Schulterrahmen. ## Schritt 19 – Rückwand {#step-19} ![Schritt 19](../../../docs/assembly/img/step_19.png)
1×Blende des Arming-Ports (gedruckt)
1×Ring des Arming-Ports (gedruckt)
1×Rückschale Taster (gedruckt)
1×ATO-Sicherungshalter
1×12-mm-Drucktaster
1×XT60H Buchse
2×M2.5 × 6 Zylinderschraube mit Innensechskant (ISO 4762)
1. Montieren Sie den 12-mm-Einschalttaster im kleinen Loch der Rückschale und löten Sie W13 an (22-AWG-Paar, zu den A/B-Pads des Schalters geführt). 2. Setzen Sie den XT60-Arming-Port von außen in die gedruckte Blende und klemmen Sie ihn von innen mit dem Ring: 2 × M2.5 × 6. 3. Löten Sie W02 und W03 an die beiden Kontakte des Arming-Ports. Logiksicherung: Kürzen Sie die Eingangsleitung eines zweiten Inline-Halters auf ihre Zuschnittlänge und spleißen Sie sie an W02 (Schrumpfschlauch); kürzen Sie die Ausgangsleitung auf 20 mm und spleißen Sie W09 daran. Legen Sie den Halter in der Schale zwischen Buchse und Taster ab. Noch keine Sicherung einsetzen. 4. Setzen Sie die Rückschale auf. Der Loop-Key bleibt bis zum ersten Einschalten (letzter Schritt) draußen. ## Schritt 20 – Kabelbaum ordnen und Logikversorgung prüfen {#step-20} ![Schritt 20](../../../docs/assembly/img/step_20.png)
2×Selbstklebender Kabelbinder-Sockel 13 × 13 mm
1. Versorgungsprüfung, bevor der Pi angeschlossen wird: Stecken Sie kurz einen geladenen Akkupack an den Akkueingang (W00), setzen Sie beide Sicherungen ein, Loop-Key draußen, drücken Sie den Taster und messen Sie 4,8–5,2 V an den Dupont-Enden von W12 (D36V50F5: 5 V ± 4 %). Drücken Sie erneut, ziehen Sie die Sicherungen, stecken Sie den Akkupack ab. Stecken Sie dann W12 auf die Pi-Pins 2/4 (5 V) und 6/14 (GND). 2. Umwickeln Sie jedes Bündel aus drei oder mehr Kabeln sowie W01 dort mit Spiralschlauch, wo die Zeichnung eine Hülle zeigt; er schützt die Leitungen, wo sie an Rahmen und beweglichen Teilen vorbeiführen. 3. Binden Sie an jeder markierten Stelle fest (Kabelbinder 2,5 × 100 mm, bündig abschneiden); zwei selbstklebende Kabelbinder-Sockel auf dem Deck tragen die Bündel in den Seitenstreifen. 4. Bewegen Sie jedes Bein von Hand durch seinen vollen Bewegungsbereich: Kein Kabel darf straff gezogen, eingeklemmt werden oder ein Servohorn oder eine Koppel berühren ([Verkabelungsprüfung](../verification/wiring.md)). ## Schritt 21 – Oberschale und LiDAR {#step-21} ![Schritt 21](../../../docs/assembly/img/step_21.png)
1×LiDAR-Sockel (gedruckt)
1×Oberschale Sensor (gedruckt)
1×RPLIDAR C1
1×RPLIDAR-USB-Adapter
4×M2.5 × 6 Zylinderschraube mit Innensechskant (ISO 4762)
4×M3 × 12 Zylinderschraube mit Innensechskant (ISO 4762)
6×M3 × 8 Zylinderschraube mit Innensechskant (ISO 4762)
1. Schrauben Sie den LiDAR-Sockel von unten an die Oberschale: 4 × M3 × 12 (selbstschneidend). 2. Setzen Sie den LiDAR-USB-Adapter in den Sockel, hinter den Kabelschlitz, USB-Ende zum Schlitz (Schaumklebeband). Führen Sie das eigene Kabel des LiDAR (W23) durch die Kerbe vorne am Sockel in den Adapter und befestigen Sie dann den RPLIDAR C1 mit 4 × M2.5 × 6 (max. 4 mm in den LiDAR). 3. Stecken Sie das zweite USB-Kabel (W15, vom oberen USB-Anschluss des Pi, über den Pi neben dem Kühlerlüfter geführt) durch den Schlitz der Oberschale in den Adapter und schließen Sie dann die Oberschale über Front- und Rückschale: 6 × M3 × 8 in die in Schritt 4 eingesetzten Muttern. ## Schritt 22 – Akku und Unterschale {#step-22} ![Schritt 22](../../../docs/assembly/img/step_22.png)
1×Unterschale (gedruckt)
1×LiPo 2S 5000 mAh
8×M3 × 8 Zylinderschraube mit Innensechskant (ISO 4762)
1. Schnallen Sie den 2S-LiPo unter das Deck (Klettband), Leitungsende nach hinten. 2. Stecken Sie die eigene Leitung des Akkupacks (W00) in die XT60H des Akkueingangs in der Tasche neben dem Akku (die Leitung biegt entlang der linken Seite unter dem hinteren Hüftservo nach vorne ab). Lassen Sie den Loop-Key draußen. 3. Schließen Sie die Unterschale: 8 × M3 × 8 Schrauben in die in Schritt 4 eingesetzten Muttern. ## Schritt 23 – Verkabelung, Kalibrierung und erstes Einschalten {#step-23} 1. Prüfen Sie den Kabelbaum anhand von [Elektronik › Kabelbaum](../electronics.md#wiring-harness) (W00–W23, Servokabel S-*): jede Verbindung gelötet und mit Schrumpfschlauch versehen, keine Litzen außerhalb einer WAGO-Klemme oder Schraubklemme. Lassen Sie die Sicherungen und den Loop-Key draußen. 2. Sicherungen einsetzen, Einschalttaster drücken: Der Pi bootet, das Gesicht erscheint auf dem LCD, `ros2 topic echo /battery_state` zeigt die Akkuspannung. Die Servos bleiben schlaff: Der Controller hält die PCA9685-Ausgänge aus, bis er Positionsbefehle erhält. 3. Kalibrieren Sie jedes Gelenk fein mit `strido-cli calibrate` (Roboter auf einem Ständer, Beine frei; Offsets im Flash des ESP32 gespeichert). 4. Legen Sie den Roboter mit eingeklappten Beinen auf den Bauch (die Ruhepose), stecken Sie den Loop-Key ein (Servos bleiben schlaff) und starten Sie dann `ros2 launch strido_bringup robot.launch.py`: Die Servos fahren in die Ruhepose, und der Roboter steht innerhalb von 3 s auf. Stecken Sie den Loop-Key nie ein, während Positionsbefehle laufen: Alle 12 Servos würden gleichzeitig springen (bis zu 6 × 3,5 A Blockierstrom pro Hohlraum gegenüber 15 A Spitzenwert eines UBEC). 5. Fernsteuern: `ros2 run teleop_twist_keyboard teleop_twist_keyboard`. Veröffentlichen Sie `true` auf `/strido/estop`, um zu stoppen. Starten Sie nach dem Lösen eines Not-Halts oder einer Entspannung den Launch mit dem Roboter in der Ruhepose liegend neu: Der Gait-Node fährt nur beim Start hoch. --- # Stückliste {#bill-of-materials} Generiert von `strido_publish.bom` aus `hardware/bom.yaml` und der CAD-Baugruppe. Preise: EUR inkl. MwSt., erhoben am 2026-10-30 (jeweils günstigstes Angebot; alle Angebote und Bündel in [shopping_list.md](shopping_list.md); Recherchenotizen in [sources.md](sources.md)). Gedruckte Teile: [hardware/print/print_list.md](../../hardware/print/print_list.md). ## Rechner und Sensoren {#compute-and-sensors} | Anz. | Artikel | Günstigstes Angebot | Preis | Hinweis | |---|---|---|---|---| | 1 | Raspberry Pi 5, 4 GB | DigiKey.at SC1431 (2648-SC1431-ND) | 117,18 € | | | 1 | Raspberry Pi Active Cooler | Welectron (DE) SC1148 | 4,90 € | | | 1 | microSD 64 GB A2 (SanDisk Extreme) | Berrybase.at SanDisk Extreme A2 64GB | 25,90 € | | | 1 | Raspberry Pi Camera Module 3 Wide | Welectron (DE) Camera Module 3 Wide | 35,90 € | | | 1 | Pi-5-Kamerakabel 22→15 Pin, 300 mm | DigiKey.at SC1129 | 2,14 € | | | 1 | Seeed XIAO ESP32-S3, Stiftleisten vorgelötet | DigiKey.at 102010634 | 9,05 € | | | 1 | PCA9685 16-Kanal-PWM-Platine (Adafruit-815-Layout) | Amazon.de B06XSFFXQY | 6,95 € | Klone müssen den Adafruit-815-Footprint haben (62,5 x 25,4 mm, 4 Eckbohrungen); Klon/Drittanbieter | | 1 | Adafruit LSM6DSOX 6-DoF-IMU (4438) | DigiKey.at Adafruit 4438 | 12,73 € | | | 1 | Adafruit INA260 Power-Monitor (4226) | DigiKey.at Adafruit 4226 | 10,60 € | | | 1 | Waveshare 2"-LCD-Modul, ST7789, 240x320 (17344) | Welectron (DE) 17344 | 10,90 € | | | 1 | Slamtec RPLIDAR C1 (mit USB-Adapter) | Amazon.de B0CP8YRY44 (WayPonDEV) | 70,58 € | | | 2 | STEMMA-QT-Kabel auf Buchsen, 150 mm (Adafruit 4397; IMU zu PCA9685 und IMU zu INA260) | DigiKey.at Adafruit 4397 | 2,02 € | | | 1 | Widerstand 2,2 kΩ 0,25 W (PCA9685-OE-Pull-up) | Reichelt.at METALL 2,20K | 0,10 € | Preis nicht verifiziert | | | **Zwischensumme** | | **308,95 €** | | ## Antrieb und Mechanik {#actuation-and-mechanics} | Anz. | Artikel | Günstigstes Angebot | Preis | Hinweis | |---|---|---|---|---| | 13 | Servo SPT5435LV-180W, 35 kg·cm, 180° (12 + 1 Reserve) | AliExpress (DigitalServo Store) 4000135787995, Variante 35kg-180 Waterproof | 174,98 € | muss die 180°-Variante sein (500-2500 µs = 180°); Winkel bei jedem Nicht-SPT-Verkäufer bestätigen lassen | | 8 | 25T-Aluminium-Scheibenhorn | Amazon.de B07F71J1Q2 (DollaTek, 5er-Pack) (Packungen zu 5) | 10,06 € | Klon/Drittanbieter | | 4 | 25T-Aluminium-Klemmarmhorn | Amazon.de B0F5QG8HQS (5er-Pack) (Packungen zu 5) | 9,06 € | Klon/Drittanbieter | | 4 | Kugellager 625ZZ (5x16x5) | kugellager-express.de 625-ZZ | 3,52 € | | | 4 | Kugellager 6805-2RS (25x37x7) | kugellager-express.de 6805/61805-2RS | 6,80 € | | | 8 | Kugellager 633ZZ (3x13x5) | Amazon.de B0GGT3GW69 (8er-Pack) (Packungen zu 8) | 10,27 € | | | 32 | Sinterbronze-Gleitlager 3x5x5 | Amazon.de B0G15L264D (50er-Pack) (Packungen zu 50) | 10,27 € | | | | **Zwischensumme** | | **224,96 €** | | ## Stromversorgung {#power} | Anz. | Artikel | Günstigstes Angebot | Preis | Hinweis | |---|---|---|---|---| | 2 | Hobbywing UBEC-10A (V2-Car), 6,0 V | Lindinger.at HW30603003 | 53,98 € | | | 1 | LiPo 2S 5000 mAh Hardcase, XT60, max. 138 x 47 x 25 mm (Gens ace G-Tech) | Amazon.de B0GKP683YF | 22,18 € | | | 1 | LiPo-Balance-Ladegerät, AC-Eingang (Klasse B6AC) | Amazon.de B0F3CYZ6L8 (HTRC B6AC) | 46,38 € | | | 1 | LiPo-Sicherheitstasche | Lindinger.at Robbe 23x30 cm (9787514) | 6,49 € | | | 1 | LiPo-Zellenprüfer / Unterspannungsalarm | Lindinger.at Absima (9771616) | 5,95 € | | | 1 | Pololu D36V50F5 5 V 5,5 A Abwärtsregler | Eckstein (DE) D36V50F5 | 41,59 € | | | 1 | Pololu #2813 Big Pushbutton Power Switch HP | DigiKey.at Pololu 2813 (Marketplace) | 10,80 € | | | 1 | 12-mm-Taster, tastend, Edelstahl (ONPOW GQ12B-10S) | Reichelt.at 318555 | 5,66 € | | | 1 | XT60H-Steckverbinder, 3 Paare (Akkuleitung, Arming-Port, Loop-Key) | Lindinger.at Robbe XT60 3 pairs (9750234) | 4,99 € | | | 2 | Inline-ATO-Sicherungshalter, 14-AWG-Leitungen (Haupt- + Logikzweig) | Amazon.de B07426WCLM (Nilight, 10 Halter) (Packungen zu 10) | 8,56 € | Klon/Drittanbieter | | 3 | ATO-Flachsicherung 25 A (Haupt, 1 + 2 Reserve) | Reichelt.at 7786 | 1,08 € | | | 2 | ATO-Flachsicherung 7,5 A (Logikzweig, 1 + 1 Reserve) | Reichelt.at FKS 7.5 A (gleiche Serie wie 7786) | 0,72 € | Preis ungefähr | | 8 | WAGO 221-415 Hebelklemme | Reichelt.at 149800 | 6,48 € | | | | **Zwischensumme** | | **214,86 €** | | ## Verkabelung {#wiring} | Anz. | Artikel | Günstigstes Angebot | Preis | Hinweis | |---|---|---|---|---| | 1 | Silikonlitze 14 AWG / 2,5 mm², rot + schwarz, je 1 m | Lindinger.at 20479 | 4,99 € | | | 2 | Silikonlitze 18 AWG / 0,75 mm², rot + schwarz (je 1 m pro Einheit) | Lindinger.at 44422 | 5,98 € | | | 1 | Silikonlitze 22 AWG (Pi-5-V-Einspeisung mit Dupont-Crimps, Taster, Brücken) | Amazon.de B0C7T9KYND (6 Farben x 4 m) | 12,10 € | | | 2 | USB-A-auf-USB-C-Kabel, 20 cm, 90° (Pi → XIAO, Pi → LiDAR-Adapter) | Amazon.de B09ZDV7S44 (aceyoon 20 cm 90°, 3er-Pack) (Packungen zu 3) | 7,64 € | | | 1 | Dupont-Jumper-Set 20 cm (F-F, M-M, F-M) | Berrybase.at DUPK-SET-20 | 4,90 € | | | 1 | Schrumpfschlauch-Sortiment | Reichelt.at 152924 | 5,39 € | | | 1 | Kabelbinder 100 x 2,5 mm (100) | Berrybase.at E-E510 | 0,90 € | | | 1 | Spiralschlauch, schwarzes PE, für Bündel 4-10 mm (5-10 m) | Reichelt.at CIMCO 186220 (10 m, Bündel 4-20 mm) | 4,84 € | | | 2 | Selbstklebender Kabelbinder-Sockel 13 x 13 mm (HellermannTyton MB2APT-A) | Reichelt.at HT 151-02243 (pro Stück) | 2,12 € | | | 1 | Dupont-2,54-mm-Crimpkontakte und -Gehäuse (1-6 Pin) für die abgelängten Signalleitungen | Amazon.de B0FP14VDGS (620 Stück) | 9,06 € | | | 1 | Lötdraht, bleifrei, 0,8 mm, Flussmittelseele (50-100 g) | Reichelt.at Goobay 420259 (50 g, SAC) | 13,61 € | | | 1 | Klettbänder (Akkugurt) | Reichelt.at 280182 | 5,14 € | | | 1 | Doppelseitiges Schaum-Montageband, 19 mm | Reichelt.at tesa PRO Universal 338987 | 9,98 € | | | | **Zwischensumme** | | **86,65 €** | | ## Befestigungselemente {#fasteners} | Anz. | Artikel | Günstigstes Angebot | Preis | Hinweis | |---|---|---|---|---| | 1 | M3-Zylinderkopfschrauben-Set, Edelstahl (6-50 mm, Muttern, Unterlegscheiben; WZHUIDA 1080 Stk.) | Amazon.de B0D2VST57H | 17,14 € | | | 100 | M3 x 10 DIN 912 A2 | Schraubenking.at M3x10 DIN912 A2, 100 (Packungen zu 100) | 2,35 € | Preis ungefähr | | 10 | M3 x 20 DIN 912 A2 | Schraubenking.at M3x20 DIN912 A2, 10 (Packungen zu 10) | 0,97 € | Preis ungefähr | | 25 | M3 DIN 985 Nylon-Sicherungsmutter | Schraubenking.at P000461 (verzinkt) (Packungen zu 100) | 1,39 € | | | 22 | M2.5 x 5 DIN 912 A2 | Schraubenking.at P004986 (Packungen zu 10) | 2,49 € | | | 10 | M2.5 x 6 DIN 912 A2 | Schraubenking.at P005010 (Packungen zu 10) | 0,83 € | | | 12 | M2 x 5 DIN 912 A2 | Schraubenking.at P003957 (Packungen zu 10) | 1,72 € | | | 6 | M2 x 10 DIN 912 A2 | Schraubenking.at P002803 (Packungen zu 10) | 0,78 € | | | 6 | M2-Sechskantmutter DIN 934 A2 | Schraubenking.at P002807 (Packungen zu 100) | 1,87 € | | | 4 | M2.5-Sechskantmutter DIN 934 A2 | Schraubenking.at P004196 (Packungen zu 100) | 2,00 € | Preis nicht verifiziert | | 12 | Abstandsbolzen M2.5 x 6 mm Innen-Innen (Würth 970060151) | DigiKey.at 970060151 | 6,62 € | | | 5 | Abstandsbolzen M2 x 8 mm Innen-Innen, Messing | Amazon.de B0DR67YGQL (Packungen zu 40) | 7,73 € | | | 1 | Schraubensicherung, mittelfest (blau) | Schraubenking.at Förch 10 ml (P002471) | 5,71 € | | | | **Zwischensumme** | | **51,60 €** | | ## Filament {#filament} | Anz. | Artikel | Günstigstes Angebot | Preis | Hinweis | |---|---|---|---|---| | 1 | Filament PETG, graphit/schwarz, 1 kg | 3DJake.at ELG-50.203.0216 (Elegoo Rapid PETG black) | 11,19 € | PETG passend zum verifizierten Slicer-Profil und zur Festigkeitsprüfung (PLA erweicht in der Nähe der warmen Servos) | | 1 | Filament PETG, limette/gelb (Schalen), 1 kg | 3DJake.at ELG-50.203.0221 (Elegoo Rapid PETG yellow) | 11,19 € | PETG passend zum verifizierten Slicer-Profil und zur Festigkeitsprüfung | | | **Zwischensumme** | | **22,38 €** | | ## Werkbank (empfohlen) {#bench-recommended} | Anz. | Artikel | Günstigstes Angebot | Preis | Hinweis | |---|---|---|---|---| | 1 | Raspberry Pi 27 W USB-C-Netzteil, EU-Stecker (Werkbankversorgung ohne Akku) | Welectron (DE) SC1407 | 11,90 € | | | | **Zwischensumme** | | **11,90 €** | | **Teile gesamt (günstigste Angebote, ohne Versand): 921,30 €.** Versandoptimierte Bündel: [shopping_list.md](shopping_list.md). ## Befestigungselemente nach Verbindung (aus dem CAD) {#fasteners-by-joint-from-the-cad} | Befestigungselement | Im CAD | Kaufen (inkl. Reserve) | Verwendet bei | |---|---|---|---| | `din985_m3` | 17 | 19 | tibia_joints ×8, tibia_foot ×4, tibia_link_pin ×4, Drehpunkt-Nyloc (Reibung) ×1 | | `iso4032_m2` | 4 | 6 | M2-Mutter hinter der Neigeplatte ×4 | | `iso4032_m2_5` | 2 | 4 | IMU-Mutter unter dem Deck ×2 | | `iso4032_m3` | 56 | 62 | shoulder_frames ×16, hip_servo_ears ×16, shell_to_shoulder_bottom ×8, chassis_side ×8, shell_to_shoulder_top ×6, unverlierbare Mutter im oberen Schulterrahmen (Upstream-Tasche) ×2 | | `iso4762_m2_5x5` | 20 | 22 | Abstandsbolzen -> Deck (von unten, Kopf in Tasche) ×8, Platine -> Abstandsbolzen ×8, INA260 -> Abstandsbolzen ×2, Abstandsbolzen -> Deck (von unten) ×2 | | `iso4762_m2_5x6` | 8 | 10 | LiDAR -> Sockel ×4, Klemmring -> Blende durch das D20-Loch ×2, IMU -> Deck ×2 | | `iso4762_m2x10` | 4 | 6 | Kamera-Platine -> Neigeplatten-Dome ×4 | | `iso4762_m2x5` | 10 | 12 | Halter -> LCD-Sechskantbolzen ×4, Spannungsregler -> Abstandsbolzen ×3, Abstandsbolzen -> Deck (von unten) ×3 | | `iso4762_m3x10` | 86 | 95 | leg_servo_ears_and_bracket ×32, shoulder_frames ×16, hip_servo_ears ×16, chassis_side ×8, knee_axle ×8, hip_pivot ×4, Halter -> Frontschalen-Dom (selbstschneidend) ×2 | | `iso4762_m3x12` | 16 | 18 | tibia_joints ×8, Sockel -> Oberschale (von unten, selbstschneidend) ×4, Kamerabasis + Frontschale -> Mutter im oberen Schulterrahmen (ersetzt Upstream-M3x8) ×2, Bushalter -> unterer Schulterrahmen (selbstschneidend) ×2 | | `iso4762_m3x16` | 4 | 6 | arm_pin ×4 | | `iso4762_m3x20` | 28 | 31 | femur_to_horn ×16, bracket_screws ×8, tibia_foot ×4 | | `iso4762_m3x25` | 12 | 14 | crank_pins ×8, tibia_link_pin ×4 | | `iso4762_m3x40` | 1 | 3 | Kamera-Neigedrehpunkt ×1 | | `iso4762_m3x8` | 34 | 38 | shell_to_shoulder_bottom ×8, horn_centre_screw ×8, hip_horn ×8, shell_to_shoulder_top ×6, knee_drive_centre_screw ×4 | | `iso7089_m3` | 16 | 18 | knee_axle ×8, hip_pivot ×4, arm_pin ×4 | | `standoff_m2_5_ff_6` | 10 | 12 | Platinen-Abstandsbolzen ×8, INA260-Abstandsbolzen ×2 | | `standoff_m2_ff_8` | 3 | 5 | Spannungsregler-Abstandsbolzen ×3 | ## CAD-Abdeckungsprüfung (günstigste Angebote) {#cad-coverage-check-cheapest-offers} Jedes Zukaufteil und jede Befestigungselement-Instanz im montierten CAD-Modell muss durch die Angebote gedeckt sein, die eine Strategie kauft (Packungen aufgerundet; Befestigungselemente mit max(2, 10 %) Reserve). Geprüft für jede Strategie in der Einkaufsliste. | CAD-ID | Im CAD | Benötigt | Geliefert | OK | |---|---|---|---|---| | `adafruit_ina260` | 1 | 1 | 1 | ja | | `adafruit_lsm6dsox` | 1 | 1 | 1 | ja | | `adafruit_pca9685` | 1 | 1 | 1 | ja | | `bearing_625zz` | 4 | 4 | 4 | ja | | `bearing_633zz` | 8 | 8 | 8 | ja | | `bearing_6805_2rs` | 4 | 4 | 4 | ja | | `cable_tie_mount` | 2 | 2 | 2 | ja | | `din985_m3` | 17 | 19 | 100 | ja | | `fuse_holder_ato` | 2 | 2 | 10 | ja | | `hobbywing_ubec_10a` | 2 | 2 | 2 | ja | | `iso4032_m2` | 4 | 6 | 100 | ja | | `iso4032_m2_5` | 2 | 4 | 100 | ja | | `iso4032_m3` | 56 | 62 | 360 | ja | | `iso4762_m2_5x5` | 20 | 22 | 30 | ja | | `iso4762_m2_5x6` | 8 | 10 | 10 | ja | | `iso4762_m2x10` | 4 | 6 | 10 | ja | | `iso4762_m2x5` | 10 | 12 | 20 | ja | | `iso4762_m3x10` | 86 | 95 | 130 | ja | | `iso4762_m3x12` | 16 | 18 | 30 | ja | | `iso4762_m3x16` | 4 | 6 | 30 | ja | | `iso4762_m3x20` | 28 | 31 | 40 | ja | | `iso4762_m3x25` | 12 | 14 | 20 | ja | | `iso4762_m3x40` | 1 | 3 | 20 | ja | | `iso4762_m3x8` | 34 | 38 | 40 | ja | | `iso7089_m3` | 16 | 18 | 360 | ja | | `lipo_2s_5000_gensace` | 1 | 1 | 1 | ja | | `pololu_d36v50f5` | 1 | 1 | 1 | ja | | `pololu_power_switch_hp` | 1 | 1 | 1 | ja | | `pushbutton_12mm` | 1 | 1 | 1 | ja | | `raspberry_pi_5` | 1 | 1 | 1 | ja | | `rpi_camera_module_3_wide` | 1 | 1 | 1 | ja | | `rplidar_c1` | 1 | 1 | 1 | ja | | `rplidar_usb_adapter` | 1 | 1 | 1 | ja | | `seeed_xiao_esp32s3` | 1 | 1 | 1 | ja | | `servo_arm_horn_25t` | 4 | 4 | 5 | ja | | `servo_disc_horn_25t` | 8 | 8 | 10 | ja | | `servo_spt5435lv` | 12 | 12 | 13 | ja | | `sleeve_bearing_3x5x5_pair` | 16 | 16 | 25 | ja | | `standoff_m2_5_ff_6` | 10 | 12 | 12 | ja | | `standoff_m2_ff_8` | 3 | 5 | 40 | ja | | `wago_221_415` | 8 | 8 | 8 | ja | | `waveshare_lcd_2inch` | 1 | 1 | 1 | ja | | `xt60h_female` | 2 | 2 | 3 | ja | Ergebnis: alles abgedeckt Nicht im CAD modelliert und daher ohne Abdeckungsprüfung aus den obigen Positionen gekauft: Kabel, Litze, Sicherungen, Verbrauchsmaterial, microSD, Ladegerät. ## Werkzeuge (nicht in den Summen) {#tools-not-in-the-totals} | Werkzeug | Händler | Preis | |---|---|---| | Sechskantschlüssel 1,5-2,5 mm (Wera 950/9 Hex-Plus) | Amazon.de B009ODV0OE | 28,22 € | | Lötkolben (Miniware TS101) | Amazon.de B0CPDRQZYB | 74,62 € | | Abisolierzange (Jokari Super 4 plus) | Amazon.de | 14,06 € | | Dupont-Crimpset mit Gehäusen (DxCRIMP) | Amazon.de | 30,22 € | | Multimeter (Kaiweets) | Amazon.de | 46,28 € | | Messschieber | Amazon.de | 18,94 € | | Seitenschneider (Wiha 26812) | Amazon.de | 16,09 € | | Steckschlüssel 4,0 / 5,0 / 5,5 mm (Muttern M2, M2.5, M3) | ohne Preis | — | | Dünnflüssiger CA-Kleber (flüssiger Sekundenkleber) zum Härten schwacher gedruckter Kernlöcher (ADR-009) | ohne Preis | — | | 3D-Drucker mit Druckbett >= 220 x 220 mm (Schalen sind 114 x 208 mm), z. B. Bambu Lab A1 Combo | eu.store.bambulab.com | 339,00 € | --- # Einkaufsliste und Pakete (Österreich) {#shopping-list-and-bundles-austria} **So lesen Sie diese Seite.** Es gibt vier alternative Wege, die Teile zu kaufen. Jeder Plan ist eine *vollständige* Einkaufsliste für den ganzen Roboter: jedes Kaufteil, jede Schraube und Mutter samt Reserve sowie das Filament. Wählen Sie **einen** Plan und bestellen Sie alles, was darunter aufgeführt ist; mischen Sie keine Pläne. Die Pläne unterscheiden sich nur darin, welcher Shop einen Artikel liefert, daher unterscheiden sich Preis, Anzahl der Pakete und Lieferzeit. Werkzeuge und der 3D-Drucker sind nicht enthalten (siehe die [Werkzeugliste](README.md#tools-not-in-the-totals)). Um einzelne Artikel zu ändern, für mehrere Roboter zu bestellen oder die Warenkörbe zu befüllen, verwenden Sie den [Teile-Shop](../shop.md). | Plan | Wählen, wenn | Shops (Pakete) | Teile | Versand | **Gesamt** | ggü. günstigstem | |---|---|---|---|---|---|---| | [Plan A: Niedrigste Gesamtsumme](#plan-a-lowest-total) | der Preis am wichtigsten ist; Servos kommen von AliExpress (2-3 Wochen; über 150 € die Bestellung teilen oder Einfuhrumsatzsteuer einplanen) | 8 | 939,23 € | 39,53 € | **978,76 €** | am günstigsten | | [Plan B: Wenigste Shops](#plan-b-fewest-shops) | Sie möglichst wenige Pakete und Konten wollen; teurer, weil Amazon günstigere Shops ersetzt | 4 | 1.111,72 € | 15,25 € | **1.126,97 €** | +148,21 € | | [Plan C: EU-Lager (DigiKey nur für Teile ohne EU-Angebot, kein AliExpress)](#plan-c-eu-warehouses-digikey-only-for-parts-without-an-eu-offer-no-aliexpress) | alles aus EU-Lagern (kein AliExpress), schnellste Lieferung; DigiKey nur, wo kein EU-Shop das Teil führt | 9 | 1.070,76 € | 74,48 € | **1.145,24 €** | +166,48 € | | [Plan D: Original-Boards, wo verfügbar](#plan-d-genuine-boards-where-available) | wie A, aber Original-Boards von Adafruit/Seeed/Pololu überall dort, wo ein Klon günstiger wäre | 8 | 948,20 € | 39,53 € | **987,73 €** | +8,97 € | Preise in EUR inkl. USt., erhoben am 2026-10-30; Versand nach Österreich (Versandkostenfrei-Schwellen und Gebühren pro Bestellung eingerechnet). Prüfen Sie Preise und Verfügbarkeit vor der Bestellung erneut. ## Wo sich die Pläne unterscheiden {#where-the-plans-differ} 26 von 62 Artikeln kommen je nach Plan aus verschiedenen Shops; jeder andere Artikel wird in allen Plänen im selben Shop gekauft. Shop und Kosten pro Plan: | Artikel | Plan A | Plan B | Plan C | Plan D | |---|---|---|---|---| | Raspberry Pi 5, 4 GB | DigiKey.at 117,18 € | DigiKey.at 117,18 € | Berrybase.at 123,90 € | DigiKey.at 117,18 € | | Raspberry Pi Active Cooler | DigiKey.at 5,33 € | DigiKey.at 5,33 € | Welectron (DE) 4,90 € | DigiKey.at 5,33 € | | microSD 64 GB A2 (SanDisk Extreme) | Amazon.de 26,21 € | Amazon.de 26,21 € | Berrybase.at 25,90 € | Amazon.de 26,21 € | | Raspberry Pi Camera Module 3 Wide | DigiKey.at 37,28 € | DigiKey.at 37,28 € | Welectron (DE) 35,90 € | DigiKey.at 37,28 € | | Pi-5-Kamerakabel 22→15 Pin, 300 mm | DigiKey.at 2,14 € | DigiKey.at 2,14 € | Berrybase.at 2,30 € | DigiKey.at 2,14 € | | Seeed XIAO ESP32-S3, Stiftleisten vorgelötet | DigiKey.at 9,05 € | DigiKey.at 9,05 € | Berrybase.at 9,90 € | DigiKey.at 9,05 € | | PCA9685 16-Kanal-PWM-Board (Adafruit-815-Layout) | Amazon.de 6,95 € | Amazon.de 6,95 € | Amazon.de 6,95 € | DigiKey.at 15,92 € | | Adafruit LSM6DSOX 6-DoF IMU (4438) | DigiKey.at 12,73 € | DigiKey.at 12,73 € | Amazon.de 20,16 € | DigiKey.at 12,73 € | | Adafruit INA260 Power-Monitor (4226) | DigiKey.at 10,60 € | DigiKey.at 10,60 € | Eckstein (DE) 11,84 € | DigiKey.at 10,60 € | | Waveshare 2" LCD-Modul, ST7789, 240x320 (17344) | Eckstein (DE) 14,27 € | Amazon.de 20,16 € | Welectron (DE) 10,90 € | Eckstein (DE) 14,27 € | | STEMMA-QT-Kabel auf Buchsen, 150 mm (Adafruit 4397; IMU zu PCA9685 und IMU zu INA260) | DigiKey.at 2,02 € | DigiKey.at 2,02 € | Berrybase.at 5,00 € | DigiKey.at 2,02 € | | SPT5435LV-180W Servo, 35 kg·cm, 180° (12 + 1 Reserve) | AliExpress (DigitalServo Store) 174,98 € | Amazon.de 292,24 € | Amazon.de 292,24 € | AliExpress (DigitalServo Store) 174,98 € | | Kugellager 625ZZ (5x16x5) | 3DJake.at 4,99 € | Amazon.de 7,36 € | 3DJake.at 4,99 € | 3DJake.at 4,99 € | | Hobbywing UBEC-10A (V2-Car), 6,0 V | Lindinger.at 53,98 € | Amazon.de 59,80 € | Lindinger.at 53,98 € | Lindinger.at 53,98 € | | LiPo-Sicherheitstasche | Lindinger.at 6,49 € | Amazon.de 14,11 € | Lindinger.at 6,49 € | Lindinger.at 6,49 € | | LiPo-Zellprüfer / Unterspannungsalarm | Lindinger.at 5,95 € | Amazon.de 6,04 € | Lindinger.at 5,95 € | Lindinger.at 5,95 € | | Pololu D36V50F5 5 V 5,5 A Abwärtsspannungsregler | Eckstein (DE) 41,59 € | DigiKey.at 48,24 € | Eckstein (DE) 41,59 € | Eckstein (DE) 41,59 € | | XT60H-Steckverbinder, 3 Paare (Akkuleitung, Arming-Port, Loop-Key) | Lindinger.at 4,99 € | Amazon.de 6,44 € | Lindinger.at 4,99 € | Lindinger.at 4,99 € | | Silikonlitze 14 AWG / 2,5 mm², rot + schwarz, je 1 m | Lindinger.at 4,99 € | Amazon.de 12,10 € | Lindinger.at 4,99 € | Lindinger.at 4,99 € | | Silikonlitze 18 AWG / 0,75 mm², rot + schwarz (je 1 m pro Einheit) | Lindinger.at 5,98 € | Amazon.de 18,12 € | Lindinger.at 5,98 € | Lindinger.at 5,98 € | | Dupont-Jumper-Set 20 cm (F-F, M-M, F-M) | Amazon.de 8,05 € | Amazon.de 8,05 € | Berrybase.at 4,90 € | Amazon.de 8,05 € | | Kabelbinder 100 x 2,5 mm (100) | Reichelt.at 1,16 € | Reichelt.at 1,16 € | Berrybase.at 0,90 € | Reichelt.at 1,16 € | | Abstandsbolzen M2.5 x 6 mm Buchse-Buchse (Würth 970060151) | DigiKey.at 6,62 € | DigiKey.at 6,62 € | Amazon.de 11,29 € | DigiKey.at 6,62 € | | Filament PETG, Graphit/Schwarz, 1 kg | 3DJake.at 11,19 € | Amazon.de 14,11 € | 3DJake.at 11,19 € | 3DJake.at 11,19 € | | Filament PETG, Limette/Gelb (Schalen), 1 kg | 3DJake.at 11,19 € | Amazon.de 14,36 € | 3DJake.at 11,19 € | 3DJake.at 11,19 € | | Raspberry Pi 27 W USB-C Netzteil, EU-Stecker (Tischversorgung ohne Akku) | DigiKey.at 12,78 € | DigiKey.at 12,78 € | Welectron (DE) 11,90 € | DigiKey.at 12,78 € | So werden die Pläne berechnet (`strido_publish.bom`): Für jeden Plan probiert der Optimierer jede Teilmenge der zulässigen Shops aus, nimmt innerhalb der Teilmenge pro Artikel das günstigste zulässige Angebot und addiert die Versandkosten jedes Shops. Er kauft keine teureren Angebote, nur um eine Versandkostenfrei-Schwelle zu erreichen. ## Plan A: Niedrigste Gesamtsumme {#plan-a-lowest-total} **978,76 €** in 8 Bestellungen. Bestellen Sie alles unten Aufgeführte; die Zwischensummen pro Shop ergeben diese Gesamtsumme. ### Amazon.de – 295,72 € + Versand 2,40 € {#amazon-de-€295-72-shipping-€2-40} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | microSD 64 GB A2 (SanDisk Extreme) | B09X7CXWQQ | 26,21 € | | 1 | PCA9685 16-Kanal-PWM-Board (Adafruit-815-Layout) | B06XSFFXQY | 6,95 € | | 1 | Slamtec RPLIDAR C1 (mit USB-Adapter) | B0CP8YRY44 (WayPonDEV) | 70,58 € | | 2 × Packung à 5 | 25T Aluminium-Scheibenhorn | B07F71J1Q2 (DollaTek, 5er-Pack) | 10,06 € | | 1 × Packung à 5 | 25T Aluminium-Klemmarmhorn | B0F5QG8HQS (5er-Pack) | 9,06 € | | 2 × Packung à 2 | Kugellager 6805-2RS (25x37x7) | B0CL4Z679J (2er-Pack) | 13,48 € | | 1 × Packung à 8 | Kugellager 633ZZ (3x13x5) | B0GGT3GW69 (8er-Pack) | 10,27 € | | 1 × Packung à 50 | Sinterbronze-Gleitlager 3x5x5 | B0G15L264D (50er-Pack) | 10,27 € | | 1 | LiPo 2S 5000 mAh Hardcase, XT60, max 138 x 47 x 25 mm (Gens ace G-Tech) | B0GKP683YF | 22,18 € | | 1 | LiPo-Balancer-Ladegerät, Netzeingang (B6AC-Klasse) | B0F3CYZ6L8 (HTRC B6AC) | 46,38 € | | 1 × Packung à 10 | Inline-ATO-Sicherungshalter, 14-AWG-Leitungen (Haupt- + Logikzweig) | B07426WCLM (Nilight, 10 Halter) | 8,56 € | | 1 | Silikonlitze 22 AWG (Pi-5-V-Versorgung mit Dupont-Crimps, Taster, Jumper) | B0C7T9KYND (6 Farben x 4 m) | 12,10 € | | 1 × Packung à 3 | USB-A-auf-USB-C-Kabel, 20 cm, 90° (Pi → XIAO, Pi → LiDAR-Adapter) | B09ZDV7S44 (aceyoon 20 cm 90°, 3er-Pack) | 7,64 € | | 1 | Dupont-Jumper-Set 20 cm (F-F, M-M, F-M) | B0F98KBV61 (160 x F-F) | 8,05 € | | 1 | Dupont 2,54 mm Crimpkontakte und Gehäuse (1–6 Pin), für die abgelängten Signalleitungen | B0FP14VDGS (620 Stück) | 9,06 € | | 1 | M3-Zylinderschrauben-Set, Edelstahl (6-50 mm, Muttern, Unterlegscheiben; WZHUIDA 1080 Stk.) | B0D2VST57H | 17,14 € | | 1 × Packung à 40 | Abstandsbolzen M2 x 8 mm Buchse-Buchse, Messing | B0DR67YGQL | 7,73 € | _+2,40 österreichische Paketabgabe pro Bestellung_ ### DigiKey.at – 226,53 € + Versand 0,00 € {#digikey-at-€226-53-shipping-€0-00} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | Raspberry Pi 5, 4 GB | SC1431 (2648-SC1431-ND) | 117,18 € | | 1 | Raspberry Pi Active Cooler | SC1148 | 5,33 € | | 1 | Raspberry Pi Camera Module 3 Wide | SC1224 | 37,28 € | | 1 | Pi-5-Kamerakabel 22→15 Pin, 300 mm | SC1129 | 2,14 € | | 1 | Seeed XIAO ESP32-S3, Stiftleisten vorgelötet | 102010634 | 9,05 € | | 1 | Adafruit LSM6DSOX 6-DoF IMU (4438) | Adafruit 4438 | 12,73 € | | 1 | Adafruit INA260 Power-Monitor (4226) | Adafruit 4226 | 10,60 € | | 2 | STEMMA-QT-Kabel auf Buchsen, 150 mm (Adafruit 4397; IMU zu PCA9685 und IMU zu INA260) | Adafruit 4397 | 2,02 € | | 1 | Pololu #2813 Big Pushbutton Power Switch HP | Pololu 2813 (Marketplace) | 10,80 € | | 12 | Abstandsbolzen M2.5 x 6 mm Buchse-Buchse (Würth 970060151) | 970060151 | 6,62 € | | 1 | Raspberry Pi 27 W USB-C Netzteil, EU-Stecker (Tischversorgung ohne Akku) | SC1407 (nicht SC1153 = US-Stecker) | 12,78 € | ### AliExpress (DigitalServo Store) – 174,98 € + Versand 5,90 € {#aliexpress-digitalservo-store-€174-98-shipping-€5-90} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 13 | SPT5435LV-180W Servo, 35 kg·cm, 180° (12 + 1 Reserve) | 4000135787995, Variante 35kg-180 Waterproof | 174,98 € | _Servobestellung > 150 EUR fällt aus IOSS: in zwei Bestellungen teilen oder Einfuhrumsatzsteuer/Verzollung einplanen_ ### Lindinger.at – 82,38 € + Versand 5,99 € {#lindinger-at-€82-38-shipping-€5-99} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 2 | Hobbywing UBEC-10A (V2-Car), 6,0 V | HW30603003 | 53,98 € | | 1 | LiPo-Sicherheitstasche | Robbe 23x30 cm (9787514) | 6,49 € | | 1 | LiPo-Zellprüfer / Unterspannungsalarm | Absima (9771616) | 5,95 € | | 1 | XT60H-Steckverbinder, 3 Paare (Akkuleitung, Arming-Port, Loop-Key) | Robbe XT60 3 Paare (9750234) | 4,99 € | | 1 | Silikonlitze 14 AWG / 2,5 mm², rot + schwarz, je 1 m | 20479 | 4,99 € | | 2 | Silikonlitze 18 AWG / 0,75 mm², rot + schwarz (je 1 m pro Einheit) | 44422 | 5,98 € | ### Reichelt.at – 56,28 € + Versand 6,95 € {#reichelt-at-€56-28-shipping-€6-95} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | Widerstand 2,2 kΩ 0,25 W (PCA9685-OE-Pull-up) | METALL 2,20K | 0,10 € | | 1 | 12 mm Taster (tastend), Edelstahl (ONPOW GQ12B-10S) | 318555 | 5,66 € | | 3 | ATO-Flachsicherung 25 A (Haupt, 1 + 2 Reserve) | 7786 | 1,08 € | | 2 | ATO-Flachsicherung 7,5 A (Logikzweig, 1 + 1 Reserve) | FKS 7,5 A (gleiche Serie wie 7786) | 0,72 € | | 8 | WAGO 221-415 Hebelklemme | 149800 | 6,48 € | | 1 | Schrumpfschlauch-Sortiment | 152924 | 5,39 € | | 1 | Kabelbinder 100 x 2,5 mm (100) | Delock 19186 | 1,16 € | | 1 | Spiralschlauch, schwarzes PE, für Bündel 4-10 mm (5-10 m) | CIMCO 186220 (10 m, Bündel 4-20 mm) | 4,84 € | | 2 | Selbstklebender Kabelbinder-Sockel 13 x 13 mm (HellermannTyton MB2APT-A) | HT 151-02243 (pro Stück) | 2,12 € | | 1 | Lötdraht, bleifrei, 0,8 mm, Flussmittelseele (50-100 g) | Goobay 420259 (50 g, SAC) | 13,61 € | | 1 | Klettbänder (Akkugurt) | 280182 | 5,14 € | | 1 | Doppelseitiges Schaum-Montageband, 19 mm | tesa PRO Universal 338987 | 9,98 € | ### Eckstein (DE) – 55,86 € + Versand 6,90 € {#eckstein-de-€55-86-shipping-€6-90} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | Waveshare 2" LCD-Modul, ST7789, 240x320 (17344) | Waveshare 2inch LCD | 14,27 € | | 1 | Pololu D36V50F5 5 V 5,5 A Abwärtsspannungsregler | D36V50F5 | 41,59 € | _Versand nach AT erst an der Kasse angezeigt: 6,90 angenommen (UNVERIFIED)_ ### 3DJake.at – 27,37 € + Versand 5,49 € {#_3djake-at-€27-37-shipping-€5-49} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 × Packung à 10 | Kugellager 625ZZ (5x16x5) | 625ZZ 10er-Pack | 4,99 € | | 1 | Filament PETG, Graphit/Schwarz, 1 kg | ELG-50.203.0216 (Elegoo Rapid PETG schwarz) | 11,19 € | | 1 | Filament PETG, Limette/Gelb (Schalen), 1 kg | ELG-50.203.0221 (Elegoo Rapid PETG gelb) | 11,19 € | ### Schraubenking.at – 20,11 € + Versand 5,90 € {#schraubenking-at-€20-11-shipping-€5-90} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 × Packung à 100 | M3 x 10 DIN 912 A2 | M3x10 DIN912 A2, 100 | 2,35 € | | 1 × Packung à 10 | M3 x 20 DIN 912 A2 | M3x20 DIN912 A2, 10 | 0,97 € | | 1 × Packung à 100 | M3 DIN 985 Sicherungsmutter mit Nylonring | P000461 (verzinkt) | 1,39 € | | 3 × Packung à 10 | M2.5 x 5 DIN 912 A2 | P004986 | 2,49 € | | 1 × Packung à 10 | M2.5 x 6 DIN 912 A2 | P005010 | 0,83 € | | 2 × Packung à 10 | M2 x 5 DIN 912 A2 | P003957 | 1,72 € | | 1 × Packung à 10 | M2 x 10 DIN 912 A2 | P002803 | 0,78 € | | 1 × Packung à 100 | M2 Sechskantmutter DIN 934 A2 | P002807 | 1,87 € | | 1 × Packung à 100 | M2,5 Sechskantmutter DIN 934 A2 | P004196 | 2,00 € | | 1 | Schraubensicherung, mittelfest (blau) | Förch 10 ml (P002471) | 5,71 € | ## Plan B: Wenigste Shops {#plan-b-fewest-shops} **1.126,97 €** in 4 Bestellungen. Bestellen Sie alles unten Aufgeführte; die Zwischensummen pro Shop ergeben diese Gesamtsumme. ### Amazon.de – 760,56 € + Versand 2,40 € {#amazon-de-€760-56-shipping-€2-40} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | microSD 64 GB A2 (SanDisk Extreme) | B09X7CXWQQ | 26,21 € | | 1 | PCA9685 16-Kanal-PWM-Board (Adafruit-815-Layout) | B06XSFFXQY | 6,95 € | | 1 | Waveshare 2" LCD-Modul, ST7789, 240x320 (17344) | B081NBBRWS | 20,16 € | | 1 | Slamtec RPLIDAR C1 (mit USB-Adapter) | B0CP8YRY44 (WayPonDEV) | 70,58 € | | 13 | SPT5435LV-180W Servo, 35 kg·cm, 180° (12 + 1 Reserve) | B0G39ZHL4B (Winkel nicht angegeben) | 292,24 € | | 2 × Packung à 5 | 25T Aluminium-Scheibenhorn | B07F71J1Q2 (DollaTek, 5er-Pack) | 10,06 € | | 1 × Packung à 5 | 25T Aluminium-Klemmarmhorn | B0F5QG8HQS (5er-Pack) | 9,06 € | | 1 × Packung à 15 | Kugellager 625ZZ (5x16x5) | B0CM8TYDR6 (15er-Pack) | 7,36 € | | 2 × Packung à 2 | Kugellager 6805-2RS (25x37x7) | B0CL4Z679J (2er-Pack) | 13,48 € | | 1 × Packung à 8 | Kugellager 633ZZ (3x13x5) | B0GGT3GW69 (8er-Pack) | 10,27 € | | 1 × Packung à 50 | Sinterbronze-Gleitlager 3x5x5 | B0G15L264D (50er-Pack) | 10,27 € | | 2 | Hobbywing UBEC-10A (V2-Car), 6,0 V | B0BCWYQYKW (original Hobbywing, Marketplace-Händler) | 59,80 € | | 1 | LiPo 2S 5000 mAh Hardcase, XT60, max 138 x 47 x 25 mm (Gens ace G-Tech) | B0GKP683YF | 22,18 € | | 1 | LiPo-Balancer-Ladegerät, Netzeingang (B6AC-Klasse) | B0F3CYZ6L8 (HTRC B6AC) | 46,38 € | | 1 | LiPo-Sicherheitstasche | B09C31KVK1 | 14,11 € | | 1 | LiPo-Zellprüfer / Unterspannungsalarm | B077Z1N9CS | 6,04 € | | 1 | XT60H-Steckverbinder, 3 Paare (Akkuleitung, Arming-Port, Loop-Key) | B07C3KH1VT (Amass, 3 Paare) | 6,44 € | | 1 × Packung à 10 | Inline-ATO-Sicherungshalter, 14-AWG-Leitungen (Haupt- + Logikzweig) | B07426WCLM (Nilight, 10 Halter) | 8,56 € | | 1 | Silikonlitze 14 AWG / 2,5 mm², rot + schwarz, je 1 m | B0C53D343Y (5 m) | 12,10 € | | 2 | Silikonlitze 18 AWG / 0,75 mm², rot + schwarz (je 1 m pro Einheit) | B0D12R349S (5+5 m) | 18,12 € | | 1 | Silikonlitze 22 AWG (Pi-5-V-Versorgung mit Dupont-Crimps, Taster, Jumper) | B0C7T9KYND (6 Farben x 4 m) | 12,10 € | | 1 × Packung à 3 | USB-A-auf-USB-C-Kabel, 20 cm, 90° (Pi → XIAO, Pi → LiDAR-Adapter) | B09ZDV7S44 (aceyoon 20 cm 90°, 3er-Pack) | 7,64 € | | 1 | Dupont-Jumper-Set 20 cm (F-F, M-M, F-M) | B0F98KBV61 (160 x F-F) | 8,05 € | | 1 | Dupont 2,54 mm Crimpkontakte und Gehäuse (1–6 Pin), für die abgelängten Signalleitungen | B0FP14VDGS (620 Stück) | 9,06 € | | 1 | M3-Zylinderschrauben-Set, Edelstahl (6-50 mm, Muttern, Unterlegscheiben; WZHUIDA 1080 Stk.) | B0D2VST57H | 17,14 € | | 1 × Packung à 40 | Abstandsbolzen M2 x 8 mm Buchse-Buchse, Messing | B0DR67YGQL | 7,73 € | | 1 | Filament PETG, Graphit/Schwarz, 1 kg | B07TJDTJZD (Sunlu PETG schwarz) | 14,11 € | | 1 | Filament PETG, Limette/Gelb (Schalen), 1 kg | B0D9NDB63H (Sunlu Rapid PETG gelb) | 14,36 € | _+2,40 österreichische Paketabgabe pro Bestellung_ ### DigiKey.at – 274,77 € + Versand 0,00 € {#digikey-at-€274-77-shipping-€0-00} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | Raspberry Pi 5, 4 GB | SC1431 (2648-SC1431-ND) | 117,18 € | | 1 | Raspberry Pi Active Cooler | SC1148 | 5,33 € | | 1 | Raspberry Pi Camera Module 3 Wide | SC1224 | 37,28 € | | 1 | Pi-5-Kamerakabel 22→15 Pin, 300 mm | SC1129 | 2,14 € | | 1 | Seeed XIAO ESP32-S3, Stiftleisten vorgelötet | 102010634 | 9,05 € | | 1 | Adafruit LSM6DSOX 6-DoF IMU (4438) | Adafruit 4438 | 12,73 € | | 1 | Adafruit INA260 Power-Monitor (4226) | Adafruit 4226 | 10,60 € | | 2 | STEMMA-QT-Kabel auf Buchsen, 150 mm (Adafruit 4397; IMU zu PCA9685 und IMU zu INA260) | Adafruit 4397 | 2,02 € | | 1 | Pololu D36V50F5 5 V 5,5 A Abwärtsspannungsregler | Pololu 4091 (Marketplace) | 48,24 € | | 1 | Pololu #2813 Big Pushbutton Power Switch HP | Pololu 2813 (Marketplace) | 10,80 € | | 12 | Abstandsbolzen M2.5 x 6 mm Buchse-Buchse (Würth 970060151) | 970060151 | 6,62 € | | 1 | Raspberry Pi 27 W USB-C Netzteil, EU-Stecker (Tischversorgung ohne Akku) | SC1407 (nicht SC1153 = US-Stecker) | 12,78 € | ### Reichelt.at – 56,28 € + Versand 6,95 € {#reichelt-at-€56-28-shipping-€6-95-1} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | Widerstand 2,2 kΩ 0,25 W (PCA9685-OE-Pull-up) | METALL 2,20K | 0,10 € | | 1 | 12 mm Taster (tastend), Edelstahl (ONPOW GQ12B-10S) | 318555 | 5,66 € | | 3 | ATO-Flachsicherung 25 A (Haupt, 1 + 2 Reserve) | 7786 | 1,08 € | | 2 | ATO-Flachsicherung 7,5 A (Logikzweig, 1 + 1 Reserve) | FKS 7,5 A (gleiche Serie wie 7786) | 0,72 € | | 8 | WAGO 221-415 Hebelklemme | 149800 | 6,48 € | | 1 | Schrumpfschlauch-Sortiment | 152924 | 5,39 € | | 1 | Kabelbinder 100 x 2,5 mm (100) | Delock 19186 | 1,16 € | | 1 | Spiralschlauch, schwarzes PE, für Bündel 4-10 mm (5-10 m) | CIMCO 186220 (10 m, Bündel 4-20 mm) | 4,84 € | | 2 | Selbstklebender Kabelbinder-Sockel 13 x 13 mm (HellermannTyton MB2APT-A) | HT 151-02243 (pro Stück) | 2,12 € | | 1 | Lötdraht, bleifrei, 0,8 mm, Flussmittelseele (50-100 g) | Goobay 420259 (50 g, SAC) | 13,61 € | | 1 | Klettbänder (Akkugurt) | 280182 | 5,14 € | | 1 | Doppelseitiges Schaum-Montageband, 19 mm | tesa PRO Universal 338987 | 9,98 € | ### Schraubenking.at – 20,11 € + Versand 5,90 € {#schraubenking-at-€20-11-shipping-€5-90-1} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 × Packung à 100 | M3 x 10 DIN 912 A2 | M3x10 DIN912 A2, 100 | 2,35 € | | 1 × Packung à 10 | M3 x 20 DIN 912 A2 | M3x20 DIN912 A2, 10 | 0,97 € | | 1 × Packung à 100 | M3 DIN 985 Sicherungsmutter mit Nylonring | P000461 (verzinkt) | 1,39 € | | 3 × Packung à 10 | M2.5 x 5 DIN 912 A2 | P004986 | 2,49 € | | 1 × Packung à 10 | M2.5 x 6 DIN 912 A2 | P005010 | 0,83 € | | 2 × Packung à 10 | M2 x 5 DIN 912 A2 | P003957 | 1,72 € | | 1 × Packung à 10 | M2 x 10 DIN 912 A2 | P002803 | 0,78 € | | 1 × Packung à 100 | M2 Sechskantmutter DIN 934 A2 | P002807 | 1,87 € | | 1 × Packung à 100 | M2,5 Sechskantmutter DIN 934 A2 | P004196 | 2,00 € | | 1 | Schraubensicherung, mittelfest (blau) | Förch 10 ml (P002471) | 5,71 € | ## Plan C: EU-Lager (DigiKey nur für Teile ohne EU-Angebot, kein AliExpress) {#plan-c-eu-warehouses-digikey-only-for-parts-without-an-eu-offer-no-aliexpress} **1.145,24 €** in 9 Bestellungen. Bestellen Sie alles unten Aufgeführte; die Zwischensummen pro Shop ergeben diese Gesamtsumme. ### Amazon.de – 585,15 € + Versand 2,40 € {#amazon-de-€585-15-shipping-€2-40} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | PCA9685 16-Kanal-PWM-Board (Adafruit-815-Layout) | B06XSFFXQY | 6,95 € | | 1 | Adafruit LSM6DSOX 6-DoF IMU (4438) | B085F3F19D | 20,16 € | | 1 | Slamtec RPLIDAR C1 (mit USB-Adapter) | B0CP8YRY44 (WayPonDEV) | 70,58 € | | 13 | SPT5435LV-180W Servo, 35 kg·cm, 180° (12 + 1 Reserve) | B0G39ZHL4B (Winkel nicht angegeben) | 292,24 € | | 2 × Packung à 5 | 25T Aluminium-Scheibenhorn | B07F71J1Q2 (DollaTek, 5er-Pack) | 10,06 € | | 1 × Packung à 5 | 25T Aluminium-Klemmarmhorn | B0F5QG8HQS (5er-Pack) | 9,06 € | | 2 × Packung à 2 | Kugellager 6805-2RS (25x37x7) | B0CL4Z679J (2er-Pack) | 13,48 € | | 1 × Packung à 8 | Kugellager 633ZZ (3x13x5) | B0GGT3GW69 (8er-Pack) | 10,27 € | | 1 × Packung à 50 | Sinterbronze-Gleitlager 3x5x5 | B0G15L264D (50er-Pack) | 10,27 € | | 1 | LiPo 2S 5000 mAh Hardcase, XT60, max 138 x 47 x 25 mm (Gens ace G-Tech) | B0GKP683YF | 22,18 € | | 1 | LiPo-Balancer-Ladegerät, Netzeingang (B6AC-Klasse) | B0F3CYZ6L8 (HTRC B6AC) | 46,38 € | | 1 × Packung à 10 | Inline-ATO-Sicherungshalter, 14-AWG-Leitungen (Haupt- + Logikzweig) | B07426WCLM (Nilight, 10 Halter) | 8,56 € | | 1 | Silikonlitze 22 AWG (Pi-5-V-Versorgung mit Dupont-Crimps, Taster, Jumper) | B0C7T9KYND (6 Farben x 4 m) | 12,10 € | | 1 × Packung à 3 | USB-A-auf-USB-C-Kabel, 20 cm, 90° (Pi → XIAO, Pi → LiDAR-Adapter) | B09ZDV7S44 (aceyoon 20 cm 90°, 3er-Pack) | 7,64 € | | 1 | Dupont 2,54 mm Crimpkontakte und Gehäuse (1–6 Pin), für die abgelängten Signalleitungen | B0FP14VDGS (620 Stück) | 9,06 € | | 1 | M3-Zylinderschrauben-Set, Edelstahl (6-50 mm, Muttern, Unterlegscheiben; WZHUIDA 1080 Stk.) | B0D2VST57H | 17,14 € | | 1 × Packung à 12 | Abstandsbolzen M2.5 x 6 mm Buchse-Buchse (Würth 970060151) | B0GK7QTZ7B (Messing-F-F-Sortiment; 6-mm-Variante prüfen) | 11,29 € | | 1 × Packung à 40 | Abstandsbolzen M2 x 8 mm Buchse-Buchse, Messing | B0DR67YGQL | 7,73 € | _+2,40 österreichische Paketabgabe pro Bestellung_ ### Berrybase.at – 172,80 € + Versand 5,95 € {#berrybase-at-€172-80-shipping-€5-95} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | Raspberry Pi 5, 4 GB | RPI5-4GB | 123,90 € | | 1 | microSD 64 GB A2 (SanDisk Extreme) | SanDisk Extreme A2 64GB | 25,90 € | | 1 | Pi-5-Kamerakabel 22→15 Pin, 300 mm | RPI-CC-SM-30 | 2,30 € | | 1 | Seeed XIAO ESP32-S3, Stiftleisten vorgelötet | SE-102010634 | 9,90 € | | 2 | STEMMA-QT-Kabel auf Buchsen, 150 mm (Adafruit 4397; IMU zu PCA9685 und IMU zu INA260) | SE-114992154 (Seeed, Alternative) | 5,00 € | | 1 | Dupont-Jumper-Set 20 cm (F-F, M-M, F-M) | DUPK-SET-20 | 4,90 € | | 1 | Kabelbinder 100 x 2,5 mm (100) | E-E510 | 0,90 € | ### Lindinger.at – 82,38 € + Versand 5,99 € {#lindinger-at-€82-38-shipping-€5-99-1} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 2 | Hobbywing UBEC-10A (V2-Car), 6,0 V | HW30603003 | 53,98 € | | 1 | LiPo-Sicherheitstasche | Robbe 23x30 cm (9787514) | 6,49 € | | 1 | LiPo-Zellprüfer / Unterspannungsalarm | Absima (9771616) | 5,95 € | | 1 | XT60H-Steckverbinder, 3 Paare (Akkuleitung, Arming-Port, Loop-Key) | Robbe XT60 3 Paare (9750234) | 4,99 € | | 1 | Silikonlitze 14 AWG / 2,5 mm², rot + schwarz, je 1 m | 20479 | 4,99 € | | 2 | Silikonlitze 18 AWG / 0,75 mm², rot + schwarz (je 1 m pro Einheit) | 44422 | 5,98 € | ### Welectron (DE) – 63,60 € + Versand 9,90 € {#welectron-de-€63-60-shipping-€9-90} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | Raspberry Pi Active Cooler | SC1148 | 4,90 € | | 1 | Raspberry Pi Camera Module 3 Wide | Camera Module 3 Wide | 35,90 € | | 1 | Waveshare 2" LCD-Modul, ST7789, 240x320 (17344) | 17344 | 10,90 € | | 1 | Raspberry Pi 27 W USB-C Netzteil, EU-Stecker (Tischversorgung ohne Akku) | SC1407 | 11,90 € | ### Reichelt.at – 55,12 € + Versand 6,95 € {#reichelt-at-€55-12-shipping-€6-95} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | Widerstand 2,2 kΩ 0,25 W (PCA9685-OE-Pull-up) | METALL 2,20K | 0,10 € | | 1 | 12 mm Taster (tastend), Edelstahl (ONPOW GQ12B-10S) | 318555 | 5,66 € | | 3 | ATO-Flachsicherung 25 A (Haupt, 1 + 2 Reserve) | 7786 | 1,08 € | | 2 | ATO-Flachsicherung 7,5 A (Logikzweig, 1 + 1 Reserve) | FKS 7,5 A (gleiche Serie wie 7786) | 0,72 € | | 8 | WAGO 221-415 Hebelklemme | 149800 | 6,48 € | | 1 | Schrumpfschlauch-Sortiment | 152924 | 5,39 € | | 1 | Spiralschlauch, schwarzes PE, für Bündel 4-10 mm (5-10 m) | CIMCO 186220 (10 m, Bündel 4-20 mm) | 4,84 € | | 2 | Selbstklebender Kabelbinder-Sockel 13 x 13 mm (HellermannTyton MB2APT-A) | HT 151-02243 (pro Stück) | 2,12 € | | 1 | Lötdraht, bleifrei, 0,8 mm, Flussmittelseele (50-100 g) | Goobay 420259 (50 g, SAC) | 13,61 € | | 1 | Klettbänder (Akkugurt) | 280182 | 5,14 € | | 1 | Doppelseitiges Schaum-Montageband, 19 mm | tesa PRO Universal 338987 | 9,98 € | ### Eckstein (DE) – 53,43 € + Versand 6,90 € {#eckstein-de-€53-43-shipping-€6-90} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | Adafruit INA260 Power-Monitor (4226) | Adafruit 4226 | 11,84 € | | 1 | Pololu D36V50F5 5 V 5,5 A Abwärtsspannungsregler | D36V50F5 | 41,59 € | _Versand nach AT erst an der Kasse angezeigt: 6,90 angenommen (UNVERIFIED)_ ### 3DJake.at – 27,37 € + Versand 5,49 € {#_3djake-at-€27-37-shipping-€5-49-1} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 × Packung à 10 | Kugellager 625ZZ (5x16x5) | 625ZZ 10er-Pack | 4,99 € | | 1 | Filament PETG, Graphit/Schwarz, 1 kg | ELG-50.203.0216 (Elegoo Rapid PETG schwarz) | 11,19 € | | 1 | Filament PETG, Limette/Gelb (Schalen), 1 kg | ELG-50.203.0221 (Elegoo Rapid PETG gelb) | 11,19 € | ### Schraubenking.at – 20,11 € + Versand 5,90 € {#schraubenking-at-€20-11-shipping-€5-90-2} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 × Packung à 100 | M3 x 10 DIN 912 A2 | M3x10 DIN912 A2, 100 | 2,35 € | | 1 × Packung à 10 | M3 x 20 DIN 912 A2 | M3x20 DIN912 A2, 10 | 0,97 € | | 1 × Packung à 100 | M3 DIN 985 Sicherungsmutter mit Nylonring | P000461 (verzinkt) | 1,39 € | | 3 × Packung à 10 | M2.5 x 5 DIN 912 A2 | P004986 | 2,49 € | | 1 × Packung à 10 | M2.5 x 6 DIN 912 A2 | P005010 | 0,83 € | | 2 × Packung à 10 | M2 x 5 DIN 912 A2 | P003957 | 1,72 € | | 1 × Packung à 10 | M2 x 10 DIN 912 A2 | P002803 | 0,78 € | | 1 × Packung à 100 | M2 Sechskantmutter DIN 934 A2 | P002807 | 1,87 € | | 1 × Packung à 100 | M2,5 Sechskantmutter DIN 934 A2 | P004196 | 2,00 € | | 1 | Schraubensicherung, mittelfest (blau) | Förch 10 ml (P002471) | 5,71 € | ### DigiKey.at – 10,80 € + Versand 25,00 € {#digikey-at-€10-80-shipping-€25-00} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | Pololu #2813 Big Pushbutton Power Switch HP | Pololu 2813 (Marketplace) | 10,80 € | ## Plan D: Original-Boards, wo verfügbar {#plan-d-genuine-boards-where-available} **987,73 €** in 8 Bestellungen. Bestellen Sie alles unten Aufgeführte; die Zwischensummen pro Shop ergeben diese Gesamtsumme. ### Amazon.de – 288,77 € + Versand 2,40 € {#amazon-de-€288-77-shipping-€2-40} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | microSD 64 GB A2 (SanDisk Extreme) | B09X7CXWQQ | 26,21 € | | 1 | Slamtec RPLIDAR C1 (mit USB-Adapter) | B0CP8YRY44 (WayPonDEV) | 70,58 € | | 2 × Packung à 5 | 25T Aluminium-Scheibenhorn | B07F71J1Q2 (DollaTek, 5er-Pack) | 10,06 € | | 1 × Packung à 5 | 25T Aluminium-Klemmarmhorn | B0F5QG8HQS (5er-Pack) | 9,06 € | | 2 × Packung à 2 | Kugellager 6805-2RS (25x37x7) | B0CL4Z679J (2er-Pack) | 13,48 € | | 1 × Packung à 8 | Kugellager 633ZZ (3x13x5) | B0GGT3GW69 (8er-Pack) | 10,27 € | | 1 × Packung à 50 | Sinterbronze-Gleitlager 3x5x5 | B0G15L264D (50er-Pack) | 10,27 € | | 1 | LiPo 2S 5000 mAh Hardcase, XT60, max 138 x 47 x 25 mm (Gens ace G-Tech) | B0GKP683YF | 22,18 € | | 1 | LiPo-Balancer-Ladegerät, Netzeingang (B6AC-Klasse) | B0F3CYZ6L8 (HTRC B6AC) | 46,38 € | | 1 × Packung à 10 | Inline-ATO-Sicherungshalter, 14-AWG-Leitungen (Haupt- + Logikzweig) | B07426WCLM (Nilight, 10 Halter) | 8,56 € | | 1 | Silikonlitze 22 AWG (Pi-5-V-Versorgung mit Dupont-Crimps, Taster, Jumper) | B0C7T9KYND (6 Farben x 4 m) | 12,10 € | | 1 × Packung à 3 | USB-A-auf-USB-C-Kabel, 20 cm, 90° (Pi → XIAO, Pi → LiDAR-Adapter) | B09ZDV7S44 (aceyoon 20 cm 90°, 3er-Pack) | 7,64 € | | 1 | Dupont-Jumper-Set 20 cm (F-F, M-M, F-M) | B0F98KBV61 (160 x F-F) | 8,05 € | | 1 | Dupont 2,54 mm Crimpkontakte und Gehäuse (1–6 Pin), für die abgelängten Signalleitungen | B0FP14VDGS (620 Stück) | 9,06 € | | 1 | M3-Zylinderschrauben-Set, Edelstahl (6-50 mm, Muttern, Unterlegscheiben; WZHUIDA 1080 Stk.) | B0D2VST57H | 17,14 € | | 1 × Packung à 40 | Abstandsbolzen M2 x 8 mm Buchse-Buchse, Messing | B0DR67YGQL | 7,73 € | _+2,40 österreichische Paketabgabe pro Bestellung_ ### DigiKey.at – 242,45 € + Versand 0,00 € {#digikey-at-€242-45-shipping-€0-00} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | Raspberry Pi 5, 4 GB | SC1431 (2648-SC1431-ND) | 117,18 € | | 1 | Raspberry Pi Active Cooler | SC1148 | 5,33 € | | 1 | Raspberry Pi Camera Module 3 Wide | SC1224 | 37,28 € | | 1 | Pi-5-Kamerakabel 22→15 Pin, 300 mm | SC1129 | 2,14 € | | 1 | Seeed XIAO ESP32-S3, Stiftleisten vorgelötet | 102010634 | 9,05 € | | 1 | PCA9685 16-Kanal-PWM-Board (Adafruit-815-Layout) | Adafruit 815 | 15,92 € | | 1 | Adafruit LSM6DSOX 6-DoF IMU (4438) | Adafruit 4438 | 12,73 € | | 1 | Adafruit INA260 Power-Monitor (4226) | Adafruit 4226 | 10,60 € | | 2 | STEMMA-QT-Kabel auf Buchsen, 150 mm (Adafruit 4397; IMU zu PCA9685 und IMU zu INA260) | Adafruit 4397 | 2,02 € | | 1 | Pololu #2813 Big Pushbutton Power Switch HP | Pololu 2813 (Marketplace) | 10,80 € | | 12 | Abstandsbolzen M2.5 x 6 mm Buchse-Buchse (Würth 970060151) | 970060151 | 6,62 € | | 1 | Raspberry Pi 27 W USB-C Netzteil, EU-Stecker (Tischversorgung ohne Akku) | SC1407 (nicht SC1153 = US-Stecker) | 12,78 € | ### AliExpress (DigitalServo Store) – 174,98 € + Versand 5,90 € {#aliexpress-digitalservo-store-€174-98-shipping-€5-90-1} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 13 | SPT5435LV-180W Servo, 35 kg·cm, 180° (12 + 1 Reserve) | 4000135787995, Variante 35kg-180 Waterproof | 174,98 € | _Servobestellung > 150 EUR fällt aus IOSS: in zwei Bestellungen teilen oder Einfuhrumsatzsteuer/Verzollung einplanen_ ### Lindinger.at – 82,38 € + Versand 5,99 € {#lindinger-at-€82-38-shipping-€5-99-2} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 2 | Hobbywing UBEC-10A (V2-Car), 6,0 V | HW30603003 | 53,98 € | | 1 | LiPo-Sicherheitstasche | Robbe 23x30 cm (9787514) | 6,49 € | | 1 | LiPo-Zellprüfer / Unterspannungsalarm | Absima (9771616) | 5,95 € | | 1 | XT60H-Steckverbinder, 3 Paare (Akkuleitung, Arming-Port, Loop-Key) | Robbe XT60 3 Paare (9750234) | 4,99 € | | 1 | Silikonlitze 14 AWG / 2,5 mm², rot + schwarz, je 1 m | 20479 | 4,99 € | | 2 | Silikonlitze 18 AWG / 0,75 mm², rot + schwarz (je 1 m pro Einheit) | 44422 | 5,98 € | ### Reichelt.at – 56,28 € + Versand 6,95 € {#reichelt-at-€56-28-shipping-€6-95-2} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | Widerstand 2,2 kΩ 0,25 W (PCA9685-OE-Pull-up) | METALL 2,20K | 0,10 € | | 1 | 12 mm Taster (tastend), Edelstahl (ONPOW GQ12B-10S) | 318555 | 5,66 € | | 3 | ATO-Flachsicherung 25 A (Haupt, 1 + 2 Reserve) | 7786 | 1,08 € | | 2 | ATO-Flachsicherung 7,5 A (Logikzweig, 1 + 1 Reserve) | FKS 7,5 A (gleiche Serie wie 7786) | 0,72 € | | 8 | WAGO 221-415 Hebelklemme | 149800 | 6,48 € | | 1 | Schrumpfschlauch-Sortiment | 152924 | 5,39 € | | 1 | Kabelbinder 100 x 2,5 mm (100) | Delock 19186 | 1,16 € | | 1 | Spiralschlauch, schwarzes PE, für Bündel 4-10 mm (5-10 m) | CIMCO 186220 (10 m, Bündel 4-20 mm) | 4,84 € | | 2 | Selbstklebender Kabelbinder-Sockel 13 x 13 mm (HellermannTyton MB2APT-A) | HT 151-02243 (pro Stück) | 2,12 € | | 1 | Lötdraht, bleifrei, 0,8 mm, Flussmittelseele (50-100 g) | Goobay 420259 (50 g, SAC) | 13,61 € | | 1 | Klettbänder (Akkugurt) | 280182 | 5,14 € | | 1 | Doppelseitiges Schaum-Montageband, 19 mm | tesa PRO Universal 338987 | 9,98 € | ### Eckstein (DE) – 55,86 € + Versand 6,90 € {#eckstein-de-€55-86-shipping-€6-90-1} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 | Waveshare 2" LCD-Modul, ST7789, 240x320 (17344) | Waveshare 2inch LCD | 14,27 € | | 1 | Pololu D36V50F5 5 V 5,5 A Abwärtsspannungsregler | D36V50F5 | 41,59 € | _Versand nach AT erst an der Kasse angezeigt: 6,90 angenommen (UNVERIFIED)_ ### 3DJake.at – 27,37 € + Versand 5,49 € {#_3djake-at-€27-37-shipping-€5-49-2} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 × Packung à 10 | Kugellager 625ZZ (5x16x5) | 625ZZ 10er-Pack | 4,99 € | | 1 | Filament PETG, Graphit/Schwarz, 1 kg | ELG-50.203.0216 (Elegoo Rapid PETG schwarz) | 11,19 € | | 1 | Filament PETG, Limette/Gelb (Schalen), 1 kg | ELG-50.203.0221 (Elegoo Rapid PETG gelb) | 11,19 € | ### Schraubenking.at – 20,11 € + Versand 5,90 € {#schraubenking-at-€20-11-shipping-€5-90-3} | Bestellung | Artikel | SKU | Kosten | |---|---|---|---| | 1 × Packung à 100 | M3 x 10 DIN 912 A2 | M3x10 DIN912 A2, 100 | 2,35 € | | 1 × Packung à 10 | M3 x 20 DIN 912 A2 | M3x20 DIN912 A2, 10 | 0,97 € | | 1 × Packung à 100 | M3 DIN 985 Sicherungsmutter mit Nylonring | P000461 (verzinkt) | 1,39 € | | 3 × Packung à 10 | M2.5 x 5 DIN 912 A2 | P004986 | 2,49 € | | 1 × Packung à 10 | M2.5 x 6 DIN 912 A2 | P005010 | 0,83 € | | 2 × Packung à 10 | M2 x 5 DIN 912 A2 | P003957 | 1,72 € | | 1 × Packung à 10 | M2 x 10 DIN 912 A2 | P002803 | 0,78 € | | 1 × Packung à 100 | M2 Sechskantmutter DIN 934 A2 | P002807 | 1,87 € | | 1 × Packung à 100 | M2,5 Sechskantmutter DIN 934 A2 | P004196 | 2,00 € | | 1 | Schraubensicherung, mittelfest (blau) | Förch 10 ml (P002471) | 5,71 € | ## Hinweise {#caveats} * Geringer Lagerstand zum Zeitpunkt der Recherche: 633ZZ 8er-Pack, Bronzebuchsen, Lindinger Hobbywing UBEC, Amazon-M2-Abstandsbolzen. Bestellen Sie diese zuerst oder verwenden Sie die Alternativen in `hardware/bom.yaml`. * Servos: Kaufen Sie die Variante SPT5435LV **-180W** (180°). Das Amazon-Angebot gibt den Winkel nicht an; die AliExpress-Bestellung überschreitet die IOSS-Grenze von 150 € (teilen Sie sie oder planen Sie Einfuhrumsatzsteuer ein). * DigiKey liefert aus den USA (verzollt, USt. enthalten). Pololu-Artikel auf DigiKey sind Marketplace-Artikel, die Pololu versendet; deren zusätzliche Versandgebühr ist nicht berücksichtigt. * DE-Shops zeigen die deutsche USt.; an der österreichischen Kasse kann ~1 % hinzukommen. * Klon-Boards sind für den PCA9685 (Adafruit-815-Footprint), Hörner und Sicherungshalter in Ordnung; kaufen Sie LiPo, LiDAR, Pi, Spannungsregler und UBECs im Original (nur Original-UBEC-Angebote sind gelistet). --- # Quellen der Preisrecherche {#price-research-sources} > **Was diese Seite ist:** Recherchenotizen — jedes Angebot, das pro Artikel gefunden wurde, einschließlich teurerer, nicht vorrätiger oder überholter Alternativen. Sie ist **keine** Bestellliste. Um den Roboter zu kaufen, verwenden Sie die [Einkaufsliste](shopping_list.md): Sie macht aus diesen Angeboten vier vollständige alternative Pläne mit ihren Gesamtsummen. Zwei Recherchedurchgänge (2026-10-30) haben die Stückliste für die Lieferung nach Österreich bepreist. Sie sind hier mit ihren URLs, Lagerhinweisen und Vorbehalten wiedergegeben; `hardware/bom.yaml` enthält die ausgewählten Angebote. Preise ändern sich: Prüfen Sie sie vor der Bestellung erneut. Durchgang 1 bepreiste einen früheren Entwurf des Designs (ESP32-S3 DevKitC, ein 20-A-BEC, Gewindeeinsätze, 4 Servo-Verlängerungen); seine Strategiesummen sind durch die [Einkaufsliste](shopping_list.md) überholt. Korrekturen, die für beide Durchgänge gelten: Der Bambu A1 mini (180-mm-Bett) ist zu klein für die 114 × 208 mm großen Schalen (verwenden Sie ein Bett ≥ 220 mm); der Pololu #2813 ist für 6 A Dauerstrom bei 55 °C ausgelegt (16 A nur bei 150 °C) und #2808 für 3 A bei 55 °C (Pololu-Produktseiten). Durchgang 2 bepreiste die Artikel, die das endgültige Design hinzugefügt oder geändert hat (XIAO ESP32-S3, zwei Hobbywing UBEC-10A, Pololu-Schalter, Drucktaster, 30-cm-Verlängerungen, M2/M2.5-Kleinteile). --- ## Strido-EU-Einkaufsliste für einen Bauer in Österreich: Preise, Händler und Bündelstrategien (2026-10-30) {#strido-eu-shopping-list-for-an-austrian-builder-prices-vendors-and-bundle-strategies-2026-10-30} **Antwort:** Drei Shops (DigiKey.at, Amazon.de und AliExpress) decken die gesamte Stückliste des Roboters für **969,59 €** inklusive Lieferung ab. Verteilt man die Bestellung auf sechs Shops, sinkt sie auf **908,31 €**. Ein Aufbau nur mit EU-Lagerware kostet etwa **1.149 €** zuzüglich der Versandkosten von Eckstein, die ich nicht sehen konnte. Alle drei Summen verwenden den Pi 5 4 GB und schließen Werkzeug und den 3D-Drucker aus. **Quellen:** - **Sub-Agents:** Die meisten Preise stammen von Seiten, die vier Recherche-Sub-Agents heute abgerufen haben. - **Amazon.de:** Ich habe jede in den Strategiesummen verwendete ASIN heute mit `curl` erneut abgerufen (Buy-Box-Preis und Lagerstand). - **DigiKey.at:** Die Preise wurden in einem Browser abgelesen und enthalten 20% österreichische USt. - **Conrad.at:** Die Preise werden ohne USt. angezeigt. Die Bruttowerte hier sind netto × 1,2, also **berechnet, nicht angezeigt**. - **DE-Shops (Welectron, Eckstein, kugellager-*, ruthex, MYBOTSHOP):** Sie zeigen 19% deutsche USt. Ob die Kasse auf die österreichischen 20% umstellt, ist UNVERIFIED. ## 1. Angebote pro Artikel {#_1-offers-per-item} ### 1a. Rechner, Kamera und Platinen {#_1a-compute-camera-and-boards} | Artikel (Anz.) | Händler | Produkt / SKU | € inkl. USt. | Lager | URL | |---|---|---|---|---|---| | Pi 5 4 GB (1) | **DigiKey.at** | SC1431 (neuere Revision von SC1111), 2648-SC1431-ND | **117,18** | 203 | digikey.at (Suche 2648-SC1431-ND) | | | Berrybase.at | RPI5-4GB | 123,90 | Begrenzt | https://www.berrybase.at/raspberry-pi-5-4gb-ram | | | Welectron | RP1-151400-P | 118,00 (DE-USt.) | Nicht vorrätig | https://www.welectron.com/Raspberry-Pi-5-4-GB-RAM | | | Reichelt.at | RASP PI 5 B 4GB | 137,55 | Vorbestellung | https://www.reichelt.at/at/de/shop/produkt/raspberry_pi_5_b_4x_2_4_ghz_4_gb_ram_wlan_bt-359842 | | Pi 5 8 GB (Option) | DigiKey.at | SC1432 | **186,42** | 19.766 | digikey.at | | | Welectron | RP1-151800-P | 189,00 | Vorrätig | https://www.welectron.com/Raspberry-Pi-5-8-GB-RAM_1 | | | Reichelt.at / Berrybase.at | – | 191,59 / 189,00 | Vorrätig / Begrenzt | reichelt …-359846 / https://www.berrybase.at/raspberry-pi-5-8gb-ram | | Active Cooler (1) | DigiKey / Welectron / Reichelt / Berrybase | SC1148 | 5,33 / 4,90 / 5,60 / 5,90 | Alle vorrätig (Berrybase begrenzt) | https://www.welectron.com/Offizieller-Raspberry-Pi-Active-Cooler | | 64 GB A2 microSD (1) | **Amazon.de** | SanDisk Extreme 64GB, B09X7CXWQQ | **26,21** | Vorrätig | https://www.amazon.de/dp/B09X7CXWQQ | | | Berrybase.at | SanDisk Extreme A2 64GB | 25,90 | Begrenzt | https://www.berrybase.at/sandisk-extreme-microsdxc-a2-uhs-i-u3-v30-170mb-s-speicherkarte-adapter-64gb | | | Reichelt.at | Offizielle Raspberry Pi A2 64GB | 44,62 | Vorrätig | https://www.reichelt.at/at/de/shop/produkt/raspberry_pi_-_microsd-karte_a2-class_64_gb-383381 | | Cam Module 3 **Wide** (1) | DigiKey.at | SC1224, 2648-SC1224-ND | 37,28 | 6.881 | digikey.at | | | Welectron | Offizielle CM3 Wide | **35,90** | Vorrätig | https://www.welectron.com/Official-Raspberry-Pi-Camera-Module-3-Wide | | | Berrybase / Reichelt | – | 39,90 / 38,32 | Ausverkauft / Nicht vorrätig | https://www.berrybase.at/raspberry-pi-camera-module-3-wide-12mp | | Cam Module 3 Standard (Option) | Welectron / Berrybase / Reichelt | – | 25,90 / 28,90 / 30,15 | Vorrätig / Begrenzt / Vorrätig | https://www.welectron.com/Official-Raspberry-Pi-Camera-Module-3 | | Pi-5-Kamerakabel, 200 mm (1) | DigiKey / Berrybase / Welectron | SC1892 / RPI-CC-SM-20 / – | 1,07 / 1,20 / 1,90 | Vorrätig | https://www.berrybase.at/raspberry-pi-camera-cable-standard-mini-200mm | | 27-W-USB-C-Netzteil, EU-Stecker | DigiKey (SC1407) / Welectron / Berrybase | – | 12,78 / 11,90 / 12,40 | Vorrätig | DigiKey führt auch SC1153, das ist die Version mit **US-Stecker**; nicht bestellen | | ESP32-S3-DevKitC-1-**N16R8**, original | Reichelt.at | 444792 | 17,75 | **Nicht vorrätig** | https://www.reichelt.at/at/de/shop/produkt/entwicklungsboard_esp32-s3-wroom-1-n16r8-444792 | | | soyter.pl | Original Espressif | 20,87 (USt.-Basis unklar) | **Nicht vorrätig** | https://soyter.pl/en/products/espressif-esp32-s3-devkitc-1-n16r8-development-board-4875.html | | | DigiKey.at / Mouser.at | – | nicht gelistet / UNVERIFIED (Bot-Sperre) | – | – | | ↳ Original-Alternative | DigiKey.at | ESP32-S3-DevKitC-1-**N32R16V** | 17,42 | 53 | digikey.at. Verwendet Octal-PSRAM mit 1,8 V, daher sind GPIO35–37 nicht nutzbar | | ↳ Klon N16R8 | Amazon.de | B0FYFF8CB2 | **10,07** | Vorrätig | https://www.amazon.de/dp/B0FYFF8CB2 | | | makeroo.de | ESP32-S3 N16R8 DevKit (hergestellt in China; Kleinunternehmen, keine USt. berechnet) | 7,99 | – | https://makeroo.de/products/esp32-s3-n16r8-dev-kit-dual-usb-c-16mb-flash-8mb-psram-ai-optimiert-wifi-bluetooth-microcontroller (Versand nach AT UNVERIFIED) | | PCA9685 (1) | DigiKey.at | Adafruit 815, 1528-815-ND | 15,92 | 366 | digikey.at | | | Amazon.de | JZK-Klon, B06XSFFXQY | **6,95** | – | https://www.amazon.de/dp/B06XSFFXQY | | | Amazon.de | DollaTek-Klon, B0BKZC1XWR | 7,04 | noch 10 | https://www.amazon.de/dp/B0BKZC1XWR | | | Eckstein | QITA-Klon | 10,50 | Vorrätig | https://eckstein-shop.de/16CH-Servomotor-Treiber-Modul-PCA9685-PWM-fuer-Arduino-Raspberry-Pi | | LSM6DSOX IMU (1) | DigiKey.at | Adafruit 4438 | **12,73** | 270 | digikey.at | | | Amazon.de | B085F3F19D | 20,16 | noch 3 | https://www.amazon.de/dp/B085F3F19D | | | Berrybase.at | ADA4438 | 11,90 | Ausverkauft | https://www.berrybase.at/adafruit-lsm6dsox-6-dof-beschleugnigunssensor-und-gyroskop | | INA260 (1) | DigiKey.at | Adafruit 4226 | **10,60** | 1.375 | digikey.at | | | Eckstein | 4226 | 11,84 | Vorrätig | https://eckstein-shop.de/AdafruitINA260HighorLowSideVoltage2FCurrent2FPowerSensor | | | Berrybase | ADA4226 | 10,95 | Ausverkauft | https://www.berrybase.at/adafruit-ina260-high-oder-low-side-spannungs-strom-und-leistungs-sensor | | Waveshare 2" LCD, ST7789 (1) | Welectron | 17344 | **10,90** | Vorrätig | https://www.welectron.com/Waveshare-17344-2inch-LCD-Module_1 | | | Amazon.de | B081NBBRWS | 20,16 | Vorrätig | https://www.amazon.de/dp/B081NBBRWS | | | Eckstein | – | 14,27 | Vorrätig | https://eckstein-shop.de/WaveShare-240320-General-2inch-IPS-LCD-Display-Module | | Pololu D36V50F5 (1) | DigiKey.at | Pololu 4091, 2183-4091-ND (DigiKey Marketplace) | 48,24 | 215 | digikey.at | | | Eckstein | – | **41,59** | Vorrätig | https://eckstein-shop.de/Pololu-5V-55A-Step-Down-Voltage-Regulator-D36V50F5-EN | | | Berrybase | – | 34,95 | Ausverkauft | https://www.berrybase.at/pololu-d36v50f5-5v-5-5a-step-down-spannungsregler | | STEMMA-QT-Kabel, 100 mm (3) | DigiKey.at | Adafruit 4210 | **1,01 pro Stück** | 17.267 | digikey.at | | | Amazon.de | 12-teiliges JST-SH-4-Pin-Set, B0HB5F48YD | 9,06 | Vorrätig | https://www.amazon.de/dp/B0HB5F48YD | | | Eckstein / Berrybase | – | 2,25 / 1,90–2,30 | Nicht vorrätig | – | ### 1b. LiDAR, Servos, Servohörner {#_1b-lidar-servos-horns} | Artikel (Anz.) | Händler | Produkt / SKU | € inkl. USt. | Lager | URL | |---|---|---|---|---|---| | RPLIDAR C1 (1) | Amazon.de (WayPonDEV) | B0CP8YRY44 | **70,58** | Versand in 4–5 Tagen | https://www.amazon.de/dp/B0CP8YRY44 | | | Amazon.de (Waveshare) | B0CT31PH8S | 103,86 | Vorrätig | https://www.amazon.de/dp/B0CT31PH8S | | | Génération Robots | A-000000-06970 | 81,12 (netto 67,60 × 1,2, berechnet) | Nicht angezeigt | https://www.generationrobots.com/de/404200-telemetre-laser-360-rplidar-c1-slamtec.html | | | MYBOTSHOP.DE | – | 99,95 (DE-USt.) | Vorrätig | https://www.mybotshop.de/SLAMTEC-RPLIDAR-C1-360-Laser-Scanner-12-m | | SPT5435LV-180W (13) | AliExpress "DigitalServo Store" | 4000135787995, Variante „35kg-180 Waterproof“ | **13,46** (mit Alu-Servohorn Arm/Disc: 14,21); Versand 5,90 € | 8.515 | https://de.aliexpress.com/item/4000135787995.html | | | Amazon.de | „SPT5435LV“, B0H17Y4KS2 — **Drehwinkel nicht angegeben** | 23,99 | Vorrätig | https://www.amazon.de/dp/B0H17Y4KS2 | | | Amazon.de | B0G39ZHL4B | 22,48 | noch 3 | https://www.amazon.de/dp/B0G39ZHL4B | | | Banggood | -180 (nicht wasserdicht), p-1577509 | US\$27,99 (≈25,05) | UNVERIFIED | banggood.com | | 25T-Alu-Scheibenhorn (4) | Amazon.de (DollaTek) | 5er-Pack, B07F71J1Q2 | 5,03 | Vorrätig | https://www.amazon.de/dp/B07F71J1Q2 | | 25T-Alu-Klemmarm (4) | Amazon.de | 5er-Pack, B0F5QG8HQS | 9,06 | noch 17 | https://www.amazon.de/dp/B0F5QG8HQS | | | Lindinger | SAVÖX 25T einzeln | 7,90 pro Stück | Vorbestellung | https://www.lindinger.at/de/RC-Elektronik/RC-Produkte/Servos-Zubehoer/SAVOEX-Servo-Horn-Single-Alu-High-Torque-25T-Servohebel-Alu/9798687 | | Servohörner, günstigster Weg | AliExpress | Servo als Variante „WP Arm“ oder „WP Disc“ gekauft | +0,75 pro Servo | – | Dieselbe Artikelseite wie die Servos | ### 1c. Stromversorgung {#_1c-power} | Artikel (Anz.) | Händler | Produkt / SKU | € inkl. USt. | Lager | URL | |---|---|---|---|---|---| | Servo BEC | Lindinger | **Hobbywing UBEC-10A V2-Car (P/N 30603003)**: 2–6S Eingang, 6,0/7,4/8,4 V Ausgang, 10 A Dauer / 15 A Spitze ([Handbuch](https://oss.hobbywing.com/pdf/pdfen/UBEC10ACar.pdf)); der Flugzeug-UBEC-10A (P/N 30603000, 20 A Spitze) ist ein anderes Gerät | 26,99 pro Stück (Aktion) | Nur noch wenige | https://www.lindinger.at/de/RC-Elektronik/Stromversorgung-Bus-Systeme/Akkuweichen-Spannungsregler-BEC/HOBBYWING-BEC-10A-V2-Car-UBEC-Regler-fuer-2-6s/9787110 | | | Amazon.de | SPARKHOBBY-10A-UBEC-Klon, B0DK31PYFZ | 26,63 pro Stück | noch 3 | https://www.amazon.de/dp/B0DK31PYFZ | | | Amazon.de | Suoumwa „20A SBEC“, B0D4YCJWR3 (Dauerbelastbarkeit und minimale Eingangsspannung UNVERIFIED) | 37,75 | Vorrätig | https://www.amazon.de/dp/B0D4YCJWR3 | | | Motion RC EU | Castle CC BEC Pro 20A, 010-0004-01 (15 A Dauer bei 2S, laut Sub-Agent) | 56,99 | Nicht angezeigt | https://motionrc.com/eu/products/castle-creations-20a-bec-pro-010-0004-01 | | LiPo 2S 5000 mAh, XT60 (1) | Amazon.de | Gens ace G-Tech 60C, 138×47×25 mm, B0GKP683YF | **22,18** | Vorrätig | https://www.amazon.de/dp/B0GKP683YF | | | Amazon.de | Zeee 5200 80C, 2er-Pack, B08X4GF9DK | 41,34 für 2 | Vorrätig | https://www.amazon.de/dp/B08X4GF9DK | | | Lindinger | Robbe RO-POWER 5000 2S 35C, 139×46,8×25,9 mm (0,9 mm über der Höhengrenze) | 32,99 | Nur noch wenige | https://www.lindinger.at/de/RC-Elektronik/Antriebe/Akkus/Robbe-Modellsport-RO-POWER-ULTRA-MAXAMP-CAR-5000MAH-7-4-VOLT-2S-35-70-C-LIPO-AKKU-T-XT-60-Stecker/9767786 | | | Stefansliposhop | SLS XTRON 5000 2S 50C Hardcase (4-mm-Goldstecker) | 42,50 | 1–3 Tage | https://www.stefansliposhop.de/en/batteries/sls-xtron/sls-xtron-car/sls-xtron-5000mah-2s1p-7-4v-50c-100c-hardcase-steckkontakte::1105.html | | Ladegerät, AC-Eingang | Amazon.de | HTRC B6AC 80 W, B0F3CYZ6L8 | **46,38** | Vorrätig | https://www.amazon.de/dp/B0F3CYZ6L8 | | | Robitronic (AT) | SkyRC B6AC V2, original | 61,90 | Vorrätig | https://shop.robitronic.com/de/skyrc-b6ac-v2-ladegeraet-sk100008 | | | Lindinger | SkyRC B6AC Neo / ISDT 608AC | 64,99 / 63,99 | Nur noch wenige | lindinger.at (9798342 / 9771152) | | LiPo-Tasche | Lindinger / Amazon | Robbe 23×30 cm / FLASLD, B09C31KVK1 | 6,49 / 14,11 | – | lindinger.at 9787514 / https://www.amazon.de/dp/B09C31KVK1 | | LiPo-Tester | Lindinger / Amazon | Absima / ARCELI, B077Z1N9CS | 5,95 / 6,04 | – | lindinger.at 9771616 / https://www.amazon.de/dp/B077Z1N9CS | | XT60-Paare | Amazon.de | Original Amass XT60H, 3 Paare, B07C3KH1VT | 6,44 | Vorrätig | https://www.amazon.de/dp/B07C3KH1VT | | | Lindinger / Reichelt | Robbe, 3 Paare / Jamara, 1 Paar | 4,99 / 2,01 | – | lindinger.at 9750234 / reichelt.at 207648 | | ATO-Sicherungshalter + 25-A-Sicherung | Reichelt.at | Halter 325426 + Sicherung 7786 | 3,02 + 0,36 pro Stück | Vorrätig | reichelt.at (325426, 7786) | | | Amazon.de | Halter 5er-Pack (mit 20-A-Sicherungen), B0B4MWDFD8 + 25-A-Sicherungen ×10, B09ZXRZLV8 | 8,05 + 4,02 | Vorrätig | https://www.amazon.de/dp/B0B4MWDFD8 · https://www.amazon.de/dp/B09ZXRZLV8 | | Hauptschalter ≥30 A | Amazon.de | XT60-Inline-Schalter 30 A, B0FG2NTYXF | 11,09 | noch 7 | https://www.amazon.de/dp/B0FG2NTYXF | | Silikonlitze 14 / 18 / 22 AWG | Amazon.de | B0C53D343Y (5 m) / B0D12R349S (5+5 m) / B0C7T9KYND (6×4 m) | 12,10 / 9,06 / 12,10 | Vorrätig | amazon.de/dp/… | | | Lindinger | 2,5 mm² / 0,75 mm², je 1 m rot + 1 m schwarz | 4,99 / 2,99 | – | lindinger.at 20479 / 44422 | | Wago 221-415 (4) | Reichelt.at | 149800 | 0,81 pro Stück | Vorrätig | reichelt.at 149800 | | | Amazon.de | 25er-Pack, B0107SYYGU | 14,11 | Vorrätig | https://www.amazon.de/dp/B0107SYYGU | | Servo-Verlängerung 15 cm (6) | Amazon.de | 5er-Pack, B081NVPRNG (2 kaufen) | 6,54 pro Packung | noch 20 | https://www.amazon.de/dp/B081NVPRNG | | | Lindinger | Multiplex | 3,90 pro Stück | – | lindinger.at 67983 | | Dupont F-F / Schrumpfschlauch / Kabelbinder / Spiralschlauch | Reichelt.at | 282699 / 152924 / 280182 (Klett) / 332584 | 1,11 / 5,39 / 5,14 / 2,50 | Vorrätig | reichelt.at | | | Amazon.de | B01EV70C78 / B071D7LJ31 / B0BFVRQVFP / B093SQP3PZ | 7,04 / 8,56 / 7,04 / 6,16 | Vorrätig | amazon.de/dp/… | ### 1d. Mechanik {#_1d-mechanical} | Artikel (Anz.) | Händler | Produkt / SKU | € inkl. USt. | Lager | URL | |---|---|---|---|---|---| | 625ZZ (4) | 3DJake.at | 10er-Pack | **4,99** | Vorrätig | https://www.3djake.at/3djake/kugellager?sai=33676 | | | Amazon.de | QUARKZMAN 15er-Pack, B0CM8TYDR6 | 7,36 | Vorrätig | https://www.amazon.de/dp/B0CM8TYDR6 | | | kugellager-express.de | 625-ZZ | 0,88 pro Stück ab 4 (DE-USt.) | Verfügbar | https://www.kugellager-express.de/miniatur-kugellager-625-ZZ-5x16x5-mm | | | 123kugellager.at | 625-ZZ | 1,60 pro Stück | 50+ | 123kugellager.at | | 6805-2RS (4) | Amazon.de | QUARKZMAN 2er-Pack, B0CL4Z679J (2 kaufen) | 6,74 pro Packung | Vorrätig | https://www.amazon.de/dp/B0CL4Z679J | | | kugellager-express.de | 6805/61805-2RS | **1,70 pro Stück** ab 4 | Verfügbar | https://www.kugellager-express.de/rillenkugellager-6805-61805-2rs-25x37x7-mm | | | kugellager-shop.net / 123kugellager.at | – | 1,90 / 4,36 pro Stück | Vorrätig | – | | 633ZZ (8) | Amazon.de | QUARKZMAN 8er-Pack ABEC5, B0GGT3GW69 | **10,27** | **noch 3** | https://www.amazon.de/dp/B0GGT3GW69 | | | 123kugellager.at | 633-ZZ | 2,04 pro Stück (16,32 für 8) | 50+ | 123kugellager.at | | Gleitlager 3×5×5 (32) | Amazon.de | QUARKZMAN Sinterbronze, 50er-Pack, B0G15L264D | **10,27** | **noch 4** | https://www.amazon.de/dp/B0G15L264D | | | Amazon.de | Gerollte Buchse 10er-Pack, B0CWRXCWF9 | 5,44 pro Packung | Vorrätig | – | | | igus.at | iglidur G **GSM-0304-05 (3×4,5×5)**; Preise exkl. USt. angezeigt | 50 Stk. = 18,50 netto (22,20 brutto, berechnet) | 24–48 h | https://www.igus.at/iglidur-ibh/zylindrische-gleitlager/product-details/iglidur-g-m?artnr=GSM-0304-05 | | M3-Zylinderschrauben-Sortiment | Amazon.de | WZHUIDA 1080 Stk., Edelstahl (je 40 × 6/8 mm; je 30 × 10/12/14/16/18/20; je 20 × 25/30/35/40/50; dazu 360 Muttern, 360 Unterlegscheiben), B0D2VST57H | **17,14** | noch 17 | https://www.amazon.de/dp/B0D2VST57H | | | Schraubenking.at | DIN 912 A2, lose Packungen: 6–16 mm zu je 100 um 2,04–2,35 €; 18–35 mm zu je 10 um 0,83–0,97 € (pro Packung günstiger ab 3 Packungen) | siehe links | Vorrätig | https://www.schraubenking.at/Zylinderschrauben__M3__Edelstahl-A2-/-V2A | | M3-Sicherungsmutter DIN 985 (100) | Schraubenking / Amazon | P000454 / B0GXYB1TWK | 2,30 / 7,04 | Vorrätig | schraubenking.at / https://www.amazon.de/dp/B0GXYB1TWK | | M3-Gewindeeinsätze (Einschmelzmuttern) (30) | Amazon.de | ORTAVA M3×5.7, 100er-Pack, B0CNGHVWHC | **7,04** | Vorrätig | https://www.amazon.de/dp/B0CNGHVWHC | | | 3DJake.at / ruthex.de | ruthex RX-M3x5.7, 100er-Pack (kein 50er-Pack erhältlich) | 8,99 | Vorrätig | https://www.3djake.at/ruthex/gewindeeinsatz-m3-100-stueck | | M2.5-Abstandsbolzen-Set | Amazon.de | GeeekPi 220 Stk. Messing, B07PHBTTGV | 12,10 | Vorrätig | https://www.amazon.de/dp/B07PHBTTGV | | M2-Schrauben (20) | Schraubenking.at | M2×6 DIN 912 A2, 10er-Pack | 0,88 pro Packung | Vorrätig | https://www.schraubenking.at/M2-x-6mm-Zylinderschrauben-DIN912-Edelstahl-A2-P003960 | | | Amazon.de | 660-teiliges M2-Set (Flachkopf), B0DJ948G7K | 8,05 | Vorrätig | https://www.amazon.de/dp/B0DJ948G7K | | Filament, 2 × 1 kg | 3DJake.at | Elegoo PLA schwarz / gelb | **10,39 / kg** | Vorrätig | https://www.3djake.at/elegoo/pla-schwarz-5 | | | Extrudr (Österreich) | PLA NX2 Matt (−40% Aktion) | 15,59 / kg | Vorrätig | https://extrudr.com/de/at/products/pla-nx2-matt | | | Amazon.de | Sunlu PLA schwarz, B0BTHSX6S3 / hellgelb, B0FLWKNF2G | 13,10 / 15,12 | Vorrätig | amazon.de/dp/… | | | Bambu EU / Polymaker (3DJake) / Prusament | PLA Basic / PolyTerra / Prusament PLA | 16,99 Nachfüllpack · 19,99 mit Spule / 14,99 / 26,39 | Vorrätig | eu.store.bambulab.com/products/pla-basic-filament | ### 1e. Werkzeug (optional; Preise vom Werkzeug-Sub-Agent) {#_1e-tools-optional-prices-from-the-tools-sub-agent} | Werkzeug | Auswahl (Händler, Preis €) | Alternativen | |---|---|---| | Drucker | Bambu A1 mini, 180³-Bett: **179** + 10 € Versand (eu.store.bambulab.com/products/a1-mini) | A1 Combo 339 (A1 ohne AMS lite: UNVERIFIED); Prusa MK4S Bausatz 719 / montiert 999; CORE One+ 1.049 Bausatz / 1.349 montiert (prusa3d.com). Black-Friday-Preise | | Innensechskantschlüssel | Wera 950/9 Hex-Plus, Amazon 28,22 (B009ODV0OE) | Conrad Wera 950 SPKL ≈31,99 (berechnet) | | Lötkolben + Einsatzspitzen | Miniware TS101 74,62 (B0CPDRQZYB) + ruthex-Spitzenset 17,04 (B0DP51DDF7) + Adapter 13,10 (B0CTQV11YC) | Pinecil 82,14; günstig: Beizkna 22,16 + Preciva-Spitzen 25,61 (Passung der Spitzen UNVERIFIED) | | Abisolierzange / Crimpzange | Jokari Super 4 plus 14,06 / DxCRIMP-Set mit Steckern 30,22 | iCrimp SN-2549 26,21; Knipex 12 62 180 bei Conrad ≈34,50 | | Multimeter / Messschieber / Seitenschneider | Kaiweets 46,28 / Kynup 18,94 / Wiha 26812 16,09 | Voltcraft VC131 bei Conrad ≈29,99; Knipex 78 61 125 ≈20,99 | | Bohrer, Gewindebohrer, Feilen | Bosch 3 mm ×10: 6,04; Bosch 5 mm: 1,91 (B078W5CF3D); Gewindebohrer-Set mit Windeisen: 9,95; KS-Feilen: 6,85; Entgrater: 9,06 | RS-M3-Gewindebohrer bei Conrad ≈3,34 | | Schraubensicherung / Sekundenkleber | Loctite 243, 5 ml: 8,11 / Pattex Ultra Gel: 5,80 | – | | **Zwischensumme Werkzeug, alles Amazon** | **306,29 €** (Variante mit günstigem Lötkolben 249,30 €); versandkostenfrei, wenn zur Amazon-Bestellung des Roboters hinzugefügt | Drucker zusätzlich: 189 € (A1 mini + Versand) | ## 2. Versand nach Österreich {#_2-shipping-to-austria} | Händler | Versand nach AT | Versandfrei ab | Quelle | |---|---|---|---| | DigiKey.at | 25 € | **75 €** | Banner auf der Produktseite von digikey.at. Ob Marketplace-Artikel (der Pololu) mitzählen, ist UNVERIFIED | | Amazon.de | 3,99 € nach Hause / 1,99 € Abholstation (von Amazon versandte Artikel) | **39 €** | https://www.amazon.de/gp/help/customer/display.html?nodeId=GESTJTJG49FEM5SV | | Amazon.de-Paketsteuer | **+2,40 € pro Bestellung** (österreichische Paketsteuer, an der Kasse berechnet) | – | https://www.amazon.de/gp/help/customer/display.html?nodeId=TjkNaI0ZNMEFZXbP1q · BMF: https://www.bmf.gv.at/en/topics/taxation/parcel_delivery_tax_overview_and_faq.html | | Berrybase.at | DHL 5,95 € | 200 € auf der Versandseite; 150 € im Banner (widersprüchlich) | https://www.berrybase.at/footer-at/informationen/versand-und-zahlungsbedingungen | | Reichelt.at | DPD 6,95 € | UNVERIFIED | https://www.reichelt.at/at/de/shop/service/-12_28 | | Welectron | UPS 9,90 € (≤2 kg) / DHL 14,90 € | 200 € (DHL) | https://www.welectron.com/Zahlung-und-Versand | | Eckstein | UNVERIFIED (nur im Warenkorb angezeigt) | UNVERIFIED | https://eckstein-shop.de/Informationen-zum-Versand | | Lindinger.at | 5,99 € | 89 € (nicht für Gefahrgut oder Sperrgut) | https://www.lindinger.at/de/Modellbau-Lindinger/Versandkosten/ | | 3DJake.at | 5,49 € | 49,90 € | https://www.3djake.at/info/versand-und-lieferung | | Schraubenking.at | 5,90 € | 99 € | https://www.schraubenking.at/Versandinformationen | | kugellager-express.de / kugellager-shop.net | 8,90 € / 8,50 € | Keine für AT | https://www.kugellager-express.de/Zahlungsarten-Versand | | ruthex.de | 9,90 € | 80 € | https://www.ruthex.de/policies/shipping-policy | | Extrudr | ab 6,90 € | 5 Artikel | https://extrudr.com/de/at/page/shipping/ | | Bambu EU | Drucker 10 €; Filament 10 € | Filament ab 55 €; Drucker nie versandfrei | https://eu.store.bambulab.com/policies/shipping-policy | | Robitronic / Motion RC EU | 5,90 € / 6,99 € | – / 99 € | shop.robitronic.com/de/versandkosten · https://www.motionrc.eu/pages/shipping-policy | | Stefansliposhop | UPS 16,61 € | Keine gefunden | https://www.stefansliposhop.de/en/shipping-costs:_:1.html | | Conrad.at | 6,99 € | 69 € | https://www.conrad.at/de/service/versandkosten.html | | AliExpress DigitalServo / Fidurobot | 5,90 € / versandfrei ab 10 € | – | Artikelseiten | | igus, 123kugellager, Génération Robots, MYBOTSHOP, Banggood, DFRobot, HobbyKing (gesperrt) | UNVERIFIED | UNVERIFIED | – | ## 3. Bündelstrategien {#_3-bundle-strategies} Diese decken die vollständige Stückliste des Roboters mit dem Pi 5 4 GB, einem Camera Module 3 Wide, 13 Servos (12 + 1 Ersatz), 4 Scheiben- + 4 Arm-Servohörnern und 2 kg PLA ab. Werkzeug und Drucker sind ausgeschlossen. Preise gemäß Abschnitt 1. | Shop | (a) Wenigste Shops: Zwischensumme + Versand = Summe | (b) Niedrigste Summe | (c) Am schnellsten, nur EU-Lager | |---|---|---|---| | DigiKey.at | Pi, Kühler, CM3W, Kabel, Netzteil, Original-ESP32 N32R16V, Ada 815, 4438, 4226, 4210 ×3, Pololu: 281,57 + 0 = **281,57** | Dasselbe ohne ESP32 und 815: 248,23 + 0 = **248,23** | – (Versand aus den USA) | | Amazon.de | Alles andere in der EU: LiDAR (WayPonDEV), LCD, SD, LiPo, HTRC-Ladegerät, 2× SPARKHOBBY BEC, gesamte Verkabelung, Lager, Buchsen, Schrauben, Gewindeeinsätze, Abstandsbolzen, Sunlu PLA ×2: 498,74 + 0 + 2,40 = **501,14** | LiDAR, LCD, SD, LiPo, Ladegerät, Schalter, 6805, 633, Buchsen, M3-Set, Sicherungsmuttern, Gewindeeinsätze, Abstandsbolzen, M2, Verlängerungen, Kabelbinder, 22 AWG, Klon-ESP32 + PCA9685: 331,23 + 2,40 = **333,63** | Artikel aus (a) plus Waveshare C1 (103,86, vorrätig), Ada 4438, JST-SH-Set, Klon-ESP32, 13× Amazon „SPT5435LV“ (311,87), Servohorn-Packs: 850,90 + 2,40 = **853,30** | | AliExpress (DigitalServo) | 4× WP Arm + 4× WP Disc + 5× WP: 180,98 + 5,90 = **186,88** | Dasselbe: **186,88** | – | | Reichelt.at | – | Wago ×4, ATO-Halter, 2× 25-A-Sicherung, Dupont, Schrumpfschlauch, Spiralschlauch: 15,98 + 6,95 = **22,93** | – | | Lindinger.at | – | 2× Hobbywing UBEC 10A V2, Tasche, Tester, 2,5 mm² + 0,75 mm² Litze, XT60 ×3 Paare: 79,39 + 5,99 = **85,38** | – | | 3DJake.at | – | Elegoo PLA schwarz + gelb, 625ZZ 10er-Pack: 25,77 + 5,49 = **31,26** | – | | Berrybase.at | – | – | Pi 4 GB, Kühler, SD, Kabel, Netzteil: 169,30 + 5,95 = **175,25** | | Welectron | – | – | CM3 Wide, LCD: 46,80 + 9,90 = **56,70** | | Eckstein | – | – | Pololu, INA260, PCA9685-Klon: 63,93 + Versand UNVERIFIED | | **Gesamtsumme** | **969,59 €** (3 Shops) | **908,31 €** (6 Shops) | **1.149,18 € + Versand Eckstein** (4 Shops) | **Zielkonflikte in den Summen:** - **Shops aus (b) streichen:** Ohne 3DJake kostet es +4,32 €, ohne Lindinger +15,63 € und ohne Reichelt +25,01 €. - **Original-Platinen in (b):** Der Original-ESP32 (N32R16V) und der Adafruit 815 statt Klonen kosten 16,32 € mehr, also 924,63 €. - **Pi 5 8 GB:** kostet bei DigiKey 69,24 € mehr. - **Vorbehalte zu Strategie (c):** - Das Amazon-SPT-Angebot nennt den Drehwinkel nicht; eine 90°- oder 270°-Ausführung würde die Gelenkzuordnung zerstören. Klären Sie das mit dem Verkäufer, bevor Sie 13 Stück kaufen. - „Vorrätig“ bei Berrybase bedeutet LimitedAvailability. - Kein EU-Shop hatte den Original-N16R8-ESP32 oder den Adafruit LSM6DSOX in nennenswerter Menge; Amazon hat noch 3 Stück der IMU. - **Lagerbestände, die eine Summe ändern könnten:** Amazons 633ZZ (noch 3), Bronzebuchsen (noch 4), SPARKHOBBY BEC (noch 3) und Lindingers Hobbywing (nur noch wenige). Bestellen Sie diese zuerst. ## 4. AliExpress und andere Nicht-EU-Optionen {#_4-aliexpress-and-other-non-eu-options} | Artikel | Angebot | € | Hinweis | |---|---|---|---| | SPT5435LV-180W ×13 | DigitalServo Store, Artikel 4000135787995 | 13,46 pro Stück (14,21 mit Servohorn) + 5,90 | Meistverkauftes Angebot mit dem vollen SPT-Sortiment. Laut einer Suchzusammenfassung ist es der Exklusivvertrieb von SPT (UNVERIFIED). Das 10er-Pack (155,16) kostet mehr als 10 Einzelstücke (134,60) | | RPLIDAR C1 | Hefei Fidurobot, 1005006190309082 / FD Robot, 1005008790608977 | 66,29 / 65,01, versandkostenfrei | Keiner ist ein offizieller Slamtec-Store; nur 4–5 € günstiger als Amazon.de | | RPLIDAR C1 | DFRobot DFR1138 | US\$69 (≈61,76 netto) | Versand und Einfuhrumsatzsteuer UNVERIFIED | | ESP32-S3-N16R8-Klon | Artikel 1005006240070551 | US\$4,49 (nur Suchergebnis-Auszug, UNVERIFIED) | – | **Regeln für Nicht-EU-Bestellungen:** - **3 € Zoll pro Artikel:** Seit 1. Jul 2026 erhebt die EU pauschal 3 € pro Artikel (gezählt pro Tarifposition, nicht pro Stück) auf Sendungen bis 150 €. Der Verkäufer zahlt ihn ([EU-Kommission](https://taxation-customs.ec.europa.eu/news/guidance-and-legal-text-temporary-flat-fee-low-value-imports-which-will-apply-until-1-july-2028-2026-06-08_en)). - **2 € Bearbeitungsgebühr:** Ab 1. Nov 2026 fallen zusätzlich 2 € pro Artikel an ([vienna.at](https://www.vienna.at/temu-und-shein-neue-2-euro-gebuehr-ab-november/10583882)). Sie kann über die Preise weitergegeben werden. - **Die Servo-Bestellung liegt über 150 €.** IOSS (USt. an der Kasse erhoben) gilt nur für Sendungen bis 150 € ([Revenue.ie](https://www.revenue.ie/en/vat/vat-ecommerce/import-oss/index.aspx)). Darüber gilt das normale Einfuhrverfahren, rechnen Sie also mit möglicher USt. und Verzollungsgebühren des Zustellers. Eine Aufteilung in zwei Bestellungen mit 7 + 6 Servos (je etwa 90 €) bleibt für +5,90 € Versand unter der Grenze. Wie AliExpress damit umgeht, ist UNVERIFIED. - **Lieferung und Qualität:** Die Lieferung ist langsam; das Qualitätsrisiko ist für Servohörner, Lager, den PCA9685 und den ESP32 vertretbar. **Kaufen Sie dort keinen LiPo, kein Ladegerät und kein LiDAR.** ## 5. Wo ein Klon genügt und wo das Original zählt {#_5-clone-fine-vs-genuine-matters} | Klon oder No-Name genügt | Original oder Marke ist wichtig | |---|---| | PCA9685; Lager (625, 633); Bronzebuchsen; M2/M3-Schrauben, -Muttern und -Gewindeeinsätze (Edelstahl A2); Abstandsbolzen; 25T-Servohörner (Verzahnung prüfen); Kamerakabel; LCD (generisches ST7789 funktioniert); JST-SH-Kabel; Dupont, Schrumpfschlauch, Kabelbinder, Spiralschlauch, Verbindungsklemmen im Wago-Stil; LiPo-Tasche und -Tester; Filamentmarke | **Servos** (Original-SPT, die Variante -180W); **LiPo** (Klasse Gens ace, SLS oder Robbe, Hardcase, echte C-Rate); **LiDAR** (echter Slamtec C1, für den ROS-Treiber); **Pi 5, Kameras, Netzteil** (nur offiziell); **microSD** (Fälschungen sind häufig, daher von Amazon versandt oder aus Händlerbestand kaufen); **Pololu-Spannungsregler** (billige Abwärtswandler übertreiben den Strom); **XT60** (Original Amass); **BEC** (Hobbywing oder Castle statt Klonen, da er alle 13 Servos versorgt); **Ladegerät** (SkyRC oder ISDT bevorzugt; HTRC ist Klon-Niveau); **6805-2RS-Hauptgelenklager** (Spiel zeigt sich direkt am Gelenk); Loctite 243 | ## 6. Vorbehalte, die die Stückliste betreffen {#_6-caveats-that-affect-the-bom} 1. **Es fand sich kein echter „20 A, 6/7,4 V, 2S-Eingang“-BEC.** Ein Abwärtsregler kann aus einem 2S-Akkupack (6,4–8,4 V) keine 7,4 V liefern, betreiben Sie die Servos daher mit **6,0 V**. Sinnvolle Optionen sind 2× Hobbywing UBEC-10A V2-Car (je 10 A Dauer / 15 A Spitze), die jeweils zwei Beine versorgen, oder ein Castle BEC Pro 20A (15 A Dauer bei 2S laut Sub-Agent). 2. **Der Original-ESP32-S3-DevKitC-1-N16R8 ist überall, wo in der EU geprüft wurde, nicht vorrätig** (Reichelt, soyter.pl; DigiKey führt ihn nicht; Mouser war gesperrt). Wählen Sie eines: - den Original-N32R16V (DigiKey 17,42 €), unter Verzicht auf GPIO35–37; - einen N16R8-Klon (Amazon 10,07 €). 3. **igus hat kein 3×5×5-Teil.** Sein Teil mit 3-mm-Bohrung ist 3×4,5×5 (GSM-/JSM-0304-05). Ändern Sie entweder die gedruckte Bohrung auf 4,5 mm oder verwenden Sie Bronze 3×5×5. 4. **Shops mit geändertem Status:** - Botland verkauft jetzt nur noch an Unternehmen (UID-Nummer erforderlich). - Der Shop von AZ-Delivery ist geschlossen. - Mouser, Antratek, RobotShop EU und HobbyKing haben automatisierte Zugriffe gesperrt, daher sind sie nicht bepreist. 5. **Österreichische Paketsteuer:** 2,40 € pro Bestellung, an der Amazon-Kasse berechnet. Sie gilt nur für Versandhändler mit mehr als 100 Mio. € Umsatz, betrifft also die meisten kleinen EU-Shops nicht. 6. **LiPo-Versand:** Ein 2S-Akkupack mit 5000 mAh hat etwa 37 Wh, also unter 100 Wh, und wird daher zu normalen Tarifen versendet. Lindinger und SLS verlangen Zuschläge erst über 100 Wh. 7. **Shops mit DE-USt.:** Die Preise von Welectron, Eckstein und kugellager-* können um etwa 0,8% steigen, wenn die Kasse die österreichischen 20% USt. anwendet. 8. **Conrad-Werkzeugpreise** sind netto × 1,2 (berechnet). Die Preise von Bambu und Prusa sind befristete Black-Friday-Preise. --- ## EU-Preise für die 15 zusätzlichen Artikel der Vierbeiner-Stückliste (Österreich, 2026-10-30) {#eu-pricing-for-the-15-extra-quadruped-bom-items-austria-2026-10-30} Für jeden Artikel gibt es mindestens ein Angebot, das ich auf der Seite des Shops gelesen habe. Preise sind € inkl. USt. wie am 2026-10-30 angezeigt, günstigste zuerst. **Drei Korrekturen am Auftrag:** - **Artikel 1:** Seeed-SKU 102010635 ist das XIAO ESP32S3 **Sense**, vorgelötet (es hat eine Kamera). Die einfache vorgelötete Platine ist **102010634**, und 113991114 ist die einfache Platine ohne Stiftleisten. - **Artikel 2:** Pololu #2813 ist der **Big** Pushbutton Power Switch HP (4,5–40 V, etwa 16 A), kein Mini. Einen „Mini HP 6 A“ gibt es nicht. #2812 ist der Big MP (4,5–40 V, 8 A). Das 6-A-Teil ist der Mini LV **#2808** (2,2–20 V). - **Artikel 11:** Das GeeekPi-Set B07PHBTTGV enthält **keine** M2.5×6-Abstandsbolzen I-I. Diese müssen Sie separat kaufen. **So lesen Sie die Preisspalten:** - Eckstein und Botland zeigen deutsche USt. (19%). Der österreichische Preis kann etwa 1% höher sein. - Die Amazon.de-Preise wurden ohne Lieferadresse abgerufen, enthalten also wahrscheinlich deutsche USt. Der österreichische Preis kann leicht abweichen. - „(Listing)“ bedeutet, dass ich den Preis nur auf der Amazon-Suchergebnisseite gesehen habe, nicht auf der Produktseite. Behandeln Sie ihn als UNVERIFIED. - DigiKey-Preise sind der Wert „inkl. USt.“ auf DigiKey.at. ## 1. Seeed XIAO ESP32S3 (Anz. 1) {#_1-seeed-xiao-esp32s3-qty-1} | Händler | Produkt / SKU | € | Packung | Lager | URL | |---|---|---|---|---|---| | DigiKey.at | 113991114 einfach, ohne Stiftleisten (original) | 7,98 | 1 | 9.565 | https://www.digikey.at/de/products/result?keywords=113991114 | | DigiKey.at | 102010634 vorgelötet (original) | 9,05 | 1 | 159 | https://www.digikey.at/de/products/detail/seeed-technology-co-ltd/102010634/26553885 | | Berrybase.at | SE-102010634 „Mit Header“ (original) | 9,90 | 1 | 100+ | https://www.berrybase.at/en/seeed-studio-xiao-esp32-s3-wifi-bluetooth-5.0-mesh-8mb-psram-dual-core-240-mhz-6-mb-flash-5v-019de2c9775872f985e5ef385c70decc | | Amazon.de | B0BYSB66S5, Seeed XIAO ESP32-S3 | 16,08 | 1 | Auf Lager | https://www.amazon.de/dp/B0BYSB66S5 | - Die Berrybase-Variante „Ohne Header“ ist vorrätig, aber ihren eigenen Preis habe ich nicht gesehen. Die Seite nennt „Ab 9,90 €“. - Berrybases „XIAO ESP32-S3 **Plus**“ um 9,50 € ist eine andere Platine. ## 2. Pololu-Tasterschalter (Anz. 1) {#_2-pololu-pushbutton-power-switch-qty-1} | Händler | Produkt | € | Lager | URL | |---|---|---|---|---| | Botland.de | #2808 Mini LV, 2,2–20 V / 6 A | 4,50 | InStock | https://botland.de/elektronische-und-digitale-schalter/29436-mini-push-mosfet-schalter-lv-2-2-20v-6a-mit-rueckstromschutz-pololu-2808.html | | Botland.de | #2812 Big MP, 4,5–40 V / 8 A | 4,90 | InStock | https://botland.de/elektronische-und-digitale-schalter/5118-grosser-push-mosfet-mp-schalter-45-40-v-8-a-mit-ruckstromschutz-pololu-2812-5903351244879.html | | Botland.de | #2813 Big HP, 4,5–40 V / 16 A | 7,90 | InStock | https://botland.de/elektronische-und-digitale-schalter/5117-grosser-push-mosfet-schalter-hp-45-40v-16a-mit-ruckstromschutz-pololu-2813-5903351244862.html | | Eckstein (DE) | #2808 (PO2808) | 5,89 | Verfügbar, 1–3 Tage | https://eckstein-shop.de/PololuMiniPushbuttonPowerSwitchwithReverseVoltageProtection2CLVEN | | DigiKey.at Marketplace | #2808 / #2812 / #2813 | 5,98 / 7,18 / 10,80 | 382 / 241 / 156 | https://www.digikey.at/de/products/result?keywords=pololu%202813 | - **Eignung für 2S (6,0–8,4 V):** Alle drei Varianten decken diesen Bereich ab. #2808 ist auf 20 V begrenzt und würde daher bei 3S oder mehr nicht funktionieren. - **Welcher der richtige ist, hängt davon ab, was der Schalter führt:** - Schaltet er nur den Logik-/Pi-Zweig, genügt #2808 (6 A). - Schaltet er den gesamten Akkupack, der zwei 10-A-UBECs versorgt, kann die Akkuseite bei voller Servolast etwa 18 A ziehen (meine Schätzung). Das liegt über den ~16 A Dauerstrom, für die #2813 ausgelegt ist. Halten Sie ihn in diesem Fall aus dem Servopfad heraus und verwenden Sie den XT60-Loop-Key. - **DigiKey-Marketplace**-Artikel werden von Pololu aus den USA versendet, und laut Seite kann eine separate Versandgebühr anfallen. - **Nicht empfohlen:** Amazon B079NSQ1ML (#2813) um 56,34 € (Listing). Berrybase POL2812 um 4,90 € ist nicht lieferbar. ## 3. 12-mm-Metall-Drucktaster, tastend, Schließer (Anz. 1) {#_3-12-mm-momentary-metal-pushbutton-normally-open-qty-1} | Händler | Produkt | € | Lager | URL | |---|---|---|---|---| | Reichelt.at | ONPOW VS GQ12B-10S, Edelstahl, Schraubklemmen, tastend, Schließer | 5,66 (statt 7,05) | ab Lager | https://www.reichelt.at/at/de/shop/produkt/drucktaster_17_5_12_mm_2a-36_vdc_edelstahl-318555 | | Reichelt.at | ONPOW VS GQ12B-10JS, Edelstahl, Lötösen | 7,46 | ab Lager | https://www.reichelt.at/at/de/shop/produkt/drucktaster_17_5_12_mm_2a-36_vdc_edelstahl-318547 | | Amazon.de | Metzler 12 mm Edelstahl, B0FH2TX1LN | 5,53 | Auf Lager | https://www.amazon.de/dp/B0FH2TX1LN | - **Kaufen Sie den Metzler nicht:** Seine Seite nennt eine Einbautiefe von 40 mm, das liegt über Ihrer Grenze von 30 mm. - **Die Tiefe des GQ12B ist UNVERIFIED.** Das abgerufene Datenblatt hatte keine lesbare Gehäuselänge. ONPOW beschreibt die Serie als „short body“. - GQ12B-10/J/N ist die Version aus vernickeltem Messing. Reichelt führt die Edelstahlversion (S). ## 4. Hobbywing UBEC 10A V2-Car, 2–6S (Anz. 2) {#_4-hobbywing-ubec-10a-v2-car-2-6s-qty-2} | Händler | Produkt | € pro Stück | Lager | URL | |---|---|---|---|---| | Lindinger.at | HW30603003 BEC 10A V2-Car (original) | **26,99** (statt 31,98), bestätigt | „Nur noch wenige auf Lager“, 1–3 Tage | https://www.lindinger.at/en/RC-Electronics/Power-Supply-Bus-System/Battery-Switches-BEC/HOBBYWING-BEC-10A-V2-Car-UBEC-controller-for-2-6S/9787110 | | Amazon.de | SPARKHOBBY UBEC 10A 2–6S, B0DK31PYFZ (**Klon**) | 26,63 | noch 3 | https://www.amazon.de/dp/B0DK31PYFZ | | Amazon.de | Hobbywing B0BCWYQYKW (original) | 29,90 von 3 Verkäufern (Listing) | keine Buy Box | https://www.amazon.de/dp/B0BCWYQYKW | - Zwei Stück bei Lindinger kosten 53,98 €, zuzüglich 5,99 € Versand (versandfrei ab 89 €). - Lindingers Versandkostenfrei-Grenze für Österreich von 89 € ist auf seiner Website bestätigt. ## 5. ATO/ATC-Inline-Sicherungshalter mit Leitungen ≥14 AWG, plus 20-A-Sicherungen {#_5-ato-atc-inline-fuse-holder-with-≥14-awg-leads-plus-20-a-fuses} | Händler | Produkt | € | Packung | Lager | URL | |---|---|---|---|---|---| | Amazon.de | Nilight NI-FH01, 14 AWG, 12-Zoll-Schleife, B07426WCLM | 8,56 | 10 Halter | Auf Lager | https://www.amazon.de/dp/B07426WCLM | | Amazon.de | Bst4U, 14 AWG, wasserdichte Kappe, plus 100 sortierte Sicherungen inkl. 20 A, B087BT1PH3 | 10,07 | 6 Halter + 100 Sicherungen | Auf Lager | https://www.amazon.de/dp/B087BT1PH3 | | Reichelt.at | FKS-20A-ATO-Sicherung | 0,36 pro Stück (0,236 ab 10) | 1 | ab Lager | https://www.reichelt.at/at/de/shop/produkt/kfz-flachsicherung_20a_gelb-7785 | | Amazon.de | JatilEr 20-A-Standard-Flachsicherungen, B09ZXQ8F3J | 4,02 | 10 | Auf Lager | https://www.amazon.de/dp/B09ZXQ8F3J | - Reichelt hat keinen verkabelten **ATO**-Inline-Halter. Die nächstliegende Option ist der IMAXX HLP7335 für **Mini**-Flachsicherungen (Leitungen 2,5 mm², 30 A, IP55) um 2,62 €. Er bräuchte FK1-20A-Mini-Sicherungen um je 0,41 €. Link: https://www.reichelt.at/at/de/shop/produkt/kfz-sicherungshalter_minioto_30_a_58_v_low_profile_ip55-229125 ## 6. Servo-Verlängerungskabel, 30 cm JR (Anz. 12) {#_6-servo-extension-cables-30-cm-jr-qty-12} | Händler | Produkt | € | Packung | Lager | URL | |---|---|---|---|---|---| | Amazon.de | 30 cm Stecker–Buchse JR, B07FYF76Y1 (Querschnitt nicht angegeben) | 10,07 | 10 | noch 12 | https://www.amazon.de/dp/B07FYF76Y1 | | Amazon.de | VUNIVERSUM 30 cm **22 AWG** (0,32 mm²), B078VSNC9D | 11,08 | 10 | noch 11 | https://www.amazon.de/dp/B078VSNC9D | | Amazon.de | GTIWUNG 30 Stk. JR, B082WYFWSY (Längenmix nicht geprüft) | 12,10 (Listing) | 30 | ? | https://www.amazon.de/dp/B082WYFWSY | - Sie brauchen 12, kaufen Sie also zwei 10er-Packs: 2 × 11,08 € = 22,16 € für die 22-AWG-Version. - Bei Berrybase oder Reichelt habe ich nichts Passendes gefunden. Lindinger wurde nicht geprüft. ## 7. Pi-5-Kamerakabel, 22-Pin auf 15-Pin, 300 mm (Anz. 1) {#_7-pi-5-camera-cable-22-pin-to-15-pin-300-mm-qty-1} | Händler | Produkt | € | Lager | URL | |---|---|---|---|---| | DigiKey.at | Raspberry Pi SC1129 (offiziell) | 2,14 | 1 | https://www.digikey.at/de/products/detail/raspberry-pi/SC1129/21658260 | | Berrybase.at | RPI-CC-SM-30, offiziell Standard–Mini 300 mm | 2,30 | 100+ | https://www.berrybase.at/raspberry-pi-camera-cable-standard-mini-300mm | | Amazon.de | B0CMZPKZFT, verkauft als „offizielles“ (unbestätigt) | 5,20 | Auf Lager | https://www.amazon.de/dp/B0CMZPKZFT | | Amazon.de | Waveshare 22-auf-15-Pin 300 mm, B0CX1SFD44 | 9,67 | Auf Lager | https://www.amazon.de/dp/B0CX1SFD44 | - Reichelts „RASP CAM FPC 30“ um 2,27 € ist das ältere orange Kamerakabel, vermutlich 15-auf-15-Pin. Es ist nicht der 22-Pin-Typ für den Pi 5. ## 8. Kurzes USB-A-auf-USB-C-Kabel, 90° (Anz. 2) {#_8-short-usb-a-to-usb-c-cable-90°-qty-2} | Händler | Produkt | € | Packung | Lager | URL | |---|---|---|---|---|---| | Amazon.de | deleyCON 0,15 m USB-A auf C 90°, B0FVXP8LXJ | 4,99 | 1 | Auf Lager | https://www.amazon.de/dp/B0FVXP8LXJ | | Amazon.de | deleyCON 0,15 m USB-A auf C 90°, 480 Mbps, B0DGTR2X97 | 5,84 | 1 | Auf Lager | https://www.amazon.de/dp/B0DGTR2X97 | | Amazon.de | aceyoon 20 cm USB-A auf C 90°, B09ZDV7S44 | 7,64 | 3 | Auf Lager | https://www.amazon.de/dp/B09ZDV7S44 | - Bei Berrybase habe ich kein kurzes USB-A-auf-C-Kabel gefunden. ## 9. Adafruit-STEMMA-QT-Kabel (Anz. 1) {#_9-adafruit-stemma-qt-cable-qty-1} | Händler | Produkt | € | Lager | URL | |---|---|---|---|---| | DigiKey.at | Adafruit 4397, JST SH auf Buchsen, 150 mm | 1,01 | 8 | https://www.digikey.at/de/products/result?keywords=adafruit%204397 | | DigiKey.at | Adafruit 4209, JST SH auf Stiftleiste | 1,01 | 5 | https://www.digikey.at/de/products/result?keywords=adafruit%204209 | | Berrybase.at | Seeed SE-114992154, Grove & Qwiic/STEMMA QT auf Stecker-/Buchsen-Jumper (Alternative) | 2,50 | 3 | Suche „stemma qt kabel“ | - Berrybases Adafruit ADA-JSTSH4 und die SparkFun-Kabel CAB-14988 / CAB-17261 sind alle „nicht lieferbar“. - DigiKey verlangt unter 75 € 25 € Versand, bestellen Sie 4397 dort also nur als Teil einer größeren DigiKey-Bestellung. ## 10. Dupont-Jumperkabel, Buchse–Buchse (1 Packung) {#_10-dupont-jumper-wires-female-female-1-pack} | Händler | Produkt | € | Lager | URL | |---|---|---|---|---| | Berrybase.at | DUPK-SET-10: 40-pin F-F + M-M + F-M, 10 cm | 4,40 | 100+ | https://www.berrybase.at/40pin-jumper-dupont-kabel-set-je-1x-f-f-m-m-f-m-10cm | | Berrybase.at | DUPK-SET-20: gleiches Set, 20 cm | 4,90 | 100+ | https://www.berrybase.at/40pin-jumper-dupont-kabel-set-je-1x-f-f-m-m-f-m-20cm | | Amazon.de | 120 × F-F 10 cm, B072JT6BCN | 7,04 | Auf Lager | https://www.amazon.de/dp/B072JT6BCN | | Amazon.de | 160 × F-F, 10/20/30/40 cm, B0F98KBV61 | 8,05 | Lagerfeld leer | https://www.amazon.de/dp/B0F98KBV61 | ## 11. M2- und M2.5-Kleinteile {#_11-m2-and-m2-5-hardware} **GeeekPi B07PHBTTGV**, 12,10 €, vorrätig. Inhalt laut Seite: | Teil | Anz. | |---|---| | M2.5 × 20+6 Außen–Innen | 16 | | M2.5 × 5+6 Außen–Innen | 16 | | M2.5 × 11+6 Außen–Innen | 16 | | M2.5 × 11 (vermutlich I-I; meine Schlussfolgerung) | 16 | | M2.5 × 12+6 | 4 | | M2.5-Schrauben | 50 | | M2.5-Muttern | 50 | | Acryl-Unterlegscheiben | 50 | Das Set enthält **keine 6-mm-Abstandsbolzen I-I**. | Bedarf | Händler | Produkt | € | Packung | Lager | URL | |---|---|---|---|---|---|---| | M2.5 × 6 F-F (≥10) | DigiKey.at | Würth 970060151, Stahl sechskant, Innen–Innen | 0,552 pro Stück, also ≈5,52 für 10 | 1 | 3.699 | https://www.digikey.at/de/products/result?keywords=970060151 | | M2.5 × 6 F-F | Amazon.de | B0GK7QTZ7B, Listing mit I-I-Messing in mehreren Größen (Variante nicht bestätigt) | 11,29 | 2–50 | Auf Lager | https://www.amazon.de/dp/B0GK7QTZ7B | | M2 × 8 F-F (≥3) | Amazon.de | B0DR67YGQL, M2×8 Messing, beidseitig Innengewinde | 7,73 | 40 | noch 2 | https://www.amazon.de/dp/B0DR67YGQL | | M2 × 5 DIN 912 | Schraubenking.at | Edelstahl A2 | 0,86 | 10 | 2–3 Tage | https://www.schraubenking.at/M2-x-5mm-Zylinderschrauben-DIN912-Edelstahl-A2-P003957 | | M2 × 10 DIN 912 | Schraubenking.at | Edelstahl A2 | 0,78 | 10 | 2–3 Tage | https://www.schraubenking.at/M2-x-10mm-Zylinderschrauben-DIN912-Edelstahl-A2-P002803 | | M2-Muttern DIN 934 | Schraubenking.at | Edelstahl A2 | 1,87 | 100 | 1 Tag | https://www.schraubenking.at/M2-Sechskantmuttern-DIN934-Edelstahl-A2-P002807 | | M2.5 × 5 / × 6 DIN 912 | Schraubenking.at | Edelstahl A2 | 0,83 je Größe | 10 | 2–3 Tage | …-P004986 / https://www.schraubenking.at/M25-x-6mm-Zylinderschrauben-DIN912-Edelstahl-A2-P005010 | | M2.5-Muttern DIN 934 | Schraubenking.at | Edelstahl A2 | Preis nicht gesehen | 100 | ? | https://www.schraubenking.at/M25-Sechskantmuttern-DIN934-Edelstahl-A2-P004196 | - Eine kurze DigiKey-Suche ergab keinen Messing-Abstandsbolzen M2 × 8 I-I. ## 12. M3 × 40 DIN 912 und M3-Sicherungsmuttern DIN 985 {#_12-m3-×-40-din-912-and-m3-din-985-nylock-nuts} **WZHUIDA-Set B0D2VST57H**, 17,14 €, „Nur noch 17 auf Lager“. Das Angebot bestätigt, dass es **M3 × 40 enthält**: | Länge | Anz. | |---|---| | M3 × 6, M3 × 8 | je 40 | | M3 × 10, 12, 14, 16, 18, 20 | je 30 | | M3 × 25, 30, 35, **40**, 50 | je 20 | | M3-Muttern (einfach, **keine** Sicherungsmuttern) | 360 | | M3-Unterlegscheiben | 360 | Die Schrauben sind aus Edelstahl 304 mit Zylinderkopf (Variante „Zylinderkopf“). | Bedarf | Händler | Produkt | € | Packung | Lager | URL | |---|---|---|---|---|---|---| | M3 × 40 DIN 912 | Schraubenking.at | Edelstahl A2 | 1,01 | 10 | Sofort verfügbar | https://www.schraubenking.at/M3-x-40mm-Zylinderschrauben-DIN912-Edelstahl-A2-P004987 | | M3 × 40 DIN 912 | Schraubenking.at | 8.8 verzinkt | 1,16 | 10 | 1 Tag | https://www.schraubenking.at/M3-x-40mm-Zylinderschrauben-DIN912-Stahl-verzinkt-FKL-88-P005519 | | M3 DIN 985 Sicherungsmutter | Schraubenking.at | Stahl verzinkt | 1,39 | 100 | 1 Tag | https://www.schraubenking.at/M3-Sicherungsmuttern-DIN985-Stahl-verzinkt-FKL6/8-P000461 | | M3 DIN 985 Sicherungsmutter | Schraubenking.at | Edelstahl A2 | 2,30 | 100 | 1 Tag | https://www.schraubenking.at/M3-Sicherungsmuttern-DIN985-Edelstahl-A2-P000454 | | M3 DIN 985 Sicherungsmutter | Reichelt.at | SKSM M3-100 | 3,48 | 100 | ab Lager | https://www.reichelt.at/at/de/shop/produkt/sicherungsmuttern_m3_100_stueck-65808 | | M3 DIN 985 Sicherungsmutter | Amazon.de | Edelstahl A2, B0BJYRLG6G | 5,53 | 50 | Auf Lager | https://www.amazon.de/dp/B0BJYRLG6G | ## 13. Schaumstoff-Montageband (19 mm) und 2,5-mm-Kabelbinder (100 Stk.) {#_13-foam-mounting-tape-19-mm-and-2-5-mm-cable-ties-100-pcs} | Händler | Produkt | € | Packung | Lager | URL | |---|---|---|---|---|---| | Reichelt.at | tesa PRO Universal 19 mm × 5 m (kein VHB) | 9,98 | 1 Rolle | ab Lager | https://www.reichelt.at/at/de/shop/produkt/montageband_tesa_pro_universal_5_m_x_19_mm_weiss-338987 | | Amazon.de | 3M VHB 5952F, 19 mm × 3 m × 1,1 mm, B00EDLPG7Y | 14,11 | 1 Rolle | Auf Lager | https://www.amazon.de/dp/B00EDLPG7Y | | Amazon.de | 3M VHB 4991, 19 mm × 5,5 m × 2,3 mm, B0779B5LBZ | 20,59 | 1 Rolle | Auf Lager | https://www.amazon.de/dp/B0779B5LBZ | | Berrybase.at | Kabelbinder 100 × 2,5 mm, weiß (E-E510) | 0,90 | 100 | 9 | https://www.berrybase.at/kabelbinder-100-mm-x-2-5-mm-weiss-100-stueck | | Reichelt.at | Delock 19186, 100 × 2,5 mm, schwarz, kältebeständig | 1,16 | 100 | ab Lager | https://www.reichelt.at/at/de/shop/produkt/kabelbinder_kaelteresistent_l_100_x_b_2_5_mm_schwarz_100_stueck-316436 | | Berrybase.at | Kabelbinder 100 × 2,5 mm, transparent (D18605) | 1,90 | 100 | 3 | https://www.berrybase.at/kabelbinder-100-x-2-5mm-transparent-100-stueck | ## 14. XT60-Loop-Key {#_14-xt60-arming-loop-plug} **Bestätigt.** B07C3KH1VT ist „3 Paar (6 Stück) Original Amass Premium XT60H … Stecker Buchse Male Female inkl. Schutzkappen“. Das sind 3 Stecker und 3 Buchsen, 6,44 €, vorrätig: https://www.amazon.de/dp/B07C3KH1VT ## 15. Mittelfeste Schraubensicherung {#_15-medium-strength-thread-locker} | Händler | Produkt | € | Lager | URL | |---|---|---|---|---| | Schraubenking.at | Förch-Schraubensicherung, mittelfest, blau, 10 ml (kein Loctite) | 5,71 | 1 Tag | https://www.schraubenking.at/Schraubensicherung-mittelfest-blau-10ml-P002471 | | Amazon.de | Loctite 243, 5 ml, B00745GNPK | 8,11 | noch 4 | https://www.amazon.de/dp/B00745GNPK | | Amazon.de | Loctite 243, 10 ml, B00Y8DOMCC | 13,07 | Auf Lager | https://www.amazon.de/dp/B00Y8DOMCC | | Reichelt.at | Loctite 243, 10 ml | 15,12 | ab Lager | https://www.reichelt.at/at/de/shop/produkt/schraubensicherung_lack_mitttelfest_blau_10_ml-94948 | ## Versand für Shops außerhalb Ihrer Liste {#shipping-for-shops-outside-your-list} - **Botland (Versand aus Polen):** Ich habe nur die deutschen Konditionen gesehen: ab 4,99 €, versandfrei über 100 €. Die Tarife nach Österreich sind UNVERIFIED. - **Eckstein (DE):** Dieser Shop steht auf Ihrer Wunschliste, aber Sie haben keine Versandkosten dafür angegeben. Der Tarif nach Österreich ist UNVERIFIED; die abgerufenen Versandinfo-Seiten zeigten ihn nicht. - **DigiKey Marketplace (Pololu-Artikel):** von Pololu aus den USA versendet; zusätzlich zu DigiKeys 25 € / versandfrei ab 75 € kann eine separate Versandgebühr anfallen. ## Nicht erreicht {#not-reached} - **TME** und **metzler-electronics.com** sperren beide automatisierte Zugriffe, daher habe ich von ihnen keine Preise. - **Conrad.at** und **AliExpress** habe ich nicht geprüft. --- # Teilekatalog {#parts-catalogue} > **Status:** generiert aus der verifizierten CAD-Baugruppe und `hardware/bom.yaml` (`make catalog`). Die Preise sind beobachtete Angebote (EUR inkl. MwSt., 2026-10-30); prüfen Sie sie vor der Bestellung erneut. **[Katalog & Montagebuch herunterladen (A4-PDF)](catalog/strido-catalog.pdf)** — gedruckte Teile, Kaufteile, Schraubenbeutel im Maßstab 1:1, der Einkaufsplan, Werkzeuge, jeder Montageschritt, die Verkabelung und der Software-Anhang. Maschinenlesbar: `docs/catalog/parts.json` (wird auch vom MCP-Server `strido-hardware` bereitgestellt). Teile, die nicht im CAD modelliert sind (Draht, Servokabel-Verlängerungen, Sicherungen, Filament, Klebeband), sind in der [Stückliste](bom/README.md) aufgeführt. --- # Konfiguration {#configuration} > **Status:** alle Umgebungsschlüssel, die der Code liest. Standardwerte stehen in der eingecheckten `.env.example`; Geheimnisse: keine. | Schlüssel | Standard | Gelesen von | Bedeutung | |---|---|---|---| | `ROS_DOMAIN_ID` | `42` | `docker/compose.yaml` | ROS-2-Domain der Roboter- und Simulationscontainer | | `STRIDO_BLENDER` | *(leer)* | `strido_publish.scene` | Blender-Programm für Renderings; leer = `blender` im PATH, sonst das macOS-App-Bundle | | `STRIDO_PRUSASLICER` | *(leer)* | `strido_verify.printability` | PrusaSlicer-Programm für die Druckbarkeitsprüfung; leer = `prusa-slicer` im PATH, sonst das macOS-App-Bundle | | `STRIDO_REPO_ROOT` | *(leer)* | `strido.workspace` | Repository-Wurzel für die Werkzeuge bei Ausführung außerhalb des Checkouts | | `STRIDO_SERIAL_PORT` | `/dev/strido_mcu` | `strido-cli`, `strido_ntx.plugin` | Serielles Gerät des XIAO ESP32-S3 (udev-Symlink aus `ros2/strido_bringup/config/99-strido.rules`) | Die ROS-2-Launch-Dateien übernehmen dieselben Werte als Launch-Argumente (`mcu_port`, `use_policy`, `policy`, `camera`). Makefile-Variablen: `NTX_HARNESS` (Pfad des NT-X-Checkouts für `make ntx-smoke`, Standard `../../ntx-harness`), `POLICY` (Policy-Datei für `make sim-gazebo`). --- # Entscheidungen {#decisions} > **Status:** Architekturentscheidungen (ADRs) für Strido. Entscheidungsdatum 2026-10-31, sofern nicht anders angegeben. ## ADR-001 — Yertle-Mechanik beibehalten, modularen Sensorkopf ergänzen {#adr-001-keep-the-yertle-mechanics-add-a-modular-sensor-head} **Kontext.** Mini Pupper 4 ist ein Vorserienprodukt ohne veröffentlichtes CAD, Stückliste oder PCB-Design. **Optionen.** (A) Einen Mini-Pupper-4-Klon anhand von Fotos nachmodellieren. (B) Einen neuen Roboter entwerfen. (C) Die veröffentlichten, real gebauten Yertle-Beine und den Rahmen beibehalten und Sensorkopf, Elektronik und Software ergänzen. **Entscheidung.** C. **Konsequenzen.** Die Mechanik erbt eine reale Baugeschichte; jede Änderung ist eine CAD-Boolesche Operation auf den Upstream-STEP/STL-Dateien, verifiziert durch den Harness. **Nur neu bewerten, wenn:** MangDang das CAD des Mini Pupper 4 unter einer offenen Lizenz veröffentlicht. ## ADR-002 — CAD als Code, Verifikation als Prüfungen {#adr-002-cad-as-code-verification-as-gates} **Kontext.** Menschen drucken und montieren allein anhand dieses Repositorys; eine falsche Bohrung kostet einen Neudruck. **Entscheidung.** Alle neuen und geänderten Teile sind CadQuery/manifold-Boolesche Operationen in `strido_cad`; jede Prüfung (Durchdringung, Bewegungsbereich, Passungen, Freigang, Sensoren, Elektronik, Stücklisten-Abdeckung) ist eine ausführbare Prüfung mit nachverfolgtem Bericht. Toleranzbänder und Kontaktregeln liegen samt Begründung in `hardware/verification/*.yaml`. **Konsequenzen.** Physikalische Aussagen sind reproduzierbar; eine Prüfung darf nur durch eine festgehaltene Entscheidung gelockert werden. **Nur neu bewerten, wenn:** ein parametrisches CAD-System mit gleichwertiger Skriptfähigkeit CadQuery ersetzt. ## ADR-003 — uv-Workspace mit geschichteten Paketen {#adr-003-uv-workspace-with-layered-packages} **Kontext.** Die Roboter-Laufzeit muss schlank bleiben (Pi, ROS-2-Image), während die Werkzeuge CadQuery, MuJoCo, PyTorch und WeasyPrint benötigen. **Optionen.** (A) Ein Paket mit Extras. (B) Ein uv-Workspace: core, cad, verify, publish, sim, ntx, workspace. **Entscheidung.** B, mit import-linter-Verträgen (core importiert nichts; publish → verify → cad → core; sim und ntx importieren nie CAD). **Konsequenzen.** `pip install packages/strido-core --no-deps` ist alles, was der Roboter braucht. **Nur neu bewerten, wenn:** die Anzahl der Pakete ohne Nutzen bei den Abhängigkeiten zur Wartungslast wird. ## ADR-004 — Upstream-Mängel als abgeleitete Teile beheben, nicht durch Bearbeiten der Upstream-Dateien {#adr-004-fix-upstream-defects-as-derived-parts-not-by-editing-upstream-files} **Kontext.** Die Verifikation fand Upstream-Probleme: den vorderen Servohalterungen fehlt die Vorbohrung für den Hüftdrehpunkt auf der Seite, die die Vorderbeine nutzen; das Servohorn-Muster des Femurs am rechten Bein ist gegenüber dem STEP um 30° verdreht; die Ausrichtung des Verbinders um 22°. **Entscheidung.** `upstream/yertle/` bleibt byte-identisch; Korrekturen werden als Daten (`hardware/assembly/corrections.yaml`) und abgeleitete Teile (`left_servo_mount_fl`, `right_servo_mount_fr` im Druckpaket) ausgedrückt. **Konsequenzen.** Das Druckpaket enthält zwei zusätzliche Teiletypen; Upstream-Aktualisierungen lassen sich sauber vergleichen. **Nur neu bewerten, wenn:** Upstream korrigierte Dateien veröffentlicht. ## ADR-005 — Gelenkgrenzen berücksichtigen das gespiegelte Partnerbein und Freigang im Betrieb {#adr-005-joint-limits-include-the-mirrored-partner-leg-and-running-clearance} **Kontext.** Grenzen pro Bein erlaubten, dass sich beide Vorderfüße unter dem Körper treffen, wenn beide Hüften nach innen schwenken. **Entscheidung.** Der Hüft-Sweep setzt den Achspartner auf den gespiegelten Winkel und verlangt ≥ 0,3 mm Freigang sowie keine Überlappung. **Konsequenzen.** Engere innere Hüftgrenzen (≈ −17,5°); Firmware, Gait, Simulation und NT-X teilen sie über Codegenerierung. **Nur neu bewerten, wenn:** ein Controller die Beine koordiniert, um Kontakt zwischen den Beinen zu vermeiden. ## ADR-006 — Gelernter Controller ohne Rückmeldung {#adr-006-feedback-free-learned-controller} **Kontext.** Die Hobby-Servos SPT5435LV melden weder Position noch Drehmoment. **Entscheidung.** Die Policy beobachtet nur IMU, Kommando, vorherige Action und einen Gait-Takt; Anstiegsbegrenzung und Begrenzungen der Firmware werden im Training modelliert; die numpy-Laufzeit wird von Simulation und Roboter gemeinsam genutzt. **Konsequenzen.** Seitliches und rückwärtiges Folgen sind schwach; der Transfer hängt vom gemessenen Servoverhalten ab. **Nur neu bewerten, wenn:** Servos mit Rückmeldung (z. B. serielle Bus-Servos) die SPT5435LV ersetzen. ## ADR-007 — NT-X-Integration über eine Erweiterung, nicht durch Änderungen am Kern {#adr-007-nt-x-integration-through-an-extension-not-core-edits} **Kontext.** NT-X leitet Hardware nur an Unitree SDK2 weiter. **Entscheidung.** Katalog-Assets und einen Registry-`robot`-Adapter in `strido-ntx` ausliefern; die eine Kernänderung dokumentieren, die NT-X braucht; das NT-X-Repository nie von hier aus bearbeiten. **Konsequenzen.** Simulation, Studio und Training funktionieren schon heute; Live-Hardware-Sitzungen warten auf die NT-X-Änderung. **Nur neu bewerten, wenn:** NT-X eine registry-basierte Hardware-Weiterleitung übernimmt (dann die Zieldatei ergänzen). ## ADR-008 — VitePress-Seite und WeasyPrint-Buch {#adr-008-vitepress-site-and-weasyprint-book} **Kontext.** Bauende brauchen einen durchsuchbaren Katalog, ein 3D-Modell und ein druckbares A4-Buch. **Entscheidung.** VitePress (wie in den anderen Workspace-Projekten) mit einer three.js-Ansicht eines aus dem CAD exportierten GLB; das Buch ist HTML + CSS, gerendert mit WeasyPrint, sodass Befestigungselemente in echten Millimetern gezeichnet werden können. **Konsequenzen.** Node 26 für die Seite; Pango für das PDF. **Nur neu bewerten, wenn:** die Seite ohne Build-Schritt ausgeliefert werden muss. ## ADR-009 — Die M3-Vorbohrungen der Upstream-Servohalterungen akzeptieren, mit einer Slicer-Maßnahme {#adr-009-accept-the-upstream-servo-mount-m3-pilots-with-a-slicer-action} **Kontext.** Die Passungsprüfung bewertet eine gedruckte M3-Vorbohrung über 0,93 d (gedruckte Größe, CAD − 0,15 mm) als „kein Halt“. 29 Schrauben der Upstream-Servohalterungsfamilie (`left_servo_mount`, `right_servo_mount`, deren abgeleitete Varianten `_fl`/`_fr`) und `servo_mount_top_bracket` greifen in CAD-Vorbohrungen von 2,94–2,97 mm (0,93–0,94 d gedruckt) mit 4–12 mm Einschraubtiefe. Upstream-Yertle-Roboter werden mit genau diesen Bohrungen gedruckt und montiert; die meisten FDM-Drucker drucken kleine Bohrungen 0,2–0,3 mm zu klein, wodurch sie im Band mit schwachem Halt landen. Eine Neukonstruktion der vier Halterungsteile würde die Upstream-Geometrie für eine druckerabhängige Reserve ändern. **Entscheidung.** Das Band bleibt bei 0,93 d, und diese Teile werden in `accepted_deviations` von `hardware/verification/tolerances.yaml` mit einer Maßnahme für Bauende aufgeführt: Drucken Sie sie mit einer X-Y-Lochkompensation von −0,15 mm (Vorbohrung ≈ 2,65 mm) oder härten Sie bei einem unkompensierten Druck die Vorbohrung mit einem Tropfen dünnflüssigem CA-Kleber, bevor Sie die Schraube eindrehen, und prüfen Sie, dass sie greift, bevor das Gelenk belastet wird (anaerobe Schraubensicherung härtet auf Kunststoff nicht aus und kann bei PETG Spannungsrisse verursachen; Datenblatt Loctite 243). Der Passungsbericht zeigt sie als Warnungen mit dieser Maßnahme; jedes andere Teil über dem Band schlägt weiterhin fehl. **Konsequenzen.** Die Prüfung bleibt für neue Teile und jede weitere Aufweitung rot; die Liste der akzeptierten Abweichungen ist explizit und überprüfbar. **Nur neu bewerten, wenn:** eine gedruckte Halterung ein Gewinde ausreißt (dann Varianten mit Ø2,5-mm-Neuvorbohrung wie in ADR-004 ergänzen). ## ADR-010 — Knicken der langen Koppel: eine bekannte Schwachstelle, nur akzeptiert, bis die lange Koppel von Strido sie ersetzt {#adr-010-long-link-buckling-a-known-weak-point-accepted-only-until-the-strido-long-link-replaces-it} **Kontext.** Die Festigkeitsprüfung (`strido_verify.strength`) fährt das Kniekoppelgetriebe durch jede Pose innerhalb der Gelenkgrenzen, mit dem Knieservo am Blockiermoment (3,43 N·m). Die Upstream-`long_link` ist ein Stab, 5 mm breit in der Beinebene und 8 mm quer dazu, 130 mm zwischen den Bolzen. In der Beinebene sind ihre Enden gelenkig gelagert (K = 1) und ihre Wände ergeben I ≈ 75 mm⁴, daher beträgt ihre Euler-Knicklast π² · 1500 · 75 / 130² ≈ 65 N. Die ungünstigste Pose belastet sie mit 192 N, also S ≈ 0,34. In der Referenzpose sind es 127 N (S ≈ 0,51); im Stand (0,70 N·m am Knie, MuJoCo) etwa 29 N (S ≈ 2,2). Quer zur Beinebene ist sie ausreichend (S ≈ 1,8 mit K = 0,7). Jede andere Prüfung besteht mit S ≥ 1,5. Upstream-Yertle-Roboter betreiben diese Koppel mit Servos derselben Drehmomentklasse, beim normalen Laufen hält sie also. Ein Knieservo, der am Blockiermoment gegen einen blockierten Fuß oder in einer extremen Pose drückt, biegt sie in der Beinebene seitlich aus. **Entscheidung.** Als bekannte Schwachstelle behandeln, nicht als akzeptable Reserve. Sie ist unter `accepted` in `hardware/strength.yaml` mit `min_safety: 0.3` aufgeführt, sodass die Prüfung eine Warnung mit der Maßnahme für Bauende meldet (das Knie nie gegen einen blockierten Fuß oder einen harten Anschlag steuern; nach harten Landungen die langen Koppeln auf Verbiegung prüfen und eine verbogene ersetzen) und erneut fehlschlägt, wenn sich die Reserve verschlechtert. **Konsequenzen.** Eine lange Koppel von Strido mit einem etwa 9 mm breiten Schaft in der Beinebene (I ≈ 330 mm⁴ nur mit Wänden, S ≥ 1,5 in der ungünstigsten Pose) ist die geplante Lösung (`TODO.md`). Dafür müssen die Prüfungen für Freigang, Bewegungsbereich, Druckbarkeit und Festigkeit erneut laufen. Sobald sie existiert, wird der `accepted`-Eintrag entfernt. **Gelöst (2026-11-01).** Die steife Strido-Koppel (`strido_cad.long_link`, Druckteil `stiff_long_link`) ersetzt die Upstream-Koppel an allen vier Beinen: gleiche Bolzen (131 mm Abstand), Buchsenaugen und Augendicke, ein Schaft von 10 × 10 mm statt 5 × 8 mm. Mittig auf der Bolzenlinie kam sie dem Femur bei gestrecktem Knie bis auf 0,25 mm nahe, und der Bewegungsbereich-Sweep schränkte den Kniebereich um 5° ein; ihre Mittellinie liegt daher 2 mm neben der Bolzenlinie, vom Femur weg, und jeder Nachbar behält mindestens 1 mm (die Gelenkgrenzen sind unverändert). Die Festigkeitsprüfung ergibt jetzt S = 2,53 für das Knicken, und keine Prüfung braucht mehr eine Ausnahme (`accepted: {}` in `hardware/strength.yaml`). Sie wird flach ohne Stützen gedruckt. Die Hinweise für Bauende oben sind nicht mehr nötig; eine verbogene Upstream-Koppel ersetzt man weiterhin durch die steife. ## ADR-011 — Kabelbaum im CAD verlegt und geprüft {#adr-011-wiring-harness-routed-and-checked-in-the-cad} **Kontext.** Bis v0.2.11 existierte die Verkabelung nur als Liste mit geschätzten Längen; nichts modellierte ein Kabel. Die Verlegung durch die Baugruppe deckte Mängel auf, die die Liste nicht zeigen konnte: Der 25-A-Sicherungshalter auf der Deckleiste ließ 4 mm, damit seine 14-AWG-Leitung in Richtung des vorderen Hüftservos austreten kann; Dupont-Gehäuse passten weder auf die IMU-Stiftleiste (2,5 mm unter dem Pi) noch auf die XIAO-Pins (9 mm unter dem oberen Schulterrahmen); der LiDAR-USB-Adapter verdeckte den Kabelschlitz der Oberschale; die Drähte vom XIAO zum PCA9685 brauchen ~0,3 m, nicht 0,1 m; ein STEMMA-QT-Kabel fehlte; der 18-AWG-Vorrat war zu knapp; und ein 60-mm-Abgriff in 18 AWG hing allein hinter der 25-A-Sicherung. **Optionen.** (A) Die Liste behalten und die Mängel von Hand beheben. (B) Jedes Kabel modellieren: Ankerpunkte an den Steckverbindern, Kabelbinder-Knoten, ein Router durch den freien Raum (Teile plus alles, was die Beine überstreichen) und eine Prüfung. **Entscheidung.** B: `hardware/wiring.yaml` ist die einzige Quelle; `strido_cad.wiring` verlegt, `strido_cad.wiring_geometry` fügt Kabel, Schläuche, Kabelbinder und Kabelbinder-Sockel zur Baugruppe hinzu (Renderings, 3D-Ansicht, Anleitung, Modellmassen); `strido_verify.wiring` prüft Reichweite, Vorrat, Durchhang der Hüftschlaufen, Anschlüsse und Freigang in jeder Betriebspose. Servokabel laufen ohne Verlängerungen, auf Länge gekürzt (Signal neu gecrimpt). Die Hauptsicherung wandert in den hinteren Hohlraum (ihre Leitungen treten durch die Rahmenöffnungen aus), die Logiksicherung in die Rückschale mit der eigenen 14-AWG-Leitung des Halters als Abgriff, der Akkueingang in die Tasche neben dem Akku. **Konsequenzen.** W01 (Akkueingang zur Hauptsicherung, ≈ 0,15 m) ist ungesichert, wie die eigene Leitung des Akkupacks; sie verläuft im Spiralschlauch abseits beweglicher Teile. Bauende schneiden jeden Draht nach der generierten Zuschnittliste zu. Biegeradien und die Form einer hängenden Schlaufe werden nicht modelliert (Routenecken sind scharf; Schlaufen werden über die Länge geprüft). Jede CAD-Änderung verlegt und prüft den Kabelbaum neu. **Nur neu bewerten, wenn:** ein kompakter abgesicherter Akkueingang (Sicherung wenige Zentimeter vom XT60 entfernt) unter das Deck passt oder Kabelmasse/-steifigkeit an einem realen Aufbau so stark abweichen, dass es für die Schlaufen relevant ist. ## ADR-012 — Deutsche Seite aus Übersetzungskatalogen; Assistenzdienst über Cortex Keyring {#adr-012-german-site-from-translation-catalogues-assistant-service-on-cortex-keyring} **Kontext.** Die Seite brauchte Deutsch, einen KI-Assistenten, der aus der Dokumentation antwortet (mit Bildern, Verlauf und anheftbarem Panel), und einen Weg, auf dem Sprachmodelle und Coding-Agenten dasselbe Wissen nutzen. Rund ein Drittel der 110 000 Wörter ist generiert (Montageanleitung, Stückliste, Verifikationsberichte) und ändert sich mit jedem `make`-Lauf; die Seite ist statisches nginx hinter Cortex SSO. **Optionen.** Deutsch: (A) eine übersetzte Kopie jeder Markdown-Datei; (B) deutsche Texte in jedem Python-Generator; (C) ein Katalog pro Seite, der jedes englische Segment (Absatz, Listenpunkt, Tabellenzeile, Überschrift, Diagramm) seiner Übersetzung zuordnet und beim Build gerendert wird. Assistent: (D) ein Modellaufruf aus dem Browser; (E) ein Dienst neben der Seite, der Unterhaltungen hält, die Seiten durchsucht und das Modell über Cortex Keyring aufruft. **Entscheidung.** (C) und (E). Ein geändertes englisches Segment fällt auf Englisch zurück (die Seite meldet, dass sie teilweise übersetzt ist), und `make drift` schlägt fehl, bis es übersetzt ist; Zahlen in einem übersetzten Segment werden übernommen, sodass neu generierte Berichte ihr Deutsch behalten; deutsche Überschriften behalten die englischen IDs, sodass jeder Anker in beiden Sprachen funktioniert. Der Assistent (`assistant/`, Node, keine Abhängigkeiten) speichert Unterhaltungen und Anhänge pro angemeldetem Nutzer in SQLite, antwortet mit Werkzeugen über dieselben Seiten (`search_docs`, `read_page`, `list_pages`, `search_parts`) und stellt sie Agenten mit einem Cortex-App-Token als MCP-Server bereit; `/llms.txt` und das Agent-Skill-Paket erzeugt der Doku-Sync. Die App bringt ihre eigene Gateway-Route mit: `/api/*` und `/mcp` gehen ohne Kompression (Server-Sent Events) an den Assistenten, alles andere an nginx. **Folgen.** Englische Änderungen brauchen einen Übersetzungsdurchgang (`make i18n`); die Kataloge sind versionierte Quellen. Der Keyring-`subscriber` ist der Betreiber, daher bekommt bis zu einem gemeinsamen Pool-Schlüssel nur das Konto des Betreibers Antworten (andere sehen den Grund). Das Gateway-Secret erreicht den Assistenten über die vom Gateway erzeugte Env-Datei (der Sign/Folio-Vertrag), die diesem Container auch die übrigen erzeugten Werte des Stacks zeigt; nur diesen Schlüssel in die `.env` des Hosts zu kopieren (der Canvas-Vertrag) ist der sicherere nächste Schritt (TODO). Das Support-Widget ist aus: Sein Proxy säße im Antwortstrom. Antworten sind generiert: Leiste und `docs/ai.md` weisen darauf hin, Zahlen auf der verlinkten Seite zu prüfen. --- # Design und CAD-Pipeline {#design-and-cad-pipeline} ## Maßgebliche Quelle {#source-of-truth} Die Upstream-Yertle-STEP-Baugruppe (`upstream/yertle/design/CAD/Yertle_Single_v2.step`) und die veröffentlichten Druck-STLs (`upstream/yertle/design/STL/`) definieren die Mechanik. Nichts wird von Hand nachmodelliert: Die Pipeline liest die STEP-Datei, registriert jede STL auf ihren STEP-Körper, misst die Kinematik und baut die Strido-Teile als CadQuery-Boolesche Operationen auf der Upstream-Geometrie auf. ```mermaid flowchart TD STEP["upstream/yertle/design/CAD/Yertle_Single_v2.step"] --> CACHE["strido_cad.step_cache
tessellierte Körper (build/)"] STL["upstream/yertle/design/STL/*.stl"] --> REG["strido_cad.register_upstream
STL ↔ STEP-Registrierung"] CACHE --> REG --> PLACE["hardware/assembly/upstream_placements.yaml"] CACHE --> KIN["strido_cad.extract_kinematics"] --> KY["hardware/kinematics.yaml
Hüft-/Oberschenkel-/Knieachsen, Koppellängen"] KY --> ROM["strido_verify.rom
kollisionsfreie Gelenkgrenzen"] --> JL["hardware/joint_limits.yaml"] KY --> GEN["strido_cad.codegen"] JL --> GEN GEN --> PYG["packages/strido-core/src/strido/geometry.py"] GEN --> CG["firmware/.../geometry_generated.h"] VEND["strido_cad.fetch_vendor_cad
offizielle Hersteller-STEP"] --> PARTS PLACE --> PARTS["strido_cad.parts + catalog.py
neue / geänderte Teile, Herstellerplatinen, Befestigungselemente"] PARTS --> ASM["strido_cad.assembly
vollständige gestellte Baugruppe"] ASM --> VER["strido_verify
Durchdringung, Bewegungsbereich, Passungen, Freigang, Sensor-Sichtfeld"] ASM --> SIM["strido_cad.models
URDF/xacro + MJCF + meshes"] ASM --> OUT["Druckdateien, Stückliste, Anleitung, Renderings"] ``` Koordinatensysteme: Das STEP-System hat +x = Roboter links, +y = Roboter hinten, +z = oben (mm). `assembly.step_to_base()` bildet es auf das REP-103-System `base_link` ab (x vorwärts, y links, z oben; Ursprung zwischen den Hüftachsen). ## Änderungen gegenüber dem Upstream-Yertle {#changes-compared-with-upstream-yertle} | Modul | Teil | Änderung und Begründung | |---|---|---| | Frontdisplay | `front_shell_display` | Upstream-Frontschale + Fenster 43 × 33 mm und zwei M3-Dome für das Waveshare-2"-LCD; Schlitz für das Kamera-Flachbandkabel | | | `display_bracket` | Klemmt das LCD auf seinen M2-Sechskant-Abstandsbolzen an die Dome der Schale | | Frontkamera | `camera_mount_base`, `camera_tilt_plate` | Neigbare Halterung auf der flachen Oberseite der Frontschale; nutzt die beiden Upstream-Schalenschrauben mit (M3 × 12 statt × 8); Drehachse M3 × 40 mit Sicherungsmutter ergibt eine Reibungsneigung. Von der Oberschale hierher verlegt, weil in der ersten Position die Nase des Roboters 42 % des Bildes einnahm (Raycast-Prüfung); jetzt 0 % | | Obere Sensoren | `top_shell_sensor`, `lidar_pedestal` | 14-mm-Sockel mit Tasche für den C1-USB-Adapter hebt die Scanebene über jede Beinpose und die Kamera; Kabelschlitz zum Innenraum | | Rückwand | `back_shell_button`, `arming_port_bezel`, `arming_port_ring` | Bohrung Ø 12,2 mm für den Einschalttaster; XT60-Arming-Port in der vorhandenen Bohrung Ø 20 mm | | Elektronik | `electronics_deck` | Upstream-Platte + IMU-Tasche und Bohrungen für Abstandsbolzen für Spannungsregler und INA260; mit der Oberseite nach unten ohne Stützstrukturen druckbar | | Hohlräume | `lower_shoulder_frame_front/_rear`, `servo_bus_holder_front/_rear` | WAGO-Servostrombus pro Hohlraum, eine zusätzliche Vorbohrung im Upstream-Rahmen | | Zukaufteile | — | Pi 5 (war Pi 4), XIAO ESP32-S3 (war ESP32 DevKit), 2 × UBEC-10A (war ein SBEC), LiDAR, Kamera, LCD, INA260, LSM6DSOX, Pololu-Schalter und -Spannungsregler | Der Upstream-Körper „servo holder3“ in der STEP-Datei ist ein veraltetes Duplikat, das den echten Halter um 2860 mm³ überlappt; er wird ignoriert. Der Fuß-Distanzring und der Hüftlagerbolzen existieren nur in der STEP-Datei und werden als druckbare STLs exportiert. ## Kinematik {#kinematics} Jedes Bein: Hüftabduktion (Servo im Körper), Oberschenkel (Servo im Beinmodul, Direktantrieb) und Knie. Der Knieservo treibt eine Kurbel an; ein Parallelogramm und ein Viergelenk übertragen sie auf die Tibia, sodass der Unterschenkelwinkel eine nichtlineare Funktion des Kurbelwinkels *und* des Oberschenkelwinkels ist. `packages/strido-core/src/strido/leg.py` und das `servo_map` der Firmware lösen dieses Koppelgetriebe exakt aus den im CAD gemessenen Koppellängen (`hardware/kinematics.yaml`). Die Upstream-STEP-Datei hat eine Koppellängen-Abweichung von 1,02 mm (gezeichnetes Knie −98,8°, geschlossenes Koppelgetriebe −101,2°); verwendet werden die gemessenen Längen. Die Gelenkgrenzen stammen aus einer Kollisionsanalyse der gesamten Baugruppe (alle Teile und die Strido-Befestigungselemente; Upstream-Gelenkbefestigungen, deren Kopfseite und Mutterausrichtung angenähert sind, gehen nur in die statische Durchdringungsprüfung ein): Oberschenkel × Unterschenkel in einem 5°-Raster bei null Abduktion mit einem minimalen Übertragungswinkel von 25°, dann der Hüftbereich in der Stand- und Mittelpose mit dem gespiegelten Partnerbein und 0,3 mm Abstand (`hardware/joint_limits.yaml`, MECH-005). Die Codegenerierung hält zusätzlich jedes Gelenk innerhalb von ±85° Servoweg um seine Montage-Neutralstellung: | Gelenk | Grenze | |---|---| | Hüfte (Abduktion) | FL −17,5…50°, FR −50…17,5°, RL −17,5…45°, RR −45…17,5° | | Oberschenkel | −40…125° (vorne; Analyse −45°, durch den Servoweg um die 45°-Neutralstellung begrenzt), −15…125° (hinten) | | Unterschenkel | −150…−45° | | Kniekurbel | −2,5…75° | Montagereferenz (alle Servos bei 1500 µs): Beine in der Abduktion senkrecht, Femur 45° nach hinten, Kniekurbel 35°. ## Masseeigenschaften {#mass-properties} Die Massen ergeben sich aus den Teilevolumina (Druckteile: PETG/PLA-Dichte mit der effektiven Füllung der Druckeinstellungen) und aus Datenblattmassen für Zukaufteile (`hardware/mass_properties.yaml`); Trägheiten aus den Netzen, die verlegten Kabel nach Länge. Gesamt 3,07 kg; Werte pro Glied in `ros2/strido_description/config/mass_report.yaml`. --- # Downloads {#downloads} > **Status:** aus der verifizierten CAD-Baugruppe erzeugt; die folgenden Dateien werden bei jedem Deployment der Dokumentation neu gebaut. Sie werden von der Dokumentationswebsite ausgeliefert, nicht von der Repository-Ansicht. | Download | Inhalt | |---|---| | **[Baupaket (ZIP)](/downloads/strido-build-kit.zip)** | Jedes Druckteil als ausgerichtete STL, die fertigen 3MF-Druckplatten, das verifizierte PrusaSlicer-Profil, die Druckliste, das PDF des Katalog- und Montagebuchs und die Stückliste | | **[Katalog- & Montagebuch (A4-PDF)](/catalog/strido-catalog.pdf)** | Druck- und Kaufteile, Kleinteile im Maßstab 1:1, Einkaufsplan, Werkzeuge, jeder Montageschritt, Verkabelung, Software-Anhang | | 3D-Modell (GLB) | Der komplett montierte Roboter für jeden glTF-Viewer oder Blender; interaktiv in der [3D-Ansicht](viewer.md) | ## Alles drucken {#print-everything} 1. Entpacken Sie das Baupaket und laden Sie `prusaslicer.ini` (PrusaSlicer: File › Import › Import Config). Andere Slicer: Übernehmen Sie die Einstellungen aus `print_list.md` (0,4-mm-Düse, 0,2-mm-Schichten, 3 Perimeter, 5 obere/untere Schichten, 30 % Gyroid, PETG). 2. Drucken Sie die Druckplatten in `plates/`: Graphit-Platten für Rahmen und Beine, Limetten-Platten für Schalen und Schultern. Einzelteile: `stl/` (Stückzahlen in `print_list.md`). 3. Stützen und Brims wie pro Teil angegeben; die Slicer-Prüfung in [Druckbarkeit](verification/printability.md) slict jedes Teil und jede Druckplatte mit genau diesem Profil. Etwa 1 kg PETG (eine Spule pro Farbe) und rund 100 Stunden Druckzeit für den ganzen Roboter (Slicer-Schätzung). ## Quellcode {#source} Das Repository ist öffentlich: [github.com/Xpitfire/strido](https://github.com/Xpitfire/strido), Software unter Apache-2.0, Hardware-Dateien unter CERN-OHL-P-2.0. Es enthält die CAD-Pipeline, Firmware, ROS-2-Pakete, Simulation und jede Verifikationsprüfung; `make publish` erzeugt alle Downloads neu. --- # Elektronik, Verkabelung und Stromversorgung {#electronics-wiring-and-power} Strido teilt den Roboter in zwei Versorgungsdomänen mit gemeinsamer Masse: * **Servodomäne (6,0 V):** Akku → 25-A-Hauptsicherung → Arming-Loop-Key → zwei Hobbywing UBEC-10A → WAGO-Servobus im vorderen und hinteren Hohlraum → 12 Servos. Der PCA9685 liefert nur die Servo-*Signale*; Servostrom fließt nie über eine Logikplatine. * **Logikdomäne (5 V):** Akku → 25-A-Hauptsicherung → 7,5-A-Logiksicherung → Pololu-Tasterschalter → INA260 (misst Akkuspannung und Logikstrom) → Pololu D36V50F5 5 V/5,5 A → 5-V-GPIO-Pins des Raspberry Pi 5. Der Pi versorgt den XIAO ESP32-S3 (Bewegungscontroller) und den LiDAR-Adapter über USB. Die Platinenpositionen sind im CAD festgelegt; die [Durchdringungsprüfung](verification/interference.md) erfasst jede Platine, jeden Abstandsbolzen und jeden Steckverbinderkörper. Auch jedes Kabel wird im CAD verlegt (`hardware/wiring.yaml`, siehe [Kabelbaum](#wiring-harness)): Die Renderings, die 3D-Ansicht und die Montageanleitung stellen es dar, und die [Verkabelungsprüfung](verification/wiring.md) weist nach, dass jede Leitung ihr Ziel erreicht, jede Schlaufe über ein Hüftgelenk über den gesamten Hüftbereich Spiel hat und kein Kabel in den Betriebsposen ein bewegtes Teil berührt. **Stromversorgung** (Servodomäne links, Logikdomäne rechts): ```mermaid flowchart TD BAT["2S LiPo 5000 mAh
XT60-Leitung (W00)"] --> XT["Akkueingang Roboter XT60H
(unter dem Deck)"] -->|"W01 14 AWG"| FUSE["ATO-Halter, 25-A-Hauptsicherung
(hinterer Hohlraum)"] FUSE -->|"W02 14 AWG"| KEY["XT60-Arming-Port
(Rückschale, Loop-Key)"] KEY -->|"W03 14 AWG"| UF["UBEC-10A vorne
6,0 V"] -->|"W05"| WF["WAGO 221-415 ×4
Bus vorderer Hohlraum"] --> SF["FL-, FR-Servos ×6"] KEY -->|"W03 14 AWG"| UR["UBEC-10A hinten
6,0 V"] -->|"W06"| WR["WAGO 221-415 ×4
Bus hinterer Hohlraum"] --> SR["RL-, RR-Servos ×6"] FUSE -->|"Halterleitung 14 AWG"| LF["ATO-Halter, 7,5-A-Logiksicherung
(Rückschale)"] -->|"W09 18 AWG"| SW["Pololu #2813
Tasterschalter"] -->|"W10"| INA["INA260
0x41"] -->|"W11"| REG["Pololu D36V50F5
5 V 5,5 A"] XT -->|"W04 14/18 AWG, Massestern"| UF & UR & SW BTN["12-mm-Taster
(Rückschale)"] -.->|"A–B"| SW REG -->|"W12: GPIO-Pins 2/4 (5 V), 6/14 (GND)"| PI["Raspberry Pi 5"] ``` **Signale:** ```mermaid flowchart TD PI["Raspberry Pi 5"] -->|"USB-C"| XIAO["XIAO ESP32-S3"] PI -->|"USB"| LIDAR["RPLIDAR C1
+ USB-Adapter"] PI -->|"CSI 300 mm"| CAM["Camera Module 3 Wide"] XIAO -->|"I²C 400 kHz"| PCA["PCA9685 0x40"] XIAO -->|"I²C"| IMU["LSM6DSOX 0x6A"] XIAO -->|"I²C"| INA["INA260 0x41"] XIAO -->|"SPI"| LCD["Waveshare 2-inch ST7789"] XIAO -->|"D3 → OE (2,2-kΩ-Pull-up)"| PCA PCA -->|"nur Signal"| SERVOS["12 Servos"] ``` ## Nennwerte und Begründung der Teileauswahl {#ratings-and-why-these-parts} | Element | Nennwert | Last in diesem Roboter | Reserve / Hinweis | |---|---|---|---| | Servo SPT5435LV | nur 4,8–6,0 V; PWM-Signal 3,3–5,0 V; 35 kg·cm @ 6 V; Blockierstrom 3,5 A | Stehen ≈ 0,7 N·m am Knie (MuJoCo) | 6,0 V ist die Obergrenze: Verwenden Sie **nicht** die 7,4-V-Einstellung des UBEC. Der PCA9685 gibt 3,3-V-Pulse aus (VCC = XIAO 3V3), genau den niedrigsten zulässigen Signalpegel des Servos: innerhalb der Spezifikation, ohne Reserve | | Hobbywing UBEC-10A ×2 | 2–6S Eingang; 6,0 V ohne Jumper; je 10 A dauerhaft, 15 A Spitze | je 6 Servos | insgesamt 20 A dauerhaft / 30 A Spitze. Sechs blockierte Servos ziehen 21 A, mehr als die 15 A Spitze eines UBEC: Fahren Sie nie alle Beine gegen harte Anschläge und schalten Sie nie Strom zu, während Servos angesteuert werden (siehe erstes Einschalten) | | WAGO 221-415 | 32 A, 0,2–4 mm² | ≤ 3 Servos + Einspeisung je Klemme | 2 Klemmen (+/–) je Bein, insgesamt 8 | | Hauptsicherung (ATO) | 25 A | Servozweig (≤ 2 × 10 A UBEC-Ausgang ≈ 21 A bei leerem Akku) + Logik | schützt die 14-AWG-Hauptleitung dahinter; W01 (≈ 0,15 m vom Akkueingang) ist wie die eigene Leitung des Akkus ungesichert | | Logiksicherung (ATO) | 7,5 A | Logikzweig ≤ 3 A | schützt die 18-AWG-Logikverkabelung nach ihrem Halter. Der Abgriff von W02 ist die eigene 14-AWG-Leitung des Halters, daher liegt kein Draht dünner als 14 AWG allein hinter der 25-A-Sicherung | | Pololu #2813 (Big Pushbutton Power Switch HP) | 4,5–40 V; 6 A dauerhaft bei 55 °C | Logikzweig ≤ 3 A | nie im Servozweig; kein Not-Aus (Pololu) | | INA260 | 36 V, 15 A, 1,25 mA LSB | Logikzweig | misst die Akkuspannung für die Unterspannungsabschaltung. **Erforderlich:** ohne ihn verweigert die Firmware die Ansteuerung der Servos | | Pololu D36V50F5 | 5 V ± 4 %, 5,5 A typisch dauerhaft | Pi 5 + USB + Kamera ≈ 2–3 A | Pi benötigt `PSU_MAX_CURRENT=5000` (siehe unten) | | XT60-Arming-Port | 30 A dauerhaft | Servozweig | der Loop-Key ist ein XT60 mit 14-AWG-Brücke, siehe die Steckerregel unten | Jeder Versorgungseingang und jedes Logiksignal wird von `python -m strido_verify.electronics` gegen seinen Nennbereich geprüft (Schienen, Versorgungen und Signale in `hardware/electronics.yaml`; Bericht in [verification/electronics.md](verification/electronics.md)). Drei bestehen ohne Reserve: Servo-PWM und LCD laufen mit 3,3 V, dem niedrigsten Pegel, den beide akzeptieren; eine schwache 3V3-Schiene des XIAO (unter 3,3 V) ist daher das Erste, was Sie messen sollten, wenn ein Servo zittert oder das LCD dunkel bleibt. ### XT60-Kontaktregel (der Loop-Key darf nie auf den Akku passen) {#xt60-contact-rule-the-loop-key-must-never-fit-the-battery} Beschreiben Sie XT60-Hälften nach ihren Kontakten, nicht als „Stecker/Buchse“ (Händler verwenden beide Wörter für beide Hälften): Eine Hälfte hat **Stifte**, die andere **Buchsenkontakte** (Amass: XT60-M = Stifte, XT60-F = Buchsenkontakte). Der Loop-Key ist ein kurzgeschlossener Steckverbinder, daher muss er **denselben Kontakttyp wie der Steckverbinder des Akkus** tragen: Dann lässt er sich nicht mit dem Akku verbinden. Der Akkueingang des Roboters und der Arming-Port tragen den anderen Typ. Beispiel: Akku mit Buchsenkontakten → Akkueingang des Roboters Stifte, Arming-Port Stifte, Loop-Key Buchsenkontakte. Das CAD modelliert einen Arming-Port XT60H-F (Buchsenkontakte), also einen Akku mit Stiften; tauschen Sie alle drei, wenn Ihr Akku Buchsenkontakte hat. Prüfen Sie vor dem Brücken des Steckers: Nehmen Sie das *ungebrückte* Steckergehäuse und versuchen Sie es auf den Akkustecker zu stecken; es darf nicht passen. Testen Sie nie mit einem gebrückten Stecker. Der Akku selbst passt in den Arming-Port; beschriften Sie den Port mit „ARM“ und schließen Sie den Akku immer am Akkueingang unter dem Deck an (W00 in den XT60H von W01/W04). ## Verkabelungsliste {#wiring-list} Jedes Kabel aus `hardware/wiring.yaml`; Verläufe, Zuschnittlängen und die Prüfungen stehen in der [Verkabelungsprüfung](verification/wiring.md) (aus dem CAD neu erzeugt). Farbe: rot = +, schwarz/braun = –, Signale wie angegeben. | ID | Von | Nach | Kabel | Anschluss | |---|---|---|---|---| | W00 | Akku (eigene 12-AWG-Leitung) | Akkueingang XT60H, unter dem Deck | mit dem Akku geliefert | in Schritt 22 einstecken | | W01 | Akkueingang XT60H (+) | Halter der 25-A-Hauptsicherung (hinterer Hohlraum) | 14 AWG rot in Spiralschlauch | löten, Schrumpfschlauch; an die auf 20 mm gekürzte Halterleitung gespleißt; ungesichert | | W02 | Ausgang Hauptsicherung (Halterleitung auf 20 mm gekürzt) | Spleiß in der Rückschale → Arming-Port Kontakt 1 und eigene Eingangsleitung des Logiksicherungshalters (auf Zuschnittlänge gekürzt) | 14 AWG rot | löten + Schrumpfschlauch an den Spleißen | | W03 | Arming-Port Kontakt 2 | Spleiß unter dem Deck → UBEC vorne IN+ und UBEC hinten IN+ | 14 AWG rot | löten; der Loop-Key verbindet die beiden Kontakte des Ports | | W04 | Akkueingang XT60H (–) | Massestern daneben → UBEC IN– ×2 (14 AWG), Schalter GND (18 AWG) | 14 / 18 AWG schwarz | ein Sternpunkt am Akkueingang | | W05 / W06 | UBEC vorne / hinten OUT | Port 0 von WAGO-Platz 0, vorderer / hinterer Hohlraum | UBEC-Leitung mit 18-AWG-Paar verlängert | 11 mm abisolieren, in das WAGO-Paar (rot V+ oben, schwarz GND unten) | | W07 / W08 | WAGO-Port 4 von Platz 0 | Port 0 von Platz 1 (zweites Bein des Hohlraums) | 18 AWG, ein Draht je Schiene | entlang der WAGO-Stirnseiten | | S-*leg*-*joint* (12) | Servokabel | am Basis-Kabelbinder aufgeteilt: rot/braun → WAGO-Paar des Beins (Port Hüfte 1, Oberschenkel 2, Knie 3); orange → PCA9685-Kanal | eigenes 260-mm-Servokabel, auf Länge gekürzt | rot/braun abisoliert in die WAGO; orange neu gecrimpt (Dupont-Buchse, 1-poliges Gehäuse) | | W09 | Ausgang 7,5-A-Logiksicherung (Halterleitung auf 20 mm gekürzt) | Schalter VIN | 18 AWG rot | Spleiß am Halter, Schraubklemme am Schalter; seine Masse ist W04 | | W10 | Schalter VOUT | INA260 VIN+ | 18 AWG rot | Schraubklemmen; der INA260 ist ein High-Side-Shunt | | W11 | INA260 VIN– | D36V50F5 VIN | 18 AWG rot | Schraubklemme, löten | | W24 | Schalter GND | D36V50F5 GND | 18 AWG schwarz | die Klemmleiste des INA260 nimmt nur VIN+ und VIN– auf; seine Logikmasse kommt über I²C (W19) | | W12 | D36V50F5 VOUT / GND | Pi-5-Header Pins 2 + 4 (5 V), 6 + 14 (GND) | 22 AWG ×4 | Dupont-Buchse gecrimpt, ein Draht je Pin (2 × 1,5 A je Schiene) | | W13 | 12-mm-Taster | Schalter A und B | 22-AWG-Paar | löten, Schrumpfschlauch | | W14 | Pi 5 USB-A (unterer Port des linken Stapels) | XIAO USB-C | 20 cm USB-A (90°) → C | Überlänge im vorderen Hohlraum falten | | W15 | Pi 5 USB-A (oberer Port) | LiDAR-USB-Adapter (im Sockel) | 20 cm USB-A (90°) → C | über den Pi neben dem Kühlerlüfter, nach oben durch den Schlitz der Oberschale | | W16 | Pi 5 CAM/DISP 0 | Camera Module 3 Wide | Flachbandkabel 22→15 Pin, 300 mm | durch beide Schulterrahmenöffnungen und den Schlitz der Frontschale; flach falten | | W17 | XIAO D4/D5 (SDA/SCL), 3V3, GND | linker Header des PCA9685 (SDA, SCL, VCC, GND) | 22 AWG ×4 | an die XIAO-Pins gelötet (kein Platz für Gehäuse unter dem oberen Schulterrahmen), Dupont-Crimps am PCA | | W18 | rechter Header des PCA9685 (VCC, SDA, SCL, GND) | LSM6DSOX STEMMA QT | STEMMA QT → Buchsenkontakte, 150 mm | die IMU sitzt 2,5 mm unter dem Pi: nur der flache STEMMA-QT-Stecker passt | | W19 | zweiter STEMMA QT des LSM6DSOX | INA260-Header (VCC, SDA, SCL, GND) | STEMMA QT → Buchsenkontakte, 150 mm | INA260-Jumper A0 gebrückt → 0x41 | | W20 | XIAO D3 | PCA9685 OE | 22 AWG grün | high = alle Servoausgänge aus. Löten Sie einen 2,2-kΩ-Widerstand von OE nach VCC am PCA9685-Header: Die Platine zieht OE auf low, ohne ihn bleiben die Ausgänge also aktiv, während der XIAO zurückgesetzt wird oder im Bootloader steht | | W21 | XIAO D8, D10, D9, D0, D1, D2, 3V3, GND | LCD CLK, DIN, DC, CS, RST, BL, VCC, GND | Displaykabel (PH2.0 8-polig, 200 mm, mitgeliefert) | seine Dupont-Enden an die XIAO-Pins gelötet; 3V3 und GND teilen sich die Pins mit W17 | | W22 (optional) | Pi 5 GPIO 26 (Pin 37) | Schalter OFF | 22 AWG weiß | Dupont-Crimp am Pi, am Schalter gelötet; ermöglicht dem Pi, nach dem Herunterfahren die eigene Versorgung abzuschalten, siehe unten | | W23 | RPLIDAR C1 | sein USB-Adapter | eigenes Kabel des Sensors | durch die Kerbe vorne am Sockel | ## Pinbelegungen {#pin-maps} **XIAO ESP32-S3** (`firmware/strido_esp32s3/src/board_config.h` ist die maßgebliche Quelle) | XIAO-Pin | GPIO | Funktion | |---|---|---| | D0 | 1 | LCD CS | | D1 | 2 | LCD RST | | D2 | 3 | LCD-Hintergrundbeleuchtung (PWM; Strapping-Pin, erst nach dem Booten angesteuert) | | D3 | 4 | PCA9685 OE (Low-aktive Freigabe; Firmware hält ihn bis zum Scharfschalten auf high) | | D4 | 5 | I²C SDA | | D5 | 6 | I²C SCL | | D8 | 7 | LCD SCK | | D9 | 8 | LCD DC | | D10 | 9 | LCD MOSI | | — | 21 | Onboard-Benutzer-LED (Status) | **PCA9685-Kanäle** (200 Hz, 500–2500 µs) | Bein | Hüfte | Oberschenkel | Kniekurbel | |---|---|---|---| | FL | 15 | 11 | 7 | | FR | 14 | 10 | 6 | | RL | 13 | 9 | 5 | | RR | 12 | 8 | 4 | **I²C-Bus:** PCA9685 0x40 (und seine All-Call-Adresse 0x70), LSM6DSOX 0x6A, INA260 0x41 (A0 gebrückt; 0x40 würde mit dem PCA9685 kollidieren). ## Leistungsbudget und Laufzeit {#power-budget-and-runtime} | Verbraucher | Typisch | Spitze | Quelle | |---|---|---|---| | 12 Servos stehend | ≈ 30 W (≈ 5 A bei 6 V) | — | [ESTIMATE] aus den MuJoCo-Stehmomenten und dem Blockierstrom von 3,5 A bei 3,43 N·m | | 12 Servos im Trot | ≈ 50 W | > 150 W für ms | [ESTIMATE] | | Pi 5 + Kühler | 5–7 W | 12 W | Raspberry Pi | | RPLIDAR C1 | ≈ 1,2 W | — | Slamtec-Datenblatt | | Kamera, XIAO, LCD, IMU, PCA | ≈ 1,5 W | — | Datenblätter | | **Gesamt im Trot** | ≈ 60 W aus dem Akku (90 % Wandler) | | | 2S 5000 mAh ≈ 37 Wh, 80 % nutzbar → **≈ 30 min Trot, ≈ 45 min Stehen** [ESTIMATE; messen Sie mit `/battery_state` und den Strom am Loop-Key mit einer Strommesszange]. Die Firmware warnt bei 6,8 V (3,4 V/Zelle) und entspannt die Servos bei 6,4 V (3,2 V/Zelle). ## Kabelbaum {#wiring-harness} ![Der verlegte Kabelbaum mit abgenommenen Schalen, oberen Sensoren und oberen Schulterrahmen](../../docs/images/wiring.png) Der Kabelbaum wird im CAD konstruiert, nicht beim Bau improvisiert: `hardware/wiring.yaml` benennt jedes Kabel, den Steckverbinder an jedem Ende und die Befestigungspunkte, die es passiert; `strido_cad.wiring` verlegt die Abschnitte zwischen diesen Punkten durch den freien Raum des Roboters (jedes Basisteil und alles, was die Beine über ihre Gelenkbereiche überstreichen, wird ausgespart), und das Ergebnis wird in den Renderings, der [3D-Ansicht](viewer.md) und der [Montageanleitung](assembly/README.md) (Schritte 14–16, die Schalenschritte und Schritt 20) dargestellt. Die [Verkabelungsprüfung](verification/wiring.md) weist dann unabhängig vom Router nach: * **Reichweite:** jede fertig konfektionierte Leitung (Servokabel 260 mm, USB 200 mm, Flachband 300 mm, STEMMA QT 150 mm, Akkuleitung) deckt ihren Verlauf mit mindestens 10 mm Reserve ab; * **Material:** die Zuschnittliste (Verlauf + Abisolier-/Lötzugabe + 8 % Spiel) passt zu Draht, Spiralschlauch und Kabelbindern in der Stückliste; * **Hüftschlaufen:** die Servokabel der Oberschenkel- und Knieservos laufen auf der Hüfte mit und kreuzen das Hüftgelenk nahe seiner Achse; jedes hat eine freie Schlaufe von mindestens dem 1,2-Fachen des größten Abstands, den seine zwei Befestigungspunkte über den gesamten Hüftbereich erreichen (36 mm Oberschenkel, 40 mm Knie); * **Freigang:** kein Kabel verläuft durch ein Teil, und gegenüber jedem Teil eines anderen Körpers (Beine, Hörner, Koppeln) hält es in den 13 Betriebsposen den Laufabstand der Prüfung bewegter Teile ein (der Router hält Kabel aus allem heraus, was die Beine über ein Raster von Gelenkwinkeln überstreichen); * **Ports:** ein Kabel je WAGO-Eingang, ein Stecker je PCA9685-Kanal. Bauablauf (die Anleitung stellt jeden Schritt dar): 1. **Servobus.** Klipsen Sie die vier WAGO 221-415 in jeden Bushalter: je Bein eine V+-Klemme (oben) und eine GND-Klemme (unten); alle Eingänge zeigen zur linken Seite des Roboters. Platz 0 (vorne in jedem Hohlraum): UBEC-Einspeisung Port 0, Hüfte/Oberschenkel/Knie Ports 1–3, Brücke Port 4. Platz 1: Brücke Port 0, Servos 1–3, Port 4 frei. Klipsen Sie ein WAGO-Paar aus, um seine Hebel zu öffnen: Auf Platz 0 blockiert die XIAO-Plattform sie. 2. **UBECs.** Lassen Sie den Ausgangsjumper offen (6,0 V). Messen Sie die Leerlaufausgangsspannung, bevor Sie ein Servo anschließen: zulässig sind 5,8–6,0 V (das Servo ist bis 6,0 V spezifiziert; senden Sie ein Gerät mit höherem Messwert zurück). Kleben Sie beide UBECs mit Schaumklebeband in die Seitentaschen unter dem Deck. 3. **Stromeingang (Schritt 14).** Akkueingang XT60H mit W01 (rot, im Spiralschlauch) und W04 (schwarz) in der Tasche neben dem Akku; Massestern; Hauptsicherungshalter (Leitungen auf 20 mm gekürzt) am hinteren WAGO-Bus, am oberen Schulterrahmen befestigt; W02, W03 und W09 laufen in den Raum der Rückschale; noch keine Sicherungen. 4. **Servokabel (Schritt 15).** Binden Sie jedes Oberschenkel- und Kniekabel an der Servohalterplatte fest, lassen Sie die freie Schlaufe, binden Sie es am Schulterrahmen oder Bushalter fest; teilen Sie es dort auf: rot/braun auf Länge gekürzt in das WAGO-Paar des Beins, orange auf Länge gekürzt und neu gecrimpt für seinen PCA9685-Kanal. Die Kabel der Hüftservos werden an der Öffnung des inneren Rahmens aufgeteilt. 5. **Logik und Signale (Schritt 16).** W10/W11 (18 AWG rot) vom Schalter über den INA260 (A0 gebrückt) zum D36V50F5, W24 (18 AWG schwarz) Schalter-GND zu Regler-GND, W12 gecrimpt, aber **noch nicht eingesteckt** in den Pi, W14, W17–W20, W22. 6. **Schalenschritte.** Displaykabel W21 (Schritt 17), Kamera-Flachbandkabel W16 (Schritt 18); Rückwand (Schritt 19): Taster W13, W02/W03 an den Arming-Port gelötet, Logiksicherungshalter in W02 und W09 gespleißt. 7. **Versorgungsprüfung und Kabelführung (Schritt 20).** Akku kurz eingesteckt, beide Sicherungen eingesetzt, Loop-Key gezogen, Taster gedrückt: 4,8–5,2 V an den Dupont-Enden von W12 (D36V50F5: 5 V ± 4 %); Sicherungen wieder heraus, dann W12 auf die Pi-Pins 2/4/6/14 stecken. Spiralschlauch über jedes Bündel aus drei oder mehr Kabeln und über W01, Kabelbinder an den markierten Punkten, zwei selbstklebende Kabelbinder-Sockel auf dem Deck; bewegen Sie jedes Bein von Hand durch seinen Bereich und prüfen Sie, dass nichts zieht oder scheuert. Die LiDAR-Kabel kommen mit der Oberschale (Schritt 21), die Akkuleitung mit dem Akku (Schritt 22). 8. **Rauchtest ohne Servos:** Sicherungen eingesetzt, Loop-Key **gezogen**, einschalten → Pi bootet, `ros2 topic echo /battery_state` zeigt die Akkuspannung, `/diagnostics` zeigt `pwm_ok`, `imu_ok`, `power_ok`. Halten Sie die BOOT-Taste des XIAO und drücken Sie RESET: OE muss ≥ 2,4 V (Ausgänge aus) anzeigen, solange er im Bootloader steht. Warum der Kabelbaum so ausgelegt ist: [Kabelmanagement](wiki/making/cable-management.md) (Entscheidung: [ADR-011](decisions.md#adr-011-wiring-harness-routed-and-checked-in-the-cad)). ## Konfiguration des Raspberry Pi {#raspberry-pi-configuration} Die Versorgung über die 5-V-GPIO-Pins umgeht USB-PD; teilen Sie dem Pi daher mit, dass die Versorgung 5 A liefern kann: ```bash sudo rpi-eeprom-config --edit # add: PSU_MAX_CURRENT=5000 echo "usb_max_current_enable=1" | sudo tee -a /boot/firmware/config.txt ``` Stabile Gerätenamen (`ros2/strido_bringup/config/99-strido.rules`): ```bash sudo cp ros2/strido_bringup/config/99-strido.rules /etc/udev/rules.d/ && sudo udevadm control --reload && sudo udevadm trigger ``` Optionale Selbstabschaltung (W22): `dtoverlay=gpio-poweroff,gpiopin=26` in `config.txt` setzt GPIO 26 nach dem Herunterfahren auf high, was einen Puls auf den OFF-Eingang des Schalters gibt. [UNVERIFIED on Pi 5: test with the servos disarmed before relying on it.] ## Sicherheitsregeln {#safety-rules} * Laden Sie nur in einem LiPo-Sack mit einem Balancer-Ladegerät; lassen Sie den Ladevorgang nie unbeaufsichtigt. * Der Loop-Key ist die Servo-Abschaltung: Ziehen Sie ihn zum Entschärfen. Der Tasterschalter ist kein Not-Aus (Pololu sagt das ausdrücklich). * `/strido/estop` rastet ein: Die Firmware setzt PCA9685 OE auf high und stoppt alle Pulse. * Einschaltreihenfolge: Logik ein → Roboter liegt in der Ruhepose (Beine eingeklappt) → Loop-Key einsetzen (Servos bleiben schlaff; der Controller sendet vor dem ersten Positionsbefehl keine Pulse) → `ros2 launch strido_bringup robot.launch.py` starten (Servos fahren in die Ruhepose, dann 3 s Aufstehen). Setzen Sie den Loop-Key nie ein, während Positionsbefehle laufen: Alle Servos würden gleichzeitig springen. * Die Firmware verweigert die Ansteuerung ohne funktionierenden INA260 (sonst gäbe es keine Unterspannungsabschaltung). Die Abschaltung benötigt 5 aufeinanderfolgende Messwerte (0,5 s) unter 6,4 V, damit Spannungseinbrüche unter Last den Roboter nicht mitten im Schritt absetzen. * Ohne Befehle für 200 ms halten die Servos ihre Pose; 2 s später entspannen sie. Es gibt kein separates Keep-alive: Fällt der Gait- oder Policy-Node aus, hält der Roboter und entspannt dann. --- # Erste Schritte {#getting-started} Sieben Etappen vom leeren Tisch zum gehenden Roboter. Jede Etappe verlinkt auf die Seite mit den Details; das [Lernen-Wiki](wiki/README.md) erklärt die Technik dahinter. ## 1 · Drucken {#_1-·-print} Am einfachsten: Die Seite [Druckpaket](print-kit.md) erstellt ein druckfertiges Paket (wählen Sie komplette Roboter oder einzelne Teile; STLs mit ihrer Stückzahl im Namen, das Slicer-Profil, ein Teileblatt und die fertigen Druckplatten), oder laden Sie das gesamte Baupaket von der Seite [Downloads](downloads.md). Importieren Sie die enthaltene `prusaslicer.ini` (PrusaSlicer: Datei › Importieren › Konfiguration importieren; andere Slicer: übernehmen Sie die Werte aus der [Druckliste](../hardware/print/print_list.md)) und drucken Sie dann die Druckplatten (Druckbett 220 × 220 mm oder größer) oder die einzelnen STLs. Jedes Teil und jede Druckplatte wurde mit genau diesem Profil gesliced ([Druckbarkeit](verification/printability.md)); etwa 1,0 kg PETG und 100 h Druckzeit. Die limettengrünen Teile sind die Schalen und Schultern; alles andere ist graphitfarben. Beachten Sie nach dem Drucken die Warnungen im [Passungsbericht](verification/fits.md). ## 2 · Kaufen {#_2-·-buy} Der [Shop](shop.md) verkauft den kompletten Roboter als ein Bausatz (oder einzelne Teile) mit echten Shop-Angeboten: Wählen Sie einen der vier [Einkaufspläne](bom/shopping_list.md) oder ändern Sie den Shop pro Teil, sehen Sie die Gesamtsumme inklusive der Versandkosten jedes Shops im Warenkorb und gehen Sie pro Shop mit einer geführten Checkliste zur Kasse, die nacheinander die Shopseite jedes Artikels öffnet (dazu eine kopierbare Bestellliste für Shops mit Schnellbestellformular). Befestigungselemente enthalten 10 % Reserve. Werkzeug: Abschnitt E des [Katalog-PDFs](catalog/strido-catalog.pdf). ## 3 · Montieren {#_3-·-assemble} Folgen Sie der [Montageanleitung](assembly/README.md) oder dem PDF. Die [3D-Ansicht](viewer.md) spielt jeden Schritt am vollständigen Modell ab. Vor Schritt 1: Zentrieren Sie alle zwölf Servos (Etappe 5 unten kann vorher auf dem Arbeitstisch erfolgen). ## 4 · Verkabeln {#_4-·-wire} [Elektronik](electronics.md): Versorgungsbaum, Verkabelungsliste, der verlegte Kabelbaum, Pinbelegung und der erste Rauchtest ohne Servos. Die Pinbelegung wird maschinell gegen die Firmware geprüft ([Elektronikprüfung](verification/electronics.md)). ## 5 · Flashen und kalibrieren {#_5-·-flash-and-calibrate} ```bash uv sync --locked # Python tools (strido-cli) cd firmware/strido_esp32s3 && pio run -e xiao_esp32s3 -t upload uv run strido-cli --port /dev/ttyACM0 center # assembly reference: hip vertical, femur 45° back, crank 35° uv run strido-cli --port /dev/ttyACM0 calibrate # per-joint trim, stored in flash ``` Details: [Software › Firmware](software.md#firmware) und [Elektronik › Kabelbaum](electronics.md#wiring-harness). ## 6 · Ausführen {#_6-·-run} Auf dem Raspberry Pi 5 (Docker): `docker compose -f docker/compose.yaml run --rm robot`, dann `ros2 run teleop_twist_keyboard teleop_twist_keyboard`. Topics und Launch-Dateien: [Software](software.md). ## 7 · Simulieren, trainieren, integrieren {#_7-·-simulate-train-integrate} `make sim-walk`, `make sim-gazebo`, `make rl-train` und das NT-X-Harness über `make ntx-smoke`: [Simulation](simulation.md), [NT-X-Integration](ntx-integration.md). ## Entwicklung an diesem Repository {#developing-on-this-repository} Design ändern, Verifikationsprüfungen ausführen oder diese Site neu bauen: siehe das [Harness-Runbook](harness.md). --- # Runbook für den Engineering-Harness {#engineering-harness-runbook} > **Status:** wie an diesem Repository gearbeitet wird (Menschen und Coding-Agenten). Regeln: `AGENTS.md`. ## Einrichtung {#setup} ```bash make setup # uv sync, docs-site npm ci, submodules, harness install (hooks, skills, MCP config) ``` Voraussetzungen: uv ≥ 0.9, Python 3.12 (von uv verwaltet), Node 26 (`.nvmrc`), PlatformIO (`pipx install platformio`), Blender 4 für Renderings, Docker für Gazebo, Pango für das PDF (`brew install pango`). ## Prüfungen {#gates} | Stufe | Befehl | Belegt | Dauer | |---|---|---|---| | Q0 | `make check-fast` | ruff, mypy (strikt für core/ntx/workspace), import-linter-Schichten, Drift generierter Dateien (Geometrie-Bindings, Elektronikbericht, NT-X-Assets), Python-Tests mit Coverage, native Firmware-Tests | ~1 min | | Q1 | `make verify` | CAD: Bohrungsstapel → Befestigungselemente, Durchdringung (4 Posen), Sensor-Sichtfeld, Bewegungsbereichs-Sweep, Passungen/Toleranzen, Festigkeit (Biegung/Knickung der Koppeln, Schraubenscherung, Lochleibung, Lager, Vorbohr-Drehmomente), Freigang in Bewegung | ~10 min | | Q1 | `make printability` | jedes gedruckte Teil und jede 3MF-Druckplatte mit PrusaSlicer und `hardware/print/prusaslicer.ini` gesliced (Fehler, Konflikte, Stabilitätsprobleme, fehlende Teile führen zum Abbruch), Wandstärken-Scan, Filament und Zeit | ~1 min, benötigt PrusaSlicer | | Q1 | `make check` | Q0 + verify + printability + Stücklisten-Abdeckung + CAD-Tests + Docs-Build + Harness-Prüfungen | ~13 min | | Q2 | `make smoke` | MuJoCo-Laufvideo, MCP-Server über stdio, NT-X-Erweiterung im NT-X-Harness | ~2 min | | Q2 | `make sim-gazebo`, `make rl-smoke` | ROS-2- + Gazebo-Lauftest in Docker; PPO-Pipeline | 5–10 min | | Q3 | Hardware | ein gebauter Roboter: Stehen, Laufen, gemessener Strom/gemessene Laufzeit | — | Der Pre-Commit-Hook führt den Harness-Selbsttest aus; die CI (`.github/workflows/quality.yml`) führt Q0 und den Docs-Build aus. ## Hardware ändern {#changing-hardware} 1. Bearbeiten Sie die Quelle: ein CadQuery-Teil in `packages/strido-cad/src/strido_cad/parts.py`, eine Platzierung, `hardware/*.yaml`. 2. `make cad`, wenn sich Kinematik oder Grenzen ändern können, sonst `make models`. 3. `make verify` — korrigieren Sie die Geometrie, bis sie besteht; erweitern Sie niemals `hardware/verification/*.yaml`, nur damit sie besteht. Halten Sie jede bewusste Regeländerung in `docs/decisions.md` fest. 4. `make publish` — Druckpaket, Stückliste, Anleitung, Renderings, 3D-Ansicht, Buch. 5. `make check-fast`, den Lauf in `docs/verification.md` festhalten. ## Agenten-Werkzeuge {#agent-tooling} * **Skills** (`.agents/skills/`): `strido-hardware`, `strido-verification`, `strido-bringup`, `strido-docs`, `strido-ntx`, dazu die Harness-Skills (`software-engineering`, …). * **MCP** (`.mcp.json`, `.codex/config.toml`): `strido-hardware` (Teilegrößen, Befestigungselemente, Passungen, Freigänge, Gelenkgrenzen, Pinbelegung, Stückliste, Verifikationsstatus), `codegraph` (Code-Index). * **CLI**: `uv run strido part electronics_deck`, `strido pinout lcd`, `strido fits --status warn`, `strido clearances --max-gap 1`. ## Release {#release} `make publish && make package` schreibt `dist/strido-.zip` (Repository + PDF + Laufvideo). Tag `strido-v`. ## Dokumentationsseite auf Cortex {#documentation-site-on-cortex} Die Website läuft öffentlich unter **https://strido.cortex.a2olabs.com/**, auf Englisch und Deutsch (`/de/`). Das Image (`docs-site/Dockerfile`, `docker-compose.docs.yml` + `docker-compose.cortex.yml`) baut die Website aus dem Repository und bündelt die Downloads: das Bausatz-ZIP (jede STL, die 3MF-Platten, Slicer-Profil, Druckliste, Buch-PDF, Stückliste), das Buch-PDF, das 3D-Modell, das Agent-Skill-ZIP und `llms.txt`. Ein zweiter Dienst, `assistant`, beantwortet die KI-Leiste und den MCP-Server `/mcp` aus denselben Seiten; er erreicht das Modell über Cortex Keyring (`models` in `.cortex/app.yml`) und speichert Unterhaltungen in einem Docker-Volume. Die eigene Gateway-Route der App (`.cortex/access/caddy/sso/`) liefert die Website an alle aus und leitet `/api/*` und `/mcp` hinter Cortex-SSO (oder einem Cortex-App-Token) an den Assistenten weiter, sodass die Modellnutzung bei angemeldeten Nutzern bleibt. ```bash make docs & make assistant # local: site with live AI bar on http://127.0.0.1:4173/ docker compose -f docker-compose.docs.yml up --build # local images: site :4392, assistant :4393 make i18n # after English changes: new German segments to translate git push # Cortex builds from GitHub, not from the checkout cortex deploy --ref "$(git rev-parse HEAD)" cortex jobs watch cortex apps show strido ``` Das Repository ist öffentlich unter [github.com/Xpitfire/strido](https://github.com/Xpitfire/strido). Veröffentliche erst nach `make publish` und `make printability`, damit die Downloads zur verifizierten CAD passen. --- # NT-X-Integration {#nt-x-integration} > **Status:** Katalog, Simulation und serieller Transport sind in der NT-X-Harness-Umgebung verifiziert (`make ntx-smoke`). Um den physischen Roboter aus einer NT-X-Session zu öffnen, ist eine Änderung am NT-X-Kern nötig (siehe unten). `packages/strido-ntx` ist eine NT-X-Erweiterung. In die NT-X-Umgebung installiert, steuert sie Folgendes bei: | Einstiegspunkt | Beitrag | |---|---| | `ntx.assets` → `strido_ntx` | `robots/strido.yaml` (RobotSpec), `robots/models/strido.xml` + Meshes (MJCF), `skills/strido-stand.yaml` | | `ntx.adapters` → `strido_ntx.plugin:register` | Roboter-Adapter `strido-serial` → `StridoSerialPort` | | `ntx-extension.yaml` | Manifest für `ntx ext info/doctor strido` | ## In NT-X installieren {#install-into-nt-x} ```bash cd ../../ntx-harness uv pip install -e ../workspace/robot/packages/strido-core -e ../workspace/robot/packages/strido-ntx uv run ntx ext doctor strido uv run ntx robots show strido ``` `make ntx-smoke` führt dieselben Prüfungen aus, ohne das NT-X-Virtualenv zu verändern (`uv run --project ntx-harness --with-editable …`): Der Roboter wird aus dem Katalog geladen, in eine NT-X-MuJoCo-Welt kompiliert und steht 2 s lang, der Adapter ist registriert, und der serielle Port steuert eine simulierte MCU auf Protokollebene (Befehl → Zustand → Schutzstopp → Schließen). ## Roboter-Spezifikation {#robot-spec} Erzeugt von `python -m strido_ntx.build_assets` aus dem CAD-abgeleiteten MJCF (`make models` führt es aus; `make drift` prüft es): * Gelenke in MCU-Reihenfolge FL, FR, RL, RR × (Hüfte, Oberschenkel, Unterschenkel), Grenzen aus dem Kollisions-Sweep, Standardwerte = 170-mm-Standpose; * SPT5435LV-Grenzen: 3,43 N·m Kraft, 7,48 rad/s Geschwindigkeit; PD-Verstärkungen aus dem MuJoCo-Servomodell; * Füße `FL_foot` … Körper in den Fußmittelpunkten; `hardware_status: unverified`, bis ein Roboter qualifiziert ist. ## RobotPort-Semantik (`StridoSerialPort`) {#robotport-semantics-stridoserialport} | NT-X erwartet | Strido liefert | |---|---| | `read_state().q`, `dq`, `tau` | `q` = der Winkel, den die MCU nach ihren Begrenzungen anwendet (Hobby-Servos melden nichts zurück); `dq` Nullen; `tau` leer | | Basispose / Geschwindigkeit | Orientierung + Drehraten des Körpers aus der IMU; Position und Lineargeschwindigkeit nicht gemessen → `has_odometry = False`. Ein Zustand mit gelöschtem `imu_ok` rastet den Schutzstopp ein und löst `ImuUnavailableError` aus (sicherer Zustand bei Fehler) | | `apply(JointCommand)` | nur Positionsziel. Positive `kp`/`kd` gelten als feste Steifigkeit des Servos, und `tau_ff` (die Schwerkraft-Vorsteuerung von `pd-pose`) wird verworfen; ein `dq` ungleich null oder `kp <= 0` wird abgelehnt; nicht endliche Ziele rasten einen Schutzstopp ein | | `hold()` | sendet das letzte Ziel erneut (MCU-Watchdog hält 200 ms, entspannt nach 2 s) | | `protective_stop()` | eingerasteter MCU-Not-Halt: PCA9685 OE high, alle Servopulse aus. Servos werden schlaff (keine Dämpfung) | | `release()`, `close()` | Not-Halt aufheben; serielles Gerät stoppen und freigeben | | Aktualität | der Eingangspuffer wird beim Öffnen geleert und bei jeder Abfrage ausgelesen (der neueste Frame gewinnt); `TimeoutError`, wenn innerhalb von 0,2 s kein Zustands-Frame eintrifft | **Odometrie-Prüfung.** NT-X-Sessions verweigern Nicht-Gantry-Skills an einem Port ohne Odometrie (`ntx.runtime.session._check_port_support`). `strido-stand` ist ein frei stehender Skill, läuft auf der Hardware also erst, wenn ein Basis-Schätzer existiert, oder als Gantry-Variante mit dem Körper auf einem Ständer und frei hängenden Beinen. Simulations-Sessions sind nicht betroffen (der MuJoCo-Port misst die Basis). ## Was NT-X für Hardware-Sessions ändern muss {#what-nt-x-needs-to-change-for-hardware-sessions} NT-X öffnet Hardware über `ntx.deploy.open_robot_port`, das immer den Unitree-SDK2-Port erzeugt, und `TargetSpec.transport.kind` akzeptiert nur `unitree-sdk2`. Um Strido live aus einer Session zu betreiben, sollte NT-X Hardware über seine Adapter-Registry ansteuern: 1. `transport.kind`-Werte zulassen, die einen registrierten `robot`-Adapter benennen (z. B. `strido-serial`); 2. in `open_robot_port`, `registry.create("robot", target.transport.kind, spec=robot, device=…)`; 3. ein Target `config/targets/strido-desk.yaml` mit den Qualifikationsprüfungen (Identität, Not-Halt, Shadow) für einen gebauten Roboter hinzufügen; 4. eine Basispose-Schätzung (IMU + Beinkinematik) oder eine Gantry-Variante von `strido-stand` für die ersten Hardware-Sessions bereitstellen. Diese Änderung gehört in das NT-X-Repository und wird in [TODO](https://github.com/Xpitfire/strido/blob/main/TODO.md) verfolgt; nichts in diesem Repository verändert NT-X. ## Training in NT-X {#training-in-nt-x} Die NT-X-Vorlage `locomotion-velocity` trainiert jeden Vierbeiner aus dem Katalog: `uv run ntx train run --template locomotion-velocity --set spec.robot_id=strido`. Dort trainierte Policies verwenden das Observation-Format von NT-X; der Strido-ROS-2-`policy_node` führt Policies aus `strido_sim.rl.train` aus (Observation ohne Rückmeldung). Die Verbindung beider Laufzeitumgebungen ist noch offen. --- # Strido auf einen Blick {#strido-at-a-glance} > **Status:** Konstruktion in CAD und Simulation verifiziert; aus dieser Revision wurde noch kein Roboter gebaut (siehe [Verifikation](verification.md)). Strido ist ein 3D-gedruckter Vierbeiner mit 12 Freiheitsgraden in der Klasse des Mini Pupper 4: klein genug für einen Schreibtisch, vollständig genug, um echte ROS-2- und Lernsoftware zu entwickeln, die sich auf einen Unitree Go2 übertragen lässt. Er übernimmt die bewährten Beine und den Rahmen von [Yertle](https://github.com/Jerome-Graves/yertle) (MIT, Jerome Graves) und ergänzt Sensorkopf, Elektronik und Software-Stack eines modernen Forschungsroboters. ![Strido stehend](../../docs/images/hero_front.png) ## Technische Daten {#specifications} | Eigenschaft | Strido | |---|---| | Größe (stehend, inkl. LiDAR) | 430 × 188 × 264 mm | | Masse (CAD, inkl. Akku) | ≈ 3,0 kg | | Antrieb | 12 × SPT5435LV, 35 kg·cm bei 6 V; Knie über Kurbel und Viergelenk-Koppelgetriebe angetrieben | | Rechner | Raspberry Pi 5 (4 GB) + Bewegungscontroller Seeed XIAO ESP32-S3 (200 Hz) | | Sensoren | RPLIDAR C1 (freie 360°), Camera Module 3 Wide, IMU LSM6DSOX, Power-Monitor INA260 | | Gesicht | Waveshare 2" ST7789 LCD hinter der Frontschale | | Stromversorgung | 2S 5000 mAh LiPo; 2 × 6,0-V-UBEC für die Servos; 5 V/5,5 A Logik-Spannungsregler; 25-A-Haupt- + 7,5-A-Logiksicherung; XT60-Loop-Key | | Software | ROS 2 Jazzy (Docker, amd64/arm64), Gazebo Harmonic, MuJoCo 3, PPO, NT-X-Erweiterung | | Kosten | ab 979 € inkl. Versand nach Österreich (Plan A, niedrigste Gesamtsumme; siehe [Shop](shop.md) und [Einkaufsliste](bom/shopping_list.md)) | ## Im Vergleich {#how-it-compares} | | Strido | Mini Pupper 2 | Mini Pupper 4 (Vorserie) | Unitree Go2 | |---|---|---|---|---| | Freiheitsgrade Beine | 12 | 12 | 12 | 12 | | Größenklasse | 430 mm | 210 mm | ≈ 250 mm | 700 mm | | Bewegungscontroller | ESP32-S3 | ESP32-S3 | k. A. | proprietär | | LiDAR / Kamera / Gesicht | ja / ja / ja | optional / ja / ja | ja / ja / ja | ja / ja / nein | | ROS-2-Schnittstelle | Go2-Gelenknamen, `/cmd_vel`, `/scan` | MangDang-Stack | MangDang-Stack | Unitree SDK2 / ROS 2 | | Offenheit | vollständiges CAD, Druckdateien, Firmware, Simulationsmodelle | teilweise | nicht veröffentlicht | geschlossen | Es geht um Übertragbarkeit: Entwickeln Sie Navigation, Wahrnehmung und Lernen zu Hause mit denselben ROS-2-Topics und Gelenkkonventionen wie beim Go2, und übertragen Sie dann die Anwendungsschicht in der Arbeit auf den Go2. Low-Level-Gaits und gelernte Policies lassen sich nicht unverändert zwischen einem 3 kg schweren Hobby-Servo-Roboter und einem 15 kg schweren Go2 übertragen; siehe [Simulation](simulation.md). ## Was sich gegenüber Yertle geändert hat {#what-changed-compared-with-yertle} * **Sensorkopf:** Frontschale mit LCD-Fenster und Halterung; neigbare Kamerahalterung; LiDAR-Sockel, der die Scanebene über jede Beinpose hebt. * **Elektronik:** Pi 5 + XIAO ESP32-S3, PCA9685 mit Hardware-Abschaltung über Output-Enable, IMU, Power-Monitor; Servostrom über zwei UBECs und WAGO-Busse, nie über eine Logikplatine. * **Durch die Verifikation behobene Mechanik:** Die vorderen Servohalterungen erhalten die fehlende Vorbohrung für den Hüftdrehpunkt; Femur-Hörner und -Verbinder des rechten Beins an das gedruckte Lochbild angepasst; Vorbohrungen des LiDAR-Sockels vertieft, damit die Schrauben klemmen; Hüftgrenzen, die die Füße auseinanderhalten, wenn beide Beine nach innen schwingen. * **Software:** koppelgetriebegenaue Kniezuordnung, Watchdog, einrastender Not-Halt, Unterspannungsabschaltung, ROS-2-Schnittstelle im Go2-Stil, aus dem CAD erzeugte MuJoCo-/Gazebo-Modelle, PPO-Training, NT-X-Integration. Weiter mit [Erste Schritte](getting-started.md). --- # Druckpaket {#print-kit} Wählen Sie die Druckteile und Stückzahlen (oder komplette Roboter) und laden Sie ein druckfertiges Paket herunter: jede STL für den Druck ausgerichtet und mit ihrer Stückzahl benannt, das PrusaSlicer-Profil, mit dem jedes Teil verifiziert wurde, ein Teileblatt mit Filament, Zeit, Stützen und Brims sowie für komplette Roboter die fertigen Druckplatten mit 220 × 220 mm. Öffnen Sie ein beliebiges Teil, um zu sehen, was es tut und wo es hingehört. Das gesamte Paket ist auch im [Bausatz-ZIP](downloads.md) enthalten. --- # Shop {#shop} Alles für den Bau von Strido, bepreist bei echten Shops: Raspberry Pi 5 mit Kühler und microSD, XIAO ESP32-S3, PCA9685-Servotreiber, zwölf SPT5435LV-Servos mit Aluminium-Servohörnern, RPLIDAR C1, Camera Module 3 Wide, 2"-LCD, LSM6DSOX-IMU, INA260-Power-Monitor, 2S-LiPo mit Ladegerät, UBECs, Spannungsregler, Sicherungen, Steckverbinder und Draht, Lager, jede Schraube mit Reserve sowie das Filament. Legen Sie den kompletten Roboter (oder einzelne Teile) in den Warenkorb, wählen Sie einen der vier Einkaufspläne oder ändern Sie den Shop pro Teil, und öffnen Sie jedes Teil für seine Beschreibung, technischen Daten und seinen Einbauort im Roboter. Der Warenkorb addiert die Versandkosten jedes Shops; die Kasse teilt die Bestellung pro Shop auf und führt Sie hindurch: Eine Checkliste pro Shop öffnet nacheinander die Seite jedes Artikels mit der einzugebenden Menge und Bestellnummer, und eine kopierbare Bestellliste dient Shops mit Schnellbestellformular. Hier wird nichts bestellt, und die Preise sind die am 30. Oktober 2026 beobachteten Angebote: Prüfen Sie den Warenkorb jedes Shops vor dem Bezahlen. Die gedruckten Teile finden Sie auf der Seite [Druckpaket](print-kit.md). --- # Simulation und Lernen {#simulation-and-learning} Alle Modelle werden von `strido_cad.models` (`make models`) aus dem CAD erzeugt: | Datei | Verwendung | |---|---| | `ros2/strido_description/urdf/strido.urdf.xacro` (+ `strido.urdf`) | ROS 2 / Gazebo Harmonic: `sim:=true` fügt `gz_ros2_control`, IMU, GPU-LiDAR, Kamera und einen Ground-Truth-Odometrie-Publisher hinzu | | `ros2/strido_description/meshes/*.stl` | 13 Link-Meshes (dezimiert, je 25 k Flächen) | | `models/mujoco/strido.xml`, `scene.xml` | MuJoCo 3: Positionsservos (kp 25, kv 0,4, ±3,43 N·m = Blockiermoment des SPT5435LV), IMU und Fuß-Sites | Linkmassen und Trägheiten stammen aus dem CAD (`ros2/strido_description/config/mass_report.yaml`, gesamt 3,07 kg inkl. der verlegten Verkabelung). Das Knie ist als direktes Drehgelenk am Unterschenkel modelliert; das Koppelgetriebe wird in Software (Gait, Firmware) gelöst, und seine Grenzen werden angewendet, bevor Befehle das Gelenk erreichen. ## MuJoCo {#mujoco} ```bash make sim-walk # 10 s trot at 0.15 m/s -> build/sim/walk.mp4 uv run --locked python -m strido_sim.walk --seconds 6 --wz 0.6 # turn uv run --locked mjpython -m strido_sim.walk --viewer # interactive (macOS needs mjpython) ``` Die Lauf-Demo führt `packages/strido-core/src/strido/gait.py` aus, den Gait, den der Roboter über ROS 2 ausführt, plus eine Kurshaltung, die den Gierwinkel des Simulators nutzt (der Roboter hat keine solche Regelschleife). ## Gazebo Harmonic (ROS 2 Jazzy, Docker) {#gazebo-harmonic-ros-2-jazzy-docker} ```bash make sim-gazebo # build image, headless walk test with pass/fail docker compose -f docker/compose.yaml run --rm ros ros2 launch strido_bringup gazebo.launch.py # GUI needs X11/Wayland forwarding ``` `POLICY=/path/policy.npz` führt denselben Test mit `policy_node` aus (binden Sie die Datei in den Container ein, siehe `docker/ros2/sim_smoke.sh`). `walk_smoke` stellt den Roboter auf, befiehlt 8 s lang 0,15 m/s und prüft den Ground-Truth-Fortschritt (≥ 0,4 m), die aufrechte Haltung und dass `/joint_states`, `/imu/data`, `/scan`, `/camera/image_raw` und `/ground_truth/odom` publizieren. ## Reinforcement Learning (MuJoCo + PPO) {#reinforcement-learning-mujoco-ppo} `strido_sim.rl.env` (`packages/strido-sim`) ist eine Gymnasium-Aufgabe zur Geschwindigkeitsverfolgung, ausgelegt für die Übertragung auf Hobby-Servos: Die Policy beobachtet nur, was der Roboter messen kann (IMU-Gyro und Schwerkraft, Befehl, ihre vorherige Action, ein Gangtakt) — kein Gelenk-Feedback, denn der SPT5435LV hat keines. Actions sind Gelenkversätze um die Standpose, begrenzt durch dieselben Gelenk- und Kniekurbelgrenzen wie in der Firmware. Die Gelenk-Anstiegsbegrenzung der Firmware von 6 rad/s wird in der Umgebung angewendet (pro 20-ms-Policy-Schritt; die Firmware rampt in 5-ms-Schritten mit derselben Geschwindigkeit), gefolgt von der Gelenk- und Kniekurbelbegrenzung. Domain Randomization: Kontaktreibung (Boden und Füße gemeinsam, da MuJoCo den größeren der beiden Werte verwendet), Servosteifigkeit, Basismasse, IMU-Rauschen. `policy_node` begrenzt `/cmd_vel` auf die trainierten Befehlsbereiche und publiziert kein `/odom` (verwenden Sie LiDAR-Odometrie/SLAM). ```bash make rl-smoke # 20 k steps + evaluation (pipeline check) make rl-train # 20 M steps, 8 envs (CPU, ≈ 30 min) uv run --locked python -m strido_sim.rl.evaluate build/rl//policy.npz --vx 0.2 --video build/rl/eval.mp4 ``` Das Training schreibt `policy.npz` (einfache Arrays). `strido.policy.MlpPolicy` führt sie mit numpy aus, sowohl in `evaluate.py` als auch im ROS-2-`policy_node`, daher ist auf dem Pi kein PyTorch nötig: ```bash ros2 launch strido_bringup gazebo.launch.py use_policy:=true policy:=/path/policy.npz ros2 launch strido_bringup robot.launch.py use_policy:=true policy:=/path/policy.npz ``` Bevor Sie eine gelernte Policy auf der Hardware ausführen: Evaluieren Sie sie in MuJoCo und Gazebo, beginnen Sie mit dem Roboter auf einem Ständer, halten Sie `/strido/estop` bereit und rechnen Sie damit, mit gemessenem Servoverhalten (kp/kv, Latenz) neu zu trainieren, sobald der Roboter existiert. Die Upstream-Pipelines für PyBullet (`upstream/yertle/learning/`) und Isaac Lab (`upstream/yertle/isaac_lab/`) zielen auf die ursprüngliche Yertle-URDF und werden als Referenz beibehalten. --- # Software {#software} ```mermaid flowchart TD subgraph PI["Raspberry Pi 5 – ROS 2 Jazzy (Docker oder nativ)"] TELEOP["teleop / Nav2 / Ihr Node"] -->|"/cmd_vel"| GAIT["gait_node
(oder policy_node)"] GAIT -->|"/leg_controller/commands
12 × rad, Go2-Reihenfolge"| BRIDGE["mcu_bridge"] GAIT -->|"/odom + TF"| TF["robot_state_publisher"] BRIDGE -->|"/joint_states /imu/data
/battery_state /diagnostics"| TF LIDAR["sllidar_ros2"] -->|"/scan"| TELEOP CAM["camera_ros"] -->|"/camera/image_raw"| TELEOP end BRIDGE <-->|"USB CDC, COBS + CRC16"| MCU["XIAO ESP32-S3 firmware
200-Hz-Regelung, Watchdog, Not-Halt"] MCU -->|"I²C"| PCA["PCA9685 → 12 Servos"] MCU -->|"I²C"| IMU["LSM6DSOX, INA260"] MCU -->|"SPI"| LCD["LCD-Gesicht"] ``` Dasselbe Topic `/leg_controller/commands` wird in Gazebo von `ros2_control` und am Roboter von `mcu_bridge` verarbeitet, sodass jeder Node oberhalb der Bridge unverändert in der Simulation und auf der Hardware läuft. ## ROS-2-Schnittstelle (Go2-Stil) {#ros-2-interface-go2-style} | Topic | Typ | Richtung | Hinweise | |---|---|---|---| | `/cmd_vel` | geometry_msgs/Twist | ein | vx, vy [m/s], wz [rad/s]; Grenzen 0,30 / 0,15 / 1,0; 0,5 s Timeout → Stehen | | `/leg_controller/commands` | std_msgs/Float64MultiArray | intern | 12 Gelenkwinkel [rad] in Go2-Reihenfolge FL, FR, RL, RR × Hüfte, Oberschenkel, Unterschenkel | | `/joint_states` | sensor_msgs/JointState | aus | Go2-Gelenknamen (`FL_hip_joint` …). Roboter: Winkel, die die MCU nach dem Begrenzen anwendet (Hobby-Servos haben keine Rückmeldung) | | `/imu/data` | sensor_msgs/Imu | aus | Orientierung (Mahony auf der MCU), Winkelgeschwindigkeit, Beschleunigung; Frame `imu_link`; wird nicht veröffentlicht, solange die IMU einen Fehler meldet | | `/scan` | sensor_msgs/LaserScan | aus | RPLIDAR C1, Frame `lidar_link`, 10 Hz | | `/camera/image_raw` | sensor_msgs/Image | aus | Camera Module 3 Wide, Frame `camera_optical_frame` | | `/battery_state` | sensor_msgs/BatteryState | aus | Akkupackspannung + Strom des Logikzweigs (INA260), negativ = Entladen | | `/odom` + TF `odom→base_link` | nav_msgs/Odometry | aus | Koppelnavigation aus der *kommandierten* Geschwindigkeit (nur gait_node) | | `/strido/estop` | std_msgs/Bool | ein | true = verriegelter Halt (Servoausgänge aus), false = Freigabe | | `/strido/relax` | std_msgs/Bool | ein | true = Servos kraftlos | | `/strido/face` | std_msgs/UInt8 | ein | LCD-Gesichtsausdruck | | `/diagnostics` | diagnostic_msgs/DiagnosticArray | aus | MCU-Flags: estop, relaxed, watchdog, imu_ok, power_ok, pwm_ok, clamped | Frames folgen REP-103 (`base_link`: x nach vorne, y nach links, z nach oben); Gelenk-Nullstellung = Bein gerade nach unten, Oberschenkel positiv = Fuß nach hinten, Unterschenkel negativ = Knie gebeugt (Go2-Konvention). ### Code von einem Unitree Go2 portieren {#porting-code-from-a-unitree-go2} Gelenknamen, Vorzeichen, Frames und `/cmd_vel` folgen der Go2-ROS-2-Beschreibung, daher laufen Stacks auf Geschwindigkeitsebene (Teleop, Nav2, SLAM mit `/scan`) unverändert. Unterschiede: Die Reihenfolge des Befehlsarrays ist FL, FR, RL, RR (die Motorindex-Reihenfolge des Unitree SDK ist FR, FL, RR, RL: Zuordnung über den Gelenknamen, nicht über den Index), es gibt keine Topics für Fußkontakt oder Motordrehmoment, `/joint_states` sind kommandierte Werte, der Geschwindigkeitsbereich liegt bei ≈ 0,3 m/s, und die Low-Level-Messages `unitree_go` werden nicht bereitgestellt. ## Pakete {#packages} | Pfad | Inhalt | |---|---| | `ros2/strido_description` | URDF/xacro und Meshes **aus CAD generiert** (`strido_cad.models`), ros2_control-Controllerkonfiguration, `display.launch.py` | | `ros2/strido_bringup` | `gazebo.launch.py`, `robot.launch.py`, Welt, udev-Regeln | | `ros2/strido_control` | `gait_node`, `policy_node`, `mcu_bridge`, `walk_smoke` | | `packages/strido-core` | reiner Python-Kern, gemeinsam genutzt von ROS, MuJoCo und Tests: generierte Geometrie, Bein-/Koppelgetriebe-Kinematik, Trot-Gait, MCU-Protokoll, numpy-Policy-Laufzeit, `strido-cli` | | `firmware/strido_esp32s3` | PlatformIO-Firmware; `lib/strido_core` enthält den portablen Kinematik-/Protokoll-/Sicherheitscode mit nativen Unit-Tests | Starten: ```bash ros2 launch strido_bringup gazebo.launch.py headless:=false # simulation with GUI ros2 launch strido_bringup robot.launch.py # on the robot (add camera:=true once camera_ros is installed) ros2 launch strido_bringup robot.launch.py use_policy:=true policy:=/path/policy.npz # learned controller ros2 launch strido_description display.launch.py # model + joint sliders in RViz ``` ## Firmware {#firmware} PlatformIO, Arduino-ESP32 3.x auf dem Seeed XIAO ESP32-S3: ```bash cd firmware/strido_esp32s3 pio test -e native # kinematics, protocol, safety unit tests on the host pio run -e xiao_esp32s3 -t upload ``` * 200-Hz-Schleife: Befehl → koppelgetriebegenaue Gelenk→Servo-Abbildung (`servo_map`, generierte Geometrie) → Änderungsratenbegrenzung 6 rad/s → PCA9685-Pulse (200 Hz PWM). * Sicherheit: Nur Gelenkbefehle speisen den Watchdog (keine Keep-alive-Message): 200 ms kein Befehl → Halten, weitere 2 s → kraftlos schalten; verriegelter Not-Halt; PCA9685-OE-Pin wird beim Kraftlosschalten/Not-Halt auf High gezogen (plus ein Hardware-Pull-up für Resets); Akkuwarnung bei 6,8 V, Abschaltung nach 5 aufeinanderfolgenden Messwerten unter 6,4 V; kein Fahren ohne den INA260; nicht-endliche Befehle werden verworfen; Gelenk- und Kniekurbelgrenzen aus dem CAD-Bewegungsbereich-Sweep. * Die Kalibrierung (Neutralpuls, Richtung, Grenzen pro Gelenk) wird im Flash gespeichert (`Preferences`). ### Protokoll (USB CDC) {#protocol-usb-cdc} Frames: `COBS(type | payload | CRC16-CCITT-FALSE little endian) 0x00`. Payloads sind gepackte Little-Endian-Structs, gespiegelt in `packages/strido-core/src/strido/protocol.py` und `firmware/.../protocol.h`. | Typ | Name | Payload | |---|---|---| | 0x01 | JOINT_COMMAND | seq u16, mode u8 (0 kraftlos, 1 Position), q[12] f32 | | 0x02 | SERVO_PULSE_COMMAND | seq u16, pulse_us[12] u16 (0 = aus) – nur Kalibrierung | | 0x03 | SET_CALIBRATION | joint u8, direction i8, neutral_us u16, zero_rad f32, min_us u16, max_us u16 | | 0x04 | SAVE_CALIBRATION | – | | 0x05 | REQUEST_CALIBRATION | – → 12 × CALIBRATION | | 0x06 | ESTOP | engaged u8 | | 0x07 | DISPLAY | expression u8, length u8, text | | 0x81 | STATE (100 Hz) | last seq u16, time_ms u32, flags u8, q[12], quat wxyz[4], gyro[3], accel[3], Bus-V, Strom A (f32) | | 0x82 | CALIBRATION | wie SET_CALIBRATION | | 0x83 | LOG | ASCII | ## Prüfstand-Werkzeug {#bench-tool} `strido-cli` (installiert mit `packages/strido-core`) kommuniziert ohne ROS mit dem Controller: ```bash strido-cli center # 1500 µs on every channel: the assembly reference (fit horns now; raw pulses bypass joint limits) strido-cli pulse FL_thigh 1600 # one joint strido-cli calibrate # trim each joint's neutral (±5/±25 µs), saved to flash strido-cli monitor # battery, flags, roll/pitch ``` ## Raspberry-Pi-Einrichtung {#raspberry-pi-setup} 1. Ubuntu Server 24.04 (arm64) oder Raspberry Pi OS Bookworm 64-bit; Docker Engine. 2. `docker compose -f docker/compose.yaml build ros` (ROS 2 Jazzy, Gazebo-Bibliotheken, sllidar_ros2 fixiert, die Pakete dieses Repos). 3. Stromversorgungs- und udev-Konfiguration: siehe [electronics.md](electronics.md#raspberry-pi-configuration). 4. Kamera: Der Kamera-Stack des Pi 5 benötigt den libcamera-Fork von Raspberry Pi; bauen Sie `camera_ros` auf dem Host dagegen (Raspberry Pi OS liefert ihn mit) oder verwenden Sie `rpicam-vid` + eine GStreamer-Bridge, und starten Sie dann mit `camera:=true` (Standard false; das Docker-Image enthält keinen Kamera-Node). --- # Freigang beweglicher Teile {#moving-part-clearance} Generiert von `strido_verify.clearance` (exakter Mindestabstand zwischen geschlossenen Netzen, manifold3d). Posen: stand_170mm, crouch_120mm, tall_210mm, trot_0of8, trot_1of8, trot_2of8, trot_3of8, trot_4of8, trot_5of8, trot_6of8, trot_7of8, hips_out, hips_in. Paare auf verschiedenen Starrkörpern, die sich in irgendeiner Pose näher als 1,5 mm kommen: 92 — **fail (< 0,3 mm) 0**, knapp (< 1,0 mm) 4, ok 8, Drehschnittstellen (konstanter Spalt) 80. Gelenkschnittstellen (in der CAD-Pose in Kontakt, nicht geprüft): 72. | Teile | Körper | Minimaler Spalt (mm) | Maximaler Spalt (mm) | Ungünstigste Pose | Ergebnis | |---|---|---|---|---|---| | bearing_625zz / iso7089_m3 | RR.hip / base | 0,11 | 0,11 | stand_170mm | Drehschnittstelle | | bearing_625zz / iso7089_m3 | RL.hip / base | 0,11 | 0,11 | stand_170mm | Drehschnittstelle | | bearing_633zz / femur | FL.calf / FL.thigh | 0,12 | 0,12 | tall_210mm | Drehschnittstelle | | bearing_633zz / femur | RR.calf / RR.thigh | 0,12 | 0,12 | tall_210mm | Drehschnittstelle | | bearing_633zz / femur | FR.calf / FR.thigh | 0,12 | 0,12 | tall_210mm | Drehschnittstelle | | bearing_633zz / femur | RL.calf / RL.thigh | 0,14 | 0,14 | trot_2of8 | Drehschnittstelle | | iso4762_m3x8 / servo_spt5435lv | FL.hip / base | 0,25 | 0,25 | stand_170mm | Drehschnittstelle | | iso4762_m3x8 / servo_spt5435lv | FR.hip / base | 0,25 | 0,25 | stand_170mm | Drehschnittstelle | | bearing_625zz / left_servo_mount_fl | FL.hip / base | 0,32 | 0,32 | hips_in | Drehschnittstelle | | bearing_625zz / right_servo_mount_fr | FR.hip / base | 0,34 | 0,34 | hips_in | Drehschnittstelle | | left_shoulder / stiff_long_link | FL.crank / FL.long_link | 0,49 | 0,49 | tall_210mm | Drehschnittstelle | | left_shoulder / stiff_long_link | RL.crank / RL.long_link | 0,50 | 0,50 | tall_210mm | Drehschnittstelle | | right_shoulder / short_link | RR.crank / RR.short_link | 0,50 | 0,50 | trot_7of8 | Drehschnittstelle | | right_shoulder / short_link | FR.crank / FR.short_link | 0,50 | 0,50 | tall_210mm | Drehschnittstelle | | right_shoulder / sleeve_bearing_3x5x5_pair | RR.crank / RR.short_link | 0,50 | 0,50 | trot_1of8 | Drehschnittstelle | | right_shoulder / sleeve_bearing_3x5x5_pair | FR.crank / FR.short_link | 0,50 | 0,50 | trot_4of8 | Drehschnittstelle | | right_shoulder / stiff_long_link | FR.crank / FR.long_link | 0,51 | 0,51 | crouch_120mm | Drehschnittstelle | | left_shoulder / sleeve_bearing_3x5x5_pair | FL.crank / FL.long_link | 0,51 | 0,51 | hips_out | Drehschnittstelle | | right_shoulder / stiff_long_link | RR.crank / RR.long_link | 0,51 | 0,51 | tall_210mm | Drehschnittstelle | | left_shoulder / sleeve_bearing_3x5x5_pair | RL.crank / RL.long_link | 0,52 | 0,52 | crouch_120mm | Drehschnittstelle | | right_shoulder / sleeve_bearing_3x5x5_pair | RR.crank / RR.long_link | 0,52 | 0,52 | tall_210mm | Drehschnittstelle | | right_shoulder / sleeve_bearing_3x5x5_pair | FR.crank / FR.long_link | 0,52 | 0,52 | crouch_120mm | Drehschnittstelle | | left_shoulder / short_link | RL.crank / RL.short_link | 0,53 | 0,53 | tall_210mm | Drehschnittstelle | | left_shoulder / sleeve_bearing_3x5x5_pair | RL.crank / RL.short_link | 0,53 | 0,53 | trot_4of8 | Drehschnittstelle | | left_shoulder / sleeve_bearing_3x5x5_pair | FL.crank / FL.short_link | 0,53 | 0,53 | trot_6of8 | Drehschnittstelle | | left_shoulder / short_link | FL.crank / FL.short_link | 0,53 | 0,54 | trot_7of8 | Drehschnittstelle | | right_shoulder / servo_spt5435lv | FR.crank / FR.hip | 0,59 | 0,59 | trot_3of8 | Drehschnittstelle | | left_shoulder / servo_spt5435lv | FL.crank / FL.hip | 0,59 | 0,59 | tall_210mm | Drehschnittstelle | | left_shoulder / servo_spt5435lv | RL.crank / RL.hip | 0,59 | 0,60 | tall_210mm | Drehschnittstelle | | femur / right_shoulder | RR.crank / RR.thigh | 0,60 | 0,61 | tall_210mm | Drehschnittstelle | | left_shoulder / servo_spt5435lv | FL.crank / FL.hip | 0,60 | 0,61 | tall_210mm | Drehschnittstelle | | left_shoulder / servo_spt5435lv | RL.crank / RL.hip | 0,60 | 0,60 | tall_210mm | Drehschnittstelle | | right_shoulder / servo_spt5435lv | FR.crank / FR.hip | 0,60 | 0,61 | trot_3of8 | Drehschnittstelle | | bearing_625zz / iso4762_m3x10 | RR.hip / base | 0,61 | 0,61 | stand_170mm | Drehschnittstelle | | bearing_625zz / iso4762_m3x10 | RL.hip / base | 0,61 | 0,61 | stand_170mm | Drehschnittstelle | | femur / left_shoulder | FL.crank / FL.thigh | 0,62 | 0,62 | crouch_120mm | Drehschnittstelle | | right_shoulder / servo_spt5435lv | RR.crank / RR.hip | 0,62 | 0,62 | tall_210mm | Drehschnittstelle | | right_shoulder / servo_spt5435lv | RR.crank / RR.hip | 0,62 | 0,62 | trot_7of8 | Drehschnittstelle | | femur / right_shoulder | FR.crank / FR.thigh | 0,63 | 0,64 | tall_210mm | Drehschnittstelle | | femur / left_shoulder | RL.crank / RL.thigh | 0,64 | 0,64 | tall_210mm | Drehschnittstelle | | back_shell_button / right_shoulder | RR.crank / base | 0,73 | 0,73 | hips_out | knapp | | front_shell_display / servo_arm_horn_25t | FR.arm / base | 0,77 | 0,77 | hips_out | knapp | | back_shell_button / left_shoulder | RL.crank / base | 0,78 | 0,78 | hips_out | knapp | | front_shell_display / servo_arm_horn_25t | FL.arm / base | 0,79 | 0,79 | hips_out | knapp | | femur_servo_connector / servo_spt5435lv | FL.hip / FL.thigh | 0,91 | 0,91 | trot_6of8 | Drehschnittstelle | | femur_servo_connector / servo_spt5435lv | RR.hip / RR.thigh | 0,91 | 0,91 | crouch_120mm | Drehschnittstelle | | femur_servo_connector / servo_spt5435lv | FR.hip / FR.thigh | 0,91 | 0,91 | crouch_120mm | Drehschnittstelle | | femur_servo_connector / servo_spt5435lv | RL.hip / RL.thigh | 0,91 | 0,91 | trot_4of8 | Drehschnittstelle | | iso4762_m3x25 / stiff_long_link | RR.calf / RR.long_link | 0,97 | 0,97 | trot_6of8 | Drehschnittstelle | | iso4762_m3x25 / stiff_long_link | FR.calf / FR.long_link | 0,97 | 0,97 | tall_210mm | Drehschnittstelle | | outer_tibia / stiff_long_link | RR.calf / RR.long_link | 0,98 | 0,99 | crouch_120mm | Drehschnittstelle | | outer_tibia / stiff_long_link | FR.calf / FR.long_link | 0,99 | 0,99 | crouch_120mm | Drehschnittstelle | | iso4762_m3x25 / stiff_long_link | RR.crank / RR.long_link | 1,00 | 1,01 | trot_5of8 | Drehschnittstelle | | outer_tibia / sleeve_bearing_3x5x5_pair | RR.calf / RR.long_link | 1,00 | 1,00 | trot_0of8 | Drehschnittstelle | | outer_tibia / sleeve_bearing_3x5x5_pair | FR.calf / FR.long_link | 1,00 | 1,00 | trot_0of8 | Drehschnittstelle | | iso4762_m3x25 / stiff_long_link | FR.crank / FR.long_link | 1,01 | 1,01 | trot_3of8 | Drehschnittstelle | | iso7089_m3 / outer_shoulder_frame | FL.hip / base | 1,01 | 1,17 | hips_in | ok | | inner_tibia / stiff_long_link | FL.calf / FL.long_link | 1,02 | 1,02 | tall_210mm | Drehschnittstelle | | iso4762_m3x25 / stiff_long_link | FL.crank / FL.long_link | 1,02 | 1,02 | trot_6of8 | Drehschnittstelle | | inner_tibia / stiff_long_link | RL.calf / RL.long_link | 1,02 | 1,02 | tall_210mm | Drehschnittstelle | | iso4762_m3x25 / stiff_long_link | RL.crank / RL.long_link | 1,02 | 1,02 | trot_0of8 | Drehschnittstelle | | inner_tibia / sleeve_bearing_3x5x5_pair | RL.calf / RL.long_link | 1,02 | 1,02 | crouch_120mm | Drehschnittstelle | | inner_tibia / sleeve_bearing_3x5x5_pair | FL.calf / FL.long_link | 1,02 | 1,02 | trot_1of8 | Drehschnittstelle | | iso4762_m3x25 / short_link | RR.crank / RR.short_link | 1,03 | 1,03 | trot_0of8 | Drehschnittstelle | | iso4762_m3x25 / short_link | FR.crank / FR.short_link | 1,03 | 1,03 | trot_4of8 | Drehschnittstelle | | iso4762_m3x25 / short_link | RL.crank / RL.short_link | 1,03 | 1,03 | trot_4of8 | Drehschnittstelle | | iso4762_m3x25 / short_link | FL.crank / FL.short_link | 1,03 | 1,03 | trot_0of8 | Drehschnittstelle | | iso7089_m3 / outer_shoulder_frame | FR.hip / base | 1,04 | 1,20 | hips_in | ok | | femur_servo_connector / servo_spt5435lv | RR.hip / RR.thigh | 1,08 | 1,08 | trot_3of8 | Drehschnittstelle | | femur_servo_connector / servo_spt5435lv | FR.hip / FR.thigh | 1,08 | 1,08 | trot_0of8 | Drehschnittstelle | | left_shoulder / servo_arm_horn_25t | FL.arm / FL.crank | 1,09 | 1,10 | trot_3of8 | Drehschnittstelle | | femur / outer_tibia | RR.calf / RR.thigh | 1,09 | 1,09 | tall_210mm | Drehschnittstelle | | femur / outer_tibia | FR.calf / FR.thigh | 1,09 | 1,09 | tall_210mm | Drehschnittstelle | | left_shoulder / servo_arm_horn_25t | RL.arm / RL.crank | 1,09 | 1,11 | trot_7of8 | Drehschnittstelle | | femur_servo_connector / servo_spt5435lv | RL.hip / RL.thigh | 1,10 | 1,10 | stand_170mm | Drehschnittstelle | | femur_servo_connector / servo_spt5435lv | FL.hip / FL.thigh | 1,10 | 1,10 | tall_210mm | Drehschnittstelle | | right_shoulder / servo_arm_horn_25t | FR.arm / FR.crank | 1,11 | 1,13 | crouch_120mm | Drehschnittstelle | | right_shoulder / servo_arm_horn_25t | RR.arm / RR.crank | 1,11 | 1,13 | crouch_120mm | Drehschnittstelle | | femur / inner_tibia | RR.calf / RR.thigh | 1,12 | 1,12 | tall_210mm | Drehschnittstelle | | femur / outer_tibia | FL.calf / FL.thigh | 1,12 | 1,12 | tall_210mm | Drehschnittstelle | | femur / inner_tibia | FR.calf / FR.thigh | 1,12 | 1,13 | tall_210mm | Drehschnittstelle | | femur / inner_tibia | RL.calf / RL.thigh | 1,13 | 1,13 | crouch_120mm | Drehschnittstelle | | femur / inner_tibia | FL.calf / FL.thigh | 1,13 | 1,14 | crouch_120mm | Drehschnittstelle | | femur / outer_tibia | RL.calf / RL.thigh | 1,14 | 1,14 | crouch_120mm | Drehschnittstelle | | iso4762_m3x25 / servo_spt5435lv | RL.crank / RL.hip | 1,22 | 1,46 | tall_210mm | ok | | iso4762_m3x25 / servo_spt5435lv | FL.crank / FL.hip | 1,22 | 1,46 | tall_210mm | ok | | iso4762_m3x25 / servo_spt5435lv | RR.crank / RR.hip | 1,22 | 1,46 | tall_210mm | ok | | iso4762_m3x25 / servo_spt5435lv | FR.crank / FR.hip | 1,22 | 1,46 | tall_210mm | ok | | iso4762_m3x10 / outer_shoulder_frame | FL.hip / base | 1,30 | 1,37 | hips_in | ok | | iso4762_m3x10 / outer_shoulder_frame | FR.hip / base | 1,33 | 1,40 | hips_in | ok | | iso4762_m3x8 / servo_spt5435lv | RL.hip / base | 1,39 | 1,43 | hips_out | Drehschnittstelle | | iso4762_m3x8 / servo_spt5435lv | RR.hip / base | 1,39 | 1,43 | hips_out | Drehschnittstelle | --- # Elektronikprüfung {#electronics-check} Generiert von `strido_verify.electronics` aus `hardware/electronics.yaml` und dem Firmware-Pin-Header `firmware/strido_esp32s3/src/board_config.h`. Nicht von Hand bearbeiten. ## XIAO-ESP32-S3-Pins {#xiao-esp32-s3-pins} | Pad | GPIO | Funktion | Verbunden mit | Firmware-Konstante | Hinweis | |---|---|---|---|---|---| | D0 | 1 | lcd_cs | LCD CS | `kLcdCs` | | | D1 | 2 | lcd_rst | LCD RST | `kLcdRst` | | | D2 | 3 | lcd_backlight | LCD BL | `kLcdBacklight` | Strapping-Pin: erst nach dem Booten angesteuert | | D3 | 4 | servo_oe_n | PCA9685 OE | `kServoOutputEnableN` | Low-aktiv; 2,2-kΩ-Pull-up auf VCC hält die Ausgänge im Reset aus | | D4 | 5 | i2c_sda | I²C SDA | `kSda` | | | D5 | 6 | i2c_scl | I²C SCL | `kScl` | | | D8 | 7 | lcd_sck | LCD CLK | `kLcdSck` | | | D9 | 8 | lcd_dc | LCD DC | `kLcdDc` | | | D10 | 9 | lcd_mosi | LCD DIN | `kLcdMosi` | | ## I²C-Bus {#i2c-bus} 400 kHz. | Adresse | Baustein | Hinweis | |---|---|---| | 0x40 | PCA9685 Servotreiber | 0x70 = All-Call | | 0x6A | LSM6DSOX IMU | | | 0x41 | INA260 Power-Monitor | A0-Jumper überbrücken (Standard 0x40 kollidiert mit dem PCA9685) | ## PCA9685-Servokanäle {#pca9685-servo-channels} | Bein | Hüfte | Oberschenkel | Unterschenkel (Kniekurbel) | |---|---|---|---| | FL | 15 | 11 | 7 | | FR | 14 | 10 | 6 | | RL | 13 | 9 | 5 | | RR | 12 | 8 | 4 | ## Ströme im ungünstigsten Fall {#worst-case-currents} | Zweig | Strom (A) | |---|---| | ubec_front | 10,00 | | ubec_rear | 10,00 | | servo_branch | 20,83 | | logic_branch | 2,74 | | logic_5v | 3,16 | | logic_5v_per_pin | 3,16 | | pack | 23,58 | ## Prüfungen: 81 bestanden (3 ohne Reserve), 0 fehlgeschlagen {#checks-81-passed-3-without-margin-0-failed} | Prüfung | Ergebnis | Detail | |---|---|---| | Firmware-Pin | pass | kLcdCs = 1 (YAML D0 = GPIO 1) | | Firmware-Pin | pass | kLcdRst = 2 (YAML D1 = GPIO 2) | | Firmware-Pin | pass | kLcdBacklight = 3 (YAML D2 = GPIO 3) | | Firmware-Pin | pass | kServoOutputEnableN = 4 (YAML D3 = GPIO 4) | | Firmware-Pin | pass | kSda = 5 (YAML D4 = GPIO 5) | | Firmware-Pin | pass | kScl = 6 (YAML D5 = GPIO 6) | | Firmware-Pin | pass | kLcdSck = 7 (YAML D8 = GPIO 7) | | Firmware-Pin | pass | kLcdDc = 8 (YAML D9 = GPIO 8) | | Firmware-Pin | pass | kLcdMosi = 9 (YAML D10 = GPIO 9) | | I²C-Frequenz | pass | kI2cHz = 400000 (YAML 400000) | | Firmware-I²C-Adresse | pass | kPcaAddress = 64 (YAML 0x40) | | Firmware-I²C-Adresse | pass | kImuAddress = 106 (YAML 0x6A) | | Firmware-I²C-Adresse | pass | kPowerMonitorAddress = 65 (YAML 0x41) | | I²C-Adresse eindeutig | pass | 0x40 PCA9685 Servotreiber, 0x41 INA260 Power-Monitor, 0x6A LSM6DSOX IMU, 0x70 PCA9685 Servotreiber | | Servokanäle eindeutig | pass | [15, 11, 7, 14, 10, 6, 13, 9, 5, 12, 8, 4] | | Servokanäle im Bereich | pass | 0..15 | | Firmware-Servokanäle | pass | kServoChannel = [15, 11, 7, 14, 10, 6, 13, 9, 5, 12, 8, 4] | | Servo-PWM-Frequenz | pass | kServoFrequencyHz = 200 Hz, Servo max. 330 Hz | | Onboard-LED | pass | kStatusLed = 21 (YAML GPIO 21) | | Header-Konstanten beschrieben | pass | 19 Konstanten | | ubec_front Last | pass | 6 Servos im Trot ≈ 4,2 A ≤ 10 A Dauerlast | | ubec_front Blockierwarnung | pass | 6 blockierte Servos 21 A > 15 A Spitze: niemals alle Gelenke in die harten Anschläge fahren | | ubec_rear Last | pass | 6 Servos im Trot ≈ 4,2 A ≤ 10 A Dauerlast | | ubec_rear Blockierwarnung | pass | 6 blockierte Servos 21 A > 15 A Spitze: niemals alle Gelenke in die harten Anschläge fahren | | 5-V-Spannungsregler Last | pass | 3,16 A Spitze ≤ 5,5 A | | Leistungsschalter Last | pass | 2,74 A ≤ 6,0 A | | INA260-Bereich | pass | 2,74 A, 8,4 V | | Hauptsicherung ≥ Last | pass | Servo + Logik 23,6 A ≤ 25,0 A | | Logiksicherung ≥ Last | pass | 2,74 A ≤ 7,5 A | | Leitung W01 Last | pass | 14 AWG: 23,6 A ≤ 32 A | | Leitung W02 Last | pass | 14 AWG: 23,6 A ≤ 32 A | | Leitung W02 Sicherung | pass | Hauptsicherung 25,0 A ≤ 14 AWG 32 A | | Leitung W02/arming Last | pass | 14 AWG: 23,6 A ≤ 32 A | | Leitung W02/arming Sicherung | pass | Hauptsicherung 25,0 A ≤ 14 AWG 32 A | | Leitung W02/logic Last | pass | 14 AWG: 23,6 A ≤ 32 A | | Leitung W02/logic Sicherung | pass | Hauptsicherung 25,0 A ≤ 14 AWG 32 A | | Leitung W03 Last | pass | 14 AWG: 20,8 A ≤ 32 A | | Leitung W03 Sicherung | pass | Hauptsicherung 25,0 A ≤ 14 AWG 32 A | | Leitung W03/front Last | pass | 14 AWG: 20,8 A ≤ 32 A | | Leitung W03/front Sicherung | pass | Hauptsicherung 25,0 A ≤ 14 AWG 32 A | | Leitung W03/rear Last | pass | 14 AWG: 20,8 A ≤ 32 A | | Leitung W03/rear Sicherung | pass | Hauptsicherung 25,0 A ≤ 14 AWG 32 A | | Leitung W04 Last | pass | 14 AWG: 23,6 A ≤ 32 A | | Leitung W04 Sicherung | pass | Hauptsicherung 25,0 A ≤ 14 AWG 32 A | | Leitung W04/front Last | pass | 14 AWG: 23,6 A ≤ 32 A | | Leitung W04/front Sicherung | pass | Hauptsicherung 25,0 A ≤ 14 AWG 32 A | | Leitung W04/rear Last | pass | 14 AWG: 23,6 A ≤ 32 A | | Leitung W04/rear Sicherung | pass | Hauptsicherung 25,0 A ≤ 14 AWG 32 A | | Leitung W04/logic Last | pass | 18 AWG: 2,7 A ≤ 16 A | | Leitung W04/logic Sicherung | pass | Logiksicherung 7,5 A ≤ 18 AWG 16 A | | Leitung W05 Last | pass | 18 AWG: 10,0 A ≤ 16 A | | Leitung W06 Last | pass | 18 AWG: 10,0 A ≤ 16 A | | Leitung W07/vplus Last | pass | 18 AWG: 10,0 A ≤ 16 A | | Leitung W07/gnd Last | pass | 18 AWG: 10,0 A ≤ 16 A | | Leitung W08/vplus Last | pass | 18 AWG: 10,0 A ≤ 16 A | | Leitung W08/gnd Last | pass | 18 AWG: 10,0 A ≤ 16 A | | Leitung W09 Last | pass | 18 AWG: 2,7 A ≤ 16 A | | Leitung W09 Sicherung | pass | Logiksicherung 7,5 A ≤ 18 AWG 16 A | | Leitung W10 Last | pass | 18 AWG: 2,7 A ≤ 16 A | | Leitung W10 Sicherung | pass | Logiksicherung 7,5 A ≤ 18 AWG 16 A | | Leitung W11 Last | pass | 18 AWG: 2,7 A ≤ 16 A | | Leitung W11 Sicherung | pass | Logiksicherung 7,5 A ≤ 18 AWG 16 A | | Leitung W24 Last | pass | 18 AWG: 2,7 A ≤ 16 A | | Leitung W24 Sicherung | pass | Logiksicherung 7,5 A ≤ 18 AWG 16 A | | Leitung W12 Last | pass | 22 AWG: 1,6 A ≤ 7 A | | Versorgung: Hobbywing UBEC-10A Eingang | pass | 6,0-8,4 V (nominal 7,4) innerhalb 6,0-25,2 V (2-6S LiPo bei 3,0-4,2 V pro Zelle (Hobbywing UBEC-10A V2-Car Handbuch: Eingang 2-6S)) | | Versorgung: Pololu 2813 Leistungsschalter | pass | 6,0-8,4 V (nominal 7,4) innerhalb 4,5-40,0 V (Pololu Produktseite) | | Versorgung: INA260 Bus-Eingang (VIN+/-) | pass | 6,0-8,4 V (nominal 7,4) innerhalb 0,0-36,0 V (TI INA260 Datenblatt) | | Versorgung: Pololu D36V50F5 Eingang | pass | 6,0-8,4 V (nominal 7,4) innerhalb 5,5-50,0 V (Pololu Produktseite) | | Versorgung: SPT5435LV Servo-V+ | pass | 5,4-6,0 V (nominal 6,0) innerhalb 4,8-6,0 V (SPT Spezifikationsseite (Spannungsbereich 4,8/6,0 V)) | | Versorgung: Raspberry Pi 5 (GPIO 5 V) | pass | 4,8-5,2 V (nominal 5,0) innerhalb 4,75-5,25 V ([ESTIMATE] 5 V +/- 5 %; Unterspannungsmeldung unter 4,63 V) | | Versorgung: XIAO ESP32-S3 (USB vom Pi) | pass | 4,8-5,2 V (nominal 5,0) innerhalb 4,75-5,25 V (USB-2.0-VBUS-Bereich) | | Versorgung: RPLIDAR C1 (USB vom Pi) | pass | 4,8-5,2 V (nominal 5,0) innerhalb 4,75-5,25 V (USB-2.0-VBUS-Bereich [ESTIMATE: C1-Datenblatt nennt 5 V]) | | Versorgung: PCA9685 VCC | pass | 3,2-3,4 V (nominal 3,3) innerhalb 2,3-5,5 V (NXP PCA9685 Datenblatt) | | Versorgung: LSM6DSOX Breakout VIN | pass | 3,2-3,4 V (nominal 3,3) innerhalb 3,0-5,0 V (Adafruit 4438 (3-5 V)) | | Versorgung: INA260 VS | pass | 3,2-3,4 V (nominal 3,3) innerhalb 2,7-5,5 V (TI INA260 Datenblatt) | | Versorgung: Waveshare 2inch LCD VCC | pass, ohne Reserve | Minimum der Schiene 3,2 V unter den spezifizierten 3,3 V (Waveshare wiki (3,3 V / 5 V)): keine Reserve, nachmessen | | Signal: Servo-PWM -> SPT5435LV Signaleingang | pass, ohne Reserve | Minimum der Schiene 3,2 V unter den spezifizierten 3,3 V (SPT Spezifikationsseite (PWM-Spannung 3,3-5,0 V)): keine Reserve, nachmessen | | Signal: I²C -> PCA9685, LSM6DSOX, INA260 | pass | 3,2-3,4 V (nominal 3,3) innerhalb 3,0-5,0 V (Überschneidung der drei VCC-Bereiche (PCA9685 2,3-5,5, LSM6DSOX Breakout 3-5, INA260 2,7-5,5 V)) | | Signal: LCD SPI -> Waveshare 2inch LCD | pass, ohne Reserve | Minimum der Schiene 3,2 V unter den spezifizierten 3,3 V (Waveshare wiki): keine Reserve, nachmessen | | Signal: Servo-OE -> PCA9685 OE | pass | 3,2-3,4 V (nominal 3,3) innerhalb 2,3-5,5 V (NXP PCA9685 Datenblatt (VCC-Bereich)) | --- # Passungen und Toleranzen {#fits-and-tolerances} Generiert von `strido_verify.fits` aus dem montierten CAD (Referenzpose) und `hardware/verification/tolerances.yaml`. Jede Schraubenachse wird alle 0,5 mm abgetastet; jedes gedruckte Teil um sie herum wird senkrecht zur Achse geschnitten und sein engster Bohrungsdurchmesser klassifiziert. **Schrauben:** 223 — ok 86, warn 137, **fail 0**. **Lagersitze:** 32 — fail 0. | Passungsklasse | ok | warn | fail | |---|---|---|---| | Durchgangsbohrung | 69 | 80 | 0 | | gewindeformend | 19 | 67 | 0 | | enger Durchgang | 0 | 58 | 0 | | Durchgang | 37 | 0 | 0 | | Lagerbohrung | 31 | 0 | 0 | | Nullspiel | 0 | 0 | 0 | | massiv | 0 | 0 | 0 | | Übermaß | 0 | 0 | 0 | | Schraubenabschluss | Anzahl | |---|---| | Mutter | 105 | | gewindeformend | 78 | | Herstellergewinde | 40 | ## Warnungen: was nach dem Druck zu tun ist {#warnings-what-to-do-after-printing} Gedruckte Bohrungen fallen ~0,15 mm zu klein aus. *Durchgangsbohrung / enger Durchgang*: einmal mit dem Bohrer nach ISO 273 durchbohren. *Gewindeformend, schwacher Halt*: mit Gefühl anziehen; dreht eine Schraube durch, die Vorbohrung mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (anaerobe Schraubensicherung härtet auf Kunststoff nicht aus und kann PETG reißen lassen). *Kurze Einschraubtiefe*: nicht zu fest anziehen. | Teil | Passung | Gewinde | CAD-Bohrung (mm) | Bohrungen | Maßnahme | |---|---|---|---|---|---| | arming_port_bezel | gewindeformend | M2.5 | 2,10 | 2 | kurze Einschraubtiefe 2,5 mm (< 1,5 d) | | back_shell_button | enger Durchgang | M3 | 2,94 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | back_shell_button | enger Durchgang | M3 | 2,95 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | back_shell_button | enger Durchgang | M3 | 2,98 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | back_shell_button | enger Durchgang | M3 | 3,02 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | bottom_shell | Durchgangsbohrung | M3 | 3,05 | 4 | auf 3,2 mm aufbohren (oder 3,4 mm) | | camera_tilt_plate | Durchgangsbohrung | M2 | 2,20 | 4 | auf 2,2 mm aufbohren (oder 2,4 mm) | | electronics_deck | Durchgangsbohrung | M2.5 | 2,69 | 1 | auf 2,7 mm aufbohren (oder 2,9 mm) | | electronics_deck | Durchgangsbohrung | M2.5 | 2,69 | 1 | auf 2,7 mm aufbohren (oder 2,9 mm) | | femur | gewindeformend | M3 | 2,80 | 2 | kurze Einschraubtiefe 4,0 mm (< 1,5 d) | | femur | gewindeformend | M3 | 2,85 | 1 | kurze Einschraubtiefe 4,0 mm (< 1,5 d) | | femur | gewindeformend | M3 | 2,85 | 1 | kurze Einschraubtiefe 4,0 mm (< 1,5 d) | | femur | gewindeformend | M3 | 2,85 | 1 | kurze Einschraubtiefe 4,0 mm (< 1,5 d) | | front_shell_display | Durchgangsbohrung | M3 | 3,08 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | front_shell_display | Durchgangsbohrung | M3 | 3,08 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | front_shell_display | enger Durchgang | M3 | 2,96 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | front_shell_display | enger Durchgang | M3 | 2,97 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | Durchgangsbohrung | M3 | 3,07 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | Durchgangsbohrung | M3 | 3,08 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | Durchgangsbohrung | M3 | 3,10 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | Durchgangsbohrung | M3 | 3,11 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | Durchgangsbohrung | M3 | 3,12 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | Durchgangsbohrung | M3 | 3,13 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | Durchgangsbohrung | M3 | 3,15 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | Durchgangsbohrung | M3 | 3,15 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | enger Durchgang | M3 | 2,58 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | enger Durchgang | M3 | 2,58 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | enger Durchgang | M3 | 2,69 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | enger Durchgang | M3 | 2,69 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | enger Durchgang | M3 | 2,87 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | enger Durchgang | M3 | 2,88 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | enger Durchgang | M3 | 2,89 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | enger Durchgang | M3 | 2,90 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | enger Durchgang | M3 | 2,92 | 4 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | enger Durchgang | M3 | 2,96 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_shoulder_frame | enger Durchgang | M3 | 2,97 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | Durchgangsbohrung | M3 | 3,09 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | Durchgangsbohrung | M3 | 3,10 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | Durchgangsbohrung | M3 | 3,12 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | Durchgangsbohrung | M3 | 3,13 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | enger Durchgang | M3 | 2,90 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | enger Durchgang | M3 | 2,90 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | enger Durchgang | M3 | 2,90 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | enger Durchgang | M3 | 2,91 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | enger Durchgang | M3 | 2,92 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | enger Durchgang | M3 | 2,93 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | enger Durchgang | M3 | 2,93 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | enger Durchgang | M3 | 2,94 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | enger Durchgang | M3 | 2,94 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | enger Durchgang | M3 | 2,94 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | enger Durchgang | M3 | 2,94 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | inner_tibia | enger Durchgang | M3 | 2,95 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | left_servo_mount | gewindeformend | M3 | 2,92 | 1 | schwacher Halt (gedrucktes Verhältnis 0,92): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount | gewindeformend | M3 | 2,92 | 1 | schwacher Halt (gedrucktes Verhältnis 0,92): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount | gewindeformend | M3 | 2,92 | 1 | schwacher Halt (gedrucktes Verhältnis 0,93): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount | gewindeformend | M3 | 2,93 | 1 | schwacher Halt (gedrucktes Verhältnis 0,93): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount | gewindeformend | M3 | 2,94 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount | gewindeformend | M3 | 2,94 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount | gewindeformend | M3 | 2,94 | 2 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount | gewindeformend | M3 | 2,94 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount | gewindeformend | M3 | 2,95 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount | gewindeformend | M3 | 2,95 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount | gewindeformend | M3 | 2,96 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount | gewindeformend | M3 | 2,96 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount_fl | gewindeformend | M3 | 2,50 | 1 | kurze Einschraubtiefe 4,0 mm (< 1,5 d) | | left_servo_mount_fl | gewindeformend | M3 | 2,88 | 1 | schwacher Halt (gedrucktes Verhältnis 0,91): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount_fl | gewindeformend | M3 | 2,89 | 1 | schwacher Halt (gedrucktes Verhältnis 0,91): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount_fl | gewindeformend | M3 | 2,90 | 3 | schwacher Halt (gedrucktes Verhältnis 0,92): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount_fl | gewindeformend | M3 | 2,90 | 1 | schwacher Halt (gedrucktes Verhältnis 0,92): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount_fl | gewindeformend | M3 | 2,91 | 1 | schwacher Halt (gedrucktes Verhältnis 0,92): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount_fl | gewindeformend | M3 | 2,91 | 1 | schwacher Halt (gedrucktes Verhältnis 0,92): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount_fl | gewindeformend | M3 | 2,92 | 1 | schwacher Halt (gedrucktes Verhältnis 0,92): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount_fl | gewindeformend | M3 | 2,93 | 1 | schwacher Halt (gedrucktes Verhältnis 0,93): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount_fl | gewindeformend | M3 | 2,94 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | left_servo_mount_fl | gewindeformend | M3 | 2,95 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | lower_shoulder_frame_front | Durchgangsbohrung | M3 | 3,13 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | lower_shoulder_frame_front | Durchgangsbohrung | M3 | 3,13 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | lower_shoulder_frame_front | Durchgangsbohrung | M3 | 3,15 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | lower_shoulder_frame_front | Durchgangsbohrung | M3 | 3,15 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | lower_shoulder_frame_front | Durchgangsbohrung | M3 | 3,15 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | lower_shoulder_frame_front | Durchgangsbohrung | M3 | 3,15 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | lower_shoulder_frame_front | Durchgangsbohrung | M3 | 3,17 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | lower_shoulder_frame_rear | Durchgangsbohrung | M3 | 3,15 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | lower_shoulder_frame_rear | Durchgangsbohrung | M3 | 3,15 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | lower_shoulder_frame_rear | Durchgangsbohrung | M3 | 3,15 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | lower_shoulder_frame_rear | Durchgangsbohrung | M3 | 3,15 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | lower_shoulder_frame_rear | Durchgangsbohrung | M3 | 3,16 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | lower_shoulder_frame_rear | Durchgangsbohrung | M3 | 3,17 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | lower_shoulder_frame_rear | Durchgangsbohrung | M3 | 3,17 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | lower_shoulder_frame_rear | Durchgangsbohrung | M3 | 3,17 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_shoulder_frame | Durchgangsbohrung | M3 | 3,10 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_shoulder_frame | Durchgangsbohrung | M3 | 3,10 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_shoulder_frame | Durchgangsbohrung | M3 | 3,10 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_shoulder_frame | Durchgangsbohrung | M3 | 3,10 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_shoulder_frame | Durchgangsbohrung | M3 | 3,11 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_shoulder_frame | Durchgangsbohrung | M3 | 3,11 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_shoulder_frame | Durchgangsbohrung | M3 | 3,12 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_tibia | Durchgangsbohrung | M3 | 3,09 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_tibia | Durchgangsbohrung | M3 | 3,11 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_tibia | Durchgangsbohrung | M3 | 3,12 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_tibia | enger Durchgang | M3 | 2,92 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_tibia | enger Durchgang | M3 | 2,92 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_tibia | enger Durchgang | M3 | 2,93 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_tibia | enger Durchgang | M3 | 2,94 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_tibia | enger Durchgang | M3 | 2,94 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_tibia | enger Durchgang | M3 | 2,94 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_tibia | enger Durchgang | M3 | 2,95 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_tibia | enger Durchgang | M3 | 2,95 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_tibia | enger Durchgang | M3 | 2,96 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | outer_tibia | enger Durchgang | M3 | 2,96 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | right_servo_mount | gewindeformend | M3 | 2,94 | 1 | schwacher Halt (gedrucktes Verhältnis 0,93): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount | gewindeformend | M3 | 2,94 | 1 | schwacher Halt (gedrucktes Verhältnis 0,93): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount | gewindeformend | M3 | 2,94 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount | gewindeformend | M3 | 2,94 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount | gewindeformend | M3 | 2,94 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount | gewindeformend | M3 | 2,95 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount | gewindeformend | M3 | 2,95 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount | gewindeformend | M3 | 2,95 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount | gewindeformend | M3 | 2,96 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount | gewindeformend | M3 | 2,96 | 2 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount | gewindeformend | M3 | 2,96 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount | gewindeformend | M3 | 2,96 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount_fr | gewindeformend | M3 | 2,50 | 1 | kurze Einschraubtiefe 4,0 mm (< 1,5 d) | | right_servo_mount_fr | gewindeformend | M3 | 2,92 | 2 | schwacher Halt (gedrucktes Verhältnis 0,92): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount_fr | gewindeformend | M3 | 2,93 | 1 | schwacher Halt (gedrucktes Verhältnis 0,93): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount_fr | gewindeformend | M3 | 2,93 | 1 | schwacher Halt (gedrucktes Verhältnis 0,93): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount_fr | gewindeformend | M3 | 2,94 | 1 | schwacher Halt (gedrucktes Verhältnis 0,93): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount_fr | gewindeformend | M3 | 2,94 | 2 | schwacher Halt (gedrucktes Verhältnis 0,93): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount_fr | gewindeformend | M3 | 2,94 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount_fr | gewindeformend | M3 | 2,94 | 2 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | right_servo_mount_fr | gewindeformend | M3 | 2,94 | 2 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | servo_mount_top_bracket | gewindeformend | M3 | 2,93 | 2 | schwacher Halt (gedrucktes Verhältnis 0,93): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | servo_mount_top_bracket | gewindeformend | M3 | 2,94 | 1 | schwacher Halt (gedrucktes Verhältnis 0,93): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | servo_mount_top_bracket | gewindeformend | M3 | 2,94 | 1 | schwacher Halt (gedrucktes Verhältnis 0,93): anhalten, sobald sie satt anliegt; dreht sie durch, Vorbohrung mit dünnflüssigem Sekundenkleber (CA) härten und erneut eindrehen (keine anaerobe Schraubensicherung auf Kunststoff) | | servo_mount_top_bracket | gewindeformend | M3 | 2,96 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | servo_mount_top_bracket | gewindeformend | M3 | 2,96 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | servo_mount_top_bracket | gewindeformend | M3 | 2,97 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | servo_mount_top_bracket | gewindeformend | M3 | 2,97 | 1 | akzeptierte Abweichung (ADR-009): mit X-Y-Lochkompensation -0,15 mm drucken (Vorbohrung ~2,65 mm); bei einem unkompensierten Druck die Vorbohrung vor dem Eindrehen der Schraube mit einem Tropfen dünnflüssigem Sekundenkleber (CA) härten und prüfen, ob sie greift, bevor das Gelenk belastet wird (keine anaerobe Schraubensicherung auf Kunststoff) | | side_body_beam | Durchgangsbohrung | M3 | 3,13 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | side_body_beam | Durchgangsbohrung | M3 | 3,13 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | side_body_beam | Durchgangsbohrung | M3 | 3,16 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | side_body_beam | Durchgangsbohrung | M3 | 3,16 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | stiff_long_link | enger Durchgang | M3 | 2,91 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | stiff_long_link | enger Durchgang | M3 | 2,91 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | stiff_long_link | enger Durchgang | M3 | 3,02 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | stiff_long_link | enger Durchgang | M3 | 3,03 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | top_shell_sensor | enger Durchgang | M3 | 2,36 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | top_shell_sensor | enger Durchgang | M3 | 2,37 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | top_shell_sensor | enger Durchgang | M3 | 2,38 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | top_shell_sensor | enger Durchgang | M3 | 2,38 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | upper_shoulder_frame | Durchgangsbohrung | M3 | 3,08 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | upper_shoulder_frame | Durchgangsbohrung | M3 | 3,12 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | upper_shoulder_frame | Durchgangsbohrung | M3 | 3,13 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | upper_shoulder_frame | Durchgangsbohrung | M3 | 3,14 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | upper_shoulder_frame | Durchgangsbohrung | M3 | 3,14 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | upper_shoulder_frame | Durchgangsbohrung | M3 | 3,14 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | upper_shoulder_frame | Durchgangsbohrung | M3 | 3,14 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | upper_shoulder_frame | Durchgangsbohrung | M3 | 3,15 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | upper_shoulder_frame | Durchgangsbohrung | M3 | 3,15 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | upper_shoulder_frame | Durchgangsbohrung | M3 | 3,16 | 2 | auf 3,2 mm aufbohren (oder 3,4 mm) | | upper_shoulder_frame | Durchgangsbohrung | M3 | 3,16 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | | upper_shoulder_frame | Durchgangsbohrung | M3 | 3,16 | 1 | auf 3,2 mm aufbohren (oder 3,4 mm) | ## Fehler {#failures} Keine. ## Lagersitze {#bearing-seats} | Lager | Teil | AD (mm) | Sitz (mm) | Ergebnis | |---|---|---|---|---| | body/bearing_625zz@0147 | outer_shoulder_frame | 16,0 | 16,213 | ok | | body/bearing_625zz@0148 | outer_shoulder_frame | 16,0 | 16,166 | ok | | body/bearing_625zz@0150 | outer_shoulder_frame | 16,0 | 16,191 | ok | | body/bearing_625zz@0151 | outer_shoulder_frame | 16,0 | 16,195 | ok | | RL/sleeve_bearing_3x5x5_pair@0159 | short_link | 5,0 | 4,986 | ok | | RL/sleeve_bearing_3x5x5_pair@0160 | short_link | 5,0 | 4,977 | ok | | RL/sleeve_bearing_3x5x5_pair@0177 | stiff_long_link | 5,0 | 4,948 | ok | | RL/sleeve_bearing_3x5x5_pair@0178 | stiff_long_link | 5,0 | 4,861 | ok | | RL/bearing_6805_2rs@0179 | left_shoulder | 37,0 | 36,933 | ok | | RL/bearing_633zz@0203 | outer_tibia | 13,0 | 13,226 | ok | | RL/bearing_633zz@0204 | inner_tibia | 13,0 | 13,208 | ok | | FL/sleeve_bearing_3x5x5_pair@0218 | short_link | 5,0 | 4,983 | ok | | FL/sleeve_bearing_3x5x5_pair@0219 | short_link | 5,0 | 4,979 | ok | | FL/sleeve_bearing_3x5x5_pair@0236 | stiff_long_link | 5,0 | 4,948 | ok | | FL/sleeve_bearing_3x5x5_pair@0237 | stiff_long_link | 5,0 | 4,863 | ok | | FL/bearing_6805_2rs@0238 | left_shoulder | 37,0 | 36,921 | ok | | FL/bearing_633zz@0262 | inner_tibia | 13,0 | 13,226 | ok | | FL/bearing_633zz@0263 | outer_tibia | 13,0 | 13,227 | ok | | RR/sleeve_bearing_3x5x5_pair@0276 | short_link | 5,0 | 4,983 | ok | | RR/sleeve_bearing_3x5x5_pair@0277 | short_link | 5,0 | 4,983 | ok | | RR/sleeve_bearing_3x5x5_pair@0294 | stiff_long_link | 5,0 | 4,927 | ok | | RR/sleeve_bearing_3x5x5_pair@0295 | stiff_long_link | 5,0 | 4,853 | ok | | RR/bearing_6805_2rs@0296 | right_shoulder | 37,0 | 36,945 | ok | | RR/bearing_633zz@0320 | outer_tibia | 13,0 | 13,186 | ok | | RR/bearing_633zz@0321 | inner_tibia | 13,0 | 13,233 | ok | | FR/sleeve_bearing_3x5x5_pair@0335 | short_link | 5,0 | 4,984 | ok | | FR/sleeve_bearing_3x5x5_pair@0336 | short_link | 5,0 | 4,983 | ok | | FR/sleeve_bearing_3x5x5_pair@0353 | stiff_long_link | 5,0 | 4,925 | ok | | FR/sleeve_bearing_3x5x5_pair@0354 | stiff_long_link | 5,0 | 4,856 | ok | | FR/bearing_6805_2rs@0355 | right_shoulder | 37,0 | 36,94 | ok | | FR/bearing_633zz@0379 | outer_tibia | 13,0 | 13,207 | ok | | FR/bearing_633zz@0380 | inner_tibia | 13,0 | 13,176 | ok | --- # Durchdringungsprüfung {#interference-check} Erzeugt von `strido_verify.contacts` (exakte Mesh-Boolesche Operationen, manifold3d). Körper je Pose: 483 (Druckteile, Zukaufteile, Befestigungselemente). | Pose | Überlappende Paare | Gewindeeingriff | Auflagekontakt | Gelenk | Upstream-Passung | Befestigungselement Upstream-Gelenk | **FAIL** | |---|---|---|---|---|---|---|---| | stand_170mm | 292 | 31 | 8 | 67 | 28 | 158 | **0** | | crouch_120mm | 292 | 31 | 8 | 67 | 28 | 158 | **0** | | tall_210mm | 290 | 29 | 8 | 67 | 28 | 158 | **0** | | cad_reference | 290 | 29 | 8 | 67 | 28 | 158 | **0** | ## Klassifizierte Kontakte in der Stehpose {#classified-contacts-at-the-standing-pose} | Bewertung | Paar | Volumen mm³ | Begründung | |---|---|---|---| | joint | RR/femur_servo_connector#36 / RR/servo_disc_horn_25t@0298 | 121,34 | Horn im Femur-Verbinder geklemmt (Upstream-Passung) | | joint | FR/femur_servo_connector#45 / FR/servo_disc_horn_25t@0357 | 121,34 | Horn im Femur-Verbinder geklemmt (Upstream-Passung) | | joint | FL/femur_servo_connector#27 / FL/servo_disc_horn_25t@0240 | 120,97 | Horn im Femur-Verbinder geklemmt (Upstream-Passung) | | joint | RL/femur_servo_connector#18 / RL/servo_disc_horn_25t@0181 | 119,97 | Horn im Femur-Verbinder geklemmt (Upstream-Passung) | | joint | body/bearing_625zz@0150 / FL/hip_bearing_pin@0213 | 29,32 | Hüftlager auf seinem Bolzen | | joint | body/bearing_625zz@0151 / FR/hip_bearing_pin@0330 | 29,32 | Hüftlager auf seinem Bolzen | | joint | RL/right_servo_mount#16 / body/bearing_625zz@0148 | 14,61 | Hüftlagersitz | | joint | RR/left_servo_mount#34 / body/bearing_625zz@0147 | 14,28 | Hüftlagersitz | | joint | RR/femur#37 / RR/bearing_633zz@0320 | 14,22 | Knielager auf seinem Bolzen/in seiner Bohrung | | joint | FR/femur#46 / FR/bearing_633zz@0379 | 14,22 | Knielager auf seinem Bolzen/in seiner Bohrung | | joint | RL/femur#19 / RL/bearing_633zz@0204 | 13,93 | Knielager auf seinem Bolzen/in seiner Bohrung | | joint | FL/femur#28 / FL/bearing_633zz@0262 | 13,08 | Knielager auf seinem Bolzen/in seiner Bohrung | | joint | RL/inner_tibia#22 / RL/outer_tibia#23 | 8,09 | Tibia-Hälften miteinander verklebt (Upstream-Passung) | | joint | RR/right_shoulder#39 / RR/bearing_6805_2rs@0296 | 7,24 | Lager in die Kurbel eingepresst | | joint | FL/inner_tibia#31 / FL/outer_tibia#32 | 7,15 | Tibia-Hälften miteinander verklebt (Upstream-Passung) | | joint | RL/right_servo_mount#16 / RL/servo_spt5435lv@0188 | 7,12 | Servoflansch in seiner Halterung | | joint | FR/right_shoulder#48 / FR/bearing_6805_2rs@0355 | 5,97 | Lager in die Kurbel eingepresst | | joint | RL/inner_tibia#22 / RL/foot_spacer | 5,09 | Fuß-Distanzstück zwischen den Tibia-Hälften | | joint | FL/left_shoulder#30 / FL/bearing_6805_2rs@0238 | 4,88 | Lager in die Kurbel eingepresst | | joint | body/bearing_625zz@0147 / RR/hip_bearing_pin@0271 | 4,79 | Hüftlager auf seinem Bolzen | | joint | body/bearing_625zz@0148 / RL/hip_bearing_pin@0154 | 4,79 | Hüftlager auf seinem Bolzen | | joint | RR/outer_tibia#40 / RR/foot_spacer | 4,34 | Fuß-Distanzstück zwischen den Tibia-Hälften | | joint | FL/inner_tibia#31 / FL/foot_spacer | 4,15 | Fuß-Distanzstück zwischen den Tibia-Hälften | | joint | RL/left_shoulder#21 / RL/bearing_6805_2rs@0179 | 3,63 | Lager in die Kurbel eingepresst | | joint | RR/long_link#38 / RR/sleeve_bearing_3x5x5_pair@0295 | 3,43 | Gleitlager in die Koppel eingepresst | | joint | FR/long_link#47 / FR/sleeve_bearing_3x5x5_pair@0354 | 3,38 | Gleitlager in die Koppel eingepresst | | joint | FL/long_link#29 / FL/sleeve_bearing_3x5x5_pair@0237 | 3,28 | Gleitlager in die Koppel eingepresst | | joint | RL/long_link#20 / RL/sleeve_bearing_3x5x5_pair@0178 | 3,25 | Gleitlager in die Koppel eingepresst | | joint | RL/servo_arm_horn_25t@0157 / RL/servo_spt5435lv@0188 | 2,91 | Horn auf der Abtriebsverzahnung des Servos | | joint | FL/servo_arm_horn_25t@0216 / FL/servo_spt5435lv@0247 | 2,91 | Horn auf der Abtriebsverzahnung des Servos | | joint | RR/servo_arm_horn_25t@0274 / RR/servo_spt5435lv@0305 | 2,91 | Horn auf der Abtriebsverzahnung des Servos | | joint | FR/servo_arm_horn_25t@0333 / FR/servo_spt5435lv@0364 | 2,91 | Horn auf der Abtriebsverzahnung des Servos | | joint | FL/left_servo_mount#24 / FL/servo_spt5435lv@0241 | 2,69 | Servoflansch in seiner Halterung | | joint | FL/left_servo_mount#24 / FL/servo_spt5435lv@0247 | 2,6 | Servoflansch in seiner Halterung | | joint | FR/outer_tibia#49 / FR/foot_spacer | 2,34 | Fuß-Distanzstück zwischen den Tibia-Hälften | | joint | RL/right_servo_mount#16 / RL/servo_spt5435lv@0182 | 2,04 | Servoflansch in seiner Halterung | | joint | RR/servo_disc_horn_25t@0298 / RR/servo_spt5435lv@0299 | 1,84 | Horn auf der Abtriebsverzahnung des Servos | | joint | FR/servo_disc_horn_25t@0357 / FR/servo_spt5435lv@0358 | 1,84 | Horn auf der Abtriebsverzahnung des Servos | | joint | RL/servo_disc_horn_25t@0181 / RL/servo_spt5435lv@0182 | 1,83 | Horn auf der Abtriebsverzahnung des Servos | | joint | FL/servo_disc_horn_25t@0240 / FL/servo_spt5435lv@0241 | 1,83 | Horn auf der Abtriebsverzahnung des Servos | | joint | RR/long_link#38 / RR/sleeve_bearing_3x5x5_pair@0294 | 1,76 | Gleitlager in die Koppel eingepresst | | joint | RR/femur_servo_connector#36 / RR/femur#37 | 1,75 | Verbinder in den Femur geklebt/geschraubt (Upstream-Passung) | | joint | FR/femur_servo_connector#45 / FR/femur#46 | 1,75 | Verbinder in den Femur geklebt/geschraubt (Upstream-Passung) | | joint | FR/long_link#47 / FR/sleeve_bearing_3x5x5_pair@0353 | 1,73 | Gleitlager in die Koppel eingepresst | | joint | FL/outer_tibia#32 / FL/foot_spacer | 1,67 | Fuß-Distanzstück zwischen den Tibia-Hälften | | joint | FL/femur_servo_connector#27 / FL/femur#28 | 1,46 | Verbinder in den Femur geklebt/geschraubt (Upstream-Passung) | | joint | RR/left_servo_mount#34 / RR/servo_spt5435lv@0299 | 1,35 | Servoflansch in seiner Halterung | | joint | FL/servo_disc_horn_25t@0264 / FL/servo_spt5435lv@0265 | 1,32 | Horn auf der Abtriebsverzahnung des Servos | | joint | FR/servo_disc_horn_25t@0381 / FR/servo_spt5435lv@0382 | 1,32 | Horn auf der Abtriebsverzahnung des Servos | | joint | RL/outer_tibia#23 / RL/foot_spacer | 1,31 | Fuß-Distanzstück zwischen den Tibia-Hälften | | joint | FL/long_link#29 / FL/sleeve_bearing_3x5x5_pair@0236 | 1,17 | Gleitlager in die Koppel eingepresst | | joint | RL/servo_disc_horn_25t@0206 / RL/servo_spt5435lv@0207 | 1,16 | Horn auf der Abtriebsverzahnung des Servos | | joint | RR/servo_disc_horn_25t@0323 / RR/servo_spt5435lv@0324 | 1,16 | Horn auf der Abtriebsverzahnung des Servos | | joint | RR/left_servo_mount#34 / RR/servo_spt5435lv@0305 | 1,1 | Servoflansch in seiner Halterung | | joint | RL/long_link#20 / RL/sleeve_bearing_3x5x5_pair@0177 | 1,08 | Gleitlager in die Koppel eingepresst | | joint | FR/inner_tibia#50 / FR/foot_spacer | 0,93 | Fuß-Distanzstück zwischen den Tibia-Hälften | | joint | RR/short_link#35 / RR/sleeve_bearing_3x5x5_pair@0277 | 0,47 | Gleitlager in die Koppel eingepresst | | joint | FR/short_link#44 / FR/sleeve_bearing_3x5x5_pair@0336 | 0,47 | Gleitlager in die Koppel eingepresst | | joint | RR/short_link#35 / RR/sleeve_bearing_3x5x5_pair@0276 | 0,45 | Gleitlager in die Koppel eingepresst | | joint | FR/short_link#44 / FR/sleeve_bearing_3x5x5_pair@0335 | 0,45 | Gleitlager in die Koppel eingepresst | | joint | RL/femur_servo_connector#18 / RL/bearing_6805_2rs@0179 | 0,43 | Oberschenkel-Lagersitz | | joint | RL/short_link#17 / RL/sleeve_bearing_3x5x5_pair@0160 | 0,42 | Gleitlager in die Koppel eingepresst | | joint | RR/femur#37 / RR/bearing_6805_2rs@0296 | 0,42 | Oberschenkel-Lagersitz | | joint | FR/femur#46 / FR/bearing_6805_2rs@0355 | 0,42 | Oberschenkel-Lagersitz | | joint | FL/short_link#26 / FL/sleeve_bearing_3x5x5_pair@0219 | 0,38 | Gleitlager in die Koppel eingepresst | | joint | RL/short_link#17 / RL/sleeve_bearing_3x5x5_pair@0159 | 0,37 | Gleitlager in die Koppel eingepresst | | joint | FL/short_link#26 / FL/sleeve_bearing_3x5x5_pair@0218 | 0,34 | Gleitlager in die Koppel eingepresst | | seating contact | front_shell_display / camera_mount_base | 5,64 | Kamerasockel steht auf der Oberseite der Frontschale (Durchdringung 0,01 mm) | | seating contact | top_shell_sensor / lidar_pedestal | 4,5 | Sockel steht auf der Oberseite der Schale (Durchdringung 0,01 mm) | | seating contact | body/upper_shoulder_frame#13 / iso4032_m3#15 | 2,91 | Auflagefläche von iso4032_m3 auf upper_shoulder_frame (0,08 mm) | | seating contact | body/upper_shoulder_frame#13 / iso4032_m3#17 | 2,64 | unverlierbare iso4032_m3 in ihrer Sechskanttasche (Eckkontakt 0,14 mm) | | seating contact | back_shell_button / arming_port_ring | 1,97 | Klemmring an der Innenseite der Rückschale (Durchdringung 0,03 mm) | | seating contact | front_shell_display / waveshare_lcd_2inch#0 | 0,95 | LCD-Glas von der Halterung an die Innenseite der Frontschale gedrückt (Durchdringung 0,01 mm) | | seating contact | top_shell_sensor / rplidar_usb_adapter#2 | 0,62 | Adapter im Sockel an die Schalenoberseite geklebt (Durchdringung 0,00 mm) | | seating contact | back_shell_button / pushbutton_12mm#4 | 0,31 | Tasterblende an der Schale, Körper durch die Bohrung D12.2 (Durchdringung 0,01 mm) | | upstream fit | body/upper_shoulder_frame#13 / front_shell_display | 44,88 | upper_shoulder_frame / front_shell (Durchdringung 0,06 mm, Upstream-Geometrie) | | upstream fit | body/side_body_beam#8 / top_shell_sensor | 39,35 | side_body_beam / top_shell (Durchdringung 0,02 mm, Upstream-Geometrie) | | upstream fit | body/outer_shoulder_frame#11 / back_shell_button | 35,11 | outer_shoulder_frame / back_shell (Durchdringung 0,05 mm, Upstream-Geometrie) | | upstream fit | body/outer_shoulder_frame#12 / front_shell_display | 31,11 | outer_shoulder_frame / front_shell (Durchdringung 0,04 mm, Upstream-Geometrie) | | upstream fit | body/side_body_beam#7 / electronics_deck | 26,04 | side_body_beam / electronics_mounting_plate (Durchdringung 0,06 mm, Upstream-Geometrie) | | upstream fit | body/upper_shoulder_frame#14 / back_shell_button | 19,33 | upper_shoulder_frame / back_shell (Durchdringung 0,04 mm, Upstream-Geometrie) | | upstream fit | body/bottom_shell#1 / body/inner_shoulder_frame#10 | 16,7 | bottom_shell / inner_shoulder_frame (Durchdringung 0,03 mm, Upstream-Geometrie) | | upstream fit | back_shell_button / lower_shoulder_frame_rear | 15,2 | back_shell / lower_shoulder_frame (Durchdringung 0,03 mm, Upstream-Geometrie) | | upstream fit | body/inner_shoulder_frame#10 / electronics_deck | 14,89 | inner_shoulder_frame / electronics_mounting_plate (Durchdringung 0,21 mm, Upstream-Geometrie) | | upstream fit | body/side_body_beam#8 / body/inner_shoulder_frame#10 | 11,92 | side_body_beam / inner_shoulder_frame (Durchdringung 0,09 mm, Upstream-Geometrie) | | upstream fit | body/side_body_beam#7 / body/inner_shoulder_frame#9 | 11,81 | side_body_beam / inner_shoulder_frame (Durchdringung 0,09 mm, Upstream-Geometrie) | | upstream fit | front_shell_display / lower_shoulder_frame_front | 6,51 | front_shell / lower_shoulder_frame (Durchdringung 0,02 mm, Upstream-Geometrie) | | upstream fit | body/bottom_shell#1 / body/side_body_beam#7 | 6,4 | bottom_shell / side_body_beam (Durchdringung 0,01 mm, Upstream-Geometrie) | | upstream fit | body/inner_shoulder_frame#10 / top_shell_sensor | 6,13 | inner_shoulder_frame / top_shell (Durchdringung 0,04 mm, Upstream-Geometrie) | | upstream fit | body/bottom_shell#1 / lower_shoulder_frame_front | 5,86 | bottom_shell / lower_shoulder_frame (Durchdringung 0,02 mm, Upstream-Geometrie) | | upstream fit | body/inner_shoulder_frame#9 / top_shell_sensor | 5,59 | inner_shoulder_frame / top_shell (Durchdringung 0,02 mm, Upstream-Geometrie) | | upstream fit | body/upper_shoulder_frame#14 / top_shell_sensor | 5,07 | upper_shoulder_frame / top_shell (Durchdringung 0,01 mm, Upstream-Geometrie) | | upstream fit | body/inner_shoulder_frame#10 / lower_shoulder_frame_front | 4,78 | inner_shoulder_frame / lower_shoulder_frame (Durchdringung 0,02 mm, Upstream-Geometrie) | | upstream fit | body/bottom_shell#1 / body/inner_shoulder_frame#9 | 3,86 | bottom_shell / inner_shoulder_frame (Durchdringung 0,02 mm, Upstream-Geometrie) | | upstream fit | body/inner_shoulder_frame#9 / lower_shoulder_frame_rear | 1,45 | inner_shoulder_frame / lower_shoulder_frame (Durchdringung 0,01 mm, Upstream-Geometrie) | | upstream fit | body/inner_shoulder_frame#9 / RR/servo_spt5435lv@0324 | 0,79 | inner_shoulder_frame / servo_spt5435lv (Durchdringung 0,01 mm, Upstream-Geometrie) | | upstream fit | body/inner_shoulder_frame#10 / FL/servo_spt5435lv@0265 | 0,79 | inner_shoulder_frame / servo_spt5435lv (Durchdringung 0,01 mm, Upstream-Geometrie) | | upstream fit | body/upper_shoulder_frame#13 / top_shell_sensor | 0,72 | upper_shoulder_frame / top_shell (Durchdringung 0,01 mm, Upstream-Geometrie) | | upstream fit | FR/right_servo_mount#42 / FR/servo_disc_horn_25t@0381 | 0,67 | right_servo_mount / servo_disc_horn_25t (Durchdringung 0,00 mm, Upstream-Geometrie) | | upstream fit | body/inner_shoulder_frame#10 / body/upper_shoulder_frame#13 | 0,64 | inner_shoulder_frame / upper_shoulder_frame (Durchdringung 0,00 mm, Upstream-Geometrie) | | upstream fit | body/bottom_shell#1 / body/side_body_beam#8 | 0,62 | bottom_shell / side_body_beam (Durchdringung 0,00 mm, Upstream-Geometrie) | | upstream fit | body/inner_shoulder_frame#9 / RL/servo_spt5435lv@0207 | 0,46 | inner_shoulder_frame / servo_spt5435lv (Durchdringung 0,04 mm, Upstream-Geometrie) | | upstream fit | body/inner_shoulder_frame#10 / FR/servo_spt5435lv@0382 | 0,46 | inner_shoulder_frame / servo_spt5435lv (Durchdringung 0,04 mm, Upstream-Geometrie) | 31 Überlappungen durch Gewindeeingriff (Schraubenschaft in einer Vorbohrung, Mutter, einem Abstandsbolzen oder Gewindebolzen) und 158 Überlappungen von Befestigungselementen an Upstream-Gelenken (Befestigungselement auf einer gemessenen Bohrungsachse; Ausrichtung von unverlierbaren Muttern und Schlitzen ist nicht modelliert) sind in der Tabelle nicht aufgeführt. --- # Druckbarkeit {#printability} Erzeugt von `strido_verify.printability` mit PrusaSlicer-2.9.6 based on Slic3r (with GUI support) und `hardware/print/prusaslicer.ini`. 34 Teiletypen wie im Druckpaket ausgerichtet geslict, 13 Druckplatten wie angeordnet geslict: **0 fail**, 4 warn. Gesamtes Druckpaket: 958 g PETG, 100 h Druckzeit (Slicer-Schätzung, alle Teile). Dünne Bereiche: seitliche Wände unter 0,8 mm (zwei Linien) oder horizontale Deckschichten unter 0,6 mm (drei Schichten); 1-%-Perzentil der Dicke je Ausrichtung. | Teil | Anz. | Stützstrukturen | Brim | Zeit | Filament (g) | Dünn seitlich (mm²) | Dünne Deckschicht (mm²) | Min. Wand / Deckschicht (mm) | Ergebnis | Slicer / Anmerkungen | |---|---|---|---|---|---|---|---|---|---|---| | left_servo_mount | 1 | ja | nein | 2h 01m | 18,0 | 12 | 22 | 1,54 / 0,42 | warn | dünne Wände oder Deckschichten: druckbar, aber nur ein bis zwei Linien / Schichten dick | | left_servo_mount_fl | 1 | ja | nein | 2h 01m | 18,0 | 7 | 17 | 1,52 / 0,51 | warn | dünne Wände oder Deckschichten: druckbar, aber nur ein bis zwei Linien / Schichten dick | | right_servo_mount | 1 | ja | nein | 2h 01m | 18,0 | 12 | 11 | 1,53 / 0,53 | warn | dünne Wände oder Deckschichten: druckbar, aber nur ein bis zwei Linien / Schichten dick | | right_servo_mount_fr | 1 | ja | nein | 2h 01m | 18,0 | 12 | 26 | 1,52 / 0,38 | warn | dünne Wände oder Deckschichten: druckbar, aber nur ein bis zwei Linien / Schichten dick | | arming_port_bezel | 1 | nein | nein | 0h 11m | 1,4 | 0 | 0 | 0,50 / 1,00 | ok | | | arming_port_ring | 1 | nein | nein | 0h 07m | 0,8 | 0 | 0 | 0,96 / 3,00 | ok | | | back_shell_button | 1 | nein | ja | 4h 33m | 53,0 | 0 | 0 | 1,64 / 2,00 | ok | | | bottom_shell | 1 | ja | ja | 8h 12m | 76,2 | 0 | 0 | 1,00 / 1,97 | ok | | | camera_mount_base | 1 | nein | nein | 0h 45m | 5,2 | 0 | 0 | 2,83 / 3,00 | ok | | | camera_tilt_plate | 1 | ja | nein | 0h 40m | 6,8 | 0 | 0 | 1,10 / 3,00 | ok | | | display_bracket | 1 | nein | nein | 1h 06m | 9,5 | 0 | 0 | 1,82 / 3,00 | ok | | | electronics_deck | 1 | ja | nein | 5h 11m | 45,3 | 6 | 0 | 1,17 / 1,50 | ok | | | femur | 4 | ja | nein | 2h 29m | 24,6 | 0 | 0 | 2,36 / 0,73 | ok | | | femur_servo_connector | 4 | ja | nein | 0h 17m | 2,9 | 0 | 0 | 2,17 / 1,00 | ok | | | foot_spacer | 4 | ja | nein | 0h 12m | 1,9 | 0 | 0 | 0,83 / 1,16 | ok | | | front_shell_display | 1 | nein | ja | 3h 40m | 36,7 | 0 | 0 | 1,07 / 1,50 | ok | | | hip_bearing_pin | 4 | nein | nein | 0h 01m | 0,1 | 3 | 0 | 0,58 / 0,65 | ok | | | inner_shoulder_frame | 2 | nein | nein | 2h 01m | 17,7 | 0 | 0 | 0,97 / 2,00 | ok | | | inner_tibia | 4 | ja | nein | 1h 40m | 16,8 | 0 | 0 | 1,94 / 1,41 | ok | | | left_shoulder | 2 | ja | nein | 1h 11m | 12,6 | 9 | 0 | 1,04 / 1,50 | ok | | | lidar_pedestal | 1 | nein | nein | 2h 13m | 20,8 | 0 | 0 | 2,79 / 3,00 | ok | | | lower_shoulder_frame_front | 1 | nein | nein | 1h 16m | 11,5 | 0 | 0 | 0,96 / 0,77 | ok | | | lower_shoulder_frame_rear | 1 | nein | nein | 1h 16m | 11,5 | 0 | 0 | 0,96 / 0,77 | ok | | | outer_shoulder_frame | 2 | nein | nein | 2h 19m | 21,8 | 0 | 0 | 3,05 / 0,60 | ok | | | outer_tibia | 4 | ja | nein | 1h 40m | 16,7 | 0 | 0 | 1,37 / 1,30 | ok | | | right_shoulder | 2 | ja | nein | 1h 12m | 12,5 | 0 | 0 | 1,06 / 1,50 | ok | | | servo_bus_holder_front | 1 | ja | nein | 1h 13m | 11,4 | 0 | 0 | 1,60 / 0,60 | ok | | | servo_bus_holder_rear | 1 | ja | nein | 0h 45m | 6,8 | 0 | 0 | 1,54 / 0,60 | ok | Stützstrukturen angegeben, aber der Slicer findet nichts zu stützen | | servo_mount_top_bracket | 4 | nein | nein | 0h 26m | 4,2 | 0 | 0 | 2,53 / 1,33 | ok | | | short_link | 4 | ja | nein | 0h 13m | 1,9 | 0 | 0 | 0,57 / 0,56 | ok | | | side_body_beam | 2 | nein | nein | 1h 33m | 14,2 | 0 | 0 | 2,10 / 1,03 | ok | | | stiff_long_link | 4 | nein | nein | 0h 58m | 10,8 | 0 | 0 | 1,00 / 10,00 | ok | | | top_shell_sensor | 1 | ja | ja | 8h 37m | 77,2 | 0 | 0 | 1,00 / 1,97 | ok | | | upper_shoulder_frame | 2 | nein | nein | 1h 50m | 17,9 | 0 | 0 | 1,40 / 0,95 | ok | | | Druckplatte | Ergebnis | Slicer | |---|---|---| | plate_graphite_01.3mf | ok | | | plate_graphite_02.3mf | ok | | | plate_graphite_03.3mf | ok | | | plate_graphite_04.3mf | ok | | | plate_graphite_05.3mf | ok | | | plate_graphite_06.3mf | ok | | | plate_graphite_07.3mf | ok | | | plate_graphite_08.3mf | ok | | | plate_graphite_09.3mf | ok | | | plate_graphite_10.3mf | ok | | | plate_lime_01.3mf | ok | | | plate_lime_02.3mf | ok | | | plate_lime_03.3mf | ok | | --- # Sichtfeld der Sensoren {#sensor-field-of-view} Erzeugt von `strido_verify.sensor_fov` (Raycasting am posierten CAD-Modell). LiDAR-Scanebene: 150,3 mm im STEP-Koordinatensystem = 71,6 mm über den Hüftachsen (254 mm über dem Boden beim Stehen auf 170 mm). | Pose | Blockierte LiDAR-Strahlen (von 720) | Kamerabild zeigt den Roboter | |---|---|---| | stand | 0 | 0,0 % | | crouch | 0 | 0,0 % | | trot_swing_apex | 0 | 0,0 % | | trot_max_stride | 0 | 0,0 % | | hips_abducted | 0 | 0,0 % | --- # Festigkeitsprüfung {#strength-check} Erzeugt von `python -m strido_verify.strength` aus `hardware/strength.yaml`, den gedruckten STLs, der Beingeometrie und dem Passungsbericht. **19 Prüfungen: 19 ok, 0 warn, 0 fail; kleinster Sicherheitsfaktor 2,22 (Biegung der Tibia-Hälften (Kniemoment, auf beide Hälften verteilt)).** Sicherheitsfaktor S = zulässig / tatsächlich; fail unter 1,5, warn unter 2,0. Formeln und Hintergrund: [Festigkeit, Drehmoment und Versagen](../wiki/making/strength.md). ## Lasten {#loads} | Last | Wert | Herleitung | |---|---|---| | Fußkraft, harte Landung | 45,2 N | F = 3,0 · m · g / 2, m = 3,07 kg | | Gelenkmoment Oberschenkel und Hüfte | 3,43 N·m | Blockiermoment des Servos (das größte Moment, das der Servo aufbringt) | | Gelenkmoment Knie | 3,07 N·m | Knieservo im Blockierzustand über das Koppelgetriebe, Maximum über den Gelenkbereich | | Kniemoment, das eine Landung erfordern würde | 5,60 N·m | F_foot · L_tibia (124 mm); jenseits des Servomoments wird das Knie zurückgetrieben | | Kraft in der kurzen Koppel | 211 N | T_stall / (r_arm · sin α), Maximum über den Gelenkbereich (r_arm 24,0 mm) | | Kraft in der langen Koppel | 192 N | T_crank / (r_crank_b · sin β), Maximum über den Gelenkbereich | | Radialkraft im Kniegelenk | 237 N | F_foot + F_long (obere Schranke) | Werkstoff: PETG (technisches Datenblatt Prusament PETG v1.1, gedruckte Probekörper, 0,2-mm-Schichten): 47 MPa entlang der Schichten, 18 MPa quer dazu. Querschnitte zählen nur die 1,2-mm-Wände (Füllung ignoriert). Schrauben: DIN 912 A2-70 (ISO 3506, Bossard-Tabellen). ## Prüfungen {#checks} | Prüfung | Teile | Formel | Tatsächlich | Zulässig | S | Status | |---|---|---|---|---|---|---| | Biegung des Femurs am schwächsten Querschnitt (Blockiermoment des Oberschenkelservos) | femur | $\sigma = T_\mathrm{thigh} / W$ | 14,54 MPa | 47 MPa | **3,23** | ok | | Biegung der Tibia-Hälften (Kniemoment, auf beide Hälften verteilt) | inner_tibia, outer_tibia | $\sigma = \dfrac{T_\mathrm{knee}}{W_\mathrm{inner} + W_\mathrm{outer}}$ | 21,16 MPa | 47 MPa | **2,22** | ok | | Zug/Druck der kurzen Koppel (Versatz zur Bolzenlinie e = 0,0 mm) | short_link | $\sigma = \dfrac{F}{A} + \dfrac{F\,e}{W}\sec\!\left(\dfrac{L}{2}\sqrt{\dfrac{F}{E I}}\right)$ | 8,65 MPa | 47 MPa | **5,44** | ok | | Knicken der kurzen Koppel (gelenkig in der Beinebene, K = 0,7 quer dazu) | short_link | $F_\mathrm{cr} = \dfrac{\pi^2 E I}{(K L)^2}$ | 211,49 N | 2002,8 N | **9,47** | ok | | Lochleibungsdruck am Bolzenloch der kurzen Koppel | short_link | $p = \dfrac{F}{d\,t}$ | 4,28 MPa | 47 MPa | **10,97** | ok | | Zug/Druck der langen Koppel (Versatz zur Bolzenlinie e = 2,0 mm) | stiff_long_link | $\sigma = \dfrac{F}{A} + \dfrac{F\,e}{W}\sec\!\left(\dfrac{L}{2}\sqrt{\dfrac{F}{E I}}\right)$ | 10,82 MPa | 47 MPa | **4,34** | ok | | Knicken der langen Koppel (gelenkig in der Beinebene, K = 0,7 quer dazu) | stiff_long_link | $F_\mathrm{cr} = \dfrac{\pi^2 E I}{(K L)^2}$ | 192,1 N | 486,6 N | **2,53** | ok | | Lochleibungsdruck am Bolzenloch der langen Koppel | stiff_long_link | $p = \dfrac{F}{d\,t}$ | 6,61 MPa | 47 MPa | **7,11** | ok | | 4 × M3 Abscherung, Femur am Oberschenkelhorn (r = 7,0 mm) | femur, femur_servo_connector | $\tau = \dfrac{T}{n\,r\,A_s}$ | 24,35 MPa | 259,6 MPa | **10,66** | ok | | Lochleibungsdruck im gedruckten Loch, Femur am Oberschenkelhorn | femur, femur_servo_connector | $p = \dfrac{T}{n\,r\,d\,t}$ | 8,48 MPa | 47 MPa | **5,55** | ok | | 2 × M3 Abscherung, Hüfthorn an der Servohalterung (r = 7,3 mm) | left_servo_mount, left_servo_mount_fl, right_servo_mount, right_servo_mount_fr | $\tau = \dfrac{T}{n\,r\,A_s}$ | 46,51 MPa | 259,6 MPa | **5,58** | ok | | Lochleibungsdruck im gedruckten Loch, Hüfthorn an der Servohalterung | left_servo_mount, left_servo_mount_fl, right_servo_mount, right_servo_mount_fr | $p = \dfrac{T}{n\,r\,d\,t}$ | 17,93 MPa | 47 MPa | **2,62** | ok | | M3 Abscherung, Armbolzen (kurze Koppel) | short_link | $\tau = F / A_s$ | 42,04 MPa | 259,6 MPa | **6,18** | ok | | M3 Abscherung, Tibia-Koppelbolzen (lange Koppel) | inner_tibia, outer_tibia, stiff_long_link | $\tau = \dfrac{F}{2\,A_s}$ | 19,1 MPa | 259,6 MPa | **13,6** | ok | | M3 Abscherung, Knieachsschraube (eine pro Seite) | femur, inner_tibia, outer_tibia | $\tau = F / A_s$ | 23,59 MPa | 259,6 MPa | **11,01** | ok | | Lochleibungsdruck der Knieachse in der Femur-Vorbohrung | femur | $p = \dfrac{F}{d\,L_e}$ | 10,59 MPa | 47 MPa | **4,44** | ok | | 633ZZ statische Radiallast (Knie, zwei pro Bein) | bearing_633zz | $S_0 = C_0 / F_r$ | 118,64 N | 490 N | **4,13** | ok * | | 6805-2RS statische Radiallast (Schulterkurbel) | bearing_6805 | $S_0 = C_0 / F_r$ | 403,58 N | 2600 N | **6,44** | ok * | | 625ZZ statische Radiallast (Hüftdrehpunkt) | bearing_625zz | $S_0 = C_0 / F_r$ | 45,18 N | 380 N | **8,41** | ok * | \* **633ZZ statische Radiallast (Knie, zwei pro Bein):** Koyo 633 ZZ \* **6805-2RS statische Radiallast (Schulterkurbel):** SKF 61805-2RS1 \* **625ZZ statische Radiallast (Hüftdrehpunkt):** SKF 625-2Z ## Anzugsmoment in gedruckte Vorbohrungen {#tightening-torque-into-printed-pilots} Beim Ausreißen einer gewindeformenden Schraube schert der Kunststoff auf einem Zylinder mit dem Gewindedurchmesser ab: $F = \tau\,\pi\,d\,L_e$ mit $\tau = 0.577 \times$ Schichthaftung (die schwächste Richtung). Das Moment, das dies bewirkt, ist $T = k\,F\,d$ ($k = 0.2$); ziehen Sie höchstens mit der Hälfte davon an. | Verbindung | Teil | Gewinde | Einschraubtiefe | Ausreißkraft | Überdrehmoment | **Max. Anzugsmoment** | |---|---|---|---|---|---|---| | Halter -> Dom der Frontschale (selbstschneidend) | front_shell_display | M3 | 6,5 mm | 636 N | 0,38 N·m | **0,19 N·m** | | bracket_screws | left_servo_mount | M3 | 12,0 mm | 1175 N | 0,7 N·m | **0,35 N·m** | | bracket_screws | left_servo_mount_fl | M3 | 12,0 mm | 1175 N | 0,7 N·m | **0,35 N·m** | | bracket_screws | right_servo_mount | M3 | 12,0 mm | 1175 N | 0,7 N·m | **0,35 N·m** | | bracket_screws | right_servo_mount_fr | M3 | 12,0 mm | 1175 N | 0,7 N·m | **0,35 N·m** | | bracket_screws | servo_mount_top_bracket | M3 | 7,0 mm | 685 N | 0,41 N·m | **0,21 N·m** | | Bushalter -> unterer Schulterrahmen (selbstschneidend) | lower_shoulder_frame_front | M3 | 5,0 mm | 489 N | 0,29 N·m | **0,15 N·m** | | Bushalter -> unterer Schulterrahmen (selbstschneidend) | lower_shoulder_frame_rear | M3 | 5,0 mm | 489 N | 0,29 N·m | **0,15 N·m** | | Klemmring -> Blende durch das D20-Loch | arming_port_bezel | M2.5 | 2,5 mm | 204 N | 0,1 N·m | **0,05 N·m** | | crank_pins | left_shoulder | M3 | 11,5 mm | 1126 N | 0,68 N·m | **0,34 N·m** | | crank_pins | right_shoulder | M3 | 11,5 mm | 1126 N | 0,68 N·m | **0,34 N·m** | | hip_horn | left_servo_mount | M3 | 4,5 mm | 440 N | 0,26 N·m | **0,13 N·m** | | hip_horn | left_servo_mount_fl | M3 | 4,5 mm | 440 N | 0,26 N·m | **0,13 N·m** | | hip_horn | right_servo_mount | M3 | 4,5 mm | 440 N | 0,26 N·m | **0,13 N·m** | | hip_horn | right_servo_mount_fr | M3 | 4,5 mm | 440 N | 0,26 N·m | **0,13 N·m** | | hip_pivot | left_servo_mount | M3 | 4,0 mm | 392 N | 0,23 N·m | **0,12 N·m** | | hip_pivot | left_servo_mount_fl | M3 | 4,0 mm | 392 N | 0,23 N·m | **0,12 N·m** | | hip_pivot | right_servo_mount | M3 | 4,0 mm | 392 N | 0,23 N·m | **0,12 N·m** | | hip_pivot | right_servo_mount_fr | M3 | 4,0 mm | 392 N | 0,23 N·m | **0,12 N·m** | | knee_axle | femur | M3 | 4,0 mm | 392 N | 0,23 N·m | **0,12 N·m** | | leg_servo_ears_and_bracket | left_servo_mount | M3 | 9,5 mm | 930 N | 0,56 N·m | **0,28 N·m** | | leg_servo_ears_and_bracket | left_servo_mount_fl | M3 | 9,5 mm | 930 N | 0,56 N·m | **0,28 N·m** | | leg_servo_ears_and_bracket | right_servo_mount | M3 | 9,5 mm | 930 N | 0,56 N·m | **0,28 N·m** | | leg_servo_ears_and_bracket | right_servo_mount_fr | M3 | 9,5 mm | 930 N | 0,56 N·m | **0,28 N·m** | | Sockel -> Oberschale (von unten, selbstschneidend) | lidar_pedestal | M3 | 9,5 mm | 930 N | 0,56 N·m | **0,28 N·m** | ## Grenzen {#limits} * Statische Prüfungen mit Spitzenlasten; Ermüdung von PETG über Millionen Schritte, Kriechen unter Dauerlast und Kerbwirkung an scharfen Ecken sind nicht modelliert (daher S ≥ 2). * Gelenkmomente sind das spezifizierte Blockiermoment der Servos. Einen bestromten Stirnradservo von außen zurückzutreiben erfordert mehr (etwa 1 / (η_forward · η_reverse), grob 1,5–3 × bei einem mehrstufigen Getriebe [Schätzung]): Ein harter Aufprall kann diese Lasten übersteigen. * Der Stoßfaktor ist eine Annahme, keine Messung; das Blockiermoment des Servos ist der Datenblattwert bei 6,0 V. * Die Biegung wird in der Beinebene am schwächsten von 41 Querschnitten betrachtet; das Knicken deckt beide Richtungen mit der Steifigkeit der Querschnitte in Reihe ab. Biegung der Tibias quer zur Beinebene (Seitenlasten) wird nicht geprüft: Die beiden Hälften sind verbunden, und ihr gemeinsamer Querschnitt ist nicht modelliert. * Der Lochleibungsdruck wird mit der Festigkeit entlang der Schichten verglichen. * Die Aluminiumhörner werden nicht geprüft (ihre Legierung geben die Händler nicht an); sie sind weit fester als die gedruckten Teile, die sie halten. --- # Verkabelungsprüfung {#wiring-check} Erzeugt von `python -m strido_verify.wiring` aus `hardware/wiring.yaml`, durch das CAD geführt von `strido_cad.wiring`. **37 Kabel in 71 Strängen; 174 Prüfungen: 173 ok, 1 warn, 0 fail.** So wird der Kabelbaum gebaut: [Elektronik, Verkabelung und Stromversorgung](../electronics.md#wiring-harness); Hintergrund: [Kabelmanagement](../wiki/making/cable-management.md). Der Freigang verwendet Stichproben der Netzoberfläche in jeder Betriebspose (Stehen, Hocken, Hoch, acht Trot-Phasen, Hüften außen/innen); Stränge durch das Hüftgelenk sind flexible Schlaufen, deren Länge über den gesamten Hüftbereich geprüft wird. Nicht modelliert: Biegeradien (Ecken der Führung sind scharf gezeichnet) und wo eine Hüftschlaufe hängt. ## Erfordert Aufmerksamkeit {#needs-attention} | Prüfung | Element | Status | Wert | Grenze | Hinweis | |---|---|---|---|---|---| | Reichweite | `W23` | warn | 57 mm | Länge nicht veröffentlicht | Sensorkabel des RPLIDAR C1 zum USB-Adapter (mitgeliefert; Länge nicht veröffentlicht [MEASURE]) | ## Zuschnittliste {#cut-list} | Strang | Typ | Von | Nach | Geführt | Zuschnittlänge | |---|---|---|---|---|---| | `W00/red` | battery_core_red | `battery.lead_red` | `xt60_battery.pack_red` | 42 mm | fertig konfektioniert | | `W00/black` | battery_core_black | `battery.lead_black` | `xt60_battery.pack_black` | 53 mm | fertig konfektioniert | | `W01` | wire_14awg_red | `xt60_battery.robot_red` | `fuse_main.in` | 129 mm | 151 mm | | `W02` | wire_14awg_red | `fuse_main.out` | `back.splice` | 46 mm | 62 mm | | `W02/arming` | wire_14awg_red | `back.splice` | `xt60_arming.cups` | 10 mm | 26 mm | | `W02/logic` | fuse_holder_lead | `back.splice` | `fuse_logic.in` | 36 mm | fertig konfektioniert | | `W03` | wire_14awg_red | `xt60_arming.cups` | `mid.ubec_split` | 163 mm | 182 mm | | `W03/front` | wire_14awg_red | `mid.ubec_split` | `ubec_front.in` | 68 mm | 84 mm | | `W03/rear` | wire_14awg_red | `mid.ubec_split` | `ubec_rear.in` | 191 mm | 212 mm | | `W04` | wire_14awg_black | `xt60_battery.robot_black` | `mid.ground_star` | 50 mm | 66 mm | | `W04/front` | wire_14awg_black | `mid.ground_star` | `ubec_front.in` | 59 mm | 75 mm | | `W04/rear` | wire_14awg_black | `mid.ground_star` | `ubec_rear.in` | 197 mm | 219 mm | | `W04/logic` | wire_18awg_black | `mid.ground_star` | `switch.vin` | 202 mm | 226 mm | | `W05` | wire_18awg_pair | `ubec_front.out` | `wago:front.0.p0` | 201 mm | 234 mm | | `W06` | wire_18awg_pair | `ubec_rear.out` | `wago:rear.0.p0` | 151 mm | 180 mm | | `W07/vplus` | wire_18awg_red | `wago:front.0.p4.V+` | `wago:front.1.p0.V+` | 15 mm | 47 mm | | `W07/gnd` | wire_18awg_black | `wago:front.0.p4.GND` | `wago:front.1.p0.GND` | 17 mm | 49 mm | | `W08/vplus` | wire_18awg_red | `wago:rear.0.p4.V+` | `wago:rear.1.p0.V+` | 15 mm | 47 mm | | `W08/gnd` | wire_18awg_black | `wago:rear.0.p4.GND` | `wago:rear.1.p0.GND` | 17 mm | 49 mm | | `W09` | wire_18awg_red | `fuse_logic.out` | `switch.vin` | 256 mm | 290 mm | | `W10` | wire_18awg_red | `switch.vout` | `ina.vin` | 133 mm | 157 mm | | `W11` | wire_18awg_red | `ina.vin` | `reg.vin` | 44 mm | 67 mm | | `W24` | wire_18awg_black | `switch.vout` | `reg.vin` | 125 mm | 148 mm | | `W12` | wire_22awg_quad | `reg.vout` | `pi.gpio_power` | 104 mm | 123 mm | | `W13` | wire_22awg_pair | `button.terminals` | `switch.ab` | 248 mm | 280 mm | | `W14` | usb_a_c | `pi.usb_low` | `xiao.usb` | 22 mm | fertig konfektioniert | | `W15` | usb_a_c | `pi.usb_high` | `lidar_adapter.usb` | 145 mm | fertig konfektioniert | | `W16` | camera_ffc | `pi.cam0` | `camera.ffc` | 167 mm | fertig konfektioniert | | `W17` | wire_22awg_i2c | `xiao.pins` | `pca.header_left` | 280 mm | 312 mm | | `W18` | stemma_qt | `pca.header_right` | `imu.qt_right` | 96 mm | fertig konfektioniert | | `W19` | stemma_qt | `imu.qt_left` | `ina.header` | 125 mm | fertig konfektioniert | | `W20` | wire_22awg_green | `xiao.pins` | `pca.header_left` | 280 mm | 312 mm | | `W21` | lcd_cable | `lcd.connector` | `xiao.pins` | 53 mm | fertig konfektioniert | | `W22` | wire_22awg_white | `pi.gpio_poweroff` | `switch.ab` | 194 mm | 219 mm | | `W23` | lidar_cable | `lidar.cable` | `lidar_adapter.sensor` | 57 mm | fertig konfektioniert | | `S-FL-hip` | servo_lead | `servo:FL.hip` | `front.opening` | 62 mm | fertig konfektioniert | | `S-FL-hip/power` | servo_power | `front.opening` | `wago:front.0.p1` | 93 mm | 114 mm | | `S-FL-hip/signal` | servo_signal | `front.opening` | `pca:15` | 134 mm | 147 mm | | `S-FL-thigh` | servo_lead | `servo:FL.thigh` | `front.thigh_base.L` | 35 mm | fertig konfektioniert | | `S-FL-thigh/power` | servo_power | `front.thigh_base.L` | `wago:front.0.p2` | 59 mm | 80 mm | | `S-FL-thigh/signal` | servo_signal | `front.thigh_base.L` | `pca:11` | 148 mm | 162 mm | | `S-FL-calf` | servo_lead | `servo:FL.calf` | `front.calf_base.L` | 55 mm | fertig konfektioniert | | `S-FL-calf/power` | servo_power | `front.calf_base.L` | `wago:front.0.p3` | 29 mm | 50 mm | | `S-FL-calf/signal` | servo_signal | `front.calf_base.L` | `pca:7` | 171 mm | 188 mm | | `S-FR-hip` | servo_lead | `servo:FR.hip` | `front.opening` | 53 mm | fertig konfektioniert | | `S-FR-hip/power` | servo_power | `front.opening` | `wago:front.1.p1` | 58 mm | 79 mm | | `S-FR-hip/signal` | servo_signal | `front.opening` | `pca:14` | 131 mm | 145 mm | | `S-FR-thigh` | servo_lead | `servo:FR.thigh` | `front.thigh_base.R` | 35 mm | fertig konfektioniert | | `S-FR-thigh/power` | servo_power | `front.thigh_base.R` | `wago:front.1.p2` | 60 mm | 81 mm | | `S-FR-thigh/signal` | servo_signal | `front.thigh_base.R` | `pca:10` | 140 mm | 154 mm | | `S-FR-calf` | servo_lead | `servo:FR.calf` | `front.calf_base.R` | 55 mm | fertig konfektioniert | | `S-FR-calf/power` | servo_power | `front.calf_base.R` | `wago:front.1.p3` | 65 mm | 86 mm | | `S-FR-calf/signal` | servo_signal | `front.calf_base.R` | `pca:6` | 169 mm | 186 mm | | `S-RL-hip` | servo_lead | `servo:RL.hip` | `rear.opening` | 59 mm | fertig konfektioniert | | `S-RL-hip/power` | servo_power | `rear.opening` | `wago:rear.0.p1` | 50 mm | 71 mm | | `S-RL-hip/signal` | servo_signal | `rear.opening` | `pca:13` | 78 mm | 90 mm | | `S-RL-thigh` | servo_lead | `servo:RL.thigh` | `rear.thigh_base.L` | 27 mm | fertig konfektioniert | | `S-RL-thigh/power` | servo_power | `rear.thigh_base.L` | `wago:rear.0.p2` | 57 mm | 78 mm | | `S-RL-thigh/signal` | servo_signal | `rear.thigh_base.L` | `pca:9` | 138 mm | 152 mm | | `S-RL-calf` | servo_lead | `servo:RL.calf` | `rear.calf_base.L` | 45 mm | fertig konfektioniert | | `S-RL-calf/power` | servo_power | `rear.calf_base.L` | `wago:rear.0.p3` | 22 mm | 43 mm | | `S-RL-calf/signal` | servo_signal | `rear.calf_base.L` | `pca:5` | 104 mm | 117 mm | | `S-RR-hip` | servo_lead | `servo:RR.hip` | `rear.opening` | 59 mm | fertig konfektioniert | | `S-RR-hip/power` | servo_power | `rear.opening` | `wago:rear.1.p1` | 82 mm | 103 mm | | `S-RR-hip/signal` | servo_signal | `rear.opening` | `pca:12` | 76 mm | 88 mm | | `S-RR-thigh` | servo_lead | `servo:RR.thigh` | `rear.thigh_base.R` | 27 mm | fertig konfektioniert | | `S-RR-thigh/power` | servo_power | `rear.thigh_base.R` | `wago:rear.1.p2` | 46 mm | 67 mm | | `S-RR-thigh/signal` | servo_signal | `rear.thigh_base.R` | `pca:8` | 138 mm | 153 mm | | `S-RR-calf` | servo_lead | `servo:RR.calf` | `rear.calf_base.R` | 45 mm | fertig konfektioniert | | `S-RR-calf/power` | servo_power | `rear.calf_base.R` | `wago:rear.1.p3` | 60 mm | 81 mm | | `S-RR-calf/signal` | servo_signal | `rear.calf_base.R` | `pca:4` | 104 mm | 117 mm | Zuschnittlänge = geführte Länge + Anschlüsse (wago 11 mm, löten 6 mm, crimpen 3 mm, Stecker 0 mm, Schraube 7 mm) + Reserve (8%, mindestens 10 mm). Zweige der Servokabel (`S-…/power`, `S-…/signal`) werden ab dem Kabelbinder gemessen, an dem sich die Leitung aufteilt. ## Reichweite {#reach} | Prüfung | Element | Status | Wert | Grenze | Hinweis | |---|---|---|---|---|---| | Reichweite | `W00` | ok | 53 mm | ≤ 110 mm | 120 mm geliefert, 67 mm zum Falten und Binden | | Reichweite | `W14` | ok | 22 mm | ≤ 190 mm | 200 mm geliefert, 178 mm zum Falten und Binden | | Reichweite | `W15` | ok | 145 mm | ≤ 190 mm | 200 mm geliefert, 55 mm zum Falten und Binden | | Reichweite | `W16` | ok | 167 mm | ≤ 290 mm | 300 mm geliefert, 133 mm zum Falten und Binden | | Reichweite | `W18` | ok | 96 mm | ≤ 140 mm | 150 mm geliefert, 54 mm zum Falten und Binden | | Reichweite | `W19` | ok | 125 mm | ≤ 140 mm | 150 mm geliefert, 25 mm zum Falten und Binden | | Reichweite | `W21` | ok | 59 mm | ≤ 190 mm | 200 mm geliefert, 141 mm zum Falten und Binden | | Reichweite | `W23` | warn | 57 mm | Länge nicht veröffentlicht | Sensorkabel des RPLIDAR C1 zum USB-Adapter (mitgeliefert; Länge nicht veröffentlicht [MEASURE]) | | Reichweite | `S-FL-hip` | ok | 210 mm | ≤ 250 mm | 260 mm geliefert, 50 mm zum Falten und Binden | | Reichweite | `S-FL-thigh` | ok | 197 mm | ≤ 250 mm | 260 mm geliefert, 63 mm zum Falten und Binden | | Reichweite | `S-FL-calf` | ok | 243 mm | ≤ 250 mm | 260 mm geliefert, 17 mm zum Falten und Binden | | Reichweite | `S-FR-hip` | ok | 198 mm | ≤ 250 mm | 260 mm geliefert, 62 mm zum Falten und Binden | | Reichweite | `S-FR-thigh` | ok | 189 mm | ≤ 250 mm | 260 mm geliefert, 71 mm zum Falten und Binden | | Reichweite | `S-FR-calf` | ok | 241 mm | ≤ 250 mm | 260 mm geliefert, 19 mm zum Falten und Binden | | Reichweite | `S-RL-hip` | ok | 149 mm | ≤ 250 mm | 260 mm geliefert, 111 mm zum Falten und Binden | | Reichweite | `S-RL-thigh` | ok | 179 mm | ≤ 250 mm | 260 mm geliefert, 81 mm zum Falten und Binden | | Reichweite | `S-RL-calf` | ok | 162 mm | ≤ 250 mm | 260 mm geliefert, 98 mm zum Falten und Binden | | Reichweite | `S-RR-hip` | ok | 162 mm | ≤ 250 mm | 260 mm geliefert, 98 mm zum Falten und Binden | | Reichweite | `S-RR-thigh` | ok | 180 mm | ≤ 250 mm | 260 mm geliefert, 80 mm zum Falten und Binden | | Reichweite | `S-RR-calf` | ok | 162 mm | ≤ 250 mm | 260 mm geliefert, 98 mm zum Falten und Binden | ## Drahtvorrat {#wire-stock} | Prüfung | Element | Status | Wert | Grenze | Hinweis | |---|---|---|---|---|---| | Drahtvorrat | `wire_14awg black` | ok | 360 mm | ≤ 1000 mm | Silikondraht 14 AWG / 2,5 mm², rot + schwarz, je 1 m | | Drahtvorrat | `wire_14awg red` | ok | 717 mm | ≤ 1000 mm | Silikondraht 14 AWG / 2,5 mm², rot + schwarz, je 1 m | | Drahtvorrat | `wire_18awg black` | ok | 886 mm | ≤ 2000 mm | Silikondraht 18 AWG / 0,75 mm², rot + schwarz (je 1 m pro Einheit) | | Drahtvorrat | `wire_18awg red` | ok | 1022 mm | ≤ 2000 mm | Silikondraht 18 AWG / 0,75 mm², rot + schwarz (je 1 m pro Einheit) | | Drahtvorrat | `wire_22awg black` | ok | 838 mm | ≤ 4000 mm | Silikondraht 22 AWG (Pi-5-V-Versorgung mit Dupont-Crimps, Taster, Brücken) | | Drahtvorrat | `wire_22awg blue` | ok | 312 mm | ≤ 4000 mm | Silikondraht 22 AWG (Pi-5-V-Versorgung mit Dupont-Crimps, Taster, Brücken) | | Drahtvorrat | `wire_22awg green` | ok | 312 mm | ≤ 4000 mm | Silikondraht 22 AWG (Pi-5-V-Versorgung mit Dupont-Crimps, Taster, Brücken) | | Drahtvorrat | `wire_22awg red` | ok | 838 mm | ≤ 4000 mm | Silikondraht 22 AWG (Pi-5-V-Versorgung mit Dupont-Crimps, Taster, Brücken) | | Drahtvorrat | `wire_22awg white` | ok | 219 mm | ≤ 4000 mm | Silikondraht 22 AWG (Pi-5-V-Versorgung mit Dupont-Crimps, Taster, Brücken) | | Drahtvorrat | `wire_22awg yellow` | ok | 312 mm | ≤ 4000 mm | Silikondraht 22 AWG (Pi-5-V-Versorgung mit Dupont-Crimps, Taster, Brücken) | | Drahtvorrat | `spiral_wrap` | ok | 312 mm | ≤ 5000 mm | Spiralschlauch, schwarzes PE, für Bündel 4-10 mm (5-10 m) | ## Fertigkabel {#ready-made-cables} | Prüfung | Element | Status | Wert | Grenze | Hinweis | |---|---|---|---|---|---| | Fertigkabel | `cable_ties` | ok | 30 | ≤ 100 | Kabelbinder 100 x 2,5 mm (100) | | Fertigkabel | `camera_cable_300` | ok | 1 | ≤ 1 | Pi-5-Kamerakabel 22→15 Pin, 300 mm | | Fertigkabel | `stemma_qt_female` | ok | 2 | ≤ 2 | STEMMA-QT-auf-Buchsen-Kabel, 150 mm (Adafruit 4397; IMU zu PCA9685 und IMU zu INA260) | | Fertigkabel | `usb_a_c_short` | ok | 2 | ≤ 2 | USB-A-auf-USB-C-Kabel, 20 cm, 90° (Pi → XIAO, Pi → LiDAR-Adapter) | ## Hüftschlaufe {#hip-loop} | Prüfung | Element | Status | Wert | Grenze | Hinweis | |---|---|---|---|---|---| | Hüftschlaufe | `front.thigh_tie.L → front.thigh_base.L` | ok | 30 mm | ≥ 28,9 mm | Binder zu Binder 13,0–24,1 mm über den Hüftbereich | | Hüftschlaufe | `front.calf_tie.L → front.calf_base.L` | ok | 32 mm | ≥ 30,7 mm | Binder zu Binder 20,0–25,6 mm über den Hüftbereich | | Hüftschlaufe | `front.thigh_tie.R → front.thigh_base.R` | ok | 30 mm | ≥ 28,9 mm | Binder zu Binder 13,0–24,1 mm über den Hüftbereich | | Hüftschlaufe | `front.calf_tie.R → front.calf_base.R` | ok | 32 mm | ≥ 30,7 mm | Binder zu Binder 20,0–25,6 mm über den Hüftbereich | | Hüftschlaufe | `rear.thigh_tie.L → rear.thigh_base.L` | ok | 22 mm | ≥ 19,4 mm | Binder zu Binder 11,9–16,2 mm über den Hüftbereich | | Hüftschlaufe | `rear.calf_tie.L → rear.calf_base.L` | ok | 22 mm | ≥ 19,4 mm | Binder zu Binder 11,9–16,1 mm über den Hüftbereich | | Hüftschlaufe | `rear.thigh_tie.R → rear.thigh_base.R` | ok | 22 mm | ≥ 19,4 mm | Binder zu Binder 11,9–16,2 mm über den Hüftbereich | | Hüftschlaufe | `rear.calf_tie.R → rear.calf_base.R` | ok | 22 mm | ≥ 19,4 mm | Binder zu Binder 11,9–16,1 mm über den Hüftbereich | ## Anschluss {#port} | Prüfung | Element | Status | Wert | Grenze | Hinweis | |---|---|---|---|---|---| | Anschluss | `pca:10` | ok | 1 | 1 | S-FR-thigh/signal | | Anschluss | `pca:11` | ok | 1 | 1 | S-FL-thigh/signal | | Anschluss | `pca:12` | ok | 1 | 1 | S-RR-hip/signal | | Anschluss | `pca:13` | ok | 1 | 1 | S-RL-hip/signal | | Anschluss | `pca:14` | ok | 1 | 1 | S-FR-hip/signal | | Anschluss | `pca:15` | ok | 1 | 1 | S-FL-hip/signal | | Anschluss | `pca:4` | ok | 1 | 1 | S-RR-calf/signal | | Anschluss | `pca:5` | ok | 1 | 1 | S-RL-calf/signal | | Anschluss | `pca:6` | ok | 1 | 1 | S-FR-calf/signal | | Anschluss | `pca:7` | ok | 1 | 1 | S-FL-calf/signal | | Anschluss | `pca:8` | ok | 1 | 1 | S-RR-thigh/signal | | Anschluss | `pca:9` | ok | 1 | 1 | S-RL-thigh/signal | | Anschluss | `wago:front.0.p0.GND` | ok | 1 | 1 | W05 | | Anschluss | `wago:front.0.p0.V+` | ok | 1 | 1 | W05 | | Anschluss | `wago:front.0.p1.GND` | ok | 1 | 1 | S-FL-hip/power | | Anschluss | `wago:front.0.p1.V+` | ok | 1 | 1 | S-FL-hip/power | | Anschluss | `wago:front.0.p2.GND` | ok | 1 | 1 | S-FL-thigh/power | | Anschluss | `wago:front.0.p2.V+` | ok | 1 | 1 | S-FL-thigh/power | | Anschluss | `wago:front.0.p3.GND` | ok | 1 | 1 | S-FL-calf/power | | Anschluss | `wago:front.0.p3.V+` | ok | 1 | 1 | S-FL-calf/power | | Anschluss | `wago:front.0.p4.GND` | ok | 1 | 1 | W07/gnd | | Anschluss | `wago:front.0.p4.V+` | ok | 1 | 1 | W07/vplus | | Anschluss | `wago:front.1.p0.GND` | ok | 1 | 1 | W07/gnd | | Anschluss | `wago:front.1.p0.V+` | ok | 1 | 1 | W07/vplus | | Anschluss | `wago:front.1.p1.GND` | ok | 1 | 1 | S-FR-hip/power | | Anschluss | `wago:front.1.p1.V+` | ok | 1 | 1 | S-FR-hip/power | | Anschluss | `wago:front.1.p2.GND` | ok | 1 | 1 | S-FR-thigh/power | | Anschluss | `wago:front.1.p2.V+` | ok | 1 | 1 | S-FR-thigh/power | | Anschluss | `wago:front.1.p3.GND` | ok | 1 | 1 | S-FR-calf/power | | Anschluss | `wago:front.1.p3.V+` | ok | 1 | 1 | S-FR-calf/power | | Anschluss | `wago:rear.0.p0.GND` | ok | 1 | 1 | W06 | | Anschluss | `wago:rear.0.p0.V+` | ok | 1 | 1 | W06 | | Anschluss | `wago:rear.0.p1.GND` | ok | 1 | 1 | S-RL-hip/power | | Anschluss | `wago:rear.0.p1.V+` | ok | 1 | 1 | S-RL-hip/power | | Anschluss | `wago:rear.0.p2.GND` | ok | 1 | 1 | S-RL-thigh/power | | Anschluss | `wago:rear.0.p2.V+` | ok | 1 | 1 | S-RL-thigh/power | | Anschluss | `wago:rear.0.p3.GND` | ok | 1 | 1 | S-RL-calf/power | | Anschluss | `wago:rear.0.p3.V+` | ok | 1 | 1 | S-RL-calf/power | | Anschluss | `wago:rear.0.p4.GND` | ok | 1 | 1 | W08/gnd | | Anschluss | `wago:rear.0.p4.V+` | ok | 1 | 1 | W08/vplus | | Anschluss | `wago:rear.1.p0.GND` | ok | 1 | 1 | W08/gnd | | Anschluss | `wago:rear.1.p0.V+` | ok | 1 | 1 | W08/vplus | | Anschluss | `wago:rear.1.p1.GND` | ok | 1 | 1 | S-RR-hip/power | | Anschluss | `wago:rear.1.p1.V+` | ok | 1 | 1 | S-RR-hip/power | | Anschluss | `wago:rear.1.p2.GND` | ok | 1 | 1 | S-RR-thigh/power | | Anschluss | `wago:rear.1.p2.V+` | ok | 1 | 1 | S-RR-thigh/power | | Anschluss | `wago:rear.1.p3.GND` | ok | 1 | 1 | S-RR-calf/power | | Anschluss | `wago:rear.1.p3.V+` | ok | 1 | 1 | S-RR-calf/power | ## Durch Teile {#through-parts} | Prüfung | Element | Status | Wert | Grenze | Hinweis | |---|---|---|---|---|---| | durch Teile | `W00/red` | ok | +1,07 mm | ≥ 0 | nächstes: inner_shoulder_frame | | durch Teile | `W00/black` | ok | +1,11 mm | ≥ 0 | nächstes: inner_shoulder_frame | | durch Teile | `W01` | ok | +0,89 mm | ≥ 0 | nächstes: lipo_2s_5000_gensace | | durch Teile | `W02` | ok | +1,67 mm | ≥ 0 | nächstes: fuse_holder_ato | | durch Teile | `W02/arming` | ok | +3,87 mm | ≥ 0 | nächstes: xt60h_female | | durch Teile | `W02/logic` | ok | +1,18 mm | ≥ 0 | nächstes: fuse_holder_ato | | durch Teile | `W03` | ok | +1,04 mm | ≥ 0 | nächstes: lipo_2s_5000_gensace | | durch Teile | `W03/front` | ok | +0,90 mm | ≥ 0 | nächstes: xt60h_female | | durch Teile | `W03/rear` | ok | +1,18 mm | ≥ 0 | nächstes: lipo_2s_5000_gensace | | durch Teile | `W04` | ok | +1,06 mm | ≥ 0 | nächstes: bottom_shell | | durch Teile | `W04/front` | ok | +1,06 mm | ≥ 0 | nächstes: bottom_shell | | durch Teile | `W04/rear` | ok | +0,78 mm | ≥ 0 | nächstes: lipo_2s_5000_gensace | | durch Teile | `W04/logic` | ok | +1,03 mm | ≥ 0 | nächstes: electronics_deck | | durch Teile | `W05` | ok | +0,65 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `W06` | ok | +0,73 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `W07/vplus` | ok | +0,60 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `W07/gnd` | ok | +1,08 mm | ≥ 0 | nächstes: servo_bus_holder_front | | durch Teile | `W08/vplus` | ok | +0,60 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `W08/gnd` | ok | +1,08 mm | ≥ 0 | nächstes: servo_bus_holder_rear | | durch Teile | `W09` | ok | +0,83 mm | ≥ 0 | nächstes: outer_shoulder_frame | | durch Teile | `W10` | ok | +2,20 mm | ≥ 0 | nächstes: cable_tie_mount | | durch Teile | `W11` | ok | +2,00 mm | ≥ 0 | nächstes: pololu_d36v50f5 | | durch Teile | `W24` | ok | +2,20 mm | ≥ 0 | nächstes: cable_tie_mount | | durch Teile | `W12` | ok | +2,92 mm | ≥ 0 | nächstes: pololu_d36v50f5 | | durch Teile | `W13` | ok | +0,91 mm | ≥ 0 | nächstes: raspberry_pi_5 | | durch Teile | `W14` | ok | +4,89 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `W15` | ok | +0,89 mm | ≥ 0 | nächstes: raspberry_pi_5 | | durch Teile | `W16` | ok | +0,77 mm | ≥ 0 | nächstes: front_shell_display | | durch Teile | `W17` | ok | +0,82 mm | ≥ 0 | nächstes: raspberry_pi_5 | | durch Teile | `W18` | ok | +0,70 mm | ≥ 0 | nächstes: electronics_deck | | durch Teile | `W19` | ok | +0,63 mm | ≥ 0 | nächstes: adafruit_pca9685 | | durch Teile | `W20` | ok | +1,88 mm | ≥ 0 | nächstes: raspberry_pi_5 | | durch Teile | `W21` | ok | +2,81 mm | ≥ 0 | nächstes: outer_shoulder_frame | | durch Teile | `W22` | ok | +1,08 mm | ≥ 0 | nächstes: raspberry_pi_5 | | durch Teile | `W23` | ok | +0,89 mm | ≥ 0 | nächstes: rplidar_c1 | | durch Teile | `S-FL-hip` | ok | +0,80 mm | ≥ 0 | nächstes: inner_shoulder_frame | | durch Teile | `S-FL-hip/power` | ok | +0,72 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `S-FL-hip/signal` | ok | +1,06 mm | ≥ 0 | nächstes: top_shell_sensor | | durch Teile | `S-FL-thigh` | ok | +3,34 mm | ≥ 0 | nächstes: left_servo_mount_fl | | durch Teile | `S-FL-thigh/power` | ok | +0,72 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `S-FL-thigh/signal` | ok | +1,14 mm | ≥ 0 | nächstes: top_shell_sensor | | durch Teile | `S-FL-calf` | ok | +1,17 mm | ≥ 0 | nächstes: servo_spt5435lv | | durch Teile | `S-FL-calf/power` | ok | +0,63 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `S-FL-calf/signal` | ok | +1,31 mm | ≥ 0 | nächstes: top_shell_sensor | | durch Teile | `S-FR-hip` | ok | +1,29 mm | ≥ 0 | nächstes: inner_shoulder_frame | | durch Teile | `S-FR-hip/power` | ok | +0,54 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `S-FR-hip/signal` | ok | +1,07 mm | ≥ 0 | nächstes: top_shell_sensor | | durch Teile | `S-FR-thigh` | ok | +3,58 mm | ≥ 0 | nächstes: right_servo_mount_fr | | durch Teile | `S-FR-thigh/power` | ok | +0,89 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `S-FR-thigh/signal` | ok | +1,17 mm | ≥ 0 | nächstes: top_shell_sensor | | durch Teile | `S-FR-calf` | ok | +1,04 mm | ≥ 0 | nächstes: servo_spt5435lv | | durch Teile | `S-FR-calf/power` | ok | +0,46 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `S-FR-calf/signal` | ok | +1,33 mm | ≥ 0 | nächstes: top_shell_sensor | | durch Teile | `S-RL-hip` | ok | +3,34 mm | ≥ 0 | nächstes: inner_shoulder_frame | | durch Teile | `S-RL-hip/power` | ok | +0,79 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `S-RL-hip/signal` | ok | +1,22 mm | ≥ 0 | nächstes: top_shell_sensor | | durch Teile | `S-RL-thigh` | ok | +1,41 mm | ≥ 0 | nächstes: right_servo_mount | | durch Teile | `S-RL-thigh/power` | ok | +0,41 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `S-RL-thigh/signal` | ok | +0,63 mm | ≥ 0 | nächstes: fuse_holder_ato | | durch Teile | `S-RL-calf` | ok | +1,65 mm | ≥ 0 | nächstes: right_servo_mount | | durch Teile | `S-RL-calf/power` | ok | +0,66 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `S-RL-calf/signal` | ok | +1,99 mm | ≥ 0 | nächstes: top_shell_sensor | | durch Teile | `S-RR-hip` | ok | +3,33 mm | ≥ 0 | nächstes: inner_shoulder_frame | | durch Teile | `S-RR-hip/power` | ok | +0,42 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `S-RR-hip/signal` | ok | +1,25 mm | ≥ 0 | nächstes: top_shell_sensor | | durch Teile | `S-RR-thigh` | ok | +1,68 mm | ≥ 0 | nächstes: left_servo_mount | | durch Teile | `S-RR-thigh/power` | ok | +0,85 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `S-RR-thigh/signal` | ok | +0,71 mm | ≥ 0 | nächstes: fuse_holder_ato | | durch Teile | `S-RR-calf` | ok | +1,46 mm | ≥ 0 | nächstes: left_servo_mount | | durch Teile | `S-RR-calf/power` | ok | +0,50 mm | ≥ 0 | nächstes: wago_221_415 | | durch Teile | `S-RR-calf/signal` | ok | +1,03 mm | ≥ 0 | nächstes: fuse_holder_ato | ## Bewegte Teile {#moving-parts} | Prüfung | Element | Status | Wert | Grenze | Hinweis | |---|---|---|---|---|---| | bewegte Teile | `S-FL-hip/power` | ok | 1,20 mm | ≥ 1,0 mm | servo_spt5435lv (hips_in) | | bewegte Teile | `S-FL-thigh/power` | ok | 1,19 mm | ≥ 1,0 mm | servo_spt5435lv (hips_in) | | bewegte Teile | `S-FL-calf/power` | ok | 1,20 mm | ≥ 1,0 mm | servo_spt5435lv (hips_in) | | bewegte Teile | `S-FR-hip/power` | ok | 1,60 mm | ≥ 1,0 mm | servo_spt5435lv (hips_in) | | bewegte Teile | `S-RL-thigh/power` | ok | 1,18 mm | ≥ 1,0 mm | servo_spt5435lv (hips_in) | | bewegte Teile | `S-RL-thigh/signal` | ok | 1,79 mm | ≥ 1,0 mm | servo_spt5435lv (hips_in) | | bewegte Teile | `S-RL-calf/power` | ok | 1,38 mm | ≥ 1,0 mm | servo_spt5435lv (hips_in) | | bewegte Teile | `S-RL-calf/signal` | ok | 1,79 mm | ≥ 1,0 mm | servo_spt5435lv (hips_in) | | bewegte Teile | `S-RR-thigh/power` | ok | 1,67 mm | ≥ 1,0 mm | servo_spt5435lv (hips_in) | | bewegte Teile | `S-RR-thigh/signal` | ok | 1,76 mm | ≥ 1,0 mm | servo_spt5435lv (hips_in) | | bewegte Teile | `S-RR-calf/power` | ok | 1,34 mm | ≥ 1,0 mm | servo_spt5435lv (hips_in) | | bewegte Teile | `S-RR-calf/signal` | ok | 1,79 mm | ≥ 1,0 mm | servo_spt5435lv (hips_in) | --- # Verifikation {#verification} > **Status:** Nachweisregister. Jeder Abschnitt hält fest, was gelaufen ist, auf welcher Stufe, das beobachtete Ergebnis und seine Grenze. Stufen: **Q0** statisch/Unit (Sekunden), **Q1** CAD-Verifikation (Minuten), **Q2** Simulation und Integrations-Smoke-Tests, **Q3** Hardware. Nichts hiervon wurde an einem physischen Roboter durchgeführt (noch kein Q3). ## 2026-11-01 — Druckpaket nach der zweiten Durchsicht eines Bauenden {#_2026-11-01-print-kit-after-the-builder-s-second-review} | Prüfung | Befehl | Stufe | Beobachtetes Ergebnis | Grenze | |---|---|---|---|---| | Erkennung von Lochstufen | `strido_publish.print_bridges.hole_steps` auf jedem Teil des Druckpakets, so wie es liegt | Q0 | 4 Stufen gefunden und ausgeschnitten: je ein Lagersitz in `inner_tibia` und `outer_tibia`, zwei 625ZZ-Sitze (16,3 → 12,3 mm) in `outer_shoulder_frame` (die Teile, die der Bauende genannt hat); Stufen unter einer Extrusionslinie (0,4 mm) und Ränder des Teils werden übersprungen; nach dem Ausschnitt findet die Erkennung keine mehr. Schnittbilder an der Stufe zeigen weites Loch, Schlitz, Quadrat, enges Loch. Das Review hat die ausgeschnittenen Teile gesliced: `outer_shoulder_frame` druckt Schlitz, Quadrat und Loch bei 4,2/4,4/4,6 mm ohne Stützen; in beiden Tibias liegt der Sitz unter einem Auge 7,4 mm über dem Bett, und PrusaSlicer füllt die Bohrung trotzdem mit Stützen (die Notizen sagen jetzt, sie zu blockieren); die Schnitthöhen sind auf die Slicing-Schichten eingerastet | geometrische Erkennung; ein nicht runder Sitz wird nicht behandelt; Stützenplatzierung des Slicers an diesen drei Teilen von Hand geprüft | | Druckbarkeit mit neuer Ausrichtung und Ausschnitten | `make printability` (PrusaSlicer 2.9.6) | Q1 | 34 Teile und 13 Platten: 0 fail, 4 warn (dünne Deckschichten in den Upstream-Servohaltern, 0,38–0,53 mm); Druckpaket 958 g, 100 h; Servohalter 19 mm hoch wie ein U, 2 % Überhang; `inner_tibia` auf der flachen Seite (1638 mm² Bettkontakt, vorher 71 mm²) | Slicer-Schätzung; noch kein Teil gedruckt | | Tests für Festigkeit und Druckpaket | `python -m strido_verify.strength`, `pytest tests/verify/test_print_kit.py tests/verify/test_strength.py` | Q1 | 19 Prüfungen ok (Querschnitte aus den ausgeschnittenen STLs); 6 Tests bestanden | — | ## 2026-11-01 — steife lange Koppel und Ausrichtung des Druckpakets {#_2026-11-01-stiff-long-link-and-print-kit-orientation} | Prüfung | Befehl | Stufe | Beobachtetes Ergebnis | Grenze | |---|---|---|---|---| | Festigkeit mit der steifen langen Koppel | `python -m strido_verify.strength` | Q1 | 19 Prüfungen, 19 ok, 0 warn, 0 fail; Knicken der langen Koppel S = 2,53 (Upstream-Koppel 0,34, ADR-010), Zug/Druck S = 4,34 einschließlich der Biegung aus dem 2-mm-Versatz des Schafts (Secans-Formel; Befund der Durchsicht, der erste Lauf prüfte nur F/A und ergab 10,3), Lochleibung am Auge S = 7,1; kleinster Faktor jetzt die Tibia-Hälften (2,22); keine akzeptierte Abweichung mehr (`accepted: {}`); Masse 3,07 kg (+24 g für die vier Koppeln), Fußkraft bei der Landung 45,2 N | Querschnitte nur aus Wänden, Werte aus dem PETG-Datenblatt | | Prüfung rot gesehen beim Entwurf der Koppel | `python -m strido_verify.rom`, Sweep der Nachbarabstände (Wegwerfskript, 4 Oberschenkel × 43 Unterschenkel-Posen je Bein) | Q1 | eine mittig auf der Bolzenlinie liegende Koppel kam dem Femur bei gestrecktem Knie bis auf 0,25 mm nahe und berührte bei voller Beugung die Unterlegscheibe der kurzen Koppel; der ROM-Sweep verschob die Unterschenkelgrenze von −45° auf −50° (sichtbar als Diff in `hardware/joint_limits.yaml`). Schaft 2 mm neben der Bolzenlinie mit den Upstream-Augen: jeder Nachbar ≥ 1,0 mm (Femur 1,1, kurze Koppel 1,4), Gelenkgrenzen unverändert | punktweise abgetastete Abstände; der Nachweis sind die Prüfungen unten | | Vollständige CAD-Verifikation | `make verify` | Q1 | Durchdringung 0 ungeklärte Überlappungen (4 Posen, 483 Körper); Freigang 0 fail, 4 knapp (unverändert); ROM-Grenzen unverändert (nur die Kollisionsnachweise außerhalb der Grenzen nennen die neue Koppel); Passungen 0 fail (Gleitlagersitze 4,85–4,95 mm in den 5,0-mm-Bohrungen); Verkabelung 174 Prüfungen, 0 fail, 1 warn; Geometrie-Bindungen synchron | nominelle Geometrie | | Ausrichtung des Druckpakets | `make print`, `make printability` (PrusaSlicer 2.9.6) | Q1 | Femur, obere Halterung, Femur-Servoverbinder, Seitenträger und rechte Schulter neu ausgerichtet; Kamerasockel auf seiner Grundfläche; steife lange Koppel flach, ohne Stützen; die Servohalter bleiben aufrecht (Durchsicht: auf der Seite lägen die Vorbohrungen für das Hüfthorn waagrecht, außer Reichweite der Lochkompensation nach ADR-009). 34 Teile und 13 Platten: 0 fail, 4 warn (dünne Stellen in den Upstream-Servohaltern); Druckpaket 1002 g, 103 h (vorher 1021 g, 104 h). Anlass war die Durchsicht eines Bauenden: die Platten behielten die Lage der veröffentlichten STLs (obere Halterung 56 mm hoch auf 19 × 6 mm Grundfläche, Femur mit 2 mm² Bettkontakt) | Slicer-Schätzung; noch kein Teil gedruckt | | Tests für Festigkeit und Übersetzung | `pytest tests/verify/test_strength.py`, `make drift` | Q0 | Festigkeitstests 4 bestanden (Ausnahmemechanismus mit einem eingefügten ADR-Eintrag geprüft; das Flächenträgheitsmoment der steifen Koppel aus den Wänden stimmt auf 2 % mit der Formel des Hohlquadrats überein) | — | ## 2026-10-31 — Deutsche Seite, KI-Assistent, MCP-Server und Agent Skill {#_2026-10-31-german-site-ai-assistant-mcp-server-and-agent-skill} | Prüfung | Befehl | Stufe | Beobachtetes Ergebnis | Grenze | |---|---|---|---|---| | **Neu:** Übersetzungskataloge vollständig und strukturell intakt | `node docs-site/scripts/i18n-catalogues.mjs check` (in `make drift`) | Q0 | 5746 von 5746 deutschen Segmenten; 0 defekt (Code-Spans, Mathematik, Linkziele, HTML-Tags, Fettmarkierungen, Tabellenzellen, Zeilenzahl) | nur Struktur: Wortlaut per Stichprobe und Terminologie-Durchgang geprüft, nicht von einem muttersprachlichen Lektorat | | Prüfung rot gesehen | dieselbe | Q0 | schlug mit 5431/5433 fehl, solange zwei neue Absätze unübersetzt waren, und während der Übersetzung bei abweichenden Fettmarkierungen; eine vom Übersetzer umgruppierte Zahl (`1126` → `1.126`) macht das Segment jetzt unübersetzt, statt eine veraltete Zahl zu behalten (der Test schlägt mit der früheren Regel fehl) | — | | Tests der Übersetzungs-Engine | `node --test 'docs-site/scripts/*.test.mjs'` (in `make test-web`) | Q0 | 7 bestanden: jede unübersetzte Seite rendert zurück zu ihrer englischen Quelle, deutsche Überschriften behalten die englischen IDs (Wiederholungen nummeriert wie bei VitePress), Zahlen werden in deutscher Schreibweise übernommen, das Zusammenführen behält/öffnet/verwirft Segmente, Strukturprüfung | synthetische Segmente plus jede veröffentlichte Seite | | Build der deutschen Seite | `make docs-build`, gebautes HTML verglichen | Q0 | baut mit der Prüfung toter Links; 60 Seiten × Überschriften-IDs identisch in `/docs/**` und `/de/docs/**` (0 Abweichungen); jede deutsche Seite zu 100 % übersetzt | — | | Deutsche Seite im Browser | verwaltetes Chrome, `/de/`, `/de/docs/shop` | Q2 | deutsche Navigation, Startseite, Shop (Plan A € 978,76), Seitenleiste, Sprachumschalter | visuelle Stichprobe | | **Neu:** Tests des Assistenzdienstes | `cd assistant && npm test` (in `make test-web`) | Q0 | 34 bestanden: Eigentümerbindung, Prüfung von Header-Secret und `cxu_`-Token (Ablehnungen gecacht), Reihenfolge der SSE-Events, Stopp speichert `stopped`, Neu-Generieren ohne doppelte Frage, letzte Tool-Runde mit `tool_choice: none`, Magic Bytes und Grenzen von Anhängen, Kontingent pro Nutzer, Body-Grenzen, MCP initialize/list/call | gefälschter Modell-Transport, Fixture-Wissensbasis | | Assistent gegen das echte Modell | `make assistant` + `make docs`, verwaltetes Chrome | Q2 | Keyring `claude-sonnet-5`: „Schlaufe des vorderen Knies“ beantwortet mit 32 mm = 1,2 × 25,6 mm, mit KaTeX und vier Quellenlinks; angeheftete Seitenleiste bleibt über Seitenwechsel erhalten; ein eingefügtes 2400 × 1600-Bild von Schritt 1 auf `/de/docs/assembly/` auf Deutsch erkannt, mit Link zu Schritt 1; Stopp und dann Wiederholen speicherte eine Frage und eine Antwort; Unterhaltungen über die API aufgelistet, umbenannt, gelöscht | lokale Entwicklungsidentität; Zustand der Keyring-Zugangsdaten auf dem Stack nicht geprüft | | MCP mit einem echten Client | `@modelcontextprotocol/sdk` Streamable-HTTP-Client gegen `/mcp` | Q2 | Werkzeuge `search_docs`, `read_page`, `list_pages`, `search_parts`; deutsche Suche nach „loop key arming“ liefert den Glossareintrag mit seinem `/de/`-Link; `read_page` liefert den Abschnitt der Verkabelungsliste | lokal, ohne App-Token (Entwicklungsidentität) | | Produktions-Images und Identität | `docker compose -f docker-compose.docs.yml -f docker-compose.cortex.yml` (beide Targets) | Q2 | schreibgeschützte Container starten; Assistent ohne Header-Secret 401, mit ihm liefert er `/me` (ohne Keyring deaktiviert) und schreibt in sein Volume; ein gefälschtes `cxu_`-Token 401; Doku 200 auf `/de/docs/ai` | Cortex-Gateway-Route, Keyring und App-Key erst nach dem Deploy geprüft | | 0.3.1 deployt (zwei Dienste, eigene Gateway-Route) | `cortex deploy` (Job `mvwtwfpf-530e539a`), `cortex apps show strido`, `curl` | Q2 | gesund auf `c80f807` („SSO route HTTP 302, upstream HTTP 200; 2 live containers“); `/api/health` offen (61 en / 61 de Seiten, Modell konfiguriert); `/`, `/de/`, `/llms.txt`, `/api/assistant/me`, `/mcp` leiten ohne Sitzung zum SSO-Login um; ein gefälschter `cxu_`-Bearer erreicht den Assistenten und bekommt 401 aus der Token-Prüfung von Cortex | angemeldete Browser-Seiten nicht erneut geprüft (die Sitzung des Relay-Tabs war abgelaufen) | | MCP auf der deployten Seite mit einem echten App-Token | Token erzeugt mit `cortex api post /api/v1/apps/strido/tokens` (1 Tag), SDK-Client, danach widerrufen | Q2 | `tools/list` 4 Werkzeuge; deutsches `search_docs` „Hauptsicherung Bemessung“ antwortet aus dem deutschen Glossar; `search_parts` „servo“ liefert die Stücklistenzeile; `/api/agent/llms.txt` 200, Skill-ZIP 615 655 Bytes; das Token bekommt 403 auf `/api/assistant/*`. `cortex apps connect strido` antwortet 404: Control erfasst `.cortex/package.json` nur für von Cortex erstellte Apps (TODO) | ein Token, ein Client | ## 2026-10-31 — Kabelbaum im CAD verlegt und geprüft {#_2026-10-31-wiring-harness-routed-and-checked-in-the-cad} | Prüfung | Befehl | Stufe | Beobachtetes Ergebnis | Grenze | |---|---|---|---|---| | **Neu:** Verkabelungsprüfung | `python -m strido_verify.wiring` (in `make verify`) | Q1 | 37 Kabel in 71 Abschnitten, 174 Prüfungen: 0 fail, 1 warn (W23, das eigene Kabel des LiDAR: Länge nicht veröffentlicht). Reichweite (zugeschnittene Abzweige mit Reserve und Crimp gezählt): am knappsten die vorderen Knie-Servokabel (243/241 von 250 mm nutzbar aus 260 mm), W19 STEMMA QT (125 von 140 mm). Vorrat: 18 AWG reicht nur, wenn die Stückliste auf 2 m pro Farbe erhöht wird. Hüftschlaufen: vorne 30/32 mm gegenüber 28,9/30,7 mm benötigt (1,2 × Kabelbinder-zu-Kabelbinder 24,1/25,6 mm), hinten 22 mm gegenüber 19,4 mm. Abstand in 13 Posen: kein Leiter durch ein Teil; nächstes bewegtes Teil ≥ 1 mm | Nenngeometrie; Biegeradien und Schlaufenform nicht modelliert; Kabelausgänge und gelieferte Kabellängen teils angenommen (TODO) | | Prüfung während der Konstruktion rot gesehen | dasselbe | Q1 | erste Läufe schlugen fehl: W00/W15/W17/W19/W20 und drei vordere Servokabel zu kurz, Vorrat an 18 AWG und STEMMA QT zu knapp, die vordere Bus-Brücke 0,3 mm im FL-Unterschenkelservo an der inneren Hüftgrenze, der gesteckte Stecker der Akkuleitung im vorderen UBEC, ein Leiter außerhalb seiner verlegten Hülle gezeichnet (die Prüfung kontrolliert jetzt jeden gezeichneten Leiter). Nach der Reichweitenkorrektur aus dem Review schlugen die vorderen Knie-Servokabel (258/259 mm) und W22 (196 mm) fehl: Kreuzung der Knieleitungen zum Bushalter verlegt und der vordere Öffnungs-Kabelbinder auf den natürlichen Kabelweg, W22 jetzt aus zugeschnittenem 22-AWG-Draht. Jeweils in den Daten oder im CAD behoben, nicht durch eine lockerere Grenze | — | | Review-Befunde behoben | Reviewer-Subagent auf die Änderung, dann `make verify` | Q1 | Reichweite ignorierte die Reserve der Abzweige und zählte das PCA-Ende als Stecker (beides behoben; Regressionstest schlägt mit der alten Regel fehl); Kabelbinder-Sockel waren nicht im Hindernisraster (jetzt Katalogteile); W10/W11 waren als Paare auf einen INA260 mit zwei Anschlüssen gezeichnet (jetzt Einzeldrähte + W24 Masse); W01 ohne Umwicklung, obwohl ungesichert (Spiralschlauch pro Kabel); W04-Hauptstrang fehlte in der Liste der Hauptsicherung; Montageanleitung verlegte den Kabelbaum, bevor die Verkabelung der Rückwand existierte, und steckte den Pi vor einer Versorgungsprüfung an (Schritt 20 erledigt jetzt beides, in dieser Reihenfolge) | — | | Unit-Tests der Verkabelungsprüfung | `pytest tests/verify/test_wiring.py tests/verify/test_electronics.py` | Q0 | 17 bestanden: Reichweitenreserve, ein zugeschnittener Abzweig, der seine Reserve braucht, längster Servokabel-Abzweig, ein doppelt belegter Anschluss und ein Paar, das beide Schienen belegt, eine Schlaufe 1 mm kürzer als nötig, ein 22-AWG-Servoabzweig hinter der 25-A-Sicherung, ein Abzweig, der an seiner eigenen Sicherung gemessen wird | synthetische Zeilen plus die versionierte YAML | | Vollständige CAD-Verifikation mit den Kabeln und den neu platzierten Leistungsteilen | `make verify` | Q1 | bestanden: Durchdringung 0 ungeklärte Überlappungen (erster Lauf fand den gedrehten LiDAR-Adapter in einer Schraubensäule des Sockels, behoben), Abstand unverändert (0 fail, 4 knapp), Sensoren: Kabel blockieren keinen LiDAR-Strahl und bleiben außerhalb des Kamerabilds, Verkabelung 173 ok / 1 warn | Kabel von den Teil-zu-Teil-Prüfungen ausgenommen (sie haben ihre eigene); Kabelbinder-Sockel werden geprüft | | Elektronikprüfung der verlegten Kabel | `python -m strido_verify.electronics` | Q0 | 81 Prüfungen bestanden (3 ohne Reserve); der alte 18-AWG-Abgriff hinter der 25-A-Sicherung wäre durchgefallen und ist entfernt (eigene 14-AWG-Leitung des Logikhalters) | Strombelastbarkeitstabelle, kein thermisches Modell | | Veröffentlichte Artefakte | `make bom models manual renders viewer catalog` | Q1 | Pläne A 978,76 € / B 1.126,97 € / C 1.145,24 € / D 987,73 € (Servoverlängerungen raus, Spiralschlauch, Kabelbinder-Sockel, Crimpkontakte, Lötzinn, 2. STEMMA QT und 2. 18-AWG-Satz rein); CAD-Masse 3,008 → 3,050 kg (Kabel pro Instanz gewogen, Pauschalposten entfernt); Montageanleitung 22 Schritte (Verkabelung Schritte 14–16 und 20), neues Rendering `wiring.png`, GLB mit dem Kabelbaum | Preise beobachtet am 2026-10-31 | ## 2026-10-31 — Dokumentationsseite: Shop, Druckpaket, Produktseiten, Lernen-Wiki {#_2026-10-31-documentation-site-shop-print-kit-product-pages-learn-wiki} | Prüfung | Befehl | Stufe | Beobachtetes Ergebnis | Grenze | |---|---|---|---|---| | Shop-Preise reproduzieren den Stücklisten-Optimierer | verwaltetes Chrome auf der gebauten Seite: kompletter Roboter im Warenkorb, Pläne A–D | Q2 | Warenkorbsummen 963,67 € / 1.107,16 € / 1.128,66 € / 972,64 € mit 8 / 4 / 9 / 8 Shops, gleich wie `make bom`; Paketkarte zeigt 963,67 € inkl. Versand (924,14 € Teile + 39,53 €); Reviewer hat dieselben Summen aus `shop.json` nachgerechnet | Angebote beobachtet am 2026-10-30; nichts bestellt | | Download des Druckpakets | Druckpaket-Seite, kompletter Roboter, ZIP von der Seite abgefangen | Q2 | `strido-print-package-1-robot.zip`, 49 Dateien (README, Profil, 34 STLs mit Stückzahl im Namen, 13 Druckplatten), `unzip -t` fehlerfrei; Teileblatt 67 Stück, 719 g Graphit, 301 g Lime, 104 h 16 min | ZIP im Browser erzeugt, gespeichert (unkomprimiert) | | Produktinformationen vollständig | `make bom`, `pytest tests/workspace/test_products.py` | Q0 | 59 Stücklistenzeilen und 34 Druckteile abgedeckt, jeder Lernen-Link löst auf; der Test zeigt auch, dass ein entferntes Teil und ein toter Wiki-Link gemeldet werden | Formulierungen geprüft, Datenblattwerte teils aus dem Gedächtnis (im Review markiert) | | Seitenbuild und Links | `make docs-build` | Q0 | baut; Prüfung toter Links schlägt weiterhin bei einer fehlenden öffentlichen Datei (`/viewer/missing.glb`) und einem Verzeichnislink (`/viewer/`) fehl und akzeptiert vorhandene STL/GLB/INI/Log-Dateien | nur interne Links werden geprüft | | Seitenaudit | verwaltetes Chrome, alle Seiten der Seitenleiste bei 1440×900 und 390×844, hell und dunkel | Q2 | 0 defekte Bilder, 0 fehlerhafte interne Links, 0 Konsolenfehler, kein horizontaler Überlauf auf Smartphones; 35 Befunde (3 defekt, 18 verwirrend) behoben, auf der neu gebauten Seite erneut geprüft | visuelle Prüfung, keine automatisierte Barrierefreiheitssuite | | Ausweichlösung Schraubensicherung korrigiert | `python -m strido_verify.fits` | Q1 | 223 Schrauben ok 86 / warn 137 / fail 0, Sitze 32 / fail 0 (unverändert); Maßnahmen für schwache Vorbohrungen und ADR-009 nennen jetzt eine mit Sekundenkleber gehärtete Vorbohrung | nur Textänderung | | **Neu:** Festigkeit von Beinen und Gelenken | `python -m strido_verify.strength` | Q1 | 19 Prüfungen: 18 ok, 1 warn, 0 fail. Knicken der langen Koppel in der Beinebene S = 0,34 in der ungünstigsten Pose mit Knieservo im Blockierzustand (bekannte Schwachstelle, ADR-010, begrenzt durch `min_safety` 0.3); Biegung Femur S = 3,2, Tibia S = 2,2, Lochleibung am Hüft-Servohorn S = 2,6; Drehmomentgrenzen für Vorbohrungen 0,05–0,35 N·m; Reviewer hat Femur-Biegung, Knicken und ein Vorbohrungs-Drehmoment von Hand nachgerechnet und in der ersten Version vertauschte Koppelachsen gefunden (behoben: Bolzenachse aus den Bohrungen); Querschnittsberechnung per Unit-Test gegen b·h³/12 geprüft (Mutation, die die Lochausrichtung beibehält, schlägt fehl: Fläche 104 statt 56 mm²) | statisch, nur Wandquerschnitte, Blockiermoment des Servos als Auslegungslast (Rücktreiben braucht mehr), angenommene Landung mit 3 × Gewicht, K = 0,7 quer zur Ebene; keine Ermüdung/Kriechen; kein physischer Test | | Datenblattprüfung von Abweichungen und Produktspezifikationen | Recherche-Agent gegen Herstellerquellen (Hobbywing, Gens ace, Raspberry Pi, Seeed, NXP, ST, TI, Slamtec, SKF, Koyo, Prusament, Bossard) | statisch | UBEC 15 A Spitze bestätigt (20 A war das Flugzeugmodell); LiPo 60C; alle gelisteten Produktspezifikationen ok; Filamentangebote waren PLA (jetzt PETG); Kühler „JST“ unbestätigt (entfernt) | Lagerkennwerte von Markenteilen als Obergrenze für No-Name-Teile verwendet | | Amazon-Warenkorb mit einem Klick | angemeldetes Chrome, `gp/aws/cart/add.html` mit einer ASIN (kein Klick auf der Seite) | Q2 | leitet über `associates/addtocart` auf einen leeren Warenkorb um: Das Formular benötigt ein Associates-Tag; ersetzt durch die geführte Kasse (window.open in einem Tab pro Shop, Checkliste gespeichert) | Amazon-Richtlinien können sich ändern | | Pläne nach den PETG-Angeboten | `make bom` | Q0 | A 965,27 € (8 Shops), B 1.107,41 € (4), C 1.130,26 € (9), D 974,24 € (8) | Preise beobachtet am 2026-10-30/31 | | LaTeX-Rendering des Wikis und des Festigkeitsberichts | `make docs-build`, gebautes HTML durchsucht, verwaltetes Chrome bei 1440 px und 390 px | Q0/Q2 | 0 MathJax-Fehlerknoten, 0 nicht gerenderte `$…$`-Paare in den gebauten Seiten (15 einzeilige `
`-Antworten mussten zum Rendern aufgeteilt werden); Theorieseiten mit je 73–121 Gleichungen; kein horizontaler Seitenüberlauf bei 390 px (abgesetzte Gleichungen scrollen innerhalb der Spalte) | visuelle Stichproben auf 4 Seiten, nicht jede Gleichung | ## 2026-10-31 — Überarbeitung v0.2.0 (Harness, Pakete, neue Prüfungen, Korrekturen) {#_2026-10-31-v0-2-0-rework-harness-packages-new-gates-fixes} | Prüfung | Befehl | Stufe | Beobachtetes Ergebnis | Grenze | |---|---|---|---|---| | Lint, strikte Typen (Core, NT-X, Workspace), Import-Schichten | `make lint typecheck layers` | Q0 | ruff sauber; mypy: keine Probleme in 21 Dateien; 3 import-linter-Verträge eingehalten | CAD/Verify/Publish-Pakete werden gelintet, aber nicht strikt typisiert | | Generierte Quellen synchron | `make drift` | Q0 | Geometrie-Bindings, Elektronikbericht und NT-X-Assets aktuell; rot gesehen, als `geometry.py` umformatiert wurde und als sich Grenzen änderten | Text-Assets byteweise verglichen; NT-X-Meshes nur auf Vorhandensein | | Python-Tests mit Coverage-Schwelle (80 %) | `make test` | Q0 | 73 bestanden, Coverage 83,7 % | Module, die in NT-X / über stdio laufen, sind von der Coverage ausgenommen und durch die Smoke-Tests abgedeckt | | Elektronik: Firmware-Header vs. `hardware/electronics.yaml` in beide Richtungen, eindeutige GPIO/I²C, Servokanäle, Lasten ≤ Sicherungen ≤ Strombelastbarkeit der Leitungen | `python -m strido_verify.electronics` | Q0 | 44/44 Prüfungen bestanden; Tests zeigen, dass ein vertauschter Pin, ein in der YAML fehlender Header-Pin, ein doppelter Kanal, eine Adresskollision, eine unterdimensionierte Leitung und eine UBEC-Überlast alle fehlschlagen | Ströme sind Datenblatt-/[ESTIMATE]-Werte, nicht gemessen | | Firmware-Kern (Kinematik mit neuen Grenzen, Protokoll, Sicherheit) | `make test-firmware` | Q0 | 15/15 bestanden | nativer Host-Build, nicht der ESP32 | | Durchdringung, 479 Körper, 4 Posen | `make verify` | Q1 | 0 ungeklärte Überlappungen (292 klassifizierte Überlappungen im Stand) | Mesh-Geometrie, Nennmaße | | **Neu:** Passungen und Toleranzen jeder Schraube (223) und jedes Lager-/Buchsensitzes (32) | `python -m strido_verify.fits` | Q1 | 0 fail, 137 mit einer Maßnahme für den Erbauer (enges Loch an einer Mutterverbindung aufbohren, mit Sekundenkleber gehärtete Vorbohrung / Lochkompensation bei schwacher Vorbohrung), 86 ok; 29 der Warnungen sind die akzeptierten Vorbohrungen der Upstream-Servohalterungen (ADR-009: ohne die Akzeptanz fail). Rot gesehen mit 168 → 0 Fehlern beim Korrigieren des Modells und dreier echter Defekte (unten); Einschraubtiefe zählt nur Material, das die Schraube schneidet; ein Lager ohne Sitz schlägt fehl | CAD-Maße mit einem FDM-Schwindungsmodell von 0,15 mm; reale Drucke variieren je nach Drucker | | **Neu:** Freigang bewegter Teile, 13 Betriebsposen | `python -m strido_verify.clearance` | Q1 | 0 fail (< 0,3 mm), 4 knapp (0,73–0,79 mm an der äußeren Hüftgrenze), 80 rotatorische Schnittstellen, 72 Gelenkschnittstellen (nur über echte Gelenke/Koppelbolzen); rot gesehen: beide Vorderfüße kollidierten in `hips_in` (50 fails) vor der Korrektur der Grenze; die Einschränkung der Ausnahme deckte das Paar RR-Schulter / Rückschale auf (0,73 mm, zuvor ausgenommen, weil es sich in der CAD-Pose berührte) | Nenngeometrie; Servospiel nicht modelliert | | Bewegungsbereich mit gespiegeltem Partnerbein und 0,3 mm Abstand | `python -m strido_verify.rom` | Q1 | Hüftgrenzen jetzt FL/RL −17,5…50/45°, FR/RR −50/−45…17,5° (Einwärtsweg von 25–30° reduziert, damit sich die Füße nicht treffen können) | Raster 5°/2,5° | | Sensor-Sichtfeld | `python -m strido_verify.sensor_fov` | Q1 | 0 von 720 LiDAR-Strahlen blockiert, Kamera sieht 0 % Roboter, 5 Posen | — | | **Neu:** Druckpaket vollständig und druckbar | `pytest tests/verify/test_print_kit.py` | Q1 | 34 Teiletypen / 67 Stück, jede STL eine geschlossene Mannigfaltigkeit innerhalb 220 × 220 × 250 mm, jedes Stück auf genau einer 3MF-Druckplatte; rot gesehen: Kamerabasis und Neigeplatte fehlten auf den Druckplatten (trimesh verwirft 3MF-Knoten namens `camera*`) | Slicer-Einstellungen nicht simuliert | | Stückliste deckt jedes CAD-Teil und Befestigungselement ab | `make bom` | Q1 | alle Strategien abgedeckt; niedrigste Summe 963,67 € (8 Shops) | Preise beobachtet am 2026-10-30 | | MuJoCo-Gang | `make sim-walk` | Q2 | 0,15 m/s für 10 s → 1,104 m, Höhe 0,174 m, Gieren −1,7° | Kurshaltung über den Simulator | | Gazebo Harmonic Gang ohne GUI, Gait-Node (ROS 2 Jazzy, Docker, arm64) | `make sim-gazebo` | Q2 | 8 s bei 0,15 m/s → 0,98 m vorwärts, seitlich −0,003 m, Höhe 0,178 m, Rollen/Nicken < 0,01 rad; joint_states, IMU, Scan (min. 0,49 m), Kamera und Odom veröffentlichen alle | nur Simulator; derselbe Container wie das Roboter-Image ohne den Pi-Kamera-Stack | | Veröffentlichte PPO-Policy mit den neuen Grenzen | `make rl-eval` | Q2 | Befehl 0,2 m/s → 0,215 m/s Mittel, 2,15 m in 10 s, aufrecht | nur MuJoCo | | PPO-Pipeline | `make rl-smoke` | Q2 | 20 k Schritte in 6 s, Policy exportiert und evaluiert (nicht auf Gehen trainiert) | nur Pipeline-Prüfung | | **Neu:** Hardware-MCP-Server über stdio | `make mcp-smoke` | Q2 | 10 Tools gelistet, 9/9 Aufrufe ok | `measure_gap` durch die CAD-Tests abgedeckt, nicht durch den Smoke-Test | | **Neu:** NT-X-Integration in der NT-X-Harness-Umgebung | `make ntx-smoke` | Q2 | Katalogroboter (12 Gelenke, 3,008 kg) und Skill laden; steht 2 s in NT-X MuJoCo (Basis 0,178 m, Neigung 0,0°); Adapter `strido-serial` registriert; RobotPort ↔ Fake-MCU auf Protokollebene: die echte Laufzeitausgabe von `pd-pose` (Verstärkungen + Schwerkraft-Vorsteuerung bis 0,06 N·m) → Positionsziel → Zustand mit zurückgemeldeter Befehlssequenz, IMU-Ausfall löst den Schutzstopp aus und hält ihn, Schutzstopp rastet ein, Schließen gibt das Gerät frei; rot gesehen, als der Modellpfad falsch war | Fake-MCU spricht das echte Protokoll, ist aber nicht die Firmware; Hardware-Sitzungen brauchen außerdem eine Basisschätzung (NT-X-Odometrieprüfung) | | **Neu:** CAD-Regressionstests für die behobenen Passungsdefekte | `make test-cad` | Q1 | 3 bestanden (keine Schraubenpassung schlägt fehl; alle 4 Hüftdrehpunkt-Schrauben greifen in eine Servohalterung inkl. der Varianten `_fl`/`_fr`; Schrauben des LiDAR-Sockels greifen in den Sockel); rot gesehen mit der alten Vorbohrtiefe von 6 mm am Sockel (2 fehlgeschlagen: `solid`/`fail`) | dasselbe CAD-Maßmodell wie die Passungsprüfung | | **Neu:** Dokumentationsseite und 3D-Ansicht | `make docs-build`, Vorschau in Chrome | Q2 | Seite baut; 3D-Ansicht lädt das GLB, Explosion / Schritt / Schalen / Befestigungselemente / Auswahl funktionieren (ausgewähltes Teil zeigt Name, ID, Anzahl, Schritt); Teilekatalog zeigt 76 Teiletypen; defekt gesehen: jedes einzigartige Mesh wurde zusätzlich am GLB-Ursprung in Millimetern exportiert (ein 100 m großer „Keil“ um den Roboter), bis die Geometrie ohne eigenen Knoten gespeichert wurde | nur Desktop-Chrome; keine Mobil-/Safari-Prüfung | | Harness-Prüfungen (Drift der Agent-Konfiguration, Env-Doku, Arch-Scan, Secrets, npm audit) | `make harness-check` | Q0 | bestanden; gitleaks keine Lecks; npm audit 0 Schwachstellen; drei CAD-Definitionsmodule aus v0.1 im nur schrumpfenden Arch-Scan-Register als Baseline erfasst | Semgrep/Trivy übersprungen (aufwendige Sicherheitsprüfung aus) | | **Neu:** Druckbarkeit: jedes Teil von einem echten Slicer geslict | `make printability` (PrusaSlicer 2.9.6, `hardware/print/prusaslicer.ini`) | Q1 | 34 Teiletypen und 13 Druckplatten: 0 fail. Jedes Teil wie vorgeschrieben geslict (Stützstrukturen/Brim) ohne Fehlermeldung und mit vollständigem G-Code; gestützte Teile zusätzlich ohne Stützstrukturen geslict und zeigen nur Probleme, die Stützstrukturen beheben; jede Druckplatte druckt alle ihre Teile ohne Werkzeugpfadkonflikte. Druckpaket 1021 g PETG (719 g Graphit, 301 g Lime: je eine 1-kg-Spule), 104 h. Wandstärkenscan 0 fail, 5 warn (Upstream-Femur und Servohalterungen: Wände 0,65–0,8 mm, druckbar, aber dünn). Rot gesehen: Elektronikdeck ohne Stützstrukturen (schwebende Brückenanker unter der IMU-Tasche); Tibias/kurze Koppeln/Hüftbolzen in veröffentlichter Ausrichtung (geringe Betthaftung, gefunden, sobald gestützte Teile den zusätzlichen ungestützten Slice erhielten); Druckplatten mit 4 mm Teileabstand (Werkzeugpfadkonflikte); Deck mit aus der Druckliste entfernten Stützstrukturen (Unit-Test des Parsers und ein Prüflauf) | Slicer-Simulation, kein Testdruck; dünne Bereiche kürzer als 5 mm und schmaler als 1 mm zählen als Spitzen | | **Neu:** Spannungsdomänen der Elektronik | `python -m strido_verify.electronics` | Q0 | 16 Versorgungs-/Signalprüfungen bestanden: keine Schiene kann ein zulässiges Maximum überschreiten, jeder Nennpegel liegt im Bereich; 3 bestehen ohne Reserve, weil das Schienenminimum unter die Nennwerte reicht (Servo-PWM und LCD bei 3,3 V, dem niedrigsten Pegel, den sie akzeptieren); rot gesehen: Servoschiene bei der 7,4-V-Einstellung des UBEC und ein 6,3-V-UBEC (Tests) | Nennwerte aus Herstellerseiten/Datenblättern; Schienentoleranzen teils [ESTIMATE]; es gibt keine eigene Leiterplatte, daher gilt kein ERC/DRC/SPICE | | **Neu:** Dokumentationsseite auf Cortex | `docker compose -f docker-compose.docs.yml up --build docs`; `cortex deploy --ref b0fe000` (Job `mvvsdmmc-108830e0`) | Q2 | lokaler Container: /healthz ok, /docs/downloads 200, Baupaket 17,5 MB `application/zip` (57 Dateien, `unzip -t` fehlerfrei), PDF 13,9 MB; deployt 0.2.1: `cortex apps show strido` gesund („SSO route HTTP 302, upstream HTTP 200“); nicht authentifizierte Anfragen an /, /docs/downloads, das ZIP, das PDF und /healthz leiten alle (302) zum Cortex-SSO-Login um; angemeldet (Chrome): Startseite wird gerendert, ZIP/PDF/GLB-Downloads antworten 200 mit dem richtigen Typ | eine Browsersitzung; kein Lasttest | ### Gefundene und behobene Defekte (Prüfungen und Review) {#defects-found-and-fixed-gates-and-review} | Defekt | Gefunden durch | Behebung | |---|---|---| | Vorbohrungen des LiDAR-Sockels 9 mm tief für Schrauben, die 10 mm herausragen: Die Schrauben laufen auf Grund, bevor sie die Schale klemmen | Passungen (`solid` an der Spitze) | Vorbohrtiefe 11 mm (`PEDESTAL_PILOT_DEPTH`) | | Vordere Servohalterungen (dieselbe STL wie hinten) haben keine Hüftdrehpunkt-Vorbohrung auf der Seite, die die Vorderbeine nutzen: 5,5 mm massiver Kunststoff | Passungen (`solid`) | Strido-Varianten `left_servo_mount_fl`, `right_servo_mount_fr` mit einer Ø2,5-mm-Vorbohrung (ADR-004) | | Servohorn-Schrauben des rechten Femurs 3,7 mm neben den Löchern des gedruckten Femurs (STEP spiegelt die rechten Femurs; eine STL druckt alle vier) | Passungen (`solid`) | `hardware/assembly/corrections.yaml`: Scheibenhorn −30°, Femur-Verbinder +22° an FR/RR | | Mittelschrauben des Oberschenkel-Servohorns am linken Bein zeigten vom Servo weg (Kopf im Verzahnungshohlraum platziert) | Passungen (`nothing holds the screw`) | Kopfsenkung = längste stirnseitig offene Bohrung in `strido_cad.fasteners` | | Beide Vorderfüße (und beide Hinterfüße) konnten sich an den inneren Hüftgrenzen unter dem Körper treffen | Freigang (`hips_in`) | Bewegungsbereich-Durchlauf mit gespiegeltem Partnerbein und 0,3 mm Abstand (ADR-005) | | Kamerabasis und Neigeplatte fehlten auf den 3MF-Druckplatten von v0.1.0 | Druckpaket-Test | Knotennamen der Druckplatten mit Präfix `part_` | | Hüft-Scheibenhörner des rechten Beins durch die Femur-Korrektur verschoben (falscher Körper) | Bewegungsbereich (äußere RR-Grenze auf 20° eingebrochen) | Korrekturen gelten pro Starrkörper | | Der serielle NT-X-Port lehnte jeden Befehl des mitgelieferten `pd-pose`-Skills ab (Schwerkraft-Vorsteuerung ist nie null) und meldete bei IMU-Ausfall einen ebenen, ruhenden Roboter | Review; `make ntx-smoke` verwendet jetzt die echte Laufzeitausgabe | Vorsteuerung entfernt, `kp <= 0` abgelehnt, IMU-Ausfall führt in den sicheren Zustand, veraltete Frames verworfen | | CAD-Cache lieferte nach einem Revert Meshes einer älteren Quelle aus (Manifest pro Digest, Meshes an festen Pfaden) | `make check` schlug fehl, nachdem ein absichtlicher Prüfungsbruch zurückgenommen wurde | ein Manifest, nur gültig für den Digest des letzten Builds; rot/grün gesehen durch Brechen und Wiederherstellen von `PEDESTAL_PILOT_DEPTH` | | Freigang-Ausnahme deckte jedes in der CAD-Pose berührende Paar ab, nicht nur Gelenke | Review | Ausnahme auf Körper beschränkt, die durch ein Gelenk oder einen Koppelbolzen verbunden sind; deckte ein knappes Paar auf (0,73 mm) | | Elektronikdeck ohne Stützstrukturen gedruckt: Der Boden der IMU-Tasche ist eine 18-mm-Brücke mit schwebenden Ankern | Druckbarkeit (Slicer) | Deck als `supports=True` deklariert | | Tibias (135 mm aufrecht), kurze Koppeln und Hüftlagerbolzen haben in der veröffentlichten Ausrichtung zu wenig Bettkontakt | Druckbarkeit (ungestützter Analyse-Slice) | im Druckpaket flach umorientiert; Tibias 1,5 h statt 2,5 h | | 3MF-Druckplatten mit 4 mm Abstand gepackt: Benachbarte gestützte Teile erzeugten widersprüchliche Werkzeugpfade | Druckbarkeit (Slicer) | 10 mm Abstand, eng anliegende Stützstrukturen, First-Fit-Packung (13 Druckplatten) | | Ecken des XT60-Fensters ließen 0,26 mm dünne Stege im Blendendom; im FDM-Druck verrundete Innenecken würden die eckige XT60-Haube klemmen | Dickenscan, Review | Dom auf einen oberen und einen unteren Bogen reduziert; 0,5 mm Dog-Bone-Eckfreistiche in Blende und Klemmring | | Eine 6,2-mm-Schraubendreherbohrung im 6 mm dicken Bushalter-Trennsteg ließ 0,1 mm dünne Stege | Dickenscan | Zugangsschlitz statt der Bohrung | | Abnahmefenster des UBEC (6,0 ± 0,1 V) ließ 6,1 V an einem für 6,0 V spezifizierten Servo zu | Spannungsdomänen-Prüfung | 5,8–6,0 V im Leerlauf akzeptieren | ## 2026-10-30 — v0.1.0 {#_2026-10-30-v0-1-0} Auszüge der Befehlsausgabe sind pro Zeile verlinkt (`docs/verification/logs/`); absichtliche Prüfungsbrüche stehen in [gates.txt](verification/logs/gates.txt). Befehle beziehen sich auf das Layout von v0.1.0 (`tools/…`). | Prüfung | Befehl | Stufe | Ergebnis | Log | |---|---|---|---|---| | Befestigungselemente aus den gemessenen Lochstapeln abgeleitet; platzierte Befestigungselemente müssen den Regelsummen entsprechen | `make verify` (`hole_stacks.py`, `fasteners.py`) | statisch | alle Stapel zugeordnet; Platzierungen = Regelanzahlen (Prüfung nachweislich rot durch Auftrennen der geteilten Tibia-Bolzenstapel) | [verify.txt](verification/logs/verify.txt) | | Durchdringung von 479 Körpern (gedruckt, gekauft, Befestigungselemente) im Stand 170 mm, Hocke 120 mm, hoch 210 mm und in der CAD-Pose | `interference_check.py` | statisch | **0 ungeklärte Überlappungen** in allen 4 Posen; jede verbleibende Überlappung ist klassifiziert (Gewindeeingriff, Sitzkontakt, Gelenk, Upstream-Passung, Upstream-Befestigungselement auf seiner gemessenen Lochachse) – [interference.md](verification/interference.md) | verify.txt | | LiDAR-Verdeckung (720 Strahlen) und Kamera-Eigensicht, 5 Posen inkl. Trot und voller Hüftabduktion | `sensor_fov.py` | statisch | 0 Strahlen blockiert; Roboter in 0,0 % des Kamerabilds – [sensors.md](verification/sensors.md) | verify.txt | | Bewegungsbereich: Raster Oberschenkel × Unterschenkel (5°) bei null Abduktion, Übertragungswinkel ≥ 25°; Hüftbereich im Stand und in mittlerer Pose | `rom_sweep.py` | statisch | Grenzen wie in `hardware/joint_limits.yaml` eingecheckt (kein Diff nach dem Lauf) | verify.txt | | Generierte Geometrie in Firmware/Python entspricht der YAML | `codegen.py --check` | statisch | keine Abweichung | verify.txt, [test.txt](verification/logs/test.txt) | | Druckbarkeit: geschlossene Mannigfaltigkeit, passt in 220 × 220 × 250 mm, liegt auf dem Bett | `make print` | statisch | 32 Teiletypen / 67 Stück bestanden | [docs.txt](verification/logs/docs.txt) | | Stückliste liefert jedes gekaufte Teil und Befestigungselement des CAD für die Angebote, die jede Strategie kauft (Packungen aufgerundet, Befestigungselemente + max(2, 10 %) Reserve) | `make bom` | statisch | alles abgedeckt in allen 4 Strategien; Prüfung nachweislich rot durch Entfernen des M3 × 10-Vorrats | docs.txt | | Python-Kern: Protokoll (CRC-Vektor gemeinsam mit der Firmware, COBS, Beschädigung, Resynchronisation), IK/FK, Inverse des Kniekoppelgetriebes, Gait-Grenzen inkl. der Kniekurbel-Begrenzung, CLI-Kalibrierung und die Weigerung der CLI, wenn der Controller die Servos entspannt hält (Fake-Controller an einem Pseudoterminal) | `pytest` | Unit | 27 bestanden; der Kurbelgrenzen-Test schlägt fehl, wenn die Begrenzung entfernt wird | test.txt, gates.txt | | Firmware-Kern: Kinematik, Protokoll, Watchdog, Not-Aus, entprellte Akku-Abschaltung, kein Ansteuern ohne Power-Monitor (Kalibrierung am Prüfstand erlaubt), NaN-Ablehnung | `pio test -e native` | Unit | 15/15 bestanden; der NaN-Test schlägt mit der alten Begrenzung fehl | test.txt, gates.txt | | Firmware-Build für den XIAO ESP32-S3 | `pio run -e xiao_esp32s3` | Build | erfolgreich, RAM 8,0 %, Flash 16,0 % | [firmware.txt](verification/logs/firmware.txt) | | `mcu_bridge` (ROS-2-Jazzy-Container) gegen einen Fake-Controller an einem rohen Pseudoterminal | Wegwerfskript | Integration | STATE → `/joint_states` (Go2-Namen) und `/battery_state` (7,7 V, −1,2 A); Befehl → JOINT_COMMAND; NaN-Befehl verworfen; relax → JOINT_COMMAND(relax); Not-Aus → ESTOP; kein Frame verloren | [mcu_bridge_fake.txt](verification/logs/mcu_bridge_fake.txt) | | MuJoCo, Produktions-Gait (Kurshaltung nutzt den Gierwinkel des Simulators) | `make sim-walk` | Simulation | 0,15 m/s: 1,10 m in 10 s, Höhe 0,174 m, Gieren −1,7°; Drehung 0,6 rad/s: 197,9° in 6 s (−162,1° umgebrochen) | [mujoco_walk.txt](verification/logs/mujoco_walk.txt) | | Gazebo Harmonic Gang ohne GUI, Gait-Node (ROS 2 Jazzy, Docker, arm64) | `make sim-gazebo` | Simulation | 1,00 m in 8 s bei 0,15 m/s, seitlich 0,12 m, Rollen/Nicken < 0,1 rad, alle Sensor-Topics veröffentlichen | [gazebo.txt](verification/logs/gazebo.txt) | | PPO-Policy, 20 M Schritte (1734 s, CPU), Anstiegsbegrenzung der Firmware modelliert | `make rl-train`, `evaluate.py` | Simulation | MuJoCo, 10 s pro Befehl: vx 0,2 → 0,210 m/s (Gieren 2°), 0,15 → 0,152 m/s, 0 → steht, −0,1 → −0,068 m/s, vy 0,1 → 0,023 m/s (schwach), wz 0,5 → 232° in 10 s (−128,4° umgebrochen) | [rl_eval.txt](verification/logs/rl_eval.txt) | | Dieselbe Policy in Gazebo über `policy_node` (Sim-to-Sim) | `make sim-gazebo POLICY=build/rl/ppo-v1/policy.npz` | Simulation | 0,82 m in 8 s bei 0,15 m/s, seitlich 0,10 m, aufrecht | gazebo.txt | | Abruf der Hersteller-CAD | `make vendor-cad` | — | 8 von 9 Downloads per SHA-256 verifiziert; die Littelfuse-Datei liegt hinter einem Formular (manueller Download, Hüllkörper als Ersatz) | gates.txt | ## Nicht verifiziert {#not-verified} * Nichts wurde gedruckt, montiert, verkabelt oder eingeschaltet. Passungen sind gegen CAD und Datenblätter geprüft, nicht gegen gedruckte Teile (rechnen Sie damit, Loch- und Lagerpassungen an Ihren Drucker anpassen zu müssen). * Servostrom, Laufzeit und thermisches Verhalten sind Schätzungen ([Elektronik](electronics.md)). Der Wert des OE-Pull-ups setzt voraus, dass der Pull-down der PCA9685-Platine ≥ 10 kΩ ist (messen Sie OE während des Resets wie beschrieben). * Datenblatt-Hüllkörper (keine Hersteller-CAD): Servos (Upstream-STEP-Modell), WAGO 221-415, LiPo, UBEC, Taster, LiDAR-USB-Adapter (Größe unbestätigt). * Upstream-Gelenkbefestigungselemente werden aus Lochstapeln mit ungefährer Kopfseite und Mutterausrichtung platziert; sie sind Teil der statischen Durchdringungsprüfung, aber nicht des Bewegungsbereich-Durchlaufs. * Das Knie ist in Gazebo/MuJoCo ein Drehgelenk; Nachgiebigkeit und Spiel des Koppelgetriebes werden nicht simuliert. Die gelernte Policy hat keine echte Servodynamik gesehen. * Der Kamera-Node auf dem Pi 5 benötigt den libcamera-Fork von Raspberry Pi (nicht im Docker-Image); `robot.launch.py` wurde nicht auf einem Pi ausgeführt. --- # 3D-Ansicht {#_3d-viewer} Die verifizierte CAD-Baugruppe in 170 mm Standhöhe (Meshes für das Web vereinfacht). Ziehen zum Drehen, Scrollen zum Zoomen, Klick auf ein Teil, um es zu identifizieren. * **Explosion** zieht alle Teile vom Körpermittelpunkt weg. * **Schritt** spielt die [Montageanleitung](assembly/README.md) nach: Die Teile erscheinen in der Reihenfolge, in der Sie sie montieren, und der aktuelle Schritt leuchtet orange. * **Schalen / Verbindungselemente** blendet die Schalen aus, um hineinzusehen, oder die Schrauben, um die Teile zu sehen. * Klicken Sie auf ein Teil, um es zu identifizieren: Name, Teile-ID, Anzahl am Roboter und der Schritt, in dem es montiert wird. [Modell herunterladen (GLB)](viewer/strido.glb): Es lässt sich in jedem glTF-Viewer, in Blender oder in der Asset-Ansicht von NT-X Studio öffnen. --- # Glossar {#glossary} Begriffe, die auf der Strido-Seite und in diesem Wiki verwendet werden, von A–Z. Jeder Eintrag erklärt, was der Begriff bedeutet und, wo es darauf ankommt, wie er auf diesen Roboter zutrifft; folgen Sie dem Link zur Wiki-Seite, die ihn ausführlich erklärt. ## A {#a} ### Abduktion {#abduction} Seitliches Schwenken eines Beins von der Körpermittellinie weg oder zu ihr hin. Bei Strido ist das das Hüftgelenk, angetrieben vom Servo im Körper; siehe [Kinematik und Gaits](software/kinematics-and-gaits.md). ### Akzeptierte Abweichung {#accepted-deviation} Eine Bohrung, die ein Verifikationsband verfehlt, aber bewusst beibehalten wird, festgehalten in `accepted_deviations` von `hardware/verification/tolerances.yaml` mit einem ADR und einer Maßnahme für Bauende. Die einzige ist ADR-009, die M3-Vorbohrungen der Servohalterungen; siehe [Befestigungselemente](making/fasteners.md). ### ADR (Architekturentscheidung) {#adr-architecture-decision-record} Eine kurze Aufzeichnung einer Konstruktionsentscheidung: Kontext, Optionen, Entscheidung, Konsequenzen und wann sie neu zu bewerten ist. Strido führt sie in [decisions.md](../decisions.md). ### Arachne {#arachne} Der Perimeter-Generator mit variabler Breite von PrusaSlicer, im Profil des Bausatzes aktiviert, der dünne Wände füllt, statt Lücken zu lassen; siehe [3D-Druck](making/3d-printing.md). ### Arming-Port {#arming-port} Die XT60H-Buchse in der Rückschale (`arming_port_bezel`): W02 von der Hauptsicherung an einem Kontakt, W03 zu den UBECs am anderen. Sie verbindet den Servo-Versorgungszweig nur, wenn der Loop-Key eingesteckt ist; siehe [Sicherheit](making/safety.md). ### AWG (American Wire Gauge) {#awg-american-wire-gauge} Skala für Drahtquerschnitte, bei der eine kleinere Zahl einen dickeren Draht bedeutet. Strido verwendet 14 AWG für die Akku-Hauptleitung, 18 AWG für UBEC-Ausgänge, Bus-Brücken und den Logikzweig, 22 AWG für Servokabel, Signale und die 5-V-Versorgung des Pi; siehe [Versorgung](hardware/power.md). ## B {#b} ### Balancer-Ladegerät {#balance-charger} Ein LiPo-Ladegerät, das jede Zelle über den Balancer-Anschluss des Akkupacks überwacht und ausgleicht. Die Stückliste enthält ein Ladegerät der B6AC-Klasse; siehe [Akkus](hardware/batteries.md). ### Betthaftung {#bed-adhesion} Wie fest die erste Schicht auf dem Druckbett haftet. Zu wenig, und das Teil löst sich; bei PETG auf glattem PEI kann zu viel die Platte beschädigen; siehe [3D-Druck](making/3d-printing.md). ### Lagersitz {#bearing-seat} Eine gedruckte Bohrung, in die ein Kugellager oder eine Gleitbuchse eingepresst wird. Die Passungsprüfung akzeptiert einen Sitz von 0,15 mm unter bis 0,30 mm über dem Außendurchmesser des Lagers; siehe [Mechanik](hardware/mechanics.md). ### BEC / UBEC {#bec-ubec} (Universal) Battery Eliminator Circuit: ein Schaltregler aus dem RC-Modellbau, der die Akkuspannung in Servospannung umwandelt. Strido verwendet zwei Hobbywing UBEC-10A mit 6,0 V, die jeweils zwei Beine versorgen; siehe [Versorgung](hardware/power.md). ### BOM (Stückliste) {#bom-bill-of-materials} Die Liste aller zu kaufenden Teile mit Mengen und Angeboten. Quelle: `hardware/bom.yaml`; veröffentlicht als [Stücklisten-Seite](../bom/README.md). ### Brim {#brim} Zusätzliche Linien um die erste Schicht eines Teils, die den Kontakt zum Bett vergrößern. Im Bausatz: 5 mm Brim bei Teilen, die höher als 40 mm sind; siehe [3D-Druck](making/3d-printing.md). ### Abwärtswandler (Step-down) {#buck-regulator-step-down} Ein Schaltwandler, der eine Spannung effizient absenkt. Der Pololu D36V50F5 erzeugt die 5-V-Logikschiene aus dem 2S-Akkupack; siehe [Versorgung](hardware/power.md). ### Bausatz {#build-kit} Das herunterladbare ZIP mit allem, was zum Drucken und Bauen eines Roboters nötig ist; siehe [Downloads](../downloads.md). ## C {#c} ### C-Rate {#c-rating} Der maximale Entladestrom eines LiPo als Vielfaches seiner Kapazität, $I = C \cdot Q / 1\,\mathrm{h}$ (z. B. $60 \times 5\,\mathrm{A} = 300\,\mathrm{A}$ Dauerstrom für den 5-Ah-Akkupack von Strido, 100C kurzzeitig). Siehe [Akkus](hardware/batteries.md). ### CadQuery {#cadquery} Eine Python-Bibliothek für parametrisches CAD. Alle neuen und geänderten Teile von Strido sind CadQuery-Boolesche Operationen auf der Upstream-Geometrie; siehe [CAD als Code](software/cad-as-code.md). ### Katalog {#catalogue} Die durchsuchbare Liste aller 76 Teiletypen (gedruckt, gekauft und Befestigungselemente) mit Bildern, Größen und Montageschritten; siehe den [Katalog](../catalog.md). ### Durchgangsbohrung {#clearance-hole} Eine Bohrung, durch die eine Schraube frei hindurchgeht. Die ISO-273-Größen für M3 sind 3,2 mm (fein) und 3,4 mm (mittel); gedruckte Bohrungen werden mit diesen Bohrern nachgebohrt; siehe [Befestigungselemente](making/fasteners.md). ### COBS {#cobs} Consistent Overhead Byte Stuffing: eine Codierung, die Null-Bytes aus einer Nachricht entfernt, sodass `0x00` das Ende jedes Rahmens markieren kann. Verwendet auf der USB-Verbindung zwischen dem Pi und dem XIAO; siehe [Firmware](software/firmware.md). ### CRC16 {#crc16} Eine 16-Bit-Prüfsumme, die an jeden Protokollrahmen angehängt wird (CRC16-CCITT-FALSE), damit beschädigte Rahmen verworfen werden; siehe [Firmware](software/firmware.md). ### CSI {#csi} Camera Serial Interface: der Flachbandkabel-Kameraanschluss am Raspberry Pi 5, genutzt vom Camera Module 3 Wide über ein 22→15-Pin-Kabel; siehe [Sensoren](hardware/sensors.md). ### Zuschnittliste {#cut-list} Die Tabelle in der [Verkabelungsprüfung](../verification/wiring.md), die für jeden Draht die verlegte Länge und die Zuschnittlänge angibt: verlegte Länge + ein Anschlusszuschlag pro Ende (WAGO abisolieren 11 mm, Löten 6 mm, Crimpen 3 mm, Schraubklemme 7 mm) + 8 % Reserve, mindestens 10 mm. Bauende schneiden jeden Draht danach zu; siehe [Kabelmanagement](making/cable-management.md). ## D {#d} ### Docker {#docker} Ein Werkzeug, das Software mit allen Abhängigkeiten in Containern ausführt. Das ROS-2-Jazzy-Image für den Pi und für Gazebo wird aus `docker/compose.yaml` gebaut; siehe [Docker](software/docker.md). ### Domain Randomisation {#domain-randomisation} Das Variieren von Simulationsparametern (Reibung, Servosteifigkeit, Masse, IMU-Rauschen) während des Trainings, damit eine gelernte Policy mit dem realen Roboter zurechtkommt; siehe [Simulation und RL](software/simulation-and-rl.md). ### Dupont-Steckverbinder {#dupont-connector} Ein Crimpkontakt mit Gehäuse im 2,54-mm-Raster, der auf Stiftleisten gesteckt wird und durch Reibung hält. Verwendet für die 5-V-Versorgung des Pi (W12), W17/W20 am PCA9685 und die zwölf Servo-Signalleitungen (neu in 1-polige Gehäuse gecrimpt); siehe [Werkzeuge und Werkstatt](making/tools-and-workshop.md). ## E {#e} ### Not-Aus (E-Stop) {#e-stop-emergency-stop} Ein verriegelnder Stopp. Bei Strido bringt `/strido/estop` die Firmware dazu, PCA9685 OE auf High zu ziehen und alle Pulse zu stoppen; die physische Servo-Abschaltung ist der Loop-Key. Siehe [Sicherheit](making/safety.md). ### Elefantenfuß {#elephant-foot} Die ausgestellte Unterkante eines Drucks, verursacht durch die gequetschte erste Schicht; sie verengt nach unten gerichtete Bohrungen; siehe [3D-Druck](making/3d-printing.md). ### Einschraublänge {#engagement-length} Die Länge einer Schraube, die tatsächlich Gewinde formt oder in Gewinde greift. Die Passungsprüfung verlangt mindestens 1,5 d in gedruckten Vorbohrungen (4,5 mm für M3); siehe [Befestigungselemente](making/fasteners.md). ### ESD (elektrostatische Entladung) {#esd-electrostatic-discharge} Ein statischer Funke, der Chips beschädigen kann. Fassen Sie Pi, XIAO und Sensorplatinen an den Kanten an, nachdem Sie geerdetes Metall berührt haben; siehe [Sicherheit](making/safety.md). ### ESP32-S3 {#esp32-s3} Der Dual-Core-Mikrocontroller von Espressif mit USB, verwendet auf dem Bewegungscontroller Seeed XIAO ESP32-S3; siehe [Mikrocontroller](hardware/microcontrollers.md). ## F {#f} ### FDM (Fused Deposition Modelling) {#fdm-fused-deposition-modelling} 3D-Druck durch Extrudieren von geschmolzenem Kunststoff Linie für Linie und Schicht für Schicht; siehe [3D-Druck](making/3d-printing.md). ### Femur {#femur} Das Oberschenkelglied eines Beins, zwischen dem Bein-Servomodul und dem Knie; vier werden gedruckt (`femur`). ### FFC (flexibles Flachbandkabel) {#ffc-flat-flexible-cable} Das flache Flachbandkabel, das die Kamera mit dem CSI-Anschluss des Pi verbindet (300 mm bei Strido). ### Firmware {#firmware} Das Programm, das auf dem Mikrocontroller läuft. Die Firmware von Strido (`firmware/strido_esp32s3`, PlatformIO) führt die 200-Hz-Regelschleife und die Sicherheitslogik aus; siehe [Firmware](software/firmware.md). ### Passungsprüfung {#fit-gate} Der Verifikationsschritt `python -m strido_verify.fits`, der jede Schraubenbohrung und jeden Lagersitz im CAD mit den Bändern in `tolerances.yaml` vergleicht; siehe [Befestigungselemente](making/fasteners.md). ### Viergelenkgetriebe {#four-bar-linkage} Vier Glieder, durch vier Drehgelenke zu einer Schleife verbunden. Das Knie von Strido verwendet ein Parallelogramm und ein Viergelenk, um die Tibia von der Kniekurbel aus anzutreiben; siehe [Mechanik](hardware/mechanics.md). ### Sicherung {#fuse} Ein Leiterstück, das oberhalb seines Nennstroms schmilzt und so die nachfolgende Leitung schützt. Strido verwendet eine 25-A-Haupt- und eine 7,5-A-Logik-ATO-Flachsicherung; siehe [Sicherheit](making/safety.md). ## G {#g} ### Gait {#gait} Das Muster, in dem sich die Beine bewegen. Standard bei Strido ist ein Trot (diagonale Beinpaare gemeinsam) in `packages/strido-core`; siehe [Kinematik und Gaits](software/kinematics-and-gaits.md). ### Prüfung (Gate) {#gate} Eine ausführbare Prüfung, die bestehen muss, bevor eine Änderung akzeptiert wird (Durchdringung, Bewegungsbereich, Passungen, Freigang, Druckbarkeit, Elektronik, Verkabelung, Stückliste). Siehe die Seite [Verifikation](../verification.md). ### Gazebo Harmonic {#gazebo-harmonic} Ein Robotersimulator, der den ROS-2-Stack unverändert gegen einen simulierten Strido ausführt; siehe [Simulation und RL](software/simulation-and-rl.md). ### Go2-Konvention {#go2-convention} Gelenknamen, Vorzeichen, Koordinatensysteme und Topics, übernommen von der ROS-2-Schnittstelle des Unitree Go2, sodass für einen Go2 geschriebener Code Strido steuern kann; siehe [ROS 2](software/ros2.md). ### Massesternpunkt {#ground-star} Der einzige Punkt, an dem alle Massen zusammenlaufen. Bei Strido ist das eine mit Schrumpfschlauch isolierte Spleißstelle neben dem Akkueingang, von der W04 zu beiden UBEC-Eingängen (14 AWG) und zur Schaltermasse (18 AWG) führt; ein einziger Punkt hält die Servo-Rückströme aus den Logikmassen heraus; siehe [Versorgung](hardware/power.md). ### Gyroid {#gyroid} Ein welliges, selbsttragendes Füllmuster, das in alle Richtungen fest ist; der Bausatz verwendet 30 % Gyroid; siehe [3D-Druck](making/3d-printing.md). ## H {#h} ### Schrumpfschlauch {#heat-shrink} Schlauch, der beim Erhitzen schrumpft, um eine Lötstelle zu isolieren und zugzuentlasten; siehe [Werkzeuge und Werkstatt](making/tools-and-workshop.md). ### High-Side-Shunt {#high-side-shunt} Ein Strommesswiderstand in der positiven Versorgungsleitung. Der INA260 misst den Logikzweig auf diese Weise (VIN+ hinein, VIN− hinaus); siehe [Sensoren](hardware/sensors.md). ### Lochkompensation {#hole-compensation} Eine Slicer-Einstellung, die gedruckte Bohrungen verkleinert oder vergrößert. Die Druckliste verlangt eine X-Y-Lochkompensation von −0,15 mm bei den Servohalterungen (ADR-009); siehe [3D-Druck](making/3d-printing.md). ### Servohorn {#horn} Der Arm oder die Scheibe, die auf die verzahnte Abtriebswelle eines Servos passt und dessen Drehmoment überträgt. Strido verwendet Aluminium-Scheiben- und Klemmarm-Servohörner mit 25 Zähnen (25T); siehe [Servos](hardware/servos.md). ## I {#i} ### I²C {#i2c} Ein Zweidrahtbus (SDA Daten, SCL Takt), bei dem jedes Gerät eine Adresse hat. Bei Strido: PCA9685 0x40, LSM6DSOX 0x6A, INA260 0x41 mit 400 kHz; siehe [Busse](hardware/buses.md). ### IMU (inertiale Messeinheit) {#imu-inertial-measurement-unit} Ein Sensor, der Beschleunigung und Drehrate misst. Der LSM6DSOX liefert dem Roboter seine Orientierung (Mahony-Filter auf dem XIAO); siehe [Sensoren](hardware/sensors.md). ### INA260 {#ina260} Der Strom-/Spannungs-/Power-Monitor von Texas Instruments mit integriertem Shunt (Adafruit 4226). Er meldet die Akkuspannung für die Unterspannungsabschaltung; ohne ihn steuert die Firmware nicht an; siehe [Sensoren](hardware/sensors.md). ### Füllung (Infill) {#infill} Die innere Füllung eines gedruckten Teils, angegeben als Dichte und Muster (Bausatz: 30 % Gyroid); siehe [3D-Druck](making/3d-printing.md). ### Durchdringungsprüfung {#interference-check} Die Prüfung, die das montierte CAD auf Teile untersucht, die sich räumlich überlappen; Bericht in [verification/interference.md](../verification/interference.md). ### ISO 4762 / DIN 912 {#iso-4762-din-912} Die Norm für Zylinderschrauben mit Innensechskant, die einzige Schraubenkopfform bei Strido; siehe [Befestigungselemente](making/fasteners.md). ## J {#j} ### Gelenkgrenzen {#joint-limits} Der sichere Bereich jedes Gelenks, ermittelt aus einem Kollisions-Sweep der gesamten Baugruppe (z. B. Unterschenkel −150…−45°), gemeinsam genutzt von Firmware, Gait und Simulation; siehe [Kinematik und Gaits](software/kinematics-and-gaits.md). ## K {#k} ### Kinematik {#kinematics} Die Geometrie, die Gelenkwinkel mit Fußpositionen (vorwärts) und Fußpositionen mit Gelenkwinkeln (invers) verknüpft; siehe [Kinematik und Gaits](software/kinematics-and-gaits.md). ### Kniekurbel {#knee-crank} Der Arm am Knieservo, der das Kniekoppelgetriebe antreibt; sein Winkel bildet sich nichtlinear auf den Unterschenkelwinkel ab; siehe [Mechanik](hardware/mechanics.md). ## L {#l} ### Schichthöhe {#layer-height} Die Dicke jeder gedruckten Schicht; 0,2 mm im Bausatz, die Hälfte der 0,4-mm-Düse; siehe [3D-Druck](making/3d-printing.md). ### LiDAR {#lidar} Ein Sensor, der Entfernungen mit einem rotierenden Laser misst. Der Slamtec RPLIDAR C1 veröffentlicht `/scan` mit 10 Hz vom oberen Sockel aus; siehe [Sensoren](hardware/sensors.md). ### LiPo (Lithium-Polymer) {#lipo-lithium-polymer} Die Akkuchemie des 2S-5000-mAh-Akkupacks des Roboters: hohe Leistung, aber gefährlich bei Kurzschluss, Überladung oder Tiefentladung; siehe [Akkus](hardware/batteries.md). ### Sicherungsmutter (DIN 985) {#lock-nut-din-985} Eine Mutter mit Nyloneinsatz, die das Gewinde klemmt, verwendet an beweglichen Gelenken, damit sie sich frei drehen können, ohne dass sich die Mutter löst; siehe [Befestigungselemente](making/fasteners.md). ### Loop-Key {#loop-key} Ein kurzgeschlossener XT60-Stecker, der den Servozweig scharf schaltet, wenn er in den Arming-Port gesteckt wird; Abziehen schaltet die Servos ab; siehe [Sicherheit](making/safety.md). ## M {#m} ### mAh (Milliamperestunde) {#mah-milliampere-hour} Akkukapazität: 5000 mAh können eine Stunde lang 5 A liefern. Bei 7,4 V Nennspannung speichert der Akku etwa 37 Wh; siehe [Akkus](hardware/batteries.md). ### Mahony-Filter {#mahony-filter} Ein schlanker Algorithmus, der Gyroskop- und Beschleunigungsdaten zu einer Orientierungsschätzung fusioniert; läuft auf dem XIAO für `/imu/data`; siehe [Sensoren](hardware/sensors.md). ### Manifold (geschlossen) {#manifold-closed} Ein Netz ohne Löcher oder lose Flächen, sodass es ein wohldefiniertes Inneres hat; jede STL des Bausatzes wird auf Geschlossenheit geprüft; siehe [CAD als Code](software/cad-as-code.md). ### Mikrocontroller (MCU) {#microcontroller-mcu} Ein kleiner Ein-Chip-Computer für Echtzeitaufgaben. Der XIAO ESP32-S3 ist die MCU von Strido; siehe [Mikrocontroller](hardware/microcontrollers.md). ### MJCF {#mjcf} Das XML-Modellformat von MuJoCo; `models/mujoco/strido.xml` wird aus dem CAD generiert; siehe [Simulation und RL](software/simulation-and-rl.md). ### MuJoCo {#mujoco} Ein schneller Physiksimulator, der für die Laufdemo und Reinforcement Learning verwendet wird; siehe [Simulation und RL](software/simulation-and-rl.md). ## N {#n} ### Nav2 {#nav2} Der ROS-2-Navigationsstack. Er kommuniziert über `/cmd_vel` und `/scan` mit dem Roboter und läuft daher unverändert auf Strido; siehe [ROS 2](software/ros2.md). ### NT-X {#nt-x} Die Robotikplattform, in die Strido über die Erweiterung `strido-ntx` integriert ist; siehe [NT-X-Integration](../ntx-integration.md). ### N·m und kg·cm {#n·m-and-kg·cm} Drehmomenteinheiten. Servohersteller geben kg·cm an; $1\,\mathrm{kg\,cm} = 9.81\,\mathrm{N} \times 0.01\,\mathrm{m} \approx 0.098\,\mathrm{N\,m}$, also $35\,\mathrm{kg\,cm} \approx 3.43\,\mathrm{N\,m}$; siehe [Servos](hardware/servos.md). ## O {#o} ### OE (Output Enable) {#oe-output-enable} Der PCA9685-Pin, der bei High alle 16 Ausgänge abschaltet. Der XIAO hält ihn High, bis scharf geschaltet wird, und ein 2,2-kΩ-Pull-up hält ihn während Resets High; siehe [Sicherheit](making/safety.md). ### Überhang {#overhang} Eine Fläche, die über leerem Raum gedruckt wird. Ab etwa 45° zur Senkrechten braucht sie meist Stützen; die Druckliste gibt den Überhanganteil jedes Teils an; siehe [3D-Druck](making/3d-printing.md). ## P {#p} ### PCA9685 {#pca9685} Ein 16-Kanal-PWM-Treiber mit 12 Bit an I²C. Er erzeugt die 12 Servosignale mit 200 Hz, führt aber keinen Servostrom; siehe [Busse](hardware/buses.md). ### Perimeter {#perimeter} Eine Umrisslinie einer gedruckten Schicht; der Bausatz druckt 3 Perimeter (≈ 1,2 mm Wand); siehe [3D-Druck](making/3d-printing.md). ### PETG {#petg} Polyethylenterephthalat-Glykol: ein zähes, hitzebeständiges Filament und das Material des Bausatzprofils; PLA+ ist die Alternative; siehe [3D-Druck](making/3d-printing.md). ### Vorbohrung {#pilot-hole} Eine Bohrung, kleiner als die Schraube, in die eine gewindeformende Schraube ihr Gewinde schneidet (etwa 0,8 d nach dem Druck); siehe [Befestigungselemente](making/fasteners.md). ### PlatformIO {#platformio} Das Build-System der Firmware: `pio run` zum Kompilieren und Hochladen, `pio test -e native` für Unit-Tests auf dem Host; siehe [Firmware](software/firmware.md). ### PLA+ {#pla} Eine zähere Variante von PLA-Filament, die die Druckliste als Alternative zu PETG zulässt; siehe [3D-Druck](making/3d-printing.md). ### Druckplatte {#plate} Eine fertig angeordnete Druckplatte von 220 × 220 mm (3MF-Datei); der Bausatz hat 10 Druckplatten in Graphit und 3 in Limette; siehe [3D-Druck](making/3d-printing.md). ### Policy {#policy} Ein gelernter Controller, der Observations (IMU, Kommando, vorherige Action, Gait-Takt) auf Gelenk-Actions abbildet; gespeichert als `policy.npz` und mit numpy ausgeführt; siehe [Simulation und RL](software/simulation-and-rl.md). ### PPO (Proximal Policy Optimization) {#ppo-proximal-policy-optimisation} Der Algorithmus für Reinforcement Learning, mit dem die Lauf-Policy von Strido in MuJoCo trainiert wird; siehe [Simulation und RL](software/simulation-and-rl.md). ### Druckpaket {#print-kit} Das Paket aus orientierten STLs, Slicer-Profil, Teileblatt und Druckplatten; stellen Sie eines auf der Seite [Druckpaket](../print-kit.md) zusammen. ### Druckbarkeitsprüfung {#printability-gate} Die Prüfung, die jedes Teil und jede Druckplatte mit PrusaSlicer slict und die Wandstärke scannt; Bericht in [verification/printability.md](../verification/printability.md); siehe [3D-Druck](making/3d-printing.md). ### Pull-up-Widerstand {#pull-up-resistor} Ein Widerstand, der ein Signal auf einem definierten High-Pegel hält, wenn nichts es treibt, wie die 2,2 kΩ an PCA9685 OE; siehe [Busse](hardware/buses.md). ### PWM (Pulsweitenmodulation) {#pwm-pulse-width-modulation} Ein Signal, dessen Pulslänge Information trägt. Hobby-Servos lesen die Position aus der Pulsbreite: 500–2500 µs für 180° beim SPT5435LV, wobei 1500 µs die Mitte ist; siehe [Servos](hardware/servos.md). ## R {#r} ### Bewegungsbereich (ROM) {#range-of-motion-rom} Wie weit sich jedes Gelenk ohne Kollisionen bewegen kann; der Bewegungsbereichs-Sweep liefert die Gelenkgrenzen; siehe [Kinematik und Gaits](software/kinematics-and-gaits.md). ### Raspberry Pi 5 {#raspberry-pi-5} Der Hauptrechner des Roboters (4 GB) mit Linux und ROS 2; siehe [Linux auf dem Pi](software/linux-on-the-pi.md). ### REP-103 {#rep-103} Die ROS-Konvention für Einheiten und Koordinatensysteme: x nach vorn, y nach links, z nach oben, SI-Einheiten; siehe [ROS 2](software/ros2.md). ### Reinforcement Learning (RL) {#reinforcement-learning-rl} Das Trainieren eines Controllers durch Versuch und Irrtum in der Simulation, wobei gutes Verhalten belohnt wird; siehe [Simulation und RL](software/simulation-and-rl.md). ### ROS 2 {#ros-2} Robot Operating System 2: eine Middleware, in der Nodes Messages über Topics austauschen. Strido verwendet ROS 2 Jazzy; siehe [ROS 2](software/ros2.md). ### ros2_control {#ros2-control} Das ROS-2-Framework für Controller und Hardware-Schnittstellen; in Gazebo verarbeitet es `/leg_controller/commands`; siehe [ROS 2](software/ros2.md). ## S {#s} ### Bewegungsschlaufe {#service-loop} Eine bewusst freie Kabellänge zwischen zwei Kabelbindern, mit der ein Kabel ein bewegliches Gelenk überqueren kann, ohne an seinen Anschlüssen zu ziehen. Die Servokabel von Oberschenkel und Knie bei Strido überqueren das Hüftgelenk mit Schlaufen von 36 mm und 40 mm, mindestens das 1,2-Fache des größten Abstands zwischen Kabelbindern über den Hüftbereich; siehe [Kabelmanagement](making/cable-management.md). ### Servo (Hobby-Servo) {#servo-hobby-servo} Motor, Getriebe, Positionssensor und Regler in einem Gehäuse, das den durch einen PWM-Puls vorgegebenen Winkel anfährt. Strido verwendet zwölf SPT5435LV-180W ohne Positionsrückmeldung an den Controller; siehe [Servos](hardware/servos.md). ### Anstiegsbegrenzung {#slew-limit} Die maximale Geschwindigkeit, mit der die Firmware einen kommandierten Gelenkwinkel sich ändern lässt (6 rad/s), um heftige Sprünge zu vermeiden; siehe [Firmware](software/firmware.md). ### Slicer {#slicer} Software, die ein 3D-Modell Schicht für Schicht in Druckeranweisungen (G-Code) umwandelt, z. B. PrusaSlicer; siehe [3D-Druck](making/3d-printing.md). ### SLAM {#slam} Simultane Lokalisierung und Kartierung: Aufbau einer Karte bei gleichzeitiger Verfolgung der Roboterposition darin, hier anhand von `/scan`; siehe [ROS 2](software/ros2.md). ### Smoke-Test {#smoke-test} Das erste Einschalten mit abgezogenem Loop-Key: Prüfen Sie Boot, `/battery_state`, `/diagnostics` und die OE-Spannung, bevor sich ein Servo bewegen kann; siehe [Sicherheit](making/safety.md). ### Handfest {#snug} Eine Schraube nur so weit anziehen, bis der Kopf aufliegt und sich die Teile nicht mehr bewegen – die Regel für Schrauben in gedruckten Teilen; siehe [Befestigungselemente](making/fasteners.md). ### SPI {#spi} Ein schneller synchroner Bus mit Takt-, Daten- und Chip-Select-Leitungen. Der XIAO steuert das ST7789-LCD über SPI an, mit einer zusätzlichen DC-Leitung (Data/Command); siehe [Busse](hardware/buses.md). ### Spiralschlauch {#spiral-wrap} Eine Kunststoffspirale, die um ein Kabelbündel gewickelt wird, es hält und schützt und dabei einzelne Kabel überall abzweigen lässt. Strido setzt ihn an jedem Bündel aus drei oder mehr Kabeln ein (`spiral_wrap`); siehe [Kabelmanagement](making/cable-management.md). ### Blockiermoment / Blockierstrom {#stall-torque-stall-current} Das Drehmoment, das ein Motor erzeugt, und der Strom, den er aufnimmt, wenn er blockiert ist. SPT5435LV: etwa 3,43 N·m und 3,5 A bei 6 V; siehe [Servos](hardware/servos.md). ### Abstandsbolzen {#stand-off} Ein Distanzstück mit Gewinde, das eine Platine vom Deck abhebt (M2.5 × 6 mm und M2 × 8 mm Messing, Innen-Innengewinde); siehe [Befestigungselemente](making/fasteners.md). ### STEMMA QT {#stemma-qt} Das 4-polige JST-SH-I²C-Steckverbindersystem von Adafruit. Zwei Kabel STEMMA QT → Buchse verbinden die IMU mit dem PCA9685 (W18; die IMU sitzt zu dicht unter dem Pi für Dupont-Gehäuse) und mit dem INA260 (W19); siehe [Busse](hardware/buses.md). ### STEP, STL und 3MF {#step-stl-and-3mf} STEP: exakte CAD-Volumenkörper (die Upstream-Yertle-Baugruppe). STL: Dreiecksnetze für den Druck. 3MF: ein Paket aus Netzen plus Anordnung, verwendet für die Druckplatten; siehe [CAD als Code](software/cad-as-code.md). ### Zugentlastung {#strain-relief} Alles, was Zug und Biegung vom Anschluss eines Drahts fernhält: die Isolationskrimpung eines Crimpkontakts, Schrumpfschlauch über einer Lötstelle, ein Kabelbinder nahe an einem Steckverbinder. Am wichtigsten ist sie dort, wo Lot in die Litzen gezogen ist und sie steif gemacht hat; siehe [Kabelmanagement](making/cable-management.md). ### Stützstrukturen {#supports} Temporär gedruckte Strukturen unter Überhängen, die nach dem Druck entfernt werden; der Bausatz verwendet anliegende Stützen bei den aufgeführten Teilen; siehe [3D-Druck](making/3d-printing.md). ## T {#t} ### TF {#tf} Das ROS-2-Transformationssystem, das Koordinatensysteme verfolgt (`odom`, `base_link`, `imu_link`, `lidar_link`); siehe [ROS 2](software/ros2.md). ### Gewindeformende Schraube {#thread-forming-screw} Eine Schraube, die ihr eigenes Gewinde in eine glatte Vorbohrung schneidet oder formt. 78 Schrauben von Strido tun dies in gedruckten Teilen; siehe [Befestigungselemente](making/fasteners.md). ### Schraubensicherung {#threadlocker} Ein anaerober Klebstoff, der das Lösen von Schrauben verhindert. Mittelfeste (blaue) wird bei Schrauben in Metall-Servohörner verwendet; siehe [Befestigungselemente](making/fasteners.md). ### Tibia {#tibia} Das Unterschenkelglied. Jedes Bein hat eine gedruckte Hälfte `inner_tibia` und `outer_tibia` mit je einem 633ZZ-Lager; siehe [Mechanik](hardware/mechanics.md). ### Topic {#topic} Ein benannter ROS-2-Message-Kanal, etwa `/cmd_vel`, `/joint_states` oder `/battery_state`; siehe [ROS 2](software/ros2.md). ### Trot {#trot} Ein Gait, bei der sich diagonale Beinpaare (vorn links mit hinten rechts, vorn rechts mit hinten links) gemeinsam bewegen; siehe [Kinematik und Gaits](software/kinematics-and-gaits.md). ## U {#u} ### udev-Regel {#udev-rule} Eine Linux-Regel, die einem Gerät beim Einstecken einen stabilen Namen gibt; `99-strido.rules` benennt den XIAO und das LiDAR; siehe [Linux auf dem Pi](software/linux-on-the-pi.md). ### Upstream (Yertle) {#upstream-yertle} Der ursprüngliche Open-Source-Roboter Yertle, auf dessen STEP- und STL-Dateien Strido aufbaut, unverändert in `upstream/yertle/` aufbewahrt; siehe [Design](../design.md). ### URDF / xacro {#urdf-xacro} Das ROS-Format zur Roboterbeschreibung (URDF) und seine Makrosprache (xacro); `strido.urdf.xacro` wird aus dem CAD generiert; siehe [Simulation und RL](software/simulation-and-rl.md). ### USB CDC {#usb-cdc} Die Communication Device Class von USB: Der XIAO erscheint für den Pi als serieller Port und überträgt das COBS-gerahmte Protokoll; siehe [Firmware](software/firmware.md). ### uv {#uv} Ein Python-Paket- und Workspace-Manager; die Python-Pakete von Strido bilden einen uv-Workspace; siehe [CAD als Code](software/cad-as-code.md). ## V {#v} ### VitePress {#vitepress} Der statische Seitengenerator, der diese Dokumentationsseite baut. ## W {#w} ### WAGO 221-415 {#wago-221-415} Eine fünfpolige Hebelklemme (32 A, 0,2–4 mm², abisolieren 11 mm), mit der der Servo-Versorgungsbus im vorderen und hinteren Hohlraum aufgebaut wird; siehe [Kabelmanagement](making/cable-management.md). ### Watchdog {#watchdog} Ein Timer, der eine sichere Aktion auslöst, wenn kein Kommando eintrifft: 200 ms kein Gelenkkommando → halten, weitere 2 s → entspannen; siehe [Firmware](software/firmware.md). ## X {#x} ### XIAO ESP32-S3 {#xiao-esp32-s3} Das daumengroße ESP32-S3-Board von Seeed: der Bewegungscontroller des Roboters, der per USB mit dem Pi und per I²C/SPI mit PCA9685, Sensoren und LCD kommuniziert; siehe [Mikrocontroller](hardware/microcontrollers.md). ### XT60 {#xt60} Ein zweipoliger Leistungssteckverbinder (Amass-XT-Serie) für 30 A Dauerstrom, verwendet für den Akkueingang (unter dem Deck), den Arming-Port und den Loop-Key; bezeichnen Sie die Hälften nach Stiften oder Buchsen, nicht als männlich/weiblich; siehe [Versorgung](hardware/power.md). --- # Akkus: der 2S-LiPo {#batteries-the-2s-lipo} Strido läuft mit einem 2S-Lithium-Polymer-Akkupack (LiPo): 7,4 V nominal, 5000 mAh, etwa 37 Wh. Ein LiPo speichert viel Energie für sein Gewicht und kann große Ströme liefern, ist aber auch das eine Teil des Roboters, das einen Brand auslösen kann. Diese Seite erklärt die Zahlen auf dem Etikett und die Gewohnheiten, die den Akkupack gesund und sicher halten. ::: tip In Strido - **Teil:** LiPo 2S 5000 mAh Hardcase mit XT60, max. 138 × 47 × 25 mm (Gens-ace-G-Tech-Klasse), Stücklistenposition `lipo_2s_5000`. - **Zubehör:** Balance-Ladegerät mit Netzeingang (B6AC-Klasse, `charger`), LiPo-Sicherheitstasche (`lipo_bag`), LiPo-Zellenprüfer / Unterspannungsalarm (`lipo_checker`). - **Daten:** `hardware/electronics.yaml` → `power.pack` (7,4 V nominal, 8,4 V voll, 6,4 V leer, 5000 mAh) und `rails.pack` (6,0–8,4 V). - **Firmware:** Akku-Warnung bei 6,8 V, Servoabschaltung bei 6,4 V (`firmware/strido_esp32s3/lib/strido_core/include/strido/safety.h`), gemessen vom INA260. - **ROS 2:** `/battery_state` (Akkuspannung und Strom des Logikzweigs). ::: ## Zellen und die Bezeichnung „2S“ {#cells-and-the-2s-label} Eine LiPo-**Zelle** ist ein einzelner Lithium-Ionen-Pouch. Ihre Spannung hängt vom Ladezustand ab: | Zellzustand | Spannung pro Zelle | 2S-Akkupack | |---|---|---| | Voll (Ladeende) | 4,20 V | 8,4 V | | Nominal (Etikettwert) | 3,70 V | 7,4 V | | Strido-Warnung | 3,40 V | 6,8 V | | Strido-Servoabschaltung | 3,20 V | 6,4 V | | Niedrigster Schienenwert, für den der Logikzweig geprüft ist | 3,00 V | 6,0 V | **2S** bedeutet zwei Zellen in **S**erie: Die Spannungen addieren sich, und die Kapazität bleibt die einer Zelle. (Ein „2S2P“-Akkupack hätte zwei parallele Paare und doppelte Kapazität.) Zwei Zellen wurden gewählt, weil: - 2S (6,4–8,4 V im Betrieb) knapp über der 6,0-V-Servoschiene liegt, sodass die UBECs nur wenig herunterregeln müssen. - 2S der übliche RC-Car-Akkupack ist, sodass Akkupacks, Ladegeräte und XT60-Leitungen günstig und leicht erhältlich sind. ## Kapazität und Energie {#capacity-and-energy} **Kapazität** (mAh) ist die Ladung $Q$: 5000 mAh bedeutet, dass der Akkupack eine Stunde lang 5 A oder fünf Stunden lang 1 A liefern kann, bevor er leer ist. Ladung ist der über die Zeit integrierte Strom, $Q = \int I\,\mathrm{d}t$, bei konstantem Strom also $Q = I\,t$. **Energie** (Wh) berücksichtigt auch die Spannung. Elektrische Leistung ist $P = V I$; ihr Integral über die Entladung ergibt die Energie, und bleibt die Spannung nahe ihrem Nennwert, vereinfacht sich dies zu $$ E = \int V I\,\mathrm{d}t \approx V_\mathrm{nom}\, Q = 7.4\,\mathrm{V} \times 5.0\,\mathrm{Ah} = 37\,\mathrm{Wh} $$ (1 Wh = 3600 J, das sind also etwa 133 kJ.) Die Nennspannung wird verwendet, weil die Spannung eines LiPo über den Großteil der Entladung sanft von 4,2 V auf etwa 3,2 V pro Zelle fällt; 3,7 V pro Zelle ist ein guter Mittelwert. Die Energie ist die Größe, die die Laufzeit vorhersagt. `docs/electronics.md` schätzt etwa 60 W Entnahme aus dem Akkupack beim Trot (12 Servos ≈ 50 W, plus Pi, LiDAR und der Rest, über Wandler mit 90 % Wirkungsgrad). Mit einem nutzbaren Anteil $\eta_\mathrm{use} = 0.8$ der gespeicherten Energie: $$ E_\mathrm{usable} \approx 37\,\mathrm{Wh} \times 0.8 = 29.6\,\mathrm{Wh} $$ $$ t_\mathrm{run} = \frac{E_\mathrm{usable}}{P} \approx \frac{29.6\,\mathrm{Wh}}{60\,\mathrm{W}} \approx 0.5\,\mathrm{h} \approx 30\,\mathrm{min}\ \text{trotting} $$ Stehen verbraucht weniger, daher schätzt das Dokument etwa 45 min. Der Faktor 80 % ist da, weil die Firmware die Servos lange vor der echten Entleerung der Zellen abschaltet. Beide Laufzeiten sind als [ESTIMATE] markiert: Messen Sie Ihre eigene mit `/battery_state` und einer Strommesszange. 37 Wh liegen auch unter der Grenze von 100 Wh, oberhalb derer der Versand eines LiPo einen Zuschlag kostet (`docs/bom/sources.md`). ## C-Rate: wie schnell der Akkupack liefern kann {#c-rating-how-fast-the-pack-can-deliver} Die **C-Rate** drückt den Strom als Vielfaches der Kapazität aus. Mit $Q$ in Amperestunden bedeutet eine Rate von $C$ den Strom $$ I = C \cdot \frac{Q}{1\,\mathrm{h}} $$ also sind 1C bei einem 5000-mAh-Akkupack $5\,\mathrm{A}$, und 60C sind $60 \times 5\,\mathrm{A} = 300\,\mathrm{A}$ (der Dauerwert des Gens-ace-Akkupacks; 100C ergibt $500\,\mathrm{A}$ Spitze). Gleichbedeutend: Ein mit $n$C entladener Akkupack ist in $1/n$ Stunden leer. `hardware/electronics.yaml` verzeichnet für diesen Akkupack einen `max_discharge_a` von 300 A (60C dauerhaft, Gens ace GEA502S60X6HGT). Der ungünstigste Akkustrom des Roboters beträgt etwa 23,6 A (Servo- und Logikzweig, `docs/verification/electronics.md`), der Akkupack arbeitet also unter einem Zehntel seiner Nennbelastbarkeit. Warum weit mehr C kaufen als nötig? Jede Zelle verhält sich grob wie eine ideale Spannungsquelle $V_\mathrm{oc}$ (die Leerlaufspannung) in Reihe mit einem **Innenwiderstand** $R_\mathrm{int}$. Nach dem Ohmschen Gesetz ist die Klemmenspannung unter Last $$ V_\mathrm{term} = V_\mathrm{oc} - I\,R_\mathrm{int} $$ und der Akkupack wandelt außerdem $P_\mathrm{loss} = I^2 R_\mathrm{int}$ in Wärme um. Ein Akkupack mit höherer echter C-Rate hat meist einen geringeren Innenwiderstand und **bricht** daher weniger ein, wenn zwölf Servos gemeinsam eine Stromspitze ziehen. Zur Veranschaulichung (kein Messwert): Ein Akkupack mit $R_\mathrm{int} = 10\,\mathrm{m\Omega}$ würde beim ungünstigsten Strom des Roboters von $23.6\,\mathrm{A}$ um $0.24\,\mathrm{V}$ einbrechen und $5.6\,\mathrm{W}$ verheizen. Weniger Einbruch bedeutet weniger falsche Unterspannungsmeldungen und mehr Spannungsreserve für die UBECs. Billige Akkupacks geben ihre C-Rate oft zu hoch an, weshalb `docs/bom/sources.md` den LiPo zu den Teilen zählt, bei denen die Marke zählt (Hardcase, echte C-Rate). ### Lasteinbruch und der Abschaltfilter {#load-sag-and-the-cut-off-filter} Der Einbruch ist auch der Grund, warum die Firmware **nicht** bei einem einzelnen niedrigen Messwert abschaltet. Der INA260 wird alle 100 ms gelesen. Die Servos werden erst nach **5 aufeinanderfolgenden Messwerten unter 6,4 V** (0,5 s) entspannt, sodass eine kurze Stromspitze mitten im Schritt den Roboter nicht fallen lässt. Ein wirklich leerer Akkupack bleibt niedrig und löst die Abschaltung aus. ## Laden: immer mit Balance-Ladegerät {#charging-always-a-balance-charger} LiPo-Zellen werden mit **Konstantstrom, dann Konstantspannung** (CC/CV) geladen: Das Ladegerät treibt einen eingestellten Strom, bis die Zelle 4,20 V erreicht, und hält dann 4,20 V, während der Strom abfällt. Über 4,20 V pro Zelle wird die Zelle beschädigt und kann instabil werden. In einem Serien-Akkupack sieht das Ladegerät nur die Gesamtspannung, und die beiden Zellen sind nie genau gleich. Eine Zelle könnte 4,30 V erreichen, während die andere noch bei 4,10 V liegt, und die Summe würde trotzdem 8,4 V anzeigen. Die **Balance-Leitung**, der kleine Zusatzstecker mit einem Draht pro Zellverbindung, lässt ein **Balance-Ladegerät** jede Zelle messen und die höhere entladen. Das Ladegerät der B6AC-Klasse von Strido tut das. Faustregeln (siehe Battery University unter Weiterführende Literatur): - Laden Sie mit **1C oder weniger**: 5 A für diesen Akkupack. - Stecken Sie immer die Balance-Leitung an und wählen Sie das LiPo-Programm mit der richtigen Zellenzahl (2S). - Laden Sie **in der LiPo-Tasche** auf einer nicht brennbaren Unterlage und **lassen Sie ihn nie unbeaufsichtigt** (`docs/electronics.md`, Sicherheitsregeln). - Lassen Sie einen warmen Akkupack vor dem Laden abkühlen. ## Lagerspannung {#storage-voltage} Ein LiPo altert am schnellsten, wenn er **voll** (4,20 V pro Zelle) gelagert wird, und er wird beschädigt, wenn er **leer** gelagert wird. Bringen Sie für eine Lagerung von mehr als einigen Tagen jede Zelle auf etwa **3,80–3,85 V** (etwa 7,6–7,7 V für den Akkupack). Die meisten Balance-Ladegeräte, auch die der B6AC-Klasse, haben ein *Storage*-Programm, das automatisch auf diesen Wert lädt oder entlädt. ## Der LiPo-Prüfer {#the-lipo-checker} Der Zellenprüfer wird an die Balance-Leitung gesteckt und zeigt die Spannung jeder Zelle und die Summe. Verwenden Sie ihn: - **Vor einem Einsatz:** beide Zellen nahe 4,2 V und innerhalb weniger Hundertstel Volt voneinander. - **Nach einem Einsatz:** Zellen noch bei oder über etwa 3,2 V und weiterhin ausgeglichen. - **Vor der Lagerung:** Zellen auf Lagerspannung. Eine Zelle, die sich Einsatz für Einsatz von ihrer Partnerzelle entfernt, ist das erste Anzeichen eines versagenden Akkupacks. Im Alarmmodus piept der Prüfer, wenn eine Zelle unter einen Schwellwert fällt. Das ergänzt die Warnung der Firmware um eine zweite, unabhängige. ## Sicherer Umgang {#safe-handling} ::: danger LiPo-Brandgefahr Ein beschädigter, überladener oder tiefentladener LiPo kann ausgasen und heftig brennen. Ein LiPo-Brand lässt sich nicht durch Ersticken löschen. ::: - **Prüfen Sie den Akkupack.** Ein Hardcase hilft, aber achten Sie nach dem Gebrauch auf Aufblähen („Puffing“), Dellen, beschädigte Drähte oder einen heißen Akkupack. Nehmen Sie jeden aufgeblähten Akkupack außer Betrieb. - **Schließen Sie die Leitungen nie kurz.** Der Akkupack kann Hunderte Ampere liefern. Deshalb darf der Arming-Loop-Key auch nie in die XT60 des Akkus selbst passen. Siehe [Stromversorgung](power.md) für die Kontaktregel. - **Sicherung nahe am Akkupack.** Die 25-A-Hauptsicherung schützt den 14-AWG-Hauptstrang direkt nach dem Akkueingang. - **Nach dem Gebrauch abstecken.** Auch bei ausgeschalteter Logik bleibt der Roboter über seine Verkabelung mit dem Akkupack verbunden. Trennen Sie den Akku, wenn Sie fertig sind. - **Transportieren und lagern** Sie den Akkupack in der LiPo-Tasche, auf Lagerspannung und fern von Hitze. - **Fachgerecht entsorgen:** Vollständig mit dem Entladeprogramm eines Ladegeräts entladen und dann zu einer Batteriesammelstelle bringen. ## Selbsttest {#check-yourself} 1. Wie hoch ist die Akkuspannung eines 2S-LiPo bei 3,4 V pro Zelle, und was tut die Firmware dort? 2. Wie viel Strom sind 2C für diesen Akkupack? 3. Warum braucht ein Balance-Ladegerät die Balance-Leitung, wenn es an den Hauptleitungen bereits 8,4 V misst? 4. Warum wartet die Firmware auf fünf aufeinanderfolgende niedrige Messwerte, bevor sie abschaltet? 5. Sie werden den Roboter einen Monat lang nicht benutzen. Was sollten Sie mit dem Akkupack tun?
Antworten 1. 6,8 V; die Firmware löst die Akku-Warnung aus. 2. $2 \times 5\,\mathrm{A} = 10\,\mathrm{A}$. 3. Die Summe kann 8,4 V anzeigen, während eine Zelle überladen und die andere unterladen ist; nur die Messung pro Zelle zeigt und korrigiert das. 4. Stromspitzen lassen die Spannung kurz einbrechen. Die Forderung von 0,5 s unter 6,4 V ignoriert Spitzen und reagiert nur auf einen wirklich leeren Akkupack. 5. Bringen Sie ihn mit dem Storage-Programm des Ladegeräts auf Lagerspannung (etwa 3,80–3,85 V pro Zelle) und bewahren Sie ihn in der LiPo-Tasche auf.
## Weiterführende Literatur {#further-reading} - [BU-409: Laden von Lithium-Ionen-Akkus (Battery University)](https://batteryuniversity.com/article/bu-409-charging-lithium-ion) - [BU-808: Wie man die Lebensdauer von Lithium-Akkus verlängert (Battery University)](https://batteryuniversity.com/article/bu-808-how-to-prolong-lithium-based-batteries) - [TI-INA260-Datenblatt](https://www.ti.com/lit/ds/symlink/ina260.pdf): der Sensor, der die Akkuspannung misst - Verwandte Seiten: [Stromversorgung](power.md), [Sicherheit](../making/safety.md), [Elektronik, Verkabelung und Stromversorgung](../../electronics.md) --- # Busse und Signale {#buses-and-signals} Ein Bus ist eine vereinbarte Art, Bits zwischen Chips zu übertragen: welche Leitungen was führen, wie schnell und wer wann sprechen darf. Strido verwendet fünf: I²C für die Sensoren und den Servotreiber, USB-Seriell zwischen dem Pi und dem ESP32 (und zum LiDAR), PWM zu den Servos, SPI zum Gesichtsdisplay und CSI zur Kamera. Jeder wurde aus einem Grund gewählt, den Sie aus den Zahlen herleiten können. ::: tip In Strido - **I²C** (400 kHz) an XIAO D4 = SDA, D5 = SCL: PCA9685 0x40 (All-Call 0x70), LSM6DSOX 0x6A, INA260 0x41. Leitungen W17 (22 AWG, am XIAO gelötet, am PCA9685 gecrimpt) und W18, W19 (STEMMA-QT-Kabel, `stemma_qt_female` × 2). - **USB-Seriell:** Pi → XIAO USB CDC (W14, `/dev/strido_mcu`) und Pi → RPLIDAR-C1-USB-Adapter (W15, `/dev/rplidar`). - **PWM:** PCA9685 → 12 Servos, 200 Hz, 500–2500 µs; LCD-Hintergrundbeleuchtung an D2. - **SPI:** XIAO → Waveshare 2" ST7789 LCD (D8 SCK, D10 MOSI, D9 DC, D0 CS, D1 RST), W21. - **CSI:** Pi 5 CAM/DISP 0 → Camera Module 3 Wide, 22→15-Pin-FFC, 300 mm (W16). - **Maßgebliche Quelle:** `hardware/electronics.yaml`, `firmware/strido_esp32s3/src/board_config.h`, `hardware/wiring.yaml` (Kabel und Routen; Zuschnittliste in der [Verkabelungsprüfung](../../verification/wiring.md)), `docs/electronics.md` (Pinbelegungen, Verkabelungsliste). ::: ## Überblick {#overview} | Bus | Leitungen | Geschwindigkeit in Strido | Topologie | Verwendet für | |---|---|---|---|---| | I²C | SDA, SCL (+ 3,3 V, GND) | 400 kHz | gemeinsam, adressiert | Servotreiber, IMU, Power-Monitor | | USB (CDC-Seriell) | D+, D−, 5 V, GND | USB Full Speed | Punkt-zu-Punkt | Pi ⇄ XIAO Kommandos und Zustand | | UART (hinter USB-Adapter) | TX, RX, GND | 460 800 Baud | Punkt-zu-Punkt | RPLIDAR-C1-Scandaten | | Servo-PWM | ein Signal pro Servo | 200-Hz-Rahmen, µs-Puls | eine Leitung pro Servo | Gelenkpositionskommandos | | SPI | SCK, MOSI, CS, DC | 27 MHz Schreibtakt | hier ein Gerät | LCD-Pixel | | MIPI CSI-2 | differenzielle Lanes in einem Flachbandkabel | Gbit/s-Klasse | Punkt-zu-Punkt | Kamerabilder | ## I²C: ein Leitungspaar, viele Geräte {#i2c-one-pair-of-wires-many-devices} **I²C** (Inter-Integrated Circuit) verwendet zwei Leitungen: **SCL** (Takt, vom Controller getrieben) und **SDA** (Daten, in beide Richtungen). Jedes Gerät hat eine 7-Bit-**Adresse**. Der XIAO beginnt jede Transaktion mit dem Senden einer Adresse, und nur das Gerät mit dieser Adresse antwortet. ### Adressen in diesem Roboter {#addresses-in-this-robot} | Adresse | Gerät | Hinweis | |---|---|---| | 0x40 | PCA9685 Servotreiber | Firmware `kPcaAddress` | | 0x70 | PCA9685 All-Call | der PCA9685 antwortet auch hier; nichts anderes darf sie verwenden | | 0x6A | LSM6DSOX IMU | `kImuAddress` | | 0x41 | INA260 Power-Monitor | `kPowerMonitorAddress`; **Jumper A0 brücken** | Der INA260 wird mit **0x40** ausgeliefert, derselben Adresse wie der PCA9685. Zwei Geräte an einer Adresse antworten gleichzeitig und verfälschen gegenseitig ihre Antworten. Das Brücken des Lötjumpers A0 verschiebt den INA260 auf 0x41. `strido_verify.electronics` prüft, dass alle Adressen eindeutig sind und die Firmware-Konstanten mit der YAML übereinstimmen. ### Open Drain und Pull-ups {#open-drain-and-pull-ups} I²C-Geräte treiben eine Leitung nie auf High. Sie können sie nur auf **Low** ziehen (Open Drain), und **Pull-up-Widerstände** bringen sie auf die Versorgungsspannung zurück, wenn niemand zieht. So teilen sich mehrere Geräte eine Leitung, ohne sich gegenseitig kurzzuschließen. Zwei Folgen: - **Die Pull-up-Spannung bestimmt den Logikpegel.** Bei Strido ist der Bus auf die **3,3 V** des XIAO hochgezogen, und jedes Gerät daran wird aus dieser 3,3-V-Schiene versorgt. Die Prüfung bestätigt, dass 3,3 V im Bereich jedes Geräts liegt: PCA9685 2,3–5,5 V, LSM6DSOX-Breakout 3–5 V, INA260 2,7–5,5 V. - **Die Widerstände und die Verkabelung bestimmen die Geschwindigkeit.** Jeder Pull-up lädt die Buskapazität (Leitungen plus Pins) wieder auf High. Zu viel Kapazität oder zu schwache Pull-ups machen die steigenden Flanken langsam, und Fast-Mode-I²C mit 400 kHz hat eine strenge Grenze für die Anstiegszeit. Breakout-Boards haben meist eigene Pull-ups, die an einem gemeinsamen Bus parallel wirken. Kurze Leitungen halten die Kapazität niedrig. W17 ist die längste Strecke, 272 mm verlegt und auf 300 mm zugeschnitten; W18 und W19 sind 150-mm-STEMMA-QT-Kabel (86 mm und 125 mm verlegt). Der Pull-up-Widerstand $R_\mathrm{p}$ und die Buskapazität $C_\mathrm{b}$ bilden ein RC-Glied. Wenn das letzte Gerät die Leitung freigibt, steigt die Spannung exponentiell in Richtung der Versorgung $V_\mathrm{DD}$: $$ V(t) = V_\mathrm{DD}\left(1 - e^{-t/(R_\mathrm{p} C_\mathrm{b})}\right) $$ I²C misst die **Anstiegszeit** $t_\mathrm{r}$ zwischen 30 % und 70 % von $V_\mathrm{DD}$. Löst man $V(t)$ für diese beiden Pegel, ergibt sich $t_\mathrm{r} = R_\mathrm{p} C_\mathrm{b} \ln(0.7/0.3) \approx 0.847\,R_\mathrm{p} C_\mathrm{b}$. Die I²C-Spezifikation (NXP UM10204) erlaubt im Fast Mode höchstens $300\,\mathrm{ns}$ und $400\,\mathrm{pF}$ Buskapazität, daher ist der größte zulässige Pull-up $$ R_\mathrm{p,max} = \frac{t_\mathrm{r}}{0.847\, C_\mathrm{b}} $$ Für ein angenommenes $C_\mathrm{b} = 100\,\mathrm{pF}$ (eine Veranschaulichung, keine Messung dieses Kabelbaums) sind das $R_\mathrm{p,max} \approx 3.5\,\mathrm{k\Omega}$. Die Untergrenze ergibt sich aus den $3\,\mathrm{mA}$, die ein Gerät aufnehmen können muss, während es die Leitung unter $0.4\,\mathrm{V}$ hält: $R_\mathrm{p,min} = (V_\mathrm{DD} - 0.4\,\mathrm{V}) / 3\,\mathrm{mA} \approx 0.97\,\mathrm{k\Omega}$ bei $3.3\,\mathrm{V}$. Pull-ups auf mehreren Breakouts addieren sich wie parallele Widerstände, $1/R_\mathrm{p} = \sum_i 1/R_i$, weshalb zu viele Boards $R_\mathrm{p}$ unter dieses Minimum drücken können. ### Warum 400 kHz {#why-400-khz} Die Taktperiode und damit die Zeit für ein Bit ist $T_\mathrm{bit} = 1/f_\mathrm{SCL}$; bei $400\,\mathrm{kHz}$ sind das $2.5\,\mu\mathrm{s}$. Jedes I²C-Byte benötigt 9 Taktzyklen (8 Datenbits plus ein Acknowledge). Um einen PCA9685-Kanal zu setzen, werden die Adresse, eine Registernummer und vier Datenbytes gesendet: $$ t_\mathrm{ch} = 6 \times 9 \times T_\mathrm{bit} = 54 \times 2.5\,\mu\mathrm{s} \approx 135\,\mu\mathrm{s} $$ $$ t_{12} = 12\, t_\mathrm{ch} \approx 1.6\,\mathrm{ms}\quad\text{(plus small overheads)} $$ Das Auslesen der IMU und, alle 100 ms, das Auslesen des INA260 teilen sich dieselbe Regelperiode von 5 ms. Im Standard Mode mit 100 kHz würden allein die Servo-Schreibvorgänge etwa 6,5 ms dauern und die Frist verpassen. Deshalb läuft der Bus im **Fast Mode, 400 kHz** (`kI2cHz`). Diese Zahlen sind grobe Schätzungen; die genaue Anzahl hängt von der Bibliothek ab. ### STEMMA QT {#stemma-qt} Beide Strecken zur und von der IMU verwenden ein **STEMMA-QT**-Kabel: den 4-poligen JST-SH-Steckverbinder von Adafruit (1 mm Raster) mit 3,3 V, GND, SDA und SCL. Er ist pinkompatibel mit Qwiic von SparkFun. Das IMU-Breakout hat zwei STEMMA-QT-Buchsen, sodass der Bus weitergeführt werden kann; jedes Kabel aus der Stückliste endet in Buchsen für eine 2,54-mm-Stiftleiste. Die IMU sitzt 2,5 mm unter der Leiterplatte des Pi, daher passen Dupont-Gehäuse nicht auf ihre Stiftleiste; der flache STEMMA-QT-Stecker schon. Die erste Strecke hat das umgekehrte Problem. Die Pins des XIAO zeigen 9 mm unterhalb des oberen Schulterrahmens nach oben, zu wenig für ein 14 mm hohes Dupont-Gehäuse, daher wird W17 (3V3, GND, SDA, SCL, 22 AWG) **an die XIAO-Pins gelötet** und am PCA9685 mit Dupont-Kontakten **gecrimpt** (siehe [Kabelmanagement](../making/cable-management.md#connectors-and-terminations)). Die vollständige Kette ist: ``` XIAO ──W17 22 AWG (soldered / Dupont)──▶ PCA9685 (left header) ──W18 STEMMA QT──▶ LSM6DSOX ──W19 STEMMA QT──▶ INA260 ``` ## USB-Seriell und UART {#usb-serial-and-uart} ### UART-Grundlagen {#uart-basics} Ein **UART** sendet Bytes Bit für Bit über eine TX-Leitung und empfängt über eine RX-Leitung. Es gibt keine Taktleitung: Beide Seiten vereinbaren vorab eine **Baudrate**. Jedes Byte wird von einem Start- und einem Stoppbit eingerahmt, sodass die 8N1-Rahmung 10 Bitzeiten pro Byte kostet. Der RPLIDAR C1 spricht 3,3-V-TTL-UART mit **460 800 Baud, 8N1**: $$ \frac{460\,800\,\mathrm{bit/s}}{10\,\mathrm{bit/byte}} \approx 46\,\mathrm{kB/s} $$ Das reicht für 5000 Messpunkte pro Sekunde reichlich. Ein kleiner CP210x-USB-Adapter (im LiDAR-Sockel) macht aus diesem UART einen USB-Seriell-Port am Pi. Die udev-Regel benennt ihn `/dev/rplidar`, sodass sich der Portname zwischen Systemstarts nie ändert. ### USB CDC zum XIAO {#usb-cdc-to-the-xiao} Der ESP32-S3 hat natives USB. Die Firmware meldet sich als serieller **CDC**-Port (Communications Device Class), den Linux als tty anzeigt und udev `/dev/strido_mcu` nennt. Über USB ist die „Baudrate“ bedeutungslos: Die Daten werden in USB-Paketen übertragen. `kUsbBaud = 2000000` der Firmware wird ignoriert und nur für einen möglichen UART-Rückfall behalten. ### Rahmung: COBS und CRC16 {#framing-cobs-and-crc16} Eine serielle Verbindung ist nur ein Bytestrom, daher muss der Empfänger wissen, wo eine Nachricht beginnt und ob sie unversehrt angekommen ist: - **COBS** (Consistent Overhead Byte Stuffing) schreibt jeden Rahmen so um, dass er kein `0x00`-Byte enthält, und hängt dann ein `0x00` als Endmarke an. Nach einer Störung synchronisiert sich der Empfänger an der nächsten Null neu. - **CRC16-CCITT-FALSE** ist eine 16-Bit-Prüfsumme über den Rahmen. Ein Rahmen mit falscher CRC wird verworfen, statt ein Bein auf einen unsinnigen Winkel zu bewegen. Der Datenverkehr ist gering: Eine `STATE`-Nutzlast umfasst 103 Byte bei 100 Hz, $103\,\mathrm{B} \times 100\,\mathrm{Hz} \approx 10\,\mathrm{kB/s}$, und ein `JOINT_COMMAND` trägt 12 × float32 pro Gait-Schritt. ## PWM zu den Servos {#pwm-to-the-servos} Das Servosignal ist eine pulsweitenmodulierte Leitung: ein 3,3-V-Puls alle 5 ms (200 Hz), dessen **Breite**, 500–2500 µs, den Winkel codiert. Jedes Servo hat eine eigene Signalleitung von einem PCA9685-Kanal; die Masse wird über den Servo-Versorgungsbus geteilt. Details und Zahlen finden Sie unter [Servos](servos.md). Die LCD-Hintergrundbeleuchtung ist eine zweite PWM-Anwendung, an XIAO D2. Hier bestimmt das **Tastverhältnis** $D = t_\mathrm{on}/T$, der Zeitanteil, in dem die Leitung High ist, die Helligkeit: Die mittlere Spannung an der LED ist $\bar{V} = D\,V_\mathrm{high}$. Sie läuft mit 20 kHz ($T = 50\,\mu\mathrm{s}$), weit über dem, was das Auge als Flimmern wahrnimmt. D2 ist GPIO 3, ein **Strapping-Pin** des ESP32-S3, der beim Booten gelesen wird, um den Boot-Modus zu wählen. Die Firmware treibt ihn daher erst nach dem Booten. ## SPI zum Gesichtsdisplay {#spi-to-the-face-display} **SPI** (Serial Peripheral Interface) hat einen Takt (SCK), eine Datenleitung vom Controller zum Gerät (MOSI) und einen Chip-Select (CS) pro Gerät. Es gibt keine Adressen: Wird CS auf Low gezogen, ist das Gerät ausgewählt. SPI arbeitet im Gegentakt statt mit Open Drain und läuft daher weit schneller als I²C. Das Waveshare-2"-LCD verwendet einen ST7789-Controller mit 240 × 320 Pixeln. Ein vollständiges Bild mit 16 Bit pro Pixel umfasst: $$ N = 240 \times 320 \times 16\,\mathrm{bit} = 1\,228\,800\,\mathrm{bit} $$ $$ t_\mathrm{frame} = \frac{N}{f_\mathrm{SCK}} = \frac{1\,228\,800\,\mathrm{bit}}{27 \times 10^{6}\,\mathrm{bit/s}} \approx 45\,\mathrm{ms} $$ Über I²C mit 400 kHz und 9 Takten pro 8-Bit-Byte würde dasselbe Bild $N \cdot \tfrac{9}{8} / 400\,\mathrm{kHz} \approx 3.5\,\mathrm{s}$ dauern. Die Firmware schreibt mit **27 MHz**, in `face.cpp` vermerkt als „konservativ für ~15 cm Jumperkabel“: Längere, ungeschirmte Leitungen verschleifen schnelle Flanken. Das Display braucht nur eine Richtung, daher bleibt MISO ungenutzt. Die zusätzliche **DC**-Leitung (Data/Command) teilt dem Controller mit, ob ein Byte ein Kommando oder Pixeldaten ist. **RST** setzt das Panel zurück. ## CSI zur Kamera {#csi-to-the-camera} Die Kamera erzeugt weit mehr Daten als jeder der obigen Busse: 12 Megapixel, 1080p50-Video. Sie verwendet **MIPI CSI-2**, eine schnelle serielle Schnittstelle mit differenziellen Daten-Lanes, geführt über ein flexibles Flachbandkabel (FFC) direkt zum Bildsignalprozessor des Pi. - Der **Pi 5** hat 22-polige Kameraanschlüsse mit 0,5 mm Raster; das **Camera Module 3** hat einen 15-poligen Anschluss mit 1 mm Raster. Daher das **22 → 15 Pin**-Adapterkabel, 300 mm lang, durch den Flachbandschlitz der Frontschale verlegt. - FFCs sind empfindlich: Das Flachbandkabel wird mit der Kamera eingesetzt, kurz vor der Frontschale (Montage-Schritt 18). Vermeiden Sie scharfe Knicke, falten Sie die 124 mm Überlänge flach, und stecken Sie es mit den Metallkontakten zu den Kontakten des Steckverbinders ein. Die Kamera hat außerdem einen eigenen kleinen Steuerbus für Fokus und Einstellungen. Dieser läuft innerhalb des CSI-Kabels zum Pi, nicht über den I²C-Bus des Roboters. ## Selbsttest {#check-yourself} 1. Was würde schiefgehen, wenn Sie vergessen, den Jumper A0 des INA260 zu brücken? 2. Warum brauchen I²C-Leitungen Pull-up-Widerstände, SPI-Leitungen aber nicht? 3. Wie lange dauert es ungefähr, alle 12 Servokanäle mit 100 kHz zu schreiben, und warum ist das wichtig? 4. Was bewirkt das `0x00`-Byte am Ende jedes USB-Rahmens? 5. Warum verwendet die Kamera CSI statt USB oder SPI?
Antworten 1. Der INA260 läge zusammen mit dem PCA9685 auf 0x40, und beide würden auf dieselben Transaktionen antworten und den Bus stören. Die Firmware würde dann ohne funktionierenden Power-Monitor den Betrieb verweigern. 2. I²C-Ausgänge sind Open Drain und ziehen nur auf Low, daher muss etwas die Leitung auf High ziehen. SPI-Ausgänge treiben beide Pegel aktiv. 3. Etwa 6,5 ms (das Vierfache der 1,6 ms bei 400 kHz), länger als die Regelperiode von 5 ms. 4. Es markiert das Ende eines COBS-codierten Rahmens. COBS garantiert, dass innerhalb keine weitere Null vorkommt, sodass sich der Empfänger immer neu synchronisieren kann. 5. Ihre Datenrate (12-MP-Standbilder, 1080p50-Video) erfordert eine schnelle differenzielle Verbindung direkt zum Bildprozessor des Pi; SPI ist viel zu langsam, und CSI ist die native Kameraschnittstelle des Pi.
## Weiterführende Literatur {#further-reading} - [Berechnung der Pull-up-Widerstände am I²C-Bus (TI SLVA689)](https://www.ti.com/lit/an/slva689/slva689.pdf) - [Einführung in Adafruit STEMMA QT](https://learn.adafruit.com/introducing-adafruit-stemma-qt) - [Consistent Overhead Byte Stuffing (Überblick)](https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing) - [RPLIDAR-C1-Datenblatt (Slamtec)](https://wiki.slamtec.com/download/attachments/83066883/SLAMTEC_rplidar_datasheet_C1_v1.0_en.pdf?api=v2&modificationDate=1700531479533&version=1) - Verwandte Seiten: [Mikrocontroller](microcontrollers.md), [Sensoren](sensors.md), [Firmware](../software/firmware.md), [Kabelmanagement](../making/cable-management.md), [Elektronik, Verkabelung und Versorgung](../../electronics.md) --- # Mechanik: Beine, Koppelgetriebe, Lager und Passungen {#mechanics-legs-linkages-bearings-and-fits} Ein Laufroboter ist eine Reihe starrer Glieder, die durch Gelenke verbunden sind, und wie gut er läuft, hängt davon ab, wie diese Gelenke aufgebaut sind: was sich worauf dreht, wo die Motoren sitzen und wie viel Spiel jedes Gelenk zulässt. Diese Seite verfolgt ein Strido-Bein vom Körper bis zum Fuß und erklärt dann die Lager, die Gelenkgrenzen und warum Zehntelmillimeter bei gedruckten Teilen zählen. ::: tip In Strido - **Kinematische Daten:** `hardware/kinematics.yaml` (Gliederlängen, gemessen am Upstream-STEP), `hardware/joint_limits.yaml` (kollisionsfreie Grenzen), generiert in `firmware/.../geometry_generated.h` und `packages/strido-core/src/strido/geometry.py`. - **Gedruckte Teile je Bein:** `femur`, `femur_servo_connector`, `left_shoulder` / `right_shoulder` (Schulterkurbel), `short_link`, `stiff_long_link` (Strido, ersetzt die Upstream-`long_link`), `inner_tibia`, `outer_tibia`, `foot_spacer`, Servohalter und `servo_mount_top_bracket`, `hip_bearing_pin`. - **Lager:** 4 × 625ZZ, 4 × 6805-2RS, 8 × 633ZZ, 32 × Sinterbronze-Gleitlager 3 × 5 × 5 (Stücklistenzeilen `bearing_625zz`, `bearing_6805`, `bearing_633zz`, `sleeve_3x5x5`). - **Verifikation:** `docs/verification/fits.md` (Schrauben und Lagersitze), `clearance.md` (bewegte Teile), `interference.md` (statische Überlappungen), Toleranzregeln in `hardware/verification/tolerances.yaml`. ::: ## Freiheitsgrade {#degrees-of-freedom} Jedes Bein hat **drei Freiheitsgrade (DoF)**, je einen Servo: | Gelenk | Bewegt das Bein | Servoposition | Antrieb | |---|---|---|---| | Hüfte (Abduktion) | seitwärts, um eine Achse entlang des Körpers | im Körper, durch den inneren Schulterrahmen | direkt, über ein 25T-Scheibenhorn | | Oberschenkel | vorwärts und rückwärts | in der Servohalterung des Beinmoduls | direkt, über ein 25T-Scheibenhorn in den Femur-Servoverbinder | | Knie | beugt das Unterbein | in derselben Servohalterung, neben dem Oberschenkelservo | indirekt, über eine Kurbel und zwei Koppeln | Drei DoF pro Bein sind das Minimum, um einen Fuß an jeden erreichbaren Punkt im 3D-Raum zu setzen. Vier Beine ergeben insgesamt 12 Servos, dasselbe Layout wie bei einem Unitree Go2. Deshalb kann Strido die Gelenknamen und Konventionen des Go2 verwenden. ## Die kinematische Kette eines Beins {#the-kinematic-chain-of-one-leg} ```mermaid flowchart LR BODY["Körper
(Schulterrahmen)"] -->|"Hüftservo + 625ZZ-Drehpunkt"| MOD["Beinmodul
(Servohalterung)"] MOD -->|"Oberschenkelservo, Scheibenhorn"| FEM["Femur
130 mm"] MOD -->|"Knieservo, Armhorn r 24 mm"| SL["Kurze Koppel
28,3 mm"] SL --> SC["Schulterkurbel
(6805-2RS auf Oberschenkelachse)"] SC --> LL["Lange Koppel
131 mm"] FEM -->|"Knieachse, 2 × 633ZZ"| TIB["Tibia
124 mm bis zum Fuß"] LL --> TIB ``` ### Hüfte: beidseitig gelagert {#hip-supported-on-both-sides} Die Verzahnung des Hüftservos trägt eine Seite des Beinmoduls. Die andere Seite dreht sich auf einem **625ZZ**-Lager im äußeren Schulterrahmen, auf dem gedruckten `hip_bearing_pin` und einer M3 × 10-Drehpunktschraube. Da die Achse an beiden Enden gelagert ist, werden das Gewicht des Beins und die Bodenkräfte nicht allein von den kleinen Abtriebslagern des Servos getragen, wie es bei einer einseitigen Auskragung der Fall wäre. ### Oberschenkel: Direktantrieb {#thigh-direct-drive} Der Oberschenkelservo dreht den Femur direkt. Das Aluminium-Scheibenhorn ist im `femur_servo_connector` eingeklemmt und mit 4 × M3 × 20 an den Femur geschraubt. Der Femur misst 130 mm von der Oberschenkelachse bis zum Knie. ### Knie: Kurbel, Parallelogramm und Viergelenk {#knee-crank-parallelogram-and-four-bar} Säße der Knieservo *am* Knie, hingen 72 g Servo am Ende des Oberschenkels, wo sie jeder Schwingbewegung die meiste Trägheit hinzufügen. Strido hält den Knieservo oben im Beinmodul und überträgt seine Bewegung das Bein hinunter: 1. **Servoarm → Schulterkurbel (Parallelogramm).** Das Armhorn des Knieservos (Radius 24,0 mm) treibt die **kurze Koppel** (28,28 mm) an. Die kurze Koppel treibt den ersten Arm der Schulterkurbel (Radius 24,0 mm) an, die sich auf einem **6805-2RS**-Lager um die **Oberschenkelachse** dreht. Servowelle und Oberschenkelachse liegen 28,26 mm auseinander. Zwei gleiche Kurbeln, verbunden durch eine Koppel von der Länge ihres Abstands, bilden ein **Parallelogramm**: Die Schulterkurbel überträgt den Servowinkel exakt auf die Oberschenkelachse. 2. **Schulterkurbel → Tibia (Viergelenk).** Der zweite Arm der Kurbel (Radius 26,92 mm) schiebt die **lange Koppel** (131 mm) zu einer 24-mm-Kurbel an der Tibia. Die Tibia dreht sich auf zwei **633ZZ**-Lagern an der Knieachse. Zusammen mit dem Femur (130 mm) bildet dies ein **Viergelenkgetriebe**. Da das Gestell des Viergelenks der Femur selbst ist und die Armlängen nicht gleich sind, hängt der Unterschenkelwinkel **nichtlinear** sowohl vom Kurbelwinkel *als auch* vom Oberschenkelwinkel ab. Eine Bewegung nur des Oberschenkels ändert den Kniewinkel. Die Firmware (`servo_map.cpp`, `kinematics.cpp`) und `strido-core` (`leg.py`) lösen das Koppelgetriebe daher exakt und rechnen jeden angeforderten Unterschenkelwinkel in einen Kniekurbelwinkel um. Das Upstream-CAD von Yertle hat hier eine kleine Inkonsistenz: Das gezeichnete Knie (−98,8°) und der Winkel, bei dem sich das Koppelgetriebe tatsächlich schließt (−101,2°), unterscheiden sich, eine Abweichung der Koppellänge von 1,02 mm. Strido verwendet die gemessenen Längen, nicht die gezeichnete Pose (`docs/design.md`). ### Übertragungswinkel {#transmission-angle} In einem Viergelenk ist der **Übertragungswinkel** der Winkel zwischen der Koppel (lange Koppel) und der Abtriebskurbel. Nahe 0° oder 180° schiebt die Koppel entlang der Kurbel, statt sie zu drehen. Die Kraftübertragung bricht dort zusammen, und das Koppelgetriebe kann klemmen oder durchschlagen. Der Durchlauf des Bewegungsbereichs verwirft jede Pose mit einem Übertragungswinkel unter **25°** (`transmission_min_deg`). ## Gelenkgrenzen {#joint-limits} Die Grenzen stammen aus einem Kollisionsdurchlauf der vollständigen Baugruppe: jedes gedruckte Teil, Lager, Horn und Strido-Befestigungselement. Der Durchlauf läuft über Oberschenkel × Unterschenkel in einem 5°-Raster bei null Abduktion, gefolgt von einem Hüftdurchlauf in der Steh- und der Mittelpose. Eine weitere Regel hält jeden Servo innerhalb von **±85°** um seine Montage-Neutralstellung, innerhalb seines Stellwegs von ±90°. Dies sind die generierten Werte (das Durchlaufergebnis in `hardware/joint_limits.yaml`, auf den Servostellweg begrenzt in `codegen.py` / `geometry_generated.h`; das vordere Oberschenkelminimum von −40° stammt aus dieser Begrenzung): | Gelenk | FL | FR | RL | RR | |---|---|---|---|---| | Hüfte | −17,5…50° | −50…17,5° | −17,5…45° | −45…17,5° | | Oberschenkel | −40…125° | −40…125° | −15…125° | −15…125° | | Unterschenkel | −150…−45° | −150…−45° | −150…−45° | −150…−45° | | Kniekurbel | −2,5…75° | −2,5…75° | −2,5…75° | −2,5…75° | Die vorderen Oberschenkel schwenken kollisionsfrei bis −45°, doch die ±85°-Stellwegregel um die 45°-Neutralstellung begrenzt sie auf −40°. Am FL-Bein kollidieren 566 der Rasterzellen Oberschenkel × Unterschenkel, 422 sind zulässig. Die Firmware begrenzt jeden Befehl auf diese Grenzen und meldet `clamped` in `/diagnostics`, wenn sie eingreifen musste. Die Vorzeichenkonventionen folgen dem Go2: Oberschenkel positiv = Fuß nach hinten, Unterschenkel negativ = Knie gebeugt. ## Lager {#bearings} | Lager | Größe (Bohrung × AD × Breite) | Anz. | Wo | |---|---|---|---| | 625ZZ | 5 × 16 × 5 mm | 4 | Hüftdrehpunkt, äußere Schulterrahmen | | 6805-2RS | 25 × 37 × 7 mm | 4 | Schulterkurbel, dreht sich um die Oberschenkelachse um den Femur-Servoverbinder | | 633ZZ | 3 × 13 × 5 mm | 8 | Knie, zwei pro Tibia (innere und äußere Hälfte) | | Sinterbronze-Gleitlager | 3 × 5 × 5 mm | 32 | Koppelaugen, zwei pro Auge, 8 pro Bein | **Suffixe:** **ZZ** bedeutet beidseitig eine Metalldeckscheibe, die Staub abhält, aber nicht abdichtet. **2RS** bedeutet beidseitig Gummidichtungen, die zusätzlich das Fett im Lager halten. **Kugellager oder Gleitlager.** Ein Kugellager rollt, daher ist die Reibung gering und bleibt auch unter Last gering. Das passt zu den Gelenken, die das Gewicht des Roboters tragen und sich über große Winkel drehen. Ein **Sinterbronze-Gleitlager** ist ein poröses, ölgetränktes Gleitlager: winzig, günstig und gut geeignet für Koppelbolzen, die auf einer M3-Schraube nur um einige zehn Grad pendeln. Ein reines gedrucktes Loch würde schnell oval verschleißen; das Bronzelager bietet der Schraube eine harte, geschmierte Lauffläche. **Wie lange hält ein Kugellager?** Der Rollkontakt ermüdet die Laufbahnen mit der Zeit. Die nominelle Lebensdauer (ISO 281) eines Kugellagers beträgt $$ L_{10} = \left(\frac{C}{P}\right)^{3}\quad\text{million revolutions} $$ wobei $C$ die dynamische Tragzahl des Lagers aus dem Katalog ist, $P$ die äquivalente Belastung, die es trägt, und $L_{10}$ die Lebensdauer, die 90 % einer großen Lagercharge erreichen. Der Exponent 3 gilt für Kugellager (Rollenlager verwenden $10/3$). Die dritte Potenz macht die Lebensdauer sehr lastempfindlich: Halbiert man $P$, verachtfacht sich die Lebensdauer. Als Rechenbeispiel nehmen wir die 3,07 kg des Roboters (`docs/design.md`) im Trab, bei dem zwei Beine das Gewicht tragen, sodass jedes Bein im Stillstand in der mittleren Standphase etwa $P \approx 3.07\,\mathrm{kg} \times 9.81\,\mathrm{m/s^2} / 2 \approx 15.1\,\mathrm{N}$ trägt. Mit $C \approx 1.14\,\mathrm{kN}$, einer typischen Katalogtragzahl für ein 625-Rillenkugellager (prüfen Sie das Datenblatt Ihres Lieferanten), $$ L_{10} \approx \left(\frac{1140\,\mathrm{N}}{15.1\,\mathrm{N}}\right)^{3} \approx 4.3 \times 10^{5}\ \text{million revolutions} $$ Dynamische Fußstöße betragen ein Mehrfaches der statischen Last, und die Gelenke pendeln nur, doch selbst eine zehnfache Last lässt noch Hunderte Millionen Umdrehungen zu. Nicht die Ermüdung begrenzt diese Lager, sondern Schmutz, ein wandernder Außenring oder ein gerissener gedruckter Sitz. Siehe [Statik und Dynamik](../theory/statics-and-dynamics.md) dazu, wie Gelenklasten entstehen. Prüfen Sie die Passung jedes Lagers und Gleitlagers in seinem gedruckten Sitz **vor** der Montage (`docs/assembly/README.md`). ## Passungen: Übermaß-, Übergangs- und Spielpassung {#fits-press-transition-and-clearance} Eine **Passung** beschreibt, wie Welle und Bohrung mit gleichem Nennmaß zusammenpassen: | Passung | Bohrung im Vergleich zum Teil | Verwendung | |---|---|---| | Spielpassung | Bohrung immer größer | Teile, die gleiten oder sich drehen müssen: Schrauben durch Durchgangsbohrungen, Koppelaugen auf Bolzen | | Übergangspassung | etwa gleich groß | positionierte Teile, die sich noch von Hand einschieben lassen | | Übermaßpassung (Presspassung) | Bohrung immer kleiner | Teile, die sich in ihrem Sitz nie bewegen dürfen: Lageraußenringe, Gleitlager | Ein Lager muss sich auf seinen **Kugeln** drehen, nicht in seinem Sitz. Wandert der Außenring in einem lockeren Sitz, verschleißt der Kunststoff und das Gelenk bekommt Spiel. Ist der Sitz viel zu eng, reißt das gedruckte Teil, oder der Außenring wird so zusammengedrückt, dass das Lager klemmt. ### Lagersitze bei Strido {#strido-bearing-seats} `tolerances.yaml` erlaubt eine CAD-Sitzbohrung zwischen **0,15 mm unter** und **0,30 mm über** dem Außendurchmesser des Lagers. FDM-Drucker drucken Bohrungen etwa **0,15 mm zu klein**, daher berücksichtigen diese CAD-Bänder das erwartete Schrumpfen bereits. Alle 32 Sitze bestehen (`docs/verification/fits.md`): | Lager | AD | Gemessene CAD-Sitze | Differenz zum AD | |---|---|---|---| | 625ZZ (äußerer Schulterrahmen) | 16,0 mm | 16,17–16,21 mm | +0,17 bis +0,21 mm | | 633ZZ (Tibiahälften) | 13,0 mm | 13,18–13,23 mm | +0,18 bis +0,23 mm | | 6805-2RS (Schulterkurbel) | 37,0 mm | 36,92–36,95 mm | −0,05 bis −0,08 mm | | Gleitlager, kurze Koppel | 5,0 mm | 4,98–4,99 mm | etwa −0,02 mm | | Gleitlager, lange Koppel | 5,0 mm | 4,85–4,95 mm | −0,05 bis −0,15 mm | Fällt ein gedruckter Sitz zu locker aus und dreht sich das Lager mit, behebt ein Tropfen Sekundenkleber (CA) das Problem (`tolerances.yaml`). ### Schrauben in gedruckten Bohrungen {#screws-in-printed-holes} Dasselbe Schrumpfen betrifft jede Schraubenbohrung. Die Passungsprüfung erfasst 223 Schrauben: 0 Fehler, 137 Warnungen, jeweils mit einer Maßnahme. - **Durchgangsbohrungen**, die zu eng gedruckt werden: einmal mit einem 3,2-mm-Bohrer (ISO 273, feine Reihe für M3) durchbohren. - **Gewindeformende Bohrungen**, in denen die Schraube ihr eigenes Gewinde in den Kunststoff schneidet: Die gedruckte Vorbohrung sollte das 0,70–0,90-Fache des Schraubendurchmessers betragen. Darüber greift die Schraube schwach: Ziehen Sie sie mit Gefühl an, und wenn sie durchdreht, härten Sie die Vorbohrung mit einem Tropfen dünnflüssigem Sekundenkleber (CA) und drehen die Schraube erneut ein (anaerobe Schraubensicherung härtet auf Kunststoff nicht aus). Die Upstream-Servohalterungen liegen knapp über dem Band (ADR-009). Drucken Sie sie mit −0,15 mm X-Y-Lochkompensation oder härten Sie ihre Vorbohrungen mit CA. - **Sicherungsmutter-Verbindungen** im Koppelgetriebe: nur so weit anziehen, bis das Gelenk spielfrei ist. Die Koppeln müssen noch unter ihrem Eigengewicht schwingen (`docs/assembly/README.md`, Schritt 12). ## Warum Toleranzen bei gedruckten Teilen so wichtig sind {#why-tolerances-matter-so-much-on-printed-parts} `tolerances.yaml` geht davon aus, dass jede gedruckte Fläche um etwa 0,15 mm abweichen kann (0,4-mm-Düse, 0,2-mm-Schichten). Das klingt wenig, doch Beingelenke wirken als Hebel. Angenommen, das Oberschenkelgelenk hat hypothetisch 0,2 mm Spiel, gemessen 24 mm von seiner Achse (dem Radius der Kniekurbeln): $$ \Delta\theta \approx \frac{s}{r} = \frac{0.2\,\mathrm{mm}}{24\,\mathrm{mm}} \approx 0.0083\,\mathrm{rad} \approx 0.48^\circ $$ Das ist die Kleinwinkelform der Bogenlänge, $s = r\,\Delta\theta$. Der Fuß kann bis zu $l_1 + l_2 = 130\,\mathrm{mm} + 124\,\mathrm{mm} = 254\,\mathrm{mm}$ von der Oberschenkelachse entfernt sein, daher verschiebt ihn derselbe Winkel um $$ \Delta x \approx \Delta\theta \,(l_1 + l_2) \approx 0.0083 \times 254\,\mathrm{mm} \approx 2.1\,\mathrm{mm} $$ Kleine Fehler in mehreren Gelenken summieren sich, und der Fuß setzt dann woanders auf, als die Kinematik erwartet hat. Dieselben Abweichungen können auch bewegte Teile streifen lassen. Die Prüfung des Bewegungsfreigangs wertet daher jeden Spalt unter **0,3 mm** zwischen Teilen an verschiedenen Gliedern als Fehler (er könnte sich nach dem Druck schließen) und unter **1,0 mm** als knapp (er kann bei einem rauen Druck streifen). Über 13 Posen hat Strido **0 Fehler** und **4 knappe Paare**: die Front- und Rückschale gegenüber den Armhörnern und Schulterkurbeln bei voller Hüftabduktion, 0,73–0,79 mm (`docs/verification/clearance.md`). ## Selbsttest {#check-yourself} 1. Warum sitzt der Knieservo im Beinmodul statt am Knie? 2. Warum ändert eine Bewegung nur des Oberschenkelservos den Unterschenkelwinkel? 3. Was geht schief, wenn ein 633ZZ-Sitz viel zu locker gedruckt wird? Und viel zu eng? 4. Eine Schraubenbohrung für eine M3-Spielpassung wird mit 2,95 mm gedruckt. Was tun Sie? 5. Schätzen Sie das Fußwackeln bei 0,1 mm radialem Spiel an der 24-mm-Tibiakurbel ab, wenn der Fuß 124 mm vom Knie entfernt ist.
Antworten 1. Um Masse und Trägheit aus dem schwingenden Unterbein herauszuhalten, damit das Bein mit demselben Servodrehmoment schneller beschleunigen kann. 2. Das Viergelenk, das die Tibia antreibt, ist am Femur verankert; eine Drehung des Femurs ändert daher die Geometrie des Koppelgetriebes und damit den Kniewinkel. 3. Zu locker: Der Außenring dreht sich im Kunststoff, verschleißt den Sitz und erzeugt Spiel (Abhilfe mit einem Tropfen Sekundenkleber). Zu eng: Der Sitz reißt oder der zusammengedrückte Außenring lässt das Lager klemmen. 4. Einmal mit einem 3,2-mm-Bohrer durchbohren (ISO 273, feine Durchgangsbohrung für M3). 5. $\Delta\theta \approx 0.1 / 24 \approx 0.0042\,\mathrm{rad}$; $\Delta x \approx 0.0042 \times 124\,\mathrm{mm} \approx 0.5\,\mathrm{mm}$ am Fuß.
## Weiterführende Literatur {#further-reading} - [Viergelenkgetriebe (Überblick und Übertragungswinkel)](https://en.wikipedia.org/wiki/Four-bar_linkage) - [Rillenkugellager (SKF)](https://www.skf.com/group/products/rolling-bearings/ball-bearings/deep-groove-ball-bearings) - Verwandte Seiten: [Servos](servos.md), [Kinematik und Gaits](../software/kinematics-and-gaits.md), [3D-Druck](../making/3d-printing.md), [Befestigungselemente](../making/fasteners.md), [CAD als Code](../software/cad-as-code.md), [Montageanleitung](../../assembly/README.md), [Festigkeit, Drehmoment und Versagen](../making/strength.md) - Theorie: [Kinematik](../theory/kinematics.md), [Statik und Dynamik](../theory/statics-and-dynamics.md) --- # Mikrocontroller und der Raspberry Pi {#microcontrollers-and-the-raspberry-pi} Strido hat zwei Computer. Ein Raspberry Pi 5 läuft mit Linux und ROS 2 und entscheidet, *wohin die Beine sollen*. Ein Mikrocontroller Seeed XIAO ESP32-S3 führt ein kleines Programm aus, das diese Ziele alle 5 ms in Servopulse umsetzt und den Roboter sicher hält. Diese Seite erklärt, warum die Arbeit so aufgeteilt ist und wie die Daten zwischen beiden fließen. ::: tip In Strido - **Raspberry Pi 5, 4 GB** mit Active Cooler (`pi5_4gb`, `pi5_cooler`): ROS 2 Jazzy in Docker oder nativ, mit `gait_node` / `policy_node`, `mcu_bridge`, `sllidar_ros2` und optional `camera_ros` (`ros2/strido_control`, `ros2/strido_bringup`). - **Seeed XIAO ESP32-S3** (`xiao_esp32s3`): Firmware in `firmware/strido_esp32s3` (PlatformIO, Arduino-ESP32 3.x). Die Pins stehen in `src/board_config.h`, gespiegelt in und geprüft gegen `hardware/electronics.yaml`. - **PCA9685 16-Kanal-PWM-Treiber** (`pca9685`, Adafruit-815-Layout) an I²C-Adresse 0x40: erzeugt die 12 Servopulse. - **Verbindung:** USB-CDC-Seriell, Pi USB-A → XIAO USB-C (W14), Gerätename `/dev/strido_mcu` aus `ros2/strido_bringup/config/99-strido.rules`. ::: ## Zwei Arten von Computer {#two-kinds-of-computer} | | Raspberry Pi 5 | XIAO ESP32-S3 | |---|---|---| | Prozessor | Broadcom BCM2712, 4 × Arm Cortex-A76 mit 2,4 GHz | Espressif ESP32-S3, 2 × Xtensa LX7 mit bis zu 240 MHz | | Speicher | 4 GB RAM, Betriebssystem auf einer 64-GB-microSD | 8 MB PSRAM, 8 MB Flash | | Betriebssystem | Linux (Ubuntu Server 24.04 oder Raspberry Pi OS) | FreeRTOS unter dem Arduino-Core | | Stärke | große Software: ROS 2, Docker, Python, neuronale Policy, LiDAR- und Kameratreiber | vorhersagbares Timing, sofortiger Start, direkte Steuerung von Pins und Bussen | | Schwäche | Timing nicht garantiert; Booten dauert einige zehn Sekunden; SD-Karte kann durch Stromausfall beschädigt werden | wenig Speicher, keine Betriebssystemdienste, kein ROS | | Leistung | typisch 5–7 W, Spitze 12 W mit Kühler | etwa 1 W inklusive LCD, IMU und PCA9685-Logik | Ein **Mikrocontroller** (MCU) ist ein kompletter Computer auf einem Chip, gebaut, um dauerhaft ein Programm auszuführen und innerhalb von Mikrosekunden auf Hardware-Ereignisse zu reagieren. Ein **Einplatinencomputer** wie der Pi ist ein kleiner PC: Ein Allzweck-Betriebssystem teilt die CPU zwischen vielen Prozessen auf. ## Echtzeit vs. „im Mittel schnell“ {#real-time-vs-fast-on-average} Eine Regelschleife ist **echtzeitfähig**, wenn sie ihre Deadline in *jedem* Zyklus einhält, nicht nur im Mittel. Die Servoschleife in Strido hat eine Deadline von 5 ms (`kControlPeriodUs = 5000`): Periode und Schleifenrate sind Kehrwerte, $T = 1/f = 1/200\,\mathrm{Hz} = 5\,\mathrm{ms}$. Warum die Periode für einen Controller wichtig ist, behandelt [Regelung](../theory/control.md). Linux ist schnell, aber nicht deterministisch. Der Scheduler, ein USB-Interrupt, ein Schreibvorgang auf die SD-Karte, Pythons Garbage Collector oder ein ausgelasteter ROS-Node können einen Prozess um mehrere Millisekunden verzögern. Ein verspätetes Servo-Update zeigt sich als Ruck im Bein. Ein eingefrorener Prozess auf dem Pi darf außerdem niemals zwölf Servos mit 3,43 N·m dauerhaft auf ihrem letzten Befehl halten lassen. Der XIAO führt nur seine eigene Firmware aus, aufgeteilt in zwei FreeRTOS-Tasks auf getrennten Kernen (`src/main.cpp`): | Task | Kern | Priorität | Periode | Aufgabe | |---|---|---|---|---| | `controlTask` | 1 | 3 (höher) | 5 ms | IMU lesen, Orientierung aktualisieren, INA260 alle 100 ms lesen, Sicherheits-Zustandsautomat ausführen, 12 Servopulse berechnen und schreiben | | `commsTask` | 0 | 2 | ~1 ms Polling | eingehende Frames parsen, alle 10 ms einen STATE-Frame senden (100 Hz), LCD-Gesicht alle 50 ms aktualisieren | Durch die Aufteilung auf die Kerne kann ein Schwall serieller Daten das Servo-Update nie verzögern. ## Warum beide und nicht nur einer {#why-both-and-not-one-or-the-other} - **Nur der Pi?** Der Pi müsste Pulse erzeugen und die Sicherheit aus Linux heraus gewährleisten, ohne Timing-Garantie. Ein Absturz oder Neustart des Pi würde die Servos in einem unbekannten Zustand lassen. - **Nur der ESP32?** Er kann weder ROS 2, Nav2, den LiDAR-Treiber, den Kamera-Stack noch die gelernte Policy mit ihrer numpy-Laufzeit ausführen. - **Beide:** Jeder macht, was er gut kann. Der Pi plant mit 100 Hz (`gait_node`, `rate_hz: 100`) oder 50 Hz (`policy_node`). Der XIAO führt mit 200 Hz aus und verantwortet alles Sicherheitskritische. ### Was der XIAO selbstständig garantiert {#what-the-xiao-guarantees-on-its-own} Dies gilt unabhängig davon, was der Pi gerade tut (`docs/software.md`, `safety.h`): - **Watchdog:** 200 ms kein Gelenkbefehl → Pose halten; weitere 2 s → kraftlos (Ausgänge aus). Nur Gelenkbefehle speisen den Watchdog; stirbt also der Gait-Node, hält der Roboter zuerst und wird dann kraftlos. - **Verriegelter Not-Halt:** `/strido/estop` zieht den Output-Enable-Pin des PCA9685 auf High. Alle Pulse stoppen sofort, und der Halt bleibt verriegelt, bis er freigegeben wird. - **Akkuabschaltung:** Warnung bei 6,8 V; nach 5 Messwerten unter 6,4 V kraftlos schalten und Fahren verweigern. - **Grenzen:** Jedes Ziel wird auf 6 rad/s ratenbegrenzt und auf die Gelenk- und Kniekurbelgrenzen aus dem CAD-Bewegungsbereich-Sweep begrenzt. Nicht-endliche Werte (NaN) werden verworfen. - **Kein INA260, kein Fahren:** Ohne Power-Monitor gibt es keine Abschaltung. ## Der PWM-Treiber PCA9685 {#the-pca9685-pwm-driver} Warum erzeugt der ESP32 die zwölf Pulse nicht direkt? 1. **Pins.** Der XIAO bietet 11 Pads (D0–D10). Neun sind bereits belegt, für das LCD (6), I²C (2) und die Output-Enable-Leitung (1). Zwölf weitere Pulsausgänge sind nicht verfügbar. 2. **Entlastung.** Der PCA9685 hält pro Kanal einen 12-Bit-Ein/Aus-Zählwert und wiederholt die Pulse selbstständig mit 200 Hz. Die Firmware schreibt nur dann einen neuen Wert, wenn sich ein Ziel ändert. 3. **Eine Abschaltleitung.** Sein Low-aktiver **OE**-Pin (Output Enable) schaltet alle 16 Ausgänge auf einmal ab, in Hardware. 4. **Kontinuität mit Upstream.** Strido behält die Kanalbelegung des Upstream-Yertle bei (Kanäle 4–15), sodass Verkabelungswissen übertragbar bleibt. ::: warning Der OE-Pull-up Die PCA9685-Platine zieht OE auf **Low**, was „Ausgänge an“ bedeutet. Während der XIAO zurückgesetzt wird oder im Bootloader steht, ist sein Pin D3 offen, und die Servos würden dem folgen, was der PCA9685 zuletzt hielt. Ein **2,2-kΩ-Widerstand von OE nach VCC** hält die Ausgänge aus, bis die Firmware sie aktiv freigibt. Der Smoke-Test prüft das: Im Bootloader muss OE ≥ 2,4 V messen (`docs/electronics.md`, Kabelbaum-Schritt 8). ::: ## Datenfluss {#data-flow} ```mermaid flowchart LR CMD["/cmd_vel
teleop, Nav2"] --> GAIT["gait_node 100 Hz
oder policy_node 50 Hz"] GAIT -->|"/leg_controller/commands
12 Gelenkwinkel"| BR["mcu_bridge"] BR -->|"USB CDC: JOINT_COMMAND
COBS + CRC16"| CT["XIAO controlTask 200 Hz
Ratenbegrenzung, Koppelgetriebe, Begrenzung"] CT -->|"I²C 400 kHz"| PCA["PCA9685"] -->|"PWM 200 Hz"| SV["12 Servos"] IMU["LSM6DSOX"] -->|"I²C"| CT INA["INA260"] -->|"I²C"| CT CT -->|"STATE 100 Hz"| BR BR --> TOP["/joint_states /imu/data
/battery_state /diagnostics"] ``` Ein Zyklus, von Anfang bis Ende: 1. **Planen.** `gait_node` wandelt den Geschwindigkeitsbefehl in 12 Gelenkwinkel in Radiant um, Go2-Reihenfolge FL, FR, RL, RR × Hüfte, Oberschenkel, Unterschenkel. 2. **Senden.** `mcu_bridge` packt sie in einen `JOINT_COMMAND`-Frame: Sequenznummer, Modus, 12 × float32. Er fügt eine CRC16-Prüfsumme hinzu, COBS-kodiert den Frame und schreibt ihn nach `/dev/strido_mcu`. 3. **Ausführen.** Bei seinem nächsten 5-ms-Takt: - begrenzt der XIAO die Änderungsrate der Ziele; - rechnet er den Unterschenkelwinkel über das Koppelgetriebemodell in den Kniekurbelwinkel um (`jointsToActuators`); - begrenzt er auf die Gelenkgrenzen; - rechnet er jeden Winkel mit der Kalibrierung pro Gelenk in einen Puls um; - schreibt er die Pulse in den PCA9685. 4. **Melden.** Alle 10 ms sendet der XIAO eine 103 Byte große `STATE`-Payload: die angewendeten Gelenkwinkel, das Orientierungsquaternion, Gyroskop- und Beschleunigungsmesswerte, Busspannung, Strom und Status-Flags. `mcu_bridge` veröffentlicht sie als ROS-Topics. Da beide Seiten eine gemeinsame Protokolldefinition nutzen (`packages/strido-core/src/strido/protocol.py` ⇄ `firmware/.../protocol.h`), funktionieren dieselben Frames aus ROS, aus `strido-cli` auf einem Laptop und aus dem NT-X-Adapter. ## Selbsttest {#check-yourself} 1. Was passiert mit den Servos 200 ms und 2,2 s nach einem Absturz von `gait_node`? 2. Nennen Sie zwei Gründe, warum die Servopulse von einem PCA9685 statt direkt vom XIAO kommen. 3. Warum läuft der Regel-Task auf einem eigenen Kern mit höherer Priorität als der Kommunikations-Task? 4. Was verhindert der 2,2-kΩ-Widerstand am OE-Pin des PCA9685? 5. Welche Komponente rechnet den Unterschenkelwinkel in einen Kniekurbelwinkel um, und warum geschieht das nicht auf dem Pi?
Antworten 1. Nach 200 ms ohne Befehle halten die Servos die letzte Pose. Nach weiteren 2 s (insgesamt 2,2 s) werden sie kraftlos, die Ausgänge sind aus. 2. Zwei beliebige von: Der XIAO hat zu wenige freie Pins; der PCA9685 wiederholt die Pulse in Hardware; sein OE-Pin schaltet alle Ausgänge auf einmal ab; er behält die Upstream-Kanalbelegung bei. 3. Damit serieller Datenverkehr und LCD-Updates die 5-ms-Servo-Deadline nie verzögern können. 4. Dass Servos angesteuert werden, während der XIAO zurückgesetzt wird oder im Bootloader steht, wenn sein Pin D3 OE nicht aktiv auf High hält. 5. Die XIAO-Firmware (`jointsToActuators` in `servo_map.cpp`). Geschieht dies direkt neben Begrenzung und Pulserzeugung, kann die MCU die Kniekurbelgrenzen selbst durchsetzen, egal was der Pi sendet. Dieselbe Mathematik existiert auch in `strido-core` für die Simulation.
## Weiterführende Literatur {#further-reading} - [ESP32-S3-Datenblatt (Espressif)](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) - [Seeed XIAO ESP32-S3: Erste Schritte](https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/) - [Raspberry Pi 5 Produktseite](https://www.raspberrypi.com/products/raspberry-pi-5/) - [PCA9685-Datenblatt (NXP, Adafruit-Spiegel)](https://cdn-shop.adafruit.com/datasheets/PCA9685.pdf) - Verwandte Seiten: [Busse](buses.md), [Servos](servos.md), [Firmware](../software/firmware.md), [ROS 2](../software/ros2.md), [Software](../../software.md), [Regelungstheorie](../theory/control.md) --- # Stromverteilung {#power-distribution} Die Stromverteilung nimmt einen Akku und erzeugt daraus die richtige Spannung für jedes Teil, mit Schutz gegen Fehler, die sonst einen Draht schmelzen oder eine Platine zerstören würden. Strido teilt seine Versorgung in eine **Servo-Domäne** mit 6,0 V und eine **Logik-Domäne** mit 5 V / 3,3 V, die sich eine Masse teilen; diese Seite verfolgt den Strom vom XT60 bis zum letzten Servo. ::: tip In Strido - **Maßgebliche Quelle:** `hardware/wiring.yaml` (jedes Kabel W00–W23 und die Servokabel, durch das CAD geführt; Zuschnittliste in der [Verkabelungsprüfung](../../verification/wiring.md)), `hardware/electronics.yaml` (`power`, `rails`, `supplies`, `fuses`, `wire_ampacity_a`) und `docs/electronics.md` (Verkabelungsliste, Tabelle der Nennwerte). `python -m strido_verify.electronics` liest die Stromkabel aus `wiring.yaml` und prüft jeden Draht, jede Sicherung und jeden Wandler gegen seine Last (`docs/verification/electronics.md`). Wie der Kabelbaum aufgebaut ist: [Kabelmanagement](../making/cable-management.md). - **Teile:** XT60H-Steckverbinder (Akkueingang, Arming-Port, Loop-Key), 2 × ATO-Inline-Sicherungshalter mit 25-A- und 7,5-A-Sicherungen, 2 × Hobbywing UBEC-10A (6,0 V), 8 × WAGO 221-415, Pololu #2813 Einschalttaster, Adafruit INA260, Pololu D36V50F5 5-V-Spannungsregler, Silikonlitze 14 / 18 / 22 AWG. - **Schienen:** `pack` 6,0–8,4 V, `servo_6v` 5,4–6,0 V, `logic_5v` 4,8–5,2 V, `logic_3v3` 3,2–3,4 V. ::: ## Der Versorgungsbaum {#the-power-tree} ```mermaid flowchart LR BAT["2S LiPo
6,4–8,4 V"] --> XT["XT60-Akkueingang"] -->|"W01 14 AWG, ungesichert"| F25["25-A-Hauptsicherung"] F25 -->|"14 AWG"| ARM["XT60-Arming-Port
+ Loop-Key"] ARM --> UF["UBEC vorne 6,0 V"] --> SF["FL- + FR-Servos"] ARM --> UR["UBEC hinten 6,0 V"] --> SR["RL- + RR-Servos"] F25 -->|"Halterleitung 14 AWG"| F7["7,5-A-Logiksicherung"] --> SW["Pololu #2813
Schalter"] --> INA["INA260
Shunt"] --> REG["D36V50F5
5 V"] REG --> PI["Raspberry Pi 5"] PI -->|"USB 5 V"| XIAO["XIAO ESP32-S3"] PI -->|"USB 5 V"| LID["RPLIDAR C1"] XIAO -->|"3,3 V"| L3["PCA9685, IMU,
INA260-Logik, LCD"] ``` Zwei Zweige verlassen die Hauptsicherung: - **Servozweig:** Arming-Port → zwei UBECs → WAGO-Busse → 12 Servos. Er führt bis zu etwa 21 A und wird nur über den Loop-Key geschaltet. - **Logikzweig:** Logiksicherung → Einschalttaster → INA260 → 5-V-Spannungsregler → Pi 5, der den XIAO und das LiDAR über USB versorgt. Der eigene 3,3-V-Spannungsregler des XIAO versorgt dann die I²C-Platinen und das LCD. Dieser Zweig zieht höchstens etwa 2,7 A. Die Trennung gibt es, weil sich die beiden Lasten stark unterscheiden. Servos ziehen große, sprunghafte Ströme, die die Akkuspannung einbrechen lassen. Ein Raspberry Pi gerät bei einem Spannungseinbruch in einen Brownout und beschädigt seine SD-Karte. Getrennte Spannungsregler halten Servo-Transienten vom Computer fern, und Sie können die Motoren entschärfen, während der Computer weiterläuft. ## Steckverbinder und die Scharfschaltschleife {#connectors-and-the-arming-loop} ### XT60 {#xt60} Der XT60 ist der Standard-Hochstromsteckverbinder im RC-Bereich, ausgelegt für 30 A Dauerstrom. Strido verwendet drei XT60H-Hälften: | Steckverbinder | Aufgabe | |---|---| | Akkueingang | unter dem Deck, in der Tasche neben dem Akku; die eigene Leitung des Akkupacks (W00) wird dort eingesteckt | | Arming-Port | in der Rückschale, Blende `arming_port_bezel`; seine beiden Kontakte sind die beiden Enden der Servoversorgung | | Loop-Key | ein loser XT60 mit einer 14-AWG-Brücke: Einstecken schließt den Servozweig | Der **Loop-Key** ist ein physischer, sichtbarer Notaus für jeden Servo. Ziehen Sie ihn ab, und kein Servo kann Strom bekommen, egal was die Software tut. Der Einschalttaster ist *kein* Not-Halt: Pololu sagt das ausdrücklich, und er schaltet nur den Logikzweig. ::: danger Der Loop-Key darf niemals auf den Akku passen Der Loop-Key ist ein kurzgeschlossener Steckverbinder. Würde er mit dem Akkupack zusammenpassen, schlösse er den Akku kurz. Geben Sie ihm den **gleichen Kontakttyp wie der eigene Steckverbinder des Akkupacks** (Stifte oder Buchsen), damit er sich physisch nicht einstecken lässt. Testen Sie mit einem *unüberbrückten* Gehäuse, bevor Sie die Brücke löten (`docs/electronics.md`, „XT60 contact rule“). ::: ### Reihenfolge beim Scharfschalten {#arming-order} Die sichere Startreihenfolge (`docs/electronics.md`, Sicherheitsregeln): 1. Logik ein (Einschalttaster). Pi und XIAO starten, die Servos bleiben kraftlos. 2. Roboter liegt in der Ruhepose, Beine eingeklappt. 3. Stecken Sie den Loop-Key ein. Die Servos erhalten noch keine Pulse: Die Output-Enable-Leitung des PCA9685 ist gesperrt. 4. Starten Sie `ros2 launch strido_bringup robot.launch.py`: Ruhepose, dann ein Aufstehen in 3 s. Stecken Sie den Stecker nie ein, während Positionsbefehle laufen: Alle zwölf Servos würden gleichzeitig springen. ## Sicherungen: Sie schützen den Draht, nicht das Gerät {#fuses-protecting-the-wire-not-the-device} Eine Sicherung soll verhindern, dass ein **Draht** bei einem Kurzschluss überhitzt. Ihr Nennwert muss beides erfüllen: $$ I_\mathrm{load} \le I_\mathrm{fuse} \le I_\mathrm{wire} $$ (Laststrom, Nennwert der Sicherung und der Strom, den der Draht tragen kann). | Sicherung | Nennwert | Schützt | Last im ungünstigsten Fall | Drahtgrenze | |---|---|---|---|---| | Haupt (ATO) | 25 A | W02, W03, W04/front, W04/rear (14 AWG) | 23,6 A (Servo + Logik) | 32 A | | Logik (ATO) | 7,5 A | W09, W10, W11 und die Logik-Masserückleitungen W24, W04/logic (18 AWG) | 2,74 A | 16 A | Die „Drahtgrenze“ ist die des *dünnsten* Drahts hinter der Sicherung. Der Logik-Sicherungshalter wird über seine **eigene 14-AWG-Leitung** versorgt, die in der Rückschale an W02 gespleißt ist; so liegt kein Draht dünner als 14 AWG allein hinter der 25-A-Sicherung, und alles nach der 7,5-A-Sicherung hat mindestens 18 AWG. (Ein früheres Design verwendete dort einen 60 mm langen 18-AWG-Abgriff: nur durch die 25-A-Sicherung abgedeckt, über den 16 A dieses Drahts, weshalb er ersetzt wurde.) W01 vom Akkueingang zur Hauptsicherung ist **ungesichert**, wie die eigene Leitung des Akkupacks. Der Sicherungshalter sitzt am hinteren WAGO-Bus, wo seine 14-AWG-Leitungen Platz zum Biegen haben, etwa 0,15 m vom Akkueingang entfernt; daher wird W01 so kurz gehalten, in Spiralschlauch und fern von beweglichen Teilen. Details: [Kabelmanagement](../making/cable-management.md#fusing-a-fuse-protects-the-wire). ## Spannungsregler: die richtige Spannung erzeugen {#regulators-getting-the-right-voltage} | Wandler | Typ | Ausgang | Nennwert | Versorgt | |---|---|---|---|---| | Hobbywing UBEC-10A ×2 | Schaltregler (Abwärtswandler), 2–6S Eingang | 6,0 V (Jumper offen) | je 10 A Dauer, 15 A Spitze | je 6 Servos | | Pololu D36V50F5 | Schaltregler (Abwärtswandler), 5,5–50 V Eingang | 5 V ± 4 % | 5,5 A | Pi 5 (und über USB: XIAO, LiDAR) | | XIAO ESP32-S3 on-board | Linearregler | 3,3 V | gering | PCA9685 VCC, LSM6DSOX, INA260 VS, LCD | ### Warum Schaltregler {#why-switching-regulators} Zwei Gesetze liegen jeder Zahl auf dieser Seite zugrunde. Das **ohmsche Gesetz** verknüpft die Spannung über einem Widerstand mit dem Strom durch ihn, und elektrische **Leistung** ist Spannung mal Strom: $$ V = I R, \qquad P = V I = I^2 R = \frac{V^2}{R} $$ Ein **Linearregler** ist ein veränderlicher Widerstand in Reihe mit der Last: Der volle Laststrom fließt durch ihn, während an ihm die Spannungsdifferenz abfällt, also verheizt er $P_\mathrm{loss} = (V_\mathrm{in} - V_\mathrm{out})\, I$. 7,4 V bei 3 A auf 5 V abzusenken würde verschwenden: $$ P_\mathrm{loss} = (7.4\,\mathrm{V} - 5\,\mathrm{V}) \times 3\,\mathrm{A} = 7.2\,\mathrm{W} $$ Das ist mehr, als der Pi selbst im Mittel verbraucht. Ein **Buck**-Wandler (Abwärts-Schaltregler) zerhackt den Eingang mit einem Transistor und glättet ihn mit einer Spule und einem Kondensator. Ein idealer Buck mit Tastgrad $D$ liefert $V_\mathrm{out} = D\,V_\mathrm{in}$, und weil Energie erhalten bleibt, gilt $V_\mathrm{in} I_\mathrm{in} = V_\mathrm{out} I_\mathrm{out}/\eta$ mit Wirkungsgrad $\eta$: Er wandelt Leistung um, statt sie zu verheizen. Die Verifikation nimmt 90 % Wirkungsgrad an (`converter_efficiency: 0.9`). Zurückgerechnet auf den Akkustrom bei der niedrigsten Akkuspannung werden aus den 15,8 W Spitze des Logikzweigs bei 5 V: $$ I_\mathrm{pack} = \frac{P_\mathrm{out}}{\eta\, V_\mathrm{pack}} = \frac{15.8\,\mathrm{W}}{0.9 \times 6.4\,\mathrm{V}} \approx 2.74\,\mathrm{A} $$ Gegen diesen Wert werden Schalter, INA260 und Logiksicherung geprüft. ### Dropout {#dropout} Ein Buck kann nur **abwärts** wandeln. Sein Ausgang bleibt etwas unter dem Eingang, wenn sich der Eingang dem Sollwert nähert. Mit leerem Akkupack (6,4 V) und 10 A fällt die 6,0-V-Servoschiene voraussichtlich auf etwa 5,4 V ([ESTIMATE] in `rails.servo_6v`). Das ist ein Grund, warum eine 7,4-V-Servoschiene aus 2S unmöglich ist, wie `docs/bom/sources.md` anmerkt. ### Die 5-V-Versorgung des Pi {#the-pi-s-5-v-feed} Der Pi 5 wird über seine GPIO-5-V-Pins (2 und 4, Masse an 6 und 14) versorgt, nicht über USB-C. Das umgeht USB Power Delivery, daher weiß der Pi nicht, dass seine Versorgung 5 A liefern kann. Teilen Sie es ihm mit: ```bash sudo rpi-eeprom-config --edit # add: PSU_MAX_CURRENT=5000 ``` Ohne diese Einstellung begrenzt der Pi den Strom, den seine USB-Ports ziehen dürfen, und an diesen Ports hängen LiDAR und XIAO. ## Drahtquerschnitt und Spannungsabfall {#wire-gauge-and-voltage-drop} **AWG**-Nummern (American Wire Gauge) werden *kleiner*, je dicker der Draht ist. Der Widerstand eines Leiters wächst mit seiner Länge $L$ und sinkt mit seinem Querschnitt $A$: $$ R = \frac{\rho L}{A} $$ mit dem spezifischen Widerstand von Kupfer $\rho \approx 1.72 \times 10^{-8}\,\Omega\,\mathrm{m}$. Für 18 AWG gilt $\rho / A = 1.72 \times 10^{-8}\,\Omega\,\mathrm{m} / 0.82 \times 10^{-6}\,\mathrm{m^2} \approx 21\,\mathrm{m\Omega/m}$, der Wert in der Tabelle. Dicker Draht hat einen geringeren Widerstand, erwärmt sich also weniger ($P = I^2 R$) und verliert weniger Spannung. | Querschnitt | Kupferfläche (ca.) | Widerstand (ca.) | In der Prüfung verwendete Strombelastbarkeit | Verwendet für | |---|---|---|---|---| | 14 AWG | 2,1 mm² | 8,3 mΩ/m | 32 A | Akku-Hauptstrang W01–W04, Leitung des Logik-Sicherungshalters | | 18 AWG | 0,82 mm² | 21 mΩ/m | 16 A | UBEC-Ausgangsverlängerungen W05/W06, Bus-Brücken W07/W08, Logikzweig W09–W11, Logikmassen W24 und W04/logic | | 20 AWG | 0,52 mm² | 33 mΩ/m | 11 A | UBEC-Ausgangsleitungen | | 22 AWG | 0,33 mm² | 53 mΩ/m | 7 A | Pi-5-V-Versorgung W12, Servokabel (die eigenen 260-mm-Servokabel, auf Länge gekürzt; keine Verlängerungen), Signale | Die Werte der Strombelastbarkeit stammen aus `wire_ampacity_a` in `hardware/electronics.yaml`. Sie sind für kurze Strecken im Chassis an freier Luft bewusst konservativ. Der **Spannungsabfall** folgt dem ohmschen Gesetz, $\Delta V = I R$, und der Strom fließt *hin und zurück*, also zählen beide Leiter. Derselbe Strom erwärmt den Draht mit $P = I^2 R$: Die Verlustleistung wächst mit dem *Quadrat* des Stroms, weshalb der Hochstrom-Servozweig die dicksten, kürzesten Drähte bekommt. Die folgenden Längen stammen aus der Zuschnittliste in der [Verkabelungsprüfung](../../verification/wiring.md). Die Zuschnittlänge als Kupfer im Stromkreis anzusetzen ergibt eine obere Schranke. - **W05**, UBEC vorne zum WAGO-Bus: 18-AWG-Paar, verlegt 190 mm, zugeschnitten 222 mm, bei 10 A. $$ R = 0.222\,\mathrm{m} \times 21\,\mathrm{m\Omega/m} \approx 4.7\,\mathrm{m\Omega}\ \text{per conductor} $$ $$ \Delta V \approx 10\,\mathrm{A} \times 4.7\,\mathrm{m\Omega} \times 2 \approx 93\,\mathrm{mV}, \qquad P \approx (10\,\mathrm{A})^2 \times 9.3\,\mathrm{m\Omega} \approx 0.93\,\mathrm{W} $$ - **Der Stromzweig eines Servokabels**: das eigene rot/braune 22-AWG-Paar des Servos vom Servo zu seinem WAGO-Paar, ohne Verlängerung. Das längste ist das der Hüfte vorne links, 60 mm bis zu seinem Kabelbinder plus 88 mm bis zur WAGO = 148 mm verlegt, beim Blockierstrom von 3,5 A. $$ R = 0.148\,\mathrm{m} \times 53\,\mathrm{m\Omega/m} \approx 7.8\,\mathrm{m\Omega}\ \text{per conductor} $$ $$ \Delta V \approx 3.5\,\mathrm{A} \times 7.8\,\mathrm{m\Omega} \times 2 \approx 55\,\mathrm{mV} $$ Eine 300-mm-Verlängerung aus demselben Draht, wie sie der Roboter früher verwendete, hätte etwa 0,11 V zusätzlich gebracht, und pro Servo einen Stecker und eine Buchse. - **W12**, die Pi-Versorgung: 2 × 22 AWG parallel pro Schiene, verlegt 104 mm, zugeschnitten 123 mm, 1,6 A pro Draht ($0.123\,\mathrm{m} \times 53\,\mathrm{m\Omega/m} \approx 6.5\,\mathrm{m\Omega}$ pro Draht). $$ \Delta V \approx 1.6\,\mathrm{A} \times 6.5\,\mathrm{m\Omega} \times 2 \approx 21\,\mathrm{mV} $$ Kurze, ausreichend dicke Drähte halten jeden Abfall deutlich unter 0,2 V. Die Pi-Versorgung ist trotzdem doppelt ausgeführt, weil der Pi unter 4,63 V Unterspannung meldet und die untere Toleranz des Spannungsreglers bereits 4,8 V beträgt. ## Leistung messen: der INA260 {#measuring-power-the-ina260} Der INA260 ist ein Strom-, Spannungs- und Leistungsmonitor mit eingebautem 2-mΩ-Shunt-Widerstand. Er sitzt **high-side** im Logikzweig: Der Strom tritt an VIN+ ein und an VIN− aus, und der Chip misst die winzige Spannung über seinem internen Shunt, $V_\mathrm{shunt} = I R_\mathrm{shunt}$, und teilt durch den bekannten Wert $R_\mathrm{shunt} = 2\,\mathrm{m\Omega}$, um den Strom zu erhalten. Bei den 2,74 A des Logikzweigs sind das nur $5.5\,\mathrm{mV}$, und der Shunt setzt $I^2 R \approx 15\,\mathrm{mW}$ um. | Was er misst | Wozu | |---|---| | Busspannung an VIN− (= Akkuspannung abzüglich kleiner Verluste) | die Warnung bei niedrigem Akkustand (6,8 V) und die Abschaltung (6,4 V) | | Strom des Logikzweigs (Auflösung 1,25 mA, bis 15 A) | Logik-Leistungsaufnahme in `/battery_state` | Den Servostrom sieht er **nicht**, der über den Arming-Port an ihm vorbeifließt. Seine Aufgabe ist hier vor allem die des Voltmeters, das den Akkupack schützt. Die Firmware verweigert daher das Ansteuern der Servos, wenn der INA260 auf I²C an Adresse 0x41 nicht antwortet: Ohne ihn gibt es keine Unterspannungsabschaltung. ## Masseführung {#grounding} Alle Domänen teilen sich **eine Masse**, sternförmig am Akkueingang verbunden (W04: Akkueingang − → Massestern daneben → beide UBEC-Eingänge in 14 AWG und die Schaltermasse in 18 AWG). Die Massen von Spannungsregler und INA260 gehen an die Schaltermasse, die Massepins des Pi an den Spannungsregler. Eine gemeinsame Masse ist wichtig, weil ein Signal nur eine Spannung *relativ zur Masse* ist. Der 3,3-V-Puls des PCA9685 muss vom Servo gegen dieselbe Referenz gemessen werden. Ein Sternpunkt verhindert, dass die großen Servo-Rückströme durch die dünnen Logikmassen fließen. Täten sie es, würden die 21 A von sechs blockierten Servos die Logikreferenz um `I × R` verschieben und könnten Signale verfälschen. ## Selbsttest {#check-yourself} 1. Welche Komponenten schaltet das Ziehen des Loop-Keys ab, und welche laufen weiter? 2. Warum darf die Logiksicherung 7,5 A haben, aber nicht 20 A? 3. Schätzen Sie den Spannungsabfall (hin und zurück) von W06 (18-AWG-Paar, verlegt 151 mm) bei 10 A. 4. Warum verweigert die Firmware ohne den INA260 das Ansteuern der Servos, obwohl der INA260 keinen Servostrom misst? 5. Warum wird der Pi über zwei 5-V-Pins statt über einen versorgt?
Antworten 1. Der Loop-Key öffnet den Servozweig, sodass die UBECs und alle 12 Servos stromlos werden. Der Logikzweig (Pi, XIAO, Sensoren, LCD) läuft weiter. 2. Die Sicherung darf nicht über dem liegen, was der geschützte 18-AWG-Draht tragen kann (16 A). 7,5 A liegt über der Last von 2,74 A und unter 16 A; bei 20 A würde der Draht überhitzen, bevor die Sicherung auslöst. 3. $R \approx 0.151\,\mathrm{m} \times 21\,\mathrm{m\Omega/m} \approx 3.2\,\mathrm{m\Omega}$ pro Leiter; $\Delta V \approx 10\,\mathrm{A} \times 3.2\,\mathrm{m\Omega} \times 2 \approx 63\,\mathrm{mV}$ (mit der Zuschnittlänge von 180 mm als obere Schranke etwa 76 mV). 4. Er misst die Akkuspannung. Ohne ihn kann die Unterspannungsabschaltung nicht arbeiten, und der Akkupack könnte tiefentladen werden. 5. Um den Strom pro 22-AWG-Draht und Dupont-Kontakt (je etwa 1,6 A) und den Spannungsabfall zu halbieren, damit der Pi über seiner Unterspannungsschwelle bleibt.
## Weiterführende Literatur {#further-reading} - [TI INA260 Datenblatt](https://www.ti.com/lit/ds/symlink/ina260.pdf) - [Pololu D36V50F5 5 V 5,5 A Abwärtsregler](https://www.pololu.com/product/4091) - [Pololu Big Pushbutton Power Switch HP (#2813)](https://www.pololu.com/product/2813) - [Hobbywing UBEC-10A](https://www.hobbywing.com/en/products/ubec-10a-2-6s152) - Verwandte Seiten: [Akkus](batteries.md), [Servos](servos.md), [Kabelmanagement](../making/cable-management.md), [Elektronik, Verkabelung und Stromversorgung](../../electronics.md#wiring-harness), [Verkabelungsprüfung](../../verification/wiring.md), [Sicherheit](../making/safety.md) - Horowitz und Hill, *The Art of Electronics*, 3. Aufl., Cambridge University Press (ohmsches Gesetz, Spannungsregler, Schaltwandler) --- # Sensoren {#sensors} Über Sensoren weiß der Roboter überhaupt etwas über sich und seine Umgebung. Hobby-Servos melden nichts zurück, daher setzt Strido auf vier Sensoren: eine IMU für die Körperlage, ein 2D-LiDAR für Abstände, eine Weitwinkelkamera für Bilder und einen Power-Monitor für den Akku. Diese Seite erklärt, wie jeder davon funktioniert, wo er sitzt und welche Software seine Daten nutzt. ::: tip In Strido | Sensor | Stücklistenzeile | Angeschlossen an | ROS-2-Topic | Frame | |---|---|---|---|---| | Adafruit LSM6DSOX 6-DoF IMU (4438) | `lsm6dsox` | XIAO, I²C 0x6A | `/imu/data` | `imu_link` | | Slamtec RPLIDAR C1 + USB-Adapter | `rplidar_c1` | Pi USB, `/dev/rplidar` | `/scan` | `lidar_link` | | Raspberry Pi Camera Module 3 Wide | `camera_module_3_wide` | Pi CSI, FFC 22→15 Pin | `/camera/image_raw` | `camera_optical_frame` | | Adafruit INA260 Power-Monitor (4226) | `ina260` | XIAO, I²C 0x41 | `/battery_state` | — | Sichtfeldprüfungen: `docs/verification/sensors.md`. Firmware-Einrichtung: `firmware/strido_esp32s3/src/main.cpp`. ::: ## IMU: LSM6DSOX Beschleunigungssensor und Gyroskop {#imu-lsm6dsox-accelerometer-and-gyroscope} Eine **IMU** (inertiale Messeinheit) misst Bewegung von innen, ohne externe Referenz. Der LSM6DSOX ist eine 6-DoF-IMU: zwei 3-Achsen-MEMS-Sensoren in einem Chip. | Sensor | Misst | Einheit | Einstellung in Strido | |---|---|---|---| | Beschleunigungssensor | spezifische Kraft: Schwerkraft plus jede Beschleunigung | m/s² (g) | Bereich ±8 g, Ausgabedatenrate 416 Hz | | Gyroskop | Winkelgeschwindigkeit um jede Achse | rad/s (°/s) | Bereich ±1000 °/s, Ausgabedatenrate 416 Hz | Die Firmware liest beide alle 5 ms (200 Hz). Da der Chip mit 416 Hz läuft, liefert jeder Lesevorgang einen frischen Messwert. ### Montage und Achsen {#mounting-and-axes} Die IMU sitzt in einer Tasche im `electronics_deck`, Chipseite oben, die STEMMA-QT-Buchsen nach hinten, gehalten von zwei M2.5 × 6 Schrauben. So montiert zeigt ihre x-Achse zur linken Seite des Roboters und ihre y-Achse nach hinten. Die Firmware dreht jeden Messwert in die `base_link`-Konvention des Roboters (x nach vorne, y nach links, z nach oben, REP-103): $$ \begin{pmatrix} x \\ y \\ z \end{pmatrix}_\mathrm{base} = \underbrace{\begin{pmatrix} 0 & -1 & 0 \\ 1 & 0 & 0 \\ 0 & 0 & 1 \end{pmatrix}}_{\mathbf{R}_\mathrm{base,imu}} \begin{pmatrix} x \\ y \\ z \end{pmatrix}_\mathrm{imu} $$ also $x_\mathrm{base} = -y_\mathrm{imu}$, $y_\mathrm{base} = x_\mathrm{imu}$, $z_\mathrm{base} = z_\mathrm{imu}$. Die Matrix $\mathbf{R}_\mathrm{base,imu}$ ist eine Drehung um $+90^\circ$ um $z$; dieselbe Matrix wird auf die Vektoren von Beschleunigungssensor und Gyroskop angewendet. Rotationsmatrizen werden unter [Koordinatensysteme und Rotationen](../theory/frames-and-rotations.md) erklärt. Ein falsches Vorzeichen ließe den Roboter glauben, er kippe in die andere Richtung – der klassische erste Fehler in jedem Balance-Controller. ### Von zwei Sensoren zu einer Orientierung {#from-two-sensors-to-one-orientation} Keiner der beiden Sensoren allein liefert eine gute Orientierung: - **Der Beschleunigungssensor** misst in Ruhe nur die Schwerkraft, daher folgen Roll- und Nickwinkel direkt daraus, wohin „unten“ zeigt. Beim Gehen fügt jeder Schritt Beschleunigung hinzu, daher ist diese Schätzung verrauscht. - **Das Gyroskop** ist glatt und schnell. Die Integration der Winkelgeschwindigkeit über die Zeit ergibt die Winkeländerung, doch jeder kleine Offset integriert sich zu einer stetig wachsenden **Drift**. **Sensorfusion** kombiniert beide: Über kurze Zeiten dem Gyroskop vertrauen und den Beschleunigungssensor die Schätzung langsam zurück zum wahren „unten“ ziehen lassen. Die einfachste Form ist der **Komplementärfilter** für einen Winkel $\theta$ (etwa den Nickwinkel), aktualisiert in jedem Zeitschritt $\Delta t$: $$ \hat\theta_k = \alpha\left(\hat\theta_{k-1} + \omega_k\,\Delta t\right) + (1 - \alpha)\,\theta_{\mathrm{acc},k}, \qquad \theta_\mathrm{acc} = \operatorname{atan2}\!\left(-a_x,\ \sqrt{a_y^2 + a_z^2}\right) $$ Der erste Term integriert die Gyro-Rate $\omega$; der zweite ist die Neigung, berechnet aus der Schwerkraftrichtung im Messwert $\mathbf{a}$ des Beschleunigungssensors. Mit $\alpha$ nahe 1 ist der Filter ein Hochpass für das Gyroskop und ein Tiefpass für den Beschleunigungssensor, daher der Name: Die beiden Filter ergänzen sich zu eins. Die Übergangszeitkonstante ist $\tau = \alpha\,\Delta t / (1 - \alpha)$; zum Beispiel ergibt $\alpha = 0.98$ bei $\Delta t = 5\,\mathrm{ms}$ den Wert $\tau \approx 0.25\,\mathrm{s}$, sodass Gyro-Drift innerhalb etwa einer Viertelsekunde korrigiert wird, während kürzere Erschütterungen durch Schritte geglättet werden. Strido betreibt auf dem XIAO einen **Mahony-Filter** (`Adafruit_Mahony`) mit 200 Hz, die 3D-Quaternionen-Form derselben Idee. Er integriert das Gyroskop und führt den Fehler $\mathbf{e} = \mathbf{g}_\mathrm{meas} \times \hat{\mathbf{g}}$ zwischen vorhergesagter und gemessener Schwerkraftrichtung als Korrektur auf die Rate zurück: $$ \boldsymbol{\omega}_\mathrm{corr} = \boldsymbol{\omega}_\mathrm{gyro} + K_\mathrm{p}\,\mathbf{e} + K_\mathrm{i} \int \mathbf{e}\,\mathrm{d}t $$ Die Proportionalverstärkung $K_\mathrm{p}$ legt fest, wie stark der Beschleunigungssensor zieht, und die optionale Integralverstärkung $K_\mathrm{i}$ kann einen konstanten Gyro-Offset lernen. Die Firmware nutzt die Standardwerte der Bibliothek: $K_\mathrm{p} = 0.5$ und $K_\mathrm{i} = 0$, also kein Lernen des Offsets. [State Estimation](../theory/state-estimation.md) leitet beide Filter her und vergleicht sie mit dem Kalman-Filter. Das Ergebnis ist ein **Quaternion**, eine Darstellung der 3D-Orientierung mit vier Zahlen ohne Gimbal-Lock-Probleme. Es wird im `STATE`-Frame mit 100 Hz übertragen und zusammen mit den Roh-Gyro- und Beschleunigungswerten als `/imu/data` veröffentlicht. ::: warning Der Gierwinkel ist nicht beobachtbar Die Schwerkraft liefert Roll- und Nickwinkel, sagt aber nichts über die Ausrichtung (Gierwinkel). Ohne Magnetometer driftet die Gierwinkel-Schätzung der IMU. Für die Ausrichtung über längere Zeit verwenden Sie das LiDAR (Scan-Matching / SLAM). ::: ### Wer sie nutzt {#who-uses-it} - **`policy_node`** (gelernter Controller) wandelt das Quaternion in die Schwerkraftrichtung im Körperkoordinatensystem um und speist sie zusammen mit den Gyro-Raten in jedem 50-Hz-Schritt in die Observation der Policy ein. Er startet erst, wenn er IMU-Daten gesehen hat. - **`strido-cli monitor`** zeigt Roll- und Nickwinkel am Prüfstand. - **`mcu_bridge`** veröffentlicht nie eine vorgetäuschte aufrechte Orientierung: Meldet die IMU einen Fehler (`imu_ok` false), wird `/imu/data` einfach nicht veröffentlicht. ## LiDAR: RPLIDAR C1 {#lidar-rplidar-c1} Ein **2D-LiDAR** dreht einen Laser-Entfernungsmesser und misst unter jedem Winkel in einer horizontalen Ebene den Abstand zum nächsten Objekt. Der C1 misst die **Laufzeit** (DTOF): Er misst, wie lange ein 905-nm-Infrarot-Laserpuls für den Rückweg braucht. | Spezifikation (Slamtec-Datenblatt) | Wert | |---|---| | Reichweite | 0,05–12 m (weißes Ziel), 0,05–6 m (schwarzes Ziel) | | Abtastrate | 5000 Messpunkte/s | | Scanfrequenz | typisch 10 Hz (8–12 Hz) | | Winkelauflösung | 0,72° bei 10 Hz | | Genauigkeit | ±30 mm | | Schnittstelle | 3,3 V TTL-UART, 460 800 Baud (hier über einen USB-Adapter) | | Versorgung | 5 V, etwa 230 mA im Betrieb, etwa 800 mA beim Anlauf | | Lasersicherheit | IEC 60825 Klasse 1 | Die Zahlen passen zusammen: $\dfrac{5000\,\mathrm{samples/s}}{10\,\mathrm{scans/s}} = 500$ Punkte pro Scan und $360^\circ / 500 = 0.72^\circ$ zwischen den Punkten. Die Laufzeit ergibt den Abstand als $d = c\,\Delta t / 2$ (das Licht läuft hin und zurück); bei der maximalen Reichweite von 12 m dauert der Hin- und Rückweg nur $\Delta t = 2d/c \approx 80\,\mathrm{ns}$. ### Platzierung {#placement} Ein LiDAR sieht nichts unterhalb oder oberhalb seiner Scanebene, und alles am Roboter selbst, was die Ebene kreuzt, blendet einen Teil des Scans aus. Strido hebt den C1 auf einem 14 mm hohen `lidar_pedestal` auf `top_shell_sensor` an. Seine Scanebene liegt 71,6 mm über den Hüftachsen, im Stand bei 170 mm etwa 254 mm über dem Boden. Die Raycast-Prüfung in `docs/verification/sensors.md` blockiert in jeder Pose **0 von 720** Teststrahlen: Stand, Hocke, Scheitel der Trot-Schwungphase, maximale Schrittweite und abgespreizte Hüften. ### Wer sie nutzt {#who-uses-it-1} `sllidar_ros2` veröffentlicht `/scan` (`sensor_msgs/LaserScan`) mit 10 Hz in `lidar_link`. Das Topic `/scan` folgt den Go2-Konventionen, daher laufen Standard-ROS-2-Werkzeuge unverändert: SLAM zum Kartenaufbau, Nav2 für Hindernisvermeidung und Pfadplanung. Das ist wichtig, weil `/odom` von `gait_node` nur die *befohlene* Geschwindigkeit integriert (Koppelnavigation, kein Schlupfmodell). Für echte Navigation sollte eine LiDAR-basierte Odometrie- oder SLAM-Quelle sie ersetzen (Docstring von `gait_node.py`). ## Kamera: Camera Module 3 Wide {#camera-camera-module-3-wide} | Spezifikation (Raspberry-Pi-Produktbeschreibung) | Wert | |---|---| | Sensor | Sony IMX708, 11,9 MP (4608 × 2592), rückseitig belichtet, gestapelt | | Objektiv | 2,75 mm, F2.2 | | Sichtfeld | 120° diagonal, 102° horizontal, 67° vertikal | | Fokus | Phasenerkennungs-Autofokus, 5 cm bis unendlich | | Videomodi | 1080p50, 720p100, 480p120 | | Schnittstelle | MIPI CSI-2, 15-Pin-FPC 1 mm | Die **Wide**-Variante wurde gewählt, weil ein kleiner, bodennaher Roboter mit 102° horizontalem Sichtfeld mehr von seiner Umgebung sieht als mit den 66° des Standardmoduls. ### Platzierung {#placement-1} Die Kamera sitzt auf einer neigbaren Halterung (`camera_mount_base` und `camera_tilt_plate`) auf der flachen Oberseite der Frontschale. Ein M3 × 40 Drehbolzen mit Sicherungsmutter ergibt eine Reibungsneigung. Im ersten Entwurf saß die Kamera auf der Oberschale, wo die Raycast-Prüfung ergab, dass die eigene Nase des Roboters **42 %** des Bilds füllte. Die neue Position zeigt in jeder geprüften Pose **0 %** (`docs/design.md`, `docs/verification/sensors.md`). ### Wer sie nutzt {#who-uses-it-2} `camera_ros` veröffentlicht `/camera/image_raw` in `camera_optical_frame`. Auf dem Pi 5 benötigt die Kamera den Raspberry-Pi-Fork von libcamera, daher wird der Node auf dem Host gebaut und mit `camera:=true` aktiviert (Standard false; das Docker-Image hat keinen Kamera-Node). Die Kamera ist für Ihre eigenen Wahrnehmungs-Nodes da: Video für die Fernsteuerung, Objekterkennung, visuelle Navigation. ## Power-Monitor: INA260 {#power-monitor-ina260} Der INA260 misst **Spannung und Strom** mit einem eingebauten 2-mΩ-Shunt-Widerstand, 1,25 mA Stromauflösung, bis 15 A und 36 V. In Strido sitzt er High-Side im Logikzweig (siehe [Stromversorgung](power.md)): - **Busspannung = Akkuspannung** (abzüglich winziger Verluste). Die Firmware liest sie alle 100 ms. Sie warnt bei 6,8 V und entspannt die Servos nach 5 aufeinanderfolgenden Messwerten unter 6,4 V. - **Strom = nur Strom des Logikzweigs.** Der Servostrom fließt an ihm vorbei. `mcu_bridge` veröffentlicht beides als `/battery_state` (`sensor_msgs/BatteryState`, Technologie LiPo, negativer Strom = Entladen). Die Firmware verweigert ohne ihn die Ansteuerung der Servos, weil ein Roboter ohne Spannungssensor seinen LiPo bis zur Schädigung entladen kann. ## Zusammenfassung: vom Sensor zur Software {#summary-sensor-to-software} | Sensor | Gelesen von | Rate | Software, die ihn nutzt | |---|---|---|---| | LSM6DSOX | XIAO, I²C | 200 Hz, veröffentlicht mit 100 Hz | Mahony-Filter → `/imu/data` → `policy_node`, Überwachung | | INA260 | XIAO, I²C | 10 Hz | Unterspannungswarnung und -abschaltung, `/battery_state` | | RPLIDAR C1 | Pi, USB seriell | 10 Hz Scans | `/scan` → SLAM, Nav2, Hindernisvermeidung | | Camera Module 3 Wide | Pi, CSI | Videorate | `/camera/image_raw` → Ihre Wahrnehmungs-Nodes | ## Selbsttest {#check-yourself} 1. Warum liefert der Beschleunigungssensor allein keine zuverlässige Orientierung, während der Roboter trabt? 2. Was bestimmt im Mahony-Filter die Proportionalverstärkung, und was würde eine Integralverstärkung ungleich null hinzufügen? 3. Wie viele Punkte enthält ein C1-Scan bei 10 Hz, und wie groß ist ihr Winkelabstand? 4. Warum wurde die Kamera von der Oberschale auf die Frontschale verlegt? 5. Welche Ausrichtungsinformation kann die IMU *nicht* liefern, und welcher Sensor schließt die Lücke?
Antworten 1. In Bewegung misst er zusätzlich zur Schwerkraft die Beschleunigungen der Schritte, daher ist die gemeldete Richtung „unten“ verrauscht. 2. Die Proportionalverstärkung bestimmt, wie stark die Schwerkraftrichtung des Beschleunigungssensors die vom Gyroskop integrierte Schätzung zurückzieht. Eine Integralverstärkung ungleich null würde zusätzlich einen konstanten Gyro-Offset lernen; Strido belässt sie bei 0. 3. $5000 / 10 = 500$ Punkte, $0.72^\circ$ voneinander entfernt. 4. Auf der Oberschale füllte die Nase des Roboters 42 % des Bilds; auf der Frontschale füllt sie 0 %. 5. Der Gierwinkel (Ausrichtung) ist aus der Schwerkraft nicht beobachtbar und driftet; das LiDAR (Scan-Matching oder SLAM) liefert ihn.
## Weiterführende Literatur {#further-reading} - [LSM6DSOX-Produktseite (STMicroelectronics)](https://www.st.com/en/mems-and-sensors/lsm6dsox.html) - [Adafruit-LSM6DSOX-Anleitung](https://learn.adafruit.com/lsm6dsox-and-ism330dhc-6-dof-imu) - [RPLIDAR-C1-Datenblatt (Slamtec)](https://wiki.slamtec.com/download/attachments/83066883/SLAMTEC_rplidar_datasheet_C1_v1.0_en.pdf?api=v2&modificationDate=1700531479533&version=1) - [Produktbeschreibung Camera Module 3 (Raspberry Pi)](https://pip.raspberrypi.com/documents/RP-008151-DS-camera-module-3-product-brief.pdf) - [Open-Source-Algorithmen für IMU und AHRS (x-io, inkl. Mahony)](https://x-io.co.uk/open-source-imu-and-ahrs-algorithms/) - Verwandte Seiten: [Busse](buses.md), [Stromversorgung](power.md), [ROS 2](../software/ros2.md), [Kinematik und Gaits](../software/kinematics-and-gaits.md) - Theorie: [Koordinatensysteme und Rotationen](../theory/frames-and-rotations.md), [State Estimation](../theory/state-estimation.md) --- # Servos {#servos} Ein Hobby-Servo ist ein kleiner Getriebemotor mit eigenem Positionsregler: Sie senden ihm eine Pulsbreite, er dreht seine Abtriebswelle auf den passenden Winkel und hält ihn dort. Strido verwendet zwölf davon, einen pro Gelenk, und alles an der Bewegung des Roboters beginnt damit, wie diese Servos angesteuert werden. ::: tip In Strido - **Teil:** Digitalservo SPT5435LV-180W, 13 gekauft (12 + 1 Reserve), Stücklistenposition `servo_spt5435lv` in `hardware/bom.yaml`. - **Gelenke:** Hüfte (Abduktion), Oberschenkel und Kniekurbel an jedem Bein, FL, FR, RL, RR. PCA9685-Kanäle 4–15 (`hardware/electronics.yaml`, `servos.channels`). - **Signal:** PCA9685-PWM-Treiber mit 200 Hz, 500–2500 µs, 3,3-V-Logikpegel, freigegeben über die Leitung XIAO D3 → PCA9685 OE. - **Stromversorgung:** die 6,0-V-Servoschiene aus zwei Hobbywing UBEC-10A, je sechs Servos, über die WAGO-Busse im vorderen und hinteren Hohlraum. - **Servohörner:** 25T-Aluminium-Scheibenhörner (8) für Hüfte und Oberschenkel, 25T-Aluminium-Klemmarmhörner (4) für die Kniekurbel. - **Code:** `firmware/strido_esp32s3/lib/strido_core/src/servo_map.cpp` (Winkel → Puls), `strido-cli center` / `calibrate`. ::: ## Was in einem Hobby-Servo steckt {#what-is-inside-a-hobby-servo} Ein Servo packt vier Dinge in ein Gehäuse von 40,5 × 20 × 40,5 mm (72 g beim SPT5435LV): 1. **DC-Motor.** Der SPT5435LV verwendet einen Motor mit Eisenanker (cored). 2. **Getriebe.** Ganzmetall-Zahnräder tauschen Geschwindigkeit gegen Drehmoment. Die Abtriebswelle trägt eine Verzahnung mit 25 Zähnen (Futaba 25T) und läuft in zwei Kugellagern (2BB). 3. **Potentiometer.** Es sitzt auf der Abtriebswelle und wandelt den Wellenwinkel in eine Spannung, sodass der Servo immer weiß, wo sein Abtrieb steht. 4. **Steuerplatine.** Sie vergleicht den befohlenen Winkel (aus der Pulsbreite) mit dem gemessenen Winkel (vom Potentiometer) und treibt den Motor, um die Differenz zu schließen. Das ist ein geschlossener Positionsregelkreis *im* Servo. Der Regelkreis verlässt den Servo nie. Der Roboter *befiehlt* nur Winkel und kann sie nicht zurücklesen, daher meldet `/joint_states` die von der Firmware nach der Begrenzung befohlenen Winkel, keine gemessenen (`docs/software.md`). ### Analog vs. digital {#analogue-vs-digital} Ein Analogservo aktualisiert seine Motoransteuerung im Takt der eintreffenden Pulse. Ein Digitalservo hat einen Mikrocontroller, der den Puls abtastet und den Motor mit einer viel höheren internen Rate neu ansteuert. Das Ergebnis ist ein steiferes Halten, ein kleinerer Totbereich und schnellere Reaktion. Der Preis ist ein höherer Ruhestrom: Die SPT-Seite nennt 100 mA Ruhestrom. Bei einem laufenden Roboter verhindert gerade das steife Halten, dass ein Bein unter Last absackt. ## Das Pulsbreitensignal (PWM) {#the-pulse-width-signal-pwm} Der Servo liest die **Breite** eines sich wiederholenden Logikpulses, nicht seine Frequenz oder sein Tastverhältnis: | Pulsbreite | Welle des SPT5435LV-180W | |---|---| | 500 µs | ein Ende (−90° von neutral) | | 1500 µs | Neutralpunkt (Mitte) | | 2500 µs | anderes Ende (+90°) | Innerhalb dieses Fensters ist die Zuordnung linear: Der Winkel $\theta$ aus der Neutralstellung ist proportional dazu, wie weit die Pulsbreite $t_\mathrm{p}$ von $1500\,\mu\mathrm{s}$ entfernt ist, $$ \theta = \frac{t_\mathrm{p} - 1500\,\mu\mathrm{s}}{k}, \qquad k = \frac{2500\,\mu\mathrm{s} - 500\,\mu\mathrm{s}}{180^\circ} \approx 11.1\,\mu\mathrm{s}/^\circ = \frac{2000\,\mu\mathrm{s}}{\pi\,\mathrm{rad}} \approx 636.6\,\mu\mathrm{s/rad} $$ Die Radiant-Form von $k$ ist die Konstante `kUsPerRad` in `servo_map.h`. Der Puls wiederholt sich mit fester Rate. Klassische RC-Technik sendet alle 20 ms einen Puls (50 Hz). Der SPT5435LV akzeptiert bis zu 330 Hz, und Strido läuft mit **200 Hz** (`kServoFrequencyHz`), ein neuer Puls alle $T = 1/f = 5\,\mathrm{ms}$. Das passt zur 200-Hz-Regelschleife der Firmware, sodass jedes neue Gelenkziel den Servo im nächsten Frame erreicht. Allgemein in PWM-Begriffen hat ein Puls der Breite $t_\mathrm{p}$, der alle $T$ wiederholt wird, ein **Tastverhältnis** $D = t_\mathrm{p}/T$. Der Neutralpuls bei 200 Hz ist $D = 1500\,\mu\mathrm{s} / 5000\,\mu\mathrm{s} = 30\,\%$, die Extreme 10 % und 50 %. Der Servo ignoriert $D$ und misst nur $t_\mathrm{p}$, weshalb der Wechsel der Framerate von 50 Hz auf 200 Hz die Welle nicht bewegt, solange die Lücke zwischen den Pulsen lang genug bleibt, damit der Servo jeden einzeln erkennt. ::: warning Kaufen Sie die richtige Winkelvariante Derselbe Pulsbereich bedeutet bei verschiedenen Varianten unterschiedliche Winkel. Bei einem 270°-Servo würden 500–2500 µs 270° abdecken, und jede Gelenkzuordnung wäre falsch. Die Stückliste verlangt die Variante **-180W**; bestätigen Sie den Winkel bei jedem Nicht-SPT-Händler (`hardware/bom.yaml`, Hinweis zu `servo_spt5435lv`). ::: ### Auflösung und Totbereich {#resolution-and-dead-band} Der **Totbereich** ist die kleinste Änderung der Pulsbreite, auf die der Servo reagiert. Die SPT-Seite nennt 4 µs, etwa 0,36°. Der PCA9685, der die Pulse erzeugt, teilt jede Periode in 4096 Schritte (12 Bit): $$ \Delta t_\mathrm{step} = \frac{T}{2^{12}} = \frac{T}{4096} $$ $$ 200\,\mathrm{Hz}:\ \frac{5000\,\mu\mathrm{s}}{4096} \approx 1.22\,\mu\mathrm{s}, \qquad 50\,\mathrm{Hz}:\ \frac{20\,000\,\mu\mathrm{s}}{4096} \approx 4.88\,\mu\mathrm{s} $$ Bei 200 Hz entspricht ein Schritt $1.22\,\mu\mathrm{s} / 636.6\,\mu\mathrm{s/rad} \approx 1.9\,\mathrm{mrad} \approx 0.11^\circ$ Wellenweg. Bei 50 Hz wäre ein Schritt bereits breiter als der Totbereich; bei 200 Hz löst der Treiber etwa drei Schritte darin auf. Die höhere Framerate bringt sowohl schnellere Aktualisierungen als auch feinere Positionierung. ### Signalpegel {#signal-level} Die SPT-Seite spezifiziert einen PWM-Signalpegel von 3,3–5,0 V. Der PCA9685 läuft am 3,3-V-Spannungsregler des XIAO, daher sind seine Pulse genau 3,3 V hoch: innerhalb der Spezifikation, aber ohne Reserve. `docs/verification/electronics.md` markiert diese Prüfung als „bestanden, keine Reserve“. Wenn ein Servo zittert, messen Sie zuerst die 3V3-Schiene des XIAO. ## Drehmoment, Geschwindigkeit und Strom {#torque-speed-and-current} | Spezifikation (SPT-Datenblattseite) | 4,8 V | 6,0 V | |---|---|---| | Blockiermoment | 29 kg·cm | 35 kg·cm | | Geschwindigkeit (ohne Last) | 0,16 s / 60° | 0,14 s / 60° | | Nennstrom | | 1,4 A | | Blockierstrom | | 3,5 A | ### Blockiermoment in SI-Einheiten {#stall-torque-in-si-units} Hobby-Servos geben das Drehmoment in kg·cm an: das Gewicht einer Masse in Kilogramm an einem Arm in Zentimetern. Drehmoment ist Kraft mal Hebelarm, $\tau = F r$, und die Kraft von 1 kg ist ihr Gewicht $m g$, also $$ 1\,\mathrm{kg\,cm} = 1\,\mathrm{kg} \times 9.81\,\mathrm{m/s^2} \times 0.01\,\mathrm{m} = 0.0981\,\mathrm{N\,m} $$ $$ 35\,\mathrm{kg\,cm} \times 0.0981\,\frac{\mathrm{N\,m}}{\mathrm{kg\,cm}} = 3.43\,\mathrm{N\,m} $$ Das **Blockiermoment** ist das Maximum, das der Servo drücken kann, wenn er sich gar nicht bewegt. Es ist eine Grenze, kein Arbeitspunkt. In MuJoCo braucht das stehende Knie etwa **0,7 N·m**, grob ein Fünftel des Blockiermoments (`docs/electronics.md`). Diese Reserve erlaubt dem Roboter zu traben, sich von einem Stolpern zu erholen und seine 3,07 kg zu tragen (`docs/design.md`). ### Der Strom folgt dem Drehmoment {#current-follows-torque} Das Drehmoment eines DC-Motors ist proportional zu seinem Strom, $\tau_\mathrm{m} = k_\mathrm{t}\, I$, mit der Drehmomentkonstante $k_\mathrm{t}$ des Motors; das Getriebe multipliziert das Motormoment mit seiner Übersetzung. Der Strom steigt also grob proportional zum gelieferten Drehmoment, und beim vollen Blockiermoment zieht der SPT5435LV seinen **Blockierstrom**, 3,5 A. Deshalb berücksichtigt die Auslegung der Stromversorgung Blockierfälle: $$ 6 \times 3.5\,\mathrm{A} = 21\,\mathrm{A} > 15\,\mathrm{A}\ \text{(UBEC peak rating)}, \qquad 12 \times 3.5\,\mathrm{A} = 42\,\mathrm{A}\ \text{total} $$ Ein Servo, der gegen einen harten Anschlag drückt oder gegen ein anderes Bein arbeitet, liegt beim Blockierstrom und erhitzt sich schnell. Daraus folgen zwei Regeln in der Dokumentation: - Stecken Sie den Loop-Key **nie** ein, während Positionsbefehle laufen: Alle zwölf Servos würden gleichzeitig springen. - Befehlen Sie **nie** alle Beine in harte Anschläge. Die Firmware begrenzt außerdem die Gelenkgeschwindigkeit auf **6 rad/s** (`max_joint_speed_rad_s` in `safety.h`), unter der Leerlaufgeschwindigkeit des Servos bei 6 V, $\omega_0 = 60^\circ / 0.14\,\mathrm{s} = (\pi/3)\,\mathrm{rad} / 0.14\,\mathrm{s} \approx 7.5\,\mathrm{rad/s}$. Plötzliche Sprünge würden sonst Stromstöße nahe dem Blockierstrom ziehen. Das Drehmoment eines DC-Motors fällt grob linear vom Blockiermoment bei Drehzahl null auf null bei $\omega_0$, $\tau(\omega) \approx \tau_\mathrm{stall}(1 - \omega/\omega_0)$; siehe [Statik und Dynamik](../theory/statics-and-dynamics.md). ## Die 6-V-Servoschiene {#the-6-v-servo-rail} Der SPT5435LV ist **nur für 4,8–6,0 V** ausgelegt. Der 2S-LiPo schwankt zwischen 8,4 V (voll) und 6,4 V (Abschaltung), also immer über diesem Bereich. Ein direkter Anschluss an den Akkupack würde jeden Servo mit Überspannung betreiben. Zwei Hobbywing-UBEC-10A-Spannungsregler setzen den Akkupack daher auf 6,0 V herab: - Der **Ausgangs-Jumper des UBEC bleibt offen**: Das wählt 6,0 V. Die Einstellung 7,4 V würde die Servos zerstören. - Messen Sie jeden UBEC ohne Last, bevor Sie Servos anschließen, und akzeptieren Sie nur **5,8–6,0 V** ([Elektronik › Kabelbaum](../../electronics.md#wiring-harness), Schritt 2). - Unter Last bei fast leerem Akkupack wird erwartet, dass die Schiene auf etwa **5,4 V** einbricht (Schätzung in `hardware/electronics.yaml`). Der Servo ist dann noch im Bereich, aber schwächer: Das Drehmoment fällt grob mit der Spannung (29 kg·cm bei 4,8 V gegenüber 35 kg·cm bei 6 V). Der PCA9685 führt **nur das Signal**. Der Servostrom fließt UBEC → WAGO-Bus → rote/braune Drähte des Servos und nie durch eine Logikplatine. Der V+-Pin an der PCA9685-Stiftleiste bleibt unbenutzt. Mehr Details unter [Stromversorgung](power.md). ## Servohörner und die 25T-Verzahnung {#horns-and-the-25t-spline} Das **Servohorn** koppelt die Abtriebsverzahnung des Servos mit der Struktur des Roboters. Strido verwendet Aluminiumhörner, weil gedruckte Teile, die an ein Kunststoffhorn geschraubt sind, die Verzahnung abscheren oder sich verbiegen würden. | Servohorn | Anz. | Gelenk | Befestigt mit | |---|---|---|---| | 25T-Aluminium-Scheibenhorn | 4 | Oberschenkel: Femur und Femur-Servoverbinder, 4 × M3 × 20 | M3 × 8 Zentralschraube | | 25T-Aluminium-Scheibenhorn | 4 | Hüfte: Beinmodul, 2 × M3 × 8 | M3 × 8 Zentralschraube | | 25T-Aluminium-Klemmarmhorn | 4 | Kniekurbel | M3 × 8 Zentralschraube | **25T** bedeutet 25 Zähne an der Verzahnung. Jeder Zahn entspricht $360^\circ / 25 = 14.4^\circ$, das Servohorn kann also nur in Schritten von 14,4° sitzen. Ein „um einen Zahn versetzt“ aufgestecktes Servohorn ist um 14,4° falsch, etwa $14.4^\circ \times 11.1\,\mu\mathrm{s}/^\circ \approx 160\,\mu\mathrm{s}$ Puls. Servohörner eines anderen Verzahnungsstandards (zum Beispiel 24T oder 23T) passen nicht richtig und scheren ab. Schrauben, die aus Stahl in das Aluminium-Servohorn gehen, erhalten einen Tropfen **mittelfeste Schraubensicherung**: Metall-Metall-Verbindungen vibrieren sich sonst los (`docs/assembly/README.md`). ## Zentrieren und Kalibrieren {#centring-and-calibration} ### Schritt 1: zentrieren, bevor Sie ein Servohorn montieren {#step-1-centre-before-you-fit-a-horn} Bevor ein Servohorn aufgesteckt wird, wird jeder Servo auf **1500 µs** gefahren, seine Neutralstellung: ```bash strido-cli --port center # 1500 µs on every channel ``` Bei Welle in Neutralstellung wird jedes Servohorn in der **Montage-Referenzpose** aufgesteckt: | Gelenk | Referenz bei 1500 µs | |---|---| | Hüfte | Bein senkrecht | | Oberschenkel | Femur 45° nach hinten | | Kniekurbel | 35° | Das sind die Werte `neutral_hip`, `neutral_thigh` und `neutral_crank` in der generierten Geometrie (0, 0,785 und 0,611 rad). Da die Verzahnung nur Schritte von 14,4° erlaubt, wählen Sie den Zahn, der am nächsten kommt; der Rest wird in Software korrigiert. ### Schritt 2: Feinabgleich in der Firmware {#step-2-trim-in-firmware} Jedes Gelenk hat einen `ServoCalibration`-Datensatz, der im Flash des ESP32 gespeichert ist (`Preferences`): | Feld | Bedeutung | |---|---| | `direction` | +1 oder −1: Gespiegelte Servos links und rechts drehen sich für dieselbe Gelenkbewegung entgegengesetzt | | `neutral_us` | Puls, der das Gelenk auf seinen Referenzwinkel stellt (Standard 1500) | | `zero_rad` | der Referenzwinkel selbst | | `min_us`, `max_us` | hartes Pulsfenster | Die Firmware wandelt einen Aktuatorwinkel in einen Puls um mit: $$ t_\mathrm{p} = t_\mathrm{neutral} + s\, k\, (\theta - \theta_0) $$ mit $t_\mathrm{neutral}$ = `neutral_us`, dem Vorzeichen $s$ = `direction`, $k = 636.6\,\mu\mathrm{s/rad}$ und dem Referenzwinkel $\theta_0$ = `zero_rad`; das Ergebnis wird auf `[min_us, max_us]` begrenzt. Rechenbeispiel: Um einen Oberschenkel mit `direction = +1` von seiner 45°-Referenz auf 60° zu bewegen: $$ \theta - \theta_0 = 60^\circ - 45^\circ = 15^\circ = 0.262\,\mathrm{rad} $$ $$ t_\mathrm{p} \approx 1500\,\mu\mathrm{s} + 0.262 \times 636.6\,\mu\mathrm{s} \approx 1500\,\mu\mathrm{s} + 167\,\mu\mathrm{s} = 1667\,\mu\mathrm{s} $$ Mit `strido-cli calibrate` können Sie jedes `neutral_us` in Schritten von ±5 µs oder ±25 µs verschieben, bis das Gelenk genau in seiner Referenz sitzt, und dann in den Flash speichern. Der Roboter sollte dabei auf einem Ständer mit frei hängenden Beinen stehen. Ein Fehler von einem halben Zahn (7,2°) entspricht etwa 80 µs, gut innerhalb des Abgleichbereichs. Die Kalibrierung gleicht auch kleine chipspezifische Unterschiede im PCA9685-Takt aus, die jeden Puls skalieren. ::: danger Rohpulse umgehen die Gelenkgrenzen `strido-cli center` und `pulse` senden rohe Pulsbreiten. Sie überspringen die Gelenk- und Kniekurbelgrenzen aus dem CAD-Bewegungsbereichs-Sweep. Verwenden Sie sie nur, solange die Servohörner abgenommen sind oder sich die Beine frei bewegen können. ::: ## Selbsttest {#check-yourself} 1. Warum kann der Roboter den wahren Winkel eines Gelenks nicht melden? 2. Welche Pulsbreite sendet die Firmware für ein Gelenk 10° über seiner Referenz, mit `direction = −1` und `neutral_us = 1500`? 3. Warum wird die Servoschiene auf 6,0 V geregelt, statt direkt vom 7,4-V-Akkupack versorgt zu werden? 4. Ein Servohorn sitzt auch nach dem Zentrieren sichtbar schief. Wie groß darf der Fehler sein, bevor Sie es um einen Zahn versetzen sollten? 5. Warum trägt jeder UBEC in `docs/verification/electronics.md` eine Blockierwarnung?
Antworten 1. Die Positionsrückmeldung (Potentiometer) wird nur im Servo verwendet. Nichts liest sie zurück, daher meldet die Firmware die von ihr befohlenen Winkel. 2. $10^\circ = 0.1745\,\mathrm{rad}$; $0.1745 \times 636.6\,\mu\mathrm{s} \approx 111\,\mu\mathrm{s}$; mit Richtung $-1$ ist der Puls $1500 - 111 \approx 1389\,\mu\mathrm{s}$. 3. Der SPT5435LV ist nur für 4,8–6,0 V ausgelegt; der Akkupack liegt im Betrieb bei 6,4–8,4 V und würde ihn mit Überspannung betreiben. 4. Bis zu einem halben Zahn, 7,2° (≈ 80 µs), ist das eine Aufgabe für `strido-cli calibrate`. Darüber hinaus versetzen Sie das Servohorn um einen Zahn (14,4°). 5. Sechs blockierte Servos ziehen $6 \times 3.5\,\mathrm{A} = 21\,\mathrm{A}$, mehr als der Spitzenwert des UBEC von 15 A.
## Weiterführende Literatur {#further-reading} - [SPT5435LV-180W-Spezifikation (SPT Servo)](http://www.spt-servo.com/Product/015234339.html) - [PCA9685-Datenblatt (NXP, Adafruit-Spiegel)](https://cdn-shop.adafruit.com/datasheets/PCA9685.pdf) - [Adafruit-Anleitung zum 16-Kanal-PWM/Servo-Treiber](https://learn.adafruit.com/16-channel-pwm-servo-driver) - [Referenz zu Servoverzahnungen (ServoCity)](https://www.servocity.com/servo-spline-info/) - Verwandte Seiten: [Stromversorgung](power.md), [Mikrocontroller](microcontrollers.md), [Mechanik](mechanics.md), [Elektronik, Verkabelung und Stromversorgung](../../electronics.md) - Theorie: [Regelung](../theory/control.md) (der PD-Regelkreis im Servo), [Statik und Dynamik](../theory/statics-and-dynamics.md) (Gelenkmomente) --- # 3D-Druck {#_3d-printing} Rahmen, Beine und Schalen von Strido sind 67 gedruckte Teile aus 34 Teiletypen, alle per FDM (Fused Deposition Modelling) auf einem gewöhnlichen 220 × 220 mm großen Drucker hergestellt. Diese Seite erklärt die Einstellungen im Kit-Profil, warum jede davon für einen Laufroboter wichtig ist und wie Sie die Druckliste und den Druckbarkeitsbericht lesen. ::: tip In Strido Jedes gedruckte Teil ist in der [Druckliste](../../../hardware/print/print_list.md) mit Anzahl, Farbe, Datei, Größe auf dem Druckbett, Stützen und Hinweisen aufgeführt. Die verifizierten Slicer-Einstellungen stehen in [prusaslicer.ini](../../../hardware/print/prusaslicer.ini); 13 fertige 220 × 220 mm große Druckplatten (10 graphit, 3 limette) sind im [Druckpaket](../../print-kit.md) und im Bausatz enthalten. Die Druckbarkeitsprüfung (`make printability`, Bericht in [Druckbarkeit](../../verification/printability.md)) slict jedes Teil und jede Druckplatte mit PrusaSlicer. Die Seite [Druckpaket](../../print-kit.md) bündelt all das zum Herunterladen. ::: ## Wie FDM funktioniert {#how-fdm-works} Ein FDM-Drucker schiebt ein 1,75 mm dickes Kunststofffilament durch eine heiße Düse (0,4 mm in diesem Kit) und legt es in dünnen Linien ab. Linien bilden eine Schicht; Schichten stapeln sich zum Teil. Daraus folgen drei Konsequenzen, und jede Einstellung unten betrifft eine davon: 1. **Ein Teil ist ein Stapel verschweißter Linien, kein massiver Block.** Es ist entlang der Linien am stärksten und zwischen den Schichten am schwächsten. 2. **Jede Schicht braucht etwas darunter.** Steile Überhänge und frei schwebende Elemente brauchen Stützen. 3. **Geschmolzener Kunststoff fließt und schrumpft.** Löcher werden etwas kleiner als gezeichnet, und die erste Schicht breitet sich aus. ## Das Material: PETG (oder PLA+) {#the-material-petg-or-pla} Die Druckliste erlaubt PETG oder PLA+; das Profil ist auf PETG eingestellt (`filament_type = PETG`, Dichte 1,27 g/cm³). | Eigenschaft | Warum sie für Strido wichtig ist | |---|---| | Zäh statt spröde | Beine nehmen bei jedem Auftreten Stöße auf; PETG biegt sich eher, bevor es bricht | | Gute Schichthaftung | Weniger Risse zwischen den Schichten bei dünnen Koppeln wie `short_link` | | Wärmeformbeständigkeit bei 68 °C (Prusament-PETG-Datenblatt) | Servos und UBECs erwärmen sich im Körper; PLA erweicht bei niedrigerer Temperatur | | Geringer Verzug | Große flache Teile wie `bottom_shell` und `top_shell_sensor` (114 × 208 mm) bleiben eben | | Zieht Fäden und haftet stark auf glattem PEI | Verwenden Sie ein texturiertes oder Satin-Blech oder Klebestift auf glattem PEI | | Stützen sind schwer zu entfernen | Eng anliegende Stützen und sorgfältiger Einsatz des Seitenschneiders (siehe [Werkzeuge](tools-and-workshop.md)) | Temperaturen im Kit-Profil: Düse 235 °C für die erste Schicht, danach 240 °C; Bett durchgehend 80 °C. Prusas PETG-Leitfaden empfiehlt 230/240 °C für die Düse und 85/90 °C für das Bett, die Kit-Werte liegen also im üblichen Bereich; passen Sie das Bett an Ihr Druckblech an, wenn die erste Schicht nicht haftet. ::: warning Trockenes Filament PETG nimmt Feuchtigkeit aus der Luft auf. Feuchtes Filament knackt, zieht Fäden und ergibt schwächere Schichten. Wenn Sie an der Düse Knistern hören, trocknen Sie die Spule, bevor Sie tragende Teile drucken. ::: ## Das Kit-Profil, Einstellung für Einstellung {#the-kit-profile-setting-by-setting} `hardware/print/prusaslicer.ini` spiegelt die Druckliste wider. Laden Sie es in PrusaSlicer über *File > Import > Import Config*. Wenn Sie einen anderen Slicer verwenden, übernehmen Sie diese Werte von Hand. | Einstellung | Wert | Was sie bewirkt und warum dieser Wert | |---|---|---| | Bettgröße | 220 × 220 mm, 250 mm hoch | Die größten Teile (Schalen, 114 × 208 mm) müssen passen; das ist auch die Druckplattengröße | | Düse | 0,4 mm | Die Standarddüse; eine Linie ist etwa 0,45 mm breit | | Schichthöhe | 0,2 mm (erste Schicht 0,2 mm) | Halber Düsendurchmesser: gute Festigkeit und Geschwindigkeit; die Passungs- und Wandprüfungen setzen sie voraus | | Perimeter | 3 (≈ 1,2 mm Wand) | Die Wände tragen den Großteil der Last um Schraubenlöcher; Prusa empfiehlt für feste Teile mehr Perimeter, nicht mehr Füllung | | Perimeter-Generator | Arachne | Variiert die Linienbreite, sodass dünne Wände gefüllt werden, statt Lücken zu lassen | | Massive Ober-/Unterschichten | 5 / 5 (1,0 mm Haut) | Schließt die Füllung mit einer steifen Haut; mit weniger Schichten kann die Füllung oben durchscheinen | | Füllung | 30 % Gyroid | Gyroid ist in alle Richtungen fest und wird gedruckt, ohne dass die Düse ihre eigenen Linien auf gleicher Höhe kreuzt | | Stützen | standardmäßig aus, automatische Erkennung, Stil „snug“ | Die Prüfung schaltet Stützen laut Liste pro Teil ein; eng anliegende Stützen folgen der Teilekontur und lassen sich leichter entfernen | | Brim | standardmäßig 0 | Die Prüfung fügt Teilen, die höher als 40 mm sind, einen 5-mm-Brim hinzu | | Skirt | 1 Umlauf | Füllt die Düse vor, bevor das Teil beginnt | | `gcode_label_objects` | firmware | Ermöglicht es, ein einzelnes fehlgeschlagenes Teil auf einer vollen Druckplatte abzubrechen, ohne den Rest zu stoppen | ## Ausrichtung und Festigkeit der Schichtlinien {#orientation-and-layer-line-strength} Da Schichten schwächer verbunden sind als Linien, ist ein Teil am schwächsten, wenn es so belastet wird, dass sich seine Schichten voneinander lösen würden. Die Kit-STLs sind bereits ausgerichtet, und die Druckliste erklärt jede Wahl in ihrer Spalte *Note*: - **veröffentlichte Ausrichtung**: die eigene Ausrichtung von Upstream-Yertle, beibehalten, wo sie schon gut druckbar ist. Die Notiz nennt, welche Fläche den Überhang verringern würde (z. B. `bottom_shell`: 9 % Überhang wie veröffentlicht, 1 % auf der −Y-Fläche, dann aber 208 mm hoch auf einer schmalen Kante). Weniger Überhang heißt weniger Stützen, ändert aber auch die Schichtrichtung; behalten Sie also die veröffentlichte Ausrichtung, wenn Sie keinen Grund haben. - **neu ausgerichtet**: die veröffentlichte STL war oft die CAD-Lage des Teils, hoch auf kleiner Grundfläche; das Druckpaket legt es auf die Fläche mit dem meisten Bettkontakt und dem geringsten Überhang, nie mit der Längsachse einer Koppel senkrecht (z. B. `inner_tibia` und `outer_tibia` auf ihren flachen Seiten, `short_link`, `femur`, `femur_servo_connector`, `servo_mount_top_bracket`, `side_body_beam`). So kommen die Bohrungen von Femur und Femur-Servoverbinder senkrecht heraus. Die Servohalter liegen wie ein U (offene Seite oben): 19 mm statt 56 mm hoch, 2 % statt 13 % Überhang, und 10 ihrer 13 M3-Vorbohrungen (Servolaschen, Halterung) senkrecht; die zwei Vorbohrungen für das Hüfthorn und die für den Hüftdrehpunkt liegen waagrecht. - **auf der Grundfläche / kopfüber drucken**: `camera_mount_base` steht auf seiner Grundfläche (sein M3-Drehpunkt ist ein Reibgelenk, eine leicht abgeflachte waagrechte Bohrung ist daher in Ordnung; bei Bedarf mit 3,4 mm aufbohren); `lidar_pedestal` wird mit der Deckplatte nach unten gedruckt; `electronics_deck` mit der Oberseite nach unten; `stiff_long_link` liegt flach, beide Buchsenbohrungen senkrecht. Warum eine senkrechte Bohrung? Ein Loch mit senkrechter Achse wird als Stapel von Kreisen gedruckt und wird rund. Ein waagrechtes Loch entsteht aus Schichten, daher muss seine Oberseite überbrückt oder gestützt werden und wird leicht abgeflacht. Bohrungen, die einen Drehpunkt oder ein Lager aufnehmen, sollten nach Möglichkeit senkrecht stehen. ## Stützen und Brims {#supports-and-brims} **Stützen** sind temporäre Strukturen unter Überhängen (Flächen, die steiler sind, als der Drucker überbrücken kann). Die Spalte *Supports* der Druckliste gibt `yes (N % overhang)` an, wobei N der Anteil der Teileoberfläche ist, der Stützen braucht. Das Profil verwendet `support_material_threshold = 0`, also automatische Überhangerkennung, und den Stil „snug“. **Brims** sind ein paar zusätzliche Linien um die erste Schicht, die den Bettkontakt vergrößern. Ein hohes, schmales Teil wirkt als Hebel auf seiner kleinen Grundfläche: Die Düse stößt es los, bevor es fertig ist. Regel in diesem Druckpaket: Brim bei Teilen über 40 mm Höhe, 5 mm breit. Im Druckbarkeitsbericht gilt das zum Beispiel für die Schalen; die Servohalter (19 mm, wie ein U liegend) und `servo_mount_top_bracket` (6 mm, flach) brauchen keinen. **Lochstufen** sind der eine Überhang, den das Druckpaket stattdessen im Modell beseitigt: Wo ein weites Loch auf der Bettseite (ein Lagersitz) in ein kleineres Loch darüber übergeht, hängt der Ring dazwischen in der Luft, und eine Stütze in einem Lagersitz lässt sich schwer herauspulen. Die STLs des Druckpakets schneiden die zwei Schichten über einer solchen Stufe für Brücken aus (der *Lochüberhang-Trick*): Schicht 1 lässt einen Schlitz so breit wie das enge Loch quer über das ganze weite Loch frei, sodass das Material links und rechts davon eine gerade Brücke zwischen seinen Wänden ist; Schicht 2 lässt ein Quadrat so breit wie das enge Loch frei und überbrückt den Schlitz; Schicht 3 ist das enge Loch wie konstruiert. Der Sitzdurchmesser und das enge Loch ändern sich nicht; das Lager liegt dann auf den zwei Sicheln links und rechts des Schlitzes auf. `strido_publish.print_bridges` findet diese Stufen in jedem Teil, so wie es auf dem Bett liegt (derzeit die Lagersitze von `inner_tibia`, `outer_tibia` und `outer_shoulder_frame`); die Druckliste vermerkt jede. In `outer_shoulder_frame` öffnet sich der Sitz zum Bett und wird ganz ohne Stützen gesliced. In den Tibias liegt er unter einem Auge, das über dem Bett schwebt und ohnehin Stützen braucht, und der Slicer füllt auch die Bohrung: Blockieren Sie Stützen in der Lagerbohrung (Support-Blocker oder Aufmalen), dann wird die Stufe überbrückt. Entfernen Sie Stützen und Brims vor der Montage (Montageanleitung, Schritt 0) und entgraten Sie jede Kante, die ein bewegtes Teil berührt. ## Betthaftung und die erste Schicht {#bed-adhesion-and-the-first-layer} Die erste Schicht entscheidet, ob ein Druck gelingt: - Reinigen Sie das Druckblech (Fingerabdrücke sind Öl; PETG und PLA lösen sich beide von fettigen Stellen). - Nivellieren/kalibrieren Sie die erste Schicht, sodass die Linien leicht gequetscht sind, sich aber nicht aufwerfen. - Für PETG auf glattem PEI verwenden Sie Klebestift als Trennschicht: PETG kann so stark haften, dass es die Blechoberfläche herausreißt (Prusa). - Lassen Sie das Bett abkühlen, bevor Sie große Teile wie `bottom_shell` abnehmen. ## Toleranzen: Warum Löcher zu klein werden {#tolerances-why-holes-come-out-small} Geschmolzene Linien werden auf einer Polygon-Näherung eines Kreises abgelegt, und die erste Schicht wird nach außen gequetscht. Beide Effekte machen Löcher kleiner als gezeichnet. Die Strido-Passungsprüfung nimmt an, dass Löcher **0,15 mm zu klein** gedruckt werden (`expected_hole_shrink_mm: 0.15` in `hardware/verification/tolerances.yaml`); ADR-009 merkt an, dass die meisten Drucker kleine Löcher 0,2–0,3 mm zu klein drucken. Was Sie nach dem Druck dagegen tun: | Lochtyp | Abhilfe | Beispiel aus dem Passungsbericht | |---|---|---| | Durchgangsloch (Schraube geht hindurch) | Einmal mit einem Bohrer durchbohren: 3,2 mm für M3, 2,7 mm für M2.5, 2,2 mm für M2 (ISO 273 fein; mittel 3,4 / 2,9 / 2,4 mm) | `bottom_shell`, 4 × M3 mit 3,05 mm im CAD: 3,2 mm bohren | | Kernloch für gewindeformende Schraube (Schraube schneidet ihr eigenes Gewinde) | So belassen; siehe [Befestigungselemente](fasteners.md) | `femur` M3-Kernlöcher, 2,80–2,85 mm im CAD | | Lagersitz (Presspassung) | Vor der Montage zur Probe einpassen; ein lockeres Lager bekommt einen Tropfen CA-Kleber | `outer_shoulder_frame`, 625ZZ (16 mm Außendurchmesser) in einem 16,17–16,21-mm-Sitz | **Elefantenfuß** ist die Aufweitung an der Unterkante eines Teils, verursacht durch die gequetschte erste Schicht und das Gewicht der darüberliegenden Schichten. Er macht nach unten weisende Löcher und Schlitze enger und kann verhindern, dass ein Teil plan aufliegt. Die meisten Slicer haben eine Einstellung *Elefantenfuß-Kompensation*, die die erste Schicht leicht verkleinert; wenn die Unterkante eines Teils ausfranst, schneiden Sie sie mit einem Entgratwerkzeug nach. ::: tip Lochkompensation für die Servohalter Die Druckliste verlangt **X-Y-Lochkompensation −0,15 mm** für `left_servo_mount`, `right_servo_mount`, `left_servo_mount_fl`, `right_servo_mount_fr` und `servo_mount_top_bracket`; damit kommen ihre M3-Vorbohrungen auf etwa 2,65 mm, und die Schrauben greifen (ADR-009). Sie wirkt auf senkrechte Löcher; die Vorbohrungen für Hüfthorn und Hüftdrehpunkt der Servohalter liegen waagrecht, härten Sie diese also mit dünnflüssigem Sekundenkleber, wenn eine Schraube durchdreht. Die Option heißt so in Bambu Studio und OrcaSlicer; nicht jeder Slicer hat eine reine Lochkompensation. Wenn Sie ohne sie drucken, härten Sie diese Vorbohrungen vor dem Eindrehen der Schrauben mit einem Tropfen dünnflüssigem Sekundenkleber, wie in [Verbindungselemente](fasteners.md) erklärt; anaerobe Schraubensicherung ist nicht für Kunststoff. ::: ## Druckplatten und Farben {#plates-and-colours} Das Kit verwendet zwei Farben: **Primär (graphit)** für Rahmen und Beine und **Sekundär (limette)** für Schalen und Schultern. Die 13 fertigen Druckplatten in `hardware/print/plates/` (`plate_graphite_01…10.3mf`, `plate_lime_01…03.3mf`) sind vorab angeordnete 220 × 220 mm große Druckbetten, sodass ein ganzer Roboter kein manuelles Anordnen erfordert. Jede Druckplatte wurde von der Druckbarkeitsprüfung so wie angeordnet geslict und akzeptiert. Filamentbudget: Die Druckliste summiert sich auf 943 cm³ massive Teile (≈ 659 g PETG bei den Kit-Einstellungen). Der Slicer schätzt inklusive Füllung, Stützen und Brims für jedes Teil **958 g und 100 h**. Die Stückliste sieht zwei 1-kg-Spulen vor (eine pro Farbe); die Druckliste plant 1,2 kg inklusive Testdrucken ein. ## Die Druckbarkeitsprüfung {#the-printability-gate} Die Druckbarkeitsprüfung (`python -m strido_verify.printability`, `make printability`) stellt sicher, dass sich das Kit mit genau diesen Einstellungen wirklich drucken lässt: ```mermaid flowchart LR STL["ausgerichtete STLs
+ 3MF-Druckplatten"] --> SL["PrusaSlicer
prusaslicer.ini + Stützen/Brim pro Teil"] SL --> R1["Slicer-Warnungen?
(Überhänge, schwebende Brücken,
geringe Betthaftung)"] STL --> W["Wandstärken-Scan"] W --> R2["Wände < 1 Linie / Häute < 1 Schicht?"] R1 --> REP["printability.md
ok / warn / fail"] R2 --> REP ``` - **Slicer-Stufe:** Jedes Teil wird so geslict, wie es liegt, mit den Stützen und dem Brim aus der Druckliste. Sie scheitert, wenn der Slicer Fehler liefert oder Stabilitätsprobleme meldet, die diese Stützen und der Brim nicht verhindern. Filamentmasse und Zeit stammen aus dem erzeugten G-Code. - **Wand-Scan:** Eine seitliche Wand besteht aus Linien (je ≈ 0,45 mm), eine waagrechte Haut aus Schichten (0,2 mm). Unter einer Linie (0,4 mm) oder einer Schicht (0,2 mm) lässt der Slicer das Element weg: **fail**. Unter zwei Linien (0,8 mm) oder drei Schichten (0,6 mm) wird es gedruckt, ist aber zerbrechlich: **warn**. - **Druckplatten:** Jede 3MF-Druckplatte wird so geslict, wie sie angeordnet ist, und muss auf das Bett passen. Aktuelles Ergebnis: 34 Teiletypen und 13 Platten, **0 fail, 4 warn**. Die Warnungen betreffen die vier Servohalter mit kleinen Deckschichtbereichen von nur 0,38–0,53 mm Dicke (zwei Schichten): druckbar, aber drucken Sie sie sorgfältig. ## So lesen Sie die Druckliste {#how-to-read-the-print-list} Jede Zeile von `hardware/print/print_list.md` hat acht Spalten: | Spalte | Bedeutung | |---|---| | Part | Teile-ID, dieselbe wie im [Teilekatalog](../../catalog.md) und in der [Montageanleitung](../../assembly/README.md) | | Qty | Stück pro Roboter (z. B. `femur` 4, eines pro Bein) | | Colour | primär (graphit) oder sekundär (limette) | | File | STL unter `hardware/print/`, bereits ausgerichtet | | Size on bed (mm) | X × Y × Z, wie es liegt; Z ist die Höhe, die über den Brim entscheidet (> 40 mm) | | Supports | `no` oder `yes (N % overhang)` | | Source | Upstream-STL, Upstream-STEP, neues Strido-Teil oder ein geändertes Upstream-Teil | | Note | Gründe für die Ausrichtung und Änderungen gegenüber Upstream | Lesen Sie auch die beiden Absätze über der Tabelle: Sie enthalten die globalen Einstellungen und die besondere Anweisung für die Servohalter. ## Selbsttest {#check-yourself} 1. Warum verwendet das Kit drei Perimeter und nur 30 % Füllung statt mehr Füllung? 2. `bottom_shell` ist 42 mm hoch. Bekommt sie einen Brim, und warum? 3. Ein gedrucktes M3-Durchgangsloch ist für die Schraube zu eng. Was tun Sie? 4. Was macht das Druckpaket, wo ein Lagersitz auf der Bettseite in ein kleineres Loch darüber übergeht? 5. Was sind die beiden Fehlerkriterien des Wandstärken-Scans?
Antworten 1. Lasten um Schraubenlöcher und Kanten werden von den Wänden getragen; zusätzliche Perimeter erhöhen die Festigkeit dort, wo sie gebraucht wird, während Füllung hauptsächlich Masse und Zeit hinzufügt (Prusa gibt denselben Rat). 2. Ja. Jedes Teil, das höher als 40 mm ist, bekommt einen 5-mm-Brim, weil ein hohes Teil auf kleiner Grundfläche vom Bett gestoßen werden kann. 3. Bohren Sie einmal mit einem 3,2-mm-Bohrer durch (3,4 mm für eine lockerere Passung); gedruckte Löcher fallen etwa 0,15 mm zu klein aus. 4. Es schneidet die zwei Schichten über der Stufe für Brücken aus (der Lochüberhang-Trick): einen Schlitz so breit wie das kleine Loch quer über den Sitz, dann ein Quadrat, dann das kleine Loch. Jede Schicht überbrückt dann zwischen Wänden, auf denen sie aufliegt, sodass der Sitz keine eigenen Stützen braucht (wo der Slicer trotzdem welche setzt, wie in den Tibias, blockieren Sie sie in der Bohrung). 5. Eine seitliche Wand dünner als eine Extrusionslinie (0,4 mm) oder eine waagrechte Haut dünner als eine Schicht (0,2 mm).
## Weiterführende Literatur {#further-reading} - [Prusa-Wissensdatenbank: PETG](https://help.prusa3d.com/article/petg_2059) - [Prusa-Wissensdatenbank: Elefantenfuß-Kompensation](https://help.prusa3d.com/article/elephant-foot-compensation_114487) - [Bambu Lab Wiki: XY-Loch-/Konturkompensation](https://wiki.bambulab.com/en/software/bambu-studio/xy-hole-contour-compensation) - [PrusaSlicer auf GitHub](https://github.com/prusa3d/PrusaSlicer) - Verwandt in diesem Wiki: [Befestigungselemente](fasteners.md), [CAD als Code](../software/cad-as-code.md), [Mechanik](../hardware/mechanics.md) --- # Kabelmanagement und der Kabelbaum {#cable-management-and-the-wiring-harness} Ein gehender Roboter schüttelt, biegt und knickt seine eigene Verkabelung tausende Male pro Stunde. Die meisten Ausfälle bei Hobbyrobotern sind keine gebrochenen Teile, sondern eine durchgescheuerte Leitung, ein gelockerter Kontakt oder ein Draht, der neben einem Gelenk in seiner Isolierung gebrochen ist. Diese Seite erklärt, wie ein **Kabelbaum** gegen diese Ausfälle ausgelegt wird: wie dick jeder Draht sein muss, was eine Sicherung wirklich schützt, wie viel Spiel ein Kabel braucht, um ein bewegliches Gelenk zu überqueren, wie man Drähte biegt, bündelt und anschließt und was die CAD-Prüfung beweisen kann und was nicht. Jede Regel wird an der Zuschnittliste von Strido durchgerechnet. ::: tip In Strido **Maßgebliche Quelle:** `hardware/wiring.yaml` benennt jedes Kabel W00–W23 und die zwölf Servokabel (S-*leg*-*joint*), den Steckverbinder an jedem Ende, die Befestigungspunkte, die es passiert, und das Drahtmaterial. `strido_cad.wiring` verlegt sie im CAD; `python -m strido_verify.wiring` prüft sie und schreibt die [Verkabelungsprüfung](../../verification/wiring.md) mit der **Zuschnittliste**. Nennwerte und Sicherungen stehen in `hardware/electronics.yaml`. Die Baureihenfolge steht in [Elektronik, Verkabelung und Versorgung](../../electronics.md#wiring-harness) und in den Montageschritten 14–17 (sowie den Schalenschritten 18–22) der [Montageanleitung](../../assembly/README.md). Entscheidung: [ADR-011](../../decisions.md#adr-011-wiring-harness-routed-and-checked-in-the-cad). ::: ## Warum überhaupt einen Kabelbaum auslegen? {#why-design-a-harness-at-all} Die frühere Verkabelung des Roboters war eine Liste mit geschätzten Längen. Sobald jedes Kabel im CAD modelliert war, zeigte sich, dass die Liste echte Mängel verbarg (ADR-011): Der Hauptsicherungshalter ließ 4 mm für eine 14-AWG-Leitung, die sich nicht so eng biegen lässt; Dupont-Gehäuse passten weder auf die IMU (2,5 mm unter dem Pi) noch auf die XIAO-Pins (9 mm unter dem oberen Schulterrahmen); die Drähte vom XIAO zum PCA9685 brauchten etwa 0,3 m statt 0,1 m; und ein 60 mm langer 18-AWG-Abgriff lag allein hinter der 25-A-Sicherung. Nichts davon zeigt sich auf dem Papier. Alles davon zeigt sich beim echten Aufbau, meist als späte Überraschung. Ein Kabelbaum wird gegen die Arten ausgelegt, auf die Verkabelung in einer gehenden Maschine versagt: | Ausfall | Was passiert | Konstruktive Antwort | |---|---|---| | **Scheuern** | ein Kabel reibt an einem beweglichen Horn, einer Koppel oder Schalenkante, bis die Isolierung durchgescheuert ist und der Leiter kurzschließt | entlang der Struktur verlegen, fern von allem, was sich bewegt; Spiralschlauch an Bündeln; Freigang über die Gelenkbereiche prüfen | | **Reibkorrosion am Steckverbinder** | Vibration lässt zwei gesteckte Kontakte um Mikrometer gleiten; die Beschichtung verschleißt, Oxid baut sich auf und der Kontakt wird zeitweise unterbrochen | weniger Steckverbinder; rastende oder klemmende Kontakte; das Kabel so binden, dass sein Gewicht nicht am Kontakt hängt | | **Biegeermüdung** | ein an einer Stelle hin und her gebogener Draht bricht Litze für Litze in intakter Isolierung | Gelenke nahe ihrer Achse mit einer freien Schlaufe überqueren; steife Stellen (Lotdurchtränkung) neben einem sich biegenden Abschnitt vermeiden | | **Quetschen** | ein Kabel wird zwischen zwei sich schließenden Teilen eingeklemmt, etwa wenn ein Bein gegen den Körper klappt | jedes Kabel aus dem Volumen heraushalten, das die Beine überstreichen | | **Hitze** | ein unterdimensionierter Draht erwärmt sich mit $P = I^2 R$; die Isolierung erweicht; bei einem Kurzschluss kann er brennen | jeden Draht für seinen Strom auslegen; unterhalb dessen absichern, was er tragen kann | Der Rest der Seite geht diese Punkte nacheinander durch. ## Leiterquerschnitt {#conductor-sizing} ### Strombelastbarkeit {#ampacity} Die **Strombelastbarkeit** eines Drahts ist der Strom, den er dauerhaft führen kann, ohne dass seine Isolierung zu heiß wird. Sie hängt vom Kupferquerschnitt, der Temperaturklasse der Isolierung, der Umgebungstemperatur und davon ab, wie gut der Draht Wärme abgeben kann: Ein Draht allein in freier Luft trägt mehr als derselbe Draht in einem engen Bündel (allgemein; veröffentlichte Tabellen setzen Bündel herab). Strido verwendet für kurze Leitungen im Chassis bewusst konservative Werte (`wire_ampacity_a` in `hardware/electronics.yaml`): | Querschnitt | Kupferfläche (ca.) | Widerstand (ca.) | Verwendete Belastbarkeit | Verwendet in Strido für | |---|---|---|---|---| | 14 AWG | $2.1\,\mathrm{mm^2}$ | $8.3\,\mathrm{m\Omega/m}$ | 32 A | Akku-Hauptleitung W01–W04 | | 18 AWG | $0.82\,\mathrm{mm^2}$ | $21\,\mathrm{m\Omega/m}$ | 16 A | UBEC-Ausgänge W05/W06, Bus-Brücken W07/W08, Logikzweig W09–W11, Logikmassen W24, W04/logic | | 22 AWG | $0.33\,\mathrm{mm^2}$ | $53\,\mathrm{m\Omega/m}$ | 7 A | 5-V-Versorgung des Pi W12, Servokabel, I²C- und OE-Drähte W17/W20, Taster W13 | Die Prüfung `python -m strido_verify.electronics` liest die Leistungskabel aus `hardware/wiring.yaml` und prüft den Strom jedes Kabels im ungünstigsten Fall gegen diese Tabelle: Zum Beispiel führt W05 die 10 A Dauerstrom des UBEC auf 18 AWG ($10 \le 16$), und W12 führt 1,6 A pro 22-AWG-Draht ($1.6 \le 7$). ### Widerstand und Spannungsabfall {#resistance-and-voltage-drop} Der Widerstand eines Leiters wächst mit seiner Länge $L$ und sinkt mit seinem Querschnitt $A$: $$ R = \frac{\rho\,L}{A}, \qquad \rho_\mathrm{Cu} \approx 1.72 \times 10^{-8}\,\Omega\,\mathrm{m} $$ Der Strom fließt auf einem Leiter hin und auf dem anderen zurück, daher verliert ein Versorgungspaar $$ \Delta V = I \cdot 2R, \qquad P = I^2 \cdot 2R $$ **W05**, vorderer UBEC zum vorderen WAGO-Bus: 18-AWG-Paar, verlegt 190 mm, zugeschnitten 222 mm. Nimmt man die volle Zuschnittlänge als Kupfer im Stromkreis (eine Obergrenze) beim Dauernennstrom des UBEC von 10 A: $$ R = 0.222\,\mathrm{m} \times 21\,\mathrm{m\Omega/m} \approx 4.7\,\mathrm{m\Omega}\ \text{per conductor} $$ $$ \Delta V \approx 10\,\mathrm{A} \times 2 \times 4.7\,\mathrm{m\Omega} \approx 93\,\mathrm{mV}, \qquad P \approx (10\,\mathrm{A})^2 \times 9.3\,\mathrm{m\Omega} \approx 0.93\,\mathrm{W} $$ Das sind etwa 1,6 % der 6,0-V-Schiene: akzeptabel. **W12**, Spannungsregler zum Pi: 22 AWG, verlegt 104 mm, zugeschnitten 123 mm, zwei Drähte pro Schiene mit je 1,6 A: $$ R = 0.123\,\mathrm{m} \times 53\,\mathrm{m\Omega/m} \approx 6.5\,\mathrm{m\Omega}, \qquad \Delta V \approx 1.6\,\mathrm{A} \times 2 \times 6.5\,\mathrm{m\Omega} \approx 21\,\mathrm{mV} $$ Klein, aber auch die Reserve des Pi ist klein: Der Spannungsregler liefert möglicherweise nur 4,8 V, und der Pi meldet Unterspannung unter 4,63 V ([Versorgung](../hardware/power.md)). Deshalb verwendet W12 zwei Drähte pro Schiene und wird kurz gehalten. ## Absicherung: Eine Sicherung schützt den Draht {#fusing-a-fuse-protects-the-wire} Eine Sicherung schützt nicht die Platinen des Roboters. Sie schützt **den Draht dahinter** im Fehlerfall vor Überhitzung. Sie muss daher auslösen, bevor der schwächste Draht, den sie abdeckt, überhitzt, und darf bei normaler Last nicht auslösen: $$ I_\mathrm{load} \le I_\mathrm{fuse} \le I_\mathrm{wire,min} $$ wobei $I_\mathrm{wire,min}$ die Strombelastbarkeit des *dünnsten* Drahts irgendwo hinter dieser Sicherung ist. Die zwei Sicherungen von Strido (`fuses` in `hardware/electronics.yaml`): | Sicherung | Nennwert | Schützt | Dünnster Draht dahinter | Last im ungünstigsten Fall | |---|---|---|---|---| | Haupt (ATO) | 25 A | W02, W03, W04/front, W04/rear | 14 AWG, 32 A | 23,6 A (Servozweig ≈ 21 A bei leerem Akkupack + Logik) | | Logik (ATO) | 7,5 A | W09, W10, W11, W24, W04/logic | 18 AWG, 16 A | 2,74 A | W04/logic und W24 sind die *Masse*rückleitungen des Logikzweigs. Im Normalbetrieb führen sie denselben Strom wie die Logikversorgung, daher begrenzt die Logiksicherung ihn und sie dürfen 18 AWG haben. Die Grenze betrifft den Normalstrom, nicht jeden Fehler: Ein Kurzschluss vom Servozweig (nur hinter der 25-A-Sicherung) auf eine Logikmasse würde über sie zurückfließen. Deshalb verlaufen die Drähte des Servozweigs getrennt von den Logikmassen, außer an der inneren Rahmenöffnung, innerhalb ihrer Isolierung und Umhüllung. **Warum der alte Abgriff falsch war.** Das alte Design speiste den Logiksicherungshalter über ein 60 mm langes Stück 18 AWG, das von der Hauptleitung *hinter der 25-A-Sicherung* abgegriffen wurde. Nur die 25-A-Sicherung deckte dieses Stück ab, und 25 A liegt über den 16 A von 18 AWG. Ein Fehler, der etwa 20 A durch den Abgriff zieht, würde die Sicherung nie auslösen, aber den Abgriff erwärmen mit $$ P' = I^2 \frac{\rho}{A} = (20\,\mathrm{A})^2 \times 21\,\mathrm{m\Omega/m} \approx 8.4\,\mathrm{W/m} $$ unbegrenzt lange (eine Veranschaulichung des Prinzips, kein gemessener Fehler). „Kurz halten“ verringert die Wahrscheinlichkeit eines Fehlers, ändert aber nicht die Regel. Die Lösung: Der Abgriff ist jetzt die **eigene 14-AWG-Leitung** des Logiksicherungshalters, in der Rückschale an W02 angespleißt. Kein Draht dünner als 14 AWG liegt allein hinter der 25-A-Sicherung, und alles nach der 7,5-A-Sicherung hat mindestens 18 AWG. **Warum W01 ungesichert ist und kurz gehalten wird.** W01 verläuft vom Akkueingang zur Hauptsicherung. Nichts außer den eigenen Grenzen des Akkupacks kann sie schützen: Der Akkupack ist für 300 A ausgelegt (`hardware/electronics.yaml`), ein Kurzschluss an W01 ist also ein Akkukurzschluss. Die Sicherung sitzt dort, wo Platz für ihren Halter und das Biegen ihrer 14-AWG-Leitungen war: am hinteren WAGO-Bus, etwa 0,15 m vom Akkueingang. W01 wird daher wie die eigene Leitung des Akkupacks behandelt: 14 AWG, zugeschnitten 151 mm, im Spiralschlauch, fern von allem Beweglichen verlegt. ADR-011 sieht vor, die Sicherung nur dann näher zu rücken, wenn ein kompakter abgesicherter Akkueingang unter das Deck passt. ## Ein Gelenk überqueren: Bewegungsschlaufen {#crossing-a-joint-service-loops} Ein Kabel, das ein Gelenk überquert, muss seine Länge ändern, wenn sich das Gelenk dreht. Kann es das nicht, zieht das Gelenk am Kabel, und der Zug landet an der schwächsten Stelle: einer Lötstelle, einer Crimpverbindung oder einem Steckverbinder. Eine **Bewegungsschlaufe** ist ein bewusst freies Kabelstück zwischen zwei festen Befestigungspunkten, das diese Änderung aufnimmt. Bei Strido sitzen die Oberschenkel- und Knieservos auf dem Hüftkörper, daher überqueren ihre Leitungen nur das **Hüft**gelenk. Jede Leitung wird an der Servohalterungsplatte nahe der Hüftachse (auf der beweglichen Seite) und erneut am Schulterrahmen oder Bushalter (am Körper) festgebunden. Zwischen den Befestigungen hängt die Schlaufe. Die Hüftservos sitzen am Körper und brauchen keine Schlaufe. Auch die anderen Gelenke brauchen keine, weil keine Leitung sie überquert: Die Platzierung der Motoren entscheidet, welche Gelenke die Verkabelung überqueren muss. ### Wie weit bewegen sich die Befestigungspunkte auseinander? {#how-far-apart-do-the-ties-move} Legen Sie den Ursprung auf die Hüftachse. Sei $\mathbf{p}$ der Befestigungspunkt am beweglichen Hüftkörper (in der Referenzpose der Hüfte) und $\mathbf{q}$ der Befestigungspunkt am Körper. Dreht sich die Hüfte um $\theta$, wandert der bewegliche Befestigungspunkt nach $R(\theta)\,\mathbf{p}$, mit $R(\theta)$ der Drehung um die Hüftachse (siehe [Koordinatensysteme und Drehungen](../theory/frames-and-rotations.md)). Der Abstand zwischen den Befestigungspunkten ist $$ d(\theta) = \lVert R(\theta)\,\mathbf{p} - \mathbf{q} \rVert $$ Um zu sehen, was ihn bestimmt, zerlegen Sie jeden Punkt in einen Anteil entlang der Einheitsachse $\hat{\mathbf{a}}$ und einen Anteil senkrecht dazu: $\mathbf{p} = p_a\,\hat{\mathbf{a}} + \mathbf{p}_\perp$, $\mathbf{q} = q_a\,\hat{\mathbf{a}} + \mathbf{q}_\perp$, mit den Radien $r_p = \lVert \mathbf{p}_\perp \rVert$ und $r_q = \lVert \mathbf{q}_\perp \rVert$. Die Drehung lässt die axialen Anteile unverändert und dreht $\mathbf{p}_\perp$ um $\theta$, daher ergibt der Kosinussatz $$ d(\theta)^2 = (p_a - q_a)^2 + r_p^2 + r_q^2 - 2\,r_p\,r_q \cos(\theta - \theta_0) $$ wobei $\theta_0$ der Hüftwinkel ist, bei dem die beiden senkrechten Anteile in dieselbe Richtung zeigen. Über eine volle Umdrehung würde $d$ schwanken zwischen $$ d_\mathrm{min} = \sqrt{(p_a - q_a)^2 + (r_p - r_q)^2}, \qquad d_\mathrm{max} = \sqrt{(p_a - q_a)^2 + (r_p + r_q)^2} $$ und innerhalb des begrenzten Hüftbereichs deckt es einen Teil dieses Intervalls ab. Die Lehre steckt in den Radien: Die Schwankung wächst mit $r_p\,r_q$. **Befestigungspunkte nahe der Achse bewegen sich wenig**, daher kann die Schlaufe kurz sein. Deshalb werden die Leitungen an der Servohalterungsplatte *nahe der Hüftachse* festgebunden statt weiter außen. Die Verkabelungsprüfung vertraut keiner Handformel. Sie platziert beide Befestigungspunkte im CAD und wertet $d(\theta)$ über den gesamten Hüftbereich aus. Für die Vorderbeine: | Leitung | Abstand der Befestigungspunkte über den Hüftbereich | Erforderliche Schlaufe $1.2\,d_\mathrm{max}$ | Schlaufe in `wiring.yaml` | |---|---|---|---| | vorderer Oberschenkel | 13,0–24,1 mm | 28,9 mm | 30 mm | | vorderes Knie | 20,0–25,6 mm | 30,7 mm | 32 mm | | hinterer Oberschenkel | 11,9–16,2 mm | 19,4 mm | 22 mm | | hinteres Knie | 11,9–16,1 mm | 19,4 mm | 22 mm | Der schulterseitige Befestigungspunkt der vorderen Knieleitung sitzt am Bushalter, 17 mm in Richtung des inneren Rahmens: Ihre Schlaufe ist etwas länger, aber der Signaldraht spart auf dem Weg zum PCA9685 mehr ein, und damit reicht das 260-mm-Servokabel ohne Verlängerung. ### Die Spielregel {#the-slack-rule} Die Regel des Roboters lautet $$ L_\mathrm{loop} \ge 1.2\, d_\mathrm{max} $$ Durchgerechnet für das vordere Knie: $1.2 \times 25.6\,\mathrm{mm} = 30.7\,\mathrm{mm}$, aufgerundet auf **32 mm**. Warum nicht genau $d_\mathrm{max}$? Bei dieser Länge wäre das Kabel beim extremen Hüftwinkel eine gerade, straffe Sehne und würde an beiden Befestigungspunkten ziehen. Ein Kabel kann einen Befestigungspunkt auch nicht in beliebigem Winkel verlassen: Es verlässt ihn in der Richtung, in der es gebunden ist, und muss sich zum anderen Befestigungspunkt hin krümmen, und die Krümmung kostet Länge. Die 20 % decken beides ab. Warum nicht viel länger? Zusätzliche Schlaufe muss irgendwo hängen, und eine lange Schlaufe kann in ein bewegliches Teil durchhängen. Die Prüfung kontrolliert nur die *Länge* der Schlaufe; wo sie hängt, wird nicht modelliert, daher prüfen Sie das von Hand (siehe Checkliste unten). ## Biegeradius und Biegelebensdauer {#bend-radius-and-flex-life} Jedes Kabel hat einen minimalen Biegeradius. Eine gängige Faustregel (allgemein, kein Datenblattwert; prüfen Sie die Angaben des Kabelherstellers) ist ein Mehrfaches des Außendurchmessers (AD) für ein Kabel, das einmal gebogen und dann fixiert wird, und etwa das Zehnfache des AD oder mehr für ein Kabel, das sich im Betrieb biegt. `hardware/wiring.yaml` hält für jeden Kabeltyp eine minimale statische Biegung fest, etwa das Dreifache des AD: 11 mm für 14 AWG (3,6 mm AD), 7 mm für 18 AWG (2,2 mm), 5 mm für 22 AWG (1,6 mm), 15 mm für die USB-Kabel. Die alte Position der Hauptsicherung ließ 4 mm für eine 14-AWG-Leitung, die 11 mm braucht: Deshalb wurde die Sicherung verlegt. Warum Biegen einen Draht ermüdet: Eine Litze mit Durchmesser $d_s$, auf den Radius $R$ gebogen, dehnt sich an ihrer Außenseite um die Biegedehnung (allgemeines Balkenergebnis) $$ \varepsilon \approx \frac{d_s}{2R} $$ Kupfer übersteht viele Zyklen bei kleiner Dehnung und wenige bei großer Dehnung. Zwei Folgen: - **Feine Litzen biegen sich besser.** In einem Litzendraht können die Einzeldrähte gleiten, sodass sich jeder um seine eigene Mitte biegt. Für eine beispielhafte Litze mit $d_s = 0.08\,\mathrm{mm}$ bei $R = 5\,\mathrm{mm}$ gilt $\varepsilon \approx 0.08/10 = 0.8\,\%$. Ein massiver 22-AWG-Leiter ($A = 0.33\,\mathrm{mm^2}$, also $d = \sqrt{4A/\pi} \approx 0.65\,\mathrm{mm}$), gleich gebogen, erfährt $\varepsilon \approx 0.65/10 = 6.5\,\%$, achtmal mehr. Silikonlitze und Servokabel sind aus diesem Grund feinlitzig. - **Eine längere Schlaufe biegt sanfter.** Dieselbe Gelenkbewegung auf mehr Kabel zu verteilen bedeutet einen größeren Radius und eine kleinere Dehnung. Eine Schlaufe, die gerade lang genug ist, knickt bei jedem Schritt scharf an ihren Enden. Das CAD zeichnet die Ecken der Verlegung scharf und prüft keine Biegeradien, daher ist der Radius Ihre Aufgabe am Arbeitstisch. ## Bündeln, Spiralschlauch und Kabelbinder {#bundling-spiral-wrap-and-ties} - **Spiralschlauch** (eine PE-Spirale, die sich um ein Bündel wickelt) an jedem Bündel aus **drei oder mehr Kabeln**. Er hält das Bündel zusammen, schützt es vor Kanten und lässt trotzdem einzelne Kabel an beliebiger Stelle abzweigen. Strido verwendet etwa 228 mm davon (`spiral_wrap`, Prüfung des Drahtmaterials). - **Kabelbinder** an den markierten Befestigungspunkten von `wiring.yaml`, etwa 30 aus einem 100er-Beutel: Kanten der Servohalterungsplatten, Schlitze im Schulterrahmen, Schlitze im Bushalter, Rahmenöffnungen. Kabelbinder fixieren das Kabel an der Struktur, damit es nicht in ein bewegliches Teil wandern kann, und sie nehmen Zug von den Anschlüssen. - **Selbstklebende Kabelbinder-Sockel:** zwei 13 × 13 mm große Sockel an den seitlichen Leisten des Decks (`cable_tie_mounts`, im CAD modelliert), wo es keinen Schlitz zum Festbinden gibt. - **Abstand der Kabelbinder** (allgemeine Praxis): an jeder Abzweigung, vor und nach jeder Biegung und nahe an jedem Steckverbinder binden, sodass ein Zug am Kabel an einem Kabelbinder endet statt an einem Kontakt. Am Roboter erledigen das bereits die Befestigungspunkte im CAD. - **Spannung** (allgemein): Ziehen Sie einen Kabelbinder so fest an, dass das Kabel nicht rutschen kann, aber nicht so fest, dass er die Isolierung eindrückt. Eine gequetschte Stelle ist eine steife Stelle und eine künftige Scheuerstelle. Schneiden Sie das Ende bündig ab; ein scharfes Ende zerkratzt Haut und Isolierung. ## Signal und Leistung {#signal-and-power} Ein sich ändernder Strom $I$ in einer Schleife induziert eine Spannung in einer benachbarten Schleife, $V = M\,\mathrm{d}I/\mathrm{d}t$, wobei $M$ (Gegeninduktivität) mit den Schleifenflächen wächst und mit dem Abstand sinkt (allgemein). Servoströme ändern sich schnell: bis zu 3,5 A pro Servo im Blockierfall. Zwei allgemeine Gewohnheiten halten das von den Signalen fern: - **Trennen Sie sie.** Verlegen Sie Signaldrähte wo möglich fern von Hochstromdrähten und kreuzen Sie sie im rechten Winkel statt parallel. Bei Strido wird jedes Servokabel an einem Kabelbinder aufgeteilt: Rot/Braun gehen zum WAGO-Bus im Hohlraum, das orange Signal läuft weiter zum PCA9685 neben dem Pi. - **Halten Sie Schleifen klein und verdrillen Sie Paare.** Ein Signal und seine Rückleitung nebeneinander umschließen wenig Fläche. Das Verdrillen eines Paars (allgemeine Technik; die Dokumentation des Roboters schreibt es nicht vor) wechselt die Richtung jeder kleinen Schleife, sodass sich induzierte Spannungen entlang der Länge aufheben. Eine gemeinsame Masse gehört zur selben Geschichte: Das Signal eines Servos wird gegen seine Masse gelesen, daher teilen alle Bereiche einen Massesternpunkt am Akkueingang ([Versorgung](../hardware/power.md)). ## Steckverbinder und Anschlüsse {#connectors-and-terminations} ### WAGO-Hebelklemmen {#wago-lever-clamps} Der Servobus besteht aus WAGO-221-415-Hebelklemmen: fünf Eingänge, 0,2–4 mm², ausgelegt für 32 A. Eine Federklemme greift den blanken Leiter, wenn der Hebel schließt, ganz ohne Werkzeug. Das Datenblatt von WAGO verlangt eine **Abisolierlänge von 11 mm**: kürzer, und die Klemme greift zu wenig Kupfer; länger, und blankes Kupfer ragt aus dem Gehäuse. Schieben Sie den Leiter ein, bis die Isolierung am Gehäuse anliegt, schließen Sie den Hebel und ziehen Sie leicht daran. Das Gehäuse ist durchsichtig, sodass Sie sehen, ob der Leiter das Ende erreicht. Ein Draht pro Eingang: Die Prüfung kontrolliert das für jeden WAGO-Anschluss. ### Crimpen oder löten? {#crimp-or-solder} - **Crimpen** presst einen Metallkontakt kalt um die blanken Litzen (Leitercrimp) und um die Isolierung (Isolationscrimp). Der Isolationscrimp ist die **Zugentlastung**: Er nimmt Biegung und Zug von der Leiterverbindung. Die Litzen bleiben bis direkt zum Kontakt flexibel. - **Löten** verbindet die Litzen mit geschmolzener Legierung. Lot läuft durch Kapillarwirkung auch in die Isolierung hinein (**Lotdurchtränkung**) und macht diesen Teil des Drahts zu einem massiven Stab. Die Biegung konzentriert sich dann am Ende des durchtränkten Abschnitts, genau wie in der Dehnungsformel oben (massiver Leiter, großes $\varepsilon$), und dort brechen die Litzen unter Vibration. Lotdurchtränkung gilt in Verarbeitungsnormen für Kabelbäume wie IPC/WHMA-A-620 als Fehler. Also: Löten Sie, wo der Draht fixiert und abgestützt ist (und ergänzen Sie Schrumpfschlauch als Zugentlastung); crimpen oder klemmen Sie, wo er sich bewegt. Bei Strido sind die Lötstellen der Leistungseingang (XT60H-Lötkelche, Leitungen des Sicherungshalters, die mit Schrumpfschlauch überzogenen Spleiße), Schalter, Spannungsregler und Taster sowie die XIAO-Pins. Die XIAO-Pins sitzen 9 mm unter dem oberen Schulterrahmen, und ein Dupont-Gehäuse ist 14 mm hoch, daher werden W17 (3V3, GND, SDA, SCL) und W20 (D3 → OE) dort angelötet und am PCA9685 gecrimpt, und auch die Dupont-Enden des Displaykabels (W21) werden dort angelötet. Binden Sie diese Drähte nahe an der Platine fest, damit kein Zug die Lötstelle erreicht. ### Dupont-Kontakte {#dupont-contacts} Dupont-Kontakte werden auf 2,54-mm-Stiftleisten gesteckt und halten nur durch Federreibung. Ein schweres oder schwingendes Kabel kann sie lockern (allgemein), daher binden Sie das Bündel nahe an der Platine fest und lassen nichts an den Kontakten hängen. Am Roboter werden sie dort verwendet, wo sie passen: W12 am Pi (ein Draht pro Pin), W17/W20 am PCA9685 und der orange Signaldraht jedes Servos, neu gecrimpt in ein 1-Pin-Gehäuse auf seinem PCA9685-Kanal. Wo nicht einmal ein Gehäuse passt, gibt es einen anderen Steckverbinder: Die IMU sitzt 2,5 mm unter dem Pi, daher ist W18 ein STEMMA-QT-Kabel mit seinem flachen JST-SH-Stecker. ### XT60 und die Kontaktregel {#xt60-and-the-contact-rule} Der XT60 ist der 30-A-Steckverbinder des Akkueingangs, des Arming-Ports und des Loop-Keys. Beschreiben Sie seine Hälften mit **Stiften** und **Buchsen**, nicht mit „Stecker/Kupplung“. Der Loop-Key ist ein kurzgeschlossener Steckverbinder, daher muss er denselben Kontakttyp wie der eigene Steckverbinder des Akkupacks haben: Dann kann er nicht mit dem Akkupack gesteckt werden ([XT60-Kontaktregel](../../electronics.md#xt60-contact-rule-the-loop-key-must-never-fit-the-battery)). ## Leitungen auf Länge schneiden, nicht verlängern {#cut-leads-to-length-don-t-extend-them} Früher wurden die Servos mit 300-mm-Verlängerungskabeln angeschlossen. Jede Verlängerung fügt pro Servo eine gesteckte dreipolige Stecker-Buchse-Verbindung hinzu: zwölf zusätzliche Verbindungen, 36 zusätzliche Kontakte, jeder ein Kandidat für Reibkorrosion. Jedes Servo verwendet jetzt nur sein eigenes 260-mm-Servokabel: Es läuft zu einem Kabelbinder, wo der rote und der braune Draht abgetrennt, auf Länge geschnitten und im WAGO-Paar des Beins geklemmt werden (Rot in die obere V+-Klemme, Braun in die untere GND; Anschlüsse Hüfte 1, Oberschenkel 2, Knie 3), während der orange Signaldraht auf Länge geschnitten und für seinen PCA9685-Kanal neu gecrimpt wird. Weniger Steckverbinder in einem gehenden Roboter bedeuten weniger zeitweise unterbrochene Kontakte und einen kürzeren Leistungspfad ([Versorgung](../hardware/power.md)). Die **Zuschnittliste** in der [Verkabelungsprüfung](../../verification/wiring.md) gibt für jeden Draht die verlegte Länge und die Zuschnittlänge an: $$ L_\mathrm{cut} = L_\mathrm{routed} + t_1 + t_2 + \max(10\,\mathrm{mm},\ 0.08\,L_\mathrm{routed}) $$ mit einer Anschlusszugabe $t$ pro Ende (WAGO-Abisolierung 11 mm, Löten 6 mm, Crimpen 3 mm, Schraubklemme 7 mm). Das Spiel deckt das Verlegen und ein erneutes Anschließen ab. Zwei Beispiele: $$ \text{W05:}\quad 190 + 6 + 11 + 0.08 \times 190 = 222.2 \;\Rightarrow\; 222\,\mathrm{mm} $$ $$ \text{W12:}\quad 104 + 6 + 3 + \max(10,\ 8.3) = 123\,\mathrm{mm} $$ Fertig konfektionierte Kabel lassen sich nicht kürzen, daher prüft die Prüfung stattdessen die **Reichweite**: gelieferte Länge ≥ Verlegung + Anschlüsse + 10 mm. Ihr Überschuss wird gefaltet und festgebunden: 178 mm beim Pi–XIAO-USB-Kabel (W14), 124 mm beim Kamera-Flachbandkabel (W16), 141 mm beim Displaykabel (W21), 55 mm beim LiDAR-USB-Kabel (W15). Servokabel haben vor dem Kürzen 12–124 mm Reserve. Die vorderen Knieleitungen sind mit 12 mm am knappsten: Verlegen Sie sie genau so, wie die Anleitung sie zeigt. ## Wie das CAD den Kabelbaum verlegt {#how-the-cad-routes-the-harness} `strido_cad.wiring` behandelt das Verlegen als Pfadsuche: 1. **Hindernisse.** Ein Voxelgitter mit 1-mm-Zellen markiert jedes Grundteil sowie jedes Volumen, das ein Beinteil über seine Gelenkgrenzen überstreicht (die Hüfte in 1°-Schritten, Oberschenkel und Unterschenkel über ein Winkelraster). Ein durch freie Voxel verlegtes Kabel bleibt bei den abgetasteten Gelenkwinkeln von einem Bein frei; die Prüfung kontrolliert die Betriebsposen anschließend erneut gegen die echten Meshes. 2. **Suche.** Zwischen aufeinanderfolgenden Befestigungspunkten findet Dijkstras Kürzeste-Pfade-Algorithmus einen Pfad durch freie Voxel. Seine Kostenfunktion bevorzugt Voxel innerhalb von 3 mm zu einer Oberfläche, weil echte Kabel entlang der Struktur gebunden und nicht durch freien Raum gespannt werden. 3. **Abkürzung.** Der Pfad wird nur dort begradigt, wo die gerade Linie ebenso nahe an der Struktur bleibt wie der gesuchte Pfad. Das Ergebnis wird in den Renderings, der [3D-Ansicht](../../viewer.md) und der Montageanleitung gezeichnet, sodass Sie in den Bauschritten den verlegten Kabelbaum sehen. ### Was die Prüfung beweist und was nicht {#what-the-gate-proves-and-what-it-does-not} `python -m strido_verify.wiring` prüft den verlegten Kabelbaum unabhängig vom Verlegealgorithmus erneut: - **Reichweite:** Jedes fertig konfektionierte Kabel deckt seine Verlegung mit Anschlüssen und 10 mm Reserve ab. - **Material:** Draht pro Querschnitt und Farbe, Spiralschlauch und Kabelbinder passen zur Stückliste. - **Hüftschlaufen:** Jede Schlaufe ist mindestens $1.2\,d_\mathrm{max}$ lang. - **Anschlüsse:** ein Kabel pro WAGO-Eingang und pro PCA9685-Kanal. - **Freigang:** Kein Leiter führt durch ein Teil, und jedes Kabel hält in jeder Betriebspose mindestens 1,0 mm (warn) / 0,3 mm (fail) Abstand zu jedem Teil eines anderen Körpers: Stehen, Hocken, hoch, acht Trot-Phasen, Hüften innen und außen. Sie modelliert **keine** Biegeradien (Ecken der Verlegung werden scharf gezeichnet) und nicht, wo eine Hüftschlaufe hängt. Sie kann auch keine Verarbeitungsqualität erkennen: eine Crimpverbindung, die sich herauszieht, eine kalte Lötstelle, einen zu fest gezogenen Kabelbinder. Das wird am Arbeitstisch geprüft. ## Checkliste für den Aufbau {#build-checklist} 1. Schneiden Sie jeden Draht nach der Zuschnittliste zu; beschriften Sie beide Enden mit seiner ID. 2. Isolieren Sie WAGO-Enden auf 11 mm ab; ziehen Sie leicht an jedem WAGO-Eingang, jeder Crimp- und Lötverbindung. 3. Schieben Sie den Schrumpfschlauch vor dem Löten auf; schrumpfen Sie ihn über jede gelötete Leistungsverbindung. 4. Sicherungen und Loop-Key bleiben **draußen**, bis die Verkabelung geprüft ist ([Elektronik](../../electronics.md#wiring-harness), Bauschritte 3–7). 5. Binden Sie jede Oberschenkel- und Knieleitung an der Servohalterungsplatte und am Schulterrahmen / Bushalter fest und lassen Sie die Schlaufe zwischen den Befestigungspunkten (vorne: 30 mm Oberschenkel, 32 mm Knie; hinten: 22 mm). 6. Jedes Bündel aus drei oder mehr Kabeln in Spiralschlauch; Kabelbinder an den markierten Punkten; satt, nicht quetschend. 7. Achten Sie per Augenmaß auf Biegeradien: keine 14-AWG-Leitung enger als etwa 11 mm gebogen. 8. **Bewegen Sie jedes Gelenk von Hand durch seinen gesamten Bereich**, Loop-Key gezogen: Hüften innen und außen, Oberschenkel und Knie von gefaltet bis gestreckt. Beobachten Sie jede Schlaufe und jedes Bündel: Nichts darf sich straff ziehen, scheuern oder einem beweglichen Teil nahekommen. 9. Prüfen Sie den Durchgang jedes Kabels gegen die Verkabelungsliste; messen Sie den Widerstand zwischen + und − am Akkueingang (nicht nahe 0 Ω), bevor Sie den Akkupack anschließen. ## Selbsttest {#check-yourself} 1. Nennen Sie drei Arten, wie Verkabelung in einem gehenden Roboter versagt, und je eine konstruktive Maßnahme dagegen. 2. Die Hauptsicherung hat 25 A. Warum darf kein 18-AWG-Draht allein dahinter liegen, und wie hat die Überarbeitung den alten Logikabgriff behoben? 3. Schätzen Sie den Spannungsabfall von W06 (18-AWG-Paar, verlegt 151 mm) für Hin- und Rückleitung bei 10 A. 4. Ein Befestigungspunkt an der Hüfte sitzt im Radius $r_p = 10\,\mathrm{mm}$ von der Hüftachse und ein Befestigungspunkt am Körper bei $r_q = 15\,\mathrm{mm}$, ohne axialen Versatz. Zwischen welchen Abständen würde $d(\theta)$ über eine volle Umdrehung schwanken? Was sagt das darüber, wo Befestigungspunkte sitzen sollten? 5. Die Prüfung ermittelt als größten Abstand der Befestigungspunkte einer Schlaufe 25 mm. Wie lang muss die Schlaufe nach der Regel des Roboters sein, und warum reicht eine Schlaufe von genau 25 mm nicht? 6. Warum bricht ein verlöteter Litzendraht unter Vibration früher als ein gecrimpter? 7. Warum wurden die Servoverlängerungen entfernt? 8. Berechnen Sie die Zuschnittlänge von W09 (verlegt 256 mm, Löten am Sicherungshalter, Schraubklemme am Schalter). 9. Nennen Sie zwei Dinge, die die Verkabelungsprüfung nicht kontrolliert, und wie Sie sie stattdessen prüfen.
Antworten 1. Drei beliebige aus: Scheuern (entlang der Struktur verlegen, Spiralschlauch, Freigangsprüfung), Reibkorrosion am Steckverbinder (weniger Steckverbinder, Kabel so binden, dass nichts an Kontakten hängt), Biegeermüdung (Schlaufen nahe der Gelenkachse, keine steifen Stellen neben sich biegendem Draht), Quetschen (Kabel aus dem von den Beinen überstrichenen Volumen heraushalten), Hitze (Drähte für ihren Strom auslegen, unterhalb der Strombelastbarkeit absichern). 2. Eine Sicherung darf nicht größer sein als die Strombelastbarkeit des dünnsten Drahts dahinter; 18 AWG ist für 16 A ausgelegt, daher würde ein Fehler zwischen 16 und 25 A ihn erwärmen, ohne die Sicherung auszulösen. Der Abgriff ist jetzt die eigene 14-AWG-Leitung des Logiksicherungshalters, an W02 angespleißt. 3. $R = 0.151 \times 21 \approx 3.2\,\mathrm{m\Omega}$ pro Leiter; $\Delta V \approx 10 \times 2 \times 3.2 \approx 63\,\mathrm{mV}$ (mit der Zuschnittlänge von 180 mm als Obergrenze etwa 76 mV). 4. $d_\mathrm{min} = \lvert 10 - 15 \rvert = 5\,\mathrm{mm}$, $d_\mathrm{max} = 10 + 15 = 25\,\mathrm{mm}$. Die Schwankung wächst mit beiden Radien, daher brauchen Befestigungspunkte nahe der Achse eine kürzere Schlaufe. 5. $1.2 \times 25 = 30\,\mathrm{mm}$. Bei genau 25 mm ist das Kabel beim extremen Winkel straff und zieht an den Befestigungspunkten und Anschlüssen; es braucht außerdem Länge, um sich von jedem Befestigungspunkt wegzukrümmen. 6. Lot zieht in die Litzen und bildet einen massiven, steifen Abschnitt; die Biegung konzentriert sich an seinem Ende, wo ein massiver Leiter eine viel größere Dehnung erfährt als einzelne Litzen. Eine Crimpverbindung lässt die Litzen flexibel, und ihr Isolationscrimp sorgt für Zugentlastung. 7. Jede Verlängerung fügte pro Servo eine dreipolige Stecker-Buchse-Verbindung hinzu (insgesamt 36 Kontakte), die sich durch Reibkorrosion lockern konnte, dazu zusätzlichen Draht und Spannungsabfall. Das Kürzen des eigenen Servokabels jedes Servos entfernt sie. 8. $256 + 6 + 7 + 0.08 \times 256 = 289.5 \Rightarrow 290\,\mathrm{mm}$, wie in der Zuschnittliste. 9. Biegeradien und wo eine Schlaufe hängt (jedes Gelenk von Hand durch seinen Bereich bewegen und hinsehen); Verarbeitungsqualität wie Crimpverbindungen, Lötstellen und Spannung der Kabelbinder (Zugprobe, Sichtprüfung, Durchgangsprüfung).
## Weiterführende Literatur {#further-reading} - [IPC/WHMA-A-620, Requirements and Acceptance for Cable and Wire Harness Assemblies (Inhaltsverzeichnis)](https://www.electronics.org/TOC/IPC-WHMA-A-620E_TOC.pdf): der Branchenstandard zur Verarbeitungsqualität für Crimpverbindungen, Lötstellen, Lotdurchtränkung, Bündelung und Kabelbinder. - [NASA-STD-8739.4, Workmanship Standard for Crimping, Interconnecting Cables, Harnesses, and Wiring](https://standards.nasa.gov/sites/default/files/standards/NASA/A/4/nasa-std-87394a_w_change_4_0.pdf): ein frei verfügbarer, detaillierter Standard zur Verarbeitungsqualität von Kabelbäumen. - [Molex Quality Crimping Handbook](https://www.molex.com/content/dam/molex/molex-dot-com/products/automated/en-us/commercialcrimpbookpdf/638/63800/TM-638000029-001.pdf): Leiter- und Isolationscrimp, Zugproben, Crimpfehler. - [Datenblatt WAGO 221-415](https://wago.priintcloud.com/datasheets/221-415/en): 0,2–4 mm², 32 A, Abisolierlänge 11 mm. - [HellermannTyton Spiralschlauch (SBPE)](https://www.hellermanntyton.com/products/protective-tubing-and-spiral-binding/sbpe1.5/161-41001): Größen und Temperaturbereich des Spiralschlauchs. - [NBS Handbook 100, Copper Wire Tables](https://nvlpubs.nist.gov/nistpubs/Legacy/hb/nbshandbook100.pdf): AWG-Durchmesser, -Flächen und -Widerstände. - [PowerStream AWG-Tabelle](https://www.powerstream.com/Wire_Size.htm): eine vielfach kopierte Tabelle zur Strombelastbarkeit bei Chassisverkabelung (Sekundärquelle; die Werte des Roboters sind bewusst niedriger). - [Raspberry-Pi-Hardwaredokumentation](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html): Versorgungspins der GPIO-Stiftleiste. - Roboterdokumentation: [Elektronik, Verkabelung und Versorgung](../../electronics.md#wiring-harness), [Verkabelungsprüfung und Zuschnittliste](../../verification/wiring.md), [ADR-011](../../decisions.md#adr-011-wiring-harness-routed-and-checked-in-the-cad). - Verwandt in diesem Wiki: [Versorgung](../hardware/power.md), [Werkzeug und Werkstatt](tools-and-workshop.md), [Sicherheit](safety.md), [Koordinatensysteme und Drehungen](../theory/frames-and-rotations.md). --- # Befestigungselemente {#fasteners} Strido wird von 223 Schrauben in drei Größen (M2, M2.5, M3) zusammengehalten, alle mit Innensechskant-Zylinderkopf. Diese Seite erklärt, wie man eine Schraubenbezeichnung liest, wie eine Schraube in einem gedruckten Loch hält, warum die Vorbohrungen so bemessen sind und wie fest in Kunststoff fest genug ist. ::: tip In Strido Die Liste der Befestigungselemente steht in der Stückliste ([bom/README.md](../../bom/README.md), Abschnitte *Fasteners* und *Fasteners by joint*); jeder Montageschritt führt seine Schrauben im Teilekasten auf ([Montageanleitung](../../assembly/README.md)). Die Passungsprüfung (`python -m strido_verify.fits`, Bericht [verification/fits.md](../../verification/fits.md)) prüft jede Schraube gegen die Bereiche in `hardware/verification/tolerances.yaml`. ADR-009 in [decisions.md](../../decisions.md) behandelt die Vorbohrungen der Servohalterungen. ::: ## Eine Schraubenbezeichnung lesen {#reading-a-screw-designation} `M3 × 10 DIN 912 A2` bedeutet: | Teil | Bedeutung | |---|---| | `M3` | Metrisches ISO-Gewinde, 3 mm Nenndurchmesser (Außendurchmesser). Regelgewinde, sofern nicht anders angegeben: M2 = 0,4 mm, M2.5 = 0,45 mm, M3 = 0,5 mm pro Umdrehung | | `× 10` | Länge in mm, gemessen von unter dem Kopf bis zur Spitze | | `DIN 912` / `ISO 4762` | Zylinderschraube mit Innensechskant: zylindrischer Kopf mit Sechskantöffnung. DIN 912 und ISO 4762 haben dieselbe Form; die Stückliste bestellt DIN 912, das CAD nennt sie `iso4762_…` | | `A2` | Edelstahlgüte (A2 = austenitisch, Typ 304) | ## Die Befestigungselemente in diesem Roboter {#the-fasteners-in-this-robot} Alle Schrauben sind Zylinderschrauben mit Innensechskant. Eine Inbusschlüsselgröße pro Gewinde: | Gewinde | Inbusschlüssel | Mutter (Schlüsselweite) | Verwendete Längen | Typische Verwendung | |---|---|---|---|---| | M2 | 1,5 mm | 4,0 mm | 5, 10 mm | LCD-Halter, Abstandsbolzen des Spannungsreglers, Kameraplatine | | M2.5 | 2,0 mm | 5,0 mm | 5, 6 mm | Abstandsbolzen für Pi 5 / PCA9685 / INA260, IMU, LiDAR | | M3 | 2,5 mm | 5,5 mm | 8, 10, 12, 16, 20, 25, 40 mm | alles Tragende: Rahmen, Servos, Beine, Schalen | Die M3 × 10 ist mit Abstand die häufigste (86 im CAD: Servolaschen, Schulterrahmen, Chassis, Knieachsen). Die längste ist die einzelne M3 × 40 des Kamera-Neigegelenks. Weitere Befestigungselemente in der Stückliste: - **Sechskantmuttern** ISO 4032 / DIN 934 (M2, M2.5, M3): einfache Muttern, davon 56 in M3. Einige sitzen in eingeformten Taschen im gedruckten Teil (zum Beispiel die unverlierbare Mutter in `upper_shoulder_frame`), sodass Sie nur von der Schraubenseite festziehen. - **Sicherungsmuttern mit Nylonring** DIN 985 M3 (17 im CAD): Ein Nylonring klemmt das Gewinde, sodass sich die Mutter nicht löst, selbst wenn sie *nicht* fest angezogen ist. Deshalb werden sie an beweglichen Gelenken verwendet (Tibia-Gelenke, Bolzen der Tibia-Koppel, Kameragelenk). - **Unterlegscheiben** ISO 7089 M3 (16): verteilen die Last unter einem Kopf oder einer Mutter an den Knieachsen, Hüftdrehpunkten und Armbolzen. - **Abstandsbolzen**, Innen-Innen: Messing M2.5 × 6 mm (Platinen) und M2 × 8 mm (Spannungsregler). Sie heben Platinen vom Deck ab. Es werden keine Gewindeeinsätze (Einschmelzmuttern) verwendet: Jede Schraube endet in einer Mutter, einer gedruckten Vorbohrung oder einem Metallgewinde. ## Drei Arten, wie eine Schraube endet {#three-ways-a-screw-ends} Der Passungsbericht zählt, wie jede der 223 Schrauben endet: | Abschluss | Anzahl | Was die Schraube hält | |---|---|---| | Mutter | 105 | Eine Sechskantmutter, Sicherungsmutter oder ein Messing-Abstandsbolzen; die gedruckten Teile werden zwischen Kopf und Mutter geklemmt | | Gewindeformend | 78 | Die Schraube schneidet ihr eigenes Gewinde in eine gedruckte Vorbohrung (Servolaschen, Servohalter, Knieachsen, Kurbelbolzen, Hüfthörner, Schalendome) | | Herstellergewinde | 40 | Ein Metallgewinde in einem Kaufteil: Aluminiumhörner (Femur-an-Horn), Servoabtriebswellen (Mittelschrauben), LCD-Sechskantbolzen, LiDAR-Gehäuse | Eine Mutterverbindung ist die stärkste und lässt sich beliebig oft nachziehen. Eine gewindeformende Verbindung ist bequem (keine Mutter zum Gegenhalten), aber Kunststoffgewinde verschleißen, wenn Sie die Schraube oft heraus- und wieder eindrehen. ## Gewindeformende Schrauben in gedruckten Vorbohrungen {#thread-forming-screws-in-printed-pilots} Die normalen Maschinenschrauben der Stückliste werden als gewindeformende Schrauben verwendet: In ein Loch eingedreht, das kleiner als die Schraube ist, verdrängen sie Kunststoff und formen ein passendes Gewinde. Zwei Zahlen entscheiden, ob das funktioniert. ### Vorbohrungsdurchmesser {#pilot-diameter} Leitfäden für gewindeformende Schrauben in Thermoplasten empfehlen eine Vorbohrung von etwa $0.8\,d$ ($d$ = Nenndurchmesser). Strido bewertet die **gedruckte** Vorbohrung als Verhältnis zu $d$ und berücksichtigt dabei den erwarteten Druckschwund: $$ \frac{D_\mathrm{printed}}{d} = \frac{D_\mathrm{CAD} - 0.15\,\mathrm{mm}}{d} $$ | Gedruckte Vorbohrung / d | Bewertung | Begründung | |---|---|---| | < 0,70 | fail | zu viel Material zu verdrängen: der Dom platzt oder der Schraubenkopf dreht durch | | 0,70 – 0,90 | ok | voller Halt | | 0,90 – 0,93 | warn | schwacher Halt: nach Gefühl festziehen; dreht eine Schraube durch, die Vorbohrung mit dünnflüssigem Sekundenkleber härten und erneut eindrehen | | > 0,93 | fail | kein Halt | Für M3 bedeutet das: Eine CAD-Vorbohrung von etwa 2,25–2,85 mm ist ok, 2,85–2,94 mm ergibt eine Warnung. Beispiel: Die M3-Vorbohrungen des `femur` messen im CAD 2,80–2,85 mm, werden also mit etwa 2,65–2,70 mm gedruckt, und $2.70\,\mathrm{mm} / 3\,\mathrm{mm} = 0.90$ (Bereich $0.88$–$0.90\,d$): ok. ### Einschraublänge {#engagement-length} Die Einschraublänge ist die Länge, über die das Loch enger als die Schraube ist, also wie viel Gewinde geformt wird. Regel: mindestens $1.5\,d$ ist ok ($1.5 \times 3\,\mathrm{mm} = 4.5\,\mathrm{mm}$ für M3), $1.0$–$1.5\,d$ ergibt eine Warnung (nicht zu fest anziehen), unter $1.0\,d$ schlägt fehl. Die Vorbohrungen des `femur` haben 4,0 mm Einschraublänge ($4.0 / 3 \approx 1.33\,d$) und die M2.5-Vorbohrungen des `arming_port_bezel` 2,5 mm ($1.0\,d$): beide ergeben eine Warnung, also behutsam festziehen. Warum die Einschraublänge wichtig ist (die Scherfläche des Gewindes wächst mit der eingeschraubten Länge), wird in [Festigkeit, Drehmoment und Versagen](strength.md) durchgerechnet. ### ADR-009: die Vorbohrungen der Servohalterungen {#adr-009-the-servo-mount-pilots} 29 Schrauben der Upstream-Servohalterungsfamilie (`left_servo_mount`, `right_servo_mount`, die abgeleiteten Varianten `_fl`/`_fr` und `servo_mount_top_bracket`) greifen in CAD-Vorbohrungen von 2,94–2,97 mm: nach dem Druck 0,93–0,94 d, knapp über dem Bereich für schwachen Halt, mit 4–12 mm Einschraublänge. Upstream-Yertle-Roboter werden mit genau diesen Löchern gebaut; statt sie neu zu konstruieren, dokumentiert das Projekt daher eine akzeptierte Abweichung mit einer Maßnahme für den Erbauer: 1. **Bevorzugt:** Drucken Sie diese fünf Teile mit **X-Y-Lochkompensation −0,15 mm**; damit misst die Vorbohrung etwa 2,65 mm (siehe [3D-Druck](3d-printing.md)). 2. **Andernfalls:** Lassen Sie vor dem Eindrehen jeder Schraube einen Tropfen dünnflüssigen Sekundenkleber (Cyanacrylat) in die Vorbohrung laufen und aushärten; er härtet die Lochwand, sodass die Schraube ein festeres Gewinde formt. Prüfen Sie, dass jede Schraube greift, bevor die Verbindung Last trägt. Reißt in einer Halterung jemals ein Gewinde aus, sieht das ADR als Ausweichlösung eine Variante mit neuer Vorbohrung von Ø 2,5 mm vor. ## Schraubensicherung {#threadlocker} Mittelfeste (blaue) Schraubensicherung ist ein anaerober Klebstoff: Sie härtet unter Luftabschluss zwischen **Metall**gewinden aus (die Metallionen katalysieren die Aushärtung) und verhindert, dass Vibrationen eine Schraube lösen, erlaubt aber weiterhin das Lösen mit Handwerkzeug. Strido verwendet sie nur bei **Metall-auf-Metall-Schrauben**: den Schrauben in die Servoabtriebswellen und in die Aluminium-25T-Hörner mit Gewinde: die Mittelschrauben der Hörner, die Femur-an-Horn-M3 × 20, die Hüfthorn-M3 × 8 durch die Servohalterung in das Scheibenhorn und die Armbolzen-M3 × 16 in das Armhorn des Knieantriebs. Jeder Schritt kehrt die Last an einem Horn um, und bei Metall auf Metall gibt es keinen Kunststoff, der das Gewinde klemmt; daher lösen sich diese Schrauben am ehesten. Ein Tropfen auf das Schraubengewinde genügt. ::: warning Keine Schraubensicherung in gedruckten Löchern Laut Henkels Datenblatt wird Loctite 243 auf Kunststoffen, insbesondere Thermoplasten, normalerweise nicht empfohlen, da Spannungsrisse entstehen können; zwischen Stahlschraube und Kunststoff fehlen ihr außerdem die Metallflächen, die sie zum Aushärten braucht. Verwenden Sie für schwache gedruckte Vorbohrungen stattdessen Lochkompensation oder eine mit Sekundenkleber gehärtete Vorbohrung. ::: ## Festziehen in Kunststoff {#tightening-in-plastic} Eine M3-Stahlschraube kann leicht mehr Klemmkraft erzeugen, als ein gedruckter Dom aufnehmen kann. Der [Festigkeitsbericht](../../verification/strength.md#tightening-torque-into-printed-pilots) gibt für jede gedruckte Vorbohrung ein Drehmomentlimit an (0,05–0,35 N·m; die Formeln stehen in [Festigkeit, Drehmoment und Versagen](strength.md)). Die Regeln aus der Montageanleitung: - **Schrauben in gedruckte Vorbohrungen (als selbstschneidend markiert):** drehen, bis sie satt anliegen, niemals mit vollem Drehmoment. „Satt“ heißt, der Kopf liegt gerade auf und die Teile bewegen sich nicht mehr; hier aufhören. - **Durch dünne Teile:** Das Elektronikdeck ist in der Mitte 3 mm dick; seine Schraubenköpfe sitzen in Senkungen, also nicht zu fest anziehen. - **Sicherungsmuttern an beweglichen Gelenken:** nur so weit festziehen, bis das Gelenk kein Spiel mehr hat; die Kniekoppeln müssen unter ihrem Eigengewicht schwingen (Schritt 12). Eine Sicherungsmutter hält ihre Position, ohne fest angezogen zu sein. - **Reibgelenke:** Das Kameragelenk (M3 × 40 mit Sicherungsmutter) wird festgezogen, bis die Kamera ihren Winkel hält; Referenz ist 15° nach unten. - **Kurze Inbusschlüssel:** Halten Sie einen Inbusschlüssel nur zum Lösen am langen Schenkel; verwenden Sie zum Festziehen in Kunststoff den kurzen Schenkel (oder Fingerdruck auf einen Schraubendrehergriff), damit Sie nicht versehentlich zu viel Drehmoment aufbringen. Anzeichen, dass Sie zu weit gegangen sind: Die Schraube dreht weiter, ohne fester zu werden (Gewinde ausgerissen), um das Loch erscheint eine weiße Spannungsmarke, oder neben dem Dom öffnet sich eine Schichtlinie. ## Selbsttest {#check-yourself} 1. Was sagen Ihnen `M2.5 × 6` und `ISO 4762`? 2. Eine M3-Vorbohrung ist mit 2,80 mm gezeichnet. Mit welchem Maß wird sie gedruckt, und welche Bewertung erhält sie? 3. Warum verwenden die Kniegelenke Sicherungsmuttern DIN 985 statt einfacher Muttern? 4. Welche Schrauben in Strido erhalten standardmäßig Schraubensicherung? 5. Was ist die bevorzugte Maßnahme für den Erbauer bei den Vorbohrungen der Servohalterungen nach ADR-009?
Antworten 1. Metrisches Gewinde mit 2,5 mm Durchmesser, 6 mm lang unter dem Kopf; eine Zylinderschraube mit Innensechskant. 2. Etwa 2,65 mm (2,80 − 0,15), also 0,88 d: ok, voller Halt. 3. Das Gelenk muss sich frei drehen, daher kann die Mutter nicht fest angezogen werden; der Nyloneinsatz verhindert trotzdem, dass sie sich löst. 4. Nur die Metall-auf-Metall-Schrauben in die Servohörner; gedruckte Vorbohrungen erhalten niemals anaerobe Schraubensicherung. 5. Diese Teile mit X-Y-Lochkompensation −0,15 mm drucken, was eine Vorbohrung von etwa 2,65 mm ergibt.
## Weiterführende Literatur {#further-reading} - [Henkel: Technisches Datenblatt LOCTITE 243](https://datasheets.tdx.henkel.com/LOCTITE-243-en_GL.pdf) - [Passungsbericht: verification/fits.md](../../verification/fits.md) und [Entscheidungen (ADR-009)](../../decisions.md) - [Prusa Knowledge Base: PETG](https://help.prusa3d.com/article/petg_2059) (Material, in dem die Vorbohrungen gedruckt werden) - Verwandt in diesem Wiki: [3D-Druck](3d-printing.md), [Mechanik](../hardware/mechanics.md), [Werkzeug und Werkstatt](tools-and-workshop.md) --- # Sicherheit {#safety} Strido trägt einen Lithium-Polymer-Akku, der bei einem Kurzschluss Hunderte Ampere liefern kann, und zwölf Servos, die stark genug sind, einen Finger einzuklemmen. Diese Seite erklärt die Gefahren, die Schutzteile, die der Roboter dagegen einsetzt, und die Reihenfolge, in der Sie ihn zum ersten Mal einschalten. ::: tip In Strido Sicherheitsteile: die 25-A-Hauptsicherung und die 7,5-A-Logiksicherung (ATO-Flachsicherungen), der XT60-Arming-Port mit seinem Loop-Key in der Rückschale, der Pololu-#2813-Einschalttaster, der INA260-Power-Monitor (Abschaltung bei niedrigem Akkustand) und der Pull-up-Widerstand an PCA9685 OE. Regeln und der Rauchtest stehen in [electronics.md](../../electronics.md#safety-rules); das erste Einschalten ist Montageschritt 23 ([Montageanleitung](../../assembly/README.md)). Die Firmware-Sicherheit (Watchdog, Not-Halt, Abschaltung) ist in [software.md](../../software.md#firmware) beschrieben. ::: ## LiPo-Akkus {#lipo-batteries} Der Akkupack ist ein **2S-LiPo, 5000 mAh**, Hardcase, XT60-Leitung. „2S“ bedeutet zwei Zellen in Reihe: 7,4 V nominal, 8,4 V voll, etwa 37 Wh. In `hardware/electronics.yaml` ist seine maximale Entladung mit 300 A angegeben (60C; 500 A kurzzeitig). Ein Kurzschluss über seinen Anschlüssen verläuft daher nicht sanft: Der Draht glüht, die Isolierung brennt, und die Zellen können bis zum Brand beschädigt werden. | Regel | Warum | |---|---| | Nur mit einem **Balance-Ladegerät**, im **LiPo-Sack** und nie unbeaufsichtigt laden | Balancing hält beide Zellen auf derselben Spannung; eine unausgeglichene Zelle kann überladen werden und versagen; der Sack hält einen Brand lange genug zurück, um zu reagieren | | Nie über 4,2 V pro Zelle laden (8,4 V für den Akkupack) | Überladen von Lithiumzellen ist die klassische Ursache für thermisches Durchgehen | | Den Akkupack nie leer fahren | Tiefentladung schädigt Lithiumzellen. Die Firmware warnt bei **6,8 V** (3,4 V/Zelle) und entspannt die Servos bei **6,4 V** (3,2 V/Zelle); der Zellprüfer / Unterspannungsalarm in der Stückliste liefert eine zweite Meinung | | Mit Lagerladung lagern (etwa 3,8 V/Zelle; Ladegeräte der B6AC-Klasse haben einen Lagermodus) | Volle Akkupacks altern schneller und enthalten mehr Energie, falls etwas schiefgeht | | Einen Akkupack ausmustern, der **aufgebläht**, verbeult oder nach normalem Gebrauch heiß ist | Die Schwellung ist Gas aus zersetztem Elektrolyt, ein Zeichen für innere Schäden | | Blanke Leitungen isolieren; den Akkupack im Sack transportieren | Verhindert Kurzschlüsse durch Schlüssel, Werkzeug oder den anderen Stecker | ::: danger Wenn ein LiPo raucht Versuchen Sie nicht, ihn zu retten. Gehen Sie weg, halten Sie andere fern und lüften Sie. Decken Sie einen brennenden Akkupack nicht mit den Händen oder einem Tuch ab. Verständigen Sie die örtliche Feuerwehr, wenn sich der Brand ausbreitet. Ein Akkupack, der ausgegast hat, wird nie wieder verwendet. ::: ## Sicherungen: Schutz der Leitung {#fuses-protecting-the-wire} Eine Sicherung schützt die **Leitung** dahinter vor Überhitzung. Die Heizleistung einer Leitung ist $P = I^2 R$, sie wächst also mit dem Quadrat des Stroms, und ein Kurzschluss kann einen dünnen Draht erhitzen, bis seine Isolierung schmilzt, lange bevor der Akku leer ist. Die Sicherung ist eine bewusst schwache Stelle, die zuerst schmilzt; sie wird daher unterhalb des Stroms bemessen, den die Leitung tragen kann, und oberhalb des Stroms, den die Last braucht: $$ I_\mathrm{load} \le I_\mathrm{fuse} \le I_\mathrm{wire} $$ Für die Hauptsicherung wird die Servolast über die UBECs (90 % Wirkungsgrad, siehe [Stromversorgung](../hardware/power.md)) auf den Akkupack zurückgerechnet. Der ungünstigste Fall ist der fast leere Akkupack an der Abschaltgrenze von $6.4\,\mathrm{V}$: $2 \times 10\,\mathrm{A} \times 6.0\,\mathrm{V} / (0.9 \times 6.4\,\mathrm{V}) \approx 20.8\,\mathrm{A}$, plus $2.7\,\mathrm{A}$ Logik $= 23.6\,\mathrm{A}$ ([Elektronikprüfung](../../verification/electronics.md)). Das bleibt unter der 25-A-Sicherung, die ihrerseits unter den 32 A der 14-AWG-Hauptleitung liegt. | Sicherung | Nennwert | Schützt | Leitungsbelastbarkeit (`electronics.yaml`) | Last | |---|---|---|---|---| | Haupt (ATO) | **25 A** | W02, W03, W04/front, W04/rear: die 14-AWG-Hauptleitung | 32 A | Servozweig ≤ 2 × 10 A UBEC-Ausgang (≈ 21 A bei leerem Akkupack, siehe [Elektronik](../../electronics.md#ratings-and-why-these-parts)) + Logik | | Logik (ATO) | **7,5 A** | W09, W10, W11 und die Logik-Masserückleitungen W24, W04/logic: die 18-AWG-Logikverkabelung | 16 A | Logikzweig ≤ 3 A | Die Sicherungen sitzen so nah am Akkueingang, wie es ihre Halter zulassen, weil dort die Kurzschlussgefahr am größten ist. Der Halter der Hauptsicherung liegt auf dem hinteren WAGO-Bus, etwa 0,15 m vom Akkueingang entfernt; W01, die 14-AWG-Leitung dazwischen, ist wie die eigene Leitung des Akkupacks nicht abgesichert, daher wird sie kurz, im Spiralschlauch und fern von beweglichen Teilen gehalten. Der Halter der Logiksicherung in der Rückschale wird über **die eigene 14-AWG-Leitung des Halters** versorgt, an W02 angespleißt: Hinter der 25-A-Sicherung allein liegt kein Draht dünner als 14 AWG. Warum das wichtig ist: [Kabelmanagement](cable-management.md#fusing-a-fuse-protects-the-wire). Ersatz ist in der Stückliste (zwei zusätzliche 25 A, eine zusätzliche 7,5 A). Ersetzen Sie eine ausgelöste Sicherung nur durch eine mit **demselben Nennwert** und erst, nachdem Sie herausgefunden haben, warum sie ausgelöst hat. Beim Bau des Kabelbaums bleiben die Sicherungen **draußen**, bis die Verkabelung geprüft ist: Der Stromeingang wird ohne sie verdrahtet (Kabelbaum-Schritt 3), und sie kommen erst für die Pi-Stromprüfung hinein (Kabelbaum-Schritt 6). ## Erstes Einschalten ohne Servos: der Rauchtest {#first-power-up-without-servos-the-smoke-test} Wenn der Roboter zum ersten Mal Akkustrom bekommt, dürfen sich die Servos nicht bewegen können, und die teuren Platinen müssen die richtigen Spannungen sehen. Die Kabelbaum-Schritte in [electronics.md](../../electronics.md#wiring-harness) gehen in dieser Reihenfolge vor: ```mermaid flowchart TD A["UBECs: 5,8–6,0 V ohne Last messen
(kein Servo angeschlossen)"] --> B["Sicherungen rein, Taster gedrückt:
4,8–5,2 V an den W12-Dupont-Enden"] B --> C["W12 auf Pi-Pins 2/4 (5 V), 6/14 (GND) stecken"] C --> D["Rauchtest: Sicherungen rein, Loop-Key RAUS, einschalten"] D --> E["Pi bootet; /battery_state zeigt Akkuspannung;
/diagnostics: pwm_ok, imu_ok, power_ok"] E --> F["XIAO im Bootloader (BOOT + RESET):
PCA9685 OE ≥ 2,4 V (Ausgänge aus)"] ``` Warum jede Prüfung: - **UBEC 5,8–6,0 V vor den Servos:** Der SPT5435LV ist nur für 4,8–6,0 V ausgelegt. Ein auf 7,4 V eingestelltes (oder so ausfallendes) Gerät würde zwölf Servos gleichzeitig überlasten. - **5 V an den Dupont-Enden vor dem Pi:** Der Pi wird über seine GPIO-5-V-Pins versorgt, was den USB-C-Stromeingang und dessen Aushandlung umgeht; eine falsche Spannung dort erreicht die Platine direkt. - **Loop-Key draußen:** Der Servozweig ist stromlos, sodass sich nichts bewegen kann, während Sie die Logikseite prüfen. - **OE ≥ 2,4 V im Bootloader:** Die PCA9685-Platine zieht OE standardmäßig auf Low (Ausgänge an). Der 2,2-kΩ-Pull-up hält die Ausgänge aus, wann immer der XIAO zurückgesetzt wird oder keine Firmware ausführt, sodass ein Reset nie zufällige Pulse senden kann. Halten Sie beim ersten Booten eine Hand in der Nähe des Einschalttasters und schalten Sie sofort ab, wenn etwas heiß wird oder riecht. ## Scharfschalten: der Loop-Key {#arming-the-loop-key} Der **Loop-Key** ist ein kurzgeschlossener XT60-Stecker, den Sie in den **Arming-Port** in der Rückschale stecken, um den Servozweig zu verbinden. Ihn zu ziehen ist der Servo-Not-Aus: Kein Strom erreicht die UBECs, egal was die Software tut. - Der **Einschalttaster ist kein Not-Halt.** Er schaltet nur den Logikzweig (Pololu gibt an, dass er nicht als Not-Halt gedacht ist). - Der Loop-Key darf nie auf den Akku selbst passen, sonst würde er den Akkupack kurzschließen. Er hat daher denselben Kontakttyp wie der Akkustecker. Prüfen Sie das mit dem *nicht gebrückten* Steckergehäuse, bevor Sie die Brücke einlöten (siehe die [XT60-Kontaktregel](../../electronics.md#xt60-contact-rule-the-loop-key-must-never-fit-the-battery)). - Beschriften Sie die Buchse mit „ARM“: Der Akku selbst passt hinein, schließen Sie den Akkupack daher immer am Akkueingang unter dem Deck an (seine Leitung W00 in die XT60H). **Startreihenfolge** (aus den Sicherheitsregeln): Logik an → Roboter liegt in der Ruhepose, Beine eingeklappt → Loop-Key einstecken (Servos bleiben schlaff; der Controller sendet vor dem ersten Positionsbefehl keine Pulse) → `ros2 launch strido_bringup robot.launch.py` starten (Servos fahren in die Ruhepose, dann 3 s Aufstehen). ::: danger Nie scharf schalten, während Befehle laufen Wird der Loop-Key eingesteckt, während Positionsbefehle gesendet werden, springen alle zwölf Servos gleichzeitig auf ihre Ziele. Sechs blockierte Servos ziehen etwa 21 A, mehr als die 15 A Spitzenstrom eines UBEC. ::: Software-Stopps zusätzlich zum Loop-Key: - `/strido/estop` verriegelt: Die Firmware zieht PCA9685 OE auf High und stoppt alle Pulse. - Watchdog: kein Gelenkbefehl für 200 ms → Servos halten; 2 s später → sie entspannen. - Die Firmware verweigert den Betrieb ohne funktionierenden INA260, weil es ohne ihn keine Abschaltung bei niedrigem Akkustand gibt. ## Quetschstellen und bewegte Beine {#pinch-points-and-moving-legs} Jeder SPT5435LV ist mit 35 kg·cm angegeben (etwa 3,43 N·m Blockiermoment). Drehmoment ist Kraft mal Hebelarm, $\tau = F r$, daher kann der Servo bei $r = 30\,\mathrm{mm}$ von der Achse drücken mit $$ F = \frac{\tau}{r} = \frac{3.43\,\mathrm{N\,m}}{0.03\,\mathrm{m}} \approx 114\,\mathrm{N} $$ ungefähr der Gewichtskraft von $114\,\mathrm{N} / 9.81\,\mathrm{m/s^2} \approx 11.7\,\mathrm{kg}$, auf eine Fingerkuppe. Näher an der Achse ist die Kraft noch größer. Das Knie wird über eine Kurbel und Koppeln angetrieben, daher gibt es Scherstellen zwischen den Koppeln, dem Femur und der Tibia, die sich beim Beugen des Knies schließen. - Halten Sie die Finger aus den Beinen, solange der Loop-Key steckt. - Halten Sie den Roboter an der Körperschale, nie an einem Bein. - Testen Sie neue Gaits oder Policies zuerst mit dem Roboter auf einem Ständer, Beine frei. - Ziehen Sie den Loop-Key, bevor Sie in die Beine greifen; die Servos in der Software zu entspannen genügt nicht. - Lange Haare, Ärmel und Kabel von den Kniegetrieben fernhalten. ## ESD: statische Elektrizität {#esd-static-electricity} Ein statischer Funke, den Sie nicht einmal spüren, kann die Eingänge eines Mikrocontrollers oder Sensors beschädigen. Raspberry Pi 5, XIAO ESP32-S3, LSM6DSOX-IMU, INA260 und PCA9685 sind nackte Platinen mit offenliegenden Pins. - Berühren Sie einen geerdeten Metallgegenstand, bevor Sie eine Platine anfassen; ein ESD-Armband ist besser. - Halten Sie Platinen an den Kanten; berühren Sie weder Pins noch Bauteile. - Bewahren Sie Platinen bis zur Montage in ihren Antistatikbeuteln auf. - Arbeiten Sie auf einem blanken Tisch oder einer ESD-Matte statt auf Teppich oder Plastikfolie. ## Weitere Werkstattgefahren {#other-workshop-hazards} - **Verbrennungen:** Der Lötkolben arbeitet mit etwa 370–400 °C, die Druckerdüse mit 240 °C, das Druckbett mit 80 °C. - **Dämpfe:** Beim Löten (Flussmittel) und Drucken lüften. - **Fliegende Abschnitte:** Tragen Sie eine Schutzbrille, wenn Sie Stützstrukturen, Draht und Widerstandsbeinchen mit dem Seitenschneider abschneiden. ## Selbsttest {#check-yourself} 1. Was ist der Unterschied zwischen dem Ziehen des Loop-Keys und dem Drücken des Einschalttasters? 2. Warum hat die Logiksicherung 7,5 A, wenn der Logikzweig nur bis zu 3 A zieht? 3. Welche zwei Spannungen müssen Sie messen, bevor der erste Servo oder der Pi angeschlossen wird? 4. Bei welcher Akkuspannung entspannt die Firmware die Servos, und warum? 5. Warum muss der Loop-Key denselben Kontakttyp wie der Akkustecker haben?
Antworten 1. Der Loop-Key trennt den Servo-Stromzweig (Servo-Not-Aus); der Taster schaltet nur den Logikzweig und ist kein Not-Halt. 2. Die Sicherung schützt die 18-AWG-Leitung (hier mit 16 A belastbar), nicht die Last; sie darf bei normaler Last nicht auslösen, muss aber deutlich vor der Überhitzung der Leitung auslösen. 3. 5,8–6,0 V an jedem unbelasteten UBEC-Ausgang und 4,8–5,2 V an den W12-Dupont-Enden. 4. 6,4 V (3,2 V pro Zelle), nach 5 aufeinanderfolgenden Messwerten darunter, um eine Tiefentladung des LiPo zu vermeiden. 5. Damit der kurzgeschlossene Stecker nicht auf den Akku passt und den Akkupack kurzschließt.
## Weiterführende Literatur {#further-reading} - [Battery University: Sicherheitsaspekte bei Li-Ion (BU-304a)](https://batteryuniversity.com/article/bu-304a-safety-concerns-with-li-ion) - [OSHA: Sicherheit von Lithium-Ionen-Akkus (PDF)](https://www.osha.gov/sites/default/files/publications/OSHA4480.pdf) - [Pololu Big Pushbutton Power Switch HP (#2813)](https://www.pololu.com/product/2813) - [Elektronik, Verkabelung und Stromversorgung: Sicherheitsregeln](../../electronics.md#safety-rules) - Verwandt in diesem Wiki: [Akkus](../hardware/batteries.md), [Stromversorgung](../hardware/power.md), [Kabelmanagement](cable-management.md), [Firmware](../software/firmware.md) --- # Festigkeit, Drehmoment und Versagen {#strength-torque-and-failure} Bricht ein gedrucktes Bein, verbiegt es sich oder reißt es seine Schrauben aus? Diese Seite behandelt die Mechanik hinter dieser Frage: Drehmoment, Spannung und Dehnung, Biegung, Knickung, Verbindungen und Sicherheitsfaktoren. Jede Formel wird mit den eigenen Zahlen von Strido durchgerechnet. Dieselben Formeln laufen bei jeder Konstruktionsänderung als automatische Prüfung. ::: tip In Strido **Prüfung:** `python -m strido_verify.strength` (Teil von `make verify`) berechnet 19 Prüfungen aus den gedruckten STLs, der Beingeometrie und dem Passungsbericht; Ergebnisse im [Festigkeitsbericht](../../verification/strength.md). **Eingaben:** `hardware/strength.yaml` (Lasten, PETG- und Schraubendaten mit Quellen). **Entscheidung:** [ADR-010](../../decisions.md): das Knicken der langen Koppel, einst die eine bekannte Schwachstelle, ist mit der steifen langen Koppel behoben (keine Prüfung braucht mehr eine Ausnahme). **Die Ergebnisse jedes Teils** stehen auf seiner Seite im [Druckpaket](../../print-kit.md) und im [Shop](../../shop.md). Die Kräfte in den Beinen stammen aus [Statik und Dynamik](../theory/statics-and-dynamics.md). ::: ## Drehmoment: Kraft mal Hebel {#torque-force-times-lever} Ein Drehmoment $T$ (englisch *torque*) ist eine Kraft $F$, die im Abstand $r$ von einer Achse wirkt. Nur der Kraftanteil im rechten Winkel zum Hebel dreht die Achse. Mit $\alpha$ als Winkel zwischen Hebel und Kraft: $$ T = r\,F\,\sin\alpha \qquad [\mathrm{N\,m}] = [\mathrm{m}]\cdot[\mathrm{N}] $$ In Vektorform ist das das Kreuzprodukt $\mathbf{T} = \mathbf{r}\times\mathbf{F}$. Servo-Datenblätter geben das Drehmoment in kg·cm an: das Gewicht von 1 kg, das 1 cm von der Achse entfernt hängt. Mit $g = 9.81\,\mathrm{m/s^2}$: $$ 35\,\mathrm{kg\,cm} = 35 \cdot 9.81\,\mathrm{N} \cdot 0.01\,\mathrm{m} = 3.43\,\mathrm{N\,m} \qquad \text{(SPT5435LV at 6.0 V, stall)} $$ Rückwärts gelesen liefert dieselbe Formel die Kraft, die ein Servo über einen Arm drücken kann. Das Armhorn des Knieantriebs hat $r = 24\,\mathrm{mm}$: $$ F = \frac{T}{r\,\sin\alpha} = \frac{3.43\,\mathrm{N\,m}}{0.024\,\mathrm{m}\cdot 1.0} = 143\,\mathrm{N}\ \ (\alpha = 90^\circ), \qquad \frac{3.43}{0.024 \cdot 0.68} = 211\,\mathrm{N}\ \ \text{(worst angle within the joint limits)} $$ Kleine Hebel und flache Winkel machen aus moderaten Drehmomenten große Kräfte. Für $\alpha \to 0$ wächst die Kraft unbegrenzt: Das ist der *Totpunkt* (Kniehebel) eines Koppelgetriebes. Die Prüfung durchläuft jede Stellung innerhalb der Gelenkgrenzen und behält die größte Kraft. ## Woher die Lasten kommen {#where-the-loads-come-from} 1. **Gewicht und Landungen.** Der Roboter wiegt $m g = 3.07 \cdot 9.81 = 30.1\,\mathrm{N}$. Im Trot trägt ihn ein diagonales Fußpaar. Eine harte Landung vervielfacht die Kraft um einen Stoßfaktor $k$. Die Prüfung nimmt $k = 3$ auf zwei Füßen an: $$ F_\text{foot} = \frac{k\,m\,g}{2} = \frac{3 \cdot 30.1}{2} = 45.2\,\mathrm{N} $$ (eine Annahme; gemessene trabende Hunde erreichen Spitzen von etwa 1–1,2 × ihres Gewichts pro Vorderbein). 2. **Die Servos selbst.** Jedes Servo drückt höchstens mit seinem Blockiermoment $T_\text{stall}$, und das ist die Auslegungslast für die Gelenke. Eine Landung würde $F_\text{foot}\,L_\text{tibia} = 45.2 \cdot 0.124 = 5.6\,\mathrm{N\,m}$ am Knie erfordern. Das Knieservo bringt dort nur $3.07\,\mathrm{N\,m}$ auf, also gibt das Knie nach und das Servo wird rückwärts angetrieben. Ein Getriebeservo rückwärts anzutreiben erfordert allerdings mehr als sein Blockiermoment. Mit den Getriebewirkungsgraden vorwärts und rückwärts $\eta_f$ und $\eta_r$ sind es etwa $T_\text{stall}/(\eta_f\,\eta_r)$, rund 1,5–3 × (eine Schätzung). Harte Stöße können daher die Auslegungslasten überschreiten, und die Sicherheitsfaktoren müssen das abdecken. Bolzen und Lager tragen die volle Landekraft entlang des Beins. ## Spannung und Dehnung {#stress-and-strain} Die Last auf einem Teil verteilt sich über seinen Querschnitt. **Spannung** $\sigma$ ist Kraft pro Fläche, in $\mathrm{N/mm^2} = \mathrm{MPa}$. **Dehnung** $\varepsilon$ ist die relative Verlängerung $\Delta L / L$. Bei kleinen Dehnungen sind die meisten Werkstoffe linear-elastisch (Hookesches Gesetz), mit dem Elastizitätsmodul $E$: $$ \sigma = \frac{F}{A}, \qquad \varepsilon = \frac{\Delta L}{L}, \qquad \sigma = E\,\varepsilon $$ PETG hat $E \approx 1.5\,\mathrm{GPa}$ und fließt bei etwa $47\,\mathrm{MPa}$; nach dem Hookeschen Gesetz läge das bei $\varepsilon = 47/1500 \approx 3\,\%$, das Datenblatt misst $5\,\%$, weil PETG vor dem Fließen weicher wird. Stahl hat $E \approx 200\,\mathrm{GPa}$ und dehnt sich bei gleicher Spannung daher 130-mal weniger. Oberhalb der **Streckgrenze** verformt sich das Teil bleibend. Oberhalb der **Zugfestigkeit** bricht es. Reale Teile tragen mehrere Spannungen gleichzeitig (Zug, Biegung, Schub). Die Vergleichsspannung nach **von Mises** fasst sie zu einer Zahl zusammen, die mit der Zug-Streckgrenze verglichen wird. Für Normalspannung $\sigma$ plus Schub $\tau$: $$ \sigma_\text{v} = \sqrt{\sigma^2 + 3\,\tau^2} \qquad\Rightarrow\qquad \tau_\text{allow} = \frac{\sigma_\text{allow}}{\sqrt 3} \approx 0.577\,\sigma_\text{allow} $$ ## Biegung {#bending} Ein durch ein Moment $M$ gebogener Balken wird auf einer Seite gedehnt und auf der anderen gestaucht. Die Spannung wächst linear von der neutralen Faser (Spannung null) bis zur äußersten Faser im Abstand $c$. Die Euler-Bernoulli-Balkentheorie ergibt: $$ \sigma(y) = \frac{M\,y}{I}, \qquad \sigma_\text{max} = \frac{M\,c}{I} = \frac{M}{W}, \qquad I = \int_A y^2\,\mathrm{d}A, \qquad W = \frac{I}{c} $$ $I$ ist das **Flächenträgheitsmoment**: Es misst, wie weit das Material von der neutralen Faser entfernt liegt. $W$ ist das **Widerstandsmoment**. Für ein massives Rechteck der Breite $b$ und Höhe $h$, gebogen über $h$: $$ I = \frac{b\,h^3}{12}, \qquad W = \frac{b\,h^2}{6} $$ Die Höhe geht mit der dritten Potenz ein: Doppelte Höhe macht eine Koppel 8-mal steifer und 4-mal biegefester. Deshalb legen I-Träger ihr Material weit weg von der Mitte. **Gedruckte Teile sind überwiegend Schalen.** Das Slicer-Profil druckt 3 Perimeter (1,2 mm) und nur 30 % Gyroid-Füllung. Die Prüfung berechnet $I$ und $W$ nur für die 1,2-mm-Wände und ignoriert die Füllung, was konservativ ist. Sie nimmt 41 Schnitte entlang jeder Koppel und verwendet den schwächsten. Beispiel: Der schwächste Schnitt des Femurs hat $W = 236\,\mathrm{mm^3}$ in der Beinebene, und das Oberschenkelservo bringt $M = 3430\,\mathrm{N\,mm}$ auf: $$ \sigma = \frac{3430\,\mathrm{N\,mm}}{236\,\mathrm{mm^3}} = 14.5\,\mathrm{MPa}, \qquad S = \frac{47}{14.5} = 3.2 $$ ## Gedruckter Kunststoff ist anisotrop {#printed-plastic-is-anisotropic} Ein FDM-Teil ist ein Stapel verschweißter Schichten. Das PETG-Datenblatt von Prusament gibt an: | Richtung | Festigkeit | |---|---| | Entlang der Schichten (flach gedruckt) | $47\,\mathrm{MPa}$ Zug-Streckgrenze | | Quer zu den Schichten (Schichthaftung) | $18 \pm 4\,\mathrm{MPa}$ | Gedruckte Teile versagen meist dadurch, dass Schichten auseinandergezogen werden. Sie reißen (englisch *tear*) entlang einer Schichtlinie, oft an einer scharfen Ecke, an der sich die Spannung konzentriert. Deshalb legt die Druckliste die Koppeln, Femurs und Tibias flach. Ihre Biegespannung verläuft dann entlang der Schichten. Die Prüfung verwendet $47\,\mathrm{MPa}$, wenn eine Koppel flach liegt, und $18\,\mathrm{MPa}$, wenn ihre Längsachse in der Druckausrichtung nach oben zeigt. ## Sicherheitsfaktor {#safety-factor} $$ S = \frac{\text{allowable}}{\text{actual}} $$ Die Prüfung schlägt unter $S = 1.5$ fehl und warnt unter $2.0$. Die FDM-Festigkeit streut von Drucker zu Drucker, und PETG kriecht unter Dauerlast. Wiederholte Belastung verursacht außerdem **Ermüdung**: Millionen Schritte bei einer Spannung weit unter der statischen Festigkeit können einen Riss wachsen lassen. Nichts davon steckt in einer statischen Rechnung, also deckt es die Reserve ab. Am Roboter sind die kleinsten Faktoren die Tibia-Hälften ($S = 2.2$) und das Knicken der langen Koppel ($S = 2.5$, nächster Abschnitt), das bis zur Neukonstruktion der Koppel weit unter allem anderen lag. ## Knickung {#buckling} Ein schlanker Stab unter Druck wird nicht zerquetscht. Er weicht plötzlich seitlich aus, sobald die Kraft die Eulersche Knicklast erreicht. Der ausgelenkte Stab ist im Gleichgewicht, wenn $E I\,w'' + F\,w = 0$. Die kleinste von null verschiedene Lösung dieser Gleichung ergibt: $$ F_\text{cr} = \frac{\pi^2 E I}{(K L)^2} $$ $L$ ist der Bolzenabstand und $K$ der Knicklängenbeiwert der Randbedingungen: $1.0$ für gelenkige Enden, $0.5$ für eingespannte Enden, $0.7$ für je eines davon. Unterhalb von $F_\text{cr}$ passiert nichts Sichtbares. Bei $F_\text{cr}$ verliert der Stab seine Steifigkeit gegen seitliche Auslenkung. Die lange Upstream-Kniekoppel ist ein Stab, $5\,\mathrm{mm}$ breit in der Beinebene und $8\,\mathrm{mm}$ quer dazu, mit $130\,\mathrm{mm}$ zwischen den Bolzen. In der Beinebene drehen sich ihre Enden frei auf Bolzen ($K = 1$), und ihre Wände ergeben $I \approx 75\,\mathrm{mm^4}$: $$ F_\text{cr} = \frac{\pi^2 \cdot 1500\,\mathrm{MPa} \cdot 75\,\mathrm{mm^4}}{(130\,\mathrm{mm})^2} \approx 65\,\mathrm{N} \qquad F_\text{knee servo, worst pose} = 192\,\mathrm{N} \qquad S \approx 0.34 $$ Damit war sie mit Abstand die schwächste Stelle des Roboters. Im Stand belastet es sie mit etwa $0.70\,\mathrm{N\,m} / (0.024\,\mathrm{m}\cdot\sin 86^\circ) \approx 29\,\mathrm{N}$ ($S \approx 2.2$; siehe [Statik und Dynamik](../theory/statics-and-dynamics.md)), im normalen Gehen hielt sie also, aber ein Knie, das im Blockierzustand gegen einen blockierten Fuß oder einen harten Anschlag drückt, biegt sie seitlich aus ([ADR-010](../../decisions.md)). Weil $I \propto h^3$ gilt, bringt Breite in der Beinebene die Steifigkeit. Strido druckt deshalb eine **steife lange Koppel** (`stiff_long_link`): gleiche Bolzen und Buchsenaugen, aber ein Schaft von $10 \times 10\,\mathrm{mm}$. Nur mit $1.2\,\mathrm{mm}$ Wänden ergibt ein Hohlquadrat $I = (10^4 - 7.6^4)/12 \approx 555\,\mathrm{mm^4}$, mehr als das Siebenfache des Upstream-Stabs: $$ F_\text{cr} = \frac{\pi^2 \cdot 1500\,\mathrm{MPa} \cdot 555\,\mathrm{mm^4}}{(131\,\mathrm{mm})^2} \approx 480\,\mathrm{N} \qquad S \approx \frac{480}{192} \approx 2.5 $$ Die Prüfung misst die gedruckte STL Schnitt für Schnitt und meldet $S = 2.53$. Ein breiteres Teil braucht auch Platz: mittig auf der Bolzenlinie kam die Koppel dem Femur bei gestrecktem Knie bis auf $0.25\,\mathrm{mm}$ nahe, daher liegt ihr Schaft $2\,\mathrm{mm}$ neben der Bolzenlinie, vom Femur weg. Jeder Nachbar behält mindestens $1\,\mathrm{mm}$, und die Gelenkgrenzen haben sich nicht geändert. ## Schrauben unter Schub und in gedruckten Bohrungen {#screws-in-shear-and-in-printed-holes} Eine Schraube, die zwei Teile klemmt, die aneinander vorbeigleiten wollen, wird auf **Schub** belastet. Die Spannung verteilt sich über den Spannungsquerschnitt $A_s$ ($5.03\,\mathrm{mm^2}$ für M3). Wenn ein Drehmoment $T$ von $n$ Schrauben auf einem Lochkreis mit Radius $r$ getragen wird: $$ F = \frac{T}{n\,r}, \qquad \tau = \frac{F}{A_s} $$ Die Edelstahlschrauben DIN 912 A2-70 des Sortiments haben eine Streckgrenze von $R_{p0.2} = 450\,\mathrm{MPa}$, also $\tau_\text{allow} = 0.577 \cdot 450 = 260\,\mathrm{MPa}$. Der Femur ist mit $4 \times$ M3 auf $r = 7\,\mathrm{mm}$ an sein Horn geschraubt: $$ F = \frac{3.43}{4 \cdot 0.007} = 122\,\mathrm{N}, \qquad \tau = \frac{122}{5.03} = 24\,\mathrm{MPa}, \qquad S = 10.7 $$ Die Schraube ist selten das Problem. Der Kunststoff um sie herum schon. Die **Lochleibung** ist die Kraft über der projizierten Fläche der Bohrung (Durchmesser $d$, Materialdicke $t$): $$ p = \frac{F}{d\,t} $$ Für die Hornschrauben der Hüfte in der Servohalterung sind das $17.9\,\mathrm{MPa}$ gegenüber $47\,\mathrm{MPa}$ ($S = 2.6$), der niedrigste Wert der Schraubverbindungen. ## Ausreißen und Anziehdrehmoment {#pull-out-and-tightening-torque} Eine gewindeformende Schraube in einer gedruckten Vorbohrung hält über das Kunststoffgewinde, das sie schneidet. Wird stark genug gezogen, schert sie einen Kunststoffzylinder heraus (*ausreißen*) mit Durchmesser $d$ und Einschraublänge $L_e$. Die Scherfestigkeit quer zu den Schichten beträgt $\tau = 0.577 \cdot 18 = 10.4\,\mathrm{MPa}$: $$ F_\text{pull} = \tau\,\pi\,d\,L_e $$ Das Anziehen wandelt Drehmoment in axiale Vorspannkraft um. Der größte Teil des Drehmoments geht in Reibung im Gewinde und unter dem Kopf. Der *Mutternfaktor* $k$ (etwa 0,2 für trockene Edelstahlgewinde) fasst all das in einer Zahl zusammen: $$ T = k\,F\,d $$ Jede gedruckte Vorbohrung hat also ein Drehmoment, bei dem sie ausreißt. Beispiel: Die Schrauben der Knieachse greifen $L_e = 4.0\,\mathrm{mm}$ in den Femur ein: $$ F_\text{pull} = 10.4 \cdot \pi \cdot 3 \cdot 4 = 392\,\mathrm{N}, \qquad T_\text{strip} = 0.2 \cdot 392\,\mathrm{N} \cdot 0.003\,\mathrm{m} = 0.24\,\mathrm{N\,m} $$ **Ziehen Sie höchstens mit der Hälfte davon an, etwa $0.12\,\mathrm{N\,m}$.** Das ist eine sanfte Zwei-Finger-Drehung am kurzen Arm eines 2,5-mm-Innensechskantschlüssels: satt, nicht fest. Der [Festigkeitsbericht](../../verification/strength.md#tightening-torque-into-printed-pilots) listet die Grenze für jede gedruckte Vorbohrung (0,05–0,35 N·m). Zum Vergleich: Eine M3-A2-70-Schraube in einer Stahlmutter verträgt bis etwa $1.26\,\mathrm{N\,m}$ (Bossard, $\mu = 0.2$), zehnmal mehr. ## Lager {#bearings} Kugellager haben eine **statische Tragzahl** $C_0$: die Last, bei der die Laufbahnen bleibend eingedrückt werden. Der statische Sicherheitsfaktor ist $S_0 = C_0 / F_r$. Die beiden Kniegelenklager teilen sich die Kniekraft (237 N: Landung plus die größte Koppelkraft). Jedes 633ZZ sieht daher $118\,\mathrm{N}$ gegenüber $C_0 = 490\,\mathrm{N}$ (Koyo), $S_0 = 4.2$. Drehende Lager verschleißen außerdem durch Ermüdung. Ihre **nominelle Lebensdauer** in Millionen Umdrehungen folgt aus der dynamischen Tragzahl $C$ und der äquivalenten Last $P$: $$ L_{10} = \left(\frac{C}{P}\right)^3 \quad [10^6\ \text{revolutions}] $$ 90 % der Lager erreichen diese Lebensdauer. Die Kniegelenke schwingen nur über einen kleinen Winkel, daher zählt hier die statische Tragzahl mehr. Für die No-Name-Lager des Sortiments wird angenommen, dass sie nicht besser sind als die Tragzahlen der Markenlager. ## Prüfen Sie sich selbst {#check-yourself} 1. Ein Servo ist mit 25 kg·cm angegeben. Welche Kraft kann es im rechten Winkel über einen 20-mm-Arm drücken? 2. Warum liegt eine gedruckte Koppel flach auf dem Druckbett, statt aufrecht zu stehen? 3. Sie machen eine Koppel 1,5 × dicker. Wie ändern sich ihre Biegefestigkeit und ihre Knicklast? 4. Was begrenzt das Biegemoment in den Beinen, die Landung oder das Servo? 5. Eine Vorbohrung fasst 6 mm einer M3-Schraube. Wie groß ist nach der Regel dieser Seite das maximale Anziehdrehmoment?
Antworten 1. $T = 25 \cdot 9.81 \cdot 0.01 = 2.45\,\mathrm{N\,m}$; $F = 2.45 / 0.020 = 123\,\mathrm{N}$. 2. Damit die Biegespannung entlang der Schichten ($47\,\mathrm{MPa}$) verläuft statt quer zu ihnen ($18\,\mathrm{MPa}$ Schichthaftung). 3. Biegung über diese Dicke: $W \propto h^2$, also $2.25\times$. Knickung darüber: $I \propto h^3$, also $3.4\times$. 4. Das Blockiermoment des Servos ist die Auslegungslast: Darüber gibt das Knie nach. Ein Getriebeservo rückwärts anzutreiben erfordert mehr als sein Blockiermoment, daher können harte Stöße die Auslegungslast überschreiten; Bolzen und Lager sehen immer die volle Landekraft. 5. $F = 10.4 \cdot \pi \cdot 3 \cdot 6 = 588\,\mathrm{N}$; $T_\text{strip} = 0.2 \cdot 588 \cdot 0.003 = 0.35\,\mathrm{N\,m}$; ziehen Sie mit höchstens etwa $0.18\,\mathrm{N\,m}$ an.
## Weiterführende Literatur {#further-reading} - R. C. Hibbeler, *Mechanics of Materials*: Spannung, Biegung, Knickung, die Lehrbuchbehandlung jeder Formel oben. - [Technisches Datenblatt Prusament PETG](https://www.prusa3d.com/file/3464616/prusament-petg-technical-data-sheet.pdf): die hier verwendeten Werte für gedruckte Zugfestigkeit und Schichthaftung. - [Bossard: Vorspannkraft und Anziehdrehmomente (VDI 2230)](https://assets.eu.ctfassets.net/0vp0u5uh75zd/3S40LEUM235Qk3rJk2phR1/c715f9f45232756c12b59aa681c7fede/060_074_Preload_tightening_torques_Fastening_EN_01_2025.pdf). - [SKF-Rillenkugellager](https://www.skf.com/group/products/rolling-bearings/ball-bearings/deep-groove-ball-bearings): Tragzahlen, statische Sicherheit und nominelle Lebensdauer. - Verwandt in diesem Wiki: [Statik und Dynamik](../theory/statics-and-dynamics.md), [Befestigungselemente](fasteners.md), [3D-Druck](3d-printing.md), [Mechanik und Lager](../hardware/mechanics.md), [Servos](../hardware/servos.md). --- # Werkzeuge und Werkstatt {#tools-and-workshop} Für den Bau von Strido brauchen Sie einen kleinen Satz Handwerkzeuge, einen Lötkolben, eine Dupont-Crimpzange und ein Multimeter sowie einen 3D-Drucker. Diese Seite listet sie auf, erklärt die elektrischen Techniken des Kabelbaums (Löten, Crimpen, Hebelklemmen, Schrumpfschlauch) und die Multimeter-Prüfungen, die Verdrahtungsfehler aufdecken, bevor sie ein Board kosten. ::: tip In Strido Die Werkzeuge sind in der Stückliste unter [Werkzeuge (nicht in den Summen)](../../bom/README.md#tools-not-in-the-totals) und in Abschnitt E (*Werkzeuge und Verbrauchsmaterial*) des Katalog- und Montagebuchs ([Katalog](../../catalog.md)) aufgeführt. Die Kabelbaum-Schritte und Spannungsprüfungen stehen in [electronics.md](../../electronics.md#wiring-harness); Montageschritt 0 listet die Werkzeuge pro Aufgabe auf ([Montageanleitung](../../assembly/README.md)). ::: ## Die Werkzeugliste {#the-tool-list} Aus Abschnitt E des Katalogs (wofür jedes Werkzeug dient) und der Werkzeugtabelle der Stückliste (Beispielprodukte): | Werkzeug | Verwendung in Strido | Beispiel in der Stückliste | |---|---|---| | Innensechskantschlüssel 1,5 / 2,0 / 2,5 mm | M2- / M2.5- / M3-Zylinderköpfe | Wera 950/9 Hex-Plus Satz | | Steckschlüssel 4,0 / 5,0 / 5,5 mm | Halten der M2- / M2.5- / M3-Muttern | nicht bepreist | | Bohrer 2,2 / 2,7 / 3,2 mm (Hand oder Stiftenklöbchen) | Nachbohren der engen Löcher aus dem [Passungsbericht](../../verification/fits.md) | — | | Seitenschneider (bündig), Entgrater | Entfernen von Stützen und Brims | Wiha 26812 | | Lötkolben, Lot, Schrumpfschlauch | Stromeingang, XT60-Steckverbinder, Spleiße, XIAO-Pins, PCA9685-OE-Pull-up | Miniware TS101; Lot (`solder`) und das Schrumpfschlauch-Sortiment sind in der Stückliste | | Abisolierzange | Abisolieren von 14–22 AWG Silikonlitze | Jokari Super 4 plus | | Dupont-Crimpzange, Kontakte + Gehäuse | Pi-5-V-Versorgung (W12), W17/W20 am PCA9685, die 12 neu gecrimpten Servo-Signaldrähte | DxCRIMP-Set; Kontakte und Gehäuse: `dupont_crimp_contacts` (610-teiliges Set) in der Stückliste | | Spiralschlauch, Kabelbinder, selbstklebende Kabelbinder-Sockel | Verlegen des Kabelbaums: Spiralschlauch um jedes Bündel aus drei oder mehr Kabeln, Kabelbinder an den markierten Stellen, zwei Sockel 13 × 13 mm auf den seitlichen Deckleisten | in der Stückliste (`spiral_wrap`, `cable_ties` Beutel à 100, `cable_tie_mounts`) | | Multimeter | 6,0-V-UBEC-Prüfung, 5-V-Schiene, OE-Spannung | Kaiweets | | Messschieber | Messen gedruckter Löcher, Lager, Schraubenlängen | — | | Mittelfeste Schraubensicherung | nur für Schrauben in Metallhörnern (nie in gedruckten Löchern) | in der Stückliste (Befestigungselemente) | | Dünnflüssiger Sekundenkleber (CA) | Härten schwacher gedruckter Vorbohrungen (ADR-009-Rückfallebene) | beliebiger flüssiger Sekundenkleber | | LiPo-Balancer-Ladegerät + LiPo-Tasche | Akkupflege | in der Stückliste (Versorgung) | | USB-C-Kabel | Flashen des XIAO ESP32-S3 | — | | 3D-Drucker, Druckbett ≥ 220 × 220 mm | alle Druckteile (Schalen messen 114 × 208 mm) | z. B. Bambu Lab A1 Combo | Warum ein Stiftenklöbchen und keine Bohrmaschine zum Nachbohren? Sie wollen nur die 0,1–0,2 mm Kunststoff entfernen, die der Druck hinzugefügt hat; eine Bohrmaschine erhitzt PETG, verhakt sich und kann einen dünnen Dom sprengen. ## Einrichtung des Arbeitsplatzes {#workspace-set-up} - **Eine ebene, nicht brennbare Unterlage** zum Löten und Laden, ohne Brennbares in Reichweite des Lötkolbens oder der LiPo-Tasche. - **Gutes Licht und eine Lupe** für die 2,54-mm-Dupont-Pins und die kleinen Adafruit-Boards. - **Teileschalen** pro Montageschritt: Die Teileboxen der Anleitung listen genau, welche Schrauben jeder Schritt verwendet; sortieren Sie diese also zuerst. - **Belüftung** beim Löten (Flussmitteldämpfe) und beim Drucken. - **Eine antistatische Gewohnheit**: Berühren Sie einen geerdeten Metallgegenstand, bevor Sie Pi, XIAO, IMU oder PCA9685 anfassen, und halten Sie Boards an den Kanten (siehe [Sicherheit](safety.md)). - **Eine Tischversorgung**: Das in der Stückliste empfohlene Raspberry Pi 27 W USB-C-Netzteil versorgt den Pi allein für Softwarearbeiten, sodass der LiPo am Schreibtisch nicht nötig ist. ## Löten {#soldering} Löten verbindet zwei Metalle mit einer niedriger schmelzenden Legierung. Eine gute Lötstelle entsteht, indem Sie **beide Teile** mit dem Lötkolben erhitzen und das Lot in die Verbindung zuführen, nicht auf die Lötspitze. Wo Sie an diesem Roboter löten: | Lötstelle | Draht | Hinweise | |---|---|---| | Akkueingang XT60H: W01 (+) und W04 (−) | 14 AWG | Große Kontakte brauchen eine heiße, breite Spitze; Lötkelch und Draht vorverzinnen | | Arming-Port XT60H: W02/arming an Kontakt 1, W03 an Kontakt 2; die Brücke des Loop-Keys | 14 AWG | der Loop-Key verbindet die beiden Kontakte des Ports; prüfen Sie zuerst seinen Kontakttyp (Multimeter-Tabelle unten) | | Leitungen des Hauptsicherungshalters: W01 ein, W02 aus | 14 AWG | jede Lötstelle mit Schrumpfschlauch versehen | | Spleiß in der Rückschale: W02, W02/arming und die eigene Leitung des Logik-Sicherungshalters | 14 AWG | Spleiß mit Schrumpfschlauch; die 14-AWG-Leitung des Halters ist der Logikabgriff (kein dünnerer Draht hinter der 25-A-Sicherung) | | Spleiß unter dem Deck: W03 → beide UBEC IN+ | 14 AWG | Spleiß mit Schrumpfschlauch | | Massestern W04 neben dem Akkueingang | 14 AWG zu beiden UBEC IN−, 18 AWG zu GND des Schalters | ein Sternpunkt; mit Schrumpfschlauch versehen | | UBEC-Ausgänge W05 / W06 | 18-AWG-Paar | verlängert die Ausgangsleitung jedes UBEC | | Logik-Sicherungsausgang (W09), Spannungsregler ein und aus (W11, W24 Masse, W12) | 18 / 22 AWG | die Schalter- und INA260-Enden von W09–W11 und W24 sind Schraubklemmen | | Tasterpaar W13 | 22 AWG | jede Lötstelle mit Schrumpfschlauch versehen | | XIAO-Pins: W17 (3V3, GND, SDA, SCL), W20 (D3), W21 (Dupont-Enden des Displaykabels) | 22 AWG / Displaykabel | kein Platz für Dupont-Gehäuse 9 mm unter dem oberen Schulterrahmen. Zwei Drähte teilen sich den XIAO-3V3-Pin und zwei den GND-Pin (W17 und W21): beide an den Pin löten | | 2,2 kΩ OE-Pull-up | Widerstandsbeinchen | an der PCA9685-Stiftleiste, von OE nach VCC; vor der Montage des Boards löten (Schritt 7) | Technik, der Reihe nach: 1. Schneiden Sie den Draht auf die Länge aus der Zuschnittliste im [Verkabelungscheck](../../verification/wiring.md) zu, isolieren Sie gerade so viel ab, dass der Lötkelch oder die Verbindung gefüllt ist (die Zuschnittliste sieht 6 mm pro gelötetem Ende vor), und verdrillen Sie die Litzen. 2. **Schieben Sie den Schrumpfschlauch zuerst auf den Draht.** Nach dem Anlöten des Steckverbinders geht das nicht mehr. 3. Verzinnen Sie Draht und Kontakt getrennt, fügen Sie sie dann zusammen und erhitzen Sie erneut, bis das Lot in beide fließt. 4. Halten Sie still, bis das Lot erstarrt ist: Eine bewegte Lötstelle sieht matt und körnig aus und ist schwach („kalte Lötstelle“). 5. Prüfen: Eine gute Lötstelle ist glatt und glänzend (bleifreies Lot ist etwas matter), die Litzen sind unter dem Lot sichtbar. Der Adafruit-Leitfaden empfiehlt an einem temperaturgeregelten Lötkolben etwa 370 °C für bleihaltiges und 400 °C für bleifreies Lot; schwere XT60-Kontakte an 14 AWG brauchen die Hitze, aber keine lange Verweildauer, sonst erweicht der Kunststoff des Steckverbinders. Wenn Sie den XT60 beim Löten mit seinem Gegenstück stecken, bleiben die Kontakte ausgerichtet. ## Dupont-Steckverbinder crimpen {#crimping-dupont-connectors} Ein Crimp verbindet einen Draht mit einem Kontakt, indem Metall kalt um ihn verformt wird. Die Dupont-Crimpzange formt zwei Flügelpaare: Das vordere Paar beißt in den blanken Leiter, das hintere Paar greift die Isolierung als Zugentlastung. Der fertige Kontakt rastet in ein Kunststoffgehäuse ein, das auf einen 2,54-mm-Stiftleistenpin gesteckt wird. Crimps in Strido: - **W12:** die 5-V-Versorgung vom Spannungsregler D36V50F5 zu den Raspberry-Pi-Pins 2 und 4 (5 V) sowie 6 und 14 (GND), 22 AWG, ein Draht pro Pin, weil jeder Pin etwa 1,6 A führt. Dicke Silikonisolierung passt eventuell nicht in die Isolationsflügel; kürzen Sie sie oder verwenden Sie dünnwandigen Draht. - **W17 und W20 am PCA9685:** die I²C-Drähte (3V3, GND, SDA, SCL) und der OE-Draht, am XIAO-Ende gelötet, auf die linke Stiftleiste des PCA9685 gecrimpt. - **Die 12 Servo-Signaldrähte:** Das eigene Servokabel jedes Servos läuft zu einem Kabelbinder, wo die roten und braunen Adern für den WAGO-Bus abgetrennt werden. Die orange Signalader wird **abgelängt** und mit einem Dupont-Buchsenkontakt in einem **1-Pin-Gehäuse** **neu gecrimpt**, das auf den PWM-Pin ihres PCA9685-Kanals gesteckt wird. Es gibt keine Servoverlängerungen: Jedes Stecker-Buchse-Paar, das Sie weglassen, ist ein Kontakt weniger, der sich in einem laufenden Roboter lockern kann ([Kabelmanagement](cable-management.md)). Schneiden Sie die orange Ader so ab, dass sie ihren Kanal ohne Zug erreicht; die vorderen Knieleitungen haben nur 12 mm Reserve. Crimpen statt löten an diesen Enden: Ein Crimp lässt die Litzen bis zum Kontakt flexibel, und seine Isolationsklemmung entlastet den Zug. Prüfungen für jeden Crimp: - Zugprobe: Ein kräftiger Ruck darf den Draht nicht herausziehen. - Keine Litzen außerhalb des Kontakts. - Der Kontakt rastet im Gehäuse ein (er darf sich nicht nach vorne herausschieben lassen). ## Hebelklemmen (WAGO) {#lever-clamps-wago} Der Servo-Versorgungsbus besteht aus WAGO-221-415-Hebelklemmen: kein Werkzeug nötig, aber die Abisolierlänge zählt. Isolieren Sie **11 mm** ab (WAGO-Datenblatt), öffnen Sie den Hebel, schieben Sie den Leiter ein, bis die Isolierung am Gehäuse anliegt, schließen Sie den Hebel und ziehen Sie daran. Durch das transparente Gehäuse sehen Sie, dass das Kupfer bis zum Ende reicht. Der rote Draht jedes Servos kommt in die obere (V+) Klemme des Beins, der braune in die untere (GND), Anschlüsse Hüfte 1, Oberschenkel 2, Knie 3; ein Draht pro Eingang. Verdrahten Sie jede WAGO-Klemme, bevor Sie sie in ihren Halter schieben: Vor Ort ist kein Platz, um die Hebel zu öffnen. ## Schrumpfschlauch {#heat-shrink} Schrumpfschlauch schrumpft beim Erhitzen auf etwa die Hälfte seines Durchmessers (ein gängiges Verhältnis; prüfen Sie Ihr Sortiment) und isoliert und entlastet so eine Verbindung. Wählen Sie eine Größe, die vor dem Schrumpfen über die Verbindung gleitet und danach eng anliegt. Decken Sie jede freiliegende Lötstelle im Leistungspfad ab. Verwenden Sie ein Heißluftgerät oder die Seite des Lötkolbenschafts statt einer Flamme in der Nähe eines LiPo. ## Multimeter-Prüfungen {#multimeter-checks} Ein Multimeter ist die billigste Versicherung beim Bau. Die Kabelbaum-Schritte schreiben diese Messungen vor: | Wann | Wo | Erwartet | Falls nicht | |---|---|---|---| | Vor dem Anschließen eines Servos | jeder UBEC-Ausgang, ohne Last | **5,8–6,0 V** | der Servo ist bis 6,0 V spezifiziert: ein Gerät mit höherem Wert zurückgeben; prüfen, ob der Jumper offen ist (keine 7,4-V-Einstellung) | | Vor dem Anstecken an den Pi | Dupont-Enden von W12, Sicherungen eingesetzt, Taster gedrückt | **4,8–5,2 V** (D36V50F5: 5 V ± 4 %) | nicht anstecken; Polarität und Spannungsregler prüfen | | Rauchtest | PCA9685 OE, während der XIAO im Bootloader ist (BOOT halten, RESET drücken) | **≥ 2,4 V** (Ausgänge aus) | der 2,2-kΩ-Pull-up fehlt oder liegt nicht an VCC | | Vor dem ersten Einschalten (gute Praxis) | Widerstand zwischen + und − am Akkueingang, kein Akkupack angeschlossen | nicht nahe 0 Ω | ein Kurzschluss: finden Sie ihn, bevor Sie den Akku anschließen | | Vor dem Überbrücken des Loop-Keys | das *nicht überbrückte* Steckergehäuse am Akkustecker probieren | darf **nicht** passen | falscher Kontakttyp: siehe die XT60-Regel in [electronics.md](../../electronics.md#xt60-contact-rule-the-loop-key-must-never-fit-the-battery) | Messen Sie Spannung mit der schwarzen Messspitze an Masse (COM) und der roten am Messpunkt; stellen Sie das Messgerät auf Gleichspannung in einem Bereich über 8,4 V (der volle 2S-Akkupack). Der Durchgangsmodus (Piepton) ist praktisch, um zu prüfen, ob ein Draht dorthin führt, wo die Verdrahtungsliste es angibt. ## Selbstkontrolle {#check-yourself} 1. Warum muss der Schrumpfschlauch vor dem Löten des XT60 auf den Draht? 2. Welche drei Innensechskant-Größen brauchen Sie, und warum genau diese? 3. Was macht das hintere Flügelpaar eines Dupont-Crimps? 4. Welche Spannung muss ein UBEC zeigen, bevor ein Servo angeschlossen wird, und warum disqualifiziert ihn ein höherer Wert? 5. Warum bohrt man enge Löcher mit einem Stiftenklöbchen statt mit einer Bohrmaschine nach? 6. Warum wird die orange Signalader jedes Servos abgelängt und neu gecrimpt, statt mit einem Verlängerungskabel angesteckt zu werden?
Antworten 1. Sobald der Steckverbinder angelötet ist, lässt sich der Schlauch nicht mehr darüberschieben. 2. 1,5, 2,0 und 2,5 mm: die Schlüsselweiten der M2-, M2.5- und M3-Zylinderschrauben. 3. Es greift die Isolierung als Zugentlastung; das vordere Paar greift den Leiter. 4. 5,8–6,0 V ohne Last. Der SPT5435LV ist nur für 4,8–6,0 V spezifiziert, alles über 6,0 V überlastet also die Servos. 5. Nur 0,1–0,2 mm müssen weg; eine Bohrmaschine erhitzt den Kunststoff, verhakt sich und kann dünne Dome sprengen. 6. Eine Verlängerung fügt pro Servo ein Stecker-Buchse-Paar hinzu, das sich durch Vibration lockern kann, plus zusätzlichen Draht zum Verstauen. Abgelängt führt die Leitung mit einem Kontakt direkt zu ihrem PCA9685-Kanal.
## Weiterführende Literatur {#further-reading} - [Adafruit Guide to Excellent Soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering) - [Pololu D36V50F5 Abwärtsspannungsregler](https://www.pololu.com/product/4091) - [Elektronik, Verkabelung und Versorgung](../../electronics.md) und die [Montageanleitung](../../assembly/README.md) - [WAGO 221-415 Datenblatt](https://wago.priintcloud.com/datasheets/221-415/en) - [Molex Quality Crimping Handbook](https://www.molex.com/content/dam/molex/molex-dot-com/products/automated/en-us/commercialcrimpbookpdf/638/63800/TM-638000029-001.pdf) - Verwandt in diesem Wiki: [Kabelmanagement](cable-management.md), [Sicherheit](safety.md), [Versorgung](../hardware/power.md), [Befestigungselemente](fasteners.md) --- # Lernen {#learn} Das Lern-Wiki erklärt die Technik hinter Strido. Sie brauchen es nicht, um den Roboter zu bauen, aber es erklärt, warum der Roboter so gebaut ist. Jeder Artikel geht vom realen Roboter aus: den Servos, Schienen und Teilen in Ihrer Hand, dem Firmware- und ROS-2-Code in diesem Repository und den Zahlen, die die Verifikationsprüfungen kontrollieren. Jeder endet mit einigen Fragen zur Selbstkontrolle und Links zu den Primärquellen. ## Lernpfade {#learning-paths} | Wenn Sie … wollen | Lesen Sie in dieser Reihenfolge | |---|---| | Den Roboter sicher bauen | [3D-Druck](making/3d-printing.md) → [Befestigungselemente](making/fasteners.md) → [Werkzeuge und Werkstatt](making/tools-and-workshop.md) → [Kabelmanagement](making/cable-management.md) → [Sicherheit](making/safety.md) | | Die Elektronik verstehen | [Leistungselektronik](hardware/power.md) → [LiPo-Akkus](hardware/batteries.md) → [Servos](hardware/servos.md) → [Busse](hardware/buses.md) → [Sensoren](hardware/sensors.md) | | Die Computer zum Laufen bringen | [Mikrocontroller und der Pi](hardware/microcontrollers.md) → [Linux auf dem Pi](software/linux-on-the-pi.md) → [Docker](software/docker.md) → [Firmware](software/firmware.md) → [ROS 2](software/ros2.md) | | Wissen, was brechen kann | [Festigkeit, Drehmoment und Versagen](making/strength.md) → [Befestigungselemente](making/fasteners.md) → [Mechanik und Lager](hardware/mechanics.md) | | Ihn besser laufen lassen | [Mechanik und Lager](hardware/mechanics.md) → [Kinematik und Gaits](software/kinematics-and-gaits.md) → [Simulation und RL](software/simulation-and-rl.md) | | Robotik von Grund auf lernen | [Koordinatensysteme und Rotationen](theory/frames-and-rotations.md) → [Kinematik](theory/kinematics.md) → [Statik und Dynamik](theory/statics-and-dynamics.md) → [Regelung](theory/control.md) → [Laufende Fortbewegung](theory/legged-locomotion.md) → [State Estimation](theory/state-estimation.md) → [Reinforcement Learning](theory/reinforcement-learning.md) | | Das Design ändern | [CAD als Code](software/cad-as-code.md) → [Mechanik und Lager](hardware/mechanics.md) → [3D-Druck](making/3d-printing.md) | ## Robotik-Theorie {#robotics-theory} Die Mathematik hinter einem laufenden Roboter, jeweils an Bein, Servos und Sensoren von Strido durchgerechnet. - [Koordinatensysteme und Rotationen](theory/frames-and-rotations.md): Koordinatensysteme, Rotationsmatrizen, Quaternionen, homogene Transformationen und der tf-Baum des Roboters. - [Kinematik](theory/kinematics.md): Vorwärts- und inverse Kinematik des Beins, das Knie-Viergelenk, die Jacobi-Matrix und Singularitäten. - [Statik und Dynamik](theory/statics-and-dynamics.md): virtuelle Arbeit, $\boldsymbol{\tau} = \mathbf{J}^\top \mathbf{F}$, mechanischer Vorteil, Trägheit sowie das Drehmoment und die Leistung, die ein Gelenk braucht. - [Regelung](theory/control.md): Rückkopplung, PD- und PID-Regelung, Abtastraten und der eigene Positionsregelkreis des Servos. - [Laufende Fortbewegung](theory/legged-locomotion.md): Gaits, Stützpolygone, Stabilität und wie der Trot-Generator die Füße setzt. - [State Estimation](theory/state-estimation.md): IMU-Modelle, Komplementär- und Mahony-Filter, das Kalman-Filter und Odometrie. - [Reinforcement Learning](theory/reinforcement-learning.md): Markov-Entscheidungsprozesse, Policy-Gradienten, PPO und Sim-to-Real. ## Hardware {#hardware} - [Servos](hardware/servos.md): Pulsbreiten, Drehmoment, Blockierstrom und das Zentrieren der 12 SPT5435LV-Gelenke. - [LiPo-Akkus](hardware/batteries.md): der 2S-Akkupack, sein Spannungsfenster, Laden, Lagerung und Handhabung. - [Leistungselektronik](hardware/power.md): von XT60 zu Sicherungen, UBECs und dem Spannungsregler, Drahtquerschnitte und Leistungsüberwachung. - [Mikrocontroller und der Pi](hardware/microcontrollers.md): warum ein echtzeitfähiger ESP32-S3 neben einem Linux-Raspberry-Pi-5 sitzt. - [Busse: I²C, UART, SPI, PWM](hardware/buses.md): wie die Boards miteinander kommunizieren. - [Sensoren](hardware/sensors.md): IMU, LiDAR, Kamera und Power-Monitor und was die Software damit macht. - [Mechanik und Lager](hardware/mechanics.md): das Koppelgetriebe des Beins, Lager, Passungen und Gelenkgrenzen. ## Software {#software} - [Linux auf dem Pi](software/linux-on-the-pi.md): das Betriebssystem, Headless-Einrichtung, SSH, Berechtigungen und Dienste. - [Docker](software/docker.md): Container und wie die Robotersoftware in einem davon läuft. - [ROS 2](software/ros2.md): Nodes, Topics, Launch-Dateien und tf, anhand der eigenen Pakete des Roboters. - [Firmware](software/firmware.md): die ESP32-S3-Regelschleife, das serielle Protokoll, Kalibrierung und Failsafes. - [Kinematik und Gaits](software/kinematics-and-gaits.md): Beingeometrie, inverse Kinematik und der Trot. - [Simulation und RL](software/simulation-and-rl.md): MuJoCo, Gazebo, PPO-Training und die Sim-to-Real-Lücke. - [CAD als Code](software/cad-as-code.md): wie der Roboter aus Code entworfen, verifiziert und veröffentlicht wird. ## Fertigung {#making} - [3D-Druck](making/3d-printing.md): PETG, Ausrichtung, Stützen und das verifizierte Slicer-Profil. - [Befestigungselemente](making/fasteners.md): Schrauben in gedrucktem Kunststoff, Vorbohrungen, Einschraubtiefe und Schraubensicherung. - [Werkzeuge und Werkstatt](making/tools-and-workshop.md): was Sie brauchen und wie Sie löten, crimpen und messen. - [Kabelmanagement und der Kabelbaum](making/cable-management.md): Drahtquerschnitte, Sicherungen, Bewegungsschlaufen über die Hüfte, Biegeradius, Bündelung, Steckverbinder und die im CAD geroutete Zuschnittliste. - [Festigkeit, Drehmoment und Versagen](making/strength.md): Drehmoment, Spannung, Schichtausriss, Knicken, Schraubenabscherung und Anzugsmomente, an den eigenen Teilen des Roboters durchgerechnet. - [Sicherheit](making/safety.md): LiPo-Sicherheit, erstes Einschalten, Sicherungen und bewegte Beine. Das [Glossar](glossary.md) definiert jeden auf dieser Website verwendeten Begriff. --- # CAD als Code {#cad-as-code} Bei Code-CAD werden Teile nicht per Mausklick in einer GUI gezeichnet; sie sind Python-Programme, die Geometrie erzeugen. Strido geht noch weiter: Jede physische Aussage über den Roboter (Schrauben passen, Beine kollidieren nicht, Teile lassen sich drucken, die Verkabelung liegt innerhalb ihrer Nennwerte) ist eine ausführbare Prüfung, die den Build scheitern lassen kann. Diese Seite erklärt die Pipeline, die Prüfungen und warum sie so aufgebaut ist. ::: tip In Strido - **CAD-Paket:** `packages/strido-cad` (CadQuery 2.8 für Volumenkörper, manifold3d für robuste Mesh-Booleans, trimesh für Mesh-Arbeit). - **Verifikationspaket:** `packages/strido-verify` (Durchdringung, Bewegungsbereich, Passungen, Freigang, Sensor-Sichtfeld, Druckbarkeit, Elektronik). - **Veröffentlichungspaket:** `packages/strido-publish` (Druckpaket, Stückliste, Anleitung, Renderings, 3D-Ansicht, Katalogbuch). - **Daten:** `hardware/*.yaml` (Kinematik, Gelenkgrenzen, Stückliste, Elektronik, Befestigungselemente), Toleranzbänder in `hardware/verification/tolerances.yaml`. - **Entscheidungsprotokoll:** ADR-002 „CAD as code, verification as gates“ in [Entscheidungen](../../decisions.md); Nachweise in [Verifikation](../../verification.md). ::: ## Warum Code statt einer GUI-CAD-Datei {#why-code-instead-of-a-gui-cad-file} Eine GUI-CAD-Datei hält fest, *was* die Geometrie ist. Code hält auch fest, *warum*: Die Konstante `PEDESTAL_PILOT_DEPTH = 11.0` steht neben ihrem Kommentar „Schraubenspitze 10,0 mm tief im Sockel“. Code-CAD überträgt Software-Gewohnheiten auf Hardware: | Software-Gewohnheit | Wirkung auf den Roboter | |---|---| | Versionskontrolle mit lesbaren Diffs | Eine geänderte Lochtiefe ist eine Zeile im Review, keine undurchsichtige Binärdatei | | Eine einzige Quelle der Wahrheit | Koppellängen werden einmal gemessen und in Python und C++ *generiert*; niemand tippt sie zweimal ein | | Automatisierte Tests | Ein falsches Loch scheitert an einer Prüfung, bevor es jemand druckt | | Reproduzierbare Builds | `make publish` erzeugt jede STL, Druckplatte, Stückliste und Anleitungsseite aus denselben Eingaben neu | Die Motivation in ADR-002 ist konkret: Menschen drucken und montieren allein auf Basis dieses Repositorys, und ein falsches Loch kostet einen Neudruck. ## Von einem realen, gebauten Design ausgehen {#start-from-a-real-built-design} Strido modelliert den Roboter nicht neu. Die Mechanik stammt aus dem Upstream-Projekt Yertle: dessen STEP-Baugruppe (`upstream/yertle/design/CAD/Yertle_Single_v2.step`) und dessen veröffentlichte Druck-STLs, die tatsächlich gedruckt und montiert wurden. Diese Dateien bleiben byteidentisch (ADR-004); jede Strido-Änderung ist eine Boolesche Operation darauf, und Korrekturen von Upstream-Fehlern werden als Daten (`hardware/assembly/corrections.yaml`) oder abgeleitete Teile (`left_servo_mount_fl`, `right_servo_mount_fr`) ausgedrückt. ## Die Pipeline {#the-pipeline} ```mermaid flowchart TD STEP["upstream STEP + STLs"] --> CACHE["step_cache: einmal tessellieren"] CACHE --> REG["register_upstream: STL ↔ STEP"] CACHE --> KIN["extract_kinematics"] --> KY["hardware/kinematics.yaml"] KY --> ROM["strido_verify.rom"] --> JL["hardware/joint_limits.yaml"] KY --> GEN["codegen"] JL --> GEN GEN --> PY["strido/geometry.py"] GEN --> H["geometry_generated.h"] REG --> PARTS["Teile + Katalog: neue/geänderte Teile,
Herstellermodelle, Befestigungselemente"] PARTS --> ASM["Baugruppe: posiert mit dem exakten Bein-Koppelgetriebe"] ASM --> GATES["Verifikationsprüfungen"] ASM --> MODELS["Modelle: URDF, MJCF, Meshes"] ASM --> PUB["Veröffentlichung: Druckpaket, Stückliste, Anleitung,
Renderings, Ansicht, Katalog"] ``` Wichtige Schritte: 1. **`step_cache`** tesselliert jeden Volumenkörper der 32-MB-STEP-Datei einmal und speichert die Meshes im Cache, mit dem Datei-Hash als Schlüssel, damit er nie unbemerkt veraltet. 2. **`extract_kinematics`** vermisst den Roboter anhand von Zylinderachsen im CAD (Servoverzahnungen, Lagerbohrungen, Koppelbolzen): Hüft-/Oberschenkel-/Knieachsen, Koppellängen, die beiden Knie-Koppelgetriebe. „Nichts wird von Hand eingetippt.“ So fand es zum Beispiel eine Koppellängen-Abweichung von 1,02 mm in der Upstream-STEP ([Design](../../design.md#kinematics)). 3. **`rom`** fährt jedes Bein in einem 5°-Raster durch seinen Bereich, posiert dabei die gesamte Baugruppe mit dem exakten Knie-Koppelgetriebe und schreibt die kollisionsfreien Gelenkgrenzen. 4. **`codegen`** schreibt diese Zahlen in `packages/strido-core/src/strido/geometry.py` und `firmware/.../geometry_generated.h`. Gait, Simulation, NT-X-Adapter und Firmware lesen alle dieselben generierten Werte ([Kinematik](kinematics-and-gaits.md)). 5. **`parts`** baut die Strido-Teile. Ein reales Beispiel, der LiDAR-Sockel (gekürzt aus `parts.py`): ```python outer = box(cx - PEDESTAL_HALF, cy - PEDESTAL_HALF, z0, cx + PEDESTAL_HALF, cy + PEDESTAL_HALF, z1).edges("|Z").fillet(4.0) inner = box(cx - 25.0, cy - 25.0, z0 - 1, cx + 25.0, cy + 25.0, z1 - 3.0) shape = outer.cut(inner) # hollow, 3 mm top plate for dx, dy in PEDESTAL_SCREWS: # M3 pilot holes from below cuts.append(cylinder((cx + dx, cy + dy, z0), (0, 0, 1), 1.3, -0.1, PEDESTAL_PILOT_DEPTH)) return boolean(to_mesh(shape), cut=cuts) ``` `box` und `cylinder` liefern CadQuery-Workplanes; `boolean` wandelt für die finalen Schnitte in manifold3d-Volumenkörper um, die selbst auf den tessellierten Upstream-Meshes wasserdicht bleiben. 6. **`assembly`** platziert jede Instanz (gedruckt, zugekauft, Befestigungselement) auf einem Starrkörper (`base`, `FL.thigh`, `FL.crank` …) und kann den Roboter in beliebigen Gelenkwinkeln posieren. Jede Prüfung läuft auf diesem realen Mechanismus, nicht auf einer vereinfachten URDF. ## Die Verifikationsprüfungen {#the-verification-gates} Eine **Prüfung** ist ein Programm, das mit Code 1 endet, wenn eine Regel verletzt ist, sodass `make` stoppt. Jede schreibt einen versionierten Bericht unter `docs/verification/`. Toleranzbänder und Kontaktregeln liegen samt Begründung in YAML; laut ADR-002 darf eine Prüfung nur durch eine dokumentierte Entscheidung gelockert werden. | Prüfung | Befehl | Was sie beweist | |---|---|---| | Lochstapel und Befestigungselemente | `python -m strido_cad.hole_stacks`, `python -m strido_cad.fasteners` | Jede koaxiale Lochgruppe in den Upstream-Teilen passt zu genau einer Befestigungsregel; nicht zugeordnete Löcher scheitern | | Durchdringung | `python -m strido_verify.contacts` | Keine Volumenkörper überlappen in 4 Posen, außer klassifizierten Kontakten (Gewindeeingriff, konstruktive Auflage ≤ 0,2 mm, Gelenke) | | Bewegungsbereich | `python -m strido_verify.rom` | Gelenkgrenzen kollisionsfrei, Übertragungswinkel ≥ 25°, Servo innerhalb ±85° | | **Passungen** | `python -m strido_verify.fits` | Jeder Schrauben- und Lagersitz hat eine Passung, die nach dem FDM-Druck funktioniert | | **Freigang** | `python -m strido_verify.clearance` | Bewegte Teile halten in jeder Betriebspose einen Laufspalt | | Sensor-Sichtfeld | `python -m strido_verify.sensor_fov` | 720 LiDAR-Strahlen frei; die Kamera sieht den Roboter nicht | | **Elektronik** | `python -m strido_verify.electronics` | Pins, Busse, Kanäle und Leistungswerte stimmen zwischen YAML und Firmware überein | | **Druckbarkeit** | `make printability` | Jedes Teil und jede Druckplatte lässt sich in PrusaSlicer ohne Stabilitätsprobleme slicen; Wände dick genug | | Stücklistenabdeckung | `make bom` | Jedes Zukaufteil und Befestigungselement im CAD wird gekauft, mit Reserve | | Drift | `make drift` | Generierte Dateien entsprechen dem, was die Generatoren jetzt schreiben würden | `make verify` führt die mechanischen Prüfungen aus; `make check` führt alles aus (etwa 10 Minuten). ### Passungen {#fits} Die Passungsprüfung tastet die Schaftachse jeder Schraube alle 0,5 mm ab und schneidet jedes gedruckte Teil darum herum, um das Loch zu vermessen. FDM druckt Löcher etwa 0,1–0,2 mm zu klein, daher nimmt die Prüfung 0,15 mm Schrumpfung an und prüft die *gedruckte* Größe: | Passung | Regel ($d$ = Schraubendurchmesser) | |---|---| | Durchgangsloch | $\ge d + 0.05\,\mathrm{mm}$ (Warnung unter $d + 0.20\,\mathrm{mm}$: mit einem Bohrer nacharbeiten) | | Kernloch für gewindeformende Schraube | gedrucktes Kernloch $0.70$–$0.90\,d$ ($0.93\,d$ Warnung: schwacher Halt), Einschraublänge $\ge 1.5\,d$ | | Lagersitz | Bohrung −0,15 … +0,30 mm relativ zum Lageraußendurchmesser | Jede Schraube muss außerdem in etwas enden, das sie hält: einer Mutter, einem gedruckten Kernloch oder einem Gewindeteil. Der dokumentierte Lauf prüfte 223 Schrauben und 32 Lagersitze: 0 Fehler, 137 mit einer Aufgabe für den Erbauer (dieses Loch aufbohren, ein schwaches Kernloch mit CA-Kleber härten). Er fand echte Fehler, etwa 9 mm tiefe Kernlöcher im LiDAR-Sockel für Schrauben, die 10 mm herausragen; deshalb beträgt `PEDESTAL_PILOT_DEPTH` jetzt 11 mm. Siehe [Befestigungselemente](../making/fasteners.md). ### Freigang {#clearance} Die Durchdringungsprüfung beweist, dass nichts überlappt; die Freigangsprüfung beweist, dass nichts *schleift*. Zwei gedruckte Flächen können jeweils ~0,15 mm abweichen, daher müssen bewegte Teile auf verschiedenen Starrkörpern in allen 13 Betriebsposen (Stehen, Hocken, Hoch, acht Trot-Phasen, Hüften außen und innen) ≥ 0,3 mm Abstand halten, und unter 1,0 mm werden sie als knapp gemeldet. Diese Prüfung entdeckte, dass beide Vorderfüße in der Pose `hips_in` kollidierten, was zu den engeren Hüftgrenzen nach innen führte (ADR-005). ### Elektronik {#electronics} `hardware/electronics.yaml` ist die Quelle der Wahrheit für die Verkabelung. Die Prüfung stellt sicher, dass der Firmware-Header `board_config.h` genau deren Pins, I²C-Adressen, Servokanäle und Frequenzen definiert (in beide Richtungen), dass kein GPIO und keine I²C-Adresse doppelt verwendet wird und dass jeder Wandler, Schalter, jede Sicherung und jeder Draht seine Last trägt (`load ≤ fuse ≤ wire ampacity`). Ihre Tests beweisen, dass ein vertauschter Pin, ein doppelter Kanal, ein Adresskonflikt oder ein zu dünner Draht scheitern. Siehe [Stromversorgung](../hardware/power.md). ### Druckbarkeit {#printability} Statische Prüfungen (geschlossene Mannigfaltigkeit, passt auf ein 220 × 220 × 250 mm großes Druckbett, liegt auf z = 0) laufen in `make print`. Die Druckbarkeitsprüfung geht weiter: Sie slict jedes Teil mit dem echten PrusaSlicer und dem Profil des Repos (`hardware/print/prusaslicer.ini`), mit Stützen und Brim genau wie in der Druckliste vorgeschrieben, und scheitert bei Slicer-Fehlern oder Stabilitätswarnungen (frei schwebende Brückenanker, einbrechende Überhänge, geringe Betthaftung). Ein strahlbasierter Scan lässt Wände dünner als eine Extrusionslinie oder Häute dünner als eine Schicht scheitern. Außerdem slict sie jede 3MF-Druckplatte so, wie sie angeordnet ist. Ergebnis: 34 Teiletypen und 13 Druckplatten, 0 Fehler, 958 g PETG und 100 h Druckzeit. Siehe [3D-Druck](../making/3d-printing.md). ::: tip Rot gesehen Jede Prüfung im Verifikationsprotokoll dokumentiert einen Fall, in dem sie bei einem echten Problem oder einem absichtlichen Defekt *gescheitert* ist. Eine Prüfung, die nie gescheitert ist, prüft womöglich gar nichts. ::: ## Die Veröffentlichungs-Pipeline {#the-publish-pipeline} Dieselbe verifizierte Baugruppe speist jedes Artefakt, das Sie herunterladen: ```bash make print # oriented STLs (hardware/print/stl/), 3MF plates (hardware/print/plates/), print_list.md make bom # docs/bom/README.md, shopping_list.md, bom.csv + CAD coverage check make manual # docs/assembly/README.md + step drawings (Blender) make renders # hero, exploded, section, x-ray images → docs/images/ make viewer # docs/viewer/strido.glb + assembly.json for the web 3D viewer make catalog # docs/catalog/parts.json + strido-catalog.pdf (WeasyPrint) make publish # all of the above, in that order ``` Die Reihenfolge zählt: Das Katalogbuch liest die Druckliste, die Anleitung und die Rendering-Ausgabe. Da jede Instanz der Baugruppe genau einem Anleitungsschritt zugeordnet ist (sonst scheitert der Build), ergeben die Teile in Anleitung, Stückliste, 3D-Ansicht und [Katalog](../../catalog.md) stets denselben Roboter. Auch die Simulationsmodelle stammen aus derselben Baugruppe (`make models`, siehe [Simulation und RL](simulation-and-rl.md)). ## Grenzen des Ansatzes {#limits-of-the-approach} Die Prüfungen prüfen das CAD, nicht die Realität. Das [Verifikationsprotokoll](../../verification.md) sagt es klar: Noch wurde nichts gedruckt, montiert, verkabelt oder eingeschaltet (keine Q3-Hardware-Stufe). Passungen nehmen ein Schrumpfmodell von 0,15 mm an; Ihr Drucker kann abweichen, weshalb der Passungsbericht Aufgaben für den Erbauer enthält. Code-CAD verlagert Fehler nach vorne und macht sie sichtbar; den ersten physischen Aufbau ersetzt es nicht. ## Selbsttest {#check-yourself} 1. Warum baut Strido auf der Upstream-STEP auf, statt den Roboter neu zu modellieren? 2. Wie gelangt eine gemessene Koppellänge in die Firmware, ohne dass jemand sie eintippt? 3. Was ist der Unterschied zwischen der Durchdringungs- und der Freigangsprüfung? 4. Warum zieht die Passungsprüfung 0,15 mm von den CAD-Lochgrößen ab? 5. Warum muss `make catalog` nach `make print`, `make manual` und `make renders` laufen?
Antworten 1. Die Upstream-Mechanik wurde tatsächlich gedruckt und gebaut; sie per Boolescher Operation zu verändern, bewahrt diese Geschichte und erlaubt Diffs gegen Upstream-Änderungen (ADR-001, ADR-004). 2. `extract_kinematics` schreibt sie nach `hardware/kinematics.yaml`; `codegen` erzeugt `geometry_generated.h`; `make drift` scheitert, wenn der Header veraltet ist. 3. Die Durchdringungsprüfung stellt sicher, dass sich keine Volumenkörper überlappen; die Freigangsprüfung stellt sicher, dass bewegte Teile in jeder Betriebspose mindestens 0,3 mm Abstand halten, damit sie nach dem Druck nicht schleifen. 4. FDM druckt Löcher etwa 0,1–0,2 mm zu klein; die Prüfung bewertet das Loch so, wie es gedruckt wird. 5. Das Buch setzt die Druckliste, die Anleitungsschritte und die Renderings, die diese Targets erzeugen.
## Weiterführende Literatur {#further-reading} - [CadQuery-Dokumentation](https://cadquery.readthedocs.io/en/latest/) - [Geometriebibliothek Manifold](https://github.com/elalish/manifold) - [trimesh-Dokumentation](https://trimesh.org/) - [PrusaSlicer-Kommandozeilenschnittstelle](https://github.com/prusa3d/PrusaSlicer/wiki/Command-Line-Interface) - [Prusa-Wissensdatenbank: Maßgenauigkeit und Lochkompensation](https://help.prusa3d.com/article/dimensional-accuracy_2207) --- # Docker und Container {#docker-and-containers} Docker verpackt Software mit allem, was sie benötigt (Bibliotheken, ROS 2, Python-Pakete), in ein *Image*, das auf einem Laptop, einem CI-Runner und dem Roboter gleich läuft. Strido verwendet ein Image, `strido-ros:jazzy`, sowohl für die Gazebo-Simulation als auch für den echten Roboter. ::: tip In Strido - `docker/ros2/Dockerfile` erstellt das Workspace-Image mit ROS 2 Jazzy + Gazebo Harmonic für amd64 und arm64 (Raspberry Pi 5, Apple Silicon). - `docker/compose.yaml` definiert drei Services: `ros` (erstellt das Image), `sim-smoke` (Gazebo-Lauftest ohne Oberfläche) und `robot` (läuft auf dem Pi mit Zugriff auf `/dev`). - `docker/ros2/entrypoint.sh` lädt ROS 2 und den Workspace; `docker/ros2/sim_smoke.sh` ist der automatisierte Simulationstest hinter `make sim-gazebo`. - `ROS_DOMAIN_ID` ist standardmäßig `42` ([Konfiguration](../../configuration.md)). ::: ## Container im Vergleich zu virtuellen Maschinen {#containers-versus-virtual-machines} Eine **virtuelle Maschine** emuliert einen ganzen Computer: eigener Kernel, virtuelle Festplatte und virtuelle Hardware. Ein **Container** ist nur eine Gruppe normaler Prozesse auf dem Host-Kernel, isoliert mit Linux-Namespaces (eigene Sicht auf Dateisystem, Prozessliste, Netzwerk) und begrenzt mit cgroups. | | Virtuelle Maschine | Container | |---|---|---| | Kernel | Eigener Gast-Kernel | Teilt den Host-Kernel | | Start | Zehn Sekunden und mehr | Etwa eine Sekunde | | Overhead | Reservierter RAM und CPU | Fast keiner | | Hardwarezugriff | Über emulierte oder durchgereichte Geräte | Gerätedateien des Hosts lassen sich direkt einbinden | Für einen Roboter ist das wichtig: Der Pi 5 hat in diesem Aufbau 4 GB RAM, und `mcu_bridge` fragt alle 2 ms eine serielle USB-Schnittstelle ab. Ein Container bietet nahezu native Leistung und direkten Zugriff auf `/dev/strido_mcu`; eine VM würde Speicher kosten und Latenz hinzufügen. Unter macOS betreibt Docker Desktop eine kleine Linux-VM, in der die Container laufen. Deshalb funktioniert der Gazebo-Test auf einem Mac, USB-Geräte sind dort aber schwer erreichbar: Sie testen die Simulation auf dem Laptop und die Hardware auf dem Pi. ## Images und Schichten {#images-and-layers} Ein Image ist ein Stapel schreibgeschützter **Schichten** (Layer), eine je dateiändernder Anweisung im `Dockerfile`. Docker speichert Schichten zwischen: Sind eine Anweisung und alles davor unverändert, wird die zwischengespeicherte Schicht wiederverwendet. Das Strido-Dockerfile ist so geordnet, dass langsame, selten geänderte Schritte zuerst kommen: ```mermaid flowchart TD A["FROM ros:jazzy-ros-base
Ubuntu 24.04 + ROS-2-Kern"] --> B["apt-get install
ros-gz, gz-ros2-control, ros2-controllers,
xacro, robot-state-publisher, tf2-ros,
teleop-twist-keyboard, python3-serial, numpy"] B --> C["git clone sllidar_ros2
fixierter Commit"] C --> D["COPY + pip install packages/strido-core"] D --> E["COPY ros2/strido_description,
strido_bringup, strido_control"] E --> F["colcon build --symlink-install"] F --> G["entrypoint.sh: ROS + Workspace laden"] ``` Das Bearbeiten eines ROS-Nodes macht nur die letzten Schichten ungültig, daher dauert ein Neubau nach einer Codeänderung Sekunden bis Minuten, statt Gazebo neu herunterzuladen. Beachtenswerte Details: - **Fixierte Abhängigkeiten.** Der Slamtec-LiDAR-Treiber ist für Jazzy nicht paketiert, daher wird er auf einem festen Commit geklont (`ARG SLLIDAR_COMMIT=...`). Durch das Fixieren erzeugt ein Neubau im nächsten Jahr denselben Treiber. - **`--no-deps`-Installation von `strido-core`.** Das Kernpaket (Gait, Kinematik, Protokoll, NumPy-Policy-Laufzeit) benötigt zur Laufzeit nur NumPy, das apt bereits installiert hat. Weder PyTorch noch CadQuery noch MuJoCo gelangen in das Roboter-Image (ADR-003 in [Entscheidungen](../../decisions.md)). - **`rm -rf /var/lib/apt/lists/*`** im selben `RUN` wie `apt-get install` hält den Paketindex aus der Schicht heraus. Ihn in einer späteren Schicht zu löschen, würde das Image nicht verkleinern, weil frühere Schichten unveränderlich sind. - **Multi-Architektur.** `ros:jazzy-ros-base` wird für amd64 und arm64 veröffentlicht, daher baut dasselbe Dockerfile nativ auf dem Pi und auf einem Mac mit Apple Silicon. ## Container zur Laufzeit {#containers-at-run-time} Ein Container ist eine laufende Instanz eines Images plus einer dünnen beschreibbaren Schicht. Alles, was darin geschrieben wird, verschwindet, wenn der Container entfernt wird (`--rm`). Das passt zum Roboter: Zustand, der erhalten bleiben muss (Servokalibrierung), liegt im Flash des ESP32, nicht im Container. Der Entrypoint besteht aus drei Zeilen: ```bash source /opt/ros/jazzy/setup.bash source /ws/install/setup.bash exec "$@" ``` Damit sieht jeder übergebene Befehl (zum Beispiel `ros2 launch ...`) sowohl ROS 2 als auch die Strido-Pakete, und `exec` ersetzt die Shell, sodass Signale wie Strg-C ROS direkt erreichen. ## Compose: `docker/compose.yaml` des Repos {#compose-the-repo-s-docker-compose-yaml} Docker Compose beschreibt mehrere Container in einer YAML-Datei, sodass Sie sich keine langen `docker run`-Befehlszeilen merken müssen. | Service | Funktion | Wichtige Einstellungen | |---|---|---| | `ros` | Erstellt `strido-ros:jazzy` aus `docker/ros2/Dockerfile` (Kontext = Repo-Wurzel) | `network_mode: host`, `ipc: host`, `ROS_DOMAIN_ID` | | `sim-smoke` | Führt `/sim_smoke.sh` aus: Gazebo ohne Oberfläche, aufstehen, 8 s mit 0,15 m/s laufen, ≥ 0,4 m Fortschritt und Sensor-Topics prüfen | der Exit-Code ist das Testergebnis | | `robot` | Führt `ros2 launch strido_bringup robot.launch.py` auf dem Pi aus | `privileged: true`, `/dev:/dev`, Host-Netzwerk | Befehle, die Sie verwenden werden: ```bash docker compose -f docker/compose.yaml build ros # build or update the image docker compose -f docker/compose.yaml run --rm sim-smoke # headless Gazebo test (what make sim-gazebo runs) docker compose -f docker/compose.yaml run --rm robot # on the Pi: bring up the robot docker compose -f docker/compose.yaml run --rm ros bash # interactive shell with ROS 2 sourced docker compose -f docker/compose.yaml run --rm ros \ ros2 run teleop_twist_keyboard teleop_twist_keyboard # drive from a second terminal ``` `make sim-gazebo POLICY=` bindet eine gelernte Policy schreibgeschützt in den Container ein (`-v ...:/policy.npz:ro`) und setzt `POLICY=/policy.npz`, wodurch `sim_smoke.sh` `policy_node` statt `gait_node` startet. ### Warum Host-Netzwerk und Host-IPC {#why-host-networking-and-host-ipc} ROS 2 findet Nodes über DDS-Multicast und kann zwischen Prozessen auf demselben Rechner Shared Memory verwenden. Das Standard-Bridge-Netzwerk von Docker verbirgt Multicast, und ein privater IPC-Namespace verbirgt Shared Memory. `network_mode: host` und `ipc: host` setzen den Container in das Netzwerk und den IPC des Hosts, sodass ein Teleop-Container, der Roboter-Container und ein Laptop im selben WLAN (gleiche `ROS_DOMAIN_ID`) die Topics der anderen ohne zusätzliche Konfiguration sehen. Verwenden Sie je Roboter eine andere `ROS_DOMAIN_ID`, wenn sich mehrere ein Netzwerk teilen: ```bash ROS_DOMAIN_ID=43 docker compose -f docker/compose.yaml run --rm robot ``` ## Gerätezugriff {#device-access} Ein Container sieht keine Host-Hardware, sofern Sie sie nicht freigeben. Der Service `robot` tut das ohne Umschweife: ```yaml privileged: true volumes: - /dev:/dev ``` Das gesamte `/dev` per Bind-Mount einzubinden ist wichtig, weil die udev-Symlinks (`/dev/strido_mcu`, `/dev/rplidar`) vom udev des Hosts angelegt werden und ein USB-Gerät, das abgesteckt und wieder angesteckt wird, einen neuen Geräteknoten erhält. Eine feste `devices:`-Liste würde nur Knoten einbinden, die beim Start des Containers existieren. `privileged: true` hebt die Geräte-cgroup-Beschränkungen auf, sodass die neuen Knoten nutzbar sind. ::: warning Ein privilegierter Container hat nahezu volle Kontrolle über den Host. Auf einem dedizierten Roboterrechner ist das akzeptabel; verwenden Sie den Service `robot` nicht auf Ihrem Alltagslaptop. Für die Simulations-Services, die keine Hardware benötigen, sind keine Privilegien gesetzt. ::: Die udev-Regeln müssen auf dem **Host** installiert werden, nicht im Image ([Linux auf dem Pi](linux-on-the-pi.md#users-groups-and-device-permissions)). ## Was nicht im Image ist {#what-is-not-in-the-image} - **Kamera-Node.** Der Kamera-Stack des Pi 5 benötigt den libcamera-Fork von Raspberry Pi; das Image hat keinen Kamera-Node, und `robot.launch.py` verwendet standardmäßig `camera:=false`. Bauen Sie `camera_ros` auf dem Host oder verwenden Sie `rpicam-vid` mit einer GStreamer-Brücke ([Software](../../software.md#raspberry-pi-setup)). - **Firmware-Werkzeuge.** PlatformIO ist nicht installiert; flashen Sie den ESP32-S3 von einem Entwicklungsrechner aus oder installieren Sie PlatformIO auf dem Pi ([Firmware](firmware.md)). - **GUI.** Gazebo mit Fenster (`gazebo.launch.py` ohne `headless:=true`) benötigt eine X11/Wayland-Weiterleitung in den Container ([Simulation](../../simulation.md)). ## Selbsttest {#check-yourself} 1. Warum startet ein Container schneller und braucht weniger Speicher als eine VM? 2. Welche Dockerfile-Änderung löst den kürzesten Neubau aus, und warum? 3. Was funktioniert nicht mehr, wenn Sie `network_mode: host` aus dem Service `robot` entfernen? 4. Warum bindet der Service `robot` ganz `/dev` ein, statt zwei Geräte aufzulisten? 5. Wo muss `99-strido.rules` installiert sein, damit der Container `/dev/strido_mcu` sieht?
Antworten 1. Er teilt den Host-Kernel: kein Gast-Betriebssystem zu booten und kein reservierter RAM; es sind nur isolierte Prozesse. 2. Das Ändern von Dateien in `ros2/` macht nur die `COPY ros2/...`-Schichten und das anschließende `colcon build` ungültig; die apt- und Git-Schichten kommen aus dem Cache. 3. Die DDS-Erkennung über Container und Rechner hinweg; Teleop oder RViz in einem anderen Container oder auf einem Laptop würden die Topics des Roboters nicht mehr sehen. 4. udev auf dem Host legt die Symlinks an, und wieder angesteckte Geräte erhalten neue Knoten; eine statische Geräteliste würde sie verpassen. 5. Auf dem Host, in `/etc/udev/rules.d/`; der Container sieht das Ergebnis über den Bind-Mount von `/dev`.
## Weiterführende Literatur {#further-reading} - [Docker-Überblick (Images, Container, Schichten)](https://docs.docker.com/get-started/docker-overview/) - [Referenz der Compose-Datei](https://docs.docker.com/reference/compose-file/) - [Dockerfile-Referenz](https://docs.docker.com/reference/dockerfile/) - [Offizielle ROS-Images auf Docker Hub](https://hub.docker.com/_/ros) --- # Firmware auf dem ESP32-S3 {#firmware-on-the-esp32-s3} Die Firmware ist das C++-Programm auf dem Seeed XIAO ESP32-S3, das Gelenkwinkelbefehle vom Pi 200-mal pro Sekunde in Servopulse umsetzt, die IMU und den Akkumonitor ausliest und den Roboter sicher anhält, wenn etwas schiefgeht. Sie ist klein, aber sie ist die letzte Softwareschicht zwischen einem Fehler und zwölf Servos. ::: tip In Strido - **Projekt:** `firmware/strido_esp32s3` (PlatformIO, Arduino-ESP32 3.x). - **Einstiegspunkt:** `src/main.cpp`; Pins und Raten in `src/board_config.h`; LCD-Gesicht in `src/face.cpp`. - **Portabler Kern:** `lib/strido_core` (Kniekoppelgetriebe, Servozuordnung, Protokoll, Sicherheit), mit Unit-Tests auf Ihrem Computer über `pio test -e native`. - **Generiert:** `lib/strido_core/include/strido/geometry_generated.h`, aus dem CAD erzeugt von `strido_cad.codegen`; niemals von Hand bearbeiten. - **Peripherie am I²C (400 kHz):** PCA9685-Servotreiber `0x40`, LSM6DSOX-IMU `0x6A`, INA260-Power-Monitor `0x41`; ST7789V-LCD an SPI. - **Host-Seite:** `mcu_bridge` (ROS 2) und `strido-cli` (Werkbank-Werkzeug) sprechen dasselbe Protokoll über `packages/strido-core/src/strido/protocol.py`. ::: ## Warum überhaupt ein Mikrocontroller {#why-a-microcontroller-at-all} Auf dem Pi läuft Linux, das jeden Prozess für einige zehn Millisekunden anhalten kann. Ein stotterndes Servosignal lässt das Bein ruckeln; eine Sicherheitsprüfung, die „meistens“ läuft, ist keine Sicherheitsprüfung. Auf dem ESP32-S3 läuft nichts außer dieser Firmware, daher ist seine Schleifenperiode vorhersagbar. Er arbeitet auch weiter, wenn der Pi abstürzt, und genau dann brauchen Sie den Watchdog. Die Arbeitsteilung: Der Pi entscheidet, **welche** Winkel die Beine haben sollen; der ESP32 entscheidet, **wie** sie sicher erreicht werden (Koppelgetriebe-Mathematik, Anstiegsbegrenzung, Begrenzungen, Kalibrierung) und **ob** überhaupt angesteuert wird. ## Mit PlatformIO bauen, testen und flashen {#build-test-and-flash-with-platformio} PlatformIO ist ein Build-System und Paketmanager für Embedded-Code. `platformio.ini` legt die Toolchain (`espressif32 @ ~8.0.0`), das Board (`seeed_xiao_esp32s3`) und jede Bibliothek (Adafruit PWM Servo Driver, LSM6DS, INA260, AHRS, LovyanGFX) fest, sodass alle dasselbe Binary bauen. Es definiert zwei Umgebungen: | Umgebung | Baut für | Verwendet von | |---|---|---| | `xiao_esp32s3` (Standard) | Das echte Board | `make firmware`, Upload | | `native` | Ihren Computer, mit dem Testframework Unity | `make test-firmware` | ```bash cd firmware/strido_esp32s3 pio test -e native # 15 unit tests: linkage, protocol, watchdog, e-stop, battery, NaN rejection pio run -e xiao_esp32s3 # compile (same as `make firmware` from the repo root) pio run -e xiao_esp32s3 -t upload # compile and flash over USB pio device monitor # serial monitor (frames are binary; use strido-cli instead) ``` `-DARDUINO_USB_CDC_ON_BOOT=1` leitet `Serial` auf den nativen USB-Anschluss des Chips um, sodass das Board unter Linux als CDC-ACM-Gerät erscheint (`/dev/ttyACM*`, verlinkt auf `/dev/strido_mcu`). Die Baudrate wird bei USB CDC ignoriert. Wenn ein Upload keine Verbindung aufbauen kann, halten Sie beim Einstecken des USB-Kabels die BOOT-Taste des XIAO gedrückt, um den ROM-Bootloader zu erzwingen. ::: tip Warum eine native Testumgebung `lib/strido_core` enthält keine Arduino-Aufrufe. Derselbe Kinematik-, Protokoll- und Sicherheitscode kompiliert für den ESP32 *und* für Ihren Laptop, daher prüft `pio test -e native` ihn in Sekunden ohne Hardware und schlägt in der CI fehl, wenn jemand den Watchdog kaputt macht. ::: ## Programmstruktur {#program-structure} `setup()` initialisiert die Hardware und startet zwei FreeRTOS-Tasks, die an die beiden Kerne des ESP32-S3 gebunden sind. `loop()` schläft danach für immer. ```mermaid flowchart LR subgraph C0["Kern 0: commsTask (Priorität 2)"] RX["USB-Bytes lesen
→ COBS-Frames → handlePacket"] --> CMD[("Befehl
(Spinlock)")] ST2[("Zustand
(Spinlock)")] --> TX["STATE-Frame
alle 10 ms (100 Hz)"] FACE["LCD-Gesicht, Status-LED
alle 50 ms"] end subgraph C1["Kern 1: controlTask (Priorität 3), alle 5 ms"] IMU["IMU lesen + Mahony-Filter"] --> SAFE["SafetySupervisor.update"] PWR["INA260 alle 100 ms"] --> SAFE SAFE --> SERVO["Ratenbegrenzung → Koppelgetriebe → Begrenzung
→ kalibrierte Pulse → PCA9685"] SERVO --> ST1["Zustand schreiben"] end CMD --> SAFE ST1 --> ST2 ``` Warum zwei Tasks: USB-Verkehr kommt stoßweise, und das LCD braucht Zeit zum Zeichnen; keines von beiden darf die Servoaktualisierung verzögern. Der Regel-Task läuft mit höherer Priorität auf einem eigenen Kern, und die gemeinsamen Daten (`command`, `state`) werden in kurzen kritischen Abschnitten unter Spinlock kopiert (`portENTER_CRITICAL`). Blockierende I²C-Lesevorgänge finden nie innerhalb eines kritischen Abschnitts statt. ### Startsequenz {#start-up-sequence} 1. Den **OE**-Pin des PCA9685 (D3) auf High setzen: alle Servoausgänge aus, Servos kraftlos. 2. I²C an D4/D5 mit 400 kHz starten; Kalibrierung aus dem Flash laden. 3. Den internen Gelenkzustand auf die Montage-Referenzpose setzen. 4. PCA9685 mit 200 Hz und allen Kanälen aus starten; IMU mit ±8 g, ±1000 °/s, 416 Hz; INA260 an `0x41`. 5. „ready“ auf dem LCD anzeigen (oder „NO PCA9685“), die Tasks starten. Die Servos bleiben kraftlos, bis der Host seinen ersten Positionsbefehl sendet. Deshalb funktioniert die Startreihenfolge in [Elektronik](../../electronics.md#safety-rules): Der Loop-Key kann sicher eingesteckt werden, und der erste Befehl des Gait-Nodes ist die Ruhepose, in der der Roboter bereits liegt. ## Ein Regelzyklus (5 ms) {#one-control-cycle-5-ms} 1. **IMU.** Den LSM6DSOX auslesen, seine Achsen in das Basiskoordinatensystem drehen (das Board ist mit x zur linken Seite des Roboters, y zum Heck des Roboters montiert), den Mahony-Orientierungsfilter aktualisieren. 2. **Leistung.** Alle 100 ms Busspannung und Strom vom INA260 lesen und die Spannung an den Sicherheitsüberwacher weitergeben. 3. **Sicherheit.** `safety.update(now)` liefert den Ansteuerzustand (siehe unten). Den neuesten Befehl kopieren. 4. **Servos**, wenn der Zustand Active ist: - **Ratenbegrenzung:** Kein Gelenk bewegt sich schneller als $\dot q_\mathrm{max} = 6\,\mathrm{rad/s}$, daher wird jeder 5-ms-Schritt auf $\lvert \Delta q \rvert \le \dot q_\mathrm{max}\,\Delta t = 0.03\,\mathrm{rad}$ begrenzt. Die Nenngeschwindigkeit des SPT5435LV beträgt 0,14 s pro 60° bei 6 V, etwa $7.5\,\mathrm{rad/s}$; wer darunter bleibt, hält befohlene und tatsächliche Position nahe beieinander. - **Kniekoppelgetriebe:** (Hüfte, Oberschenkel, Unterschenkel) in die drei *Aktuator*-Winkel (Hüfte, Oberschenkel, Kniekurbel) umrechnen. Der Knieservo treibt den Unterschenkel über ein Parallelogramm und ein Viergelenk an, daher hängt der Kurbelwinkel sowohl vom Oberschenkel als auch vom Unterschenkel ab ([Kinematik](kinematics-and-gaits.md)). - **Begrenzen** von Hüfte, Oberschenkel und Kurbel auf die generierten Grenzen, dann prüfen, ob der resultierende Unterschenkelwinkel in seinem Fenster liegt. Eine unerreichbare Anforderung behält die vorherigen Pulse bei. - **Puls:** Jeden Aktuatorwinkel $\theta$ in eine Pulsbreite umrechnen und diese dann auf `[min_us, max_us]` begrenzen: $$ t_\mathrm{p} = t_\mathrm{neutral} + s \cdot 636.6\,\mu\mathrm{s/rad} \cdot (\theta - \theta_0) $$ mit `neutral_us` $t_\mathrm{neutral}$, `direction` $s = \pm 1$ und `zero_rad` $\theta_0$. Die Steigung beträgt $2000\,\mu\mathrm{s} / \pi\,\mathrm{rad} \approx 636.6\,\mu\mathrm{s/rad}$: Der SPT5435LV-180W bildet 500–2500 µs auf 180° ab ([Servos](../hardware/servos.md)). - Die Pulse auf die PCA9685-Kanäle schreiben (`kServoChannel`: FL-Hüfte auf 15 … RR-Unterschenkel auf 4, identisch zur Upstream-Verkabelung von Yertle gehalten). 5. **Melden** der tatsächlich angewendeten Winkel (nach der Begrenzung, und des Unterschenkelwinkels, den die begrenzte Kurbel wirklich erzeugt) sowie der Flags in den gemeinsamen Zustand. ### Warum der PCA9685 {#why-the-pca9685} Der PCA9685 ist ein 16-Kanal-PWM-Generator mit 12 Bit, der über I²C gesteuert wird. Einmal konfiguriert, erzeugt er alle Pulse in Hardware, sodass der ESP32 nur neue Werte sendet. Bei 200 Hz beträgt eine Periode $T = 5000\,\mu\mathrm{s}$, und 12 Bit ergeben $2^{12} = 4096$ Schritte, $T/4096 \approx 1.2\,\mu\mathrm{s}$ pro Schritt, also grob 0,1° Servoweg. Die Servofrequenz beträgt 200 Hz (der SPT5435LV akzeptiert bis zu 330 Hz): Eine höhere Bildrate als die klassischen 50 Hz bedeutet weniger Verzögerung zwischen einem neuen Befehl und dem Zeitpunkt, an dem der Servo ihn sieht. Die Abtastperiode begrenzt außerdem, was jeder digitale Controller leisten kann; siehe [Regelung](../theory/control.md). Sein Low-aktiver **OE**-Pin (Output Enable) ist mit D3 verbunden. Wird er auf High gesetzt, stoppen alle Pulse sofort, unabhängig von I²C. Das Board selbst zieht OE auf Low (Ausgänge an), daher ergänzt der Kabelbaum einen 2,2-kΩ-Pull-up von OE nach VCC (W20 in [Elektronik](../../electronics.md)): Er hält OE auf High, Servos aus, während der ESP32 neu startet oder in seinem Bootloader steht. ## Das serielle Protokoll zum Pi {#the-serial-protocol-to-the-pi} Nachrichten laufen über USB CDC als Frames: ```text COBS( type | payload | CRC16 little-endian ) 0x00 ``` - **COBS** (Consistent Overhead Byte Stuffing) entfernt jedes Null-Byte aus den Daten, sodass `0x00` das Ende eines Frames markieren kann. Ein Empfänger, der mitten im Datenstrom einsteigt oder ein Byte verliert, synchronisiert sich bei der nächsten Null neu. - **CRC-16/CCITT-FALSE** erkennt beschädigte Frames, die verworfen werden. Firmware und Python teilen sich einen Testvektor, sodass beide Seiten dieselbe CRC berechnen. - **Nutzdaten** sind gepackte Little-Endian-Structs, zweimal definiert und gegeneinander getestet: `lib/strido_core/include/strido/protocol.h` und `packages/strido-core/src/strido/protocol.py`. | Typ | Name | Richtung | Nutzdaten | |---|---|---|---| | `0x01` | JOINT_COMMAND | Pi → MCU | seq u16, mode u8 (0 relax, 1 position), q[12] f32 | | `0x02` | SERVO_PULSE_COMMAND | Pi → MCU | seq u16, pulse_us[12] u16 (0 = aus); nur Kalibrierung | | `0x03` | SET_CALIBRATION | Pi → MCU | joint, direction, neutral_us, zero_rad, min_us, max_us | | `0x04` | SAVE_CALIBRATION | Pi → MCU | keine | | `0x05` | REQUEST_CALIBRATION | Pi → MCU | keine → 12 × CALIBRATION | | `0x06` | ESTOP | Pi → MCU | engaged u8 | | `0x07` | DISPLAY | Pi → MCU | expression u8, length u8, text | | `0x81` | STATE | MCU → Pi, 100 Hz | letzte seq, Zeit, Flags, q[12], Quaternion, Gyro, Beschleunigung, Bus-V, Strom | | `0x82` | CALIBRATION | MCU → Pi | wie SET_CALIBRATION | | `0x83` | LOG | MCU → Pi | ASCII | Ein Gelenkbefehl ist auf der Leitung 56 Bytes lang (51 Byte Nutzdaten + Typ + CRC + COBS-Overhead + Trennzeichen); bei den 100 Hz des Gaits sind das etwa 5,6 kB/s, für USB eine Kleinigkeit. Die Firmware verwirft beim Deserialisieren jeden Gelenkbefehl, der NaN oder Unendlich enthält: Ein Vergleich mit NaN ist gegen jede Grenze falsch, und NaN würde sonst durch alle Begrenzungen rutschen. ## Kalibrierung im Flash {#calibration-in-flash} Keine zwei Servohörner sitzen in exakt demselben Winkel auf ihrer Verzahnung. Jedes Gelenk hat daher eine `ServoCalibration`: | Feld | Bedeutung | |---|---| | `direction` | +1 oder −1: Vorzeichen zwischen Wellenwinkel und Pulsbreite (gespiegelte Beine) | | `neutral_us` | Puls, der die Welle auf `zero_rad` hält (Standard 1500 µs) | | `zero_rad` | Aktuatorwinkel beim Neutralpuls (Standard: die Montage-Referenzpose) | | `min_us`, `max_us` | Hartes Pulsfenster (Standard 500–2500 µs) | Die Standardwerte stammen aus der generierten Geometrie. Gespeicherte Werte werden mit der ESP32-Bibliothek `Preferences` abgelegt (Schlüssel-Wert-Speicher im Flash, Namensraum `strido`, Schlüssel `cal0` … `cal11`), sodass sie das Ausschalten und das erneute Flashen der Anwendung überstehen. Das Werkbank-Werkzeug steuert den Ablauf: ```bash strido-cli center # 1500 µs on every channel: fit the horns in this reference pose strido-cli calibrate # trim each joint's neutral in ±5 / ±25 µs steps, saved to flash strido-cli monitor # battery, flags, roll/pitch ``` `strido-cli` sendet Befehle mit 20 Hz, damit der Watchdog versorgt bleibt. Rohe Pulse umgehen die Gelenkgrenzen (nur das Pulsfenster des jeweiligen Gelenks gilt), deshalb wird mit nicht montierten Hörnern oder frei beweglichen Beinen kalibriert. Wann das zu tun ist, steht in der [Montageanleitung](../../assembly/README.md). ## Sicherheit und Failsafes, wie implementiert {#safety-and-failsafes-as-implemented} `SafetySupervisor` (`lib/strido_core/src/safety.cpp`) ist ein kleiner Zustandsautomat mit vier Ansteuerzuständen: ```mermaid flowchart LR R["Relaxed
OE high, kraftlos"] -->|"Positionsbefehl
(Akku ok, INA260 vorhanden)"| A["Active
folgt Befehlen"] A -->|"kein Befehl für 200 ms"| H["Holding
letzte Pose"] H -->|"neuer Befehl"| A H -->|"weitere 2 s"| R A -->|"Relax-Befehl"| R A -->|"ESTOP aktiviert"| E["Estop
verriegelt, OE high"] H -->|"ESTOP aktiviert"| E R -->|"ESTOP aktiviert"| E E -->|"ESTOP freigegeben"| R ``` | Failsafe | Verhalten | Warum | |---|---|---| | Befehls-Watchdog | Nur Gelenkbefehle versorgen ihn; kein Befehl für 200 ms → halten; weitere 2 s → entspannen | Wenn der Gait-Node oder der Pi ausfällt, erstarrt der Roboter weder für immer unter Last, noch bricht er sofort zusammen | | Verriegelter Not-Halt | `ESTOP` schaltet die Ausgänge ab, bis er freigegeben wird; die Freigabe führt zu Relaxed, daher ist ein *neuer* Positionsbefehl nötig | Das Freigeben des Halts darf den Roboter nie wieder in Bewegung springen lassen | | Harte Ausgangsabschaltung | Relaxed und Estop ziehen OE des PCA9685 auf High und setzen jeden Kanal auf null | Funktioniert auch, wenn I²C hängt | | Akku-Abschaltung | Warnung unter 6,8 V (3,4 V/Zelle); Abschaltung nach 5 aufeinanderfolgenden Messungen (0,5 s) unter 6,4 V (3,2 V/Zelle); erholt sich erst über 6,8 V | Schützt den 2S-LiPo; die Entprellung ignoriert die kurzen Spannungseinbrüche eines tretenden Beins | | Kein Power-Monitor, keine Ansteuerung | Ohne funktionierenden INA260 werden Positionsbefehle abgelehnt (rohe Kalibrierpulse bleiben erlaubt) | Ohne Spannungsmessung gibt es keinen Unterspannungsschutz | | Ratenbegrenzung | 6 rad/s pro Gelenk | Kein Sprung, selbst wenn der Host einen sendet | | Gelenk- und Kniekurbelgrenzen | Aus dem CAD-Durchlauf des Bewegungsbereichs, in die Firmware generiert | Ein fehlerhafter Befehl kann ein Bein nicht in den Körper fahren oder das Koppelgetriebe blockieren | | Ablehnung nicht endlicher Werte | Befehle mit NaN/Inf werden verworfen | NaN umgeht Vergleiche | | Wiedereinschalten ab Befehl | Wenn die Ausgänge wieder einschalten, springt der interne Zustand auf die befohlene Pose, statt von einer veralteten aus zu fahren | Die Servopositionen sind nach dem kraftlosen Zustand unbekannt | Der Zustand all dessen erreicht ROS als Flags in `/diagnostics` (`estop`, `relaxed`, `watchdog`, `imu_ok`, `power_ok`, `pwm_ok`, `clamped`, `calibration_mode`). ::: danger Dies sind Software-Failsafes. Der Servo-Loop-Key ist die Hardware-Abschaltung und muss immer in Reichweite bleiben, wenn der Roboter scharfgeschaltet ist ([Sicherheit](../making/safety.md)). ::: ## Selbsttest {#check-yourself} 1. Warum läuft die Servoschleife auf dem ESP32 und nicht auf dem Pi? 2. Was passiert Schritt für Schritt, wenn der Gait-Node abstürzt, während der Roboter steht? 3. Warum macht COBS es sicher, `0x00` als Frame-Trennzeichen zu verwenden? 4. Wie groß ist die maximale Änderung eines Gelenkwinkels in einem 5-ms-Zyklus? 5. Wo liegen die Kalibrierwerte, und warum überstehen sie einen Firmware-Upload?
Antworten 1. Linux kann Prozesse unvorhersehbar anhalten; der ESP32 führt nur diese Schleife aus, daher sind das 200-Hz-Timing und die Sicherheitsprüfungen deterministisch und arbeiten weiter, wenn der Pi ausfällt. 2. Die Gelenkbefehle bleiben aus; nach 200 ms wechselt der Überwacher in Holding und hält die letzte Pose (Watchdog-Flag gesetzt); nach weiteren 2 s entspannt er und zieht OE auf High. 3. Die COBS-Kodierung entfernt alle Null-Bytes aus den Daten, daher ist die einzige Null im Datenstrom das Trennzeichen. 4. $6\,\mathrm{rad/s} \times 0.005\,\mathrm{s} = 0.03\,\mathrm{rad}$ (etwa $1.7^\circ$). 5. Im Flash des ESP32 über `Preferences` (Namensraum `strido`, Schlüssel `cal0`–`cal11`); diese Speicherpartition ist von der Anwendung getrennt, daher löscht ein Upload sie nicht.
## Weiterführende Literatur {#further-reading} - [PlatformIO-Dokumentation](https://docs.platformio.org/en/latest/) - [Seeed Studio XIAO ESP32S3: Erste Schritte](https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/) - [ESP32-S3-Datenblatt (Espressif)](https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf) - [PCA9685-Datenblatt (NXP, Kopie bei Adafruit)](https://cdn-shop.adafruit.com/datasheets/PCA9685.pdf) - [Arduino-ESP32-Bibliothek Preferences](https://docs.espressif.com/projects/arduino-esp32/en/latest/api/preferences.html) - Theorie: [Regelung](../theory/control.md), [State Estimation](../theory/state-estimation.md) (der IMU-Filter) --- # Kinematik und Gaits {#kinematics-and-gaits} Kinematik ist die Geometrie der Bewegung: Wo ist der Fuß bei gegebenen Gelenkwinkeln (Vorwärtskinematik), und welche Gelenkwinkel bringen ihn an eine gegebene Fußposition (inverse Kinematik)? Ein Gait ist der Rhythmus, in dem die vier Füße abheben, schwingen und abstoßen. Diese Seite arbeitet beides für das Strido-Bein durch, mit dem Code, der den Roboter tatsächlich steuert. ::: tip In Strido - **Beinkinematik und Kniekoppelgetriebe:** `packages/strido-core/src/strido/leg.py` (Python) und sein C++-Gegenstück `firmware/strido_esp32s3/lib/strido_core/src/kinematics.cpp` + `servo_map.cpp`. - **Gait:** `packages/strido-core/src/strido/gait.py` (`TrotGait`, `GaitConfig`, `stand_pose`, `clamp_leg`), unverändert verwendet von `gait_node` (ROS 2), `strido_sim.walk` (MuJoCo) und als Standpose für die gelernte Policy. - **Maße und Grenzen:** aus dem CAD in `hardware/kinematics.yaml` und `hardware/joint_limits.yaml` gemessen, dann in `packages/strido-core/src/strido/geometry.py` und `geometry_generated.h` generiert ([CAD als Code](cad-as-code.md)). - **Servos:** 12 × SPT5435LV-180W Positionsservos ([Servos](../hardware/servos.md)). ::: ## Das Bein {#the-leg} Jedes Bein hat drei Gelenke, benannt und mit Vorzeichen wie beim Unitree Go2, damit Werkzeuge und Policies übertragbar sind: | Gelenk | Achse | Null | Positive Richtung | Angetrieben von | |---|---|---|---|---| | Hüfte (q1) | +x (vorwärts) | Bein senkrecht | Fuß bewegt sich nach +y (links) | Hüftservo, direkt | | Oberschenkel (q2) | +y | Femur gerade nach unten | Knie bewegt sich nach hinten | Oberschenkelservo, direkt (koaxial zum Femur-Drehpunkt) | | Unterschenkel (q3) | +y, relativ zum Femur | Unterschenkel in Linie mit Femur | negativ = Knie gebeugt | Knieservo, **über zwei Koppelgetriebe** | Gemessene Maße (Bein vorne links, generierte Werte gerundet): | Größe | Wert | |---|---| | Position der Hüftachse in `base_link` | x = ±0,120 m, y = ±0,039 m | | Seitlicher Versatz Hüftachse → Beinebene (`thigh_offset_y`) | 0,038 m vorne, 0,040 m hinten | | Länge Oberschenkel (Femur) l1 | 0,130 m | | Länge Unterschenkel (Tibia) l2, bis Fußmitte | 0,124 m | | Radius der Fußkugel | 0,012 m | Die volle Streckung beträgt $l_1 + l_2 \approx 0.254\,\mathrm{m}$; der Roboter steht mit den Hüftachsen 0,17 m über den Fußmitten. ### Das Kniekoppelgetriebe {#the-knee-linkage} Der Knieservo sitzt nicht am Knie, sondern oben im Beinmodul. Er dreht einen Arm; ein **Parallelogramm** (Arm 24 mm, kurze Koppel 28,3 mm, Kurbel) überträgt den Armwinkel auf eine Kurbel koaxial zum Femur-Drehpunkt; ein **Viergelenk** (Kurbel 26,9 mm, lange Koppel 131 mm, Tibiakurbel 24 mm, Femur) dreht die Tibia. Weil die Servomasse nahe am Körper bleibt, lässt sich das Bein leichter schwingen. Der Preis: Der Kniewinkel $q_3$ hängt **sowohl** vom Kurbelwinkel $\psi$ als auch vom Oberschenkelwinkel $q_2$ ab. Bewegt man nur den Oberschenkelservo, ändert sich auch der Kniewinkel. Die Software muss daher das Koppelgetriebe lösen: - `crank_from_calf(leg, q2, q3)` liefert den Kurbelwinkel, den der Knieservo halten muss (inverses Koppelgetriebe), durch Schnitt zweier Kreise: einer um den Femur-Drehpunkt mit dem Kurbelradius, einer um den Tibia-Bolzen mit der Länge der langen Koppel. - `calf_from_crank(leg, q2, ψ)` ist das Vorwärts-Koppelgetriebe. Zwei Kreise schneiden sich in zwei Punkten; der Code wählt den Zweig, in dem sich die CAD-Baugruppe befindet (`_branches`), damit der Löser nie in die gespiegelte Konfiguration umspringt. Der **Übertragungswinkel** ist der Winkel zwischen der langen Koppel und der Kurbel (bzw. Tibiakurbel). Nahe 0° oder 180° ist das Koppelgetriebe nahe einer Singularität: Eine kleine Servobewegung erzeugt eine riesige Kniebewegung, und der Servo verliert Hebelwirkung. Die Bewegungsbereichs-Analyse hält ihn bei mindestens 25°; in der Standpose beträgt er etwa 84–86°, nahe am Ideal von 90°. ## Vorwärtskinematik {#forward-kinematics} `foot_position(name, q)` in `leg.py`: 1. In der Beinebene ($u$ vorwärts, $v$ nach oben, Ursprung im Oberschenkel-Drehpunkt): $$ \mathbf{p}_\mathrm{knee} = \begin{pmatrix} -l_1 \sin q_2 \\ -l_1 \cos q_2 \end{pmatrix}, \qquad \mathbf{p}_\mathrm{foot} = \mathbf{p}_\mathrm{knee} + \begin{pmatrix} -l_2 \sin(q_2 + q_3) \\ -l_2 \cos(q_2 + q_3) \end{pmatrix} $$ Der absolute Winkel des Unterschenkels ist $q_2 + q_3$, weil $q_3$ relativ zum Femur gemessen wird: Die Winkel einer seriellen Kette addieren sich. 2. Setzen Sie den Ebenenpunkt mit dem seitlichen Versatz `thigh_offset_y` an, drehen Sie ihn um den Hüftwinkel $q_1$ um $x$ und addieren Sie dann die Hüftposition in `base_link`: $\mathbf{p} = \mathbf{p}_\mathrm{hip} + \mathbf{R}_x(q_1)\,(u,\ d_y,\ v)^\top$. Die allgemeine Methode (homogene Transformationen) steht in [Kinematik](../theory/kinematics.md) und [Koordinatensysteme und Rotationen](../theory/frames-and-rotations.md). Beispiel aus dem Code: Die Standpose für das Bein vorne links ist $\mathbf{q} = (0,\ 0.812,\ -1.676)\,\mathrm{rad} = (0^\circ,\ 46.5^\circ,\ -96.0^\circ)$, und die Vorwärtskinematik liefert den Fuß bei $(0.120,\ 0.077,\ -0.170)\,\mathrm{m}$: direkt unter der Hüfte, 0,170 m tiefer. Prüfen Sie die Höhe in der Ebene: $v = -0.130\cos(0.812) - 0.124\cos(0.812 - 1.676) \approx -0.089 - 0.081 = -0.170\,\mathrm{m}$. Der $y$-Wert 0,077 m setzt sich aus den 0,039 m der Hüfte plus dem Beinebenen-Versatz von 0,038 m zusammen. ## Inverse Kinematik {#inverse-kinematics} `inverse_kinematics(name, foot)` löst die Umkehrung analytisch (ohne Iteration): 1. **Hüfte.** Betrachten Sie das Bein von vorne. Der Fuß muss auf einem Kreis mit Radius $d_y$ (`thigh_offset_y`) um die Hüftachse liegen, plus einer „Tiefe“ $d$ entlang des Beins, nach Pythagoras: $d = \sqrt{y^2 + z^2 - d_y^2}$. Der Hüftwinkel ist die Drehung, die die Beinebene auf den Fuß ausrichtet: $q_1 = \operatorname{atan2}(z, y) - \operatorname{atan2}(-d, d_y)$. 2. **Knie aus dem Kosinussatz.** In der Beinebene liegt der Fuß bei $(u, v) = (x, -d)$. Das Dreieck Oberschenkel–Unterschenkel–(Drehpunkt zu Fuß) hat die Seiten $l_1$, $l_2$ und $r = \sqrt{u^2 + v^2}$, also $r^2 = l_1^2 + l_2^2 + 2 l_1 l_2 \cos q_3$, woraus folgt $$ \cos q_3 = \frac{u^2 + v^2 - l_1^2 - l_2^2}{2\, l_1 l_2}, \qquad q_3 = -\arccos(\cos q_3) $$ (negativ: Das Knie beugt sich nach hinten). Ist $\lvert \cos q_3 \rvert > 1$, liegt das Ziel außer Reichweite und die Funktion gibt `None` zurück. 3. **Oberschenkel.** Die Richtung zum Fuß minus den Winkel, den der gebeugte Unterschenkel hinzufügt: $$ q_2 = \operatorname{atan2}(-u, -v) - \operatorname{atan2}\left(l_2 \sin q_3,\ l_1 + l_2 \cos q_3\right) $$ Danach wendet `clamp_leg` die Gelenkgrenzen und das Kniekurbelfenster an. Liegt die benötigte Kurbelstellung außerhalb ihres Fensters, wird sie begrenzt und der Unterschenkelwinkel aus der begrenzten Kurbel neu berechnet: Die Firmware tut im Aktorraum genau dasselbe, sodass Simulation und Roboter übereinstimmen. ## Gelenkgrenzen {#joint-limits} Generiert aus der CAD-Bewegungsbereichs-Analyse (Kollisionen mit allen Teilen, ein gespiegeltes Partnerbein mit 0,3 mm Abstand, Übertragungswinkel ≥ 25° und ±85° Servoweg um die Montage-Neutralstellung): | Gelenk | FL | FR | RL | RR | |---|---|---|---|---| | Hüfte | −17,5…50° | −50…17,5° | −17,5…45° | −45…17,5° | | Oberschenkel | −40…125° | −40…125° | −15…125° | −15…125° | | Unterschenkel | −150…−45° | −150…−45° | −150…−45° | −150…−45° | | Kniekurbel | −2,5…75° | −2,5…75° | −2,5…75° | −2,5…75° | Die inneren Hüftgrenzen (±17,5°) sind klein, weil sich sonst beide Vorderfüße (und beide Hinterfüße) unter dem Körper treffen könnten (ADR-005 in [Entscheidungen](../../decisions.md)). Die Analyse erlaubte für den vorderen Oberschenkel −45°, doch der Servo erreicht innerhalb von ±85° um seine 45°-Neutralstellung nur −40°. Die Grenzen werden an drei Stellen (Gait, Policy-Umgebung, Firmware) aus denselben generierten Zahlen angewendet. ## Von Winkeln zu Servopulsen {#from-angles-to-servo-pulses} Gelenkraum und Servoraum unterscheiden sich nur beim Knie: Hüft- und Oberschenkelservo halten $q_1$ und $q_2$ direkt, der Knieservo hält den Kurbelwinkel $\psi$. Die Firmware bildet dann jeden Aktorwinkel $\theta$ auf eine Pulsbreite $t_\mathrm{p}$ ab, mit Kalibriervorzeichen $s$ (`direction`), `neutral_us` $t_\mathrm{neutral}$ und Referenzwinkel $\theta_0$ (`zero_rad`): $$ t_\mathrm{p} = t_\mathrm{neutral} + s \cdot \frac{2000\,\mu\mathrm{s}}{\pi\,\mathrm{rad}} \cdot (\theta - \theta_0) $$ mit gelenkweiser Kalibrierung aus dem Flash ([Firmware](firmware.md)). In der Montagereferenz (alle Servos bei 1500 µs) stehen die Beine in der Abduktion senkrecht, der Femur ist 45° nach hinten geneigt und die Kniekurbel steht bei 35°. ## Gaits: Stand, Schwung und der Gangzyklus {#gaits-stance-swing-and-the-gait-cycle} Ein Gait wiederholt sich mit einer **Periode** $T$. Jedes Bein verbringt einen Teil davon am Boden (**Standphase**, schiebt den Körper) und den Rest in der Luft (**Schwungphase**, bewegt sich zum nächsten Auftrittspunkt vor). Der Standanteil ist der **Belastungsfaktor** $\beta = T_\mathrm{stance}/T$. **Phasenversätze** geben an, wann jedes Bein seinen Zyklus beginnt. Die Theorie zu Gaits, Stützpolygonen und Raibert-Fußplatzierung steht in [Laufende Fortbewegung](../theory/legged-locomotion.md). | Gait | Belastungsfaktor | Phasenmuster | Charakter | |---|---|---|---| | Schritt | ≥ 0,75 | ein Bein nach dem anderen (z. B. FL, RR, FR, RL) | mindestens drei Füße am Boden: statisch stabil, langsam | | Trot | 0,5 | diagonale Paare gemeinsam (FL+RR, dann FR+RL) | zwei Füße am Boden: braucht Schwung und eine kurze Periode; robust und einfach | **Statische Stabilität:** Ein stillstehender Roboter fällt nicht um, wenn sein Schwerpunkt innerhalb des **Stützpolygons** liegt, das die Füße am Boden bilden. Mit drei Füßen am Boden (Schritt) lässt sich dieses Dreieck unter dem Körper halten. Mit zwei diagonalen Füßen (Trot) ist das Polygon eine Linie, sodass der Körper in Rollen und Nicken kurz ungestützt ist; ein Zyklus von 0,4 s wechselt die Paare, bevor er merklich kippt. **Strido implementiert nur einen Trot** (`TrotGait`, `PHASE_OFFSET = {"FL": 0.0, "RR": 0.0, "FR": 0.5, "RL": 0.5}`). Ein Schritt bräuchte eine neue Phasentabelle und einen Belastungsfaktor ≥ 0,75; nichts im Repository stellt das bereit. ### Der Trot in Zahlen {#the-trot-in-numbers} Standardwerte von `GaitConfig`: | Parameter | Wert | |---|---| | `body_height` | 0.17 m | | `period` | 0,40 s (2,5 Schritte pro Sekunde je Beinpaar) | | `duty` | 0,5 (0,2 s Stand, 0,2 s Schwung) | | `step_height` | 0,035 m Scheitel der Schwungphase | | `max_linear` | 0,30 m/s vorwärts, 0,15 m/s seitwärts | | `max_yaw_rate` | 1,0 rad/s | Wie `foot_targets()` jeden Fuß platziert: 1. **Geschwindigkeit pro Bein.** Für den Körperbefehl $(v_x, v_y, \omega_z)$ muss sich ein Fuß bei $(x, y)$ mit $\mathbf{v}_\mathrm{foot} = (v_x - \omega_z y,\ v_y + \omega_z x)$ bewegen, der ebenen Form von $\mathbf{v} + \boldsymbol{\omega} \times \mathbf{r}$: Beim Drehen auf der Stelle bewegen sich die linken Füße nach hinten und die rechten nach vorne. 2. **Schrittlänge** = Geschwindigkeit × Standzeit, $L = v\,\beta T$. Bei 0,15 m/s: $0.15\,\mathrm{m/s} \times 0.2\,\mathrm{s} = 0.03\,\mathrm{m}$. Am Limit von 0,30 m/s: 0,06 m. 3. **Standphase** (Phase $< \beta$): Der Fuß gleitet relativ zu seiner Nennposition mit Körpergeschwindigkeit von $+L/2$ nach $-L/2$, sodass sich der Körper über ihn hinweg nach vorne bewegt. 4. **Schwungphase**: Der Fuß kehrt von $-L/2$ nach $+L/2$ zurück und hebt sich auf einer Halbsinuskurve, $h(s) = 0.035\,\mathrm{m} \cdot \sin(\pi s)$ mit Schwungfortschritt $s \in [0, 1]$. Eine halbe Schrittlänge vor der Hüfte aufzusetzen ist die Fußplatzierung nach Raibert: Der Aufsetzpunkt liegt symmetrisch zur Hüfte, sodass die Standphase den Körper im Mittel weder beschleunigt noch bremst. 5. **Inverse Kinematik** wandelt die vier Fußziele in 12 Winkel um, danach wendet `clamp_leg` die Grenzen an. Bei einem Nullbefehl bleiben die Füße an ihren Nennpositionen: Der Roboter steht still, statt auf der Stelle zu traben. `gait_node` ergänzt eine Rampe (Geschwindigkeitsänderungen höchstens 0,5 m/s² und 0,5 rad/s²) und ein sanftes Aufstehen in 3 s von der Ruhepose (0,07 m: Oberschenkel 69,4°, Unterschenkel −148,1°) in die Standpose. Dieser Gait ist **gesteuert (Open Loop)**: Sie liest die IMU nicht und nimmt keine Balancekorrekturen vor. Sie funktioniert, weil der Trot eine kurze Periode hat und der Roboter leicht ist (3,01 kg). Die gelernte Policy ([Simulation und RL](simulation-and-rl.md)) ist die geregelte Alternative: Sie beobachtet die IMU. ## PD-Regelung: Was ein Gelenk an seinem Ziel hält {#pd-control-what-holds-a-joint-at-its-target} Ein Positionsservo ist ein kleiner Regelkreis. Das übliche Modell ist ein **PD**-Gesetz (proportional-differenzierend): $$ \tau = k_\mathrm{p}\,(q_\mathrm{target} - q) - k_\mathrm{d}\,\dot q $$ Der P-Anteil zieht wie eine Feder zum Ziel; der D-Anteil dämpft die Bewegung wie ein Stoßdämpfer. Ein großes $k_\mathrm{p}$ ergibt steife, genaue Gelenke, kann aber schwingen; $k_\mathrm{d}$ unterdrückt die Schwingung. Für ein Gelenk mit Trägheit $I$ ist der geschlossene Kreis ein Masse-Feder-Dämpfer-System, $I\ddot q + k_\mathrm{d}\dot q + k_\mathrm{p} q = k_\mathrm{p} q_\mathrm{target}$, mit Eigenfrequenz $\omega_n = \sqrt{k_\mathrm{p}/I}$ und Dämpfungsgrad $\zeta = k_\mathrm{d} / (2\sqrt{k_\mathrm{p} I})$; siehe [Regelung](../theory/control.md). In Strido: - **Am Roboter** sitzt der PD-Regelkreis *in jedem SPT5435LV*: Seine Elektronik vergleicht den befohlenen Puls mit einem internen Potentiometer und treibt den Motor an. Der ESP32 sendet nur Sollwerte; außerhalb des Servos kennt nichts den tatsächlichen Winkel oder das Drehmoment. - **In MuJoCo** ist jeder Servo ein Positionsaktor mit $k_\mathrm{p} = 25\,\mathrm{N\,m/rad}$, $k_\mathrm{v} = 0.4\,\mathrm{N\,m\,s/rad}$ und einer Drehmomentgrenze von $\pm 3.43\,\mathrm{N\,m}$, dem Blockiermoment des SPT5435LV bei 6 V. 0,1 rad Fehler ergeben also $25 \times 0.1 = 2.5\,\mathrm{N\,m}$; jenseits von $3.43 / 25 \approx 0.14\,\mathrm{rad}$ geht der Servo in die Sättigung, wie ein echter es täte. - **In Gazebo** stellt `gz_ros2_control` pro Gelenk eine `position`-Befehlsschnittstelle bereit, angesteuert von `leg_controller` (`position_controllers/JointGroupPositionController`, 200 Hz). Diese Verstärkungen sind Modellschätzungen; [Simulation](../../simulation.md) merkt an, dass sie an das gemessene Servoverhalten angepasst werden sollten, sobald ein Roboter existiert. ## Selbsttest {#check-yourself} 1. Warum ändert sich der Kniewinkel, wenn man nur den Oberschenkelservo bewegt? 2. Was ergibt der Kosinussatz für $\cos q_3$ bei einem Fuß in voller Streckung (Abstand $l_1 + l_2$)? 3. Wie groß ist die Schrittlänge bei 0,20 m/s mit dem Standard-Trot? 4. Warum ist ein Trot nicht statisch stabil, und warum funktioniert er trotzdem? 5. Welches Drehmoment erzeugt ein Gelenk in MuJoCo bei 0,05 rad Fehler und Geschwindigkeit null?
Antworten 1. Der Knieservo treibt die Tibia über ein Parallelogramm und ein Viergelenk an, die am Femur befestigt sind; der Kniewinkel hängt vom Kurbelwinkel und vom Oberschenkelwinkel ab. 2. $(l_1 + l_2)^2 - l_1^2 - l_2^2 = 2 l_1 l_2$, also $\cos q_3 = 1$ und $q_3 = 0$: Das Bein ist gestreckt (und die Unterschenkelgrenze $-45^\circ$ verbietet das). 3. $0.20\,\mathrm{m/s} \times 0.2\,\mathrm{s} = 0.04\,\mathrm{m}$. 4. Nur zwei diagonale Füße stützen den Körper, daher liegt der Schwerpunkt nicht innerhalb eines Stützpolygons; die kurze Periode von 0,4 s wechselt die Paare, bevor der Körper weit kippt. 5. $25\,\mathrm{N\,m/rad} \times 0.05\,\mathrm{rad} = 1.25\,\mathrm{N\,m}$ (unter der Grenze von 3,43 N·m).
## Weiterführende Literatur {#further-reading} - [Modern Robotics (Lynch und Park), freies Lehrbuch und Videos](https://hades.mech.northwestern.edu/index.php/Modern_Robotics) - [M. H. Raibert, Legged Robots That Balance (MIT Press)](https://mitpress.mit.edu/9780262681193/legged-robots-that-balance/) - [MuJoCo-XML-Referenz: Positionsaktoren](https://mujoco.readthedocs.io/en/stable/XMLreference.html#actuator-position) - [ros2_control: Positionsregler](https://control.ros.org/jazzy/doc/ros2_controllers/position_controllers/doc/userdoc.html) - Theorie: [Koordinatensysteme und Rotationen](../theory/frames-and-rotations.md), [Kinematik](../theory/kinematics.md), [Laufende Fortbewegung](../theory/legged-locomotion.md), [Regelung](../theory/control.md) --- # Linux auf dem Raspberry Pi 5 {#linux-on-the-raspberry-pi-5} Der Raspberry Pi 5 ist das „Gehirn“ von Strido: ein kleiner Linux-Computer, der ROS 2 in Docker ausführt und über USB mit dem Servocontroller kommuniziert. Diese Seite behandelt die Wahl des Betriebssystems, das Flashen, die Anmeldung ohne Bildschirm und die wenigen Linux-Kenntnisse, die Sie brauchen, um den Roboter am Laufen zu halten. ::: tip In Strido - **Hardware:** Raspberry Pi 5 (4 GB) mit dem Raspberry Pi Active Cooler und einer 64-GB-A2-microSD-Karte (SanDisk Extreme), alle in `hardware/bom.yaml`. Er wird mit 5 V über die GPIO-Stiftleiste versorgt, nicht über USB-C. - **Betriebssystem:** Ubuntu Server 24.04 (arm64) oder Raspberry Pi OS Bookworm 64-Bit, dazu Docker Engine ([Software](../../software.md#raspberry-pi-setup)). - **Robotersoftware:** läuft im Container `strido-ros:jazzy`, gebaut aus `docker/ros2/Dockerfile`; das Host-Betriebssystem braucht daher nur Docker, udev-Regeln und einige Firmware-Einstellungen. - **Geräte:** Der XIAO ESP32-S3 (USB CDC) und der RPLIDAR C1 (CP210x-USB-Adapter) erscheinen über `ros2/strido_bringup/config/99-strido.rules` als `/dev/strido_mcu` und `/dev/rplidar`. ::: ## Was der Pi macht und was nicht {#what-the-pi-does-and-what-it-does-not} Der Pi führt alles oberhalb der Servoschleife aus: den Gait- oder Policy-Node, die `mcu_bridge`, den LiDAR-Treiber und (optional) die Kamera. Er steuert **keine** Servos und liest die IMU nicht selbst. Das übernimmt der ESP32-S3, dem der I²C-Bus gehört (PCA9685, LSM6DSOX, INA260) und der eine harte 200-Hz-Schleife ausführt. Die Aufteilung existiert, weil Linux kein Echtzeitbetriebssystem ist: Ein ausgelasteter Pi kann einen Prozess für Dutzende Millisekunden anhalten, was für die Planung harmlos ist, Servos aber zucken ließe. Siehe [Firmware](firmware.md). Der Pi braucht also nur USB-Seriell-Zugriff, weder I²C noch SPI. Das hält die Linux-Einrichtung kurz. ## Wahl des Betriebssystems {#choosing-the-operating-system} | | Ubuntu Server 24.04 (arm64) | Raspberry Pi OS Bookworm 64-Bit | |---|---|---| | Basis | Ubuntu „Noble“ | Debian 12 | | ROS 2 Jazzy nativ | Ja: Ubuntu 24.04 ist Jazzys Tier-1-Plattform (apt-Pakete) | Keine offiziellen Binärpakete; Docker verwenden | | Pi-5-Kamera (libcamera-Fork) | Muss selbst gebaut werden | Enthalten (`rpicam-apps`) | | Werkzeuge wie `raspi-config`, `vcgencmd` | Teilweise | Ja | Beides funktioniert, weil das Repo ROS 2 in einen Container packt (`FROM ros:jazzy-ros-base`, selbst auf Ubuntu 24.04 aufgebaut). Der Container bringt sein eigenes Ubuntu-Userland mit; der Host stellt nur Kernel, USB-Geräte und Netzwerk bereit. Wählen Sie **Raspberry Pi OS**, wenn Sie die Kamera nutzen wollen (der Kamera-Stack des Pi 5 braucht den libcamera-Fork von Raspberry Pi, den das Docker-Image nicht enthält); wählen Sie **Ubuntu Server**, wenn Sie ROS 2 später nativ installieren möchten. Verwenden Sie immer das **64-Bit**-Image. Das ROS-Image, die NumPy-Wheels und Dockers arm64-Builds setzen alle `aarch64` voraus. ## Karte mit Raspberry Pi Imager flashen {#flashing-the-card-with-raspberry-pi-imager} 1. Installieren Sie Raspberry Pi Imager auf Ihrem Laptop und stecken Sie die microSD-Karte ein. 2. Wählen Sie das Gerät **Raspberry Pi 5**, dann das Betriebssystem (unter „Other general-purpose OS → Ubuntu“ für Ubuntu Server 24.04 oder „Raspberry Pi OS (64-bit)“; die Lite-Variante hat keinen Desktop und genügt für einen Roboter ohne Bildschirm). 3. Öffnen Sie auf Nachfrage die **OS-Anpassung** (Edit settings) und legen Sie fest: - Hostname, zum Beispiel `strido`; - einen Benutzernamen und ein Passwort (keinen Standardbenutzer beibehalten); - WLAN-SSID, Passwort und Land; - im Reiter **Services**: SSH aktivieren, idealerweise mit „public-key authentication only“ und eingefügtem öffentlichem Schlüssel. 4. Schreiben, auswerfen, Karte in den Pi stecken. ::: tip Warum im Imager anpassen Ein laufender Roboter hat weder Tastatur noch Monitor. Durch Vorbelegen von Benutzer, WLAN und SSH tritt der Pi beim ersten Start Ihrem Netzwerk bei, sodass Sie ihn vom Laptop erreichen: Das ist eine *Headless*-Einrichtung. ::: ## Erster Start und SSH {#first-boot-and-ssh} Versorgen Sie den Pi mit Strom (nur Logikversorgung, Loop-Key der Servoschleife gezogen). Nach einer Minute sollte er im Netzwerk sein: ```bash ssh @strido.local # mDNS name; if it does not resolve, use the IP from your router ``` Verwenden Sie schlüsselbasierte Anmeldung statt Passwörtern: ```bash ssh-keygen -t ed25519 # on the laptop, once ssh-copy-id @strido.local # installs the public key on the Pi ``` Bringen Sie dann das System auf den neuesten Stand, bevor Sie etwas installieren: ```bash sudo apt update && sudo apt full-upgrade -y sudo reboot ``` Halten Sie unter Raspberry Pi OS auch das Bootloader-EEPROM aktuell (`sudo rpi-eeprom-update`); es enthält Stromeinstellungen, die Sie unten ändern. ## Pi-spezifische Konfiguration für diesen Roboter {#pi-specific-configuration-for-this-robot} Zwei Einstellungen aus [Elektronik](../../electronics.md#raspberry-pi-configuration) sind wichtig, weil Strido den Pi über die GPIO-5-V-Pins versorgt. Dieser Weg umgeht die USB-C-Power-Delivery-Aushandlung, sodass der Pi sonst eine schwache Versorgung annehmen und den USB-Strom begrenzen würde: ```bash sudo rpi-eeprom-config --edit # add: PSU_MAX_CURRENT=5000 echo "usb_max_current_enable=1" | sudo tee -a /boot/firmware/config.txt ``` `PSU_MAX_CURRENT=5000` teilt dem Bootloader mit, dass die Versorgung 5 A liefert; `usb_max_current_enable=1` erlaubt den USB-Ports ihren vollen Strom (LiDAR und ESP32 werden über USB versorgt). `config.txt` liegt sowohl unter Bookworm als auch unter Ubuntu 24.04 in `/boot/firmware/`. ::: warning Das optionale Overlay zur Selbstabschaltung (`dtoverlay=gpio-poweroff,gpiopin=26`) ist im Repo als [UNVERIFIED on Pi 5] markiert. Testen Sie es mit entschärften Servos, bevor Sie sich darauf verlassen. ::: ## Benutzer, Gruppen und Geräteberechtigungen {#users-groups-and-device-permissions} Linux steuert den Hardwarezugriff über Dateien in `/dev` und deren Eigentümergruppe: | Gerät | Typischer Name | Standardgruppe | Von Strido verwendet? | |---|---|---|---| | USB-CDC-Seriell (XIAO ESP32-S3) | `/dev/ttyACM0` | `dialout` | Ja: `mcu_bridge`, `strido-cli` | | USB-UART-Brücke (CP210x, LiDAR) | `/dev/ttyUSB0` | `dialout` | Ja: `sllidar_ros2` | | I²C an der GPIO-Stiftleiste | `/dev/i2c-1` | `i2c` | Nein: I²C liegt am ESP32 | | GPIO | `/dev/gpiochip*` | `gpio` | Nur das optionale Abschalt-Overlay | | Docker-Daemon-Socket | `/var/run/docker.sock` | `docker` | Ja | Zwei Dinge machen das hier einfach: - **udev-Regeln.** `99-strido.rules` erkennt die Geräte anhand der USB-Hersteller-/Produkt-ID (Espressif `303a:1001`, Silicon Labs `10c4:ea60`), legt stabile Symlinks an und setzt `MODE="0666"`. Ohne sie könnten ESP32 und LiDAR über Neustarts hinweg die Namen `ttyACM0`/`ttyUSB0` tauschen, und nur Mitglieder von `dialout` könnten sie öffnen. ```bash sudo cp ros2/strido_bringup/config/99-strido.rules /etc/udev/rules.d/ sudo udevadm control --reload && sudo udevadm trigger ls -l /dev/strido_mcu /dev/rplidar ``` - **docker-Gruppe.** Wenn Sie sich hinzufügen, können Sie `docker` ohne `sudo` ausführen: ```bash sudo usermod -aG docker $USER # log out and back in afterwards ``` ::: warning Mitgliedschaft in `docker` ist gleichbedeutend mit root: Jedes Mitglied kann einen privilegierten Container starten. Fügen Sie nur vertrauenswürdige Benutzer hinzu. ::: Wenn Sie `strido-cli` oder ROS 2 nativ (außerhalb von Docker) ohne die udev-Regel ausführen, fügen Sie sich stattdessen zu `dialout` hinzu: `sudo usermod -aG dialout $USER`. ## Docker installieren und das Roboter-Image bauen {#installing-docker-and-building-the-robot-image} Installieren Sie Docker Engine aus Dockers eigenem Repository (die Debian- oder Ubuntu-Anleitung unter Weiterführende Literatur) und führen Sie dann in einem Klon des Repositorys aus: ```bash docker compose -f docker/compose.yaml build ros # ROS 2 Jazzy, Gazebo libs, sllidar_ros2, this repo's packages docker compose -f docker/compose.yaml run --rm robot ``` Der zweite Befehl startet `ros2 launch strido_bringup robot.launch.py`. Halten Sie die Startreihenfolge aus [Elektronik](../../electronics.md#safety-rules) ein: Roboter liegt in der Ruhepose, Loop-Key eingesteckt, *dann* starten. Details stehen in [Docker](docker.md) und [ROS 2](ros2.md). ## systemd: Dienste, die beim Booten starten {#systemd-services-that-start-at-boot} systemd ist der Prozess, der auf beiden Betriebssystemen Dienste startet und überwacht. Docker selbst ist ein systemd-Dienst: ```bash systemctl status docker # running? enabled at boot? sudo systemctl enable --now docker journalctl -u docker -f # follow its log journalctl -b -p warning # warnings and errors since this boot ``` Das Repo liefert bewusst **keine** systemd-Unit für den Roboter: Der Gait-Node kommandiert die Ruhepose und steht innerhalb von 3 s nach dem Start auf, und die Sicherheitsregeln verlangen, dass Sie den Loop-Key *vor* dem Start einstecken. Ein automatischer Start beim Booten würde Servos ohne anwesende Person bewegen. Wenn Sie später eine eigene Unit hinzufügen (ein `Type=simple`-Dienst, der `docker compose -f docker/compose.yaml run --rm robot` ausführt, `After=docker.service`), behalten Sie den Loop-Key als Arming-Schritt bei und lassen Sie ihn nie unbeaufsichtigt eingesteckt. ## Nützliche Befehle {#useful-commands} | Befehl | Zeigt Ihnen | |---|---| | `hostname -I`, `ip a` | IP-Adressen | | `lsusb` | USB-Geräte: nach `303a:1001` (XIAO) und `10c4:ea60` (CP210x) suchen | | `ls -l /dev/strido_mcu /dev/rplidar` | udev-Symlinks existieren und zeigen auf ein tty | | `udevadm info -a -n /dev/ttyACM0` | Attribute für eine udev-Regel | | `dmesg -w` | Kernel-Meldungen live (Gerät einstecken und beobachten) | | `vcgencmd get_throttled` | `0x0` ist gut; Bit 0 (`0x1`) = Unterspannung jetzt, Bit 16 (`0x10000`) = Unterspannung seit dem Booten aufgetreten | | `vcgencmd measure_temp` | SoC-Temperatur (der Active Cooler hält sie unter ROS-Last im Rahmen) | | `htop`, `free -h`, `df -h` | CPU, Arbeitsspeicher, Datenträger | | `docker ps`, `docker logs ` | laufende Container und ihre Ausgabe | `vcgencmd` ist Teil von Raspberry Pi OS; unter Ubuntu muss es eventuell installiert werden (`libraspberrypi-bin`) oder ist nicht verfügbar. ## Wartbar halten {#keeping-it-maintainable} - Aktualisieren Sie den Host regelmäßig (`apt full-upgrade`); ROS 2 lebt im Image, ein Host-Update kann ROS also nicht beschädigen. - Bauen Sie das Image nach dem Pullen von Repo-Änderungen neu: Das Dockerfile kopiert `packages/strido-core` und die drei ROS-Pakete zur Build-Zeit. - Fahren Sie sauber herunter (`sudo poweroff`), bevor Sie den Strom trennen: Eine SD-Karte, auf die während eines Stromausfalls geschrieben wird, kann das Dateisystem beschädigen. ## Selbsttest {#check-yourself} 1. Warum braucht der Pi in Strido kein aktiviertes I²C? 2. Was beheben `PSU_MAX_CURRENT=5000` und `usb_max_current_enable=1`, und warum braucht dieser Roboter sie? 3. Welche Datei gibt dem ESP32-S3 einen stabilen Gerätenamen, und wie lautet dieser Name? 4. Warum ist Raspberry Pi OS die bessere Wahl, wenn Sie die Kamera nutzen wollen? 5. Warum startet das Repo den Roboter nicht automatisch beim Booten?
Antworten 1. Alle I²C-Geräte (PCA9685, LSM6DSOX, INA260) hängen am ESP32-S3; der Pi kommuniziert mit dem ESP32 nur über USB-Seriell. 2. Die Versorgung über die GPIO-5-V-Pins überspringt die USB-C-PD-Aushandlung, sodass der Pi eine schwache Versorgung annehmen und den USB-Strom begrenzen würde. Die Einstellungen deklarieren eine 5-A-Versorgung und erlauben vollen USB-Strom für LiDAR und ESP32. 3. `ros2/strido_bringup/config/99-strido.rules`, kopiert nach `/etc/udev/rules.d/`; sie legt `/dev/strido_mcu` an. 4. Der Kamera-Stack des Pi 5 braucht den libcamera-Fork von Raspberry Pi, den Raspberry Pi OS mitliefert und das Docker-Image nicht enthält. 5. Der Start lässt den Roboter innerhalb von 3 s aufstehen; die Startreihenfolge verlangt, dass eine Person die Servos unmittelbar vor dem Start mit dem Loop-Key scharf schaltet.
## Weiterführende Literatur {#further-reading} - [Raspberry-Pi-Dokumentation: Erste Schritte und Imager](https://www.raspberrypi.com/documentation/computers/getting-started.html) - [Raspberry-Pi-Dokumentation: `config.txt` und EEPROM-Einstellungen](https://www.raspberrypi.com/documentation/computers/config_txt.html) - [Docker Engine unter Debian](https://docs.docker.com/engine/install/debian/) und [unter Ubuntu](https://docs.docker.com/engine/install/ubuntu/) - [ROS-2-Jazzy-Installation und unterstützte Plattformen](https://docs.ros.org/en/jazzy/Installation.html) - [systemd.service-Handbuch](https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html) --- # ROS 2 Jazzy {#ros-2-jazzy} ROS 2 (Robot Operating System 2) ist kein Betriebssystem, sondern ein Framework: eine Sammlung von Bibliotheken und Werkzeugen, mit denen viele kleine Programme, sogenannte Nodes, typisierte Messages austauschen. Strido verwendet ROS 2 Jazzy, damit dieselben Nodes in Gazebo und auf dem echten Roboter laufen und damit Standardwerkzeuge (Teleop, RViz, Nav2, SLAM) ihn steuern können. ::: tip In Strido - **Pakete** (in `ros2/`): `strido_description` (aus dem CAD generiertes URDF/xacro, `controllers.yaml`, `display.launch.py`), `strido_bringup` (`robot.launch.py`, `gazebo.launch.py`, `worlds/flat.sdf`, udev-Regeln), `strido_control` (`gait_node`, `policy_node`, `mcu_bridge`, `walk_smoke`). - **Gemeinsamer Kern:** `packages/strido-core` (reines Python, kein ROS) enthält den Gait, die Kinematik, das MCU-Protokoll und die Policy-Laufzeit, die die Nodes aufrufen. - **Schnittstelle:** Topics und Gelenknamen im Stil des Unitree Go2, aufgeführt unter [Software](../../software.md#ros-2-interface-go2-style). - **Läuft in:** dem Docker-Image `strido-ros:jazzy` ([Docker](docker.md)). ::: ## Warum Jazzy {#why-jazzy} Jazzy Jalisco (Mai 2024) ist eine Long-Term-Support-Version mit Unterstützung bis Mai 2029, und ihre Tier-1-Plattform ist Ubuntu 24.04, die Basis des Images `ros:jazzy-ros-base`. Sie ist auf Gazebo Harmonic abgestimmt, das das Repository für die Simulation nutzt. Eine LTS-Version bedeutet, dass der Software-Stack des Roboters nicht jedes Jahr einer neuen ROS-Version hinterherlaufen muss. ## Der ROS-Graph dieses Roboters {#the-ros-graph-of-this-robot} ```mermaid flowchart LR TELEOP["teleop_twist_keyboard
(oder Nav2, Ihr Node)"] -->|"/cmd_vel"| GAIT["gait_node
oder policy_node"] GAIT -->|"/leg_controller/commands"| BRIDGE["mcu_bridge"] GAIT -->|"/odom, TF odom→base_link"| RSP["robot_state_publisher"] BRIDGE -->|"/joint_states"| RSP BRIDGE -->|"/imu/data, /battery_state, /diagnostics"| OUT["Ihre Werkzeuge"] BRIDGE -->|"/imu/data"| GAIT LIDAR["sllidar_ros2"] -->|"/scan"| OUT BRIDGE <-->|"USB CDC"| MCU["ESP32-S3-Firmware"] ``` (`policy_node` abonniert `/imu/data`; `gait_node` nicht.) ## Nodes {#nodes} Ein **Node** ist ein Prozess (oder ein Objekt in einem Prozess) mit genau einer Aufgabe. Die Aufteilung des Roboters in Nodes bedeutet, dass Sie ein Teil austauschen können, ohne die anderen anzufassen: `gait_node` und `policy_node` sind austauschbar, weil beide `/cmd_vel` in `/leg_controller/commands` umsetzen. | Node (Paket `strido_control`) | Aufgabe | |---|---| | `gait_node` | Geschwindigkeitsbefehl → Trot-Gait → 12 Gelenkziele mit 100 Hz; veröffentlicht `/odom` und die Transformation `odom→base_link` durch Integration der *befohlenen* Geschwindigkeit | | `policy_node` | Führt eine gelernte Policy (`policy.npz`) mit 50 Hz aus `/cmd_vel` und `/imu/data` aus | | `mcu_bridge` | Übersetzt zwischen ROS-Topics und dem binären seriellen Protokoll des ESP32-S3 | | `walk_smoke` | Automatisierter Gazebo-Test: läuft und prüft die Ground Truth | Dazu kommen Standard-Nodes: `robot_state_publisher`, der Slamtec-Treiber `sllidar_ros2`, `camera_ros` (optional) und in der Simulation die Gazebo-Bridge und die `ros2_control`-Controller. Jeder `strido_control`-Node ist eine von `rclpy.node.Node` abgeleitete Python-Klasse, registriert als Konsolenskript in `setup.py`, daher starten Sie ihn mit: ```bash ros2 run strido_control gait_node ``` ## Topics {#topics} Ein **Topic** ist ein benannter, typisierter Many-to-many-Datenstrom. Publisher wissen nicht, wer zuhört. Diese lose Kopplung ist der Grund, warum der Gait-Node zwischen Simulation und Hardware keine Änderung braucht: In Gazebo wird `/leg_controller/commands` vom `leg_controller` von `ros2_control` verarbeitet, auf dem Roboter von `mcu_bridge`. Die Topics, die dieses Repository tatsächlich verwendet: | Topic | Typ | Veröffentlicht von | Hinweise | |---|---|---|---| | `/cmd_vel` | `geometry_msgs/Twist` | Sie / Teleop | `linear.x`, `linear.y` [m/s], `angular.z` [rad/s]; der Gait begrenzt auf 0,30 / 0,15 / 1,0 | | `/leg_controller/commands` | `std_msgs/Float64MultiArray` | Gait- oder Policy-Node | 12 Winkel [rad], Reihenfolge FL, FR, RL, RR × Hüfte, Oberschenkel, Unterschenkel | | `/joint_states` | `sensor_msgs/JointState` | `mcu_bridge` (Roboter), `joint_state_broadcaster` (Gazebo) | Namen `FL_hip_joint` …; auf dem Roboter sind dies die befohlenen Winkel nach der Begrenzung, da die Servos keine Rückmeldung haben | | `/imu/data` | `sensor_msgs/Imu` | `mcu_bridge` / Gazebo-IMU | Frame `imu_link`; wird nicht veröffentlicht, solange die IMU einen Fehler meldet | | `/battery_state` | `sensor_msgs/BatteryState` | `mcu_bridge` | Akkupackspannung, Strom negativ = Entladen | | `/diagnostics` | `diagnostic_msgs/DiagnosticArray` | `mcu_bridge` | Flags `estop`, `relaxed`, `watchdog`, `imu_ok`, `power_ok`, `pwm_ok`, `clamped`, `calibration_mode` | | `/odom` | `nav_msgs/Odometry` | `gait_node` | Koppelnavigation aus der befohlenen Geschwindigkeit | | `/scan` | `sensor_msgs/LaserScan` | `sllidar_ros2` / Gazebo | Frame `lidar_link`, 10 Hz | | `/camera/image_raw` | `sensor_msgs/Image` | `camera_ros` / Gazebo | Frame `camera_optical_frame` | | `/strido/estop` | `std_msgs/Bool` | Sie | `true` verriegelt einen Halt (Servoausgänge aus) | | `/strido/relax` | `std_msgs/Bool` | Sie | `true` macht die Servos kraftlos | | `/strido/face` | `std_msgs/UInt8` | Sie | ID des LCD-Gesichtsausdrucks | | `/ground_truth/odom` | `nav_msgs/Odometry` | nur Gazebo | wird von `walk_smoke` verwendet, um den tatsächlichen Fortschritt zu messen | `/odom` von `gait_node` ist reine Koppelnavigation: In jedem Schritt dreht der Node die befohlene Körpergeschwindigkeit mit dem aktuellen Kurs $\psi$ in das Odometrie-Koordinatensystem und integriert sie, $$ \begin{pmatrix} x \\ y \end{pmatrix}_{k+1} = \begin{pmatrix} x \\ y \end{pmatrix}_{k} + \begin{pmatrix} \cos\psi_k & -\sin\psi_k \\ \sin\psi_k & \cos\psi_k \end{pmatrix} \begin{pmatrix} v_x \\ v_y \end{pmatrix} \Delta t, \qquad \psi_{k+1} = \psi_k + \omega_z\,\Delta t $$ daher summiert sich jeder Unterschied zwischen befohlener und tatsächlicher Bewegung (Fußschlupf, eine Policy, die zu kurz tritt) unbegrenzt auf. Deshalb bewertet `walk_smoke` den Fortschritt mit `/ground_truth/odom`, und deshalb korrigiert SLAM die Pose anhand von `/scan`. Siehe [Koordinatensysteme und Rotationen](../theory/frames-and-rotations.md) und [State Estimation](../theory/state-estimation.md). So erkunden Sie sie aus einer Shell im Container: ```bash ros2 node list ros2 topic list -t ros2 topic hz /leg_controller/commands # ≈ 100 Hz from gait_node ros2 topic echo /battery_state --once ros2 topic echo /diagnostics ros2 topic pub --once /strido/estop std_msgs/msg/Bool "{data: true}" # stop ros2 topic pub --once /strido/estop std_msgs/msg/Bool "{data: false}" # release (a new joint command is needed to move again) ``` ## Services und Actions {#services-and-actions} Ein **Service** ist ein Request/Response-Aufruf (wie ein Funktionsaufruf über das Netzwerk); eine **Action** ist ein lang laufendes Ziel mit Rückmeldung und Abbruchmöglichkeit (wie „laufe zu dieser Pose“). Die Strido-Nodes definieren **keines von beiden**: Jeder Befehl, einschließlich Not-Halt und Relax, ist ein Topic. Das passt bewusst zu einem Roboter, dessen Firmware den Befehlsstrom selbst als Herzschlag behandelt (kein Befehl für 200 ms → halten, siehe [Firmware](firmware.md)). Services begegnen Ihnen trotzdem über Standard-Nodes. Jeder Node stellt Parameter-Services bereit (`ros2 param ...` nutzt sie), und der `spawner` in `gazebo.launch.py` ruft die Services des `controller_manager` auf, um `joint_state_broadcaster` und `leg_controller` zu laden. Actions kommen hinzu, sobald Sie Nav2 ergänzen, dessen Action `NavigateToPose` `/cmd_vel` an diesen Roboter veröffentlichen würde. ## Parameter {#parameters} **Parameter** sind Node-spezifische Einstellungen, im Code mit Standardwerten deklariert und beim Start überschreibbar. Die tatsächlichen: | Node | Parameter | Standard | |---|---|---| | `gait_node` | `rate_hz` | 100.0 | | | `body_height` | 0.17 m | | | `stand_up_s` | 3.0 s | | | `cmd_timeout_s` | 0,5 s (so lange kein `/cmd_vel` → stillstehen) | | | `accel_limit` | 0,5 m/s² bzw. rad/s² | | | `publish_tf` | true | | `policy_node` | `policy` | "" (erforderlich: Pfad zu `policy.npz`) | | | `stand_up_s`, `cmd_timeout_s` | 3.0 s, 0.5 s | | `mcu_bridge` | `port` | `/dev/strido_mcu` | | `walk_smoke` | `settle_s`, `walk_s`, `vx`, `min_forward_m`, `timeout_s` | 6.0, 8.0, 0.15, 0.4, 120.0 | Die Nodes lesen ihre Parameter einmalig beim Start, setzen Sie sie daher auf der Kommandozeile statt mit `ros2 param set` während des Betriebs: ```bash ros2 run strido_control gait_node --ros-args -p body_height:=0.15 -p accel_limit:=0.3 ``` `use_sim_time:=true` ist ein Parameter, den jeder Node hat: Er lässt die Uhr des Nodes dem Gazebo-Topic `/clock` statt der Echtzeit folgen. `gazebo.launch.py` setzt ihn für alle seine Nodes. ## Launch-Dateien {#launch-files} Ein **Launch-File** startet eine Gruppe von Nodes mit ihren Parametern und Argumenten. Die von Strido sind in Python geschrieben (`*.launch.py`). ```bash ros2 launch strido_bringup robot.launch.py # on the robot ros2 launch strido_bringup robot.launch.py lidar:=false # without the LiDAR ros2 launch strido_bringup robot.launch.py use_policy:=true policy:=/path/policy.npz ros2 launch strido_bringup gazebo.launch.py headless:=true # simulation ros2 launch strido_description display.launch.py # model + joint sliders in RViz ``` | Launch-Datei | Argumente (Standard) | |---|---| | `robot.launch.py` | `mcu_port` (`/dev/strido_mcu`), `lidar_port` (`/dev/rplidar`), `lidar` (true), `camera` (false), `use_policy` (false), `policy` ("") | | `gazebo.launch.py` | `world` (`worlds/flat.sdf`), `headless` (false), `use_policy` (false), `policy` ("") | | `display.launch.py` | `rviz` (true) | `robot.launch.py` zeigt die wichtigsten Launch-Bausteine: `DeclareLaunchArgument`, `Node(...)`, `IfCondition`/`UnlessCondition` zur Wahl zwischen `gait_node` und `policy_node`, `IncludeLaunchDescription` zur Wiederverwendung der Slamtec-Launch-Datei und `Command(["xacro ", file])`, um das xacro in den String `robot_description` umzuwandeln. `gazebo.launch.py` ergänzt Event-Handler (`OnProcessExit`), damit die Controller erst gestartet werden, wenn der Roboter im Simulator existiert. ## tf2 und Koordinatensysteme {#tf2-and-frames} **tf2** verfolgt Koordinatensysteme über die Zeit, sodass jeder Node fragen kann: „Wo war der LiDAR vor 50 ms relativ zum Odometrie-Ursprung?“ Die Koordinatensysteme folgen REP-103: `base_link` hat x nach vorne, y nach links, z nach oben. ```mermaid flowchart TD ODOM["odom"] -->|"gait_node (TransformBroadcaster)"| BASE["base_link"] BASE -->|"robot_state_publisher
aus /joint_states"| HIP["FL_hip → FL_thigh → FL_calf → FL_foot
(ebenso für FR, RL, RR)"] BASE -->|"feste Gelenke im URDF"| SENS["imu_link, lidar_link,
camera_link → camera_optical_frame"] ``` `robot_state_publisher` liest das URDF (vom CAD durch `strido_cad.models` generiert) und die `/joint_states` und veröffentlicht die Pose jedes Glieds. Auf dem Roboter sind die Gelenkzustände die befohlenen Winkel nach der Begrenzung: gut für die Visualisierung, aber sie können keinen blockierenden Servo zeigen. Die Transformation `odom→base_link` entsteht durch Integration der befohlenen Geschwindigkeit, ohne Schlupfmodell. Sie reicht für die Fernsteuerung und als Startwert für SLAM; für die Navigation verwenden Sie eine LiDAR-Odometrie- oder SLAM-Quelle. `policy_node` veröffentlicht kein `/odom`. ## Quality of Service (QoS) {#quality-of-service-qos} **QoS**-Einstellungen bestimmen, wie Messages zugestellt werden: Zuverlässigkeit (reliable oder best effort), Verlaufstiefe, Dauerhaftigkeit (ob spät hinzukommende Abonnenten alte Messages erhalten) und Deadlines. Publisher und Subscriber müssen kompatible QoS haben, sonst verbinden sie sich stillschweigend nicht. Alle Publisher und Subscriber von Strido übergeben eine einfache ganzzahlige Tiefe (`10`; `50` für das IMU-Abonnement von `policy_node`). In `rclpy` bedeutet das das Standardprofil: **keep last N, reliable, volatile**. Zuverlässige Zustellung ist für Befehle auf derselben Maschine richtig. Wenn Sie einen Sensortreiber anbinden, der mit best effort veröffentlicht (üblich bei Kameras und einigen LiDAR-Treibern), empfängt ein zuverlässiger Subscriber nichts: Prüfen Sie das mit ```bash ros2 topic info /scan --verbose # shows each endpoint's QoS ``` ## Fernsteuerung {#teleoperation} Steuern Sie den Roboter (oder die Simulation) über die Tastatur. Das Image enthält `teleop_twist_keyboard`: ```bash # terminal 1 (on the Pi, robot lying in rest pose, loop key in) docker compose -f docker/compose.yaml run --rm robot # terminal 2 docker compose -f docker/compose.yaml run --rm ros ros2 run teleop_twist_keyboard teleop_twist_keyboard ``` `teleop_twist_keyboard` startet mit 0,5 m/s und 1,0 rad/s; `gait_node` begrenzt auf 0,30 m/s vorwärts, 0,15 m/s seitwärts und 1,0 rad/s und beschleunigt mit 0,5 m/s². Drücken Sie einige Male `z` (alle Geschwindigkeiten −10 %) oder `x` (nur linear), damit die Tastendrücke in den nutzbaren Bereich fallen. Die Teleop-Anwendung veröffentlicht pro Tastendruck eine Message (halten Sie eine Taste gedrückt, sorgt die automatische Tastenwiederholung für Nachschub); `gait_node` behandelt `/cmd_vel`, das älter als 0,5 s ist (`cmd_timeout_s`), als veraltet und bleibt stehen, daher hält der Roboter an, wenn die Messages ausbleiben. Beenden Sie den Gait-Node ganz, hält die Firmware die Pose 200 ms lang und entspannt dann 2 s später. ::: danger Teleop ist kein Not-Halt. Das Ziehen des Servo-Loop-Keys ist die Hardware-Abschaltung; `/strido/estop` ist die Software-Abschaltung ([Sicherheit](../making/safety.md)). ::: ## Portierung von einem Unitree Go2 {#porting-from-a-unitree-go2} Gelenknamen, Vorzeichen, Koordinatensysteme und `/cmd_vel` entsprechen der ROS-2-Beschreibung des Go2, daher laufen Stacks auf Geschwindigkeitsebene unverändert. Unterschiede: Die Reihenfolge im Befehlsarray ist FL, FR, RL, RR (das Unitree SDK verwendet FR, FL, RR, RL: nach Namen zuordnen), es gibt keine Topics für Fußkontakt oder Motordrehmoment, `/joint_states` sind befohlene Werte, und der Geschwindigkeitsbereich liegt bei etwa 0,3 m/s. ## Selbsttest {#check-yourself} 1. Warum kann `gait_node` unverändert in Gazebo und auf dem Roboter laufen? 2. Welcher Strido-Node veröffentlicht `odom→base_link`, und was ist seine Schwäche? 3. Nennen Sie einen Service, den der Roboter nutzt, obwohl `strido_control` keinen definiert. 4. Sie führen `ros2 param set /gait_node body_height 0.15` aus, und nichts ändert sich. Warum? 5. Ein Kameratreiber mit best effort veröffentlicht `/camera/image_raw`, aber Ihr Standard-Subscriber erhält nichts. Was ist die wahrscheinliche Ursache?
Antworten 1. Er veröffentlicht nur `/leg_controller/commands`; in Gazebo verarbeitet das der `leg_controller` von `ros2_control`, auf dem Roboter `mcu_bridge`. 2. `gait_node`; er integriert die befohlene Geschwindigkeit (Koppelnavigation ohne Schlupf) und driftet daher von der Realität weg. 3. Die Services des `controller_manager`, die `spawner` in `gazebo.launch.py` aufruft, oder die Parameter-Services, die jeder Node hat. 4. Der Node liest seine Parameter nur beim Start; starten Sie ihn mit `--ros-args -p body_height:=0.15` neu. 5. Eine QoS-Unverträglichkeit: Ein zuverlässiger (reliable) Subscriber passt nicht zu einem Best-effort-Publisher.
## Weiterführende Literatur {#further-reading} - [ROS 2 Jazzy: Konzepte (Nodes, Topics, Services, Actions, Parameter, Launch)](https://docs.ros.org/en/jazzy/Concepts.html) - [Über die Quality-of-Service-Einstellungen](https://docs.ros.org/en/jazzy/Concepts/Intermediate/About-Quality-of-Service-Settings.html) - [Einführung in tf2](https://docs.ros.org/en/jazzy/Concepts/Intermediate/About-Tf2.html) - [REP-103: Einheiten und Koordinatenkonventionen](https://www.ros.org/reps/rep-0103.html) - [ros2_control-Dokumentation (Jazzy)](https://control.ros.org/jazzy/index.html) --- # Simulation und Reinforcement Learning {#simulation-and-reinforcement-learning} Ein Simulator lässt den Roboter tausende Male laufen, ohne dass ein Teil bricht; Reinforcement Learning (RL) lässt den Computer in diesem Simulator durch Versuch und Irrtum einen Lauf-Controller finden. Strido verwendet MuJoCo für schnelle Physik und Training, Gazebo zum Testen des kompletten ROS-2-Stacks und PPO, um eine Lauf-Policy zu trainieren, die auf dem Pi mit reinem NumPy läuft. ::: tip In Strido - **MuJoCo-Modell:** `models/mujoco/strido.xml` + `scene.xml`, von `make models` aus dem CAD erzeugt. - **Gazebo-Modell:** `ros2/strido_description/urdf/strido.urdf.xacro` (mit `sim:=true`), Welt `ros2/strido_bringup/worlds/flat.sdf`, gestartet über `gazebo.launch.py`. - **RL-Code:** `packages/strido-sim/src/strido_sim/rl/` (`env.py`, `train.py`, `evaluate.py`); Policy-Laufzeit `packages/strido-core/src/strido/policy.py`. - **Veröffentlichte Policy:** `models/policies/ppo-v1/policy.npz` (MLP 23 → 128 → 128 → 12). - **Befehle:** `make sim-walk`, `make sim-gazebo`, `make rl-smoke`, `make rl-train`, `make rl-eval` ([Simulation](../../simulation.md)). ::: ## Warum zwei Simulatoren {#why-two-simulators} | | MuJoCo 3 | Gazebo Harmonic | |---|---|---| | Läuft als | Python-Prozess (`mujoco==3.17.0`) | Docker-Container mit ROS 2 Jazzy | | Stärke | Schnelle, deterministische Kontaktphysik; lässt sich aus Python leicht tausende Male pro Sekunde schrittweise ausführen | Simuliert Sensoren (IMU, GPU-LiDAR, Kamera) und führt die echten ROS-2-Nodes und Controller aus | | Verwendet für | Gait-Demo, PPO-Training und -Auswertung | End-to-End-Test von `gait_node` / `policy_node` mit denselben Topics wie am Roboter | | Befehl | `make sim-walk`, `make rl-*` | `make sim-gazebo` | Eine in MuJoCo trainierte Policy in Gazebo laufen zu lassen, ist eine günstige **Sim-to-Sim**-Prüfung: Funktioniert sie nur im Simulator, in dem sie trainiert wurde, hat sie dessen Eigenheiten gelernt und wird auch den echten Roboter nicht überstehen. ## Die Modelle, aus dem CAD erzeugt {#the-models-generated-from-cad} `strido_cad.models` erstellt alle Simulationsmodelle aus der verifizierten CAD-Baugruppe, sodass der simulierte Roboter die echten Gliedlängen, Massen und Gelenkgrenzen hat: - 13 Glied-Meshes (`ros2/strido_description/meshes/`), jeweils auf 25 k Flächen reduziert; - Massen aus Teilevolumen und Dichten, Trägheiten aus den Meshes, Kabel nach verlegter Länge: insgesamt 3,07 kg (`ros2/strido_description/config/mass_report.yaml`); - MJCF mit 12 Positionsaktoren (`kp 25`, `kv 0.4`, Momentgrenze ±3,432 N·m = Blockiermoment des SPT5435LV bei 6 V), ein IMU-Site mit Quaternion-, Gyro- und Beschleunigungssensoren sowie Fuß-Sites; - Physikschritt 0,002 s (500 Hz) mit dem Integrator `implicitfast`. Eine Vereinfachung: Das Knie ist als direktes Drehgelenk am Unterschenkel modelliert. Das Viergelenk-Koppelgetriebe wird in Software gelöst (Gait, Firmware), und seine Grenzen werden angewendet, bevor Befehle das Gelenk erreichen ([Kinematik](kinematics-and-gaits.md)). In Gazebo ergänzt das Xacro mit `sim:=true` `gz_ros2_control` mit einer `position`-Befehlsschnittstelle je Gelenk, eine IMU (200 Hz), ein GPU-LiDAR (360 Messpunkte, 10 Hz, 0,05–12 m, Gaußsches Rauschen σ 0,01 m), eine Kamera (640 × 360, 15 Hz) und einen Ground-Truth-Odometrie-Publisher (`/ground_truth/odom`, 50 Hz). ## MuJoCo: der Gait-Lauf {#mujoco-the-gait-walk} ```bash make sim-walk # 10 s trot at 0.15 m/s → build/sim/walk.mp4 uv run --locked python -m strido_sim.walk --seconds 6 --wz 0.6 # turn uv run --locked mjpython -m strido_sim.walk --viewer # interactive (macOS needs mjpython) ``` Dies führt `strido.gait` aus, denselben Trot, den der Roboter über ROS 2 ausführt, mit 100 Hz wie der echte Befehlsstrom. Zusätzlich hält es die Richtung mithilfe des Gierwinkels aus dem Simulator, den der Roboter nicht hat. Aufgezeichnetes Ergebnis: 1,10 m in 10 s bei 0,15 m/s, Körperhöhe 0,174 m ([Verifikation](../../verification.md)). ## Gazebo: der vollständige ROS-2-Stack {#gazebo-the-full-ros-2-stack} ```bash make sim-gazebo # build image, headless walk test, exit code = pass/fail make sim-gazebo POLICY=models/policies/ppo-v1/policy.npz # same test with policy_node ``` `walk_smoke` wartet 6 s, bis der Roboter steht, sendet 8 s lang 0,15 m/s auf `/cmd_vel` und besteht, wenn sich die Basis ≥ 0,4 m vorwärts bewegt hat (Ground Truth), aufrecht geblieben ist (|Roll|, |Pitch| < 0,5 rad, Höhe > 0,10 m) und `/joint_states`, `/imu/data`, `/scan`, `/camera/image_raw` sowie `/ground_truth/odom` alle veröffentlicht wurden. Aufgezeichnet: 0,98 m in 8 s mit dem Gait-Node. ## Reinforcement Learning in einem Absatz {#reinforcement-learning-in-one-paragraph} Ein **Agent** (hier: ein neuronales Netz, die *Policy* $\pi_\theta(a \mid s)$ mit Gewichten $\theta$) beobachtet den Zustand $s_t$, wählt eine **Action** $a_t$ und erhält einen **Reward** $r_t$. Über Millionen von Versuchen passt er sich an, um den erwarteten diskontierten Ertrag zu maximieren $$ J(\theta) = \mathbb{E}_{\pi_\theta}\left[\sum_{t=0}^{\infty} \gamma^{t} r_t\right] $$ wobei der Diskontfaktor $\gamma < 1$ nahe Rewards stärker gewichtet als ferne. Mit dem $\gamma = 0.99$ des Repos und 50 Policy-Schritten pro Sekunde zählen Rewards etwa $1/(1-\gamma) = 100$ Schritte (2 s) voraus noch. **PPO** (Proximal Policy Optimisation) ist ein dafür weit verbreiteter Algorithmus: Er sammelt mit der aktuellen Policy einen Batch an Erfahrung und verbessert die Policy dann in kleinen, *begrenzten* (clipped) Schritten, sodass ein schlechter Batch sie nicht zerstören kann. Er maximiert $$ L^\mathrm{CLIP}(\theta) = \mathbb{E}_t\left[\min\left(\rho_t(\theta)\,\hat A_t,\ \operatorname{clip}\left(\rho_t(\theta),\, 1-\epsilon,\, 1+\epsilon\right)\hat A_t\right)\right], \qquad \rho_t(\theta) = \frac{\pi_\theta(a_t \mid s_t)}{\pi_{\theta_\mathrm{old}}(a_t \mid s_t)} $$ wobei $\hat A_t$ der Advantage ist (um wie viel besser die Action war, als der Critic erwartet hat) und hier $\epsilon = 0.2$ gilt: Sobald die neue Policy eine Action um mehr als 20 % wahrscheinlicher oder unwahrscheinlicher macht als die alte, belohnt das Ziel keine weitere Änderung. Das Repo verwendet die PPO-Implementierung von Stable-Baselines3 auf der CPU. Die vollständige Herleitung steht unter [Reinforcement Learning](../theory/reinforcement-learning.md). ## Die Umgebung, wie implementiert {#the-environment-as-implemented} `StridoEnv` (`strido_sim/rl/env.py`) ist eine Gymnasium-Umgebung: „mit der befohlenen Geschwindigkeit laufen“. ### Observations (23 Zahlen) {#observations-23-numbers} | Teil | Größe | Quelle am Roboter | |---|---|---| | Winkelgeschwindigkeit (Gyro) | 3 | IMU (`/imu/data`) | | Schwerkraftrichtung im Körperkoordinatensystem | 3 | Orientierungsquaternion der IMU | | Befehl vx, vy, ωz | 3 | `/cmd_vel` | | Vorherige Action | 12 | eigene Ausgabe der Policy | | Gangtakt sin, cos (Periode 0,4 s) | 2 | ein Timer | Es gibt **keine Gelenkwinkel oder -geschwindigkeiten**. Die SPT5435LV-Servos melden nichts zurück, eine Policy, die sich auf Gelenkrückmeldung stützt, könnte also nicht auf dem Roboter laufen (ADR-006 in [Entscheidungen](../../decisions.md)). Die Observation enthält nur, was der Roboter messen kann oder weiß. ### Actions (12 Zahlen) {#actions-12-numbers} Jede Action liegt in $[-1, 1]$. Das Gelenkziel ist $\mathbf{q}_\mathrm{target} = \mathbf{q}_\mathrm{stand} + 0.3\,\mathbf{a}$ (rad), danach folgen: 1. die Anstiegsbegrenzung der Firmware von 6 rad/s ($6\,\mathrm{rad/s} \times 0.02\,\mathrm{s} = 0.12\,\mathrm{rad}$ pro Policy-Schritt), 2. die Gelenk- und Kniekurbel-Begrenzung, genau wie in der Firmware. Werden diese im Training modelliert, lernt die Policy mit denselben Grenzen, die der Roboter vorgibt, statt sie erst auf der Hardware zu entdecken. ### Timing {#timing} Policy mit 50 Hz (`CONTROL_DT = 0.02` s), Physik mit 500 Hz: $0.02\,\mathrm{s} / 0.002\,\mathrm{s} = 10$ Physikschritte pro Action. Eine Episode dauert höchstens 1000 Schritte ($1000 \times 0.02\,\mathrm{s} = 20\,\mathrm{s}$). ### Befehle {#commands} Jede Episode zieht einen Befehl: 20 % der Episoden stehen still (Nullbefehl); die übrigen ziehen gleichverteilt aus vx −0,15…0,30 m/s, vy −0,10…0,10 m/s, ωz −0,6…0,6 rad/s. `policy_node` begrenzt `/cmd_vel` am Roboter auf diese Bereiche, weil die Policy nie etwas außerhalb davon gesehen hat. ### Reward {#reward} Pro Schritt, so skaliert, dass perfektes Folgen höchstens $1.0 + 0.8 = 1.8$ ergibt: $$ \begin{aligned} r = {} & 1.0\, \exp\!\left(-\lVert \mathbf{v}_{xy} - \mathbf{c}_{xy} \rVert^2 / 0.01\right) && \text{track linear velocity} \\ & + 0.8\, \exp\!\left(-(\omega_z - c_{\omega z})^2 / 0.05\right) && \text{track yaw rate} \\ & - 2.0\, v_z^2 && \text{no bouncing} \\ & - 0.05\, (\omega_x^2 + \omega_y^2) && \text{no rolling/pitching} \\ & - 0.01\, \lVert \mathbf{a}_t - \mathbf{a}_{t-1} \rVert^2 && \text{smooth actions} \\ & - 0.002 \sum_j \tau_j^2 && \text{save energy, spare the servos} \\ & - 2.0\, \max(0,\ 0.15\,\mathrm{m} - h) && \text{do not crouch below } 0.15\,\mathrm{m} \end{aligned} $$ Dabei sind $\mathbf{v}$ und $\boldsymbol{\omega}$ die Linear- und Winkelgeschwindigkeit der Basis, $\mathbf{c}$ der Befehl, $\mathbf{a}$ die Action, $\tau_j$ die Gelenkmomente und $h$ die Höhe der Basis. Eine Episode endet mit einer Strafe von −2, wenn die Basis unter 0,09 m sinkt oder sich über etwa 53° neigt. Die exponentiellen „Tracking-Kerne“ liefern einen glatten Reward, der bei perfektem Folgen 1 ist und mit dem Fehler abklingt: Bei der Breite 0,01 senkt ein Geschwindigkeitsfehler von $0.1\,\mathrm{m/s}$ den Term bereits auf $e^{-1} \approx 0.37$. Strafen formen, *wie* der Roboter läuft. Die Moment- und Action-Rate-Terme sind wichtiger, als sie aussehen: Ein Hobby-Servo, das mit 50 Hz zittern soll, erhitzt sich und verschleißt sein Getriebe. ### Domain Randomisation {#domain-randomisation} Der echte Roboter wird nicht genau dem Modell entsprechen. Statt darauf zu hoffen, variiert das Training das Modell in jeder Episode, damit die Policy lernt, mit einer Bandbreite zurechtzukommen: | Randomisiert | Bereich | |---|---| | Servosteifigkeit (kp und der passende Bias) | × 0,85 … 1,15 | | Masse der Basis | × 0,90 … 1,15 | | Kontaktreibung, Boden und Füße gemeinsam | × 0,6 … 1,2 | | IMU-Rauschen | Gyro σ 0,05 rad/s, Schwerkraft σ 0,02 | | Anfangsgelenkwinkel | Stehpose + σ 0,02 rad | Boden und Füße werden gemeinsam skaliert, weil MuJoCo die größere Reibung der beiden sich berührenden Geoms verwendet; nur eines zu skalieren, würde oft nichts ändern. ## Training, Export und Auswertung {#training-exporting-and-evaluating} ```bash uv sync --locked --group rl # once: PyTorch, Stable-Baselines3, Gymnasium (opt-in, large) make rl-smoke # 20 k steps + evaluation: checks the pipeline in seconds make rl-train # 20 M steps, 8 parallel envs, CPU → build/rl/ppo-v1/ make rl-eval # evaluate models/policies/ppo-v1/policy.npz with a video uv run --locked --group rl python -m strido_sim.rl.evaluate build/rl//policy.npz --vx 0.2 --video build/rl/eval.mp4 ``` Wichtige PPO-Einstellungen in `train.py`: 1024 Schritte je Umgebung je Update, Batch 2048, 5 Epochen, Lernrate $3 \times 10^{-4}$, $\gamma = 0.99$, GAE $\lambda = 0.95$, Clip $\epsilon = 0.2$; Actor `[128, 128]`, Critic `[256, 256]`; Observations und Rewards normalisiert (`VecNormalize`, Clip 10). Der aufgezeichnete Lauf `ppo-v1` dauerte 1734 s auf einer CPU. Das Training schreibt `policy.zip` (Stable-Baselines3), `vecnormalize.pkl`, `progress.csv` und **`policy.npz`**: die Gewichte und Biases des Actors sowie Mittelwert/Varianz der Observations als einfache Arrays. `strido.policy.MlpPolicy` implementiert den Vorwärtsdurchlauf in einem Dutzend Zeilen NumPy neu: normalisieren $\tilde{\mathbf{o}} = \operatorname{clip}\left((\mathbf{o} - \boldsymbol{\mu})/\sqrt{\boldsymbol{\sigma}^2 + 10^{-8}},\ -10,\ 10\right)$, then $\mathbf{h}_1 = \tanh(\mathbf{W}_1 \tilde{\mathbf{o}} + \mathbf{b}_1)$, $\mathbf{h}_2 = \tanh(\mathbf{W}_2 \mathbf{h}_1 + \mathbf{b}_2)$, $\mathbf{a} = \operatorname{clip}(\mathbf{W}_3 \mathbf{h}_2 + \mathbf{b}_3,\ -1,\ 1)$. Derselbe Code läuft in `evaluate.py` und in `policy_node`, das Ausgewertete ist also Bit für Bit die Funktion, die der Roboter ausführt, und der Pi benötigt kein PyTorch. ### Was ppo-v1 erreicht {#what-ppo-v1-achieves} | Test | Ergebnis | |---|---| | MuJoCo, Befehl vx 0,2 m/s (aktuelle Grenzen) | 0,215 m/s im Mittel, 2,15 m in 10 s, aufrecht | | MuJoCo, v0.1-Durchlauf | vx 0,15 → 0,152 m/s; 0 → steht; −0,1 → −0,068 m/s; vy 0,1 → 0,023 m/s (schwach); ωz 0,5 → 232° in 10 s | | Gazebo über `policy_node` (Sim-to-Sim) | 0,82 m in 8 s bei 0,15 m/s, aufrecht | Seitliches und rückwärtiges Folgen ist schwach: zu erwarten bei einer Policy ohne Gelenkrückmeldung (ADR-006). ## Die Sim-to-Real-Lücke {#the-sim-to-real-gap} Alles oben ist Simulation. Auf einem physischen Strido ist noch nichts gelaufen. Die bekannten Lücken: - **Servoverhalten.** kp 25 / kv 0,4 und null Latenz sind Schätzungen; echte Hobby-Servos haben Totzone, Spiel, Getriebenachgiebigkeit und eine spannungsabhängige Geschwindigkeit. - **Spannungseinbruch des Akkus.** Servogeschwindigkeit und -moment sinken mit der Akkuspannung; das Modell nimmt 6 V an. - **IMU.** Das Training liest ein perfektes Quaternion plus Gaußsches Rauschen; das des Roboters stammt aus einem Mahony-Filter mit eigener Verzögerung und eigenem Bias. - **Kontakte.** Gedruckte Füße auf einem echten Boden, keine gleichmäßige Ebene mit randomisierter Reibung. - **Nicht modellierte Mechanik.** Das Knie-Koppelgetriebe ist in der Simulation ein direktes Gelenk; Drucktoleranzen und Biegung sind nicht modelliert. Das Vorgehen des Repos für einen ersten Hardwarelauf: in MuJoCo und Gazebo auswerten, mit dem Roboter auf einem Ständer beginnen, `/strido/estop` griffbereit halten und damit rechnen, mit gemessenem Servoverhalten (kp/kv, Latenz) neu zu trainieren, sobald der Roboter existiert. ```bash ros2 launch strido_bringup robot.launch.py use_policy:=true policy:=/path/policy.npz ``` ::: warning Eine gelernte Policy kann schnelle, große Bewegungen befehlen, die der programmierte Gait nie ausführen würde. Anstiegsbegrenzung, Gelenkbegrenzungen und Watchdog der Firmware gelten weiterhin, können aber nicht verhindern, dass ein Bein Ihre Hand trifft. Testen Sie zuerst auf einem Ständer ([Sicherheit](../making/safety.md)). ::: ## Selbsttest {#check-yourself} 1. Warum beobachtet die Policy keine Gelenkwinkel? 2. Welche zwei Firmware-Verhalten werden in `env.step()` nachgebildet, und warum? 3. Warum werden Boden- und Fußreibung gemeinsam randomisiert? 4. Warum wird `policy.npz` exportiert, statt das Stable-Baselines3-Modell auf dem Pi auszuführen? 5. Was sagt Ihnen das Ausführen der in MuJoCo trainierten Policy in Gazebo?
Antworten 1. Die SPT5435LV-Servos haben keine Positionsrückmeldung; eine Policy darf nur verwenden, was der echte Roboter misst (IMU, Befehl, ihre eigene vorherige Action, einen Takt). 2. Die Anstiegsbegrenzung von 6 rad/s und die Gelenk-/Kniekurbel-Begrenzung, damit die Policy unter denselben Einschränkungen trainiert, die der Roboter vorgibt. 3. MuJoCo verwendet die größere Reibung der beiden sich berührenden Geoms; nur eine zu skalieren, hätte oft keine Wirkung. 4. Der Roboter bräuchte PyTorch; die NumPy-Laufzeit ist klein, und derselbe Code wird in der Auswertung verwendet, sodass die eingesetzte Funktion genau die ausgewertete ist. 5. Ob die Policy von MuJoCo-spezifischen Eigenheiten abhängt: Eine Sim-to-Sim-Lücke ist ein Warnzeichen für die Sim-to-Real-Lücke.
## Weiterführende Literatur {#further-reading} - [MuJoCo-Dokumentation](https://mujoco.readthedocs.io/en/stable/overview.html) - [Gazebo-Harmonic-Dokumentation](https://gazebosim.org/docs/harmonic/getstarted/) - [Stable-Baselines3 PPO](https://stable-baselines3.readthedocs.io/en/master/modules/ppo.html) - [Schulman et al., Proximal Policy Optimization Algorithms (2017)](https://arxiv.org/abs/1707.06347) - [Tobin et al., Domain Randomization for Transferring Deep Neural Networks from Simulation to the Real World (2017)](https://arxiv.org/abs/1703.06907) - Theorie: [Reinforcement Learning](../theory/reinforcement-learning.md), [Fortbewegung mit Beinen](../theory/legged-locomotion.md) --- # Regelung {#control} Regelungstechnik sorgt dafür, dass ein System tut, was Sie ihm befehlen – trotz Lasten, Rauschen und Modellfehlern –, indem gemessen wird, was es tatsächlich tut, und die Differenz korrigiert wird. Diese Seite behandelt Steuerung und Regelung, PID- und PD-Regelung, Übertragungsfunktionen und Sprungantworten, Abtastraten, den internen Regelkreis des Hobbyservos und Nachgiebigkeit, mit den Servos von Strido und seinem MuJoCo-Modell als Beispielen. ::: tip In Strido - **Raten:** Die Firmware betreibt eine Regel- und IMU-Schleife mit $200\,\mathrm{Hz}$ (`kControlPeriodUs = 5000`) und aktualisiert die Servos mit $200\,\mathrm{Hz}$ (`kServoFrequencyHz`; der SPT5435LV akzeptiert bis zu $330\,\mathrm{Hz}$). Sie streamt den Zustand mit $100\,\mathrm{Hz}$ an den Host (alles in `firmware/strido_esp32s3/src/board_config.h`). Der Gelenkbefehlsstrom läuft mit $100\,\mathrm{Hz}$ (`strido_sim/walk.py`), die gelernte Policy mit $50\,\mathrm{Hz}$ (`strido/policy.py`). - **Servomodell in der Simulation:** MuJoCo-Positionsaktuatoren mit `kp="25" kv="0.4" forcerange="-3.432 3.432"`, dazu Gelenk-`damping="0.25" armature="0.012" frictionloss="0.05"` (`models/mujoco/strido.xml`). - **Hardware:** 12 SPT5435LV-180W-Positionsservos, angesteuert von einem PCA9685-PWM-Board ([Servos](../hardware/servos.md), [Firmware](../software/firmware.md)). ::: ## Steuerung und Regelung {#open-loop-and-closed-loop} **Steuerung** (offener Kreis) legt einen vorab berechneten Eingang an und prüft das Ergebnis nie. Ein Trot-Gait, der Fußtrajektorien über inverse Kinematik abspielt, ist bezüglich des Körpers eine Steuerung: Rutscht der Roboter, bemerkt der Gait es nicht. **Regelung** (geschlossener Kreis, Rückkopplung) misst den Ausgang $y$, vergleicht ihn mit der Führungsgröße $r$ und wirkt auf den Fehler $e = r - y$. Rückkopplung unterdrückt Störungen und verdeckt Modellfehler. Der Preis sind Stabilitätsprobleme, wenn die Verstärkung zu hoch oder die Verzögerung zu lang ist. Strido stapelt mehrere Regelkreise, jeder schneller als der darüber: ```mermaid graph LR P[Policy / Gait
50–100 Hz] -->|Gelenk-Sollwerte| F[ESP32-Schleife
200 Hz, Ratenbegrenzung, Koppelgetriebe] F -->|PWM-Puls, 200-Hz-Frames| S[interner
Positionsregelkreis des Servos] S --> J[Gelenk] IMU[IMU 200 Hz] -->|Schwerkraft, Gyro| P ``` Die Servos geben dem Host keine Positionsrückmeldung (`strido_sim/rl/env.py`). Der einzige Regelkreis auf Gelenkebene schließt sich also *innerhalb* jedes Servos. Die Policy schließt den Regelkreis auf Körperebene über die IMU. ## PID-Regelung {#pid-control} Der klassische Regler kombiniert drei Anteile: $$ u(t) = K_p\,e(t) + K_i \int_0^t e(\tau)\,\mathrm{d}\tau + K_d\,\dot e(t) $$ - **P** drückt proportional zum Fehler, wie eine Feder. - **I** summiert vergangene Fehler auf und beseitigt bleibende Regelabweichungen, auf Kosten von Überschwingen und Wind-up. - **D** wirkt der Änderungsrate entgegen, wie ein Dämpfer. In der Praxis wirkt er auf $-\dot y$ statt auf $\dot e$, was einen Stoß bei einem Sprung der Führungsgröße vermeidet. Für Gelenke ist die übliche Wahl **PD** mit Soll-Geschwindigkeit null: $$ \tau = k_p\,(q^\ast - q) - k_v\,\dot q $$ Das ist genau MuJoCos ``-Aktuator. Das Ergebnis wird dann auf den Kraftbereich begrenzt, $\lvert\tau\rvert \le 3.432\,\mathrm{N\,m}$, das Blockiermoment des Servos. ## Übertragungsfunktionen und die Sprungantwort {#transfer-functions-and-the-step-response} Modellieren Sie ein Gelenk als Trägheit $I$ mit viskoser Dämpfung $b$. Im Laplace-Bereich gilt $I s^2 Q = T - b s Q$. Mit PD-Regelung lautet der geschlossene Kreis von Sollwert zu Winkel: $$ \frac{Q(s)}{Q^\ast(s)} = \frac{k_p}{I s^2 + (b + k_v)s + k_p} = \frac{\omega_n^2}{s^2 + 2\zeta\omega_n s + \omega_n^2}, \qquad \omega_n = \sqrt{\frac{k_p}{I}},\quad \zeta = \frac{b + k_v}{2\sqrt{k_p I}} $$ Dieses Standardsystem zweiter Ordnung erklärt das meiste, was Sie in einer Sprungantwort sehen: - $\omega_n$ bestimmt die Geschwindigkeit. Anstiegszeit $\approx 1.8/\omega_n$ und Bandbreite $\approx \omega_n$ für $\zeta$ nahe $0.7$. - $\zeta$ bestimmt die Form. Unter 1 schwingt die Antwort über und klingt nach. Das Überschwingen beträgt $\exp(-\pi\zeta/\sqrt{1-\zeta^2})$. Über 1 ist sie träge, aber monoton. - Eine Erhöhung von $k_p$ beschleunigt die Antwort, senkt aber $\zeta$, also erhöhen Sie $k_v$ mit. - Die statische Steifigkeit ist $k_p$: Eine konstante Last $\tau_L$ hinterlässt einen Fehler von $\tau_L/k_p$. Nur ein Integralanteil beseitigt ihn. ### Rechenbeispiel: das MuJoCo-Knie {#worked-example-the-mujoco-knee} Aus `models/mujoco/strido.xml`: $k_p = 25\,\mathrm{N\,m/rad}$, $k_v = 0.4\,\mathrm{N\,m\,s/rad}$, Gelenkdämpfung $b = 0.25$, Armatur $0.012\,\mathrm{kg\,m^2}$. Der Unterschenkel trägt $m r_c^2 \approx 0.0521 \cdot 0.048^2 = 1.2\times10^{-4}\,\mathrm{kg\,m^2}$ bei, dazu seine eigenen $1.5\times10^{-4}\,\mathrm{kg\,m^2}$ um seinen Schwerpunkt (`mass_report.yaml`), also $I \approx 0.0123\,\mathrm{kg\,m^2}$ für einen schwingenden Unterschenkel (die Armatur dominiert). Dann gilt: $$ \omega_n = \sqrt{\frac{25}{0.0121}} = 45\,\mathrm{rad/s}\ (7.2\,\mathrm{Hz}), \qquad \zeta = \frac{0.25 + 0.4}{2\sqrt{25 \cdot 0.0121}} = 0.59 $$ Das sagt eine Anstiegszeit von etwa $40\,\mathrm{ms}$ und rund $10\,\%$ Überschwingen voraus. Das sind Schätzungen: Sie ignorieren Reibungsverluste, die Momentenbegrenzung und die anderen Glieder. Im Stand trägt das Knie $0.70\,\mathrm{N\,m}$ (siehe [Statik und Dynamik](statics-and-dynamics.md)), also sackt das Modell ab um: $$ \Delta q = \frac{0.70}{25} = 0.028\,\mathrm{rad} \approx 1.6^\circ $$ Die Policy kann lernen, leicht über den Sollwert hinaus zu kommandieren, um das auszugleichen. Da die RL-Umgebung die Servosteifigkeit in jeder Episode randomisiert (`env.py`), kann sich die Policy nicht auf einen exakten Wert verlassen. ## Abtastung, Verzögerung und Bandbreite {#sampling-delay-and-bandwidth} Digitale Regler tasten ab. Die Nyquist-Grenze besagt, dass Sie mehr als zwei Abtastwerte pro Periode des schnellsten relevanten Signals brauchen. Für gute Regelung lautet die Faustregel: eine Schleife **10–20-mal schneller** als die Bandbreite des geschlossenen Kreises. Verzögerung zählt genauso: Eine reine Totzeit $T_d$ fügt einen Phasenverzug $\varphi = \omega T_d$ hinzu, der die Phasenreserve aufzehrt und einen Regelkreis mit hoher Verstärkung schließlich destabilisiert. Für Strido: | Schleife | Rate | Periode / zusätzliche Verzögerung im ungünstigsten Fall | |---|---|---| | Policy | $50\,\mathrm{Hz}$ | $20\,\mathrm{ms}$ | | Gelenkbefehlsstrom | $100\,\mathrm{Hz}$ | $10\,\mathrm{ms}$ | | ESP32-Regelung + IMU | $200\,\mathrm{Hz}$ | $5\,\mathrm{ms}$ | | Servo-PWM-Frame | $200\,\mathrm{Hz}$ (max. $330\,\mathrm{Hz}$) | $5\,\mathrm{ms}$ ($3.0\,\mathrm{ms}$) | | MuJoCo-Physik | $500\,\mathrm{Hz}$ | $2\,\mathrm{ms}$ | Ein klassischer analoger Servo nimmt nur alle $20\,\mathrm{ms}$ ($50\,\mathrm{Hz}$) einen neuen Puls an. Bei der oben geschätzten Gelenkbandbreite von $7.2\,\mathrm{Hz}$ kostet allein diese Verzögerung $\omega T_d = 45 \cdot 0.02 = 0.9\,\mathrm{rad} \approx 52^\circ$ Phase. Bei $200\,\mathrm{Hz}$ sind es $13^\circ$. Vermutlich betreibt die Firmware den PCA9685 deshalb mit $200\,\mathrm{Hz}$. Die $50\,\mathrm{Hz}$-Policy ist ausreichend, weil sie nur die Gangart formt, deren Zyklus $0.4\,\mathrm{s}$ beträgt ($2.5\,\mathrm{Hz}$, `GAIT_PERIOD_S` in `strido/policy.py`). Das ergibt 20 Policy-Schritte pro Zyklus, während die schnellen Schleifen darunter die steife Arbeit leisten. ## Der interne Regelkreis des Hobbyservos {#the-hobby-servo-s-internal-loop} Ein Hobbyservo ist ein kleines Regelsystem in einer Box: ein Gleichstrommotor, ein Getriebe, ein Potentiometer am Abtrieb und ein Regler-Chip. Die Pulsbreite kodiert den Sollwinkel. Der Chip vergleicht ihn mit dem Potentiometerwert und treibt den Motor mit annähernd proportionaler (oft PD-ähnlicher) Regelung an, begrenzt durch das Blockiermoment. Sie können weder seine Position auslesen noch seine Verstärkungen einstellen. Von außen verhält er sich wie ein steifes PD-Gelenk mit Momentbegrenzung, Geschwindigkeitsbegrenzung (im Leerlauf $0.14\,\mathrm{s}/60^\circ$ bei $6\,\mathrm{V}$, etwa $7.5\,\mathrm{rad/s}$) und etwas Totzone. Genau diese Abstraktion modelliert MuJoCos Positionsaktuator. Die Firmware fügt zusätzlich eine Ratenbegrenzung von $6\,\mathrm{rad/s}$ hinzu (`MAX_JOINT_SPEED_RAD_S`), damit plötzliche Sprünge keinen Strom nahe dem Blockierstrom ziehen. ## Impedanz und Nachgiebigkeit {#impedance-and-compliance} Ein Positionsregler mit den Verstärkungen $k_p$ und $k_v$ lässt das Gelenk sich wie ein **Feder-Dämpfer-System** in Richtung Sollwert verhalten: $$ \tau_{\text{ext}} = k_p\,\Delta q + k_v\,\dot q $$ Über $\boldsymbol{\tau} = \mathbf{J}^\top\mathbf{F}$ und $\delta\mathbf{p} = \mathbf{J}\,\delta\mathbf{q}$ auf den Fuß abgebildet, ergibt sich die kartesische Steifigkeit des Fußes: $$ \mathbf{K}_x = \mathbf{J}^{-\top}\,\mathbf{K}_q\,\mathbf{J}^{-1} $$ **Impedanzregelung** wählt diese Steifigkeit gezielt. Ein Laufroboter will seine Füße beim Aufsetzen *nachgiebig*, damit Stöße absorbiert werden und kleine Geländefehler den Körper nicht erschüttern, und steif während der Standphase. Roboter mit drehmomentgeregelten Motoren (zum Beispiel der MIT Cheetah) setzen $\mathbf{K}_x$ in Software. Ein Hobbyservo ist steif und fest eingestellt, daher entsteht die Nachgiebigkeit bei Strido durch niedrigere kommandierte Geschwindigkeit, die Ratenbegrenzung, die Fußpolster und eine mit randomisierter Steifigkeit trainierte Policy. ## Selbstkontrolle {#check-yourself} 1. Warum erreicht ein PD-geregeltes Gelenk unter konstanter Last seinen Sollwert nicht exakt? 2. Was passiert mit $\omega_n$ und $\zeta$, wenn Sie $k_p$ verdoppeln und $k_v$ beibehalten? 3. Warum würde ein $50\,\mathrm{Hz}$-Servo-Frame mehr schaden als eine $50\,\mathrm{Hz}$-Policy? 4. Wo befindet sich am realen Roboter der einzige Rückkopplungskreis für die Gelenkposition?
Antworten 1. Im stationären Zustand muss der P-Anteil das Lastmoment aufbringen, also ist $e = \tau_L/k_p \neq 0$. Nur ein Integralanteil beseitigt ihn. 2. $\omega_n$ wächst um den Faktor $\sqrt{2}$. $\zeta$ sinkt um den Faktor $\sqrt{2}$, es gibt also mehr Überschwingen. 3. Die Frame-Verzögerung liegt innerhalb der schnellen, steifen Gelenkschleife, deren Bandbreite mehrere Hertz beträgt. Die Policy formt langsamere Körperbewegungen (den $2.5\,\mathrm{Hz}$-Gangzyklus) und stützt sich auf die Gelenkschleifen darunter. 4. Innerhalb jedes Servos, zwischen seinem Potentiometer und seinem Regler-Chip. Host und ESP32 sehen den Gelenkwinkel nie.
## Weiterführende Literatur {#further-reading} - K. J. Åström und R. M. Murray, *Feedback Systems: An Introduction for Scientists and Engineers*, 2. Aufl., Princeton University Press, 2021. [Kostenlos online](https://fbswiki.org) - K. M. Lynch und F. C. Park, *Modern Robotics*, Cambridge University Press, 2017, Kap. 11 (Roboterregelung, einschließlich Impedanzregelung). - N. Hogan, „Impedance Control: An Approach to Manipulation“, *ASME J. Dynamic Systems, Measurement, and Control*, 107(1), 1985. - [MuJoCo-Dokumentation: Aktuatoren](https://mujoco.readthedocs.io/en/stable/XMLreference.html#actuator). - [Servos](../hardware/servos.md) und [Firmware](../software/firmware.md) in diesem Wiki. --- # Koordinatensysteme und Rotationen {#frames-and-rotations} Jede Zahl, die ein Roboter für Position oder Orientierung verwendet, bezieht sich auf ein Koordinatensystem (Frame). Diese Seite behandelt Frames, Rotationsmatrizen, Roll-Nick-Gier-Winkel und Gimbal Lock, Quaternionen und homogene Transformationen und zeigt dann, wie sie im Transformationsbaum (tf) von Strido zusammenspielen. ::: tip In Strido - **Basis-Frame:** REP-103 (`x` vorwärts, `y` links, `z` oben), mit dem Ursprung im Mittelpunkt der vier Schnittpunkte der Hüftachsen. Er ist in `hardware/kinematics.yaml` (`base_frame`) definiert, zusammen mit der Rotation aus dem CAD-Frame (STEP). - **Frame-Baum:** `ros2/strido_description/urdf/strido.urdf.xacro` definiert `base_link`, `imu_link`, `lidar_link`, `camera_link`, `camera_optical_frame` und für jedes Bein `*_hip`, `*_thigh`, `*_calf` und `*_foot`. - **Orientierung:** Die Firmware führt einen Mahony-Filter aus und gibt eine Quaternion aus (`firmware/strido_esp32s3/src/main.cpp`). `mcu_bridge` veröffentlicht sie als `/imu/data` in `imu_link`. - **Beintransformationen im Code:** `foot_position` in `packages/strido-core/src/strido/leg.py`. ::: ## Frames {#frames} Ein **Frame** ist ein Ursprung plus drei orthogonale Einheitsachsen. Ein Punkt $\mathbf{p}$ hat für sich allein keine Koordinaten; er hat nur Koordinaten *in* einem Frame. Wir schreiben ${}^{A}\mathbf{p}$ für „die Koordinaten von $\mathbf{p}$ im Frame $A$“. Alle Frames hier sind rechtshändig: $\hat{\mathbf{x}} \times \hat{\mathbf{y}} = \hat{\mathbf{z}}$. ROS legt die Konventionen in [REP-103](https://www.ros.org/reps/rep-0103.html) fest. Körper-Frames verwenden $x$ vorwärts, $y$ links und $z$ oben. Einheiten sind Meter und Radiant. Strido folgt dem. Sein `base_link`-Ursprung ist der Mittelpunkt der vier Schnittpunkte der Hüftachsen, daher liegen die Hüften bei $(\pm 0.120, \pm 0.039, 0)\,\mathrm{m}$ (`legs_base` in `hardware/kinematics.yaml`). Das CAD-Modell verwendet einen anderen Frame. `hardware/kinematics.yaml` speichert die Rotation, die STEP-Koordinaten in Basiskoordinaten abbildet: $$ \mathbf{R}_{\text{base}\leftarrow\text{STEP}} = \begin{bmatrix} 0 & -1 & 0 \\ 1 & 0 & 0 \\ 0 & 0 & 1 \end{bmatrix} $$ Das ist eine Drehung um $+90^\circ$ um $z$: Die STEP-$y$-Achse zeigt nach hinten, daher wird STEP $-y$ zu Basis $+x$. ## Rotationsmatrizen {#rotation-matrices} Die Orientierung von Frame $B$ relativ zu Frame $A$ ist eine $3\times 3$-Matrix ${}^{A}\mathbf{R}_{B}$. Ihre Spalten sind die Einheitsachsen von $B$, ausgedrückt in $A$-Koordinaten. Ein Vektor wird umgerechnet als ${}^{A}\mathbf{v} = {}^{A}\mathbf{R}_{B}\,{}^{B}\mathbf{v}$. Da die Spalten orthonormal sind: $$ \mathbf{R}^\top \mathbf{R} = \mathbf{I}, \qquad \det \mathbf{R} = +1, \qquad \mathbf{R}^{-1} = \mathbf{R}^\top $$ Rotationsmatrizen mit diesen Eigenschaften bilden die Gruppe $SO(3)$. Die drei elementaren Rotationen sind: $$ \mathbf{R}_x(\theta) = \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cos\theta & -\sin\theta \\ 0 & \sin\theta & \cos\theta \end{bmatrix},\quad \mathbf{R}_y(\theta) = \begin{bmatrix} \cos\theta & 0 & \sin\theta \\ 0 & 1 & 0 \\ -\sin\theta & 0 & \cos\theta \end{bmatrix},\quad \mathbf{R}_z(\theta) = \begin{bmatrix} \cos\theta & -\sin\theta & 0 \\ \sin\theta & \cos\theta & 0 \\ 0 & 0 & 1 \end{bmatrix} $$ Rotationen werden durch Multiplikation verknüpft, ${}^{A}\mathbf{R}_{C} = {}^{A}\mathbf{R}_{B}\,{}^{B}\mathbf{R}_{C}$. Die Reihenfolge zählt, weil Rotationen nicht kommutieren: im Allgemeinen gilt $\mathbf{R}_x\mathbf{R}_y \neq \mathbf{R}_y\mathbf{R}_x$. ## Rollen, Nicken, Gieren und Gimbal Lock {#roll-pitch-yaw-and-gimbal-lock} Eine Rotation hat drei Freiheitsgrade, ihre Matrix aber neun Zahlen. **Euler-Winkel** beschreiben sie mit drei aufeinanderfolgenden elementaren Rotationen. ROS und URDF verwenden **Roll-Nick-Gier** (RPY): Rollen $\phi$ um $x$, Nicken $\theta$ um $y$, Gieren $\psi$ um $z$, in dieser Reihenfolge um die festen Achsen angewendet. Das ergibt: $$ \mathbf{R} = \mathbf{R}_z(\psi)\,\mathbf{R}_y(\theta)\,\mathbf{R}_x(\phi) $$ RPY ist leicht zu lesen. Die Kamera von Strido ist mit `rpy="0 0.261799 0"` montiert, einer Neigung von $15^\circ$ nach unten. Ein um $5^\circ$ „gerollter“ Körper ist leicht vorstellbar. RPY-Winkel haben eine Singularität. Bei $\theta = \pm 90^\circ$ fallen Roll- und Gierachse zusammen, und nur $\phi \pm \psi$ ist definiert. Ein Freiheitsgrad ist verloren. Das ist der **Gimbal Lock**. In seiner Nähe kann eine kleine Orientierungsänderung einen großen Sprung der Winkel verursachen, und die Winkelraten $$ \dot{\phi},\ \dot{\theta},\ \dot{\psi} $$ gehen gegen unendlich. Das liegt daran, dass die Matrix, die die Winkelgeschwindigkeit des Körpers auf $(\dot\phi,\dot\theta,\dot\psi)$ abbildet, $1/\cos\theta$ enthält. Kein Satz aus drei Winkeln vermeidet das überall; es ist eine topologische Eigenschaft von $SO(3)$. Ein gehender Roboter nickt selten um $90^\circ$, ein Sturz kann es aber. Das ist ein Grund, warum Schätzer die Orientierung als Quaternion speichern. ## Quaternionen {#quaternions} Eine Einheitsquaternion $\mathbf{q} = (w, x, y, z)$ mit $w^2+x^2+y^2+z^2 = 1$ kodiert eine Rotation um den Winkel $\alpha$ um die Einheitsachse $\hat{\mathbf{n}}$: $$ \mathbf{q} = \left(\cos\tfrac{\alpha}{2},\ \hat{\mathbf{n}}\sin\tfrac{\alpha}{2}\right) $$ Rotationen werden durch das Quaternionenprodukt (Hamilton-Produkt) verknüpft. $\mathbf{q}$ und $-\mathbf{q}$ ergeben dieselbe Rotation. Die Darstellung hat keine Singularität, braucht vier statt neun Zahlen und lässt sich nach numerischer Drift günstig renormieren. Die äquivalente Rotationsmatrix ist: $$ \mathbf{R}(\mathbf{q}) = \begin{bmatrix} 1-2(y^2+z^2) & 2(xy-wz) & 2(xz+wy) \\ 2(xy+wz) & 1-2(x^2+z^2) & 2(yz-wx) \\ 2(xz-wy) & 2(yz+wx) & 1-2(x^2+y^2) \end{bmatrix} $$ Die Firmware von Strido erhält $\mathbf{q}$ aus `orientation.getQuaternion` und sendet sie an den Pi. Die gelernte Policy verwendet nicht die rohen Winkel. Sie verwendet die Richtung der Schwerkraft aus Sicht des Körpers, ${}^{B}\mathbf{g} = \mathbf{R}(\mathbf{q})^\top (0,0,-1)^\top$ (siehe `packages/strido-sim/src/strido_sim/rl/env.py`). Dieser Vektor ist für jede Orientierung glatt und hat keinen Gimbal Lock. Siehe [State Estimation](state-estimation.md), wie der Filter $\mathbf{q}$ erzeugt. ## Homogene Transformationen {#homogeneous-transforms} Eine **Pose** kombiniert eine Rotation und eine Translation. Eine homogene $4\times 4$-Transformation fasst beide zusammen: $$ {}^{A}\mathbf{T}_{B} = \begin{bmatrix} {}^{A}\mathbf{R}_{B} & {}^{A}\mathbf{t}_{B} \\ \mathbf{0}^\top & 1 \end{bmatrix}, \qquad \begin{bmatrix} {}^{A}\mathbf{p} \\ 1 \end{bmatrix} = {}^{A}\mathbf{T}_{B} \begin{bmatrix} {}^{B}\mathbf{p} \\ 1 \end{bmatrix} $$ Hier ist ${}^{A}\mathbf{t}_{B}$ der Ursprung von $B$, ausgedrückt in $A$. Transformationen werden durch Multiplikation verkettet, ${}^{A}\mathbf{T}_{C} = {}^{A}\mathbf{T}_{B}\,{}^{B}\mathbf{T}_{C}$. Die Inverse ist: $$ {}^{B}\mathbf{T}_{A} = \left({}^{A}\mathbf{T}_{B}\right)^{-1} = \begin{bmatrix} \mathbf{R}^\top & -\mathbf{R}^\top\mathbf{t} \\ \mathbf{0}^\top & 1 \end{bmatrix} $$ Jedes URDF-Gelenk ist genau eine solche Transformation. Zuerst kommt der feste ``. Bei einem Drehgelenk folgt eine Rotation um `` um den Gelenkwinkel. ## Der tf-Baum von Strido {#the-strido-tf-tree} ```mermaid graph TD odom --> base_link base_link --> imu_link base_link --> lidar_link base_link --> camera_link --> camera_optical_frame base_link --> FL_hip --> FL_thigh --> FL_calf --> FL_foot base_link --> FR_hip --> FR_thigh --> FR_calf --> FR_foot base_link --> RL_hip --> RL_thigh --> RL_calf --> RL_foot base_link --> RR_hip --> RR_thigh --> RR_calf --> RR_foot ``` `robot_state_publisher` berechnet die Beintransformationen aus den Gelenkwinkeln. Die Sensor-Frames sind fest. Zum Beispiel liegt `imu_link` bei $(0.042, -0.004, -0.011)\,\mathrm{m}$, mit Achsen parallel zu `base_link`. `camera_optical_frame` verwendet `rpy="-π/2 0 -π/2"`, damit seine $z$-Achse entlang der Blickrichtung zeigt, was die optische Konvention in REP-103 ist. `odom → base_link` kommt von `gait_node`, das die *kommandierte* Körpergeschwindigkeit integriert. Es ist keine gemessene Odometrie (siehe den Docstring von `ros2/strido_control/strido_control/gait_node.py`). Für das vordere linke Bein lautet die URDF-Kette: $$ {}^{\text{base}}\mathbf{T}_{\text{foot}} = \underbrace{\mathrm{Trans}(0.1197, 0.039, 0)\,\mathrm{Rot}_x(q_1)}_{\text{FL\_hip\_joint}}\; \underbrace{\mathrm{Trans}(0, 0.0383, 0)\,\mathrm{Rot}_y(q_2)}_{\text{FL\_thigh\_joint}}\; \underbrace{\mathrm{Trans}(0, 0, -0.130)\,\mathrm{Rot}_y(q_3)}_{\text{FL\_calf\_joint}}\; \underbrace{\mathrm{Trans}(0, 0, -0.124)}_{\text{FL\_foot\_joint}} $$ ## Rechenbeispiel: Abduktion des vorderen linken Beins {#worked-example-abducting-the-front-left-leg} In der Standpose (`stand_pose()` in `strido/gait.py`, Körperhöhe $0.17\,\mathrm{m}$) sind die Gelenkwinkel vorne links $q_1 = 0$, $q_2 = 46.5^\circ$ und $q_3 = -96.0^\circ$. Die Rotationen von Oberschenkel und Unterschenkel platzieren den Fuß bei $\mathbf{p}_{\text{hip}} = (0,\ 0.0383,\ -0.170)\,\mathrm{m}$ relativ zum Ursprung des Hüftgelenks. Die $0.0383\,\mathrm{m}$ sind der seitliche Versatz zur Beinebene, und der Fuß steht senkrecht unter der Hüfte. Nun Abduktion um $q_1 = 10^\circ$ ($\cos = 0.9848$, $\sin = 0.1736$): $$ \mathbf{R}_x(10^\circ)\,\mathbf{p}_{\text{hip}} = \begin{bmatrix} 0 \\ 0.9848 \cdot 0.0383 - 0.1736 \cdot (-0.170) \\ 0.1736 \cdot 0.0383 + 0.9848 \cdot (-0.170) \end{bmatrix} = \begin{bmatrix} 0 \\ 0.0672 \\ -0.1608 \end{bmatrix}\mathrm{m} $$ Addiert man den Hüftursprung $(0.1197, 0.039, 0)$, liegt der Fuß bei $(0.1197,\ 0.1062,\ -0.1608)\,\mathrm{m}$ in `base_link`. `foot_position("FL", (0.1745, 0.8121, -1.6761))` liefert denselben Punkt. Dieselbe Rotation als Quaternion ist $(\cos 5^\circ, \sin 5^\circ, 0, 0) = (0.9962, 0.0872, 0, 0)$. ## Prüfen Sie sich selbst {#check-yourself} 1. Warum ist ${}^{A}\mathbf{R}_{B}^{-1}$ einfach die Transponierte? 2. Der IMU-Frame ist parallel zu `base_link`, aber um einige Zentimeter versetzt. Ändert der Versatz die gemessene Winkelgeschwindigkeit? Ändert er die gemessene Beschleunigung? 3. Warum beobachtet die Policy den Schwerkraftvektor statt Rollen, Nicken und Gieren? 4. Schreiben Sie ${}^{\text{camera\_optical}}\mathbf{T}_{\text{base}}$ mithilfe der URDF-Transformationen.
Antworten 1. Die Spalten sind orthonormal, daher gilt $\mathbf{R}^\top\mathbf{R} = \mathbf{I}$. 2. Die Winkelgeschwindigkeit ist überall auf einem starren Körper gleich, daher ändert der Versatz sie nicht. Die lineare Beschleunigung ändert sich: Ein versetzter Punkt sieht zusätzliche Terme $\boldsymbol{\omega}\times(\boldsymbol{\omega}\times\mathbf{r}) + \dot{\boldsymbol{\omega}}\times\mathbf{r}$. 3. Er ist stetig und hat keine Singularität. Außerdem ist das Gieren mit einer IMU ohne Magnetometer nicht beobachtbar, und das Gehen braucht es nicht. 4. $\left({}^{\text{base}}\mathbf{T}_{\text{camera}}\,{}^{\text{camera}}\mathbf{T}_{\text{optical}}\right)^{-1}$, wobei jeder Faktor aus `xyz` und `rpy` des Gelenks gebildet wird.
## Weiterführende Literatur {#further-reading} - K. M. Lynch und F. C. Park, *Modern Robotics: Mechanics, Planning, and Control*, Cambridge University Press, 2017, Kap. 3 (Starrkörperbewegungen). [Kostenloses PDF](http://hades.mech.northwestern.edu/index.php/Modern_Robotics) - B. Siciliano, L. Sciavicco, L. Villani und G. Oriolo, *Robotics: Modelling, Planning and Control*, Springer, 2009, Kap. 2. - [REP-103: Standard Units of Measure and Coordinate Conventions](https://www.ros.org/reps/rep-0103.html) und [REP-105: Coordinate Frames for Mobile Platforms](https://www.ros.org/reps/rep-0105.html). - J. Solà, „Quaternion kinematics for the error-state Kalman filter“, arXiv:1711.02508, 2017. - [ROS 2 und die Roboterbeschreibung](../software/ros2.md) in diesem Wiki. --- # Kinematik {#kinematics} Kinematik ist die Geometrie der Bewegung, ohne Kräfte. Die Vorwärtskinematik bildet Gelenkwinkel auf die Fußposition ab. Die inverse Kinematik bildet eine Fußposition zurück auf Gelenkwinkel ab. Die Jacobi-Matrix verknüpft Gelenkgeschwindigkeiten mit Fußgeschwindigkeiten. Diese Seite leitet alle drei für das Strido-Bein her, einschließlich seines Kniekoppelgetriebes. ::: tip In Strido - **Beinmodell:** `packages/strido-core/src/strido/leg.py` (`foot_position`, `inverse_kinematics`, `calf_from_crank`, `crank_from_calf`, `transmission_angles`), in C++ gespiegelt in `firmware/strido_esp32s3/lib/strido_core/`. - **Maße:** `hardware/kinematics.yaml` (`legs_linkage`, `legs_base`), aus dem CAD gemessen. **Grenzen:** `hardware/joint_limits.yaml`. - **Praxisleitfaden:** [Kinematik und Gaits](../software/kinematics-and-gaits.md) zeigt, wie der Gait diese Funktionen nutzt. ::: ## Das Bein als kinematische Kette {#the-leg-as-a-kinematic-chain} Jedes Bein hat drei Drehgelenke (Docstring von `leg.py`; die Konventionen entsprechen dem Unitree Go2): | Gelenk | Achse | Null | Positiv | |---|---|---|---| | Hüfte $q_1$ | $+x$ | Bein senkrecht | Fuß Richtung $+y$ | | Oberschenkel $q_2$ | $+y$ | Femur gerade nach unten | Knie nach hinten | | Unterschenkel $q_3$ | $+y$, relativ zum Femur | Unterschenkel in Linie mit Femur | negativ = Knie gebeugt | Aus `hardware/kinematics.yaml` (Bein vorne links, gerundet): Die Hüfte liegt bei $\mathbf{h} = (0.1197, 0.039, 0)\,\mathrm{m}$ in `base_link`, die Beinebene liegt $d = 38.3\,\mathrm{mm}$ außerhalb der Hüfte ($40.2\,\mathrm{mm}$ bei den Hinterbeinen), der Oberschenkel misst $l_1 = 130.0\,\mathrm{mm}$ und der Unterschenkel $l_2 = 124.1\,\mathrm{mm}$ bis zur Fußmitte. Oberschenkel und Unterschenkel bewegen sich in einer senkrechten **Beinebene**. Das Hüftgelenk kippt diese Ebene um $x$. Das Problem zerfällt also in zwei einfachere: einen ebenen Zweigelenkarm und eine Drehung. ## Vorwärtskinematik {#forward-kinematics} In der Beinebene zeige $u$ nach vorne und $v$ nach oben, beide vom Oberschenkel-Drehpunkt aus gemessen. Schreiben Sie $s_2 = \sin q_2$ und $s_{23} = \sin(q_2 + q_3)$, analog für Kosinus. Knie und Fuß liegen bei: $$ \mathbf{k} = \begin{bmatrix} -l_1 s_2 \\ -l_1 c_2 \end{bmatrix}, \qquad \begin{bmatrix} u \\ v \end{bmatrix} = \begin{bmatrix} -l_1 s_2 - l_2 s_{23} \\ -l_1 c_2 - l_2 c_{23} \end{bmatrix} $$ Die Winkel addieren sich, weil $q_3$ relativ zum Femur gemessen wird; der absolute Winkel des Unterschenkels ist also $q_2 + q_3$. Die Vorzeichen sind negativ, weil Null „nach unten zeigend“ bedeutet und ein positives $q_2$ den Fuß nach hinten schwingt (Richtung $-u$). Als Nächstes die Hüftdrehung. Der Fuß im Hüft-Koordinatensystem vor der Abduktion ist $(u, d, v)$. Drehung um $x$ um $q_1$ und Addition der Hüftposition ergibt: $$ \mathbf{p} = \mathbf{h} + \mathbf{R}_x(q_1)\begin{bmatrix} u \\ d \\ v \end{bmatrix} = \mathbf{h} + \begin{bmatrix} u \\ d\cos q_1 - v\sin q_1 \\ d\sin q_1 + v\cos q_1 \end{bmatrix} $$ Das ist `foot_position` Zeile für Zeile. Zu den Konventionen der Koordinatensysteme siehe [Koordinatensysteme und Rotationen](frames-and-rotations.md). ## Inverse Kinematik {#inverse-kinematics} Gegeben ist ein Fußziel $\mathbf{p}$, gesucht ist $(q_1, q_2, q_3)$. Sei $\mathbf{r} = \mathbf{p} - \mathbf{h} = (r_x, r_y, r_z)$. ### Hüftabduktion {#hip-abduction} Eine Drehung um $x$ lässt die $x$-Komponente unverändert und erhält die Länge in der $y$–$z$-Ebene: $$ r_y^2 + r_z^2 = d^2 + v^2 $$ Der Fuß liegt unter der Hüfte, also nehmen wir die negative Wurzel: $$ v = -\sqrt{r_y^2 + r_z^2 - d^2} $$ Ist der Term unter der Wurzel nicht positiv, liegt das Ziel innerhalb des Zylinders mit Radius $d$ um die Hüftachse und ist nicht erreichbar. Die Richtung von $(r_y, r_z)$ ist die um $q_1$ gedrehte Richtung von $(d, v)$, also: $$ q_1 = \operatorname{atan2}(r_z, r_y) - \operatorname{atan2}(v, d) $$ ### Das ebene Zweigelenkproblem: Kosinussatz {#the-planar-two-link-problem-law-of-cosines} Setzen Sie nun $u = r_x$ und lösen Sie den Zweigelenkarm. Oberschenkel, Unterschenkel und die Linie vom Drehpunkt zum Fuß bilden ein Dreieck mit den Seiten $l_1$, $l_2$ und $\rho = \sqrt{u^2+v^2}$. Der Kosinussatz am Knie liefert den Kniewinkel. Mit unserer Konvention (der Knie-Innenwinkel ist $\pi + q_3$): $$ \rho^2 = l_1^2 + l_2^2 + 2 l_1 l_2 \cos q_3 \quad\Longrightarrow\quad \cos q_3 = \frac{u^2 + v^2 - l_1^2 - l_2^2}{2 l_1 l_2} $$ Es gibt zwei Lösungen, $\pm\arccos$, für Knie nach vorne und Knie nach hinten. Strido verwendet $q_3 = -\arccos(\cdot)$, ein gebeugtes Knie, das nach hinten zeigt. Ist $\lvert\cos q_3\rvert > 1$, liegt das Ziel außer Reichweite. Der Oberschenkelwinkel ist die Richtung zum Fuß minus den Winkel, den der Unterschenkel im Dreieck hinzufügt: $$ q_2 = \operatorname{atan2}(-u, -v) - \operatorname{atan2}\!\left(l_2 \sin q_3,\ l_1 + l_2\cos q_3\right) $$ Die Minuszeichen im ersten Term stammen aus der Konvention „Null = gerade nach unten, positiv = nach hinten“. Verwenden Sie `atan2`, nie `atan`, damit der Quadrant stimmt. ### Das Knie-Viergelenk {#the-knee-four-bar} Der Knieservo treibt $q_3$ nicht direkt an. Ein Parallelogramm (Arm $24.0\,\mathrm{mm}$, kurze Koppel $28.3\,\mathrm{mm}$, Kurbel $24.0\,\mathrm{mm}$) überträgt den Servowinkel auf eine Kurbel $\psi$ am Oberschenkel-Drehpunkt. Ein Viergelenk (Kurbel $26.9\,\mathrm{mm}$, lange Koppel $131\,\mathrm{mm}$, Tibiakurbel $24.0\,\mathrm{mm}$ und der Femur $130.0\,\mathrm{mm}$ als Steg) dreht dann die Tibia. Weil der Steg des Viergelenks der Femur selbst ist: $$ q_3 = f(q_2, \psi) $$ Bewegt man nur den Oberschenkel, bewegt sich auch das Knie. `crank_from_calf` invertiert das geometrisch. Das freie Ende der Kurbel liegt auf einem Kreis mit Radius $26.9\,\mathrm{mm}$ um den Drehpunkt und zugleich auf einem Kreis mit Radius $131\,\mathrm{mm}$ (die lange Koppel) um den Tibia-Bolzen. Der Schnitt der beiden Kreise liefert zwei Kandidaten, und der Montagezweig wählt einen aus. `circle_intersection` gibt `None` zurück, wenn sich die Kreise nicht treffen. Dann lässt sich das Koppelgetriebe in dieser Pose nicht zusammensetzen. ```mermaid graph LR S[Knieservo-Winkel] -->|Parallelogramm 1:1| C[Kurbel ψ] C -->|Viergelenk, abhängig von q2| K[Knie q3] T[Oberschenkelservo q2] --> K ``` ## Die Jacobi-Matrix {#the-jacobian} Die Jacobi-Matrix bildet Gelenkgeschwindigkeiten auf die Fußgeschwindigkeit ab, $\dot{\mathbf{p}} = \mathbf{J}(\mathbf{q})\,\dot{\mathbf{q}}$. Ableiten der ebenen Vorwärtskinematik ergibt: $$ \mathbf{J}_{\text{plane}} = \frac{\partial (u, v)}{\partial (q_2, q_3)} = \begin{bmatrix} -l_1 c_2 - l_2 c_{23} & -l_2 c_{23} \\ \phantom{-}l_1 s_2 + l_2 s_{23} & \phantom{-}l_2 s_{23} \end{bmatrix}, \qquad \det \mathbf{J}_{\text{plane}} = -\,l_1 l_2 \sin q_3 $$ Die vollständige $3\times 3$-Jacobi-Matrix ergänzt die Hüftspalte, $\partial\mathbf{p}/\partial q_1 = \hat{\mathbf{x}} \times (\mathbf{p} - \mathbf{h})$, und dreht die ebenen Spalten mit $\mathbf{R}_x(q_1)$. Die Jacobi-Matrix bestimmt auch die Kräfte über $\boldsymbol{\tau} = \mathbf{J}^\top\mathbf{F}$ (siehe [Statik und Dynamik](statics-and-dynamics.md)). Für den Antrieb fügt die Kettenregel einen weiteren Faktor hinzu. Die Geschwindigkeit des Knieservos ist $\dot\psi$, und $$ \dot q_3 = \frac{\partial f}{\partial q_2}\dot q_2 + \frac{\partial f}{\partial \psi}\dot\psi $$ ## Arbeitsraum und Singularitäten {#workspace-and-singularities} Ohne Gelenkgrenzen erreicht der ebene Fuß einen Kreisring: $$ \lvert l_1 - l_2\rvert \le \rho \le l_1 + l_2 \quad\Rightarrow\quad 5.9\,\mathrm{mm} \le \rho \le 254.1\,\mathrm{mm} $$ Gelenkgrenzen und Eigenkollisionen schränken das ein. `hardware/joint_limits.yaml` begrenzt $q_3$ auf $[-150^\circ, -45^\circ]$ und das vordere $q_2$ auf $[-45^\circ, 125^\circ]$, ermittelt durch Abfahren des gestellten CAD auf Kollisionen in einem $5^\circ$-Raster. Eine **Singularität** ist eine Pose mit $\det\mathbf{J} = 0$. Dort kann sich der Fuß in eine Richtung nicht bewegen, egal wie schnell sich die Gelenke drehen, und die inverse Kinematik wird schlecht konditioniert. Beim ebenen Bein geschieht das bei $\sin q_3 = 0$: Bein vollständig gestreckt ($q_3 = 0$, am äußeren Rand des Arbeitsraums) oder vollständig eingeklappt. Die Unterschenkelgrenze hält $\lvert\sin q_3\rvert \ge \sin 30^\circ = 0.5$ (am Ende bei $-150^\circ$; mindestens $0.71$ am Ende bei $-45^\circ$), sodass das Bein nie in die Nähe kommt. Das ist ein Grund, warum die Standpose das Knie deutlich gebeugt hält. Das Viergelenk hat eigene Singularitäten. Wenn die lange Koppel mit der Kurbel oder mit der Tibiakurbel fluchtet (Übertragungswinkel nahe $0$ oder $180^\circ$), wird $\partial f/\partial\psi$ unendlich oder verschwindet. `transmission_angles` misst beide Winkel, und `joint_limits.yaml` verlangt mindestens $25^\circ$ (`transmission_min_deg`). ## Durchgerechnetes Beispiel: die Standpose {#worked-example-the-stand-pose} Die Standpose setzt jeden Fuß senkrecht unter seine Hüfte, $0.17\,\mathrm{m}$ tiefer (`stand_pose(height=0.17)` in `strido/gait.py`). Für das Bein vorne links gilt $\mathbf{r} = (0,\ 0.0383,\ -0.170)\,\mathrm{m}$. **Hüfte.** $v = -\sqrt{0.0383^2 + 0.170^2 - 0.0383^2} = -0.170$, also $q_1 = \operatorname{atan2}(-0.170, 0.0383) - \operatorname{atan2}(-0.170, 0.0383) = 0$. **Knie.** Mit $u = 0$: $$ \cos q_3 = \frac{0.170^2 - 0.1300^2 - 0.1241^2}{2 \cdot 0.1300 \cdot 0.1241} = \frac{-0.00339}{0.03226} = -0.105 \quad\Rightarrow\quad q_3 = -96.0^\circ $$ **Oberschenkel.** $l_2\sin q_3 = -0.1234$ und $l_1 + l_2\cos q_3 = 0.1170$, also $$ q_2 = \operatorname{atan2}(0, 0.170) - \operatorname{atan2}(-0.1234, 0.1170) = 0 + 46.5^\circ = 46.5^\circ $$ Das stimmt mit `stand_pose()` überein, das für jedes Bein $(0^\circ, 46.53^\circ, -96.03^\circ)$ liefert. Der absolute Winkel des Unterschenkels ist $q_2 + q_3 = -49.5^\circ$: Das Knie liegt hinter und über dem Fuß, und der Unterschenkel neigt sich nach vorne, um ihn zu erreichen. **Jacobi-Matrix.** In dieser Pose gilt $$ \mathbf{J}_{\text{plane}} = \begin{bmatrix} -0.170 & -0.0806 \\ 0 & -0.0943 \end{bmatrix}\mathrm{m/rad}, \qquad \det = 0.0160\,\mathrm{m^2} $$ Eine Oberschenkelgeschwindigkeit von $1\,\mathrm{rad/s}$ bewegt den Fuß mit $0.17\,\mathrm{m/s}$ nach hinten und überhaupt nicht senkrecht. Um den Fuß anzuheben, braucht man vor allem das Knie. **Koppelgetriebe.** `leg.py` liefert einen Kurbelwinkel von $\psi = 38.9^\circ$ und Übertragungswinkel von $84^\circ$ und $86^\circ$, nahe am Ideal von $90^\circ$. Die Empfindlichkeit ist $\partial q_3/\partial\psi = -1.12$: Das Knie dreht sich um $1.12^\circ$ pro Grad Kurbel. ## Selbsttest {#check-yourself} 1. Warum lässt sich der Hüftwinkel vor und getrennt von Oberschenkel und Knie lösen? 2. Was bedeutet $\lvert\cos q_3\rvert > 1$ physikalisch? 3. Welches Gelenk bewegt den Fuß in der Standpose hauptsächlich nach vorne, und welches hauptsächlich senkrecht? 4. Warum sind die Übertragungswinkel wichtig, selbst wenn $\det\mathbf{J}_{\text{plane}}$ weit von null entfernt ist?
Antworten 1. Die Hüftachse ist die $x$-Achse, und $q_2$, $q_3$ ändern den Abstand des Fußes von ihr nie. Daher hängt $r_y^2 + r_z^2$ nur von der ebenen Tiefe $v$ und dem festen Versatz $d$ ab. 2. Das Ziel ist weiter entfernt als $l_1 + l_2$ oder näher als $\lvert l_1 - l_2\rvert$, also existiert kein Dreieck. 3. Der Oberschenkel bewegt ihn nach vorne und hinten ($J_{11} = -0.170$, $J_{21} = 0$). Nur die Kniespalte hat eine senkrechte Komponente. 4. Sie beschreiben das *Antriebs*-Koppelgetriebe, nicht das Bein. Nahe $0^\circ$ oder $180^\circ$ verliert der Knieservo Hebelwirkung und die Abbildung Kurbel–Knie wird schlecht konditioniert, egal was die Bein-Jacobi-Matrix sagt.
## Weiterführende Literatur {#further-reading} - K. M. Lynch und F. C. Park, *Modern Robotics*, Cambridge University Press, 2017, Kap. 4–6 (Vorwärtskinematik, Geschwindigkeitskinematik, inverse Kinematik). - B. Siciliano et al., *Robotics: Modelling, Planning and Control*, Springer, 2009, Kap. 2–3. - R. L. Norton, *Design of Machinery*, McGraw-Hill, Kap. 4 (Lageanalyse von Viergelenken und Übertragungswinkel). - [Kinematik und Gaits](../software/kinematics-and-gaits.md) in diesem Wiki. --- # Laufen mit Beinen {#legged-locomotion} Wie ein vierbeiniger Roboter in Bewegung aufrecht bleibt: Gaits und ihr Timing, das Stützpolygon, statische und dynamische Stabilität sowie die Fußplatzierungsregel, die der Trot-Generator von Strido verwendet. ::: tip In Strido Der skriptbasierte Gait ist `TrotGait` in `packages/strido-core/src/strido/gait.py`, gemeinsam genutzt von MuJoCo, Gazebo und dem realen Roboter (über `ros2/strido_control/strido_control/gait_node.py`). Die gelernte Policy (`packages/strido-sim/`) erhält einen Takt mit derselben Periode von $0.4\,\mathrm{s}$ (`GAIT_PERIOD_S` in `packages/strido-core/src/strido/policy.py`). Die praktische Anwendung steht in [Kinematik und Gaits](../software/kinematics-and-gaits.md). ::: ## Gaits als Timing-Muster {#gaits-as-timing-patterns} Ein **Gait** ist ein periodisches Muster von Fußkontakten. Jedes Bein $i$ durchläuft einen **Zyklus** der Periode $T$ und wird durch eine Phase $\phi_i \in [0, 1)$ beschrieben: $$ \phi_i(t) = \left( \frac{t}{T} + \delta_i \right) \bmod 1 $$ wobei $\delta_i$ der **Phasenversatz** dieses Beins ist. Das Bein ist in der **Standphase** (Fuß am Boden, schiebend), solange $\phi_i < \beta$, andernfalls in der **Schwungphase** (Fuß in der Luft, zurückkehrend). Der **Tastgrad** (Duty Factor) $\beta$ ist der Anteil des Zyklus in der Standphase: $$ \beta = \frac{T_\mathrm{stance}}{T}, \qquad T_\mathrm{stance} = \beta T, \qquad T_\mathrm{swing} = (1-\beta) T $$ Gaits unterscheiden sich nur in $\beta$ und den Versätzen $\delta_i$: | Gait | Tastgrad $\beta$ | Versätze (FL, FR, RL, RR) | Füße am Boden | |---|---|---|---| | Schritt (Kriechgang) | $\ge 0.75$ | $0, \tfrac12, \tfrac34, \tfrac14$ | immer $\ge 3$ | | Trot | $\approx 0.5$ | $0, \tfrac12, \tfrac12, 0$ | 2 (ein diagonales Paar) | | Passgang | $\approx 0.5$ | $0, \tfrac12, 0, \tfrac12$ | 2 (ein seitliches Paar) | | Sprunggang | $\approx 0.5$ | $0, 0, \tfrac12, \tfrac12$ | 2 (vorderes oder hinteres Paar) | Mit $\beta \ge 0.75$ ist immer nur ein Bein in der Luft, daher kann der Schritt **statisch stabil** sein. Mit $\beta = 0.5$ sind immer zwei Beine in der Luft; der Trot beruht auf **dynamischer Stabilität**: Eingefroren würde der Körper kippen, doch jedes Paar landet, bevor er weit fällt. ## Schwerpunkt und Stützpolygon {#centre-of-mass-and-the-support-polygon} Der **Schwerpunkt** (CoM) von Körpern mit Massen $m_k$ an Positionen $\mathbf{p}_k$ ist $$ \mathbf{p}_\mathrm{CoM} = \frac{\sum_k m_k \mathbf{p}_k}{\sum_k m_k} $$ Das **Stützpolygon** ist die konvexe Hülle der auf den Boden projizierten Kontaktpunkte. Ein stillstehender Roboter (oder einer, der sich so langsam bewegt, dass die Trägheit vernachlässigbar ist) ist statisch stabil, wenn die Bodenprojektion des CoM innerhalb dieses Polygons liegt: Die Schwerkraft erzeugt dann um keine Polygonkante ein resultierendes Kippmoment. Die **statische Stabilitätsreserve** ist der kürzeste Abstand vom projizierten CoM zum Rand des Polygons: $$ S = \min_{e \in \text{edges}} d(\mathbf{p}_\mathrm{CoM}^{xy}, e) $$ $S > 0$ bedeutet stabil; ein größeres $S$ toleriert stärkere Stöße und Modellierungsfehler. Im Trot entartet das Stütz-„Polygon“ zur Strecke zwischen den beiden Standfüßen, daher ist fast immer $S \le 0$: Statische Stabilität ist unmöglich, und der Gait muss dynamisch sein. ## Über die Statik hinaus: ZMP und Capture Point {#beyond-statics-zmp-and-the-capture-point} Beschleunigt der Körper, kommen Trägheitskräfte zur Schwerkraft hinzu. Der **Zero-Moment-Point** (ZMP) ist der Punkt am Boden, an dem die horizontalen Momente aus Schwerkraft und Trägheit verschwinden. Für eine Punktmasse in Höhe $h$ mit horizontaler Beschleunigung $\ddot{\mathbf{x}}$ (das Modell des *linearen inversen Pendels*, konstante Höhe): $$ \mathbf{p}_\mathrm{ZMP} = \mathbf{x}_\mathrm{CoM} - \frac{h}{g}\,\ddot{\mathbf{x}}_\mathrm{CoM} $$ Die Kontaktkräfte können nur drücken, daher muss der ZMP innerhalb des Stützpolygons bleiben; verlangt die Planung einen ZMP außerhalb, rollt oder hebt ein Fuß ab und der Roboter kippt. ZMP-Planung ist das klassische Werkzeug für gehende Humanoide. Dasselbe Pendel liefert den **Capture Point** (instantaner Capture Point, divergente Bewegungskomponente). Seine Dynamik $\ddot{x} = \omega^2 (x - p)$ mit $\omega = \sqrt{g/h}$ hat einen instabilen Modus, und der Punkt $$ \boldsymbol{\xi} = \mathbf{x}_\mathrm{CoM} + \frac{\dot{\mathbf{x}}_\mathrm{CoM}}{\omega} $$ ist die Stelle, an der ein Fuß aufgesetzt werden muss, damit der Körper darüber zur Ruhe kommt. Intuition: Je schneller man sich bewegt, desto weiter vorne muss man auftreten, um anzuhalten. **Rechenbeispiel.** Die Standard-Körperhöhe von Strido ist $h = 0.17\,\mathrm{m}$ (Hüftachse über den Füßen, `GaitConfig.body_height`). Dann $$ \omega = \sqrt{\frac{9.81}{0.17}} \approx 7.6\,\mathrm{s^{-1}}, \qquad \frac{1}{\omega} \approx 0.13\,\mathrm{s} $$ Beim maximalen Vorwärtsbefehl $v = 0.30\,\mathrm{m/s}$ liegt der Capture Point etwa $0.30 \times 0.13 \approx 0.04\,\mathrm{m}$ vor dem CoM. Die Zeitkonstante des Pendels ($0.13\,\mathrm{s}$) ist vergleichbar mit der Standzeit ($0.2\,\mathrm{s}$, siehe unten), weshalb der Gait weiter Schritte machen muss: Ein eingefrorener Trot würde binnen Sekundenbruchteilen kippen. ## Fußplatzierung nach Raibert {#raibert-style-foot-placement} Marc Raiberts hüpfende und laufende Maschinen zerlegten die Regelung in drei Teile: Sprunghöhe, Körperlage und **Vorwärtsgeschwindigkeit über die Fußplatzierung**. Die Idee: Während der Standphase bewegt sich der Körper um die Strecke $v\,T_\mathrm{stance}$ über den Fuß. Landet der Fuß in der Mitte dieses Wegs, passiert der Körper ihn symmetrisch und die Geschwindigkeit bleibt erhalten (der *neutrale Punkt*): $$ x_\mathrm{f} = \frac{v\,T_\mathrm{stance}}{2} + k\,(v - v_\mathrm{des}) $$ Der Rückführterm $k(v - v_\mathrm{des})$ setzt den Fuß weiter nach vorne, um zu bremsen, und weiter nach hinten, um zu beschleunigen. Er ist eine verkappte Capture-Point-Regel. ## So funktioniert der Trot-Generator von Strido {#how-strido-s-trot-generator-works} `TrotGait` ist eine bewusst einfache, deterministische, ungeregelte (Open-Loop-)Version des Obigen (kein Rückführterm, $k = 0$). Seine Standardwerte in `GaitConfig`: | Parameter | Wert | Bedeutung | |---|---|---| | `period` | $T = 0.40\,\mathrm{s}$ | voller Zyklus | | `duty` | $\beta = 0.5$ | Trot: Stand- und Schwungphase gleich lang | | `step_height` | $h_\mathrm{s} = 0.035\,\mathrm{m}$ | Scheitel der Schwungphase | | `body_height` | $0.17\,\mathrm{m}$ | Hüftachse über den Füßen | | `max_linear` | $\lvert v_x \rvert \le 0.30$, $\lvert v_y \rvert \le 0.15\,\mathrm{m/s}$ | Befehlsbegrenzung | | `max_yaw_rate` | $\lvert \omega_z \rvert \le 1.0\,\mathrm{rad/s}$ | Befehlsbegrenzung | `PHASE_OFFSET` gibt FL und RR $\delta = 0$ sowie FR und RL $\delta = \tfrac12$: Die Diagonalen wechseln sich ab. **Geschwindigkeit je Fuß.** Für einen Befehl $(v_x, v_y, \omega_z)$ und die Nennposition eines Fußes $(p_x, p_y)$ im Körperkoordinatensystem bewegt sich der Körper mit der Starrkörpergeschwindigkeit $\mathbf{v} + \boldsymbol{\omega} \times \mathbf{p}$ über diesen Fuß, daher bewegt sich der Standfuß relativ zum Körper mit $-\mathbf{v}_i$: $$ \mathbf{v}_i = \begin{pmatrix} v_x - \omega_z p_y \\ v_y + \omega_z p_x \\ 0 \end{pmatrix}, \qquad \mathbf{s}_i = \mathbf{v}_i\, \beta T $$ wobei $\mathbf{s}_i$ die Schrittlänge über eine Standphase ist. **Standphase.** Mit dem normierten Standfortschritt $s = \phi/\beta \in [0, 1)$ gleitet der Fuß von einer halben Schrittlänge vorne zu einer halben Schrittlänge hinten: $$ \mathbf{p}_i = \mathbf{p}_i^\mathrm{nom} + \mathbf{s}_i \left(\tfrac12 - s\right) $$ **Schwungphase.** Mit $s = (\phi - \beta)/(1-\beta)$ kehrt der Fuß zurück und hebt auf einer Halbsinuskurve ab: $$ \mathbf{p}_i = \mathbf{p}_i^\mathrm{nom} + \mathbf{s}_i \left(s - \tfrac12\right) + \begin{pmatrix} 0 \\ 0 \\ h_\mathrm{s} \sin(\pi s) \end{pmatrix} $$ Jeder Fuß landet also bei $+\mathbf{s}_i/2$: genau Raiberts neutraler Punkt $v T_\mathrm{stance}/2$. Die Fußziele werden dann per inverser Kinematik in 12 Gelenkwinkel umgerechnet (siehe [Kinematik](kinematics.md)) und auf die Gelenk- und Kniekurbelgrenzen begrenzt (`clamp_leg`). Bei Nullbefehl bleiben die Füße in ihrer Nennstellung. **Rechenbeispiel.** Vorwärtsbefehl $v_x = 0.30\,\mathrm{m/s}$: $$ T_\mathrm{stance} = 0.5 \times 0.40 = 0.20\,\mathrm{s}, \qquad s_x = 0.30 \times 0.20 = 0.06\,\mathrm{m} $$ Jeder Fuß bewegt sich von $+30\,\mathrm{mm}$ bis $-30\,\mathrm{mm}$ um seine Nennposition und schwingt dann in $0.20\,\mathrm{s}$ zurück, mit einem Scheitel $35\,\mathrm{mm}$ über dem Boden. Seine Schwunggeschwindigkeit relativ zum Körper beträgt im Mittel $0.06/0.20 = 0.30\,\mathrm{m/s}$ und vertikal maximal $\tfrac{\pi}{2} \times 0.035 / 0.10 \approx 0.55\,\mathrm{m/s}$. Für eine reine Drehung, $\omega_z = 1.0\,\mathrm{rad/s}$: Der vordere linke Fuß sitzt bei $p_x \approx 0.120\,\mathrm{m}$, $p_y \approx 0.039 + 0.038 = 0.077\,\mathrm{m}$ (Hüft- und Oberschenkelversatz aus `packages/strido-core/src/strido/geometry.py`), also $\mathbf{v} = (-0.077, 0.120)\,\mathrm{m/s}$, und die Schrittlänge ist $(-15, 24)\,\mathrm{mm}$: Die Füße bewegen sich entlang eines Kreises um die Körpermitte. ```mermaid gantt dateFormat x axisFormat %L ms title Trot-Timing (T = 400 ms, Tastgrad 0,5) section FL + RR Standphase :0, 200 Schwungphase :200, 400 section FR + RL Schwungphase :0, 200 Standphase :200, 400 ``` **Grenzen.** Als ungeregelter Generator reagiert er nicht auf Stöße, Rutschen oder Neigung: Nichts setzt den Fuß weiter nach vorne, wenn der Körper zu schnell ist. Diese Lücke füllt die gelernte Policy – sie sieht die IMU und kann Rückführung lernen (siehe [Reinforcement Learning](reinforcement-learning.md)). ## Selbsttest {#check-yourself} 1. Ein Gait hat $\beta = 0.8$. Wie viele Füße sind zu jedem Zeitpunkt am Boden, und kann sie statisch stabil sein?
Antwort Jedes Bein ist 20 % des Zyklus in der Luft; mit versetzten Phasen schwingt immer nur ein Bein, daher sind mindestens drei Füße am Boden. Ja, wenn der CoM innerhalb des Stützdreiecks bleibt.
2. Warum ist die statische Stabilitätsreserve eines Trots fast immer nicht positiv?
Antwort Nur zwei diagonale Füße stützen den Körper, daher ist das Stützpolygon eine Strecke; die CoM-Projektion liegt nur zufällig darauf, nie echt innerhalb.
3. Wie groß ist in `TrotGait` die Schrittlänge bei $v_x = 0.15\,\mathrm{m/s}$, und wo landet der Fuß?
Antwort $s = 0.15 \times 0.20 = 0.03\,\mathrm{m}$; der Fuß landet $15\,\mathrm{mm}$ vor der Nennposition.
4. Was bewirkt eine Erhöhung von `body_height` bei der Capture-Point-Zeitkonstante?
Antwort $1/\omega = \sqrt{h/g}$ wächst, der Körper kippt also langsamer, aber der Capture Point liegt bei gleicher Geschwindigkeit weiter vorne.
5. Welcher Raibert-Term fehlt im Trot von Strido, und was bedeutet das?
Antwort Der Geschwindigkeits-Rückführterm $k(v - v_\mathrm{des})$. Der Gait kann Geschwindigkeitsfehler oder Störungen nicht korrigieren.
## Weiterführende Literatur {#further-reading} - M. H. Raibert, *Legged Robots That Balance*, MIT Press, 1986. - B. Siciliano und O. Khatib (Hrsg.), *Springer Handbook of Robotics*, 2. Aufl., 2016 — Kapitel über Laufroboter und Gehen. - J. Pratt, J. Carff, S. Drakunov und A. Goswami, „Capture Point: A Step toward Humanoid Push Recovery“, *IEEE-RAS Humanoids*, 2006. - M. Vukobratović und B. Borovac, „Zero-Moment Point — Thirty Five Years of Its Life“, *International Journal of Humanoid Robotics*, 2004. - R. B. McGhee und A. A. Frank, „On the stability properties of quadruped creeping gaits“, *Mathematical Biosciences*, 1968. --- # Reinforcement Learning für die Fortbewegung {#reinforcement-learning-for-locomotion} Wie sich ein Lauf-Controller in der Simulation durch Versuch und Irrtum lernen lässt: Markov-Entscheidungsprozesse, Returns und Value Functions, das Policy-Gradient-Theorem, GAE, PPO sowie die genaue Observation, Action und Reward für Strido, dazu, wie Domain Randomization die Sim-to-Real-Lücke verkleinert. ::: tip In Strido Die Umgebung ist `StridoEnv` in `packages/strido-sim/src/strido_sim/rl/env.py` (Gymnasium + MuJoCo); das Training ist `rl/train.py` (stable-baselines3 PPO auf der CPU). Gemeinsame Konstanten (`CONTROL_DT`, `ACTION_SCALE`, `COMMAND_RANGES`) liegen in `packages/strido-core/src/strido/policy.py`, und der Roboter führt das exportierte Netz in `ros2/strido_control/strido_control/policy_node.py` aus. Arbeitsablauf: [Simulation und RL](../software/simulation-and-rl.md) und [docs/simulation.md](../../simulation.md). ::: ## Der Markov-Entscheidungsprozess {#the-markov-decision-process} Ein MDP ist ein Tupel $(\mathcal{S}, \mathcal{A}, P, r, \gamma)$: Zustände, Actions, Übergangswahrscheinlichkeiten $P(s' \mid s, a)$, Reward $r(s, a)$ und Diskontfaktor $\gamma \in [0, 1)$. In jedem Schritt beobachtet der Agent $s_t$, zieht $a_t \sim \pi_\theta(a \mid s_t)$ aus einer **Policy** mit Parametern $\theta$ (einem neuronalen Netz), und die Umgebung liefert $r_t$ und $s_{t+1}$. *Markov* bedeutet, dass $s_{t+1}$ nur von $(s_t, a_t)$ abhängt, nicht von der früheren Geschichte. Ein realer Roboter sieht nur einen Teil des Zustands (ein POMDP); in der Praxis fügen wir genug Geschichte hinzu (hier die vorherige Action und einen Gait-Takt), damit die Observation nahezu markovsch wird. ## Returns und Diskontierung {#returns-and-discounting} Der **Return** ab Zeitpunkt $t$ ist die diskontierte Summe künftiger Rewards: $$ G_t = \sum_{k=0}^{\infty} \gamma^k\, r_{t+k} $$ Die Diskontierung hält die Summe endlich und drückt eine Präferenz für früheren Reward aus. Der effektive Horizont beträgt etwa $1/(1-\gamma)$ Schritte. **Rechenbeispiel:** Strido trainiert mit $\gamma = 0.99$ (`train.py`) bei einer Policy-Rate von $50\,\mathrm{Hz}$ ($\Delta t = 0.02\,\mathrm{s}$), der Horizont beträgt also etwa $100$ Schritte $= 2\,\mathrm{s}$, d. h. fünf Gangzyklen zu $0.4\,\mathrm{s}$: lang genug, um Nicht-Umfallen zu bewerten, kurz genug, um schnell zu lernen. Das Ziel ist der erwartete Return $J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta}[G_0]$ über Trajektorien $\tau$. ## Value Functions {#value-functions} $$ V^\pi(s) = \mathbb{E}_\pi[G_t \mid s_t = s], \qquad Q^\pi(s, a) = \mathbb{E}_\pi[G_t \mid s_t = s, a_t = a] $$ Sie erfüllen die **Bellman-Gleichung** $$ V^\pi(s) = \mathbb{E}_{a \sim \pi,\, s' \sim P}\left[ r(s, a) + \gamma V^\pi(s') \right] $$ Der **Advantage** $A^\pi(s, a) = Q^\pi(s, a) - V^\pi(s)$ misst, um wie viel besser die Action $a$ als der Durchschnitt der Policy im Zustand $s$ ist. ## Das Policy-Gradient-Theorem {#the-policy-gradient-theorem} Wir wollen $\nabla_\theta J$, ohne durch die (unbekannte, nicht differenzierbare) Physik zu differenzieren. Der Likelihood-Ratio-Trick liefert $$ \nabla_\theta J(\theta) = \mathbb{E}_{\pi_\theta}\left[ \sum_t \nabla_\theta \log \pi_\theta(a_t \mid s_t)\, A^{\pi}(s_t, a_t) \right] $$ In Worten: Erhöhe die Log-Wahrscheinlichkeit von Actions, die sich als besser als der Durchschnitt erwiesen haben, und senke sie für schlechtere. Benötigt werden nur Stichproben aus dem Simulator und der Gradient der eigenen Log-Wahrscheinlichkeit des Netzes. Die Verwendung des Advantage (statt $G_t$) zieht eine Baseline $V(s)$ ab, was den Gradienten erwartungstreu lässt, aber seine Varianz stark verringert. ## Generalised Advantage Estimation (GAE) {#generalised-advantage-estimation-gae} Der Advantage wird aus einem gelernten Critic $V_\phi$ geschätzt. Der einstufige **TD-Fehler** ist $$ \delta_t = r_t + \gamma V_\phi(s_{t+1}) - V_\phi(s_t) $$ GAE bildet eine exponentiell gewichtete Summe davon: $$ \hat{A}_t = \sum_{l=0}^{\infty} (\gamma \lambda)^l\, \delta_{t+l} $$ $\lambda = 0$ ergibt die varianzarme, aber verzerrte einstufige Schätzung; $\lambda = 1$ ergibt den erwartungstreuen, aber varianzreichen Monte-Carlo-Return minus $V$. Strido verwendet $\lambda = 0.95$ (`gae_lambda` in `train.py`). Bei Abbruch (einem Sturz) ist der Bootstrap $V_\phi(s_{t+1})$ null; bei Kürzung durch das Zeitlimit bleibt er erhalten, da der Roboter hätte weitermachen können. ## PPO: Proximal Policy Optimisation {#ppo-proximal-policy-optimisation} Der einfache Policy Gradient macht einen Schritt pro Batch, und ein zu großer Schritt kann die Policy ruinieren. PPO verwendet jeden Batch für mehrere Epochen wieder und verhindert dabei, dass sich die neue Policy weit von derjenigen entfernt, die die Daten gesammelt hat. Mit dem Wahrscheinlichkeitsverhältnis $$ \rho_t(\theta) = \frac{\pi_\theta(a_t \mid s_t)}{\pi_{\theta_\mathrm{old}}(a_t \mid s_t)} $$ lautet das **geclippte Surrogat-Ziel** $$ L^\mathrm{CLIP}(\theta) = \mathbb{E}_t\left[ \min\left( \rho_t \hat{A}_t,\; \operatorname{clip}(\rho_t, 1 - \epsilon, 1 + \epsilon)\, \hat{A}_t \right) \right] $$ Für eine gute Action ($\hat{A} > 0$) endet der Gewinn, sobald $\rho > 1 + \epsilon$; für eine schlechte ($\hat{A} < 0$), sobald $\rho < 1 - \epsilon$. Das $\min$ macht es zu einer pessimistischen Schranke, sodass kein Anreiz besteht, sich weiter zu bewegen. Der vollständige Verlust ergänzt einen Regressionsterm für den Critic und optional einen Entropiebonus, der belohnt, die Policy zufällig genug für die Exploration zu halten: $$ L(\theta, \phi) = -L^\mathrm{CLIP}(\theta) + c_1\, \mathbb{E}_t\left[ \left( V_\phi(s_t) - \hat{G}_t \right)^2 \right] - c_2\, \mathbb{E}_t\left[ \mathcal{H}\left( \pi_\theta(\cdot \mid s_t) \right) \right] $$ Für kontinuierliche Actions ist die Policy eine diagonale Gaußverteilung $\pi_\theta(a \mid s) = \mathcal{N}(\mu_\theta(s), \operatorname{diag}(\boldsymbol{\sigma}^2))$; im Einsatz wird der Mittelwert $\mu_\theta(s)$ verwendet. **Einstellungen von Strido** (`train.py`): $\epsilon = 0.2$, $\gamma = 0.99$, $\lambda = 0.95$, Lernrate $3 \times 10^{-4}$, $1024$ Schritte pro Umgebung pro Rollout, Minibatch $2048$, 5 Epochen pro Rollout, $c_2 = 0$ (`ent_coef=0.0`: Exploration kommt nur aus der eigenen Streuung der Gaußverteilung, `log_std_init=-1.0`), standardmäßig insgesamt $2 \times 10^7$ Schritte. Observations und Rewards werden mit laufenden Statistiken normiert (`VecNormalize`, Observations bei $\pm 10$ begrenzt); Mittelwert und Varianz des Normierers werden mit den Gewichten exportiert, damit der Roboter dieselbe Skalierung anwendet. **Rechenbeispiel.** Angenommen, eine Action hatte $\hat{A}_t = 0.5$ und nach einem Update $\rho_t = 1.35$. Ungeclippt wäre der Term $0.675$; geclippt ist er $1.2 \times 0.5 = 0.6$, und der Gradient durch diese Stichprobe ist null, also hört PPO auf, die Wahrscheinlichkeit dieser Action nach oben zu drücken. ## Die Strido-Umgebung {#the-strido-environment} **Timing.** Policy mit $50\,\mathrm{Hz}$ (`CONTROL_DT = 0.02`), Physik mit $500\,\mathrm{Hz}$ (10 Teilschritte). Episoden dauern höchstens $1000$ Schritte ($20\,\mathrm{s}$). Die Servos werden als MJCF-Positionsaktuatoren mit einer Drehmomentgrenze von $3.43\,\mathrm{N\,m}$ modelliert (Blockiermoment des SPT5435LV bei $6\,\mathrm{V}$). **Observation** ($23$ Werte, `OBSERVATION_SIZE`): $$ \mathbf{o}_t = \left[ \boldsymbol{\omega}_b,\; \mathbf{g}_b,\; \mathbf{c},\; \mathbf{a}_{t-1},\; \sin\varphi_t,\; \cos\varphi_t \right] \in \mathbb{R}^{3+3+3+12+2} $$ - $\boldsymbol{\omega}_b$: Winkelgeschwindigkeit des Körpers vom IMU-Gyroskop; - $\mathbf{g}_b = \mathbf{R}^\top (0, 0, -1)^\top$: die Richtung der Schwerkraft als Einheitsvektor im Basis-Frame, aus der IMU-Quaternion (kodiert Rollen und Nicken, nicht Gieren); - $\mathbf{c} = (v_x, v_y, \omega_z)$: das Geschwindigkeitskommando, pro Episode gezogen aus $v_x \in [-0.15, 0.30]\,\mathrm{m/s}$, $v_y \in [-0.10, 0.10]\,\mathrm{m/s}$, $\omega_z \in [-0.6, 0.6]\,\mathrm{rad/s}$, und mit Wahrscheinlichkeit $0.2$ null; - $\mathbf{a}_{t-1}$: die vorherige Action; - ein Gait-Takt $\varphi_t = 2\pi t / T$ mit $T = 0.4\,\mathrm{s}$ (`GAIT_PERIOD_S`), passend zum geskripteten Trot. Jede Eingabe ist auf dem realen Roboter aus `/imu/data` und `/cmd_vel` verfügbar; es gibt keine Basisgeschwindigkeit und keine Gelenkrückmeldung (die Servos haben keine). **Action.** $\mathbf{a}_t \in [-1, 1]^{12}$ sind Abweichungen von der Standpose $\mathbf{q}_0$: $$ \mathbf{q}^\mathrm{target}_t = \operatorname{clamp}\left( \operatorname{slew}\left( \mathbf{q}_0 + 0.3\, \mathbf{a}_t \right) \right) $$ `ACTION_SCALE` $= 0.3\,\mathrm{rad}$; `slew_limit` begrenzt die Gelenkgeschwindigkeit auf $6\,\mathrm{rad/s}$ (die Grenze der Firmware), und `clamp_targets` wendet die Gelenk- und Kniekurbelgrenzen in derselben Reihenfolge wie die Firmware an, sodass die Policy nie lernt, sich auf Bewegungen zu verlassen, die der Roboter verweigern würde. **Reward.** Mit der linearen Geschwindigkeit im Basis-Frame $\mathbf{v}_b$, der Winkelgeschwindigkeit $\boldsymbol{\omega}_b$, den Aktuatorkräften $\boldsymbol{\tau}$ und der Basishöhe $z$: $$ \begin{aligned} r_t ={}& 1.0\, \exp\left( -\frac{\lVert \mathbf{v}_b^{xy} - \mathbf{c}^{xy} \rVert^2}{0.01} \right) + 0.8\, \exp\left( -\frac{(\omega_{b,z} - c_{\omega})^2}{0.05} \right) \\ &- 2.0\, v_{b,z}^2 - 0.05\, \lVert \boldsymbol{\omega}_b^{xy} \rVert^2 - 0.01\, \lVert \mathbf{a}_t - \mathbf{a}_{t-1} \rVert^2 - 0.002\, \lVert \boldsymbol{\tau} \rVert^2 - 2.0 \max(0,\, 0.15 - z) \end{aligned} $$ Die beiden Exponentialterme belohnen das Verfolgen des Kommandos (höchstens $1.8$ pro Schritt); die Strafterme verhindern Hüpfen, Wackeln, ruckartige Actions, hohes Drehmoment (Wärme, Akku) und Ducken unter $0.15\,\mathrm{m}$. Der Code multipliziert mit `CONTROL_DT * 50`, was bei $50\,\mathrm{Hz}$ gleich $1$ ist. **Abbruch.** Die Episode endet mit einer Strafe von $-2$, wenn die Basis unter $0.09\,\mathrm{m}$ sinkt oder sich der Körper so neigt, dass $-g_{b,z} < 0.6$ (etwa $53^\circ$ Rollen oder Nicken). **Rechenbeispiel.** Kommandiert $v_x = 0.20\,\mathrm{m/s}$, erreicht $0.15\,\mathrm{m/s}$: Der Tracking-Term ist $\exp(-0.05^2/0.01) = \exp(-0.25) \approx 0.78$. Die Breite $0.01$ bedeutet, dass Fehler um $0.1\,\mathrm{m/s}$ bereits den Großteil des Rewards kosten ($\exp(-1) \approx 0.37$). ## Domain Randomization und die Sim-to-Real-Lücke {#domain-randomisation-and-the-sim-to-real-gap} Eine Policy, die Eigenheiten des Simulators ausnutzt, versagt auf der Hardware: die **Sim-to-Real-Lücke**. Ursachen sind unter anderem nicht modellierte Servodynamik und Spiel, Reibung, Fehler bei Masse und Trägheit, Sensorrauschen und Latenz. **Domain Randomization** trainiert auf einer Verteilung von Simulatoren, sodass der reale Roboter hoffentlich nur eine weitere Stichprobe ist: $$ \max_\theta\; \mathbb{E}_{\xi \sim p(\xi)}\left[ J_\xi(\theta) \right] $$ wobei $\xi$ Physikparameter sind. `StridoEnv._randomise` zieht pro Episode: | Parameter | Bereich | |---|---| | Servosteifigkeit $k_p$ | $\times\, U(0.85, 1.15)$ | | Basismasse | $\times\, U(0.90, 1.15)$ | | Boden- und Fußreibung | $\times\, U(0.6, 1.2)$ | | Gyroskoprauschen | $\mathcal{N}(0, 0.05^2)$ pro Schritt | | Rauschen des Schwerkraftvektors | $\mathcal{N}(0, 0.02^2)$ pro Schritt | | anfängliche Gelenkwinkel | $\mathbf{q}_0 + \mathcal{N}(0, 0.02^2)$ | Da die Policy aus einer einzelnen Observation nicht erkennen kann, in welchem $\xi$ sie sich befindet, lernt sie ein Verhalten, das über alle hinweg robust ist. Weitere Mittel gegen die Lücke (hier nicht alle verwendet): an gemessene Servoantworten angepasste Aktuatormodelle, Observation-Latenz, Stoßstörungen und Gelände-Curricula. ## Prüfen Sie sich selbst {#check-yourself} 1. Wie groß ist der effektive Horizont in Sekunden für $\gamma = 0.99$ bei $50\,\mathrm{Hz}$, und wie, wenn die Policy mit demselben $\gamma$ bei $100\,\mathrm{Hz}$ liefe?
Antwort Etwa $100$ Schritte $= 2\,\mathrm{s}$; bei $100\,\mathrm{Hz}$ halbiert er sich auf $1\,\mathrm{s}$, daher sollte $\gamma$ auf etwa $0.995$ steigen, um denselben Horizont zu behalten.
2. Warum verzerrt das Abziehen von $V(s)$ den Policy Gradient nicht?
Antwort $\mathbb{E}_{a \sim \pi}[\nabla_\theta \log \pi_\theta(a \mid s)] = \nabla_\theta \sum_a \pi_\theta(a \mid s) = \nabla_\theta 1 = 0$, daher hat jede nur vom Zustand abhängige Baseline einen erwarteten Beitrag von null.
3. Bei $\epsilon = 0.2$ und $\hat{A}_t < 0$: Für welche $\rho_t$ liefert der PPO-Term keinen Gradienten mehr?
Antwort Für $\rho_t < 0.8$: Die Wahrscheinlichkeit der Action wurde bereits genug verringert.
4. Warum enthält die Observation die Schwerkraftrichtung statt Euler-Winkeln einschließlich Gieren?
Antwort Gehen hängt nicht von der Blickrichtung ab, und das Gieren aus einer IMU ohne Magnetometer driftet; der Schwerkraftvektor ist driftfrei und stetig.
5. Nennen Sie zwei Sim-to-Real-Effekte, die die Randomisierung von Strido nicht abdeckt.
Antwort Zum Beispiel Sensor- und Aktuatorlatenz, Servospiel oder Totzone, äußere Stöße, unebenes Gelände.
## Weiterführende Literatur {#further-reading} - R. S. Sutton und A. G. Barto, *Reinforcement Learning: An Introduction*, 2. Aufl., MIT Press, 2018. - J. Schulman, F. Wolski, P. Dhariwal, A. Radford und O. Klimov, „Proximal Policy Optimization Algorithms“, arXiv:1707.06347, 2017. - J. Schulman, P. Moritz, S. Levine, M. Jordan und P. Abbeel, „High-Dimensional Continuous Control Using Generalized Advantage Estimation“, *ICLR*, 2016. - J. Tobin et al., „Domain Randomization for Transferring Deep Neural Networks from Simulation to the Real World“, *IROS*, 2017. - J. Hwangbo et al., „Learning agile and dynamic motor skills for legged robots“, *Science Robotics*, 2019. --- # State Estimation {#state-estimation} Ein Roboter misst seinen Zustand nie direkt; er leitet Orientierung, Geschwindigkeit und Position aus verrauschten, mit Bias behafteten Sensoren ab. Diese Seite behandelt IMU-Modelle, Komplementär- und Mahony-Filter, das Kalman-Filter, Bein-Odometrie und LiDAR-SLAM sowie das, was Strido tatsächlich veröffentlicht. ::: tip In Strido Der XIAO ESP32-S3 liest eine LSM6DSOX-IMU aus und führt in seiner Regelschleife mit $200\,\mathrm{Hz}$ ein Mahony-Filter aus (`firmware/strido_esp32s3/src/main.cpp`, Periode `kControlPeriodUs = 5000` in `board_config.h`). `ros2/strido_control/strido_control/mcu_bridge.py` veröffentlicht es erneut als `/imu/data`; `gait_node.py` veröffentlicht `/odom` per Koppelnavigation; ein RPLIDAR C1 veröffentlicht `/scan` (siehe [docs/software.md](../../software.md) und [Sensoren](../hardware/sensors.md)). ::: ## IMU-Messmodelle {#imu-measurement-models} Eine inertiale Messeinheit enthält ein 3-Achsen-**Gyroskop** (Winkelgeschwindigkeit) und einen 3-Achsen-**Beschleunigungssensor** (spezifische Kraft). Beide werden im körperfesten Koordinatensystem des Sensors $\{b\}$ ausgedrückt. **Gyroskop.** $$ \tilde{\boldsymbol{\omega}} = \boldsymbol{\omega} + \mathbf{b}_g + \mathbf{n}_g $$ $\mathbf{b}_g$ ist ein langsam driftender **Bias** (temperaturabhängig), $\mathbf{n}_g$ weißes Rauschen. Die Integration des Gyroskops liefert die Orientierung, die Integration des Bias jedoch einen Winkelfehler, der linear mit der Zeit wächst: Ein Bias von nur $0.5^\circ/\mathrm{s}$ wird nach einer Minute zu $30^\circ$. **Beschleunigungssensor.** Er misst die Beschleunigung *minus* der Schwerkraft, in den Körper gedreht: $$ \tilde{\mathbf{a}} = \mathbf{R}^\top \left( \ddot{\mathbf{p}} - \mathbf{g} \right) + \mathbf{b}_a + \mathbf{n}_a, \qquad \mathbf{g} = (0, 0, -9.81)^\top\,\mathrm{m/s^2} $$ wobei $\mathbf{R}$ vom Körper- ins Weltkoordinatensystem dreht. Im Stillstand ($\ddot{\mathbf{p}} = 0$) liest er $\mathbf{R}^\top (0, 0, 9.81)^\top$: den „Oben“-Vektor in Körperkoordinaten. Das legt **Rollen und Nicken** ohne Drift fest, ist aber verrauscht und verfälscht, sobald der Körper beschleunigt (bei jedem Schritt). Über das **Gieren** sagt er nichts aus, da eine Drehung um die Schwerkraftachse den Schwerkraftvektor nicht verändert. Die beiden Sensoren ergänzen sich: Das Gyroskop ist glatt, driftet aber; der Beschleunigungssensor ist verrauscht, aber driftfrei. ## Das Komplementärfilter {#the-complementary-filter} Für einen Neigungswinkel $\theta$ wird das integrierte Gyroskop (vertrauenswürdig bei hohen Frequenzen) mit dem Winkel des Beschleunigungssensors (vertrauenswürdig bei niedrigen Frequenzen) gemischt: $$ \hat{\theta}_k = \alpha \left( \hat{\theta}_{k-1} + \tilde{\omega}_k\, \Delta t \right) + (1 - \alpha)\, \theta_{\mathrm{acc},k}, \qquad \theta_{\mathrm{acc}} = \operatorname{atan2}(\tilde{a}_y, \tilde{a}_z) $$ Im Frequenzbereich ist das ein Hochpass auf dem Gyroskop plus ein Tiefpass auf dem Beschleunigungssensor mit derselben Grenzfrequenz; die Übergangszeitkonstante ist $$ \tau = \frac{\alpha\, \Delta t}{1 - \alpha} $$ **Rechenbeispiel.** Bei $\Delta t = 5\,\mathrm{ms}$ von Strido ergibt die Wahl $\alpha = 0.98$ den Wert $\tau = 0.98 \times 0.005 / 0.02 \approx 0.25\,\mathrm{s}$: länger als die Standphase des Trots von $0.2\,\mathrm{s}$, sodass Schrittstöße größtenteils herausgefiltert werden, während die Gyroskopdrift innerhalb von etwa einer Sekunde korrigiert wird. ## Das Mahony-Filter (das, was die Firmware ausführt) {#the-mahony-filter-what-the-firmware-runs} Mahonys Filter ist ein Komplementärfilter auf der Rotationsgruppe und verwendet statt getrennter Winkel ein Quaternion $\hat{\mathbf{q}}$. Jeder Schritt: 1. Die Schwerkraftrichtung („oben“) aus der aktuellen Schätzung vorhersagen: $\hat{\mathbf{v}} = \hat{\mathbf{R}}^\top \mathbf{e}_z$. 2. Den Beschleunigungssensor normieren: $\bar{\mathbf{a}} = \tilde{\mathbf{a}} / \lVert \tilde{\mathbf{a}} \rVert$. 3. Der Fehler ist die Drehung, die nötig ist, um beide auszurichten: $$ \mathbf{e} = \bar{\mathbf{a}} \times \hat{\mathbf{v}} $$ 4. Das Gyroskop mit proportionaler und integraler Rückführung korrigieren (der Integralterm konvergiert gegen den negativen Gyroskop-Bias und hebt ihn auf): $$ \mathbf{b}_{k} = \mathbf{b}_{k-1} + K_i\, \mathbf{e}\, \Delta t, \qquad \boldsymbol{\omega}_\mathrm{c} = \tilde{\boldsymbol{\omega}} + K_p\, \mathbf{e} + \mathbf{b}_k $$ 5. Die Quaternion-Kinematik $\dot{\mathbf{q}} = \tfrac12\, \mathbf{q} \otimes (0, \boldsymbol{\omega}_\mathrm{c})$ integrieren und erneut normieren: $$ \hat{\mathbf{q}}_k = \frac{\hat{\mathbf{q}}_{k-1} + \tfrac12\, \hat{\mathbf{q}}_{k-1} \otimes (0, \boldsymbol{\omega}_\mathrm{c})\, \Delta t}{\lVert \cdot \rVert} $$ $K_p$ legt den Übergang fest (ungefähr $\tau \approx 1/K_p$); $K_i$ entfernt einen konstanten Gyroskop-Bias. Das Gieren ist ohne Magnetometer nicht beobachtbar und driftet daher. In der Firmware wird `Adafruit_Mahony` mit $1/\Delta t = 200\,\mathrm{Hz}$ gestartet und über `updateIMU` gespeist (nur Gyroskop und Beschleunigungssensor, kein Magnetometer). Vor dem Filtern werden die Platinenachsen auf das Basiskoordinatensystem umgelegt, da die IMU mit ihrer $x$-Achse nach links und ihrer $y$-Achse nach hinten montiert ist: $$ (\omega_x, \omega_y, \omega_z) = (-\tilde{\omega}_y, \tilde{\omega}_x, \tilde{\omega}_z), \qquad (a_x, a_y, a_z) = (-\tilde{a}_y, \tilde{a}_x, \tilde{a}_z) $$ Der Sensor ist auf $\pm 8\,g$, $\pm 1000^\circ/\mathrm{s}$ bei einer Ausgabedatenrate von $416\,\mathrm{Hz}$ konfiguriert. Das Repository behält die Standardverstärkungen der Bibliothek bei (Adafruit AHRS: $K_p = 0.5$, $K_i = 0$, d. h. keine Bias-Integration). ## Das Kalman-Filter {#the-kalman-filter} Das Kalman-Filter ist der optimale Schätzer für lineare Systeme mit gaußschem Rauschen. Zustand $\mathbf{x}$ mit Kovarianz $\mathbf{P}$, Modell $$ \mathbf{x}_k = \mathbf{F} \mathbf{x}_{k-1} + \mathbf{B} \mathbf{u}_k + \mathbf{w}_k, \quad \mathbf{w} \sim \mathcal{N}(0, \mathbf{Q}); \qquad \mathbf{z}_k = \mathbf{H} \mathbf{x}_k + \mathbf{v}_k, \quad \mathbf{v} \sim \mathcal{N}(0, \mathbf{R}_\mathrm{n}) $$ **Prädiktion** (Modell fortschreiben; die Unsicherheit wächst): $$ \hat{\mathbf{x}}_{k \mid k-1} = \mathbf{F} \hat{\mathbf{x}}_{k-1} + \mathbf{B} \mathbf{u}_k, \qquad \mathbf{P}_{k \mid k-1} = \mathbf{F} \mathbf{P}_{k-1} \mathbf{F}^\top + \mathbf{Q} $$ **Korrektur** (eine Messung fusionieren; die Unsicherheit schrumpft): $$ \mathbf{K}_k = \mathbf{P}_{k \mid k-1} \mathbf{H}^\top \left( \mathbf{H} \mathbf{P}_{k \mid k-1} \mathbf{H}^\top + \mathbf{R}_\mathrm{n} \right)^{-1} $$ $$ \hat{\mathbf{x}}_k = \hat{\mathbf{x}}_{k \mid k-1} + \mathbf{K}_k \left( \mathbf{z}_k - \mathbf{H} \hat{\mathbf{x}}_{k \mid k-1} \right), \qquad \mathbf{P}_k = (\mathbf{I} - \mathbf{K}_k \mathbf{H})\, \mathbf{P}_{k \mid k-1} $$ Die Verstärkung $\mathbf{K}$ gewichtet die Innovation $\mathbf{z} - \mathbf{H}\hat{\mathbf{x}}$ danach, wie sehr wir der Messung ($\mathbf{R}_\mathrm{n}$) gegenüber der Prädiktion ($\mathbf{P}$) vertrauen. Ein Neigungsfilter mit Zustand $(\theta, b_g)$, Gyroskop als Eingang und Beschleunigungswinkel als Messung konvergiert zu einem Komplementärfilter mit automatisch abgestimmtem $\alpha$ und Bias-Schätzung. Nichtlineare Systeme (Rotationen, Laufroboter) verwenden das **erweiterte** Kalman-Filter, das $\mathbf{F}$ und $\mathbf{H}$ um die aktuelle Schätzung linearisiert. ## Bein-Odometrie {#leg-odometry} Rutscht ein Standfuß nicht, ist seine Weltposition fest, sodass sich die Körpergeschwindigkeit aus den Gelenkgeschwindigkeiten des Beins über die Vorwärtskinematik ergibt (siehe [Kinematik](kinematics.md)): $$ \mathbf{v}_\mathrm{body} = -\left( \mathbf{J}(\mathbf{q})\, \dot{\mathbf{q}} + \boldsymbol{\omega} \times \mathbf{p}_\mathrm{foot} \right) $$ gemittelt über die Standfüße und für die Position integriert. Fehler entstehen durch Rutschen, Kontakterkennung und Kalibrierung, daher driftet sie; moderne Vierbeiner fusionieren sie in einem EKF mit der IMU. Die Hobby-Servos von Strido haben **keine Positionsrückmeldung**: `/joint_states` meldet die kommandierten Winkel nach der Begrenzung, keine gemessenen. Echte Bein-Odometrie ist daher nicht verfügbar, und `gait_node.py` macht etwas Einfacheres: Es integriert die *kommandierte* Körpergeschwindigkeit, $$ x_{k} = x_{k-1} + (v_x \cos\psi - v_y \sin\psi)\, \Delta t, \quad y_{k} = y_{k-1} + (v_x \sin\psi + v_y \cos\psi)\, \Delta t, \quad \psi_k = \psi_{k-1} + \omega_z \Delta t $$ ohne Rutschmodell. Erreicht der Roboter tatsächlich 80 % eines Kommandos von $0.30\,\mathrm{m/s}$, überschätzt `/odom` die Distanz um $0.06\,\mathrm{m}$ pro Sekunde. ## LiDAR-Scan-Matching und SLAM {#lidar-scan-matching-and-slam} Ein 2D-LiDAR liefert Entfernungen $r_j$ unter Winkeln $\theta_j$. **Scan-Matching** findet die starre Transformation $(\mathbf{R}, \mathbf{t})$, die einen neuen Scan am besten auf einen vorherigen Scan oder eine Karte ausrichtet, z. B. mit ICP (Iterative Closest Point): $$ (\mathbf{R}^\star, \mathbf{t}^\star) = \arg\min_{\mathbf{R}, \mathbf{t}} \sum_j \left\lVert \mathbf{R} \mathbf{p}_j + \mathbf{t} - \mathbf{m}_{c(j)} \right\rVert^2 $$ wobei $\mathbf{m}_{c(j)}$ der nächstgelegene Kartenpunkt zu $\mathbf{p}_j$ ist. Das Verketten von Matches ergibt LiDAR-Odometrie, die ebenfalls driftet. **SLAM** (simultane Lokalisierung und Kartierung) beseitigt die Drift, indem es bereits gesehene Orte wiedererkennt (*Loop Closure*) und eine Posengraph-Optimierung über alle Posen gleichzeitig löst. Rad-/Bein-Odometrie ist ein nützlicher Startwert für den Matcher – genau die Rolle, die der Code-Kommentar dem `/odom` von Strido zuweist („ein Startwert für SLAM“). ## Was Strido veröffentlicht {#what-strido-publishes} | Topic | Inhalt | Quelle | |---|---|---| | `/imu/data` (`sensor_msgs/Imu`, Frame `imu_link`, Achsen an `base_link` ausgerichtet) | Orientierungsquaternion aus dem Mahony-Filter, Winkelgeschwindigkeit in $\mathrm{rad/s}$, lineare Beschleunigung in $\mathrm{m/s^2}$ (inklusive Schwerkraft); wird nicht veröffentlicht, solange die IMU einen Fehler meldet | `mcu_bridge.py`, Zustandsstrom mit $100\,\mathrm{Hz}$ (`kStatePeriodMs = 10`) | | `/odom` + TF `odom` $\to$ `base_link` (`nav_msgs/Odometry`) | Koppelnavigation der kommandierten Geschwindigkeit | nur `gait_node.py` | | `/scan` (`sensor_msgs/LaserScan`, `lidar_link`) | RPLIDAR-C1-Entfernungen mit $10\,\mathrm{Hz}$ | `sllidar_ros2` | Die gelernte Policy verwendet nur `/imu/data`: das Gyroskop und die aus dem Quaternion abgeleitete Schwerkraftrichtung (siehe [Reinforcement Learning](reinforcement-learning.md)). ## Selbsttest {#check-yourself} 1. Warum kann ein Beschleunigungssensor Rollen und Nicken liefern, aber nicht Gieren?
Antwort Er misst die Schwerkraftrichtung im Körperkoordinatensystem; eine Drehung um die Hochachse ändert diese Richtung nicht.
2. Welches $\alpha$ ergibt bei $\Delta t = 5\,\mathrm{ms}$ eine Zeitkonstante des Komplementärfilters von $0.5\,\mathrm{s}$?
Antwort $\alpha/(1-\alpha) = 100$, so $\alpha = 100/101 \approx 0.990$.
3. Was schätzt die Integralverstärkung $K_i$ im Mahony-Filter, und was passiert bei $K_i = 0$?
Antwort Den Gyroskop-Bias. Bei $K_i = 0$ hinterlässt ein konstanter Bias einen kleinen bleibenden Roll-/Nickversatz von etwa $b_g/K_p$ und unkorrigierte Gierdrift.
4. Was passiert in der Kalman-Korrektur mit $\mathbf{K}$, wenn $\mathbf{R}_\mathrm{n} \to \infty$?
Antwort $\mathbf{K} \to 0$: Die Messung wird ignoriert und die Schätzung folgt der Prädiktion.
5. Warum kann Strido keine klassische Bein-Odometrie durchführen?
Antwort Seine Servos liefern keine Rückmeldung der Gelenkposition, daher sind die tatsächlichen $\mathbf{q}$ und $\dot{\mathbf{q}}$ unbekannt; nur Kommandos sind verfügbar.
## Weiterführende Literatur {#further-reading} - R. Mahony, T. Hamel und J.-M. Pflimlin, „Nonlinear Complementary Filters on the Special Orthogonal Group“, *IEEE Transactions on Automatic Control*, 2008. - S. Thrun, W. Burgard und D. Fox, *Probabilistic Robotics*, MIT Press, 2005. - J. Solà, „Quaternion kinematics for the error-state Kalman filter“, arXiv:1711.02508, 2017. - M. Bloesch et al., „State Estimation for Legged Robots — Consistent Fusion of Leg Kinematics and IMU“, *Robotics: Science and Systems*, 2012. - W. Hess, D. Kohler, H. Rapp und D. Andor, „Real-Time Loop Closure in 2D LIDAR SLAM“ (Cartographer), *IEEE ICRA*, 2016. --- # Statik und Dynamik {#statics-and-dynamics} Die Statik fragt, welche Gelenkmomente eine Last ruhig halten. Die Dynamik ergänzt die Momente, die Massen beschleunigen. Zusammen zeigen sie, ob ein Servo stark genug ist und wie stark jedes Teil belastet wird. Diese Seite leitet $\boldsymbol{\tau} = \mathbf{J}^\top\mathbf{F}$ aus der virtuellen Arbeit her, erklärt die Hebelwirkung des Strido-Knie-Koppelgetriebes und vergleicht das Moment, das der Roboter braucht, mit dem Moment, das seine Servos liefern können. ::: tip In Strido - **Servogrenzen:** SPT5435LV-180W, Blockiermoment $3.43\,\mathrm{N\,m}$ bei $6\,\mathrm{V}$ (`hardware/strength.yaml`), Leerlaufgeschwindigkeit $0.14\,\mathrm{s}/60^\circ$ ([Servos](../hardware/servos.md)). - **Masse:** $3.07\,\mathrm{kg}$ inklusive Akku und Kabelbaum; Massen pro Link in `ros2/strido_description/config/mass_report.yaml`. - **Koppelkräfte:** `packages/strido-verify/src/strido_verify/strength.py` durchfährt das Knie-Koppelgetriebe bei Blockiermoment. Die Ergebnisse stehen in `docs/verification/data/strength.json`, erklärt unter [Festigkeit](../making/strength.md). - **Simulation:** MuJoCo begrenzt jeden Aktuator auf $\pm 3.432\,\mathrm{N\,m}$ (`models/mujoco/strido.xml`). ::: ## Virtuelle Arbeit und $\boldsymbol{\tau} = \mathbf{J}^\top \mathbf{F}$ {#virtual-work-and-boldsymbol-tau-mathbf-j-top-mathbf-f} Angenommen, der Fuß drückt mit der Kraft $\mathbf{F}$ auf den Boden, und der Boden drückt mit $-\mathbf{F}$ zurück. Halten Sie das Bein still und stellen Sie sich eine winzige Gelenkbewegung $\delta\mathbf{q}$ vor. Der Fuß bewegt sich um $\delta\mathbf{p} = \mathbf{J}\,\delta\mathbf{q}$ (siehe [Kinematik](kinematics.md)). Im Gleichgewicht und ohne Reibung ist die von den Gelenken verrichtete Arbeit gleich der am Fuß abgegebenen Arbeit: $$ \boldsymbol{\tau}^\top \delta\mathbf{q} = \mathbf{F}^\top \delta\mathbf{p} = \mathbf{F}^\top \mathbf{J}\,\delta\mathbf{q} $$ Dies muss für jedes $\delta\mathbf{q}$ gelten, also: $$ \boldsymbol{\tau} = \mathbf{J}^\top \mathbf{F} $$ Zwei Folgerungen: - In einer **Singularität** verliert $\mathbf{J}$ an Rang. Manche Fußkräfte benötigen dann überhaupt kein Gelenkmoment: Ein gestrecktes Bein trägt eine Last entlang seiner Länge „auf den Knochen“. Gleichzeitig kann das Bein in der verlorenen Richtung nicht drücken. - Geschwindigkeitsübersetzung und Kraftübersetzung stehen im Gegensatz. Wo ein Gelenk den Fuß schnell bewegt (große Jacobi-Einträge), drückt es schwach, und umgekehrt. Dasselbe Argument gilt für jeden Mechanismus mit einem Eingang und einem Ausgang. Ändert sich der Ausgangswinkel um $\delta\theta_{\text{out}} = G\,\delta\theta_{\text{in}}$, dann ist das Ausgangsmoment $\tau_{\text{out}} = \tau_{\text{in}}/G$. ## Mechanischer Vorteil des Knieantriebs {#mechanical-advantage-of-the-knee-drive} Der Knieservo erreicht die Tibia über zwei Koppelgetriebe (siehe [Kinematik](kinematics.md)). Bei einer Koppel, die die Kraft $F$ entlang ihrer Länge trägt, wirkt nur der senkrechte Anteil von $F$ auf eine Kurbel mit Radius $r$: $$ \tau = F\,r\,\sin\alpha $$ Dabei ist $\alpha$ der Winkel zwischen Kurbel und Koppel. `strength.py` verkettet diese Regel durch den Antrieb: $$ F_{\text{short}} = \frac{\tau_{\text{servo}}}{r_{\text{arm}}\sin\alpha},\qquad \tau_{\text{crank}} = F_{\text{short}}\, r_{\text{crank,a}}\sin\alpha',\qquad F_{\text{long}} = \frac{\tau_{\text{crank}}}{r_{\text{crank,b}}\sin\beta},\qquad \tau_{\text{knee}} = F_{\text{long}}\, r_{\text{knee}}\sin\gamma $$ - **Parallelogramm.** Gegenüberliegende Seiten sind gleich ($r_{\text{arm}} = r_{\text{crank,a}} = 24.0\,\mathrm{mm}$), also $\alpha' = \alpha$ und $\tau_{\text{crank}} = \tau_{\text{servo}}$. Das Verhältnis ist $1{:}1$. Die Koppelkraft $F_{\text{short}}$ wächst jedoch mit $1/\sin\alpha$. - **Viergelenk.** Das Momentenverhältnis ist $$ \frac{\tau_{\text{knee}}}{\tau_{\text{crank}}} = \frac{r_{\text{knee}}\sin\gamma}{r_{\text{crank,b}}\sin\beta} $$ und es ändert sich mit der Pose. Nähert sich der Übertragungswinkel $\beta$ oder $\gamma$ $0$ oder $180^\circ$, werden die Kräfte sehr groß oder der Antrieb verliert jede Hebelwirkung. Deshalb verlangen die Gelenkgrenzen mindestens $25^\circ$ (`hardware/joint_limits.yaml`). Beim Durchfahren aller Posen innerhalb der Grenzen mit dem Knieservo bei Blockiermoment sind die ungünstigsten Fälle (`docs/verification/data/strength.json`) $211\,\mathrm{N}$ in der kurzen Koppel, $192\,\mathrm{N}$ in der langen Koppel und $3.07\,\mathrm{N\,m}$ am Knie. ## Dynamik: Trägheit und Newton–Euler {#dynamics-inertia-and-newton-euler} Bewegte Körper brauchen mehr Moment. Für einen einzelnen starren Körper lauten die **Newton–Euler**-Gleichungen: $$ \mathbf{F} = m\,\ddot{\mathbf{c}}, \qquad \boldsymbol{\tau}_c = \mathbf{I}_c\,\dot{\boldsymbol{\omega}} + \boldsymbol{\omega}\times\mathbf{I}_c\,\boldsymbol{\omega} $$ Dabei ist $\mathbf{c}$ der Schwerpunkt und $\mathbf{I}_c$ der $3\times 3$-Trägheitstensor um ihn. Für einen Link, der sich um eine feste Achse dreht, liefert der Satz von Steiner die Trägheit um die Achse, $I = I_c + m r_c^2$, mit $r_c$ als Abstand von der Achse zum Schwerpunkt. Dann gilt $\tau = I\ddot\theta$. Die Verkettung von Newton–Euler über alle Links ergibt die Standard-Manipulatorgleichung: $$ \mathbf{M}(\mathbf{q})\,\ddot{\mathbf{q}} + \mathbf{C}(\mathbf{q},\dot{\mathbf{q}})\,\dot{\mathbf{q}} + \mathbf{g}(\mathbf{q}) = \boldsymbol{\tau} + \mathbf{J}^\top\mathbf{F}_{\text{ext}} $$ Die Terme sind: die Massenmatrix $\mathbf{M}$, die Coriolis- und Zentrifugalterme $\mathbf{C}$, die Schwerkraft $\mathbf{g}$ und die Kontaktkräfte über $\mathbf{J}^\top$. MuJoCo löst genau dies alle $2\,\mathrm{ms}$. Jedes Strido-Gelenk erhält außerdem `armature="0.012"` ($\mathrm{kg\,m^2}$) auf seiner Diagonale von $\mathbf{M}$. Die Armature modelliert das Getriebe: Ein Rotor mit Trägheit $I_r$ hinter einer Untersetzung $N$ erscheint am Ausgang als $N^2 I_r$. ## Leistung und die Drehmoment-Drehzahl-Kennlinie {#power-and-the-torque-speed-line} Die mechanische Leistung ist $P = \tau\,\omega$. Ein DC-Servomotor folgt grob einer geraden Drehmoment-Drehzahl-Kennlinie. Er liefert das volle Blockiermoment $\tau_s$ bei Drehzahl null und kein Moment bei der Leerlaufgeschwindigkeit $\omega_0$: $$ \tau(\omega) \approx \tau_s\left(1 - \frac{\omega}{\omega_0}\right) \quad\Rightarrow\quad P(\omega) = \tau_s\,\omega\left(1-\frac{\omega}{\omega_0}\right),\qquad P_{\max} = \frac{\tau_s\,\omega_0}{4}\ \text{at}\ \omega = \tfrac{\omega_0}{2} $$ Für den SPT5435LV bei $6\,\mathrm{V}$: $$ \omega_0 = \frac{\pi/3}{0.14\,\mathrm{s}} = 7.48\,\mathrm{rad/s},\qquad P_{\max} \approx \frac{3.43 \cdot 7.48}{4} = 6.4\,\mathrm{W} $$ Die lineare Kennlinie ist ein Modell; das Datenblatt nennt nur die beiden Endpunkte. Ein Servo kann volles Moment oder volle Geschwindigkeit liefern, nie beides zugleich. Die Firmware begrenzt die Gelenkgeschwindigkeit auf $6\,\mathrm{rad/s}$ (`MAX_JOINT_SPEED_RAD_S` in `strido/policy.py`, gespiegelt von `safety.h`). Bei dieser Geschwindigkeit lässt die Kennlinie nur etwa $3.43\,(1 - 6/7.48) \approx 0.68\,\mathrm{N\,m}$ übrig. ## Rechenbeispiel: Halten der Standpose {#worked-example-holding-the-stand-pose} In der Standpose ($q_2 = 46.5^\circ$, $q_3 = -96.0^\circ$, Fuß direkt unter der Hüfte, $0.17\,\mathrm{m}$ tiefer) ist die ebene Jacobi-Matrix (siehe [Kinematik](kinematics.md)): $$ \mathbf{J}_{\text{plane}} = \begin{bmatrix} -0.170 & -0.0806 \\ 0 & -0.0943 \end{bmatrix}\mathrm{m/rad} $$ Mit vier Füßen am Boden trägt jeder Fuß ein Viertel des Gewichts: $$ F_v = \frac{3.07 \cdot 9.81}{4} = 7.53\,\mathrm{N} $$ Der Fuß drückt auf den Boden, also gilt mit obiger Konvention $\mathbf{F} = (0, -7.53)\,\mathrm{N}$ in $(u, v)$ (der Boden drückt mit $+7.53\,\mathrm{N}$ zurück). Die Gelenkmomente, die ihn halten, sind: $$ \boldsymbol{\tau} = \mathbf{J}^\top\mathbf{F} = \begin{bmatrix} -0.170 & 0 \\ -0.0806 & -0.0943 \end{bmatrix} \begin{bmatrix} 0 \\ -7.53 \end{bmatrix} = \begin{bmatrix} 0 \\ 0.71 \end{bmatrix}\mathrm{N\,m} $$ Der Oberschenkel braucht kein Moment, weil der Fuß direkt unter seinem Drehpunkt steht und die Last durch das Gelenk geht. Das Knie braucht $+0.71\,\mathrm{N\,m}$, passend zu MuJoCo, wo der Knieaktuator vorne links die Standpose mit $0.688\,\mathrm{N\,m}$ hält (siehe auch [Servos](../hardware/servos.md)). Über das Viergelenk gilt in dieser Pose $\partial q_3/\partial\psi = -1.12$. Die virtuelle Arbeit liefert dann das Moment des Knieservos: $$ \tau_\psi = \tau_{q_3}\,\frac{\partial q_3}{\partial \psi} = 0.71 \cdot 1.12 = 0.80\,\mathrm{N\,m} $$ Zur Gegenprobe ergibt die Hebelarmregel mit den Übertragungswinkeln $84^\circ$ und $86^\circ$ ein Verhältnis von $\frac{24.0\,\sin 86^\circ}{26.9\,\sin 84^\circ} = 0.89 \approx 1/1.12$. Die $0.80\,\mathrm{N\,m}$ des Knieservos sind etwa $23\,\%$ seines Blockiermoments von $3.43\,\mathrm{N\,m}$. Ein Trot legt das Gewicht auf zwei statt vier Füße und verdoppelt die Last grob auf etwa $1.6\,\mathrm{N\,m}$, was immer noch etwa einen Faktor zwei für Beschleunigungen und Stolperer lässt. **Dynamikprüfung.** Der Unterschenkel wiegt $0.0521\,\mathrm{kg}$, sein Schwerpunkt liegt etwa $48\,\mathrm{mm}$ vom Knie entfernt. Das ergibt $m r_c^2 \approx 1.2\times10^{-4}\,\mathrm{kg\,m^2}$; mit der Eigenträgheit des Unterschenkels um seinen Schwerpunkt ($1.5\times10^{-4}$, `mass_report.yaml`) sieht das Knie etwa $2.7\times10^{-4}\,\mathrm{kg\,m^2}$, grob $1/44$ der modellierten Armature. Das Schwingen eines leichten Beins ist daher durch die Geschwindigkeit und den eigenen Rotor des Servos begrenzt, nicht durch die Trägheit des Links. **Landung.** `strength.py` nimmt eine harte Landung mit dem $3\times$-fachen Körpergewicht auf einem diagonalen Paar an: $$ F = \frac{3 \cdot 3.07 \cdot 9.81}{2} = 45.2\,\mathrm{N} $$ pro Fuß. An der $124\,\mathrm{mm}$ langen Tibia sind das $5.60\,\mathrm{N\,m}$ am Knie, mehr als das Blockiermoment. Eine Landung treibt den Servo also rückwärts, und die gedruckten Teile müssen das aushalten. Siehe [Festigkeit](../making/strength.md). ## Selbsttest {#check-yourself} 1. Leiten Sie $\boldsymbol{\tau} = \mathbf{J}^\top\mathbf{F}$ in einer Zeile aus der virtuellen Arbeit her. 2. Warum ändert das Parallelogramm das Moment nicht, kann aber trotzdem die kurze Koppel überlasten? 3. Warum braucht der Oberschenkel in der Standpose fast kein Moment? 4. Kann der Servo $3.43\,\mathrm{N\,m}$ liefern, während er sich mit $6\,\mathrm{rad/s}$ dreht?
Antworten 1. $\boldsymbol{\tau}^\top\delta\mathbf{q} = \mathbf{F}^\top\mathbf{J}\,\delta\mathbf{q}$ für alle $\delta\mathbf{q}$, also $\boldsymbol{\tau} = \mathbf{J}^\top\mathbf{F}$. 2. Seine Eingangs- und Ausgangskurbel sind gleich, daher kürzen sich die $\sin\alpha$-Terme im Momentenverhältnis. Die Koppelkraft ist jedoch $\tau/(r\sin\alpha)$ und wächst für $\alpha \to 0$ unbegrenzt. 3. Der Fuß liegt direkt unter dem Oberschenkel-Drehpunkt ($u = 0$), daher hat die vertikale Kraft um ihn keinen Hebelarm. In der Jacobi-Matrix gilt $J_{21} = 0$. 4. Nein. Im linearen Modell bleiben bei $6\,\mathrm{rad/s}$ etwa $0.7\,\mathrm{N\,m}$ übrig. Das Blockiermoment gibt es nur bei Drehzahl null.
## Weiterführende Literatur {#further-reading} - K. M. Lynch und F. C. Park, *Modern Robotics*, Cambridge University Press, 2017, Kap. 5.2 (Statik) und Kap. 8 (Dynamik offener Ketten). - R. Featherstone, *Rigid Body Dynamics Algorithms*, Springer, 2008. - B. Siciliano et al., *Robotics: Modelling, Planning and Control*, Springer, 2009, Kap. 3.8 und 7. - R. L. Norton, *Design of Machinery*, McGraw-Hill (Kraftanalyse von Koppelgetrieben, Übertragungswinkel). - [Festigkeit der gedruckten Teile](../making/strength.md) und [Servos](../hardware/servos.md) in diesem Wiki. --- # Produktanforderungen {#product-requirements} > **Status:** Anforderungskatalog für Strido 0.2. Die Spalte *Status* gibt an, was das Repository heute nachweist; die Nachweisstufen sind in [docs/verification.md](../docs/verification.md) definiert. CAD, Simulation und native Tests sind keine Hardware-Nachweise. Strido ist ein kleiner, erschwinglicher, 3D-gedruckter Vierbeiner, den ein Entwickler zu Hause baut, um ROS-2- und Lernsoftware zu entwickeln, die später auf einen Unitree Go2 bei der Arbeit übertragen wird, und der im NT-X-Harness läuft. Er übernimmt die bewährten Yertle-Beine und den Rahmen und ergänzt, was ein Roboter der Mini-Pupper-4-Klasse bietet: ein Gesichtsdisplay, ein 360°-LiDAR, eine Weitwinkelkamera und einen Bordcomputer. ## Bereiche {#families} | Bereich | Umfang | |---|---| | MECH | Mechanische Konstruktion, Passungen, Bewegung | | MAKE | Druck, Einkauf, Montagedokumentation | | ELEC | Stromversorgung, Verkabelung, Pins | | FW | Firmware der Bewegungssteuerung | | SW | Robotersoftware (ROS 2, Werkbank-Werkzeuge) | | SIM | Simulation und Lernen | | NTX | NT-X-Harness-Integration | | DOC | Dokumentationsseite, Katalog, Renderings | | ENG | Engineering-Harness, Prüfungen, Release | ## Anforderungen {#requirements} | ID | Anforderung und beobachtbare Abnahme | Prio | Status | Nachweis | |---|---|---|---|---| | MECH-001 | 12 angetriebene Gelenke (Hüftabduktion, Oberschenkel, Knie je Bein) in Go2-Gelenkbenennung und -Reihenfolge. | MUST | erfüllt (Q1) | `models/mujoco/strido.xml`, `hardware/joint_limits.yaml` | | MECH-002 | Keine zwei Volumenkörper des montierten Roboters durchdringen sich außer an vorgesehenen Kontakten (Gewinde, Sitze, Presspassungen), in jeder Referenzpose. | MUST | erfüllt (Q1) | [Durchdringung](../docs/verification/interference.md) | | MECH-003 | Jede Schraube führt durch Durchgangsbohrungen oder formt ihr Gewinde in einer Kernbohrung von 0,70–0,97 d (gedruckte Größe), wird von einer Mutter, Kernbohrung oder einem Gewindeteil gehalten und greift ≥ 1,0 d ein; jeder Lagersitz liegt innerhalb −0,15…+0,30 mm des Lageraußendurchmessers. | MUST | erfüllt (Q1) | [Passungen](../docs/verification/fits.md) | | MECH-004 | Teile auf verschiedenen Starrkörpern halten in jeder Betriebspose (Stehen/Hocken/Hoch, Trot-Zyklus, Hüftgrenzen) ≥ 0,3 mm Bewegungsfreigang. | MUST | erfüllt (Q1) | [Freigang](../docs/verification/clearance.md) | | MECH-005 | Gelenkgrenzen stammen aus einem Kollisions- und Koppelgetriebe-Sweep (inkl. des gespiegelten Partnerbeins und 0,3 mm Freigang) und werden in Firmware, Python und Simulation identisch durchgesetzt. | MUST | erfüllt (Q0/Q1) | `make drift`, `hardware/joint_limits.yaml` | | MECH-006 | Sensorkopf: 2"-LCD-Gesicht, 360°-LiDAR mit freier Scanebene, Weitwinkelkamera, die den Roboter nicht sieht. | MUST | erfüllt (Q1) | [Sensoren](../docs/verification/sensors.md) | | MAKE-001 | Jedes Druckteil wird als ausgerichtete STL und auf 220 × 220 mm großen 3MF-Druckplatten geliefert, die auf ein 220 × 220 × 250 mm großes Druckbett passen; geschlossen und mannigfaltig. | MUST | erfüllt (Q1) | `hardware/print/` | | MAKE-002 | Die Stückliste deckt jedes Kaufteil und Befestigungselement des CAD ab (Befestigungselemente + 10 %, ≥ 2 Reserve) in jeder Einkaufsstrategie; Angebote nennen Händler, SKU, Preis und Datum. | MUST | erfüllt (Q1) | `make bom`, [Stückliste](../docs/bom/README.md) | | MAKE-003 | Der Einkaufsplan minimiert die Lieferkosten (Versandschwellen, Gebühren pro Bestellung) und bietet Alternativen mit möglichst wenigen Shops, nur EU und Original-Boards. | SHOULD | erfüllt (Q1) | [Einkaufsliste](../docs/bom/shopping_list.md) | | MAKE-004 | Montage im IKEA-Stil: Jedes Druckteil, Kaufteil und Befestigungselement erscheint in genau einer Teilebox eines Schritts, mit einer CAD-Zeichnung pro Schritt. | MUST | erfüllt (Q1) | [Montage](../docs/assembly/README.md) | | MAKE-005 | A4-Katalog & Montagebuch (PDF): Kataloge der Druck- und Kaufteile, Befestigungselemente im Maßstab 1:1, Einkaufsplan, Werkzeuge, alle Schritte, Verkabelung, Software-Anhang. | MUST | erfüllt (Q1) | [Katalog-PDF](../docs/catalog/strido-catalog.pdf) | | ELEC-001 | Servostrom fließt nie durch eine Logikplatine; getrennte, abgesicherte Servo- (6,0 V) und Logik-Domänen (5 V) mit physischem Loop-Key. | MUST | erfüllt (Design) | [Elektronik](../docs/electronics.md) | | ELEC-002 | Pins, I²C-Adressen, Servokanäle, Sicherungen und Leitungsquerschnitte werden maschinell gegen den Firmware-Header und die Last geprüft. | MUST | erfüllt (Q0) | [Elektronikprüfung](../docs/verification/electronics.md) | | FW-001 | Befehls-Watchdog (Halten 200 ms, Entspannen 2 s), verriegelter Not-Halt über PCA9685 OE, Abschaltung bei niedrigem Akkustand, Fahrverweigerung ohne Power-Monitor. | MUST | erfüllt (Q0 nativ) | `make test-firmware` | | FW-002 | Die Zuordnung Gelenk ↔ Servo ist koppelgetriebe-exakt (Knie über das Kurbel-Viergelenk angetrieben) und identisch mit dem Python-Spiegel. | MUST | erfüllt (Q0) | Firmware-Tests mit Python-Referenzwerten | | SW-001 | ROS-2-Jazzy-Bringup mit einem Vertrag im Go2-Stil: `/cmd_vel`, `/joint_states`, `/imu/data`, `/scan`, `/battery_state`, `/tf`. | MUST | erfüllt (Q2 Sim) | `make sim-gazebo` | | SW-002 | Werkbank-CLI zum Zentrieren, Pulsen, Kalibrieren und Überwachen der Servos ohne ROS. | MUST | erfüllt (Q0) | `tests/core/test_cli.py` | | SIM-001 | MuJoCo- und Gazebo-Modelle, generiert aus dem verifizierten CAD (Massen, Trägheiten, Grenzen). | MUST | erfüllt (Q2) | `make models`, `make sim-walk` | | SIM-002 | Eine in der Simulation trainierte Policy zur Geschwindigkeitsverfolgung läuft über dieselbe numpy-Laufzeit wie auf dem Roboter. | SHOULD | teilweise (nur Sim) | `make rl-smoke`, `models/policies/ppo-v1` | | NTX-001 | Der Roboter erscheint im NT-X-Katalog (Roboterspezifikation + MJCF + Steh-Skill) ohne Änderungen am NT-X-Kern und steht in NT-X MuJoCo. | MUST | erfüllt (Q2) | `make ntx-smoke` | | NTX-002 | Ein `RobotPort` steuert den echten Roboter über das MCU-Protokoll mit expliziter Semantik (keine Odometrie, kommandiertes q, verriegelter Schutzhalt). | MUST | erfüllt (Fake-MCU auf Protokollebene) | `make ntx-smoke`, `tests/ntx/` | | NTX-003 | NT-X-Sitzungen öffnen den Strido-Port über die Registry. | SHOULD | offen: Der NT-X-Kern leitet Hardware nur an Unitree SDK2 weiter | [NT-X-Integration](../docs/ntx-integration.md) | | DOC-001 | Dokumentationsseite mit Katalog, interaktivem 3D-Modell (Explosion, Schritt-für-Schritt, Teileauswahl), Renderings, Anleitungen und Verifikationsberichten. | MUST | erfüllt (Q2) | `make docs-build` | | DOC-002 | Renderings des vollständigen Roboters einschließlich Display-Gesicht, LiDAR und Kamera. | MUST | erfüllt | `docs/images/` | | ENG-001 | Engineering-Harness installiert (Profil checks) mit Projekt-Skills, einem Hardware-MCP-Server und Prüfungen für Lint, Typen, Architektur, Drift, Tests, Firmware und CAD-Verifikation. | MUST | erfüllt (Q0) | `make check-fast`, `make harness-check` | | ENG-002 | Ein Befehl baut ein Release-Zip mit dem vollständigen Repository, den Druckplatten, dem PDF, dem Laufvideo und der Policy. | MUST | erfüllt | `make package` | | HW-001 | Ein gebauter Roboter steht, läuft unter Teleoperation, und seine gemessene Masse, sein Strom und seine Laufzeit werden aufgezeichnet. | MUST | offen: noch kein Roboter gebaut | [TODO](../TODO.md) | --- # Druckliste {#print-list} Erzeugt von `strido_publish.print_files`. Jedes Teil (Upstream-Yertle und Strido) wird aus `hardware/print/stl/` gedruckt, bereits für den Druck ausgerichtet; `hardware/print/plates/` enthält fertige 3MF-Druckplatten. Servohalter und `servo_mount_top_bracket`: mit X-Y-Lochkompensation −0,15 mm drucken, damit ihre M3-Vorbohrungen greifen (ADR-009); sonst diese Vorbohrungen vor dem Eindrehen der Schrauben mit einem Tropfen dünnflüssigem Sekundenkleber härten (anaerobe Schraubensicherung ist nicht für Kunststoff: Sie härtet dort nicht aus und kann PETG reißen lassen). Die Kompensation wirkt auf senkrechte Löcher: Die Servohalter liegen wie ein U, ihre Vorbohrungen für Hüfthorn und Hüftdrehpunkt sind daher waagrecht und bekommen den Sekundenkleber, wenn eine Schraube durchdreht. Lochstufen (ein Lagersitz, der in ein kleineres Loch darüber übergeht) sind in den STLs für Brücken ausgeschnitten: Die zwei Schichten über der Stufe drucken einen Schlitz, dann ein Quadrat (siehe die Notizen). Wo die Notiz es sagt, Stützen in der Lagerbohrung im Slicer blockieren: Der Sitz liegt über dem Bett und würde sonst gestützt. Einstellungen (alle Teile, sofern nicht anders angegeben): PETG oder PLA+, 0,2 mm Schichthöhe, 3 Wände (1,2 mm), 5 obere/untere Schichten, 30 % Gyroid-Füllung, eng anliegende Stützen wo angegeben, Brim bei Teilen höher als 40 mm. PrusaSlicer-Profil: `hardware/print/prusaslicer.ini` (File > Import > Import Config). Geprüft: geschlossen und mannigfaltig, passt auf ein 220 x 220 x 250 mm großes Druckbett, und jedes Teil und jede Druckplatte lässt sich mit genau diesen Einstellungen ohne Stabilitätswarnungen slicen (`make printability`, docs/verification/printability.md). | Teil | Anz. | Farbe | Datei (in `hardware/print/`) | Größe auf dem Bett (mm) | Stützen | Quelle | Hinweis | |---|---|---|---|---|---|---|---| | arming_port_bezel | 1 | primär (Graphit) | `stl/arming_port_bezel.stl` | 26 x 26 x 4 | nein | Strido (neu) | | | arming_port_ring | 1 | primär (Graphit) | `stl/arming_port_ring.stl` | 22 x 22 x 3 | nein | Strido (neu) | | | back_shell_button | 1 | sekundär (Limette) | `stl/back_shell_button.stl` | 74 x 114 x 69 | nein | Strido (abgeändertes Upstream-Teil back_shell) | Upstream-Back_Shell mit von D11.5 auf D12.2 aufgeweiteter Bohrung | | bottom_shell | 1 | sekundär (Limette) | `stl/bottom_shell.stl` | 114 x 208 x 42 | ja (9 % Überhang) | Upstream-STL | veröffentlichte Ausrichtung; auf der -Y-Fläche liegend sinkt der Überhang auf 1 % | | camera_mount_base | 1 | primär (Graphit) | `stl/camera_mount_base.stl` | 40 x 28 x 20 | nein | Strido (neu) | stehend auf der Grundfläche drucken; die M3-Drehbohrung liegt waagrecht (bei Bedarf mit 3,4 mm aufbohren) | | camera_tilt_plate | 1 | primär (Graphit) | `stl/camera_tilt_plate.stl` | 27 x 30 x 19 | ja (24 % Überhang) | Strido (neu) | | | display_bracket | 1 | primär (Graphit) | `stl/display_bracket.stl` | 40 x 83 x 3 | nein | Strido (neu) | | | electronics_deck | 1 | primär (Graphit) | `stl/electronics_deck.stl` | 106 x 150 x 5 | ja (2 % Überhang) | Strido (abgeändertes Upstream-Teil electronics_mounting_plate) | Upstream-Platte + IMU-Tasche und Bohrungen für Abstandsbolzen für den Spannungsregler und den INA260; mit der Oberseite nach unten und mit Stützen drucken (der Boden der IMU-Tasche ist eine 18-mm-Brücke, die der Slicer ohne Stützen beanstandet) | | femur | 4 | primär (Graphit) | `stl/femur.stl` | 26 x 151 x 15 | ja (5 % Überhang) | Upstream-STL | neu ausgerichtet gegenüber der veröffentlichten STL: mehr Bettkontakt, weniger Überhang | | femur_servo_connector | 4 | primär (Graphit) | `stl/femur_servo_connector.stl` | 28 x 28 x 6 | ja (7 % Überhang) | Upstream-STL | neu ausgerichtet gegenüber der veröffentlichten STL: mehr Bettkontakt, weniger Überhang | | foot_spacer | 4 | primär (Graphit) | `stl/foot_spacer.stl` | 22 x 24 x 12 | ja (21 % Überhang) | Upstream-STEP (keine Upstream-STL veröffentlicht) | | | front_shell_display | 1 | sekundär (Limette) | `stl/front_shell_display.stl` | 74 x 114 x 50 | nein | Strido (abgeändertes Upstream-Teil front_shell) | Upstream-Front_Shell + 43x33-Displayfenster, 2 Display-Dome, Schlitz für das Kamera-Flachbandkabel | | hip_bearing_pin | 4 | primär (Graphit) | `stl/hip_bearing_pin.stl` | 5 x 5 x 5 | nein | Upstream-STEP (keine Upstream-STL veröffentlicht) | neu ausgerichtet gegenüber der veröffentlichten STL: mehr Bettkontakt, weniger Überhang | | inner_shoulder_frame | 2 | primär (Graphit) | `stl/inner_shoulder_frame.stl` | 110 x 70 x 5 | nein | Upstream-STL | | | inner_tibia | 4 | primär (Graphit) | `stl/inner_tibia.stl` | 135 x 104 x 14 | ja (10 % Überhang) | Upstream-STL | neu ausgerichtet gegenüber der veröffentlichten STL: mehr Bettkontakt, weniger Überhang; 1 Lochstufe für Brücken ausgeschnitten (Lochüberhang-Trick); Stützen in der Lagerbohrung blockieren, damit die Stufe überbrückt wird | | left_servo_mount | 1 | primär (Graphit) | `stl/left_servo_mount.stl` | 56 x 52 x 19 | ja (2 % Überhang) | Upstream-STL | neu ausgerichtet gegenüber der veröffentlichten STL: mehr Bettkontakt, weniger Überhang | | left_servo_mount_fl | 1 | primär (Graphit) | `stl/left_servo_mount_fl.stl` | 56 x 52 x 19 | ja (2 % Überhang) | Strido (abgeändertes Upstream-Teil left_servo_mount) | Upstream-left_servo_mount + Ø2,5-mm-Vorbohrung für den Hüftdrehpunkt des FL-Beins; neu ausgerichtet gegenüber der veröffentlichten STL: mehr Bettkontakt, weniger Überhang | | left_shoulder | 2 | sekundär (Limette) | `stl/left_shoulder.stl` | 50 x 55 x 26 | ja (5 % Überhang) | Upstream-STL | | | lidar_pedestal | 1 | primär (Graphit) | `stl/lidar_pedestal.stl` | 56 x 56 x 14 | nein | Strido (neu) | kopfüber drucken (Deckplatte auf dem Bett) | | lower_shoulder_frame_front | 1 | primär (Graphit) | `stl/lower_shoulder_frame_front.stl` | 20 x 70 x 12 | nein | Strido (abgeändertes Upstream-Teil lower_shoulder_frame) | Upstream-Lower_Shoulder_Frame + eine M3-Vorbohrung für den Servobus-Halter | | lower_shoulder_frame_rear | 1 | primär (Graphit) | `stl/lower_shoulder_frame_rear.stl` | 20 x 70 x 12 | nein | Strido (abgeändertes Upstream-Teil lower_shoulder_frame) | Upstream-Lower_Shoulder_Frame + eine M3-Vorbohrung für den Servobus-Halter | | outer_shoulder_frame | 2 | primär (Graphit) | `stl/outer_shoulder_frame.stl` | 110 x 70 x 5 | nein | Upstream-STL | 2 Lochstufen für Brücken ausgeschnitten (Lochüberhang-Trick) | | outer_tibia | 4 | primär (Graphit) | `stl/outer_tibia.stl` | 135 x 104 x 14 | ja (10 % Überhang) | Upstream-STL | neu ausgerichtet gegenüber der veröffentlichten STL: mehr Bettkontakt, weniger Überhang; 1 Lochstufe für Brücken ausgeschnitten (Lochüberhang-Trick); Stützen in der Lagerbohrung blockieren, damit die Stufe überbrückt wird | | right_servo_mount | 1 | primär (Graphit) | `stl/right_servo_mount.stl` | 56 x 52 x 19 | ja (2 % Überhang) | Upstream-STL | neu ausgerichtet gegenüber der veröffentlichten STL: mehr Bettkontakt, weniger Überhang | | right_servo_mount_fr | 1 | primär (Graphit) | `stl/right_servo_mount_fr.stl` | 56 x 52 x 19 | ja (2 % Überhang) | Strido (abgeändertes Upstream-Teil right_servo_mount) | Upstream-right_servo_mount + Ø2,5-mm-Vorbohrung für den Hüftdrehpunkt des FR-Beins; neu ausgerichtet gegenüber der veröffentlichten STL: mehr Bettkontakt, weniger Überhang | | right_shoulder | 2 | sekundär (Limette) | `stl/right_shoulder.stl` | 50 x 55 x 26 | ja (5 % Überhang) | Upstream-STL | neu ausgerichtet gegenüber der veröffentlichten STL: mehr Bettkontakt, weniger Überhang | | servo_bus_holder_front | 1 | primär (Graphit) | `stl/servo_bus_holder_front.stl` | 22 x 67 x 28 | ja (12 % Überhang) | Strido (neu) | | | servo_bus_holder_rear | 1 | primär (Graphit) | `stl/servo_bus_holder_rear.stl` | 22 x 67 x 14 | ja (6 % Überhang) | Strido (neu) | | | servo_mount_top_bracket | 4 | primär (Graphit) | `stl/servo_mount_top_bracket.stl` | 56 x 19 x 6 | nein | Upstream-STL | neu ausgerichtet gegenüber der veröffentlichten STL: mehr Bettkontakt, weniger Überhang | | short_link | 4 | primär (Graphit) | `stl/short_link.stl` | 35 x 10 x 7 | ja (15 % Überhang) | Upstream-STL | neu ausgerichtet gegenüber der veröffentlichten STL: mehr Bettkontakt, weniger Überhang | | side_body_beam | 2 | primär (Graphit) | `stl/side_body_beam.stl` | 25 x 150 x 6 | nein | Upstream-STL | neu ausgerichtet gegenüber der veröffentlichten STL: mehr Bettkontakt, weniger Überhang | | stiff_long_link | 4 | primär (Graphit) | `stl/stiff_long_link.stl` | 10 x 141 x 10 | nein | Strido (abgeändertes Upstream-Teil long_link) | Upstream-long_link, 10 x 10 mm statt 5 x 8 mm, gleiche Bolzen und Augen: Knicken, ADR-010 | | top_shell_sensor | 1 | sekundär (Limette) | `stl/top_shell_sensor.stl` | 114 x 208 x 42 | ja (8 % Überhang) | Strido (abgeändertes Upstream-Teil top_shell) | Upstream-Top_Shell + Bohrungen für den LiDAR-Sockel und Schlitz für das LiDAR-USB-Kabel | | upper_shoulder_frame | 2 | primär (Graphit) | `stl/upper_shoulder_frame.stl` | 40 x 70 x 12 | nein | Upstream-STL | | Gesamtes Volumen aller Teile: 943 cm³ (Filament ≈ 659 g PETG bei den obigen Einstellungen; planen Sie 1,2 kg inkl. Brims, Stützen und Testdrucken ein). ---