Section 6.3: Contact, friction, and why contact-rich sim is hard

"Contact does not arrive smoothly. It arrives as an interruption, and the simulator must decide what the world looks like on the other side of it."

A Frustrated Collision Solver
Technical illustration for Section 6.3: Contact, friction, and why contact-rich sim is hard.
Figure 6.3A: A robot foot making and breaking contact with a surface, showing how the contact force switches abruptly, why rigid-body simulation struggles at the instant of collision, and how Linear Complementarity Problem (LCP) solvers handle the discontinuity.

This section assumes familiarity with rigid-body dynamics from section 6.1 (forces, torques, and inertia) and the manipulator equation from section 6.2. The numerical challenges introduced here are addressed directly in section 6.4, which covers integration schemes chosen specifically to cope with the stiff, discontinuous dynamics that contact creates. The contact models and LCP solvers described here reappear in Part 3, chapter 11, where MuJoCo, Isaac Lab, and Genesis each make different engineering trade-offs to handle exactly these difficulties at simulation scale.

Big Picture

Figure 6.3A shows the moment that breaks everything: a robot foot making and breaking contact, with the contact force switching abruptly as the surface is touched and released. A robot hand reaches for a cup. The fingers are millimeters away, the simulation is running smoothly, and then, in a single timestep, they touch. At that instant the equations of motion change structure, velocities can jump discontinuously, and the solver must decide in microseconds whether each contact point is sticking or sliding. Get it wrong and the cup teleports, the fingers vibrate at 10 kHz, or the whole scene explodes. This is the core challenge of contact-rich simulation, and it is the reason robots trained in sim so often fail the moment they touch the real world. Right now, as labs race to train manipulation policies at scale, the quality of a contact solver is the hidden bottleneck. Here you will build the mathematical vocabulary for collision geometry, restitution, and the Coulomb friction cone, and see exactly why the combinatorial structure of contact makes every simulator a careful engineering compromise.

Your grasp policy reports 95 percent success in simulation, ships to the real Franka, and the mug slips through its fingers on the first try: the gap is almost never the controller and almost always a single line in the MuJoCo contact log you never read. The vocabulary that exposes it, signed separation (the gap between two surfaces, positive when apart, zero at touch, and negative when interpenetrating), the coefficient of restitution, the Coulomb friction cone, and the stick/slide active set, is what this section builds. We define each on the simplest possible system, a point mass hitting a floor, then connect it to the case that actually breaks policies: a Franka Panda hand closing on a mug, where 20 fingertip contacts must each resolve as stick or slide every 2 ms.

The practical question is the one every sim-to-real failure eventually forces: when an IsaacGym policy reports 95 percent grasp success but the real Franka drops the object, was the grasp real or did the policy exploit a 20 mm contact shell? Answering that requires reading penetration depth and stick/slide mode out of the contact solver, not just the reward curve.

Action Is The Test

A representation earns its place when it changes the measurable action interface. In Contact, friction, and why contact-rich sim is hard, the reader should keep asking which decision becomes easier, safer, or more reliable.

Theory

Contact is fundamentally different from the rest of dynamics. Between contacts, a robot's equations of motion are smooth ordinary differential equations: forces are continuous, accelerations are continuous, and standard integrators work well. The moment two bodies touch, a constraint force appears instantaneously. Velocities can jump discontinuously: a bouncing ball reverses its normal velocity in zero time. An infinitesimal change in configuration can flip the set of active constraints. Better hardware or a smaller timestep will not cure this. It is a structural property of rigid-body mechanics. At every step, the simulator must choose which contacts are active and whether each one is sticking or sliding, a choice called the active set, meaning the specific subset of contacts currently exerting force and the stick-or-slide mode assigned to each. That combinatorial decision changes the equations the integrator solves. A five-fingered hand grasping a mug can have 20 simultaneous contact points. Each can independently stick or slide, giving \(2^{20}\) (over one million) possible active sets to evaluate every millisecond. The scale grows fast. A locomotion policy trained on a flat floor with two foot contacts converges in roughly 5,000 rollouts. The same policy trained on terrain with 20 simultaneous contact points can require over 500,000 rollouts to reach the same reward, because each new contact mode is effectively a new problem the policy has never seen. This is the combinatorial explosion of contact modes, and it is the root reason contact-rich simulation is hard.

