Tutorial · Mittelstufe · 35 Min.
Mecanum-Radkinematik: Vier Räder, drei Achsen
Die vierzeilige inverse Kinematik einer Mecanumbasis aus einer 45°-Rolle herleiten, für Odometrie invertieren und die vierte Gleichung für Schlupf nutzen.
Eine Rolle entscheidet alles
Ein Mecanum-Rad vom Roboter nehmen und halten. Es dreht sich auf seiner Achse wie jedes Rad. Um seine Felge sitzen acht, neun tonnenförmige Rollen, jede auf eigener kleiner Achse, jede frei drehbar, und jede 45° zur Radachse gestellt.
Nun fragen, welche Kraft dieses Rad in den Boden bringen kann.
Entlang der Rollenrollrichtung kann es nicht schieben – die Rolle dreht sich bloß und nichts wird übertragen. Es kann nur entlang der Rollenachse schieben – die eine Richtung, in die die Rolle sich weigert zu rollen. Die Bodenkraft des Rads liegt also fest auf einer einzigen Bodenlinie, 45° zum Chassis – und kein Motordrehmoment ändert welche Linie.
Das ist der ganze Mechanismus. Alles unten ist Buchhaltung.
Die Zwangsbedingung, Rad für Rad
Den üblichen Roboterframe aufstellen: x vorwärts, y zur Roboterlinken, ω gegen den Uhrzeigersinn. Das ist die ROS-Konvention – alles andere heißt, jede je angefasste Bibliothek zu bekämpfen.
Rad i an Position (xᵢ, yᵢ) in diesem Frame legen und ihm eine Rollenhändigkeit sᵢ = ±1 geben, die sagt, auf welcher der zwei 45°-Linien seine Rollen liegen. Dann hängt die Felgendrehzahl vᵢ des Rads (in Metern pro Sekunde am Reifen, nicht Radiant) so mit dem Chassistwist zusammen:
vᵢ = vx + sᵢ·vy + (sᵢ·xᵢ − yᵢ)·ω
Drei Terme, und jeder verdient einen Satz:
- vx – jedes Rad trägt voll zur Vorwärtsbewegung bei, egal welche Hand. Darum fühlt sich Vorwärts auf Mecanumbasis völlig normal an.
- sᵢ·vy – Seitwärtsbewegung treibt halbe Räder so herum und halbe andersherum. Die Hand entscheidet, welche Hälfte.
- (sᵢ·xᵢ − yᵢ)·ω – der Hebelarm. Beachte: nicht bloß die Spurweite; die Rollenhand steckt darin – weshalb ein Rad in der falschen Ecke Drehung wie Strafen ruiniert.
Von Felgendrehzahl zu dem, was man wirklich einem Motor befiehlt, durch den Radradius teilen: ωRad = vᵢ / r, in rad/s.
Vier Räder: die Matrix
Diese vier Zeilen stapeln und man hat eine 4×3-Matrix A, mit Chassistwist ξ = (vx, vy, ω):
v = A · ξ
Für die Standardanordnung – vorne links und hinten rechts eine Hand, vorne rechts und hinten links die andere – k = lx + ly schreiben, wobei lx der halbe Radstand ist (vorne zu hinten) und ly die halbe Spur (links zu rechts). Dann:
| Rad | vx | vy | ω |
|---|---|---|---|
| Vorne links | 1 | −1 | −k |
| Vorne rechts | 1 | +1 | +k |
| Hinten links | 1 | +1 | −k |
| Hinten rechts | 1 | −1 | +k |
Was die vier Zeilen sind, die alle schreiben:
float fl = vx - vy - K * omega;
float fr = vx + vy + K * omega;
float rl = vx + vy - K * omega;
float rr = vx - vy + K * omega;
Gegen die vier Dinge prüfen, die man von einem Mecanumroboter bereits kennt:
| Befehl | Raddrehzahlen (VL, VR, HL, HR) | Was man sieht |
|---|---|---|
| Vorwärts, vx = 1 | 1, 1, 1, 1 | Alle vier gleichherum. Die Querteile heben sich auf. |
| Links strafen, vy = 1 | −1, 1, 1, −1 | Diagonalpaare gegenläufig. Das ist der Partystück. |
| CCW drehen, ω = 1 | −k, k, −k, k | Linke Seite zurück, rechte vorwärts – eine gewöhnliche Panzerdrehung. |
| Diagonal, vx = vy = 1 | 0, 2, 2, 0 | Zwei Räder stehen völlig. Das merken. |
Das durchgerechnete Beispiel
Eine Basis mit lx = 75 mm, ly = 85 mm, 97-mm-Rädern (r = 48,5 mm), verlangt vx = 0,30 m/s, vy = 0,20 m/s, ω = 0,50 rad/s. Also k = 0,160 m.
| Rad | Rechnung | Felgendrehzahl | Motordrehzahl |
|---|---|---|---|
| Vorne links | 0,30 − 0,20 − 0,160 × 0,50 | 0,020 m/s | 0,41 rad/s (3,9 U/min) |
| Vorne rechts | 0,30 + 0,20 + 0,160 × 0,50 | 0,580 m/s | 11,96 rad/s (114 U/min) |
| Hinten links | 0,30 + 0,20 − 0,160 × 0,50 | 0,420 m/s | 8,66 rad/s (83 U/min) |
| Hinten rechts | 0,30 − 0,20 + 0,160 × 0,50 | 0,180 m/s | 3,71 rad/s (35 U/min) |
Neunundzwanzigfache Drehzahl an einem Rad gegen ein anderes – aus einem Befehl, der nicht extrem aussieht. Ein Mecanumantrieb verbringt den Großteil seines Lebens damit, dass seine vier Motoren wild Verschiedenes tun – weshalb „alle bekommen dasselbe PWM und er fährt geradeaus“ hier kein Test ist, der etwas heißt.
Sättigung: skalieren, nie clippen
Mehr verlangen, als die Motoren haben, und man muss etwas aufgeben. Es gibt exakt zwei Wahlen und sie sind nicht gleichwertig.
float peak = max(max(fabs(fl), fabs(fr)), max(fabs(rl), fabs(rr)));
if (peak > V_MAX) { // SCALE: keep the direction, lose the speed
float s = V_MAX / peak;
fl *= s; fr *= s; rl *= s; rr *= s;
}
gegen das, was geschieht, wenn man nur constrain(fl, -255, 255) auf jeden Motor schreibt: Clippen. Clippen behält das Tempo und wirft die Richtung weg. 0,60 m/s vorwärts, 0,15 seitwärts und 0,8 rad/s Drall verlangen an einem Roboter, dessen Räder bei 0,50 m/s deckeln:
| Kurs | Vorwärts | Drall | Urteil | |
|---|---|---|---|---|
| Befohlen | 14,0° | 0,60 m/s | 0,80 rad/s | — |
| Skalieren | 14,0° | 0,34 m/s | 0,46 rad/s | In jeder Achse langsamer, exakt wohin man zeigte |
| Clippen | 5,6° | 0,46 m/s | 0,28 rad/s | Schneller vorwärts, 8,4° neben Kurs, und 40 % weniger Drall |
Das Fieseste: Clippen sieht bei den Befehlen, die Leute testen, gut aus. Eine reine Diagonale verlangt von zwei Rädern 2 und von zweien 0; die Nullen liegen bereits in der Grenze – Clippen und Skalieren erzeugen also identische Zahlen und der Fehler versteckt sich. Er zeigt sich später, unter einem Pfadfolger, als Roboter, der sich ohne findbaren Grund aus Kurven lehnt. Beide Begrenzer im selben Lauf beobachten und der Unterschied ist eine sichtbare Kurve.
Rückwärts: Odometrie
Vorwärtskinematik ist dieselbe Matrix andersherum gelesen. Aber A ist 4×3 – vier Messungen, drei Unbekannte –, also gibt es keine Inverse. Es gibt eine Kleinste-Quadrate-Lösung:
ξ = (Aᵀ A)⁻¹ Aᵀ v
Für die Standardanordnung wird AᵀA diagonal und das Ganze kollabiert zu drei Zeilen für einen Arduino:
vx = (fl + fr + rl + rr) / 4.0;
vy = (-fl + fr + rl - rr) / 4.0;
omega = (-fl + fr - rl + rr) / (4.0 * K);
Das jeden Tick durch den Roboterkurs integrieren und man hat Koppelnavigation:
float dt = (now - last) * 1e-6f;
theta += omega * dt;
x += (vx * cosf(theta) - vy * sinf(theta)) * dt;
y += (vx * sinf(theta) + vy * cosf(theta)) * dt;
Was exakt so gut arbeitet wie die Annahme darunter – dass die Räder nicht rutschen. Auf Mecanumbasis ist Schlupf der Konstruktionspunkt des Rads – Querodometrie also als unzuverlässigste Zahl am Roboter behandeln.
Die vierte Gleichung, die niemand nutzt
Vier Gleichungen, drei Unbekannte. Diese überzählige Gleichung ist kein Abfall – sie ist die einzige Gratisdiagnose am ganzen Antriebsstrang.
Ist der Roboter starr und greift jedes Rad, können die vier Felgendrehzahlen nicht beliebig sein. Erste zwei Zeilen addieren und letzte zwei Zeilen addieren und beide ergeben 2·vx, also:
FL + FR = RL + RR
immer, exakt, für jede Bewegung, die ein starres Mecanumchassis ausführen kann. Also jeden Schleifendurchlauf das Residuum rechnen:
float residual = (fl + fr) - (rl + rr); // should be ~0 forever
Ungleich null heißt: Die vier Encoder beschreiben eine Bewegung, die kein fester Körper ausführen kann. Ursachen, grob nach Wahrscheinlichkeit: ein Rad in der Luft, ein Rad auf nassem Fleck, eine blockierte Rolle, eine rutschende Kupplung, ein toter Encoderkanal – oder ein Rad in der falschen Ecke, was das Residuum groß und konstant statt stoßweise macht.
Ehrlich darüber, was es nicht sehen kann: Rutschen alle vier Räder gleich zugleich, bleibt das Residuum null und der Roboter gleitet seitwärts vom Kurs in totaler Stille. Diese Blindheit ist exakt, warum Mecanum-Odometrie leise statt laut scheitert – und warum ernsthafte Bauten eine IMU oder ungetriebene Messräder ergänzen statt den Antriebsencodern zu trauen.
Die zwei Folgen von 45°
Beide fallen aus der Matrix – und keine lässt sich wegkaufen.
Diagonalbewegung deckelt bei 1/√2. Ein 45°-Befehl legt vx + vy auf zwei Räder und 0 auf die anderen zwei – das beschäftigte Paar erreicht also die Drehzahlgrenze, wenn der Roboter erst bei V_MAX / √2 ≈ 71 % seiner Geradeaus-Topdrehzahl ist. Schnellere Motoren verschieben die Decke; sie beseitigen sie nicht.
Traktion deckelt ebenfalls bei 1/√2, aus anderem Grund. Die nützliche Antriebskraft F des Motors liegt entlang der Rollrichtung – die wirkliche Bodenkraft ist aber F·√2 entlang der Rollenachse, und Reibung deckelt die. Pro Rad ist die Nutzkraft also auf μN/√2 gedeckelt, und die Beschleunigungsdecke des Roboters lautet:
a_max = μ·g / √2
Bei μ = 0,85 sind das 5,9 m/s², wo derselbe Roboter auf normalen Rädern 8,3 hätte. Die Robotermasse kürzt sich aus beiden – Ballast hilft also nicht: eine Lektion, die exakt umgekehrt läuft zu einem Sumoroboter, wo Gewicht die ganze Strategie ist.
In Firmware
Die Geometrie an einen Ort legen und nie zweimal tippen lassen.
struct Mecanum {
float lx, ly, r; // half wheelbase, half track, wheel radius (m)
float k() const { return lx + ly; }
// twist -> four wheel angular velocities, rad/s
void inverse(float vx, float vy, float w, float out[4]) const {
out[0] = (vx - vy - k() * w) / r; // FL
out[1] = (vx + vy + k() * w) / r; // FR
out[2] = (vx + vy - k() * w) / r; // RL
out[3] = (vx - vy + k() * w) / r; // RR
}
// four measured wheel angular velocities -> twist, plus the residual
float forward(const float in[4], float &vx, float &vy, float &w) const {
float fl = in[0] * r, fr = in[1] * r, rl = in[2] * r, rr = in[3] * r;
vx = (fl + fr + rl + rr) * 0.25f;
vy = (-fl + fr + rl - rr) * 0.25f;
w = (-fl + fr - rl + rr) * 0.25f / k();
return (fl + fr) - (rl + rr); // the free diagnostic
}
};
lx und ly Radmitte zu Radmitte messen, dann halbieren – nicht die Chassisplatte, die meist breiter ist. Falsches k stoppt den Roboter nicht beim Fahren; es lässt Drehung und Translation ineinander bluten – ein reiner Drehbefehl kriecht also und reines Strafen kurvt. Kriecht dein Roboter beim Drehen auf der Stelle, k verdächtigen, bevor man den Code verdächtigt.
Fehlersuche
| Symptom | Wahrscheinliche Ursache | Was zu prüfen ist |
|---|---|---|
| Geradeaus gut, Strafen kurvt und rotiert | Ein Rad in der falschen Ecke | Die X-Probe von oben; das Residuum wird groß und stabil sein |
| Straft gegen den Befehl | Alle vier Räder gespiegelt | Linkes Paar mit rechtem Paar tauschen |
| Drehen auf der Stelle versetzt auch | k falsch, oder lx/ly am Chassis statt Rädern gemessen | Radmitte zu Radmitte neu messen |
| Diagonale deutlich langsamer als geradeaus | Die 1/√2-Decke – kein Defekt | Nichts zu reparieren; darum herum entwerfen |
| Roboter lehnt sich unter Pfadfolger aus Kurven | Pro-Motor-Clipping statt Skalieren | Den ganzen Befehl am schwächsten Rad skalieren |
| Odometrie driftet seitwärts schnell, vorwärts in Ordnung | Rollenschlupf, konstruktionsbedingt | IMU für den Kurs, Messräder für die Position |
| Residuum spitzt nur auf einer Oberfläche | Dieser Fleck ist glitschig oder eine Rolle blockiert | Jede Rolle von Hand drehen |
Weiter
Die Zahlen gegen einen Roboter laufen lassen, der rutschen kann: Der Mecanum-Antriebssimulator fährt exakt diese Gleichungen in ein Reibungsmodell – man kann Odometrie und Boden sich widersprechen sehen. Dann die Räder die gerechneten Drehzahlen wirklich halten lassen – geregelte Raddrehzahlregelung –, und „vorwärts“ auf dem Boden statt auf dem Roboter heißen lassen mit feldorientierter Fahrt.
Den Graphen erkunden
Teil dieser Bauprojekte
Projekte und Lernpfade, die dieses Tutorial enthalten.
Weiterführende Literatur