use std::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::{Differential, 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,
},
Unknown {
string: String,
},
}
#[derive(Clone)]
pub enum TrackingSensor {
AdiOpticalEncoder(Arc<Mutex<AdiOpticalEncoder>>),
RotationSensor(Arc<Mutex<RotationSensor>>),
Differential(Differential),
None,
}
impl TrackingSensor {
pub fn from_adi_optical_encoder(encoder: AdiOpticalEncoder) -> Self {
Self::AdiOpticalEncoder(Arc::new(Mutex::new(encoder)))
}
pub fn from_rotation_sensor(sensor: RotationSensor) -> Self {
Self::RotationSensor(Arc::new(Mutex::new(sensor)))
}
pub fn from_differential(drivetrain: Differential) -> Self { Self::Differential(drivetrain) }
pub fn new_none() -> Self { Self::None }
pub async fn position(&self) -> Result<Angle, TrackingSensorError> {
match self {
TrackingSensor::AdiOpticalEncoder(encoder) => Ok(encoder.lock().await.position()?),
TrackingSensor::RotationSensor(encoder) => Ok(encoder.lock().await.position()?),
TrackingSensor::Differential(dt) => Ok(dt.position().value()),
TrackingSensor::None => Ok(Angle::ZERO),
}
}
pub async fn reset_position(&self) -> Result<(), TrackingSensorError> {
match self {
TrackingSensor::AdiOpticalEncoder(encoder) => {
Ok(encoder.lock().await.reset_position()?)
}
TrackingSensor::RotationSensor(encoder) => Ok(encoder.lock().await.reset_position()?),
TrackingSensor::Differential(dt) => Ok(dt.reset_position()?),
TrackingSensor::None => Ok(()),
}
}
pub async fn set_position(&self, position: Angle) -> Result<(), TrackingSensorError> {
match self {
TrackingSensor::AdiOpticalEncoder(encoder) => {
Ok(encoder.lock().await.set_position(position)?)
}
TrackingSensor::RotationSensor(encoder) => {
Ok(encoder.lock().await.set_position(position)?)
}
TrackingSensor::Differential(dt) => Ok(dt.set_position(position)?),
TrackingSensor::None => Ok(()),
}
}
}
#[derive(Clone)]
pub struct TrackerPod {
pub sensor: TrackingSensor,
pub wheel_diameter: Length,
pub driven_gear: f64,
pub driving_gear: f64,
pub offset: Length,
}
impl TrackerPod {
pub fn new(
sensor: TrackingSensor,
wheel_diameter: Length,
driven_gear: f64,
driving_gear: f64,
offset: Length,
) -> Self {
Self {
sensor,
wheel_diameter,
driven_gear,
driving_gear,
offset,
}
}
pub async fn dist(&self) -> Result<Length, TrackingSensorError> {
let angle = self.sensor.position().await?;
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)
}
}
#[derive(Clone)]
pub struct TrackerMech {
pub vertical_tracker: TrackerPod,
pub horizontal_tracker: TrackerPod,
pub imu: Arc<Mutex<InertialSensor>>,
}
impl TrackerMech {
pub fn new(
vertical_tracker: TrackerPod,
horizontal_tracker: TrackerPod,
imu: Arc<Mutex<InertialSensor>>,
) -> Self {
Self {
vertical_tracker,
horizontal_tracker,
imu,
}
}
}