Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions crazyflow/drones/cf21B_500.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<mesh name="battery" file="cf21B/cf21B_battery.stl" scale="1e-3 1e-3 1e-3"/>
<mesh name="battery-holder" file="cf21B/cf21B_battery-holder.stl" scale="1e-3 1e-3 1e-3"/>
<mesh name="led-diffuser" file="cf21B/cf_led-diffuser.stl" scale="1e-3 1e-3 1e-3"/>
<mesh name="cf21B_fused" file="cf21B/cf21B_fused.stl" scale="1e-3 1e-3 1e-3"/>
<mesh name="cf21B_fused" file="cf21B/cf21B_fused.stl" scale="1e-3 1e-3 1e-3" maxhullvert="32"/>
</asset>

<default>
Expand Down Expand Up @@ -65,8 +65,10 @@
<!-- Collision geometry is estimated based on the visual mesh. We use a sphere for maximum
computational efficiency with larger swarms. Used by default-->
<geom name="col_sphere" type="sphere" size="0.086" pos="0 0 0.02" class="collision" contype="1" conaffinity="1" />
<!-- For higher accuracy with lower performance, you can use a box. By default off. -->
<!-- For higher accuracy with lower performance, you can use a box or the convex hull of the
drone mesh. By default off. -->
<geom name="col_box" type="box" size="0.07 0.07 0.02" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
<geom name="col_hull" type="mesh" mesh="cf21B_fused" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />

<!-- Motors and Propellers -->
<site name="motor0" pos="0.03536 -0.03536 0.0" />
Expand Down Expand Up @@ -96,6 +98,7 @@
<geom mesh="cf21B_fused" material="" class="visual" />
<geom name="col_sphere_fused" type="sphere" size="0.086" pos="0 0 0.02" class="collision" contype="1" conaffinity="1" />
<geom name="col_box_fused" type="box" size="0.07 0.07 0.02" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
<geom name="col_hull_fused" type="mesh" mesh="cf21B_fused" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
</body>
</worldbody>

Expand Down
7 changes: 5 additions & 2 deletions crazyflow/drones/cf2x_L250.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<mesh name="battery" file="cf2x/cf2x_battery.stl" scale="0.001 0.001 0.001"/>
<mesh name="battery-holder" file="cf2x/cf2x_battery-holder.stl" scale="0.001 0.001 0.001"/>
<mesh name="led-diffuser" file="cf21B/cf_led-diffuser.stl" scale="1e-3 1e-3 1e-3"/>
<mesh name="cf2x_fused" file="cf2x/cf2xL_fused.stl" scale="0.001 0.001 0.001"/>
<mesh name="cf2x_fused" file="cf2x/cf2xL_fused.stl" scale="0.001 0.001 0.001" maxhullvert="32"/>
</asset>

<default>
Expand Down Expand Up @@ -65,8 +65,10 @@
<!-- Collision geometry is estimated based on the visual mesh. We use a sphere for maximum
computational efficiency with larger swarms. Used by default-->
<geom name="col_sphere" type="sphere" size="0.07" pos="0 0 0.005" class="collision" contype="1" conaffinity="1" />
<!-- For higher accuracy with lower performance, you can use a box. By default off. -->
<!-- For higher accuracy with lower performance, you can use a box or the convex hull of the
drone mesh. By default off. -->
<geom name="col_box" type="box" size="0.055 0.055 0.02" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
<geom name="col_hull" type="mesh" mesh="cf2x_fused" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />

<!-- Motors and Propellers -->
<site name="motor0" pos="0.0325 -0.0325 0.0" />
Expand Down Expand Up @@ -97,6 +99,7 @@
<geom mesh="cf2x_fused" material="" class="visual" />
<geom name="col_sphere_fused" type="sphere" size="0.07" pos="0 0 0.005" class="collision" contype="1" conaffinity="1" />
<geom name="col_box_fused" type="box" size="0.055 0.055 0.02" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
<geom name="col_hull_fused" type="mesh" mesh="cf2x_fused" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
</body>
</worldbody>

