diff --git a/Cargo.toml b/Cargo.toml index 6e01a450..c2373c11 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ rust-version = "1.76" authors = ["Yang Zhou "] description = "Peng is a minimal quadrotor pipeline including quadrotor dynamics, IMU simulation, various trajectory planners, PID controller and depth map rendering." license = "MIT OR Apache-2.0" -documentation = "https://makeecat.github.io/Peng" +documentation = "https://docs.rs/peng_quad/latest/peng_quad" homepage = "https://github.com/makeecat/Peng" repository = "https://github.com/makeecat/Peng" categories = [ diff --git a/README.md b/README.md index fb54f9fc..7598d018 100644 --- a/README.md +++ b/README.md @@ -11,26 +11,24 @@ Peng is a minimal Rust-based quadrotor simulation pipeline. It includes a simulator, controller, and planner, providing a basic framework for simulating quadrotor dynamics and control. ![demo](assets/Peng_demo.gif) ## Getting Started -terminal 1 -``` + +### Installation from Crates.io +```bash cargo install rerun-cli -rerun -``` -terminal 2 -``` cargo install peng_quad peng_quad config/quad.yaml ``` -Please follow [rerun troubleshooting](https://rerun.io/docs/getting-started/troubleshooting) if you are using Linux or WSL2. -If you want to build from latest source -``` -git clone https://github.com/makeecat/Peng.git +### Installation from Source +```bash +cargo install rerun-cli +git clone https://github.com/makeecat/Peng.git && cd Peng cargo run --release config/quad.yaml ``` -You can configure the simulation through config file, see quad.yaml for example. +You can configure the simulation through config file, see [quad.yaml](config/quad.yaml) for example. +Please follow [rerun troubleshooting](https://rerun.io/docs/getting-started/troubleshooting) if you are using Linux or WSL2. ## Overview ### Quadrotor Simulator @@ -96,20 +94,19 @@ The markdown lines are used for generating the documentation. ```markdown =============================================================================== Language Files Lines Code Comments Blanks -=============================================================================== - SVG 1 1 1 0 0 + SVG 2 492 480 0 12 TOML 1 31 30 0 1 - YAML 1 92 85 0 7 + YAML 1 94 86 0 8 ------------------------------------------------------------------------------- - Markdown 4 274 0 210 64 + Markdown 4 273 0 207 66 |- Markdown 1 17 0 17 0 - (Total) 291 0 227 64 + (Total) 290 0 224 66 ------------------------------------------------------------------------------- - Rust 3 1475 1426 13 36 + Rust 3 1487 1438 13 36 |- Markdown 1 300 0 300 0 - (Total) 1775 1426 313 36 + (Total) 1787 1438 313 36 =============================================================================== - Total 10 1873 1542 223 108 + Total 11 2377 2034 220 123 =============================================================================== ``` diff --git a/config/quad.yaml b/config/quad.yaml index a1413205..992aea8f 100644 --- a/config/quad.yaml +++ b/config/quad.yaml @@ -1,3 +1,5 @@ +use_rerun: true + simulation: control_frequency: 200.0 simulation_frequency: 1000.0 diff --git a/src/config.rs b/src/config.rs index e5707c76..3a839005 100644 --- a/src/config.rs +++ b/src/config.rs @@ -8,6 +8,7 @@ pub struct Config { pub camera: CameraConfig, pub mesh: MeshConfig, pub planner_schedule: Vec, + pub use_rerun: bool, } #[derive(serde::Deserialize)] diff --git a/src/lib.rs b/src/lib.rs index 04ebad1f..fdf55c67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,8 @@ use std::f32::consts::PI; pub enum SimulationError { #[error("Rerun error: {0}")] RerunError(#[from] rerun::RecordingStreamError), + #[error("Rerun spawn error: {0}")] + RerunSpawnError(#[from] rerun::SpawnError), #[error("Nalgebra error: {0}")] NalgebraError(String), #[error("Normal error: {0}")] diff --git a/src/main.rs b/src/main.rs index c2650616..74d468d4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,18 +5,18 @@ use config::Config; use peng_quad::*; fn main() -> Result<(), SimulationError> { env_logger::builder() - .format_target(false) - .format_module_path(false) .parse_env(env_logger::Env::default().default_filter_or("info")) .init(); + let mut config_str = "config/quad.yaml"; let args: Vec = env::args().collect(); if args.len() != 2 { - return Err(SimulationError::OtherError(format!( - "Usage: {} ", - args[0] - ))); + log::warn!("Usage: {} .", args[0]); + log::warn!("Loading default configuration: config/quad.yaml"); + } else { + log::info!("Loading configuration: {}", args[1]); + config_str = &args[1]; } - let config = Config::from_yaml(&args[1]).expect("Failed to load configuration"); + let config = Config::from_yaml(config_str).expect("Failed to load configuration"); let mut quad = Quadrotor::new( 1.0 / config.simulation.simulation_frequency, config.quadrotor.mass, @@ -37,8 +37,6 @@ fn main() -> Result<(), SimulationError> { config.imu.gyro_noise_std, config.imu.bias_instability, ); - log::info!("Please start a rerun-cli in another terminal.\n> cargo install rerun-cli.\n> rerun\nWaiting for connection to rerun..."); - let rec = rerun::RecordingStreamBuilder::new("Peng").connect()?; let upper_bounds = Vector3::from(config.maze.upper_bounds); let lower_bounds = Vector3::from(config.maze.lower_bounds); let mut maze = Maze::new(lower_bounds, upper_bounds, config.maze.num_obstacles); @@ -51,13 +49,8 @@ fn main() -> Result<(), SimulationError> { let mut planner_manager = PlannerManager::new(Vector3::zeros(), 0.0); let mut trajectory = Trajectory::new(Vector3::new(0.0, 0.0, 0.0)); let mut depth_buffer: Vec = vec![0.0; camera.resolution.0 * camera.resolution.1]; - rec.set_time_seconds("timestamp", 0); - log_mesh(&rec, config.mesh.division, config.mesh.spacing)?; - log_maze_tube(&rec, &maze)?; - log_maze_obstacles(&rec, &maze)?; let mut previous_thrust = 0.0; let mut previous_torque = Vector3::zeros(); - let mut i = 0; let planner_config = config .planner_schedule .iter() @@ -67,10 +60,23 @@ fn main() -> Result<(), SimulationError> { params: step.params.clone(), }) .collect(); + log::info!("Use rerun.io: {}", config.use_rerun); + let rec = if config.use_rerun { + rerun::spawn(&rerun::SpawnOptions::default())?; + Some(rerun::RecordingStreamBuilder::new("Peng").connect()?) + } else { + None + }; + if let Some(rec) = &rec { + rec.set_time_seconds("timestamp", 0); + log_mesh(&rec, config.mesh.division, config.mesh.spacing)?; + log_maze_tube(&rec, &maze)?; + log_maze_obstacles(&rec, &maze)?; + } log::info!("Starting simulation..."); + let mut i = 0; loop { let time = quad.time_step * i as f32; - rec.set_time_seconds("timestamp", time); maze.update_obstacles(quad.time_step); update_planner( &mut planner_manager, @@ -120,27 +126,30 @@ fn main() -> Result<(), SimulationError> { / config.simulation.log_frequency as usize) == 0 { - if trajectory.add_point(quad.position) { - log_trajectory(&rec, &trajectory)?; + if let Some(rec) = &rec { + rec.set_time_seconds("timestamp", time); + if trajectory.add_point(quad.position) { + log_trajectory(&rec, &trajectory)?; + } + log_data( + &rec, + &quad, + &desired_position, + &desired_velocity, + &_measured_accel, + &_measured_gyro, + )?; + camera.render_depth(&quad.position, &quad.orientation, &maze, &mut depth_buffer)?; + log_depth_image( + &rec, + &depth_buffer, + camera.resolution.0, + camera.resolution.1, + camera.near, + camera.far, + )?; + log_maze_obstacles(&rec, &maze)?; } - log_data( - &rec, - &quad, - &desired_position, - &desired_velocity, - &_measured_accel, - &_measured_gyro, - )?; - camera.render_depth(&quad.position, &quad.orientation, &maze, &mut depth_buffer)?; - log_depth_image( - &rec, - &depth_buffer, - camera.resolution.0, - camera.resolution.1, - camera.near, - camera.far, - )?; - log_maze_obstacles(&rec, &maze)?; } i += 1; if time >= config.simulation.duration {