How to Configure Maze and Obstacle Parameters for Simulation in Peng
Configure maze and obstacle parameters in Peng by editing the maze section in 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 (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 (lines 27-34), which maintains the actual simulation state including bounds, obstacle lists, and random number generation.
During startup, src/main.rs orchestrates the loading sequence: it reads config/quad.yaml, parses it through Config::from_yaml, extracts the MazeConfig, and initializes the runtime via Maze::new (see 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 withlower_bounds, this establishes the simulation volume.num_obstacles: Ausizevalue 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 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 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:
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:
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, hard.yaml) without modifying the repository's default config/quad.yaml:
cargo run -- ./my_custom_maze.yaml
src/main.rs prints the loaded configuration path and uses the default only when no argument is provided.
Summary
- Edit
config/quad.yamlto modify maze bounds and obstacle properties without recompiling the Rust code. - Use five key parameters:
lower_bounds,upper_bounds,num_obstacles,obstacles_velocity_bounds, andobstacles_radius_boundsto control arena size and obstacle dynamics. - Understand the data flow: YAML →
MazeConfig(src/config.rs) →Mazeinstantiation (src/lib.rslines 46-52) →generate_obstacles(lines 74-92). - Override via CLI: Pass a custom YAML path as a command-line argument to
main.rsfor 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 at lines 15-27, while the runtime simulation structure Maze is defined in 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 loads YAML configuration at startup through Config::from_yaml. Simply edit 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 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 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 entry point handles this file path argument and initializes the simulation using the specified configuration instead of the default.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →