vex_rt/
distance.rs

1//! # Distance Sensor API.
2
3use crate::{
4    bindings,
5    error::{get_errno, Error},
6    rtos::DataSource,
7};
8
9/// A struct which represents a V5 smart port configured as a distance sensor.
10pub struct DistanceSensor {
11    port: u8,
12}
13
14impl DistanceSensor {
15    /// Constructs a new distance sensor.
16    ///
17    /// # Safety
18    ///
19    /// This function is unsafe because it allows the user to create multiple
20    /// mutable references to the same distance sensor. You likely want to
21    /// implement [`Robot::new()`](crate::robot::Robot::new()) instead.
22    pub unsafe fn new(port: u8) -> DistanceSensor {
23        DistanceSensor { port }
24    }
25
26    /// Gets the currently measured distance from the sensor in millimetres.
27    pub fn get_distance(&self) -> Result<i32, DistanceSensorError> {
28        match unsafe { bindings::distance_get(self.port) } {
29            x if x == bindings::PROS_ERR_ => Err(DistanceSensorError::from_errno()),
30            x => Ok(x),
31        }
32    }
33
34    /// Gets the confidence in the distance reading.
35    ///
36    /// This is a value that has a range of 0 to 63. 63 means high confidence,
37    /// lower values imply less confidence. Confidence is only available when
38    /// distance is > 200mm (the value 10 is returned in this scenario).
39    pub fn get_confidence(&self) -> Result<i32, DistanceSensorError> {
40        match unsafe { bindings::distance_get_confidence(self.port) } {
41            x if x == bindings::PROS_ERR_ => Err(DistanceSensorError::from_errno()),
42            x => Ok(x),
43        }
44    }
45
46    /// Gets the current estimated relative object size.
47    ///
48    /// This is a value that has a range of 0 to 400. A 18” x 30” grey card will
49    /// return a value of approximately 75 in typical room lighting.
50    pub fn get_object_size(&self) -> Result<i32, DistanceSensorError> {
51        match unsafe { bindings::distance_get_object_size(self.port) } {
52            x if x == bindings::PROS_ERR_ => Err(DistanceSensorError::from_errno()),
53            x => Ok(x),
54        }
55    }
56
57    /// Gets the object velocity in metres per second.
58    pub fn get_object_velocity(&self) -> Result<f64, DistanceSensorError> {
59        match unsafe { bindings::distance_get_object_velocity(self.port) } {
60            x if x == bindings::PROS_ERR_F_ => Err(DistanceSensorError::from_errno()),
61            x => Ok(x),
62        }
63    }
64}
65
66impl DataSource for DistanceSensor {
67    type Data = DistanceData;
68
69    type Error = DistanceSensorError;
70
71    fn read(&self) -> Result<Self::Data, Self::Error> {
72        Ok(DistanceData {
73            confidence: self.get_confidence()?,
74            size: self.get_object_size()?,
75            velocity: self.get_object_velocity()?,
76        })
77    }
78}
79
80/// Represents the data that can be read from a distance sensor.
81#[derive(Clone, Copy, Debug, PartialEq)]
82pub struct DistanceData {
83    /// The confidence; see [`DistanceSensor::get_confidence()`] for details.
84    pub confidence: i32,
85    /// The object size; see [`DistanceSensor::get_object_size()`] for details.
86    pub size: i32,
87    /// The object velocity in meters per second.
88    pub velocity: f64,
89}
90
91/// Represents possible errors for distance sensor operations.
92#[derive(Debug)]
93pub enum DistanceSensorError {
94    /// Port is out of range (1-21).
95    PortOutOfRange,
96    /// Port cannot be configured as a distance sensor.
97    PortNotDistanceSensor,
98    /// Unknown error.
99    Unknown(i32),
100}
101
102impl DistanceSensorError {
103    fn from_errno() -> Self {
104        match get_errno() {
105            libc::ENXIO => Self::PortOutOfRange,
106            libc::ENODEV => Self::PortNotDistanceSensor,
107            x => Self::Unknown(x),
108        }
109    }
110}
111
112impl From<DistanceSensorError> for Error {
113    fn from(err: DistanceSensorError) -> Self {
114        match err {
115            DistanceSensorError::PortOutOfRange => Error::Custom("port out of range".into()),
116            DistanceSensorError::PortNotDistanceSensor => {
117                Error::Custom("port not a distance sensor".into())
118            }
119            DistanceSensorError::Unknown(n) => Error::System(n),
120        }
121    }
122}