# How to Configure Maze and Obstacle Parameters for Simulation in Peng

> Easily configure maze and obstacle parameters for simulation in Peng. Edit the quad.yaml config file directly without recompiling code to customize your simulation environment.

- Repository: [Yang Zhou/peng](https://github.com/makeecat/peng)
- Tags: how-to-guide
- Published: 2026-03-06

---

**Configure maze and obstacle parameters in Peng by editing the `maze` section in [`config/quad.yaml`](https://github.com/makeecat/peng/blob/main/config/quad.yaml), which deserializes into `MazeConfig` and instantiates the runtime `Maze` struct without requiring code recompilation.**

Peng is a quadrotor simulation environment developed in Rust by `makeecat/peng`. The simulation uses a data-driven configuration system where you can adjust the 3-D arena bounds and spherical obstacle behavior through YAML files or programmatically via the `Maze` API.

## Configuration Architecture

The Peng simulation separates configuration deserialization from runtime state using two primary structures. In [`src/config.rs`](https://github.com/makeecat/peng/blob/main/src/config.rs) (lines 15-27), the `MazeConfig` struct handles YAML deserialization of the `maze` section. This feeds into the runtime `Maze` struct defined in [`src/lib.rs`](https://github.com/makeecat/peng/blob/main/src/lib.rs) (lines 27-34), which maintains the actual simulation state including bounds, obstacle lists, and random number generation.

During startup, [`src/main.rs`](https://github.com/makeecat/peng/blob/main/src/main.rs) orchestrates the loading sequence: it reads [`config/quad.yaml`](https://github.com/makeecat/peng/blob/main/config/quad.yaml), parses it through `Config::from_yaml`, extracts the `MazeConfig`, and initializes the runtime via `Maze::new` (see [`src/lib.rs`](https://github.com/makeecat/peng/blob/main/src/lib.rs) lines 46-52). This pipeline ensures that physical parameters remain purely data-driven, allowing you to modify simulation difficulty without recompiling the Rust binary.

## YAML Parameter Reference

The `maze` section in your YAML configuration controls five key aspects of the simulation environment. Each field maps directly to a field in `MazeConfig` and subsequently to the runtime `Maze` initialization:

- **`lower_bounds`**: A `[f32; 3]` array defining the minimum x, y, and z coordinates of the cubic arena. Obstacles never generate outside this boundary.
- **`upper_bounds`**: A `[f32; 3]` array defining the maximum x, y, and z coordinates. Combined with `lower_bounds`, this establishes the simulation volume.
- **`num_obstacles`**: A `usize` value specifying how many spherical obstacles spawn at the start of the simulation.
- **`obstacles_velocity_bounds`**: A `[f32; 3]` array setting the maximum absolute velocity components (vx, vy, vz) for each obstacle. The simulation samples initial velocities uniformly from `[-bound, +bound]` for each axis.
- **`obstacles_radius_bounds`**: A `[f32; 2]` array defining the minimum and maximum radius for obstacles. Each obstacle receives a random radius sampled uniformly from this interval.

## Runtime Obstacle Generation and Physics

When `Maze::new` initializes, it stores the provided bounds and invokes `generate_obstacles(num_obstacles)` (implemented in [`src/lib.rs`](https://github.com/makeecat/peng/blob/main/src/lib.rs) lines 74-92). This method creates each obstacle with three randomized properties: a position uniformly sampled within the bounds, a velocity within the specified velocity limits, and a radius within the radius bounds.

During the simulation loop, the `update_obstacles(dt)` method advances obstacle positions using Euler integration (`position += velocity * dt`). When an obstacle contacts the arena boundaries defined by `lower_bounds` and `upper_bounds`, the method reflects its velocity vector according to the implementation at lines 6-14 of `update_obstacles`, creating realistic bouncing behavior.

## Practical Configuration Examples

### Editing the YAML Configuration File

Modify [`config/quad.yaml`](https://github.com/makeecat/peng/blob/main/config/quad.yaml) to adjust the simulation environment before running. The following example expands the arena in the X and Y dimensions, increases obstacle count, and adjusts dynamic properties:

```yaml
maze:
  lower_bounds: [-5.0, -3.0, 0.0]   # enlarge the arena in X/Y

  upper_bounds: [5.0, 3.0, 3.0]
  num_obstacles: 30                # more obstacles

  obstacles_velocity_bounds: [0.3, 0.3, 0.15]   # faster moving obstacles

  obstacles_radius_bounds: [0.04, 0.12]        # smaller and larger obstacles

```

This configuration creates a `[-5,5] × [-3,3] × [0,3]` meter arena containing 30 obstacles. Each obstacle moves with velocities up to ±0.3 m/s horizontally and ±0.15 m/s vertically, with physical radii varying between 4 cm and 12 cm.

### Creating a Maze Programmatically

For unit tests or custom simulations, instantiate `Maze` directly in Rust without YAML configuration. The `Maze::new` constructor accepts the bounds and obstacle parameters in the same order as the YAML fields:

```rust
use peng_quad::{Maze, Vector3};

fn make_custom_maze() -> Maze {
    Maze::new(
        [-6.0, -4.0, 0.0],      // lower_bounds
        [6.0, 4.0, 2.5],        // upper_bounds
        10,                     // num_obstacles
        [0.25, 0.25, 0.1],      // obstacles_velocity_bounds
        [0.07, 0.15],           // obstacles_radius_bounds
    )
}

```

This returns a fully initialized `Maze` with a freshly seeded random number generator, ready for insertion into the simulation loop.

### Loading Custom Configurations via Command Line

Override the default configuration file at runtime by passing a file path as the sole command-line argument. This allows maintaining multiple environment presets (e.g., [`easy.yaml`](https://github.com/makeecat/peng/blob/main/easy.yaml), [`hard.yaml`](https://github.com/makeecat/peng/blob/main/hard.yaml)) without modifying the repository's default [`config/quad.yaml`](https://github.com/makeecat/peng/blob/main/config/quad.yaml):

```bash
cargo run -- ./my_custom_maze.yaml

```

[`src/main.rs`](https://github.com/makeecat/peng/blob/main/src/main.rs) prints the loaded configuration path and uses the default only when no argument is provided.

## Summary

- **Edit [`config/quad.yaml`](https://github.com/makeecat/peng/blob/main/config/quad.yaml)** to modify maze bounds and obstacle properties without recompiling the Rust code.
- **Use five key parameters**: `lower_bounds`, `upper_bounds`, `num_obstacles`, `obstacles_velocity_bounds`, and `obstacles_radius_bounds` to control arena size and obstacle dynamics.
- **Understand the data flow**: YAML → `MazeConfig` ([`src/config.rs`](https://github.com/makeecat/peng/blob/main/src/config.rs)) → `Maze` instantiation ([`src/lib.rs`](https://github.com/makeecat/peng/blob/main/src/lib.rs) lines 46-52) → `generate_obstacles` (lines 74-92).
- **Override via CLI**: Pass a custom YAML path as a command-line argument to [`main.rs`](https://github.com/makeecat/peng/blob/main/main.rs) for rapid testing of different scenarios.
- **Programmatic alternative**: Call `Maze::new()` directly with float arrays for automated testing or custom simulation pipelines.

## Frequently Asked Questions

### Where are the maze configuration structures defined in the Peng source code?

The configuration deserialization structure `MazeConfig` resides in [`src/config.rs`](https://github.com/makeecat/peng/blob/main/src/config.rs) at lines 15-27, while the runtime simulation structure `Maze` is defined in [`src/lib.rs`](https://github.com/makeecat/peng/blob/main/src/lib.rs) at lines 27-34. The `Maze` implementation includes the `new` constructor, `generate_obstacles` method (lines 74-92), and `update_obstacles` physics loop.

### Do I need to recompile Peng after changing obstacle parameters?

No. Peng uses a data-driven architecture where [`src/main.rs`](https://github.com/makeecat/peng/blob/main/src/main.rs) loads YAML configuration at startup through `Config::from_yaml`. Simply edit [`config/quad.yaml`](https://github.com/makeecat/peng/blob/main/config/quad.yaml) and run `cargo run` again to apply new maze dimensions or obstacle counts. Recompilation is only necessary if you modify the Rust source code itself.

### How does Peng handle obstacle movement and collision with maze boundaries?

The `update_obstacles(dt)` method in [`src/lib.rs`](https://github.com/makeecat/peng/blob/main/src/lib.rs) updates obstacle positions using Euler integration (`position += velocity * dt`). When an obstacle's position exceeds the `lower_bounds` or `upper_bounds` limits, the method reflects the corresponding velocity component, causing the obstacle to bounce within the arena like a physical ball in a box.

### Can I use different maze configurations for different simulation runs?

Yes. While [`config/quad.yaml`](https://github.com/makeecat/peng/blob/main/config/quad.yaml) serves as the default, you can specify alternative configuration files via command-line arguments. Execute `cargo run -- path/to/custom.yaml` to load scenario-specific parameters. The [`main.rs`](https://github.com/makeecat/peng/blob/main/main.rs) entry point handles this file path argument and initializes the simulation using the specified configuration instead of the default.