Skip to content

Add hull collision type - #139

Open
ratheron wants to merge 1 commit into
mainfrom
feat.collission_hull
Open

ratheron wants to merge 1 commit into
mainfrom
feat.collission_hull

Conversation

@ratheron

Copy link
Copy Markdown
Collaborator

So far, we only had sphere and box collision types. We can also use a more approximate check based on the mesh. This is already built into MuJoCo, which simply takes a convex hull, limited by the maxhullvert. I set this to 32 to not slow down the sim too much. On the GPU, this is essentially free. On the CPU, contacts() is significantly slower for larger swarms. I've added a warning for that case.

Here is some short benchmark

┌────────┬────────┬─────────┬────────────────────┬────────────────────┬─────────────────┐
│ drones │ device │ step ms │ sphere contacts ms │ hull32 contacts ms │ hull32 / sphere │
├────────┼────────┼─────────┼────────────────────┼────────────────────┼─────────────────┤
│ 2      │ GPU    │ 0.4     │ 3.4                │ 3.6                │ 1.0×            │
├────────┼────────┼─────────┼────────────────────┼────────────────────┼─────────────────┤
│ 16     │ GPU    │ 0.4     │ 3.8                │ 3.6                │ 1.0×            │
├────────┼────────┼─────────┼────────────────────┼────────────────────┼─────────────────┤
│ 128    │ GPU    │ 0.4     │ 3.4                │ 3.8                │ 1.1×            │
├────────┼────────┼─────────┼────────────────────┼────────────────────┼─────────────────┤
│ 1024   │ GPU    │ 0.5     │ 4.3                │ 4.5                │ 1.0×            │
├────────┼────────┼─────────┼────────────────────┼────────────────────┼─────────────────┤
│ 2      │ CPU    │ 0.8     │ 2.6                │ 2.4                │ 0.9×            │
├────────┼────────┼─────────┼────────────────────┼────────────────────┼─────────────────┤
│ 16     │ CPU    │ 0.5     │ 2.6                │ 17.7               │ 6.9×            │
├────────┼────────┼─────────┼────────────────────┼────────────────────┼─────────────────┤
│ 128    │ CPU    │ 0.6     │ 2.6                │ 35.3               │ 13×             │
├────────┼────────┼─────────┼────────────────────┼────────────────────┼─────────────────┤
│ 1024   │ CPU    │ 0.9     │ 9.8                │ 318.6              │ 33×             │
└────────┴────────┴─────────┴────────────────────┴────────────────────┴─────────────────┘

@ratheron
ratheron requested a review from amacati as a code owner October 14, 2026 12:27
@ratheron
ratheron force-pushed the feat.collission_hull branch from 545a2a1 to 9a9f549 Compare October 14, 2026 12:29
Comment thread crazyflow/sim/__init__.py
default = sphere


from crazyflow.sim.sim import Sim # noqa: E402 (sim.py imports CollisionType from this package)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this rather be in crazyflow/sim/collision.py then?

Comment thread crazyflow/sim/sim.py
self.viewer = None
self.spec.numeric("max_geom_pairs").data = [self.max_geom_pairs]
self.mj_model, self.mj_data, self.mjx_model, self.mjx_data = self.build_mjx_model(self.spec)
core = self.data.core.replace(mjx_synced=jnp.zeros_like(self.data.core.mjx_synced))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
core = self.data.core.replace(mjx_synced=jnp.zeros_like(self.data.core.mjx_synced))
core = self.data.core.replace(mjx_synced=False)

This should work

Comment thread crazyflow/sim/sim.py
Comment on lines +778 to +780
collision_type: ``sphere`` (default) is a bounding sphere, ``box`` an oriented bounding box
and ``hull`` the convex hull of the drone mesh, limited to 32 vertices. The selected
geometry is in geom group 3, which the viewer hides by default (toggle with key 3).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
collision_type: ``sphere`` (default) is a bounding sphere, ``box`` an oriented bounding box
and ``hull`` the convex hull of the drone mesh, limited to 32 vertices. The selected
geometry is in geom group 3, which the viewer hides by default (toggle with key 3).
collision_type: ``sphere`` (default) is a bounding sphere, ``box`` an oriented bounding box
and ``hull`` the convex hull of the drone mesh, limited to 32 vertices.

Comment on lines +42 to +48
"""Fly the outer drones back and forth through a hovering drone and check for contacts.

The crossing is repeated with every collision type. Each type reports contacts for a different
fraction of the crossing, from the loose sphere to the tight convex hull. A disc above each
drone turns red while the drone is in contact. Press 3 in the viewer to show the collision
geometry.
"""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""Fly the outer drones back and forth through a hovering drone and check for contacts.
The crossing is repeated with every collision type. Each type reports contacts for a different
fraction of the crossing, from the loose sphere to the tight convex hull. A disc above each
drone turns red while the drone is in contact. Press 3 in the viewer to show the collision
geometry.
"""
"""Fly the outer drones back and forth through a hovering drone and check for contacts.
The crossing is repeated with every collision type. Each type reports contacts for a different
fraction of the crossing. A disc above each drone turns red while the drone is in contact.
Press 3 in the viewer to show the collision geometry.
"""

Comment on lines +54 to +55
dynamics=Dynamics.so_rpy,
device="cpu",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
dynamics=Dynamics.so_rpy,
device="cpu",

We initially added different options per example to show how these things can be changed on the side. Now that we have a dedicated example for almost all of them, we should remove them to focus on the stuff the example is actually about. We can probably clean these up as we edit examples (like this one here)

@ratheron ratheron added the blocked Blocked by something else label Oct 14, 2026
@ratheron

Copy link
Copy Markdown
Collaborator Author

This PR is currently blocked by the raycasting pipeline. examples/rendering/raycasting.py runs out of memory in CI (Out of memory allocating 123376480400 bytes).

Our depth renderer wraps mjx.ray, which picks geoms only by geom group and ignores contype/conaffinity. It does skip invisible geoms (alpha 0), but only after computing all intersections, because geom_rgba is a traced array in MJX. The new col_hull geoms sit in group 3 with the other collision geoms and reference the full drone mesh (85k faces for cf21B_fused). So even while disabled, every ray is tested against every face: 200×200 rays × 85k faces ≈ 123 GB. Upstream MJX main behaves the same.

Possible fixes:

  1. Drop invisible geoms from the raycast before calling mjx.ray. This fixes the default case, but raycasting group 3 still runs out of memory once hull collision is selected.
  2. Add an explicit low-poly hull STL for the col_hull geoms. Rays would then cost about 60 faces, and collisions stay the same because MJX already collides against the hull. The cost is extra mesh assets.

Neither option is great. The second is the better one though. I'll come back to this later.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

blocked Blocked by something else

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants