Jak wyprowadzić zamkniętą IK dla manipulatorów BEZ sferycznego nadgarstka, case study UR5 (Hawkins/Kufieta) i ES5 (Załącznik A dysertacji Gruszki 2024). Plus krótko o redundancji Franka Panda.
Moduł 1 pokazał piękne, „klasyczne" wyprowadzenie IK dla PUMA 560, manipulator z trzema osiami nadgarstka schodzącymi w jednym punkcie (forma A warunku Piepera). To pozwoliło na dekompozycję 3+3: najpierw pozycja, potem orientacja. Pięć stron algebry, jeden czysty wynik.
Większość współczesnych cobotów nie spełnia jednak formy A. UR5, UR10, Franka Panda, KUKA iiwa, wszystkie one mają geometrie zaprojektowane pod inne cele (smukłość, lekkość, równa dystrybucja mas), które łamią klasyczną dekompozycję. Czy to znaczy że nie można ich rozwiązać analitycznie? Nie, można, ale trzeba zmienić podejście.
Co wynika z tego modułu
Po przerobieniu modułu student potrafi: (1) rozpoznać formę warunku Piepera na podstawie geometrii DH, (2) wyprowadzić IK dla manipulatora UR5 (forma B, metoda Hawkins/Kufieta), (3) wyprowadzić IK dla ES5 z dysertacji Gruszki, (4) rozumie różnicę między manipulatorami 6-DOF a redundantnym 7-DOF (Franka Panda) i wie dlaczego ten ostatni wymaga zupełnie innego podejścia.
Donald Pieper w 1968 roku pokazał, że istnieje rozwiązanie zamknięte IK dla manipulatora 6-DOF jeśli spełniony jest jeden z dwóch warunków geometrycznych:
W obu przypadkach 6-wymiarowy problem rozpada się na dwa niezależne 3-wymiarowe (pozycja + orientacja w jakimś rozumieniu), a wyniki są wzorami zamkniętymi z funkcjami trygonometrycznymi.Jeśli żaden warunek nie zachodzi, IK nadal może być rozwiązalna analitycznie, ale wymaga zaawansowanych metod algebraicznych (Raghavan–Roth, redukcja do równania 16. stopnia w jednej zmiennej).
Forma A
3 osie schodzą w jednym punkcie
Przykłady: PUMA 560, Stäubli TX, ABB IRB
Forma B
3 osie wzajemnie równoległe
Przykłady: UR5/UR10/UR16, ES5, KUKA iiwa (częściowo)
Brak warunku Piepera
Ani A, ani B
Przykłady: Manipulatory eksperymentalne, wymagana metoda Raghavan–Roth (równanie 16. stopnia)
Zasada Piepera (1968): jeśli manipulator 6-DOF ma 3 kolejne osie spełniające A lub B, to istnieje rozwiązanie zamknięte IK (dekompozycja na 3+3 niewiadome). To warunek wystarczający, nie konieczny, manipulatory bez Piepera też mogą mieć zamknięte rozwiązania, ale wymagają zaawansowanych metod (rezultanty, metoda Raghavan–Roth).
Praktyczna konsekwencja: projektanci robotów zwykle wybierają geometrię spełniającą jedną z form Piepera celowo, żeby IK miało zamknięte rozwiązanie i było obliczane w mikrosekundach zamiast milisekundach. Manipulatory bez Piepera stosuje się rzadko (głównie w eksperymentalnych systemach badawczych).
Manipulatory Universal Robots (UR3, UR5, UR10, UR16) mają geometrię zaprojektowaną pod cele współpracy z człowiekiem: smukłe, bez ostrych krawędzi, równa dystrybucja masy. Cecha kinematyczna: kolejne osie q₂, q₃, q₄ są wzajemnie równoległe (oś pozioma, w jednym kierunku), a osie nadgarstka są przesunięte względem siebie o niezerowy , co oznacza że nie schodzą w jednym punkcie.
Parametry DH UR5 (modyfikowany Craig, [m, rad])
| i | uwagi | ||||
|---|---|---|---|---|---|
| 1 | 0 | 0 | 0,089 | obrót podstawy | |
| 2 | 0 | 0 | bark | ||
| 3 | 0 | −0,425 | 0 | forma B: q₂ ∥ q₃ ∥ q₄ | |
| 4 | 0 | −0,392 | 0,109 | łokieć | |
| 5 | 0 | 0,095 | d₅ ≠ 0, forma A wykluczona | ||
| 6 | 0 | 0,082 | kołnierz |
Wniosek: dekompozycja 3+3 z M1 nie zadziała, nie istnieje „środek nadgarstka" jako wspólny punkt 3 ostatnich osi. Ale spełniona jest forma B (q₂ ∥ q₃ ∥ q₄), więc da się rozpisać rozwiązanie zamknięte, tylko innym algorytmem.
Metoda Hawkins/Kufieta (2013/2014): kolejność wyprowadzania to . W skrócie: z geometrii „cylindra zakazanego" wokół podstawy wyznacza się q₁ przez przekształcenia atan2 z d_5 jako stałym offsetem. Mając q₁, można wyizolować q₅ i q₆ z elementów macierzy. Mając konfigurację kiści, wracamy do podproblemu 3R-planarnego w pionowej płaszczyźnie po q₁, i z twierdzenia cosinusów (jak w M1) wyznaczamy q₂, q₃, q₄.
Liczba rozwiązań: 8, tak samo jak Pumy. Dwa branche shoulder × dwa elbow × dwa wrist. Pomimo zupełnie innej algebry, struktura rozwiązań pozostaje taka sama dla każdego manipulatora spełniającego jakąkolwiek formę Piepera.
ur_kinematics w ROS, ur_rtde w Pythonie, ikfast (autogenerowany z URDF), C++ w ur_robot_driver.W aplikacji nie implementujemy pełnej IK UR5, to wykraczałoby poza zakres modułu i wymagało osobnego modelu URDF. Skupiamy się tu na ES5 (mamy go już w M9–M11), dla którego mamy gotowe wyprowadzenie z dysertacji [Gruszka 2024, Załącznik A].
ES5 to manipulator firmy EasyRobots, dla którego M9 (dynamika) i M10 (silnik) korzystają z parametrów inercji. Tu domykamy pętlę, pokazujemy jego kinematyczne rozwiązanie IK. Geometrycznie ES5 jest podobny do UR (forma B, równoległość q₂, q₃, q₄), ale ma inne wymiary i konwencję DH.
Parametry DH ES5 (modyfikowany Craig, [m, rad])
źródło: src/lib/robots/es5.ts
| i | uwagi | ||||
|---|---|---|---|---|---|
| 1 | 0 | 0 | 0 | obrót podstawy | |
| 2 | 0 | 0 | bark | ||
| 3 | 0 | 0,425 | 0 | forma B: q₂ ∥ q₃ ∥ q₄ | |
| 4 | 0 | 0,395 | 0,1105 | łokieć z odsadzeniem d₄ | |
| 5 | 0 | 0,101 | kostka nadgarstka | ||
| 6 | 0 | 0,0765 | kołnierz końcówki |
Kolejność wyprowadzania współrzędnych w dysertacji: θ₁ → θ₅ → θ₆ → θ₃ → θ₂ → θ₄. Ta sekwencja nie jest oczywista, jest algebraicznie wymuszona faktem, że pewne równania trygonometryczne dają się rozwiązać tylko gdy znane są inne współrzędne. To kontrastuje z M1 (Puma), gdzie kolejność q₁ → q₂,₃ → q₄,₅,₆ wynikała wprost z dekompozycji formy A.
Poniżej pełne wyprowadzenie 6 współrzędnych zgodnie z Załącznikiem A dysertacji. Każdy krok zawiera referencję do oryginalnego numeru równania w pracy (eq. A.x).
Zadana jest macierz transformacji TCP względem bazy w postaci ogólnej (eq. A.1 z dysertacji):
Dla czytelności zapisu używamy w dysertacji skrótu i , oraz , itd. (skutek równoległości osi q₂, q₃, q₄, sumy ich kątów zachowują się jak jeden „efektywny" kąt).
Klucz wyprowadzenia: jeśli weźmiemy obliczone na dwa różne sposoby, analitycznie z parametrów DH, oraz przez izolację z zadanego przez mnożenie odwrotnościami, dostaniemy układ równań w którym pewne komórki zależą tylko od θ₁:
Analitycznie (z DH) ma w komórce y wektora translacji (drugi wiersz, czwarta kolumna) wartość stałą: . Z drugiej strony, po wykonaniu mnożenia po lewej i porównaniu, dostajemy równanie w którym jedyną niewiadomą jest :
Podstawienie helpers, pozycja środka nadgarstka (środka układu 5) rzutowana na xy bazy:
Po podstawieniu i wykorzystaniu wzoru na sin różnicy kątów:
Stąd ostateczna postać dla θ₁:
import numpy as np
# T_target: macierz 4x4 zadanej pozy efektora
R = T_target[:3, :3]
px, py = T_target[0, 3], T_target[1, 3]
r13, r23 = R[0, 2], R[1, 2]
# eq. A.6: środek układu 5 w bazie (cofamy się o d6 wzdłuż z6_world)
p5x = px - D6 * r13
p5y = py - D6 * r23
p5xy = np.hypot(p5x, p5y)
# eq. A.13: dwie gałęzie shoulder
asin_val = np.arcsin(np.clip(D4 / p5xy, -1, 1))
alpha = np.arctan2(p5y, p5x)
theta1_candidates = [
(alpha + asin_val, "right"),
(alpha + np.pi - asin_val, "left"),
]Dwa rozwiązania, odpowiadają dwóm konfiguracjom barku (shoulder-left / shoulder-right). Analog do gałęzi shoulder w M1.
Analiza struktury kinematycznej pokazuje, że współrzędna y wektora (translacja od początku ogniwa 2 do początku ogniwa 6) zależy wyłącznie od θ₅:
Z drugiej strony, ten sam można wyrazić przez obrót (eq. A.16–A.18):
Przyrównanie i wyizolowanie :
for theta1, shoulder in theta1_candidates:
c1, s1 = np.cos(theta1), np.sin(theta1)
cos5 = (px * s1 - py * c1 - D4) / D6
if abs(cos5) > 1:
continue
base_t5 = np.arccos(np.clip(cos5, -1, 1))
for wrist_sign in (+1, -1):
theta5 = wrist_sign * base_t5
# ... dalej θ₆ i (θ₃, θ₂, θ₄)Dwa rozwiązania, odpowiadają dwóm orientacjom kiści względem ogniwa 4 (analog do gałęzi wrist flip z M1).
Uwaga o pierwszej osobliwości: gdy , szósta oś obrotu staje się równoległa do osi 2, 3 i 4, pojawia się nadmiarowość stopni swobody (obrót osi 2, 3, 4 manipuluje TCP niezależnie od rotacji osi 6). To jest klasyczny wrist singularity analogiczny do Pumy.
Wyznaczając jawnie z parametrów DH (eq. A.21) i porównując z formą uzyskaną przez (eq. A.26–A.28), z komórek [2,1] oraz [2,2] dostajemy układ:
Stąd osobno i , i ich złożenie przez atan2:
c5, s5 = np.cos(theta5), np.sin(theta5)
r11, r12 = R[0, 0], R[0, 1]
r21, r22 = R[1, 0], R[1, 1]
if abs(s5) < EPS: # wrist singularity
theta6 = 0.0
else:
sin6 = ( s1 * r12 - c1 * r22) / s5
cos6 = (-s1 * r11 + c1 * r21) / s5
theta6 = np.arctan2(sin6, cos6)atan2 (a nie acos), żeby zachować pełen zakres . Dzielenie przez jest niesingularne dopóki .
Po znalezieniu θ₁, θ₅, θ₆ wracamy do zadania pozycji. Wyznaczamy przez ciąg mnożeń odwrotnościami:
Z geometrii (Rys. A.1 z dysertacji), robot rzutowany na płaszczyznę xz tworzy trójkąt o bokach , i przekątnej . Z twierdzenia cosinusów (jak w M1):
Stąd:
# Wylicz T_1_4 = (T_0_1)^-1 · T_target · (T_5_6)^-1 · (T_4_5)^-1
T01 = link_transform(0, theta1)
T45 = link_transform(4, theta5)
T56 = link_transform(5, theta6)
T14 = inv_se3(T01) @ T_target @ inv_se3(T56) @ inv_se3(T45)
p1x_4, _, p1z_4 = T14[:3, 3]
# Twierdzenie cosinusów dla trójkąta 2R w płaszczyźnie xz:
a2, a3 = A3, A4 # ramię i przedramię
p1n2 = p1x_4**2 + p1z_4**2
cos3 = (p1n2 - a2**2 - a3**2) / (2 * a2 * a3)
if abs(cos3) > 1:
continue
base_t3 = np.arccos(np.clip(cos3, -1, 1))
for elbow_sign in (+1, -1):
theta3 = elbow_sign * base_t3
# ... dalej θ₂, θ₄Dwa rozwiązania, gałęzie elbow-up i elbow-down, analog do M1.
Z tego samego rzutu (Rys. A.1) widzimy: , gdzie γ to kąt do , a α to wewnętrzny kąt trójkąta przy O₂. Wyrażając przez znane wielkości:
α z prawa sinusów dla trójkąta O₂O₃O₄:
Stąd:
c3, s3 = np.cos(theta3), np.sin(theta3)
K = a2 + a3 * c3
Mt = a3 * s3
theta2 = np.arctan2(K * p1z_4 - Mt * p1x_4,
K * p1x_4 + Mt * p1z_4)Ostatnia współrzędna, analogicznie do θ₆, ale na innym poziomie dekompozycji macierzy:
Z komórek [1,1] i [1,2] tej macierzy wyciągamy i jako kombinacje liniowe znanych już (eq. A.45, dwie długie formuły 6-składnikowe). Następnie:
T12 = link_transform(1, theta2)
T23 = link_transform(2, theta3)
T03 = T01 @ T12 @ T23
T34 = inv_se3(T03) @ T_target @ inv_se3(T56) @ inv_se3(T45)
theta4 = np.arctan2(-T34[0, 1], T34[0, 0])
solutions.append((theta1, theta2, theta3, theta4, theta5, theta6))Komplet wzorów (eq. A.47–A.52 z dysertacji), gotowe do wstawienia do kodu solvera analitycznego dla ES5:
Liczba rozwiązań: 2 (shoulder θ₁) × 2 (elbow θ₃) × 2 (wrist θ₅) = 8 konfiguracji, identycznie jak dla Pumy 560, choć geometria jest zupełnie inna. To uniwersalny wynik dla manipulatorów 6-DOF spełniających jakąkolwiek formę warunku Piepera.
| Cecha | PUMA 560 (M1) | UR5 (Hawkins/Kufieta) | ES5 (Gruszka 2024) |
|---|---|---|---|
| Forma Piepera | A (osie 4,5,6 schodzą) | B (osie 2,3,4 równoległe) | B (osie 2,3,4 równoległe) |
| DOF | 6 | 6 | 6 |
| Liczba rozwiązań | 8 | 8 | 8 |
| Kolejność wyprowadz. | q₁ → q₂,q₃ → q₄,q₅,q₆ | q₁ → q₅,q₆ → q₂,q₃,q₄ | q₁ → q₅ → q₆ → q₃ → q₂ → q₄ |
| Środek nadgarstka | TAK, w punkcie przecięcia osi 4,5,6 | NIE, osie nie schodzą (d_5 ≠ 0) | NIE, osie nie schodzą |
| Singularności | oś 1, łokieć wew./zew., nadgarstek | cylinder zakazany, łokieć, nadgarstek | analogiczne do UR (θ₅=0 → wrist) |
| Typowe zastosowanie | przemysł motoryzacyjny, edukacja | cobot, lekkie zadania, lead-through | cobot/przemysł, dydaktyka dysertacji |
Wniosek dydaktyczny: mimo zupełnie różnych geometrii i algorytmów wyprowadzania, liczba rozwiązań (8) i ogólna struktura wyboru (shoulder × elbow × wrist) są uniwersalne dla każdego manipulatora 6-DOF spełniającego warunek Piepera. To głęboka prawda: forma rozwiązania zależy od geometrii, ale liczba i typ branch'y, od struktury problemu IK.
Franka Emika Panda łamie wszystkie założenia, na których opierał się ten moduł, bo ma siedem stopni swobody zamiast sześciu. Dla zadania SE(3) (6-DOF) oznacza to nadmiarowość 1 DOF: dla każdej osiągalnej pozy końcówki istnieje cała ciągła rodzina konfiguracji (parametryzowana jednym dodatkowym kątem, zwykle nazywanym kątem łokcia albo swivel angle).
Konsekwencje:
Pełne wyprowadzenie 7-DOF IK wykracza poza ten moduł, wymaga osobnego materiału z parametryzacją kąta łokcia, obsługą singularności łokcia (gdy oś 4 jest prawie wyprostowana) i integracją z null-space optymalizacją. Sugestia: prześledź P. Beeson & B. Ames (2015) „TRAC-IK", niereferencyjna ale praktycznie stosowana biblioteka działająca na Franka, UR i Pumie.
Sześć snippetów Python z kroków 1–6 wyprowadzenia powyżej, połączone w jedną funkcję solve_es5_ik(T_target). Zwraca listę do 8 rozwiązań (krotki 6 kątów), zgodnie z gałęziami shoulder × elbow × wrist.
import numpy as np
# Parametry DH ES5 (modified Craig), z src/lib/robots/es5.ts:
A3 = 0.425 # ramię
A4 = 0.395 # przedramię
D4 = 0.1105 # odsadzenie przedramienia
D5 = 0.101 # kostka nadgarstka
D6 = 0.0765 # wystawienie końcówki
EPS = 1e-9
def solve_es5_ik(T_target, link_transform, inv_se3):
"""
Analityczne IK dla ES5 (forma B Piepera) wg Załącznika A
dysertacji [Gruszka 2024].
link_transform(i, theta_i), macierz 4×4 ⁱ⁻¹T_i z DH (Craig).
inv_se3(T), szybka odwrotność SE(3): R^T blok + -R^T·t.
Obie funkcje musisz dostarczyć (kilka linijek każda).
Zwraca: list[tuple[float, ...]], do 8 krotek (q1..q6).
"""
R = T_target[:3, :3]
px, py = T_target[0, 3], T_target[1, 3]
r11, r12, r13 = R[0]
r21, r22, r23 = R[1]
# === Krok 1: θ₁ (dwie gałęzie shoulder) ===
p5x = px - D6 * r13
p5y = py - D6 * r23
p5xy = np.hypot(p5x, p5y)
if p5xy < EPS:
return []
ratio = D4 / p5xy
if abs(ratio) > 1:
return []
asin_val = np.arcsin(np.clip(ratio, -1, 1))
alpha = np.arctan2(p5y, p5x)
theta1_candidates = [
(alpha + asin_val, "right"),
(alpha + np.pi - asin_val, "left"),
]
solutions = []
for theta1, shoulder in theta1_candidates:
c1, s1 = np.cos(theta1), np.sin(theta1)
# === Krok 2: θ₅ (dwie gałęzie wrist) ===
cos5 = (px * s1 - py * c1 - D4) / D6
if abs(cos5) > 1:
continue
base_t5 = np.arccos(np.clip(cos5, -1, 1))
for wrist_sign in (+1, -1):
theta5 = wrist_sign * base_t5
c5, s5 = np.cos(theta5), np.sin(theta5)
# === Krok 3: θ₆, atan2(sin θ₆, cos θ₆) z komórek ⁶R₁ ===
if abs(s5) < EPS:
theta6 = 0.0
else:
sin6 = ( s1 * r12 - c1 * r22) / s5
cos6 = (-s1 * r11 + c1 * r21) / s5
theta6 = np.arctan2(sin6, cos6)
# === T_1_4 numerycznie (cofamy się przez T_5_6, T_4_5) ===
T01 = link_transform(0, theta1)
T45 = link_transform(4, theta5)
T56 = link_transform(5, theta6)
T14 = inv_se3(T01) @ T_target @ inv_se3(T56) @ inv_se3(T45)
p1x_4, _, p1z_4 = T14[:3, 3]
# === Krok 4: θ₃ (dwie gałęzie elbow) ===
a2, a3 = A3, A4
p1n2 = p1x_4**2 + p1z_4**2
cos3 = (p1n2 - a2**2 - a3**2) / (2 * a2 * a3)
if abs(cos3) > 1:
continue
base_t3 = np.arccos(np.clip(cos3, -1, 1))
for elbow_sign in (+1, -1):
theta3 = elbow_sign * base_t3
# === Krok 5: θ₂ (z układu liniowego K·c2 - M·s2 = p1x, ...) ===
c3, s3 = np.cos(theta3), np.sin(theta3)
K = a2 + a3 * c3
Mt = a3 * s3
theta2 = np.arctan2(K * p1z_4 - Mt * p1x_4,
K * p1x_4 + Mt * p1z_4)
# === Krok 6: θ₄ (z elementu T_3_4) ===
T12 = link_transform(1, theta2)
T23 = link_transform(2, theta3)
T03 = T01 @ T12 @ T23
T34 = inv_se3(T03) @ T_target @ inv_se3(T56) @ inv_se3(T45)
theta4 = np.arctan2(-T34[0, 1], T34[0, 0])
solutions.append((theta1, theta2, theta3, theta4, theta5, theta6))
return solutionsCo warto zauważyć: kolejność wyprowadzania współrzędnych jest algebraicznie wymuszona, najpierw θ₁ z geometrii rzutu, potem θ₅ i θ₆ z analizy macierzy , dopiero na końcu θ₃, θ₂, θ₄ z numerycznie wyliczonej . To inna kolejność niż klasyczna dekompozycja 3+3 Pumy z M1, bo geometria ES5 (forma B) wymaga innego rozdzielenia.
Powyższy algorytm Python jest 1:1 przetłumaczony do TypeScriptu jako src/lib/solvers/analytical-es5.ts w aplikacji. Wersja TS jest używana w playgroundzie poniżej (interaktywne wyznaczanie 8 rozwiązań na żywo). Przechodzi smoke test FK→IK→FK na 5 konfiguracjach z błędem maszynowej precyzji (~10⁻¹⁵ rad).
# Uruchom test:
npx tsx src/lib/solvers/__es5_smoke.ts
# Użycie:
import { solveEs5Analytical } from "@/lib/solvers/analytical-es5";
import { forwardKinematics } from "@/lib/robots/dh";
import { ES5 } from "@/lib/robots/es5";
const target = forwardKinematics(ES5, [0.3, 0.4, 0.5, 0.6, 0.7, 0.8]);
const solutions = solveEs5Analytical(target);
// solutions: do 8 rozwiązań z gałęziami shoulder/elbow/wristPlayground ma dwa równoległe stany:
Wskaźnik TCP odbiega od T* o ... mm mówi czy aktualne q faktycznie trafia w T*. Kliknięcie wiersza w tabeli rozwiązań ładuje wybraną gałąź do sliderów, robot ustawia się tam i wskaźnik staje się zielony.
Eksperymenty do wypróbowania:
z = 0.05 (TCP nisko nad podłożem), większość rozwiązań prawdopodobnie odpadnie (poza zasięgiem ramienia w dół). Zobaczysz krótszą listę albo komunikat „brak rozwiązań".Rozwiązania IK z pozy docelowej: 0(maks. 8, shoulder × elbow × wrist)
kliknij żeby załadować
Brak rozwiązań, poza zasięgiem albo geometryczna degeneracja. Spróbuj zmienić pozycję lub orientację w panelu po prawej.
S=shoulder (left/right), E=elbow (up/down), W=wrist (flip/noflip). Wiersz w kolorze zielonym to gałąź, do której aktualnie ustawione są przeguby. Klikając inny wiersz załadujesz tę konfigurację, robot trafi w tę samą pozę docelową inną drogą.
analytical-es5.ts) jest gotowy, może być teraz wpięty do M6 (Benchmark) jako drugi analityk obok Pumy.