use std::{cell::BorrowMutError, sync::Arc};
use snafu::Snafu;
use vexide::{
adi::encoder::AdiOpticalEncoder,
math::Angle,
smart::{
PortError,
imu::{InertialError, InertialSensor},
rotation::RotationSensor,
},
sync::Mutex,
};
use crate::{peripherals::drivetrain::DrivetrainError, utils::units::Length};
#[derive(Debug, Snafu)]
pub enum TrackingSensorError {
#[snafu(transparent)]
PortError {
source: PortError,
},
#[snafu(transparent)]
DrivetrainError {
source: DrivetrainError,
},
#[snafu(transparent)]
InertialError {
source: InertialError,
},
#[snafu(transparent)]
BorrowMutError {
source: BorrowMutError,
},
Unknown {
string: String,
},
}
pub trait Trackable {
fn track_position(&mut self) -> Result<Angle, TrackingSensorError>;
fn reset_track_position(&mut self) -> Result<(), TrackingSensorError>;
fn set_track_position(&mut self, position: Angle) -> Result<(), TrackingSensorError>;
}
pub trait HeadingSensor {
fn heading(&mut self) -> Result<Angle, TrackingSensorError>;
fn reset_heading(&mut self) -> Result<(), TrackingSensorError>;
fn set_heading(&mut self, heading: Angle) -> Result<(), TrackingSensorError>;
}
impl Trackable for AdiOpticalEncoder {
fn track_position(&mut self) -> Result<Angle, TrackingSensorError> { Ok(Self::position(self)?) }
fn reset_track_position(&mut self) -> Result<(), TrackingSensorError> {
Ok(Self::reset_position(self)?)
}
fn set_track_position(&mut self, position: Angle) -> Result<(), TrackingSensorError> {
Ok(Self::set_position(self, position)?)
}
}
impl Trackable for RotationSensor {
fn track_position(&mut self) -> Result<Angle, TrackingSensorError> { Ok(Self::position(self)?) }
fn reset_track_position(&mut self) -> Result<(), TrackingSensorError> {
Ok(Self::reset_position(self)?)
}
fn set_track_position(&mut self, position: Angle) -> Result<(), TrackingSensorError> {
Ok(Self::set_position(self, position)?)
}
}
impl HeadingSensor for InertialSensor {
fn heading(&mut self) -> Result<Angle, TrackingSensorError> { Ok(Self::rotation(self)?) }
fn reset_heading(&mut self) -> Result<(), TrackingSensorError> {
Ok(Self::reset_rotation(self)?)
}
fn set_heading(&mut self, heading: Angle) -> Result<(), TrackingSensorError> {
Ok(Self::set_rotation(self, heading)?)
}
}
pub struct TrackerPod<'s, S: Trackable> {
pub sensor: &'s mut S,
pub wheel_diameter: Length,
pub driven_gear: f64,
pub driving_gear: f64,
pub offset: Length,
}
impl<'s, S: Trackable> TrackerPod<'s, S> {
pub fn new(
sensor: &'s mut S,
wheel_diameter: Length,
driven_gear: f64,
driving_gear: f64,
offset: Length,
) -> Self {
Self {
sensor,
wheel_diameter,
driven_gear,
driving_gear,
offset,
}
}
pub fn dist(&mut self) -> Result<Length, TrackingSensorError> {
let angle = self.sensor.track_position()?;
let gear_ratio = self.driving_gear as f64 / self.driven_gear as f64;
let distance = angle.as_radians() * gear_ratio * (self.wheel_diameter / 2.0);
Ok(distance)
}
}
pub struct TrackerMech<'v, 'h, V: Trackable, H: Trackable, I: HeadingSensor> {
pub vertical_tracker: TrackerPod<'v, V>,
pub horizontal_tracker: TrackerPod<'h, H>,
pub imu: Arc<Mutex<I>>,
}
impl<'v, 'h, V: Trackable, H: Trackable, I: HeadingSensor> TrackerMech<'v, 'h, V, H, I> {
pub fn new(
vertical_tracker: TrackerPod<'v, V>,
horizontal_tracker: TrackerPod<'h, H>,
imu: Arc<Mutex<I>>,
) -> Self {
Self {
vertical_tracker,
horizontal_tracker,
imu,
}
}
}