Think of a five-fingered hand grasping a mug the way a chef grips a slippery wet tomato: every finger can either grip (stick) or skid (slide) independently, and which combination the hand ends up in depends on tiny differences in surface moisture and squeeze angle. With five fingers and two choices each, there are already 32 possible grip states, and the chef's hand must settle into one of them in a fraction of a second. A robot hand with 20 contact points faces more than a million such combinations, and the simulator must evaluate and resolve the correct one at every millisecond timestep. That is the combinatorial explosion, and no amount of faster hardware eliminates it because the number of combinations grows exponentially with the number of contact points, not with the speed of the processor.

A policy trained where contact is wrong does not learn to grasp objects; it learns to exploit the simulator's tolerance for overlap. The friction-cone diagram below makes both halves of this concrete: on the left, a single contact's impulse either lands inside the Coulomb cone (stick) or on its boundary (slide); on the right, N such independent stick-or-slide choices multiply into the \(2^N\) mode combinations the solver must sort through every timestep.

Contact Mode Decision: Friction Cone and Stick vs Slide J_n |J_t| = mu*J_n stick (inside) slide (boundary) Coulomb Friction Cone active-set decision contact_1 stick | slide contact_2 stick | slide ... contact_N stick | slide 2^N modes Mode Combinations
The Coulomb friction cone (left) governs whether each contact point sticks (impulse inside the cone) or slides (impulse on the cone boundary). With N simultaneous contact points, the simulator must resolve 2^N possible stick/slide mode combinations at every timestep, producing the combinatorial explosion that makes contact-rich simulation hard.

The practical design rule is to make the interface inspectable before optimization begins: inputs, outputs, units, latency, bounds, and failure labels should all be visible in the saved artifact.

Mechanism

The mechanism in Contact, friction, and why contact-rich sim is hard is the contract between representation and action. Name what enters the module, what leaves it, which assumptions make that transformation valid, and which log would reveal a bad handoff.

Worked Example: Impulse-Based Contact With Restitution and a Friction Cone

Hard contact is hard because it is a constrained, set-valued problem. An impulse-based resolution sidesteps stiff penalty forces by directly computing the impulse \(J = (J_n, J_t)\) that corrects the relative velocity at the contact point in a single step. Two physical laws bound that impulse:

Checkpoint

So far: an impulse \(J=(J_n, J_t)\) resolves contact in one step, the normal part \(J_n\) is set by the restitution law \(v_n^+=-e\,v_n^-\), and the tangential part \(J_t\) is capped by the Coulomb cone \(\lVert J_t\rVert\le\mu J_n\); the worked example below turns these two rules into code.

The example resolves a point mass striking the ground at an angle. It computes the normal impulse from restitution, then clamps the sticking tangential impulse to the friction cone, which is exactly the projection a contact solver performs at every active contact.

import numpy as np

def resolve_contact(v_in, m, normal, e, mu):
    """Impulse-based resolution of a point mass hitting a surface.
    v_in   : incoming velocity (2D)
    normal : unit surface normal pointing away from the surface
    e      : coefficient of restitution in [0,1]
    mu     : Coulomb friction coefficient
    Returns post-impact velocity and the applied impulse."""
    n = normal / np.linalg.norm(normal)
    t = np.array([-n[1], n[0]])            # tangent direction

    vn = v_in @ n                          # normal component (negative if approaching)
    vt = v_in @ t                          # tangential component

    if vn >= 0:                            # separating, no contact impulse
        return v_in, np.zeros(2)

    # Normal impulse enforces v_n^+ = -e * v_n^-.
    Jn = -(1 + e) * vn * m                 # >= 0

    # Sticking tangential impulse would cancel all tangential velocity.
    Jt_stick = -vt * m
    Jt_max   = mu * Jn                     # friction-cone limit
    if abs(Jt_stick) <= Jt_max:
        Jt = Jt_stick                      # inside cone: stick
        mode = "stick"
    else:
        Jt = -np.sign(vt) * Jt_max         # on cone: slide, oppose slip
        mode = "slide"

    J = Jn * n + Jt * t
    v_out = v_in + J / m
    return v_out, J, mode