Expand Down
7 changes: 5 additions & 2 deletions crazyflow/drones/cf2x_P250.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<mesh name="battery" file="cf2x/cf2x_battery.stl" scale="0.001 0.001 0.001"/>
<mesh name="battery-holder" file="cf2x/cf2x_battery-holder.stl" scale="0.001 0.001 0.001"/>
<mesh name="led-diffuser" file="cf21B/cf_led-diffuser.stl" scale="1e-3 1e-3 1e-3"/>
<mesh name="cf2x_fused" file="cf2x/cf2xP_fused.stl" scale="0.001 0.001 0.001"/>
<mesh name="cf2x_fused" file="cf2x/cf2xP_fused.stl" scale="0.001 0.001 0.001" maxhullvert="32"/>
</asset>

<default>
Expand Down Expand Up @@ -65,8 +65,10 @@
<!-- Collision geometry is estimated based on the visual mesh. We use a sphere for maximum
computational efficiency with larger swarms. Used by default-->
<geom name="col_sphere" type="sphere" size="0.07" pos="0 0 0.005" class="collision" contype="1" conaffinity="1" />
<!-- For higher accuracy with lower performance, you can use a box. By default off. -->
<!-- For higher accuracy with lower performance, you can use a box or the convex hull of the
drone mesh. By default off. -->
<geom name="col_box" type="box" size="0.055 0.055 0.02" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
<geom name="col_hull" type="mesh" mesh="cf2x_fused" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />

<!-- Motors and Propellers -->
<site name="motor0" pos="0.0325 -0.0325 0.0" />
Expand Down Expand Up @@ -96,6 +98,7 @@
<geom mesh="cf2x_fused" material="" class="visual" />
<geom name="col_sphere_fused" type="sphere" size="0.07" pos="0 0 0.005" class="collision" contype="1" conaffinity="1" />
<geom name="col_box_fused" type="box" size="0.055 0.055 0.02" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
<geom name="col_hull_fused" type="mesh" mesh="cf2x_fused" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
</body>
</worldbody>

Expand Down
7 changes: 5 additions & 2 deletions crazyflow/drones/cf2x_T350.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<mesh name="battery" file="cf2x/cf2x_battery.stl" scale="0.001 0.001 0.001"/>
<mesh name="battery-holder" file="cf2x/cf2x_battery-holder.stl" scale="0.001 0.001 0.001"/>
<mesh name="led-diffuser" file="cf21B/cf_led-diffuser.stl" scale="1e-3 1e-3 1e-3"/>
<mesh name="cf2x_fused" file="cf2x/cf2xT_fused.stl" scale="0.001 0.001 0.001"/>
<mesh name="cf2x_fused" file="cf2x/cf2xT_fused.stl" scale="0.001 0.001 0.001" maxhullvert="32"/>
</asset>

<default>
Expand Down Expand Up @@ -66,8 +66,10 @@
<!-- Collision geometry is estimated based on the visual mesh. We use a sphere for maximum
computational efficiency with larger swarms. Used by default-->
<geom name="col_sphere" type="sphere" size="0.0725" pos="0 0 0.01" class="collision" contype="1" conaffinity="1" />
<!-- For higher accuracy with lower performance, you can use a box. By default off. -->
<!-- For higher accuracy with lower performance, you can use a box or the convex hull of the
drone mesh. By default off. -->
<geom name="col_box" type="box" size="0.0575 0.0575 0.02" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
<geom name="col_hull" type="mesh" mesh="cf2x_fused" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />

<!-- Motors and Propellers -->
<site name="motor0" pos="0.0325 -0.0325 0.0" />
Expand Down Expand Up @@ -97,6 +99,7 @@
<geom mesh="cf2x_fused" material="" class="visual" />
<geom name="col_sphere_fused" type="sphere" size="0.0725" pos="0 0 0.01" class="collision" contype="1" conaffinity="1" />
<geom name="col_box_fused" type="box" size="0.0575 0.0575 0.02" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
<geom name="col_hull_fused" type="mesh" mesh="cf2x_fused" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
</body>
</worldbody>

