diff --git a/SKILL.md b/SKILL.md index 277137763..1daecbdb6 100644 --- a/SKILL.md +++ b/SKILL.md @@ -97,4 +97,4 @@ Pure, batched, array-API functions with no dependency on `Sim`. `attach_splats` performs no calibration. Both `.ply` files must already sit in the simulator's frames, the scene in the MuJoCo world frame at metric scale and the drone in its body frame. An uncalibrated splat looks correct alone but does not match the simulated geometry. See -[`splats.md`](docs/user-guide/splats.md). +[`splat-rendering.md`](docs/user-guide/splat-rendering.md). diff --git a/docs/examples/contacts.md b/docs/examples/contacts.md new file mode 100644 index 000000000..7780b152e --- /dev/null +++ b/docs/examples/contacts.md @@ -0,0 +1,24 @@ +# Contact examples + +Querying contacts between drones and the scene, and choosing the collision geometry of the drone. See [MuJoCo Integration](../user-guide/mujoco.md) for how the scene is built. + +--- + +## Contact queries + +
+
+ Contact query visualization using the default sphere collision geometry +
+
+ Contact query visualization using the oriented box collision geometry +
+
+ +--8<-- example "examples/contacts/contacts.py" + +--- + +## Crash detection + +--8<-- example "examples/contacts/crash.py" diff --git a/docs/examples/control.md b/docs/examples/control.md new file mode 100644 index 000000000..ee4ee69bb --- /dev/null +++ b/docs/examples/control.md @@ -0,0 +1,63 @@ +# Control examples + +Flying drones with the different control modes, from state commands down to force and torque, comparing the dynamics models, and model-based control. See [Control Modes](../user-guide/control/index.md) for the controller behind each mode. + +--- + +## Hover + +--8<-- example "examples/control/hover.py" + +--- + +## Changing the state + +--8<-- example "examples/control/change_pos.py" + +--- + +## Spirals + +--8<-- example "examples/control/spiral.py" + +--- + +## Attitude control + +--8<-- example "examples/control/attitude.py" + +--- + +## Body rate control + +--8<-- example "examples/control/body_rate.py" + +--- + +## Force and torque control + +--8<-- example "examples/control/force_torque.py" + +--- + +## Comparing integrators + +--8<-- example "examples/control/integrators.py" + +--- + +## Comparing dynamics models + +--8<-- example "examples/control/dynamics.py" + +--- + +## Symbolic dynamics + +--8<-- example "examples/control/symbolic.py" + +--- + +## Sampling-based MPC + +--8<-- example "examples/control/sampling.py" diff --git a/docs/examples/environments.md b/docs/examples/environments.md new file mode 100644 index 000000000..456465752 --- /dev/null +++ b/docs/examples/environments.md @@ -0,0 +1,15 @@ +# Environment examples + +Running the Gymnasium environments that wrap `Sim` for reinforcement learning. See [Gymnasium Environments](../user-guide/gymnasium-envs.md) for the available environments. + +--- + +## Figure-eight environment + +--8<-- example "examples/environments/figure8.py" + +--- + +## Reach-position environment + +--8<-- example "examples/environments/gymnasium_env.py" diff --git a/docs/examples/index.md b/docs/examples/index.md index c986e5d0c..5109d88d3 100644 --- a/docs/examples/index.md +++ b/docs/examples/index.md @@ -1,259 +1,10 @@ # Examples -These runnable examples cover control, JAX transformations, pipeline extensions, rendering, contacts, and Gymnasium environments. Start with hover if you're new, or jump to the section that matches your use case. - ---- - -## Hover - -A single drone commanded to hold a fixed height using state control. This is the minimal end-to-end loop: create a `Sim`, reset it, apply a state command, and step forward. - - -```{ .python notest } ---8<-- "examples/control/hover.py" -``` - -```bash -python examples/control/hover.py -``` - ---- - -## Attitude control - -Commanding roll, pitch, yaw, and collective thrust directly. This level bypasses the Mellinger position loop and is typical for RL agents that output attitude targets. - - -```{ .python notest } ---8<-- "examples/control/attitude.py" -``` - ---- - -## Body rate control - -Commanding body-frame angular rates and collective thrust. The firmware controller has no dedicated body rate mode and levels the drone with its attitude terms, so the example sets the `kR` and `ki_m` gains of the body rate controller to zero. - - -```{ .python notest } ---8<-- "examples/control/body_rate.py" -``` - ---- - -## Sampling-based MPC - -A sampling-based model predictive controller tracks a Lissajous curve while avoiding a grid of obstacles. It rolls out thousands of candidate control sequences in parallel using identified dynamics, then applies the first action from a cost-weighted update of the best samples. The controller automatically uses a GPU when one is available and lowers the sample count on CPU. - -```bash -python examples/control/sampling.py -``` - ---- - -## Gradient descent through dynamics - -Because the simulator is built entirely from JAX operations, `jax.grad` can differentiate through it. Starting the drone above the target height keeps it away from the floor, so the floor-clipping stage never fires and gradients flow freely through the entire trajectory. - - -```{ .python notest } ---8<-- "examples/jax/gradient.py" -``` - ---- - -## Gradients and command clipping - -Hard clips such as the `clip_rotor_vel_cmd` stage zero the gradients while the command is saturated. This example ramps a motor command beyond the rotor limits and compares the rotor state and the gradient of the vertical acceleration w.r.t. the command for three options: the default clip, a straight-through clip (clipped forward pass, unclipped gradients), and no clip. Replacing the default clip with the straight-through variant can help gradient-based methods such as trajectory optimization or policy learning, which would otherwise receive zero gradients whenever the motors saturate. - - -```{ .python notest } ---8<-- "examples/jax/gradient_clipping.py" -``` - ---- - -## Sharding across devices - -We can also distribute the simulation across devices. The host backend is asked for four logical devices. We then compare this against running on a single device. See [Sharding](../user-guide/sharding.md) for the details. - - -```{ .python notest } ---8<-- "examples/jax/sharding.py" -``` - ---- - -## Domain randomization - -Randomizing mass, inertia and drag per drone, and thrust and torque curves, rotor dynamics, arm lengths and propeller inertias per motor through the reset pipeline, each by a uniform factor around its default value. An optional mask limits randomization to selected worlds. - - -```{ .python notest } ---8<-- "examples/plugins/randomize.py" -``` - -```bash -python examples/plugins/randomize.py -``` - ---- - -## Disturbance injection - -Inserting a random external force and torque into the step pipeline. The disturbance fires on every dynamics tick, so the drone fights wind-like perturbations. - - -```{ .python notest } ---8<-- "examples/plugins/disturbance.py" -``` - ---- - -## Downwash - -Modeling downwash between identical Crazyflies with a far-field jet model. The plugin samples the flow at each target rotor and center of mass, computes rotor thrust loss and drag, and writes the resulting world-frame external force and torque. - -The demo holds one `cf21B_500` drone in hover while a second makes three passes underneath at different speeds and heights. - -
-
- Drone flying through downwash cone -
-
- Downwash field generated by hovering drone -
-
- -```bash -python examples/plugins/downwash.py -``` - ---- - -## Ground effect - -Modeling the increase in thrust near the floor for a `cf21B_500` drone. The plugin computes nominal thrust from the rotor speeds, applies a height-dependent gain, and adds the extra thrust along the drone's body z-axis as a world-frame external force. - - -```{ .python notest } ---8<-- "examples/plugins/ground_effect.py" -``` - -```bash -python examples/plugins/ground_effect.py -``` - ---- - -## State derivatives - -Adding the state derivatives, which are not stored by default, to the step pipeline with plugins. One plugin calls the dynamics at the end of each step, which gives the exact derivative at the current state. The other uses finite differences of the states, which give the exact average derivative from the last to the current step. Both store a `SimStateDeriv` in the plugins dict. The plot compares them while the drone flies a figure-eight. - - -```{ .python notest } ---8<-- "examples/plugins/derivatives.py" -``` - -```bash -python examples/plugins/derivatives.py -``` - ---- - -## IMU - -Simulating an IMU as a plugin. The accelerometer measures the specific force and the gyroscope the body rates, both with noise and drifting biases, while the drone flies loops of a figure-eight. The plot compares the readings with the true state, skipping the first loop. - - -```{ .python notest } ---8<-- "examples/plugins/imu.py" -``` - -```bash -python examples/plugins/imu.py -``` - ---- - -## Cameras and RGBD - -Offscreen rendering returns RGB-D images on every frame. The FPV camera (`fpv_cam`) is attached to the drone and moves with it. - -
- RGB-D camera outputs from a Crazyflow drone simulation -
- - -```{ .python notest } ---8<-- "examples/rendering/cameras.py" -``` - -```bash -python examples/rendering/cameras.py -``` - ---- - -## LED deck and materials - -`change_material` updates the RGBA colour and emission of any named material on any subset of drones at runtime. - -
- Crazyflow drones with runtime-controlled LED deck materials -
- - -```{ .python notest } ---8<-- "examples/rendering/led_deck.py" -``` - -```bash -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. - -
-
- Contact query visualization using the default sphere collision geometry -
-
- Contact query visualization using the oriented box collision geometry -
-
- - -```{ .python notest } ---8<-- "examples/contacts/contacts.py" -``` - ---- - -## Raycasting and depth sensing - -`render_depth` fires rays from a camera and returns per-pixel distances. This is faster than full RGB rendering and useful for obstacle sensing or depth-based controllers. - - -```{ .python notest } ---8<-- "examples/rendering/raycasting.py" -``` - -```bash -python examples/rendering/raycasting.py -``` - ---- - -## Gymnasium environment - -Evaluating a random policy in the figure-8 environment. The env wraps `Sim` behind the standard Gymnasium `VectorEnv` interface. - - -```{ .python notest } ---8<-- "examples/environments/figure8.py" -``` +The runnable examples are grouped by topic, following the folders in `examples/`. Start with [hover](control.md#hover) if you're new, or jump to the group that matches your use case. Run an example from the repository root with `python examples//