RustPhysicsMQ/src/simulation.rs

222 lines
6.6 KiB
Rust
Raw Normal View History

use macroquad::prelude as mq;
use nalgebra as na;
use rapier3d::prelude as rp;
use std::error::Error;
use crate::{
drone::{
controller::DroneController,
input::{InputRecording, JoystickInput},
Drone,
},
engine::World,
2026-02-06 13:59:27 +00:00
logger::CsvLogger,
rendering::Renderer,
};
pub enum SimMode {
Record(InputRecording, String),
Playback(InputRecording, f32),
}
2026-02-06 13:59:27 +00:00
enum StepOutcome {
Continue,
Exit,
}
pub struct DataResultRecord {
pub time: f32,
pub current_angular_velocity: na::Vector3<f32>,
pub target_angular_velocity: na::Vector3<f32>,
pub applied_motor_offset: na::Vector3<f32>,
pub desired_motor_offset: na::Vector3<f32>,
}
pub struct Simulation {
pub drone: Drone,
pub world: World,
pub mode: SimMode,
2026-02-06 13:59:27 +00:00
logger: Option<CsvLogger>,
drone_tick_rate: u64,
}
impl Simulation {
pub fn new(
drone: Drone,
world: World,
mode: SimMode,
results_file: Option<String>,
drone_tick_rate: u64,
) -> Self {
2026-02-06 13:59:27 +00:00
let logger = match &results_file {
Some(path) => Some(CsvLogger::new(path).unwrap()),
None => None,
};
let mut s = Self {
drone,
world,
mode,
2026-02-06 13:59:27 +00:00
logger,
drone_tick_rate,
};
s.world.register_free_collider(
rp::ColliderBuilder::cuboid(30.0, 1.0, 30.0)
.translation(na::vector![0.0, -2.0, 0.0])
.restitution(0.5)
.sensor(true)
.build(),
None,
);
return s;
}
2026-02-04 17:54:41 +00:00
pub async fn run_and_render(&mut self) -> Result<(), Box<dyn Error>> {
let mut renderer: Renderer = Renderer::new(Box::new(crate::camera::AttachedCamera::new(
self.drone.rb_handle,
na::vector![1.0, 0.0, 0.0],
na::vector![0.5, 0.0, 0.0],
)));
renderer.light.set_location(
na::vector![70.0, 150.0, -90.0].into(),
na::vector![-0.4, -0.7, 0.6].into(),
);
renderer.update_light(&self.world);
loop {
2026-02-06 13:59:27 +00:00
match self.step()? {
StepOutcome::Continue => {
if self.world.tick
% ((self.world.integration_parameters.inv_dt() / 60.0) as u64)
== 0
{
renderer.update_camera(&self.world);
renderer.draw(&mut self.world);
mq::next_frame().await;
}
}
2026-02-06 13:59:27 +00:00
StepOutcome::Exit => {
self.shutdown()?;
return Ok(());
}
2026-02-04 17:54:41 +00:00
}
}
}
pub fn run(&mut self) -> Result<(), Box<dyn Error>> {
loop {
2026-02-06 13:59:27 +00:00
match self.step()? {
StepOutcome::Continue => {}
StepOutcome::Exit => {
self.shutdown()?;
return Ok(());
2026-02-04 17:54:41 +00:00
}
2026-02-06 13:59:27 +00:00
}
}
}
2026-02-04 17:54:41 +00:00
2026-02-06 13:59:27 +00:00
fn step(&mut self) -> Result<StepOutcome, Box<dyn Error>> {
let current_input: JoystickInput;
let current_time = self.world.get_time() as f32;
match &mut self.mode {
SimMode::Record(recording, _) => {
current_input = recording.add_input_from_keyboard(current_time);
if mq::is_key_pressed(mq::KeyCode::Q) {
return Ok(StepOutcome::Exit);
2026-02-04 17:54:41 +00:00
}
}
2026-02-06 13:59:27 +00:00
SimMode::Playback(recording, start_time) => {
let playback_time = current_time - *start_time;
current_input = recording.get_input(playback_time);
2026-02-04 17:54:41 +00:00
2026-02-06 13:59:27 +00:00
if recording.ended(playback_time) {
println!("Playback ended.");
return Ok(StepOutcome::Exit);
}
}
2026-02-06 13:59:27 +00:00
}
2026-02-04 17:54:41 +00:00
2026-02-06 13:59:27 +00:00
// --- Physics ---
self.world.step();
if self.world.tick
% ((self.world.integration_parameters.inv_dt() / self.drone_tick_rate as f32) as u64)
== 0
{
2026-02-04 17:54:41 +00:00
if let Some(cont) = self
.drone
.controller
.as_mut_any()
2026-02-06 13:59:27 +00:00
.downcast_mut::<crate::drone::stacked::StackedController>()
2026-02-04 17:54:41 +00:00
{
2026-02-06 13:59:27 +00:00
cont.set_input(current_input);
2026-02-04 17:54:41 +00:00
}
2026-02-06 13:59:27 +00:00
self.drone.process_controller_tick(&mut self.world);
}
2026-02-06 13:59:27 +00:00
self.drone.process_tick(&mut self.world);
let mut target_angular_vel: na::Vector3<f32> = na::vector![
current_input.roll_input,
current_input.yaw_input,
current_input.pitch_input,
] * 3.14;
let mut desired_motor_diff: na::Vector3<f32> = na::vector![0.0, 0.0, 0.0];
let applied_motor_diff: na::Vector3<f32> = na::vector![
(self.drone.current_throttles[1] + self.drone.current_throttles[2]
- self.drone.current_throttles[0]
- self.drone.current_throttles[3]),
(self.drone.current_throttles[0] + self.drone.current_throttles[2]
- self.drone.current_throttles[1]
- self.drone.current_throttles[3]),
(self.drone.current_throttles[2] + self.drone.current_throttles[3]
- self.drone.current_throttles[0]
- self.drone.current_throttles[1])
] / 2.0;
if let Some(cont) = self
.drone
.controller
.as_mut_any()
.downcast_mut::<crate::drone::pidcontroller::PIDController>()
{
desired_motor_diff = cont.get_desired_motor_diffs();
target_angular_vel = cont.get_desired_angular_velocity();
}
2026-02-06 13:59:27 +00:00
if let Some(logger) = &mut self.logger {
logger
.log(&crate::logger::SimLogRow::from_data(
self.world.get_time(),
target_angular_vel,
self.drone
.get_rot(&self.world)
.inverse()
.transform_vector(&self.drone.get_angvel(&self.world))
.into(),
applied_motor_diff,
desired_motor_diff,
))
.unwrap();
}
Ok(StepOutcome::Continue)
}
fn shutdown(&mut self) -> Result<(), Box<dyn Error>> {
// Save input recording if needed
if let SimMode::Record(recording, dest) = &self.mode {
recording.save_inputs_to_csv(dest)?;
println!("Input recording saved to {}", dest);
}
2026-02-06 13:59:27 +00:00
if let Some(logger) = &mut self.logger {
logger.flush()?;
}
Ok(())
}
}