Expand Down
7 changes: 5 additions & 2 deletions crazyflow/drones/hb_x500.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
https://www.ardusimple.com/wp-content/uploads/2021/02/helical3b_dimensions.jpg -->
<mesh name="gps_antenna" file="hb_x500/hb_x500_gps_antenna.stl" scale="1e-3 1e-3 1e-3" smoothnormal="true"/>
<!-- The whole `drone` body fused into one mesh with transforms baked in (123408 faces) -->
<mesh name="hb_x500_fused" file="hb_x500/hb_x500_fused.stl" scale="1e-3 1e-3 1e-3"/>
<mesh name="hb_x500_fused" file="hb_x500/hb_x500_fused.stl" scale="1e-3 1e-3 1e-3" maxhullvert="32"/>
</asset>

<default>
Expand Down Expand Up @@ -84,8 +84,10 @@
<!-- Collision geometry is estimated based on the visual mesh. We use a sphere for maximum
computational efficiency with larger swarms. Used by default-->
<geom name="col_sphere" type="sphere" size="0.41" pos="0 0 0.071" class="collision" contype="1" conaffinity="1" />
<!-- For higher accuracy with lower performance, you can use a box. By default off. -->
<!-- For higher accuracy with lower performance, you can use a box or the convex hull of the
drone mesh. By default off. -->
<geom name="col_box" type="box" size="0.327 0.327 0.1675" pos="0 0 0.0875" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
<geom name="col_hull" type="mesh" mesh="hb_x500_fused" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />

<!-- Motors and Propellers. Motor centres: 176.78 mm on both axes (500 mm wheelbase).
Hub underside is 4.5 mm below its origin and seats on the shaft shoulder at 64.5 mm. -->
Expand Down Expand Up @@ -180,6 +182,7 @@
<geom mesh="hb_x500_fused" material="dark-gray" class="visual" />
<geom name="col_sphere_fused" type="sphere" size="0.41" pos="0 0 0.071" class="collision" contype="1" conaffinity="1" />
<geom name="col_box_fused" type="box" size="0.327 0.327 0.1675" pos="0 0 0.0875" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
<geom name="col_hull_fused" type="mesh" mesh="hb_x500_fused" class="collision" rgba="0.5 0.5 0.5 0" contype="0" conaffinity="0" />
</body>
</worldbody>

Expand Down
6 changes: 2 additions & 4 deletions crazyflow/dynamics/utils/data_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from __future__ import annotations

import logging
import warnings
from typing import TYPE_CHECKING

import numpy as np
Expand All @@ -19,8 +19,6 @@
if TYPE_CHECKING:
from crazyflow._typing import Array # To be changed to array_api_typing later

logger = logging.getLogger(__name__)