m = 0.5
v_in = np.array([3.0, -2.0])               # moving right and down
normal = np.array([0.0, 1.0])              # floor normal points up

for e, mu in [(0.0, 2.0), (0.8, 0.5), (0.8, 0.05)]:
    v_out, J, mode = resolve_contact(v_in, m, normal, e, mu)
    vn_out = v_out @ normal
    print(f"e={e} mu={mu:<4} -> v_out={np.round(v_out,3)} "
          f"vn_out={vn_out:+.3f} mode={mode}")
resolve_contact computes the restitution-scaled normal impulse, then clamps the sticking tangential impulse to the Coulomb cone \(\lVert J_t\rVert\le\mu J_n\); the driver sweeps three (e, mu) regimes to show a point mass sticking, bouncing, and sliding on the same floor impact.

The output shows the three regimes a contact-rich simulator must get right: with \(e=0\) the normal velocity is killed and high friction makes the contact stick; with \(e=0.8\) the mass bounces, \(v_n^{+}=0.8\,|v_n^{-}|\); and with low \(\mu\) the tangential impulse saturates on the cone and the mass slides instead of sticking. The set-valued switch between stick and slide is precisely the active-set decision that makes contact-rich simulation non-smooth and timestep sensitive.

Step-Through: impulse resolution of the third case (\(e=0.8\), \(\mu=0.05\))

Trace resolve_contact by hand for the sliding regime, using \(m=0.5\), \(v_{in}=(3.0,\,-2.0)\), normal \(n=(0,1)\), \(e=0.8\), \(\mu=0.05\).

  1. Tangent direction: \(t=(-n_1, n_0)=(-1, 0)\).
  2. Normal component: \(v_n = v_{in}\cdot n = (3.0)(0)+(-2.0)(1) = -2.0\). Negative, so the mass is approaching and a contact impulse is needed.
  3. Tangential component: \(v_t = v_{in}\cdot t = (3.0)(-1)+(-2.0)(0) = -3.0\).
  4. Normal impulse: \(J_n = -(1+e)\,v_n\,m = -(1.8)(-2.0)(0.5) = 1.8\).
  5. Sticking tangential impulse: \(J_{t,\text{stick}} = -v_t\,m = -(-3.0)(0.5) = 1.5\).
  6. Friction-cone limit: \(J_{t,\max} = \mu J_n = (0.05)(1.8) = 0.09\). Since \(|1.5| > 0.09\), the stick impulse violates the cone, so the contact slides.
  7. Clamped tangential impulse: \(J_t = -\operatorname{sign}(v_t)\,J_{t,\max} = -(-1)(0.09) = +0.09\).
  8. Total impulse: \(J = J_n n + J_t t = (1.8)(0,1) + (0.09)(-1,0) = (-0.09,\,1.8)\).
  9. Post-impact velocity: \(v_{out} = v_{in} + J/m = (3.0,-2.0) + (-0.18,\,3.6) = (2.82,\,1.6)\).

Check: \(v_{out}\cdot n = +1.6 = 0.8\cdot|{-2.0}|\), so restitution is satisfied, and the large residual tangential speed (\(2.82\)) confirms the mass kept sliding because friction was far too weak to arrest it.

