G28 Singularität und Planungen

This commit is contained in:
chk
2026-06-26 11:39:20 +02:00
parent bd1752f567
commit 7639266170
6 changed files with 232 additions and 34 deletions

View File

@@ -122,34 +122,95 @@ Umgesetzt:
- **Spiegelung an der x-z-Ebene** in `Arm3SegmentLinearX` (`_mirrorWorkspaceY`): die
interne Mathematik (`_ikPlusY`/`_fkPlusY`) rechnet weiter in +y, die öffentlichen
Methoden spiegeln die Workspace-Pose (y, pY, φ, ψ; θ bleibt) → α=0 zeigt nach y.
- **G28** (Home) auf y umgestellt: `y = -(l1+l2+l3)`, `phi = +π/2`.
- **G28** (Home) auf y umgestellt **und Singularität behandelt**: die voll ausgestreckte
Stellung (`|y| = l1+l2+l3`) ist eine Handgelenk-Singularität, in der die IK `a`/`c` nicht
bestimmen kann (Müll wie `a=135°, c=45°` → Finger schräg). G28 setzt dort die Motorwerte
**direkt** (`alpha=beta=a=c=0`, `b=π` = gerade Hand) und füllt die Pose per FK.
- **Tests:** `test/Robot.Kinematics.NegativeY.test.js` (Grundstellung 590, Homing-Pose
in y, Round-Trip in y, a=0 → Knick-Achse ∥ x).
- **Migration:** `Robot.02_UpperArm` und der G28-Test auf y umgestellt.
- **Doku:** `doc/Info_G92.md` Y/Z (und C/A nach der Spiegelung) aktualisiert.
### Phase 2 — Handgelenk-/Finger-Nullstellung (B, C) — OFFEN
### Phase 2 — Handgelenk-/Finger-Nullstellung (B, C, Greifer) — OFFEN
> **Voraussetzung (User):** Erst Visualisierung/Überprüfung der Finger, dort werden noch
> Fehler vermutet. **a-Achse ist bereits korrekt** (a=0 → Knick-Achse ∥ x) Phase 2
> betrifft nur **B (Knick)**, **C (Roll)** und die **Greifer-Kopplung**.
> **Voraussetzung (User):** Erst die Finger visualisieren/prüfen — dort werden noch Fehler
> vermutet. **a-Achse ist bereits korrekt** (a=0 → Knick-Achse ∥ x). Phase 2 betrifft
> **B (Knick)**, **C (Roll)** und die **Greifer-Kopplung**.
1. **Finger/Hand visualisieren** und gegen die echte Mechanik prüfen (User).
2. **B-Konvention:** gerade Hand soll **0°** sein (derzeit 180°; physischer Knick = 180° B).
Mapping festlegen (z.B. `b → 180° b` an der Schnittstelle) und FK/IK anpassen.
3. **C-Nullpunkt:** neutral soll **0°** sein (derzeit `ψ = 90° C`).
⚠️ Der C↔ψ-Bezug ist **posenabhängig** (`acos(cos β · sin a)`); ein global sauberes
`c=0 = neutral` braucht ggf. eine tiefere Umparametrierung — **vor** der Umsetzung bewerten.
4. **Greifer-Kopplung** `eMotor = e b c` prüfen: mischt mm (e) mit Radiant (b, c)
gegen die echte Sehnen-Mechanik validieren.
5. Tests + `Info_G92.md` nachziehen.
**Ziel-Konvention:** gerade Hand → **B = 0°** (statt 180°); neutraler Roll → **C = 0°**;
Greifer-Kopplung konsistent und gegen die echte Mechanik kalibriert.
#### Vorab-Erkenntnis aus dem Code (wichtig!)
Die b/c/e-Konvention ist an **mehreren** Stellen kodiert, die **gemeinsam** geändert werden
müssen. **Invariante:** solange die Hardware-Nullpunkte nicht neu kalibriert werden, müssen
die an FluidNC gesendeten Port-Werte **gleich bleiben** — eine reine Modell-Umbenennung darf
die Hardware-Bewegung nicht verändern.
Fundstellen:
| Datei / Stelle | aktuelle Kodierung |
|----------------|--------------------|
| `Arm3SegmentLinearX._fkPlusY` | `vHand = rotate(vecUnterarm, n, b)`; `psi = c acos(n.z)`**b=π = gerade** |
| `Arm3SegmentLinearX._ikPlusY` | `b = acos(cosB)` (∈[0,π]); `c = acos(cosC) + psi`**c hat posenabh. Offset** |
| `Arm3SegmentLinearX.gripperMotorFromOpening` | `eMotor = e b c` (b,c in **rad**) — **Greifer-Kopplung #1** |
| `RobotController` G92/M92 | `b = B/D`, `c = C/D`, `eMotor = gripperMotorFromOpening(e)` |
| `RobotController` M1 | `b += B`, `c += C` (relativer Motor-Jog) |
| `RobotController` G28 | `b = π`, `c = 0` (Phase 1) → nach B-Umstellung auf `b = 0` ändern |
| `portInverse.js` | `b = hand.z/D`, `c = hand.x/D + b` (Port→Motor, Hardware-Sync) |
| `TelnetSenderGRBL.execCommand` / `portValue` | Hand-Ports: `z = b·D`, `x = (cb)·D`; **e-Port mit `factorTurnLift=1.2`****Greifer-Kopplung #2** |
#### Aufgaben
1. **Finger visualisieren** (User) → Soll-Bild, gegen das kalibriert wird.
2. **Greifer-Kopplung vereinheitlichen.** Es existieren **zwei widersprüchliche** Kopplungen:
- Kinematik: `eMotor = e b c` (b,c in rad)
- Sender: `e-Port = e + 1.2·b·D c·D` (b,c in Grad, Faktor **1.2** nur auf b)
Eine Quelle der Wahrheit festlegen und gegen die echte Sehnenmechanik messen.
(`factorOpenTurn = 1.92` im Sender ist deklariert, aber **ungenutzt** → klären/entfernen.)
3. **B-Konvention (gerade = 0°).** Durchgängig:
- FK/IK in `Arm3SegmentLinearX` (b-Definition / acos-Zweig),
- `gripperMotorFromOpening` nachziehen,
- G92-Eingabe (`b = B/D`) + M1 + G28,
- `portInverse.js` (Umkehrung),
- **Sender-Formeln so kompensieren, dass die FluidNC-Ports unverändert bleiben** —
ODER bewusst die Hardware-Nullpunkte neu kalibrieren (Entscheidung dokumentieren).
4. **C-Nullpunkt (neutral = 0°).** Der `c↔ψ`-Bezug ist **posenabhängig**
(`ψ = acos(cos β · sin a) c`). Ein konstantes `c=0=neutral` ist **nicht global** möglich,
ohne die Hand-Parametrierung zu ändern. Bewerten: c als reinen Gelenkwinkel führen
(Offset herausrechnen) oder die ψ-Definition anpassen.
5. **l3-Ableitung korrigieren** (`RobotConfig.js`): `l3` kommt aus
`Ellbow.skeleton.to[0] = 90` (Ellbogen-Versatz), **nicht** aus der echten Hand-/Finger-
Länge — das erklärt die beobachteten 550 statt 590. Aus der echten Finger-Geometrie ableiten.
6. **Tests + Doku** nachziehen: Round-Trip mit neuer Konvention, Greifer-Kopplung,
G92-Referenztabellen in `Info_G92.md`, sowie diese Datei.
#### Ansatz-Entscheidung (vor Umsetzung)
- **Klein/lokal:** nur die **G92-Eingabe** umrechnen (appRobotHoming sendet B=0/C=0 für
gerade/neutral, Driver mappt intern auf die alte Konvention). Wenig Risiko, aber das
interne Modell bleibt „unsauber".
- **Groß/sauber:** interne Konvention durchgängig umstellen (alle Fundstellen oben) mit
Hardware-Port-Invariante. Sauberes All-Zero-Home, aber koordinierter Eingriff.
#### Verifikation
Jede B/C/Greifer-Änderung gegen **Visualisierung UND einen Hardware-Test** (eine Achse
isoliert) prüfen — das Modell allein genügt hier nicht, weil es um die Hardware-Abbildung geht.
### Verifikation (Definition of Done)
- **Phase 1 (erfüllt):** G92 der Grundstellung → Driver `y ≈ 590, z ≈ 0`; appRobotHoming
sendet die gemessenen α/β/a **direkt** (ohne Spiegelung); volle Suite grün.
- **Phase 2 (Ziel):** Grundstellung mit **allen** Gelenkwinkeln 0 (inkl. B=C=0); Finger
visuell korrekt.
sendet die gemessenen α/β/a **direkt** (ohne Spiegelung); **G28 fährt sauber gestreckt
nach y** (a=0, kein Singularitäts-Müll); volle Suite grün.
- **Phase 2 (Ziel):** Grundstellung mit **allen** Gelenkwinkeln 0 (inkl. B=C=0); Greifer-
Kopplung vereinheitlicht; Finger visuell korrekt.
---
@@ -157,6 +218,8 @@ Umgesetzt:
- **y-Flip (Phase 1):** Spiegelung in `Arm3SegmentLinearX` (`_mirrorWorkspaceY`, genutzt von
`calculateAngles3D` und `calculatePositionFromMotorAngles`). Am Roboter bestätigt.
- **G28-Singularität (Phase 1):** voll ausgestreckt setzt `RobotController` die Motorwerte
direkt (statt der singulären IK) → Finger sauber entlang y.
- **atan2-Fix** in der IK (`gamma = Math.atan2(pZ, pY)`): macht die interne IK für y
mathematisch korrekt — Voraussetzung des y-Flips.
- **Winkel-Konventionen** (Y/Z/A/B/C/E) sind in [doc/Info_G92.md](Info_G92.md) dokumentiert