before cargo fix
This commit is contained in:
parent
04609b2d4f
commit
f8c7761d8c
|
|
@ -3,7 +3,7 @@
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "RaylibRustPhysics"
|
name = "RustPhysicsMQ"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clearscreen",
|
"clearscreen",
|
||||||
|
|
|
||||||
10
Cargo.toml
10
Cargo.toml
|
|
@ -1,8 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "RaylibRustPhysics"
|
name = "RustPhysicsMQ"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
default-run = "RaylibRustPhysics"
|
default-run = "RustPhysicsMQ"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
macroquad = "0.4.14"
|
macroquad = "0.4.14"
|
||||||
|
|
@ -17,9 +17,11 @@ serde = {version = "1.0.228", features = ["serde_derive"]}
|
||||||
toml = "0.9.8"
|
toml = "0.9.8"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "tools"
|
name = "batch"
|
||||||
path = "src/tools/main.rs"
|
path = "src/main_batch.rs"
|
||||||
|
|
||||||
|
|
||||||
[profile.dev.package.rapier3d]
|
[profile.dev.package.rapier3d]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::any::Any;
|
||||||
|
|
||||||
use crate::drone::controller::DroneController;
|
use crate::drone::controller::DroneController;
|
||||||
|
|
||||||
use crate::drone::JoystickInput;
|
pub use crate::drone::JoystickInput;
|
||||||
|
|
||||||
pub struct FPVController {
|
pub struct FPVController {
|
||||||
input: JoystickInput,
|
input: JoystickInput,
|
||||||
|
|
|
||||||
208
src/main.rs
208
src/main.rs
|
|
@ -1,154 +1,55 @@
|
||||||
|
use gilrs;
|
||||||
use macroquad::prelude as mq;
|
use macroquad::prelude as mq;
|
||||||
|
use nalgebra as na;
|
||||||
|
use rapier3d::prelude::*;
|
||||||
|
|
||||||
mod engine;
|
mod engine;
|
||||||
use engine::*;
|
use engine::*;
|
||||||
|
|
||||||
mod camera;
|
mod camera;
|
||||||
mod config;
|
|
||||||
mod drone;
|
mod drone;
|
||||||
mod helpers;
|
|
||||||
mod rendering;
|
mod rendering;
|
||||||
mod simulation;
|
|
||||||
|
|
||||||
mod graphics_util;
|
mod graphics_util;
|
||||||
|
|
||||||
use crate::drone::input::*;
|
use crate::{drone::fpvcontroller::JoystickInput, rendering::Renderer};
|
||||||
use crate::simulation::{SimMode, Simulation};
|
|
||||||
|
|
||||||
use crate::config::SimulationConfig;
|
|
||||||
use helpers::list_files;
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
const INPUTS_DIR: &str = "inputs/";
|
|
||||||
const CONFIGS_DIR: &str = "configurations/";
|
|
||||||
const RESULTS_DIR: &str = "results/";
|
|
||||||
|
|
||||||
fn window_conf() -> mq::Conf {
|
fn window_conf() -> mq::Conf {
|
||||||
mq::Conf {
|
mq::Conf {
|
||||||
window_title: "RustDroneSim".to_owned(),
|
window_title: "RustDroneSim".to_owned(),
|
||||||
window_resizable: true,
|
window_resizable: true,
|
||||||
|
// fullscreen: true,
|
||||||
platform: mq::miniquad::conf::Platform {
|
platform: mq::miniquad::conf::Platform {
|
||||||
|
// linux_backend: mq::miniquad::conf::LinuxBackend::WaylandOnly,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::env;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::thread::JoinHandle;
|
|
||||||
|
|
||||||
enum RunMode {
|
|
||||||
Batch,
|
|
||||||
Record { output: String },
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_cli() -> RunMode {
|
|
||||||
let mut args = env::args().skip(1);
|
|
||||||
|
|
||||||
match args.next().as_deref() {
|
|
||||||
Some("record") => {
|
|
||||||
let output = args.next().expect("record mode requires output file path");
|
|
||||||
RunMode::Record { output }
|
|
||||||
}
|
|
||||||
Some("batch") | None => RunMode::Batch,
|
|
||||||
Some(other) => panic!("Unknown mode: {}", other),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macroquad::main(window_conf)]
|
#[macroquad::main(window_conf)]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
match parse_cli() {
|
/* World Setup */
|
||||||
RunMode::Batch => run_batch().await,
|
let mut world = World::default();
|
||||||
RunMode::Record { output } => run_record(output).await,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run_batch() {
|
world.register_free_collider(
|
||||||
fs::remove_dir_all(RESULTS_DIR).unwrap();
|
ColliderBuilder::cuboid(30.0, 1.0, 30.0)
|
||||||
fs::create_dir_all(RESULTS_DIR).unwrap();
|
.translation(vector![0.0, -2.0, 0.0])
|
||||||
|
.restitution(0.5)
|
||||||
let input_files = list_files(INPUTS_DIR);
|
.build(),
|
||||||
let config_files = list_files(CONFIGS_DIR);
|
None,
|
||||||
|
|
||||||
let mut handles: Vec<JoinHandle<()>> = Default::default();
|
|
||||||
|
|
||||||
for input_path in input_files {
|
|
||||||
for config_path in &config_files {
|
|
||||||
let cp = config_path.clone();
|
|
||||||
let ip = input_path.clone();
|
|
||||||
handles.push(std::thread::spawn(move || {
|
|
||||||
run(&ip, &cp);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for handle in handles {
|
|
||||||
handle.join().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("All simulations completed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(input_path: &PathBuf, config_path: &PathBuf) {
|
|
||||||
let input_name = input_path.file_stem().unwrap().to_string_lossy();
|
|
||||||
|
|
||||||
let inputs = InputRecording::load_inputs_from_csv(input_path.to_str().unwrap())
|
|
||||||
.expect("Failed to load input recording");
|
|
||||||
let config_name = config_path.file_stem().unwrap().to_string_lossy();
|
|
||||||
|
|
||||||
let config: SimulationConfig =
|
|
||||||
toml::from_str(&fs::read_to_string(config_path).unwrap()).expect("Invalid config file");
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"Running simulation: input={} config={}",
|
|
||||||
input_name, config_name
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/* World */
|
let mut drone_controller = drone::pidcontroller::PIDController::default();
|
||||||
let mut world = World::new(config.tickrate);
|
drone_controller.set_input(JoystickInput {
|
||||||
|
throttle_input: 0.75,
|
||||||
/* Drone */
|
yaw_input: 0.4,
|
||||||
let drone = drone::Drone::new(
|
roll_input: 0.7,
|
||||||
|
pitch_input: 0.0,
|
||||||
|
});
|
||||||
|
let mut drone_obj = drone::Drone::new(
|
||||||
&mut world,
|
&mut world,
|
||||||
Box::new(drone::pidcontroller::PIDController {
|
Box::new(drone_controller),
|
||||||
target_rate: config.target_rate,
|
|
||||||
proportional_multiplier: config.proportional(),
|
|
||||||
integral_multiplier: config.integral(),
|
|
||||||
diferential_multiplier: config.diferential(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
drone::MotorCharacteristics {
|
|
||||||
max_thrust: config.max_thrust,
|
|
||||||
max_torque: config.max_torque,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
config.mass,
|
|
||||||
);
|
|
||||||
|
|
||||||
let result_file = format!("{}/{}_{}.csv", RESULTS_DIR, input_name, config_name);
|
|
||||||
|
|
||||||
let mut sim = Simulation::new(
|
|
||||||
drone,
|
|
||||||
world,
|
|
||||||
false,
|
|
||||||
SimMode::Playback(inputs.clone(), 0.0),
|
|
||||||
Some(result_file),
|
|
||||||
config.drone_tick_rate,
|
|
||||||
);
|
|
||||||
|
|
||||||
sim.run().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn run_record(output: String) {
|
|
||||||
println!("Recording inputs to {}", output);
|
|
||||||
|
|
||||||
let tickrate = 60000.0;
|
|
||||||
let mut world = World::new(tickrate);
|
|
||||||
|
|
||||||
let drone = drone::Drone::new(
|
|
||||||
&mut world,
|
|
||||||
Box::new(drone::pidcontroller::PIDController {
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
drone::MotorCharacteristics {
|
drone::MotorCharacteristics {
|
||||||
max_thrust: 2.6,
|
max_thrust: 2.6,
|
||||||
max_torque: 0.5,
|
max_torque: 0.5,
|
||||||
|
|
@ -157,14 +58,59 @@ async fn run_record(output: String) {
|
||||||
0.350,
|
0.350,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut sim = Simulation::new(
|
/* Renderer Setup */
|
||||||
drone,
|
let camera = camera::AttachedCamera::new(
|
||||||
world,
|
drone_obj.rb_handle,
|
||||||
true,
|
vector![1.0, 0.0, 0.0],
|
||||||
SimMode::Record(InputRecording::default(), output),
|
vector![0.5, 0.0, 0.0],
|
||||||
None,
|
|
||||||
600,
|
|
||||||
);
|
);
|
||||||
|
let mut renderer = Renderer::new(Box::new(camera));
|
||||||
|
|
||||||
sim.run().unwrap();
|
renderer.light.set_location(
|
||||||
|
vector![70.0, 150.0, -90.0].into(),
|
||||||
|
vector![-0.4, -0.7, 0.6].into(),
|
||||||
|
);
|
||||||
|
renderer.update_light(&world);
|
||||||
|
|
||||||
|
let mut input = JoystickInput::default();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
renderer.update_camera(&world);
|
||||||
|
|
||||||
|
if mq::is_key_pressed(mq::KeyCode::Q) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Physics
|
||||||
|
world.step();
|
||||||
|
let _ = clearscreen::clear();
|
||||||
|
drone_obj.process_tick(&mut world);
|
||||||
|
|
||||||
|
// Rendering
|
||||||
|
renderer.draw(&mut world);
|
||||||
|
|
||||||
|
if world.tick % (20) == 0 {
|
||||||
|
// renderer.update_light(&world);
|
||||||
|
// world.clear_ofb();
|
||||||
|
mq::next_frame().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_objects(world: &mut World) {
|
||||||
|
for i in 0..1 {
|
||||||
|
let body = world.register_body(
|
||||||
|
RigidBodyBuilder::dynamic()
|
||||||
|
.translation(vector![0.0, 50.0 + i as f32, 0.0])
|
||||||
|
.rotation(vector![std::f32::consts::PI / 4.2, i as f32, i as f32])
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
|
world.register_collider(
|
||||||
|
ColliderBuilder::cuboid(2.0, 2.0, 2.0)
|
||||||
|
.restitution(0.1)
|
||||||
|
.build(),
|
||||||
|
body,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,170 @@
|
||||||
|
use macroquad::prelude as mq;
|
||||||
|
|
||||||
|
mod engine;
|
||||||
|
use engine::*;
|
||||||
|
mod camera;
|
||||||
|
mod config;
|
||||||
|
mod drone;
|
||||||
|
mod helpers;
|
||||||
|
mod rendering;
|
||||||
|
mod simulation;
|
||||||
|
|
||||||
|
mod graphics_util;
|
||||||
|
|
||||||
|
use crate::drone::input::*;
|
||||||
|
use crate::simulation::{SimMode, Simulation};
|
||||||
|
|
||||||
|
use crate::config::SimulationConfig;
|
||||||
|
use helpers::list_files;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
const INPUTS_DIR: &str = "inputs/";
|
||||||
|
const CONFIGS_DIR: &str = "configurations/";
|
||||||
|
const RESULTS_DIR: &str = "results/";
|
||||||
|
|
||||||
|
fn window_conf() -> mq::Conf {
|
||||||
|
mq::Conf {
|
||||||
|
window_title: "RustDroneSim".to_owned(),
|
||||||
|
window_resizable: true,
|
||||||
|
platform: mq::miniquad::conf::Platform {
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::thread::JoinHandle;
|
||||||
|
|
||||||
|
enum RunMode {
|
||||||
|
Batch,
|
||||||
|
Record { output: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_cli() -> RunMode {
|
||||||
|
let mut args = env::args().skip(1);
|
||||||
|
|
||||||
|
match args.next().as_deref() {
|
||||||
|
Some("record") => {
|
||||||
|
let output = args.next().expect("record mode requires output file path");
|
||||||
|
RunMode::Record { output }
|
||||||
|
}
|
||||||
|
Some("batch") | None => RunMode::Batch,
|
||||||
|
Some(other) => panic!("Unknown mode: {}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macroquad::main(window_conf)]
|
||||||
|
async fn main() {
|
||||||
|
match parse_cli() {
|
||||||
|
RunMode::Batch => run_batch().await,
|
||||||
|
RunMode::Record { output } => run_record(output).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_batch() {
|
||||||
|
fs::remove_dir_all(RESULTS_DIR).unwrap();
|
||||||
|
fs::create_dir_all(RESULTS_DIR).unwrap();
|
||||||
|
|
||||||
|
let input_files = list_files(INPUTS_DIR);
|
||||||
|
let config_files = list_files(CONFIGS_DIR);
|
||||||
|
|
||||||
|
let mut handles: Vec<JoinHandle<()>> = Default::default();
|
||||||
|
|
||||||
|
for input_path in input_files {
|
||||||
|
for config_path in &config_files {
|
||||||
|
let cp = config_path.clone();
|
||||||
|
let ip = input_path.clone();
|
||||||
|
handles.push(std::thread::spawn(move || {
|
||||||
|
run(&ip, &cp);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for handle in handles {
|
||||||
|
handle.join().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("All simulations completed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(input_path: &PathBuf, config_path: &PathBuf) {
|
||||||
|
let input_name = input_path.file_stem().unwrap().to_string_lossy();
|
||||||
|
|
||||||
|
let inputs = InputRecording::load_inputs_from_csv(input_path.to_str().unwrap())
|
||||||
|
.expect("Failed to load input recording");
|
||||||
|
let config_name = config_path.file_stem().unwrap().to_string_lossy();
|
||||||
|
|
||||||
|
let config: SimulationConfig =
|
||||||
|
toml::from_str(&fs::read_to_string(config_path).unwrap()).expect("Invalid config file");
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Running simulation: input={} config={}",
|
||||||
|
input_name, config_name
|
||||||
|
);
|
||||||
|
|
||||||
|
/* World */
|
||||||
|
let mut world = World::new(config.tickrate);
|
||||||
|
|
||||||
|
/* Drone */
|
||||||
|
let drone = drone::Drone::new(
|
||||||
|
&mut world,
|
||||||
|
Box::new(drone::pidcontroller::PIDController {
|
||||||
|
target_rate: config.target_rate,
|
||||||
|
proportional_multiplier: config.proportional(),
|
||||||
|
integral_multiplier: config.integral(),
|
||||||
|
diferential_multiplier: config.diferential(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
drone::MotorCharacteristics {
|
||||||
|
max_thrust: config.max_thrust,
|
||||||
|
max_torque: config.max_torque,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
config.mass,
|
||||||
|
);
|
||||||
|
|
||||||
|
let result_file = format!("{}/{}_{}.csv", RESULTS_DIR, input_name, config_name);
|
||||||
|
|
||||||
|
let mut sim = Simulation::new(
|
||||||
|
drone,
|
||||||
|
world,
|
||||||
|
false,
|
||||||
|
SimMode::Playback(inputs.clone(), 0.0),
|
||||||
|
Some(result_file),
|
||||||
|
config.drone_tick_rate,
|
||||||
|
);
|
||||||
|
|
||||||
|
sim.run().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_record(output: String) {
|
||||||
|
println!("Recording inputs to {}", output);
|
||||||
|
|
||||||
|
let tickrate = 60000.0;
|
||||||
|
let mut world = World::new(tickrate);
|
||||||
|
|
||||||
|
let drone = drone::Drone::new(
|
||||||
|
&mut world,
|
||||||
|
Box::new(drone::pidcontroller::PIDController {
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
drone::MotorCharacteristics {
|
||||||
|
max_thrust: 2.6,
|
||||||
|
max_torque: 0.5,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
0.350,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut sim = Simulation::new(
|
||||||
|
drone,
|
||||||
|
world,
|
||||||
|
true,
|
||||||
|
SimMode::Record(InputRecording::default(), output),
|
||||||
|
None,
|
||||||
|
600,
|
||||||
|
);
|
||||||
|
|
||||||
|
sim.run().unwrap();
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue