pros_devices/
position.rs

1//! Generic angular position type for motors and sensors.
2//!
3//! Positions have many conversion functions as well as common operator implementations for ease of use.
4
5use core::{cmp::Ordering, ops::*};
6
7//TODO: Add more unit types to this.
8/// Represents an angular position.
9#[derive(Clone, Copy, Debug)]
10pub enum Position {
11    /// Degrees of rotation.
12    Degrees(f64),
13    /// Counts of full rotations, 360 degrees.
14    Rotations(f64),
15    /// Raw encoder ticks.
16    Counts(i64),
17}
18
19impl Position {
20    /// Creates a position from a specified number of degrees.
21    pub const fn from_degrees(position: f64) -> Self {
22        Self::Degrees(position)
23    }
24
25    /// Creates a position from a specified number of rotations.
26    pub const fn from_rotations(position: f64) -> Self {
27        Self::Rotations(position)
28    }
29
30    /// Creates a position from a specified number of counts (raw encoder tics).
31    pub const fn from_counts(position: i64) -> Self {
32        Self::Counts(position)
33    }
34
35    /// Converts a position into degrees.
36    pub fn into_degrees(self) -> f64 {
37        match self {
38            Self::Degrees(num) => num,
39            Self::Rotations(num) => num * 360.0,
40            Self::Counts(num) => num as f64 * (360.0 / 4096.0),
41        }
42    }
43
44    /// Converts a position into rotations.
45    pub fn into_rotations(self) -> f64 {
46        match self {
47            Self::Degrees(num) => num / 360.0,
48            Self::Rotations(num) => num,
49            Self::Counts(num) => num as f64 * 4096.0,
50        }
51    }
52
53    /// Converts a position into counts (raw encoder ticks).
54    pub fn into_counts(self) -> i64 {
55        match self {
56            Self::Degrees(num) => (num * 4096.0 / 360.0) as i64,
57            Self::Rotations(num) => (num * 4096.0) as i64,
58            Self::Counts(num) => num,
59        }
60    }
61}
62
63impl Add for Position {
64    type Output = Self;
65
66    fn add(self, rhs: Self) -> Self::Output {
67        Self::from_degrees(self.into_degrees() + rhs.into_degrees())
68    }
69}
70
71impl AddAssign for Position {
72    fn add_assign(&mut self, rhs: Self) {
73        *self = *self + rhs;
74    }
75}
76
77impl Sub for Position {
78    type Output = Self;
79
80    fn sub(self, rhs: Self) -> Self::Output {
81        Self::from_degrees(self.into_degrees() - rhs.into_degrees())
82    }
83}
84
85impl SubAssign for Position {
86    fn sub_assign(&mut self, rhs: Self) {
87        *self = *self - rhs;
88    }
89}
90
91impl Mul<Self> for Position {
92    type Output = Self;
93
94    fn mul(self, rhs: Self) -> Self::Output {
95        Self::from_degrees(self.into_degrees() * rhs.into_degrees())
96    }
97}
98
99impl MulAssign<Self> for Position {
100    fn mul_assign(&mut self, rhs: Self) {
101        *self = *self * rhs;
102    }
103}
104
105impl Div<Self> for Position {
106    type Output = Self;
107
108    fn div(self, rhs: Self) -> Self::Output {
109        Self::from_degrees(self.into_degrees() / rhs.into_degrees())
110    }
111}
112
113impl DivAssign<Self> for Position {
114    fn div_assign(&mut self, rhs: Self) {
115        *self = *self / rhs;
116    }
117}
118
119impl Rem<Self> for Position {
120    type Output = Self;
121
122    fn rem(self, rhs: Self) -> Self::Output {
123        Self::from_degrees(self.into_degrees() % rhs.into_degrees())
124    }
125}
126
127impl RemAssign<Self> for Position {
128    fn rem_assign(&mut self, rhs: Self) {
129        *self = *self % rhs;
130    }
131}
132
133impl Neg for Position {
134    type Output = Self;
135
136    fn neg(self) -> Self::Output {
137        Self::from_degrees(-self.into_degrees())
138    }
139}
140
141impl PartialEq for Position {
142    fn eq(&self, other: &Self) -> bool {
143        self.into_degrees() == other.into_degrees()
144    }
145}
146
147impl PartialOrd for Position {
148    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
149        self.into_degrees().partial_cmp(&other.into_degrees())
150    }
151}