When MuJoCo contact simulations produce stick/slide chatter (the mode alternates every timestep with no change in applied force), the fastest fix is to tighten the solimp parameters (MuJoCo's constraint impedance settings, which control how stiffly a contact resists penetration) rather than reducing the timestep. Set solimp="0.99 0.999 0.001" on the relevant geom or contact pair to increase constraint stiffness while keeping the timestep at 2 ms. Reducing the timestep alone amplifies numerical noise at the contact boundary and often makes chatter worse; adjusting solimp addresses the root cause, which is the solver treating the constraint as too compliant to resolve the stick/slide decision cleanly.

Library Shortcut

The hand-built fragment exposes the physical assumption before maintained tools take over. MuJoCo, MJX, Drake, Pinocchio, and Isaac Lab are useful only when the same mass, contact, actuator, and timestep contract is preserved.

Practical Recipe

The friction-cone projection above is what one solver step does in principle; turning that principle into a contact model you can trust on real hardware means fixing the concrete timestep, solver, and logging choices that govern whether the projection ever runs on sane inputs.

  1. Set the MuJoCo timestep to 2 ms for manipulation (Franka Panda fingertip contacts) and 4 ms for locomotion (Unitree H1 foot strikes); coarser steps cause tunneling (a body moving fast enough within one timestep to pass entirely through a thin surface without the solver ever detecting contact) at fingertip scale, finer steps waste compute without improving contact fidelity.
  2. Run a free-motion energy check before adding contact: integrate a Franka arm at zero torque for 5 s and confirm that kinetic energy drifts less than 0.1 % per second; a larger drift means inertia parameters in the URDF are inconsistent.
  3. Add a single flat-ground contact and verify that penetration depth stays below 0.1 mm at steady state; if depth grows monotonically, tighten solref from the MuJoCo default "0.02 1" to "0.005 1".
  4. Test grasp stability with the Franka hand by logging the stick/slide mode at each finger pad contact across a 500 ms hold; if mode switches exceed 5 per second without a change in applied torque, the contact is chattering and solimp needs adjustment.
  5. Before scaling to Isaac Lab for parallel rollouts, reproduce the same grasp in a single-environment MuJoCo run and confirm that success rate, mean penetration, and energy error match to within 5 %; GPU-parallelism does not fix a broken contact model.

A common assumption is that shrinking the simulation timestep will always improve contact accuracy and eventually eliminate artifacts like chatter, tunneling, or energy blow-up. This is wrong in embodied AI contexts: contact discontinuities are a structural property of rigid-body mechanics, not a numerical resolution problem. A smaller timestep can make stick/slide chatter worse because it amplifies noise at the constraint boundary without resolving the underlying combinatorial decision about which contacts are active. The correct mental model treats the active-set selection (which contacts stick, which slide, which separate) as a mode-switching problem that must be handled by solver parameters such as constraint impedance and regularization, not by brute-force timestep reduction. Reduce the timestep only to prevent tunneling at the geometry scale; tune solver parameters to fix chatter and constraint violation.

Common Failure Mode

The most common mistake when training dexterous manipulation policies in simulation is trusting a high task-success rate before checking contact quality. Policies trained in IsaacGym with default contact_offset=0.02 (20 mm) learn to exploit artificially thick contact shells: the robot "grasps" objects while the fingertips are still centimeters away. When transferred to a real Franka hand, where the actual contact shell is under 1 mm, grasp success drops by 40-60 % even when the visual observations match. Log mean fingertip penetration depth per episode; if it exceeds 3 mm on average, the policy is exploiting the soft contact model rather than learning true grasping.

Practical Example

The Open X-Embodiment dataset contains teleoperated manipulation trajectories from 22 robot embodiments, including Franka Panda, WidowX, and Google Robot. Contact events in those demonstrations are implicit: the operator felt resistance through haptic feedback, but the logged state contains only joint positions and end-effector pose. When using these demonstrations to train policies in MuJoCo or Isaac Lab, the contact model in simulation must be calibrated so that the simulated fingertip force at grasp initiation matches the force range seen in the real hardware logs (typically 1-5 N for a light grasp). A mismatch of more than a factor of two in contact stiffness produces policies that either drop objects immediately or crush them, even when the motion trajectory looks correct.

Real-World Application: in-hand reorientation on the Shadow Hand

OpenAI's Dactyl system trained a policy to reorient a cube in a five-fingered Shadow Dexterous Hand entirely in simulation, where dozens of fingertip contacts switch between stick and slide every step. The team could not trust a single high-fidelity contact model, so they randomized friction, contact stiffness, and object mass across thousands of parallel MuJoCo environments, and the reported result was a policy that transferred to the physical hand without additional real-world fine-tuning. This is the combinatorial-contact problem of this section typically solved not by a perfect solver but by making the policy robust to which contact mode the real hand actually lands in.

Memory Hook

Contact quality has one diagnostic number: mean penetration depth over a held grasp. Under 1 mm the simulator is physically plausible. Over 5 mm the policy is flying through objects. Everything between is a negotiation between solver speed and physical realism that every sim-to-real transfer will eventually expose.

Research Frontier

Smoothed and randomized contact models for sim-to-real transfer (2024-2025). Rather than solving the exact LCP at every step, recent work randomizes contact stiffness, damping, and friction across parallel environments during training so policies become robust to the unknown true contact parameters of the real robot. Google DeepMind's work on agile bipedal locomotion (Haarnoja et al., "Learning Agile Soccer Skills for a Bipedal Robot," Science Robotics 2024) and MIT's work on contact-implicit trajectory optimization (Pang et al., 2024) both show that domain randomization over contact parameters closes the sim-to-real gap more reliably than tuning a single high-fidelity model.

Learned contact and deformable-object simulators (2024-2026). Neural simulators trained on real tactile and force data now replace analytic LCP solvers for deformable and cloth-like objects. CMU's DiffCloth and Stanford's work on learned contact dynamics (Li et al., "Dynamics-Aware Imitation Learning," ICRA 2024) demonstrate that a graph-network contact model trained on real trajectory data can outperform MuJoCo's rigid approximation for soft objects like cables and garments, enabling policies that transfer directly to hardware.

Contact-aware foundation models for manipulation (2025-2026). Large-scale robot learning projects (Physical Intelligence's pi0, Berkeley's RoboVLMs) are beginning to condition manipulation policies on estimated contact state (force/torque sensor readings, tactile images) rather than treating contact as a latent nuisance variable. Early results suggest that explicit contact conditioning reduces catastrophic failures by 30-50 % on in-hand reorientation tasks.

Open problem for PhD students. All current differentiable contact simulators (MJX, Drake hydroelastic, Warp) produce gradients that are numerically correct only in smooth contact regimes; they diverge or vanish at mode switches (stick to slide, contact to separation). An open problem is designing a contact solver whose gradients are informative and bounded across all contact modes, enabling gradient-based policy search on tasks with frequent mode transitions such as in-hand re-grasping and contact-rich locomotion on uneven terrain.

Lab: watch a bouncing ball lose energy as you sweep restitution and timestep

Goal. Feel, empirically, that contact behavior is set by solver parameters and restitution, not by integrator effort alone, and see where a too-coarse timestep lets a falling ball tunnel through the floor.

Tools needed. Python with the mujoco bindings (pip install mujoco); about 20 lines of script and Matplotlib for plotting. No GPU required.

Setup. Write a minimal MJCF with a single free-joint sphere (radius 0.05 m) starting 1 m above a static floor plane. Run 3 s of simulation and log the sphere height and total mechanical energy every step.

What to vary. (1) The coefficient of restitution by editing the geom solref/solimp and the contact condim, trying values that emulate \(e\approx 0.2\), \(0.6\), and \(0.9\). (2) The timestep over 0.0005, 0.002, and 0.02 s. (3) The initial drop height (0.5 m and 2 m).

What to observe. Plot height versus time for each setting. Confirm bounce-peak height drops by roughly \(e^2\) per bounce (energy scales as the square of the restitution). At the 0.02 s timestep with the 2 m drop, watch the ball pass partway through the floor or gain energy between bounces, the tunneling and energy-injection failure modes named in the Practical Recipe. Note that shrinking the timestep cures tunneling but does not change the steady-state bounce height, which is governed by restitution.

Self Check

For a Franka Panda grasping a 200 g mug in MuJoCo: what timestep would you use, what penetration depth threshold flags a broken contact model, and what single log field distinguishes a chattering contact from a correctly sticking one? If you cannot answer all three, re-read the worked example and the MuJoCo tip above before moving to section 6.4.

Production Pattern

Contact, friction, and why contact-rich sim is hard sits inside the Part II robotics contract: geometry defines where things are, kinematics defines what motion is possible, dynamics defines what motion costs, control defines how errors are corrected, and sensing defines what the agent can know on time.

Inspect contact as a numerical model with solver settings, not as a perfect physical event. Contact then serves practitioners, builders, and researchers at once: the idea has an intuitive role, a formal interface, a runnable check, and a reproducible failure mode.

Contact is hard because the model changes structure the instant two bodies touch. Free motion gives way to a constraint force, penetration must stay small, and tangential slip may switch between sticking and sliding. The solver has to satisfy all three at once, in one step.

Contact Is A Mode Switch

A contact-rich simulator is not only integrating forces. It is repeatedly deciding which constraints are active. Small pose changes can create a different active set, so a policy that looks robust in free space can become brittle when grasping, pushing, walking, or sliding.

When Contact Simulation Is Reliable Versus When It Is Not

Contact simulation is most reliable when contacts are few, well-separated, and short-lived: a ball bouncing on a flat floor, a foot striking and leaving ground in a walking gait. It becomes unreliable when many contacts are simultaneously active (a hand grasping a deformable object), when contacts persist for many timesteps with high friction (a box being pushed across a rough surface), or when the geometry has near-parallel contact normals (two flat surfaces sliding). In those regimes, the LCP solver (a Linear Complementarity Problem solver, which simultaneously decides each contact's normal force and whether it sticks or slides) may return non-unique solutions, penetration depth accumulates, or the active-set decision oscillates between stick and slide across consecutive timesteps, producing chatter. The practical signal: if logged penetration depth grows monotonically or if the stick/slide mode switches every step with no change in applied force, the contact model has broken down for that configuration and timestep.

Mechanism To Watch

Dynamics adds causes of motion: forces, torques, inertia, contact impulses, and integration. Keep units, solver step, contact parameters, and energy behavior visible.

Library Choices And Verification Checks
Tool or LibraryWhat It HandlesVerification Check
MuJoCoruns articulated dynamics and contact simulation for robot learning experimentsVerify timestep, solver parameters, contact settings, and reset semantics.
MJXruns articulated dynamics and contact simulation for robot learning experimentsVerify timestep, solver parameters, contact settings, and reset semantics.
Drakemodels dynamical systems, multibody plants, optimization, and controllersVerify scalar type, plant finalization, frame convention, and solver status.
Pinocchiocomputes articulated-body kinematics, dynamics, and derivativesVerify model frames, joint ordering, and derivative convention against the URDF.
Isaac Labscales robot-learning simulation with GPU workflows and sensor-rich scenesVerify environment parity, reset distribution, and logged seeds before training.

Use this recipe when turning Contact, friction, and why contact-rich sim is hard into code, a simulator experiment, or a robot diagnostic. The point is not to use every library. The point is to keep the hand-built baseline and the maintained-tool path comparable.

  1. Specify mass, inertia, actuator limits, contact model, timestep, and solver tolerance before running a rollout.
  2. Run one free-motion test and one contact test with logged energy, constraint violation, and penetration depth.
  3. Compare the hand calculation with MuJoCo, Drake, Pinocchio, or MJX on the same model and timestep.
  4. Store solver settings, random seed, initial state, trajectory, and failure labels in one artifact.
  5. Scale to Isaac Lab or GPU-parallel simulation only after a small model passes deterministic checks.
Evidence Gate

Compare methods only through one saved artifact that preserves the inputs, outputs, units, timestamps, latency budget, configuration, seed, metric definition, and failure labels relevant to this section. The comparison is meaningful only when the same script evaluates the same panel.

Exercise Extension

Extend the section exercise by adding one perturbation specific to Contact, friction, and why contact-rich sim is hard and one latency or uncertainty check. Save the result in the EvidenceRecord schema, then explain which library output you trust and why.

Distrust smooth simulation until the section-specific physical assumption has been stress-tested: timestep, contact stiffness, damping, friction, actuation, and energy behavior should each have a small diagnostic.

Technical Core

Contact, friction, and why contact-rich sim is hard needs a topic-native core: variables, equations or system contracts, an algorithmic procedure, an expected output, and a failure diagnosis. Figure 6.3.T summarizes the chain this section must preserve when moving from a teaching example to a real embodied system.

Figure 6.3.T

A contact result is only trustworthy when the whole chain holds: stated assumptions feed the contact model, which feeds the solver algorithm, which must produce logged evidence (energy, penetration, solver status) and a named failure diagnosis. Skipping the evidence and failure links is how a high task-success number hides a broken contact model. This is the same diagram introduced as Figure 6.1.T.

Formal Object

A hard unilateral contact can be summarized by \(\phi(q)\ge 0\), \(\lambda_n\ge 0\), and \(\phi(q)\lambda_n=0\), where \(\phi(q)\) is signed separation and \(\lambda_n\) is the normal contact force or impulse. Friction adds the Coulomb condition \(\|\lambda_t\|\le \mu\lambda_n\), with sticking inside the cone and sliding on its boundary. Many simulators soften or regularize these constraints, so record the contact model rather than treating \(\lambda\) as a direct measurement of the real world.

Contact diagnostic loop
  1. Log signed distance, normal impulse, tangential impulse, slip speed, and penetration depth for each contact pair.
  2. Check whether \(\lambda_n\) appears only when separation is near zero and whether tangential impulse stays inside the friction cone.
  3. Sweep timestep, friction coefficient, contact stiffness, damping, and solver iterations on the same initial state.
  4. Classify failures as tunneling, chatter, sticking when sliding is expected, sliding when sticking is expected, or solver nonconvergence.
Technical Contract For Contact, friction, and why contact-rich sim is hard
Contract FieldWhat To SpecifyWhy It Matters
State and observationVariables, units, timestamps, frames, and uncertainty.Prevents a model score from being mistaken for robot capability.
Action interfaceCommand type, limits, update rate, and safety fallback.Makes the learned or planned output executable.
Evidence artifactTrace, metric, configuration, seed, and failure label.Allows baseline and library path to be compared in one pass.
Tool pathMuJoCo, Drake, Isaac Sim, Gazebo, PyBullet, SAPIEN, NumPyShows the practical library route after the mechanism is understood.

Expected output is a state trace with the relevant physical invariant: bounded energy error for free motion, bounded penetration for contact, and a solver-status field that explains divergence.

Failure Mode To Test

Contact, friction, and why contact-rich sim is hard is validated by conserved quantities where they should hold, stable contact where contact is expected, and reproducible divergence under a named parameter perturbation.

Section References

Core references for Contact, friction, and why contact-rich sim is hard: Modern Robotics; Murray, Li, and Sastry; Siciliano et al.; LaValle; and the official documentation for Drake, MuJoCo, Pinocchio, CasADi, python-control, GTSAM, ROS 2, and OpenCV as applicable.

Use these references to check notation, frame conventions, solver assumptions, and library behavior before comparing hand-built and maintained-tool implementations.

Key Takeaway

Contact, friction, and why contact-rich sim is hard is useful when it makes the perception-action loop more reliable, not when it merely adds a more impressive model name.

Exercise 6.3.1

Design a method-matched experiment for Contact, friction, and why contact-rich sim is hard. Specify the environment, observations, actions, metric, one perturbation, and the library output you would compare against the hand-built baseline.

Project Ideas

Beginner (weekend): Impulse resolver with stick/slide logger. Extend the worked example above into a small script that sweeps combinations of restitution coefficient, friction coefficient, and incoming angle for a point mass hitting a flat floor, then logs whether each case sticks or slides and plots the boundary of the Coulomb cone in velocity space. The key challenge is correctly clamping the tangential impulse to the friction cone and recognising that the stick/slide boundary depends on incoming tangential velocity, not just friction coefficient. Use NumPy and Matplotlib; no simulator needed.

Intermediate (1-2 weeks): Contact-quality diagnostic harness for MuJoCo. Build a Python harness using the mujoco Python bindings that loads a Franka Panda MJCF model, drops a rigid mug onto the fingers from a fixed height, and records per-contact signed distance, normal impulse, tangential impulse, penetration depth, and stick/slide mode at every timestep. Sweep solimp, solref, and timestep over a grid, classify each run as tunneling, chattering, or stable using the thresholds from the Practical Recipe, and produce a heatmap of stable configurations. The key challenge is parsing MuJoCo's contact data structure correctly and distinguishing solver non-convergence from genuine chatter in the logged mode sequence. Extend to Isaac Lab to verify that a single stable configuration from MuJoCo reproduces the same penetration statistics under GPU-parallel rollouts before using it for policy training.