ev3_drivebase/
drivebase.rs

1//! Core drivebase functionality for controlling a two-wheeled robot.
2
3mod brake_mode;
4mod drive;
5mod ramping;
6mod run;
7mod speed;
8mod turn;
9mod utils;
10mod wait;
11
12pub use brake_mode::BrakeMode;
13
14use crate::Motor;
15use ev3dev_lang_rust::{Ev3Error, motors::TachoMotor, sensors::ColorSensor};
16use std::f64::consts::PI;
17
18/// A two-wheeled robot drivebase controller.
19///
20/// The `DriveBase` provides high-level control over a differential drive robot,
21/// handling the complex calculations needed for precise movement and turning.
22///
23/// # Physical Parameters
24///
25/// The drivebase needs to know the physical dimensions of your robot:
26///
27/// - **Wheel diameter**: The diameter of your wheels in millimeters
28/// - **Axle track**: The distance between the contact points of the left and right wheels in millimeters
29///
30/// These measurements are critical for accurate distance and angle calculations.
31///
32/// # Examples
33///
34/// Basic setup and movement:
35///
36/// ```no_run
37/// use ev3_drivebase::{DriveBase, Motor, Direction, BrakeMode};
38/// use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
39///
40/// fn main() -> Result<(), Ev3Error> {
41///     let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
42///     let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
43///
44///     let mut drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
45///     drivebase.set_brake_mode(BrakeMode::Hold)?;
46///
47///     // Drive 200mm forward at 300 deg/s
48///     drivebase.drive(300, 200, true)?;
49///
50///     Ok(())
51/// }
52/// ```
53#[derive(Debug, Clone)]
54pub struct DriveBase {
55    /// The left motor of the drivebase.
56    pub left: TachoMotor,
57    /// The right motor of the drivebase.
58    pub right: TachoMotor,
59    /// Current speed of the robot in degrees per second.
60    pub current_speed: i32,
61    /// Left color sensor if specified, useful for line following methods.
62    pub left_sensor: Option<ColorSensor>,
63    /// Right color sensor if specified, useful for line following methods.
64    pub right_sensor: Option<ColorSensor>,
65    /// Metadata of the left motor.
66    pub left_meta: Motor,
67    /// Metadata of the right motor.
68    pub right_meta: Motor,
69    /// The circumference of the wheels in millimeters.
70    pub circumference: f64,
71    /// The distance between the points where both wheels touch the ground in millimeters.
72    pub axle_track: f64,
73}
74
75impl DriveBase {
76    /// Creates a new `DriveBase` using the provided motor configurations.
77    ///
78    /// # Parameters
79    ///
80    /// - `left_meta`: Configuration for the left motor
81    /// - `right_meta`: Configuration for the right motor
82    /// - `wheel_diameter`: Diameter of the wheels in millimeters
83    /// - `axle_track`: Distance between wheel contact points in millimeters
84    ///
85    /// # Errors
86    ///
87    /// Returns an error if:
88    /// - The specified motor ports are not connected
89    /// - The ports are being used by another device
90    /// - The motors cannot be initialized
91    ///
92    /// # Examples
93    ///
94    /// ```no_run
95    /// use ev3_drivebase::{DriveBase, Motor, Direction};
96    /// use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
97    ///
98    /// fn main() -> Result<(), Ev3Error> {
99    ///     let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
100    ///     let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
101    ///
102    ///     // Create drivebase with 43.2mm diameter wheels and 185mm axle track
103    ///     let drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
104    ///
105    ///     Ok(())
106    /// }
107    /// ```
108    pub fn new(
109        left_meta: Motor,
110        right_meta: Motor,
111        wheel_diameter: f64,
112        axle_track: f64,
113    ) -> Result<Self, Ev3Error> {
114        let left = TachoMotor::get(left_meta.port)?;
115        let right = TachoMotor::get(right_meta.port)?;
116        let circumference = PI * wheel_diameter;
117        let drivebase = Self {
118            left,
119            right,
120            current_speed: 0,
121            left_sensor: None,
122            right_sensor: None,
123            left_meta,
124            right_meta,
125            circumference,
126            axle_track,
127        };
128        drivebase.reset()?;
129        Ok(drivebase)
130    }
131
132    /// Adds left and right color sensors to the drivebase.
133    ///
134    /// Color sensors can be used for line following and other applications
135    /// that require detecting surface colors or light intensity.
136    ///
137    /// # Parameters
138    ///
139    /// - `left_sensor`: The color sensor on the left side of the robot
140    /// - `right_sensor`: The color sensor on the right side of the robot
141    ///
142    /// # Examples
143    ///
144    /// ```no_run
145    /// use ev3_drivebase::{DriveBase, Motor, Direction};
146    /// use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
147    /// use ev3_drivebase::ev3dev_lang_rust::sensors::{ColorSensor, SensorPort};
148    ///
149    /// fn main() -> Result<(), Ev3Error> {
150    ///     let left_motor = Motor::new(MotorPort::OutA, Direction::Clockwise);
151    ///     let right_motor = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
152    ///     let mut drivebase = DriveBase::new(left_motor, right_motor, 43.2, 185.0)?;
153    ///
154    ///     let left_sensor = ColorSensor::get(SensorPort::In1)?;
155    ///     let right_sensor = ColorSensor::get(SensorPort::In2)?;
156    ///
157    ///     drivebase.add_colorsensor(left_sensor, right_sensor);
158    ///
159    ///     Ok(())
160    /// }
161    /// ```
162    pub fn add_colorsensor(
163        &mut self,
164        left_sensor: ColorSensor,
165        right_sensor: ColorSensor,
166    ) -> &Self {
167        self.left_sensor = Some(left_sensor);
168        self.right_sensor = Some(right_sensor);
169        self
170    }
171}