use vexide::core::float::Float;
pub mod commands;
use crate::{
command::{Command, CommandUpdate},
tracking::Tracking,
};
use alloc::{boxed::Box, sync::Arc, vec::Vec};
use vexide::{
async_runtime::{
task::{spawn, Task},
time::sleep,
},
core::sync::{Barrier, Mutex},
devices::smart::Motor,
};
pub struct DifferentialDrivetrain<T: Tracking + Send + 'static> {
left_motors: DriveMotors,
right_motors: DriveMotors,
tracking: Arc<Mutex<T>>,
command: Arc<Mutex<Option<Box<dyn Command<Output = Voltages> + Send>>>>,
barrier: Arc<Barrier>,
_task: Task<()>,
}
impl<T: Tracking + Send> DifferentialDrivetrain<T> {
pub fn new(left_motors: DriveMotors, right_motors: DriveMotors, tracking: T) -> Self {
let command = Arc::new(Mutex::new(None));
let tracking = Arc::new(Mutex::new(tracking));
let barrier = Arc::new(Barrier::new(2));
Self {
left_motors: left_motors.clone(),
right_motors: right_motors.clone(),
tracking: tracking.clone(),
command: command.clone(),
barrier: barrier.clone(),
_task: spawn(async move {
loop {
let tracking_cx = tracking.lock().await.update();
let mut command_guard = command.lock().await;
if let Some(command) = command_guard.as_mut() {
match command.update(tracking_cx) {
CommandUpdate::Update(Voltages(left, right)) => {
for motor in left_motors.lock().await.iter_mut() {
_ = motor.set_voltage(left);
}
for motor in right_motors.lock().await.iter_mut() {
_ = motor.set_voltage(right);
}
}
CommandUpdate::Settled => {
*command_guard = None;
barrier.wait().await;
for motor in left_motors.lock().await.iter_mut() {
_ = motor.set_voltage(0.0);
}
for motor in right_motors.lock().await.iter_mut() {
_ = motor.set_voltage(0.0);
}
}
}
}
drop(command_guard);
sleep(Motor::DATA_WRITE_INTERVAL).await;
}
}),
}
}
pub async fn execute(&mut self, cmd: impl Command<Output = Voltages> + Send + 'static) {
*self.command.lock().await = Some(Box::new(cmd));
self.barrier.wait().await; }
pub fn tracking(&self) -> Arc<Mutex<T>> {
Arc::clone(&self.tracking)
}
pub fn command(&self) -> Arc<Mutex<Option<Box<dyn Command<Output = Voltages> + Send>>>> {
Arc::clone(&self.command)
}
pub fn left_motors(&self) -> DriveMotors {
Arc::clone(&self.left_motors)
}
pub fn right_motors(&self) -> DriveMotors {
Arc::clone(&self.right_motors)
}
}
pub type DriveMotors = Arc<Mutex<Vec<Motor>>>;
#[macro_export]
macro_rules! drive_motors {
( $( $item:expr ),* $(,)?) => {
{
use ::alloc::{sync::Arc, vec::Vec};
use ::vexide::{core::sync::Mutex, devices::smart::Motor};
let mut temp_vec: Vec<Motor> = Vec::new();
$(
temp_vec.push($item);
)*
Arc::new(Mutex::new(temp_vec))
}
};
}
pub use drive_motors;
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct Voltages(pub f64, pub f64);
impl Voltages {
pub fn normalized(&self, max: f64) -> Self {
let larger_magnitude = self.0.abs().max(self.1.abs()) / max;
let mut voltages = *self;
if larger_magnitude > 1.0 {
voltages.0 /= larger_magnitude;
voltages.1 /= larger_magnitude;
}
voltages
}
pub fn left(&self) -> f64 {
self.0
}
pub fn right(&self) -> f64 {
self.1
}
}