mod algorithm;
pub mod control;
const LOOPRATE: Duration = Duration::from_millis(10);
use std::time::Duration;
use control::PursuitControl;
use snafu::Snafu;
use vexide::time::sleep;
use crate::{
motion::{
localization::{Localizer, tracker::devices::TrackingSensorError},
pursuit::algorithm::abs_arc_point,
},
peripherals::drivetrain::{Differential, DrivetrainError},
utils::{
geo::{self, Pose},
units::Length,
},
};
pub trait IsLocalizerError: std::error::Error + 'static {}
impl IsLocalizerError for TrackingSensorError {}
#[derive(Debug, Snafu)]
pub enum PursuitError<E = TrackingSensorError>
where E: IsLocalizerError {
#[snafu(transparent)]
LocalizerError {
source: E,
},
#[snafu(transparent)]
DrivetrainError {
source: DrivetrainError,
},
Unknown {
string: String,
},
}
#[derive(Debug, Clone, Copy)]
pub struct Pursuit {
pub lookahead: Length,
}
impl Pursuit {
pub fn new(lookahead: Length) -> Self { Self { lookahead } }
pub async fn follow<C: PursuitControl, E>(
&self,
odom: &mut impl Localizer<E>,
drivetrain: &Differential,
ctrl_algorithm: &C,
path: geo::Path,
) -> Result<(), PursuitError<E>>
where
E: IsLocalizerError, {
let mut run = true;
while run {
let odometry_values = odom.get_coords();
let (x, y, t) = (odometry_values.x, odometry_values.y, odometry_values.t);
let cir = geo::Circle {
x: x.as_inches(),
y: y.as_inches(),
r: self.lookahead.as_inches(),
};
let target = algorithm::pursuit_target(path.clone(), cir);
let (tarx, tary) = abs_arc_point(
Pose::new(x, y, t),
Length::as_inches(Length::from_inches(target.x)),
Length::as_inches(Length::from_inches(target.y)),
);
let ((powl, powr), run_curr) = ctrl_algorithm.control(
Length::from_inches(tarx),
Length::from_inches(tary),
self.lookahead,
);
drivetrain.set_left_voltage(powl)?;
drivetrain.set_right_voltage(powr)?;
run = run_curr;
odom.tick().await?;
sleep(LOOPRATE).await;
}
Ok(())
}
pub async fn tick<C: PursuitControl, E>(
&self,
odom: &mut impl Localizer<E>,
drivetrain: &Differential,
ctrl_algorithm: &C,
path: geo::Path,
) -> Result<bool, PursuitError<E>>
where
E: IsLocalizerError, {
let odometry_values = odom.get_coords();
let (x, y, t) = (odometry_values.x, odometry_values.y, odometry_values.t);
let cir = geo::Circle {
x: x.as_inches(),
y: y.as_inches(),
r: self.lookahead.as_inches(),
};
let target = algorithm::pursuit_target(path.clone(), cir);
let (tarx, tary) = abs_arc_point(
Pose::new(x, y, t),
Length::as_inches(Length::from_inches(target.x)),
Length::as_inches(Length::from_inches(target.y)),
);
let ((powl, powr), run_curr) = ctrl_algorithm.control(
Length::from_inches(tarx),
Length::from_inches(tary),
self.lookahead,
);
drivetrain.set_left_voltage(powl)?;
drivetrain.set_right_voltage(powr)?;
odom.tick().await?;
Ok(run_curr)
}
}