def preprocessing(data: dict[str, Array]) -> dict[str, Array]:
"""Applies preprocessing to collected data.
Expand Down Expand Up @@ -54,7 +52,7 @@ def preprocessing(data: dict[str, Array]) -> dict[str, Array]:
# TODO also check quat for outliers!

if n_outliers > 0:
logger.warning(f"{n_outliers} outliers detected. Interpolating")
warnings.warn(f"{n_outliers} outliers detected. Interpolating")
time_good = data["time"][~is_outlier]
pos_good = data["pos"][~is_outlier]
quat_good = data["quat"][~is_outlier]
Expand Down
17 changes: 15 additions & 2 deletions crazyflow/sim/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
from enum import StrEnum

from crazyflow.dynamics import Dynamics
from crazyflow.sim.sim import Sim

__all__ = ["Sim", "Dynamics"]

class CollisionType(StrEnum):
"""Collision geometry of the drones, selected with ``select_collision_type``."""

sphere = "sphere"
box = "box"
hull = "hull"
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?


__all__ = ["Sim", "Dynamics", "CollisionType"]
40 changes: 25 additions & 15 deletions crazyflow/sim/sim.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import copy
import warnings
import xml.etree.ElementTree as ET
from collections import OrderedDict
from functools import partial, wraps
Expand Down Expand Up @@ -30,6 +31,7 @@
from crazyflow.dynamics import Dynamics
from crazyflow.dynamics import load_params as load_dynamics_params
from crazyflow.exception import ConfigError, NotInitializedError
from crazyflow.sim import CollisionType
from crazyflow.sim.data import SimControls, SimCore, SimData, SimParams, SimState, SimStateDeriv
from crazyflow.sim.dynamics import (
first_principles_dynamics,
Expand Down Expand Up @@ -345,6 +347,8 @@ def _replicate_drone(
asset.append(clone)
new_spec = mujoco.MjSpec.from_string(ET.tostring(root, encoding="unicode"))
new_spec.copy_during_attach = True # write-only, re-apply after from_string() drops it
for mesh in spec.meshes: # to_xml() drops maxhullvert before MuJoCo 3.16, re-apply it
new_spec.mesh(mesh.name).maxhullvert = mesh.maxhullvert
return new_spec

def build_mjx_model(self, spec: mujoco.MjSpec) -> tuple[Any, Any, Model, Data]:
Expand Down Expand Up @@ -509,6 +513,8 @@ def build_mjx(self):
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

self.data = self.data.replace(core=core)

def init_data(
self,
Expand Down Expand Up @@ -764,26 +770,30 @@ def seed_sim(data: SimData, seed: int, device: Device) -> SimData:
return data.replace(core=data.core.replace(rng_key=rng_key))


def use_box_collision(sim: Sim, enable: bool = True):
"""Changes the collision geometry to use boxes or spheres (default).
def select_collision_type(sim: Sim, collision_type: CollisionType = CollisionType.default):
"""Select the collision geometry of all drones and rebuild the MJX model.

Args:
sim: The simulation instance.
enable: If True, use box collision geometry. If False, use sphere collision geometry.
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).
Comment on lines +778 to +780

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.


Warning:
Using box collision geometry is more computationally expensive than sphere collision
geometry, especially for larger swarms. It is recommended to only enable box collision
geometry for small swarms or when high accuracy is required.
Box and hull collisions are more expensive than spheres. MJX tests all edge pairs of two
hulls, which is cheap on GPU but slows down ``Sim.contacts()`` significantly on CPU for
swarms with many drone pairs.
"""
if collision_type == CollisionType.hull and sim.device.platform == "cpu" and sim.n_drones > 16:
warnings.warn(
f"Hull collision with {sim.n_drones} drones slows down `Sim.contacts()` significantly "
"on CPU. Use a GPU or the sphere/box collision type for large swarms."
)
for geom in sim.spec.geoms:
if geom.name.startswith("col_sphere"):
geom.contype = 1 * (not enable)
geom.conaffinity = 1 * (not enable)
geom.rgba[3] = 1 * (not enable)
if geom.name.startswith("col_box"):
geom.contype = 1 * enable
geom.conaffinity = 1 * enable
geom.rgba[3] = 1 * enable

if not geom.name.startswith(("col_sphere", "col_box", "col_hull")):
continue
enable = geom.name.startswith(f"col_{collision_type}")
geom.contype = 1 * enable
geom.conaffinity = 1 * enable
geom.rgba[3] = 1 * enable
sim.build_mjx()
2 changes: 1 addition & 1 deletion docs/examples/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ python examples/rendering/led_deck.py

## Contact queries

The default collision geometry is a sphere around the drone frame. `use_box_collision` replaces it with a tighter oriented box, useful for narrow-gap flight and accurate contact debugging.
The default collision geometry is a sphere around the drone frame. `select_collision_type` switches to a tighter oriented box or to the convex hull of the drone mesh, useful for narrow-gap flight and accurate contact debugging. Hull contacts are cheap on GPU but slow down significantly on CPU for swarms with many drones.

<div class="example-media-grid example-media-grid--contacts">
<figure>
Expand Down
2 changes: 1 addition & 1 deletion docs/user-guide/mujoco.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,4 @@ in_contact = check_contacts(sim.data, sim.mjx_data.mocap_pos)

