use std::sync::Arc;
use log::warn;
use vexide::{
adi::encoder::AdiOpticalEncoder,
math::Angle,
smart::{PortError, imu::InertialSensor, rotation::RotationSensor},
sync::Mutex,
};
use crate::{peripherals::drivetrain::Differential, utils::units::Length};
#[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) -> Angle {
match self {
TrackingSensor::AdiOpticalEncoder(encoder) => {
encoder.lock().await.position().unwrap_or_else(|e| {
warn!("ADI Optical Encoder Position Error: {}", e);
Angle::ZERO
})
}
TrackingSensor::RotationSensor(encoder) => {
encoder.lock().await.position().unwrap_or_else(|e| {
warn!("Rotation Sensor Position Error: {}", e);
Angle::ZERO
})
}
TrackingSensor::Differential(dt) => dt.position().value(),
TrackingSensor::None => Angle::ZERO,
}
}
pub async fn reset_position(&self) -> Result<(), PortError> {
match self {
TrackingSensor::AdiOpticalEncoder(encoder) => encoder.lock().await.reset_position(),
TrackingSensor::RotationSensor(encoder) => encoder.lock().await.reset_position(),
TrackingSensor::Differential(dt) => dt.reset_position(),
TrackingSensor::None => Ok(()),
}
}
pub async fn set_position(&self, position: Angle) -> Result<(), PortError> {
match self {
TrackingSensor::AdiOpticalEncoder(encoder) => {
encoder.lock().await.set_position(position)
}
TrackingSensor::RotationSensor(encoder) => encoder.lock().await.set_position(position),
TrackingSensor::Differential(dt) => 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) -> Length {
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);
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,
}
}
}