irsim.lib.algorithm.contact#
Rigid-body contact resolution for the contact collision mode.
Objects that overlap after a kinematic step are separated along their
contact normal. Between two passive bodies, or two driven ones, the
separation is shared in inverse proportion to their masses, which is the
perfectly inelastic collision of position-based dynamics. A driven object
(one with kinematics) pushes a passive body without yielding to it, as a
velocity-controlled robot in a physics engine does, provided its traction,
friction * mass, is at least the body's ground friction; a body it
cannot overcome stalls it. An immovable object (static or infinite mass)
stops whatever presses on it, which then slides along the surface: a robot
always, a passive body only when the push leaves the friction cone of the
two surfaces. Passive bodies keep the velocity a push gave them and coast to
a stop under ground friction, which their kinematics model integrates.
A push that misses a body's center also turns it: the contact point and
normal give a torque, shared through each body's moment of inertia as in
position-based rigid-body dynamics, and a spinning passive body slows under
friction like a sliding one. Driven objects keep their heading, which their
drive holds.
The contact normal and depth come from the separating axis theorem (SAT) evaluated between convex pieces of the two shapes: circles, convex polygons, and line segments. Non-convex polygons are triangulated with a constrained Delaunay triangulation, so every shape IR-SIM supports takes part, including compound bodies, linestring walls, and grid maps.
The resolution follows position-based dynamics: each overlap is a unilateral distance constraint, projected one pair at a time in Gauss-Seidel sweeps with the correction weighted by inverse mass, and the velocity of a body is recovered from its position change. Pairs are swept outward from immovable objects, and a body that was just pressed against something it cannot move only yields tangentially for the rest of the sweep, a simplified form of shock propagation, so that a chain pushed into a wall settles in one sweep and slides along it.
引用
Müller, M., Heidelberger, B., Hennix, M., Ratcliff, J. (2007), Position based dynamics. J. Vis. Commun. Image Represent. 18(2):109. Mass-weighted constraint projection, Gauss-Seidel iteration over the constraints, and velocities derived from the position update.
Macklin, M., Müller, M., Chentanez, N. (2016), XPBD: position-based simulation of compliant constrained dynamics. Proc. Motion in Games, p. 49. Müller, M., Macklin, M., Chentanez, N., Jeschke, S., Kim, T.-Y. (2020), Detailed rigid body simulation with extended position based dynamics. Comput. Graph. Forum 39(8):101. The rigid-body form of the same projection.
Guendelman, E., Bridson, R., Fedkiw, R. (2003), Nonconvex rigid bodies with stacking. ACM Trans. Graph. 22(3):871. Shock propagation: contacts are processed outward from immovable objects and settled bodies are treated as immovable, which the anchored sweep order and the blocked directions here simplify to a single pass.
Gottschalk, S., Lin, M. C., Manocha, D. (1996), OBBTree: a hierarchical structure for rapid interference detection. Proc. SIGGRAPH, p. 171. Ericson, C. (2005), Real-Time Collision Detection. Morgan Kaufmann, chapter 5. The separating axis theorem that gives the contact normal and depth between two convex pieces.
Catto, E. (2005), Iterative dynamics with temporal coherence. Game Developers Conference; and Box2D (https://box2d.org). Sequential per-pair resolution, the linear slop left between separated bodies, and the fattened bounding boxes of the broad phase.
Chew, L. P. (1989), Constrained Delaunay triangulations. Algorithmica
4:97, as implemented by GEOS and exposed through
shapely.constrained_delaunay_triangles(), for the convex
decomposition of non-convex polygons.
Author: Ruihua Han assisted by claude
Attributes#
Classes#
One resolved contact between two objects. |
|
One contact of an object, seen from its own side: what a contact |
Functions#
|
Decompose a shapely geometry into convex pieces. |
|
Convex pieces of an object at its current pose. |
|
Minimum translation that separates convex piece |
|
Deepest minimum translation between two objects. |
|
Separate overlapping object pairs, sharing each correction by mass. |
Module Contents#
- irsim.lib.algorithm.contact.CONTACT_SLOP = 1e-06#
- irsim.lib.algorithm.contact.REST_TOLERANCE = 9.999999999999999e-06#
- irsim.lib.algorithm.contact.CONTACT_ITERATIONS = 32#
- irsim.lib.algorithm.contact.Piece#
- class irsim.lib.algorithm.contact.Contact[源代码]#
One resolved contact between two objects.
- 变量:
a -- First object;
normalpoints frombtoward it.b -- Second object.
normal -- Unit contact normal
(2,)pointing frombtoa.depth -- Penetration depth that was removed, in meters; zero or negative for a resting contact, which moved nothing.
point -- World-frame contact point
(2,), midway through the overlap.force -- Contact force along
normalin newtons, the constraint impulse over the squared step time as XPBD estimates it, capped at the traction of a driven object pushing into the contact;0when the step time was not given.
- a: Any#
- b: Any#
- normal: numpy.ndarray#
- depth: float#
- point: numpy.ndarray | None = None#
- force: float = 0.0#
- report(obj: Any) ContactReport[源代码]#
This contact as seen from
obj, one of its two objects.
- class irsim.lib.algorithm.contact.ContactReport[源代码]#
One contact of an object, seen from its own side: what a contact sensor mounted on it would report.
- 变量:
other -- The object it touched.
point -- World-frame contact point
(2,).normal -- Unit normal
(2,)pointing fromothertoward the object, the direction it is being pushed in.depth -- Overlap that was pushed apart in meters; zero or negative for a resting contact.
force -- Contact force along
normalin newtons.
- other: Any#
- point: numpy.ndarray#
- normal: numpy.ndarray#
- depth: float#
- force: float#
- irsim.lib.algorithm.contact.geometry_pieces(geometry: shapely.geometry.base.BaseGeometry, bounds: tuple | None = None) list[Piece][源代码]#
Decompose a shapely geometry into convex pieces.
Polygons become themselves when convex, otherwise their constrained Delaunay triangles. Lines become their segments, restricted to those whose bounding box meets
boundswhen given. Points contribute nothing.- 参数:
geometry -- Any shapely geometry or collection.
bounds -- Optional
(minx, miny, maxx, maxy)filter for line segments.
- 返回:
Convex pieces as
("polygon", vertices (N, 2))tuples.- 返回类型:
list
- irsim.lib.algorithm.contact.object_pieces(obj: Any, other: Any | None = None) list[Piece][源代码]#
Convex pieces of an object at its current pose.
A
circleis kept exact. Acompounduses its parts. Amaponly contributes the boundary segments nearother(the object it is tested against), found through its own spatial index.- 参数:
obj -- The object to decompose.
other -- The object it is in contact with, used to restrict map segments.
- 返回:
Convex pieces.
- 返回类型:
list
- irsim.lib.algorithm.contact.Mtv#
- irsim.lib.algorithm.contact.piece_mtv(a: Piece, b: Piece, tolerance: float = 0.0) Mtv | None[源代码]#
Minimum translation that separates convex piece
afromb.- 参数:
a -- Convex piece to move.
b -- Convex piece it overlaps.
tolerance -- Gap up to which separated pieces still count as a contact, reported with a negative depth.
- 返回:
(normal, depth, point)where the unitnormalpoints frombtowarda, movingabynormal * depthseparates the pieces, andpointis the contact point midway through the overlap;Nonewhen they do not overlap. Exactly touching pieces count as a zero-depth contact, since shapely reports them as intersecting.- 返回类型:
tuple | None
- irsim.lib.algorithm.contact.object_mtv(a: Any, b: Any, cache: dict[Any, list[Piece]] | None = None) Mtv | None[源代码]#
Deepest minimum translation between two objects.
Every convex piece of
ais tested against every piece ofb, and the deepest overlap wins; shallower overlaps with other pieces are resolved by later sweeps or steps.- 参数:
a -- Object to move along the returned normal.
b -- Object it overlaps.
cache -- Optional pieces cache keyed by
id(obj), shared across the sweeps of one resolution; map pieces depend on the partner and are never cached.
- 返回:
(normal, depth, point)with the normal pointing frombtoa, orNonewhen no pieces overlap.- 返回类型:
tuple | None
- irsim.lib.algorithm.contact.contact_step(pairs: list[tuple[Any, Any]], iterations: int = CONTACT_ITERATIONS, slop: float = CONTACT_SLOP, margin: float = 0.0, step_time: float | None = None) list[Contact][源代码]#
Separate overlapping object pairs, sharing each correction by mass.
One call resolves the contacts of one simulation step, in three stages:
Order: pairs that nothing can move are dropped, and the rest are sorted by their contact-graph distance from immovable objects (
_anchored_order()), so a wall contact is handled before the robot contact behind it.Sweep: Gauss-Seidel passes over the pairs. Each overlapping pair is separated along its contact normal:
amoves bydepth * w_a / (w_a + w_b)andbby the rest, wherewis the inverse mass (zero for static or infinite-mass objects, which never move). Within a sweep, an object that was just pressed against something it cannot move only yields tangentially afterwards and its partner takes the rest, so a chain pushed into a wall settles in one sweep and a box pushed obliquely into a wall slides along it. Sweeps repeat until one moves nothing, oriterationsis reached. A pair resting withinREST_TOLERANCEof each other needs no correction but still blocks: a box resting on a wall is not pushed into it and back out again within a sweep.Apply: the sweeps work on translated copies of each object's convex pieces and accumulate one displacement per object, applied at the end through
apply_contact_displacement(), which also folds it into the object's velocity.
Both objects of every resolved pair are marked as in contact with each other.
- 参数:
pairs -- Candidate
(a, b)object pairs. They should include every pair that a correction could bring into contact, e.g. all pairs within one step's travel of each other, not only the pairs that intersect after the kinematic step; pairs that never overlap are skipped.iterations -- Maximum sweeps over the pairs.
slop -- Extra gap left between separated bodies.
margin -- How far an object may be moved by the sweeps, used to fetch enough grid-map boundary around each candidate up front.
step_time -- Simulation step, needed to report contact forces and to apply restitution; without it forces stay
0and nothing bounces.
- 返回:
One entry per pair that touched, in the order of the first sweep that found it, carrying its deepest push; a positive
depthmeans the pair was pushed apart, otherwise the two only rest against each other.- 返回类型:
list[Contact]