- [Pipelines](pipelines.md) — inserting custom stages into the step and reset pipelines
- [Examples](../examples/index.md#cameras-and-rgbd) — FPV camera and RGBD rendering
- [Examples](../examples/index.md#contact-queries) — contact detection with box collision geometry
- [Examples](../examples/index.md#contact-queries) — contact detection with sphere, box or hull collision geometry
84 changes: 71 additions & 13 deletions examples/contacts/contacts.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,82 @@
import mujoco
import numpy as np

from crazyflow.sim import Dynamics, Sim
from crazyflow.sim.sim import use_box_collision
from crazyflow.control import Control
from crazyflow.sim import CollisionType, Dynamics, Sim
from crazyflow.sim.sim import select_collision_type

RED, GREEN = (1.0, 0.0, 0.0), (0.0, 1.0, 0.0)


def add_contact_indicators(sim: Sim) -> list[int]:
"""Add a disc above each drone that turns red on contact and return the geom ids."""
for i in range(sim.n_drones):
geom = sim.spec.body(f"drone:{i}").add_geom()
geom.name = f"indicator:{i}"
geom.type = mujoco.mjtGeom.mjGEOM_CYLINDER
geom.size[:] = [0.05, 0.003, 0.0]
geom.pos[:] = [0.0, 0.0, 0.1]
geom.contype = 0
geom.conaffinity = 0
geom.rgba[:] = [*GREEN, 1.0]
sim.build_mjx()
return [sim.mj_model.geom(f"indicator:{i}").id for i in range(sim.n_drones)]


def crossing_trajectory(t: float, amplitude: float, period: float) -> tuple[np.ndarray, np.ndarray]:
"""Drones 0 and 2 oscillate along x in opposite directions through the hovering drone 1.

Returns:
Position and velocity setpoints at time ``t`` with shape (3, 3) each.
"""
direction = np.array([1.0, 0.0, -1.0])
phase = 2 * np.pi * t / period
pos, vel = np.zeros((3, 3)), np.zeros((3, 3))
pos[:, 0] = amplitude * np.sin(phase) * direction
pos[:, 2] = 1.0
vel[:, 0] = amplitude * 2 * np.pi / period * np.cos(phase) * direction
return pos, vel


def main():
"""Spawn multiple drones in multiple worlds and check for contacts."""
"""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.
"""
Comment on lines +42 to +48

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.
"""

n_worlds, n_drones = 2, 3
sim = Sim(n_worlds=n_worlds, n_drones=n_drones, dynamics=Dynamics.so_rpy, device="cpu")
use_box_collision(sim, enable=True) # Enable box collision for all drones
sim = Sim(
n_worlds=n_worlds,
n_drones=n_drones,
control=Control.state,
dynamics=Dynamics.so_rpy,
device="cpu",
Comment on lines +54 to +55

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)

)
indicators = add_contact_indicators(sim)
fps = 60
amplitude, period = 0.3, 2.0

cmd = np.zeros((sim.n_worlds, sim.n_drones, 4))
cmd[..., 3] = sim.data.params.mass[0] * 9.81 * 1.04
for i in range(int(2 * sim.control_freq)):
sim.attitude_control(cmd)
sim.step(sim.freq // sim.control_freq)
if ((i * fps) % sim.control_freq) < fps:
sim.render()
print(f"Contacts: {sim.contacts().any()}")
pos, _ = crossing_trajectory(0.0, amplitude, period) # Start on the trajectory
states = sim.data.states
sim.data = sim.data.replace(states=states.replace(pos=states.pos.at[:].set(pos)))
cmd = np.zeros((sim.n_worlds, sim.n_drones, 16))
cmd[..., 12] = 1.0 # Identity quaternion
for collision_type in CollisionType:
print(f"Collision type: {collision_type}")
select_collision_type(sim, collision_type) # Switches mid-flight, the sim keeps its state
for i in range(int(2 * period * sim.control_freq)):
t = i / sim.control_freq
cmd[..., :3], cmd[..., 3:6] = crossing_trajectory(t, amplitude, period)
sim.state_control(cmd)
sim.step(sim.freq // sim.control_freq)
if ((i * fps) % sim.control_freq) < fps:
for drone, gid in enumerate(indicators):
hit = sim.contacts(f"drone:{drone}")[0].any()
sim.mj_model.geom_rgba[gid, :3] = RED if hit else GREEN
sim.render()
print(f"Contacts: {sim.contacts().any()}")
sim.close()


Expand Down
Loading
Loading