Wykrywanie kolizji
GJK, EPA, MPR, SAT, BVH/AABB/OBB/k-DOP, CCD, distance queries i gradient SDF, GPU collision, self-collision Pandy.
TL;DR
Każde zapytanie „czy konfiguracja jest bezpieczna?" w końcu sprowadza się do testowania kolizji między kawałkami geometrii (linki robota ↔ przeszkody ↔ inne linki). Ten moduł kataloguje algorytmy:
- Narrow-phase (kolizja para-na-parę): GJK, EPA, MPR, SAT.
- Broad-phase (które pary w ogóle sprawdzać): BVH (AABB-tree, OBB-tree, k-DOP), sweep-and-prune, spatial hashing.
- CCD (Continuous Collision Detection): wykrywanie kolizji między dyskretnymi klatkami symulacji.
- Distance queries + gradient SDF — dla CHOMP / CBF / fabrics, gdzie potrzeba „odpychającej" siły.
- Self-collision — szczególny przypadek dla manipulatora; reduktor: Allowed Collision Matrix.
Reguła kciuka dla planowania manipulatorów: ~80% czasu sampling-based planera (RRT*, BIT*) spędza w collision checking. Optymalizacja tej warstwy jest kluczowa dla performance.
GJK — Gilbert-Johnson-Keerthi
Idea: dwa wypukłe zbiory kolidują wtedy i tylko wtedy, gdy ich różnica Minkowskiego zawiera origin:
GJK nie buduje jawnie (drogie). Zamiast tego iteracyjnie konstruuje simplex (1-, 2- lub 3-punktowy w 2D; do 4 w 3D) wewnątrz , próbując „objąć" origin. W każdej iteracji dodaje support point w aktualnym kierunku ku origin.
Kluczowy lemmat: jeśli istnieje plane separujący i (czyli ), to w pewnej iteracji wystąpi:
GJK zwraca odpowiedź w średnio 4-8 iteracjach dla 3D wielokątów. Złożoność per iteracja gdzie = liczby wierzchołków .
GJK — krok 1 / 3
⟳ iteratingPokrewne i rozszerzenia
- EPA (Expanding Polytope Algorithm) — gdy GJK wykryje kolizję, EPA znajduje penetration depth i kierunek separacji (potrzebne dla rozwiązania kontaktu).
- MPR (Minkowski Portal Refinement) — alternatywa GJK + EPA z prostszym kodem, podobny performance.
- SAT(Separating Axis Theorem) — dla wielokątów: sprawdza projekcje na osie krawędzi. Szybsze dla małej liczby wierzchołków (boxes), wolniejsze dla wielokątów > 100 vertices.
- libccd, FCL, Bullet — biblioteki C++ implementujące GJK+EPA z optymalizacjami (caching simplex między klatkami).
BVH — Bounding Volume Hierarchy
GJK testuje jedną parę w ms. Ale w scenie z setkami obiektów (manipulator + półki + obiekty) liczba par to — niedopuszczalne. Stąd potrzebny broad-phase: szybkie odrzucanie par, które na pewno nie kolidują.
BVH organizuje obiekt w drzewo bounding volumes (zwykle AABB lub OBB). Korzeń = AABB całego obiektu. Każdy węzeł wewnętrzny ma dwoje dzieci z mniejszymi AABB. Liście = pojedyncze trójkąty.
Test kolizji dwóch obiektów = jednoczesny obchód obu drzew:
function intersect(nodeA, nodeB):
if not AABB_intersect(nodeA.aabb, nodeB.aabb):
return false
if both are leaves:
return triangle_test(nodeA.tri, nodeB.tri)
recursively test childrenW typowych scenach koszt zapytania spada z do + linear cost na liście.
Bounding Volume Hierarchy — poziom 2 (4 AABB)
Po co: sprawdzając kolizję obiekt-obiekt, najpierw pytamy: czy ich korzenie się przecinają? Jeśli nie — koniec (O(1)). Jeśli tak — rekursywnie schodzimy po dzieciach. Dla dwóch obiektów po n trójkątów dostajemy O(n log n) zamiast O(n²) naiwnego sprawdzania.
Warianty bounding volumes
- AABB (Axis-Aligned BB) — 6 floats (xMin..zMax). Najtańszy test, ale luźne dla obrotowych obiektów.
- OBB (Oriented BB) — z 3D rotacją. Ciasne, ale test droższy (15 osi separacji per parze).
- k-DOP (Discrete Oriented Polytope) — k par normal-aligned half-spaces. Kompromis AABB/OBB; popularne k = 14, 18, 26.
- Sphere — 4 floats. Mega tani test, bardzo luźny (zwykle ostatni resort).
Convex decomposition: dla nie-wypukłych mesh'y (np. linków Pandy) BVH + GJK nie wystarcza — narzędzia jak V-HACD dekomponują geometrię na sumę wypukłych części, każda z osobnym narrow-phase.
CCD — Continuous Collision Detection
Dyskretny collision check sprawdza kolizję tylko w chwilach . Jeśli obiekt porusza się szybko, między a może przeskoczyć przez przeszkodę — kolizja niewykryta.
CCD wykrywa time-of-impact — pierwszą chwilę, w której obiekty stykają się. Najprostsza forma: swept volume — obejmujemy całą trajektorię obiektu między klatkami jednym objętym AABB, testujemy z geometrią statycznej sceny.
W manipulatorze CCD jest kluczowe podczas wykonania zaplanowanej trajektorii — bez niego szybkie ruchy (q̇ ~ 2 rad/s) mogą wjechać w przeszkodę między cyklami sterownika (1 kHz).
CCD vs Discrete — efekt tunelowania
Algorytmy CCD w praktyce
- Swept-AABB vs static obstacle — najprostsze, wystarcza dla pocisków / mobile robotów.
- Continuous GJK (Bergen 2003) — sweep'owy GJK z parametryzacją czasem. Złożone, ale dokładne.
- Conservative advancement — iteracyjnie advance'uj symulację o czas mniejszy niż TOI, aż osiągniesz kontakt z toleracją.
- FCL implementuje conservative advancement z GJK podstawy.
Distance queries i gradient
Często potrzebujemy więcej niż „jest/brak kolizji" — chcemy odległość do najbliższej przeszkody i kierunek, w którym się oddalać. To podstawa:
- CHOMP / TrajOpt (moduł 07): gradient SDF wokół przeszkód działa jak siła wypychająca trajektorię.
- CBF-QP (moduł 12): bezpieczeństwo formalne — ograniczenie .
- Reactive control (moduł 09): pola potencjałowe, fabrics.
GJK rozszerzony o zwracanie najbliższych punktów daje:
gdzie to najbliższe punkty na powierzchni każdego obiektu. Dla SDF (moduł 03) gradient jest natywny i ciągły.
Praktyczna kombinacja w cuRobo / NVIDIA Warp: SDF voxel grid przeszkód (na GPU) + analityczne SDF kapsuł dla ogniw Pandy (sferi + walce) → tysiące jednoczesnych queries dla batched MPC.
GPU collision — krótki przegląd
CPU collision check w pętli rolloutów MPPI (K = 1000 trajektorii × H = 30 kroków = 30 000 queries per iteracja, przy 50 Hz = 1.5M/s) szybko staje się wąskim gardłem. GPU pozwala na batched parallel queries:
- cuRobo(NVIDIA, 2023) — pełen kinodynamic stack na CUDA. Collision check oparty na sphere SDF dla ogniw + voxel SDF przeszkód. Tysiące rolloutów w < 10 ms.
- NVIDIA Warp — Python ↔ CUDA framework dla physics. Implementacja BVH + GJK na GPU dostępna w warp.sim.
- Isaac Sim / Isaac Lab — pełna fizyka GPU dla RL, używa PhysX-based collision.
- Flex / FleX — granular / soft body GPU collision.
Aplikacja webowa (ten projekt) używa CPU collision — JS nie ma dostępu do CUDA. Dla rzeczywistego deployment na manipulatorze z GPU rekomendacja: cuRobo (open-source, integrowany z ROS2).
Self-collision Pandy
Manipulator 7-DOF (i więcej) może sam się ze sobą zderzyć — przedramię z barkiem, gripper z bazą. Bez self-collision checking planer może zwrócić „idealną" trajektorię, która w praktyce zniszczy robota.
Naiwne podejście: dla wszystkich par ogniw wykonaj collision check. Dla Pandy: par. Większość jest jednak trywialna:
- Sąsiednie ogniwa (dzielące staw) zawsze się stykają — bez sensu sprawdzać.
- Pary fizycznie nieosiągalne (baza ↔ link 1) — ignored.
- Pary o znikomym prawdopodobieństwie kolizji można też wyłączyć dla performance.
Allowed Collision Matrix (ACM)zapisuje, które pary są aktywnie sprawdzane. MoveIt2 generuje ACM automatycznie przez próbkowanie 10 000 random configs i wyłączenie par, które kolidują > 95% przypadków (zawsze stykające) lub < 0.1% (nigdy). Reszta to faktycznie ryzykowne kombinacje.
Macierz par self-collision (8 ogniw, 27/28 aktywne)
| link0 | link1 | link2 | link3 | link4 | link5 | link6 | link7 | hand | |
|---|---|---|---|---|---|---|---|---|---|
| link0 | |||||||||
| link1 | |||||||||
| link2 | |||||||||
| link3 | |||||||||
| link4 | |||||||||
| link5 | |||||||||
| link6 | |||||||||
| link7 | |||||||||
| hand |
Ściąga
Hierarchia testów (broad → narrow → continuous)
- Broad-phase: BVH / sweep-and-prune — wybierz pary mogące kolidować.
- Narrow-phase: GJK / EPA / SAT — dokładny test kolizji + penetration depth.
- Continuous: CCD — wykrywa tunneling przy szybkim ruchu.
- Distance / SDF: dla planerów z gradientem (CHOMP, TrajOpt, CBF).
GJK w jednym akapicie
. Iteracyjnie buduj simplex (≤3 wierzchołki w 2D, ≤4 w 3D) wewnątrz . W każdej iteracji dodaj support point w kierunku ku origin. Jeśli — origin poza ⇒ brak kolizji. Jeśli simplex zawiera origin ⇒ kolizja.
ACM dla Pandy
Wyłącz pary sąsiednie i fizycznie nieosiągalne. Z 28 par typowo zostaje 10-15 aktywnych. Generowane automatycznie w MoveIt2 przez sampling configs.
Reguła kciuka
~80% czasu sampling-based planera (RRT*, BIT*) idzie w collision checking. Optymalizacja tej warstwy ma największy wpływ na czas planowania.
Referencje do dalszej lektury
- Gilbert, Johnson & Keerthi, „A Fast Procedure for Computing the Distance Between Complex Objects in Three-Dimensional Space" (IEEE J. Robotics & Automation, 1988) — oryginalny paper GJK.
- van den Bergen, Collision Detection in Interactive 3D Environments (Morgan Kaufmann, 2003) — kanoniczny podręcznik (GJK, EPA, CCD, BVH).
- Pan, Chitta & Manocha, „FCL: A General Purpose Library for Collision and Proximity Queries" (ICRA 2012). FCL GitHub.
- Coumans, Bullet Physics — implementacja referencyjna GJK + EPA + CCD w C++. pybullet.org.
- Cohen, Lin, Manocha & Ponamgi, „I-COLLIDE: An Interactive and Exact Collision Detection System for Large-Scale Environments" (SIGGRAPH I3D 1995) — sweep-and-prune.
- Sundaralingam et al., „cuRobo: Parallelized Collision-Free Robot Motion Generation" (ICRA 2023). curobo.org.
- MoveIt2 docs — Allowed Collision Matrix generation. collision_checking.