pub struct DriveBase {
pub left: TachoMotor,
pub right: TachoMotor,
pub current_speed: i32,
pub left_sensor: Option<ColorSensor>,
pub right_sensor: Option<ColorSensor>,
pub left_meta: Motor,
pub right_meta: Motor,
pub circumference: f64,
pub axle_track: f64,
}Expand description
A two-wheeled robot drivebase controller.
The DriveBase provides high-level control over a differential drive robot,
handling the complex calculations needed for precise movement and turning.
§Physical Parameters
The drivebase needs to know the physical dimensions of your robot:
- Wheel diameter: The diameter of your wheels in millimeters
- Axle track: The distance between the contact points of the left and right wheels in millimeters
These measurements are critical for accurate distance and angle calculations.
§Examples
Basic setup and movement:
use ev3_drivebase::{DriveBase, Motor, Direction, BrakeMode};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let mut drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
drivebase.set_brake_mode(BrakeMode::Hold)?;
// Drive 200mm forward at 300 deg/s
drivebase.drive(300, 200, true)?;
Ok(())
}Fields§
§left: TachoMotorThe left motor of the drivebase.
right: TachoMotorThe right motor of the drivebase.
current_speed: i32Current speed of the robot in degrees per second.
left_sensor: Option<ColorSensor>Left color sensor if specified, useful for line following methods.
right_sensor: Option<ColorSensor>Right color sensor if specified, useful for line following methods.
left_meta: MotorMetadata of the left motor.
right_meta: MotorMetadata of the right motor.
circumference: f64The circumference of the wheels in millimeters.
axle_track: f64The distance between the points where both wheels touch the ground in millimeters.
Implementations§
Source§impl DriveBase
impl DriveBase
Sourcepub fn set_brake_mode(&self, brake_mode: BrakeMode) -> Result<&Self, Ev3Error>
pub fn set_brake_mode(&self, brake_mode: BrakeMode) -> Result<&Self, Ev3Error>
Sets the brake mode for both motors.
The brake mode determines how the motors behave when stopped:
- Coast: Motors freely coast to a stop (no braking)
- Brake: Motors actively brake but don’t hold position
- Hold: Motors hold their current position with power
§Parameters
brake_mode: The desired brake mode to apply to both motors
§Errors
Returns an error if the brake mode cannot be set on either motor.
§Examples
use ev3_drivebase::{DriveBase, Motor, Direction, BrakeMode};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
// Use Hold mode for precise positioning
drivebase.set_brake_mode(BrakeMode::Hold)?;
Ok(())
}Sourcepub fn get_brake_mode(&self) -> Result<BrakeMode, Ev3Error>
pub fn get_brake_mode(&self) -> Result<BrakeMode, Ev3Error>
Gets the current brake mode for both motors.
If the motors have different brake modes, this method will set the right motor’s brake mode to match the left motor’s and return the left motor’s mode.
§Errors
Returns an error if the brake mode cannot be read or set.
§Examples
use ev3_drivebase::{DriveBase, Motor, Direction, BrakeMode};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
let current_mode = drivebase.get_brake_mode()?;
println!("Current brake mode: {:?}", current_mode);
Ok(())
}Source§impl DriveBase
impl DriveBase
Sourcepub fn drive(
&mut self,
speed: i32,
distance: impl Into<i32>,
stop: bool,
) -> Result<&Self, Ev3Error>
pub fn drive( &mut self, speed: i32, distance: impl Into<i32>, stop: bool, ) -> Result<&Self, Ev3Error>
Drives the robot forward or backward for a specified distance.
The robot will drive in a straight line at the given speed until it has traveled the specified distance, then stop according to the configured brake mode.
§Parameters
speed: The speed in degrees per second. Positive values use forward direction, negative values reverse the direction.distance: The distance to travel in millimeters. Positive for forward, negative for backward.stop: Whether to stop the motors after reaching the target distance.true: Motors will stop when the distance is reachedfalse: Motors will continue running at the same speed after reaching the distance
§Errors
Returns an error if:
- The motors cannot be commanded
- Speed or distance calculations fail
§Examples
Basic forward and backward movement:
use ev3_drivebase::{DriveBase, Motor, Direction, BrakeMode};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let mut drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
drivebase.set_brake_mode(BrakeMode::Hold)?;
// Drive forward 300mm at 200 deg/s and stop
drivebase.drive(200, 300, true)?;
// Drive backward 150mm at 100 deg/s and stop
drivebase.drive(100, -150, true)?;
// Drive forward 500mm and continue running
drivebase.drive(300, 500, false)?;
Ok(())
}§Behavior
- If
distanceis 0, the method returns immediately without moving - The direction of travel is determined by the sign of
distance - The method blocks until the robot reaches the target distance
- Motor speeds are automatically adjusted based on the configured motor directions
Source§impl DriveBase
impl DriveBase
Sourcepub fn set_acceleration(&self, acceleration: i32) -> Result<&Self, Ev3Error>
pub fn set_acceleration(&self, acceleration: i32) -> Result<&Self, Ev3Error>
Sets the acceleration rate for both motors.
Acceleration determines how quickly the motors ramp up to the target speed. Higher values result in faster acceleration but may cause wheel slipping or mechanical stress. Lower values provide smoother, more controlled starts.
§Parameters
acceleration: The acceleration rate in degrees per second squared (deg/s²)
§Errors
Returns an error if:
- The acceleration value is negative
- The value cannot be set on either motor
§Examples
use ev3_drivebase::{DriveBase, Motor, Direction};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
// Set moderate acceleration for smooth starts
drivebase.set_acceleration(2000)?;
// Set high acceleration for quick response
drivebase.set_acceleration(5000)?;
Ok(())
}Sourcepub fn set_deceleration(&self, deceleration: i32) -> Result<&Self, Ev3Error>
pub fn set_deceleration(&self, deceleration: i32) -> Result<&Self, Ev3Error>
Sets the deceleration rate for both motors.
Deceleration determines how quickly the motors slow down when stopping. Higher values result in faster stops but may cause the robot to jerk or tip. Lower values provide smoother, more controlled stops.
§Parameters
deceleration: The deceleration rate in degrees per second squared (deg/s²)
§Errors
Returns an error if:
- The deceleration value is negative
- The value cannot be set on either motor
§Examples
use ev3_drivebase::{DriveBase, Motor, Direction};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
// Set moderate deceleration for smooth stops
drivebase.set_deceleration(2000)?;
// Set high deceleration for quick stops
drivebase.set_deceleration(5000)?;
Ok(())
}§Note
Deceleration works in combination with the brake mode:
- With
BrakeMode::Coast: Deceleration has limited effect - With
BrakeMode::BrakeorBrakeMode::Hold: Full effect
Source§impl DriveBase
impl DriveBase
Sourcepub fn run_forever(&self) -> Result<&Self, Ev3Error>
pub fn run_forever(&self) -> Result<&Self, Ev3Error>
Runs the robot forever using the already set speed
§Errors
Errors if it can run the command to run the robot forever
Source§impl DriveBase
impl DriveBase
Sourcepub fn turn(
&mut self,
speed: i32,
degree: i32,
radius: impl Into<Option<f64>>,
) -> Result<&mut Self, Ev3Error>
pub fn turn( &mut self, speed: i32, degree: i32, radius: impl Into<Option<f64>>, ) -> Result<&mut Self, Ev3Error>
Turns the robot by a specified angle, either in place or along an arc.
This method provides two types of turns:
- In-place turn (radius =
None): The robot rotates around its center point - Arc turn (radius =
Some(r)): The robot follows a circular path with the given radius
§Parameters
speed: The speed in degrees per second (motor rotation, not robot turning speed)degree: The angle to turn in degrees. Positive for counter-clockwise, negative for clockwise.radius: The turning radius in millimeters:None: Turn in place around the robot’s centerSome(r): Turn along an arc with radiusrr = 0: Same as in-place turnr > 0: Outer wheel follows arc at distancerfrom turn center
§Errors
Returns an error if the motors cannot be commanded or calculations fail.
§Examples
In-place turns:
use ev3_drivebase::{DriveBase, Motor, Direction};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let mut drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
// Turn 90 degrees counter-clockwise in place
drivebase.turn(200, 90, None)?;
// Turn 180 degrees clockwise in place
drivebase.turn(200, -180, None)?;
Ok(())
}Arc turns with radius:
use ev3_drivebase::{DriveBase, Motor, Direction};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let mut drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
// Turn 90 degrees following a 200mm radius arc
drivebase.turn(200, 90, Some(200.0))?;
// Turn 45 degrees with a tight 50mm radius
drivebase.turn(150, 45, Some(50.0))?;
Ok(())
}§Behavior
- If
degreeis 0, the method returns immediately without moving - Negative radius values are converted to positive (radius is always absolute)
- The method blocks until the turn is complete
- For arc turns, the inner wheel moves slower than the outer wheel
Source§impl DriveBase
impl DriveBase
Sourcepub fn stop(&self) -> Result<&Self, Ev3Error>
pub fn stop(&self) -> Result<&Self, Ev3Error>
Stops both motors immediately.
The motors will stop according to the configured brake mode:
Coast: Motors freely coast to a stopBrake: Motors actively brakeHold: Motors hold their current position
This method is automatically called when the DriveBase is dropped.
§Errors
Returns an error if the stop command cannot be sent to either motor.
§Examples
use ev3_drivebase::{DriveBase, Motor, Direction};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let mut drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
// Start driving
drivebase.drive(300, 1000, false)?;
// Stop immediately
drivebase.stop()?;
Ok(())
}Sourcepub fn reset(&self) -> Result<&Self, Ev3Error>
pub fn reset(&self) -> Result<&Self, Ev3Error>
Resets all motor parameters to their default values.
This method:
- Stops both motors
- Resets position counters to zero
- Clears any pending commands
- Resets speed, acceleration, and other settings to defaults
This is automatically called when creating a new DriveBase.
§Errors
Returns an error if the reset command fails on either motor.
§Examples
use ev3_drivebase::{DriveBase, Motor, Direction};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
// After some movements, reset everything
drivebase.reset()?;
Ok(())
}Sourcepub fn is_running(&self) -> Result<bool, Ev3Error>
pub fn is_running(&self) -> Result<bool, Ev3Error>
Checks if power is being sent to either motor.
Returns true if at least one motor is currently running (receiving power),
even if the motor is ramping up or down.
§Errors
Returns an error if the motor state cannot be read.
§Examples
use ev3_drivebase::{DriveBase, Motor, Direction};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let mut drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
drivebase.drive(200, 500, false)?;
if drivebase.is_running()? {
println!("Motors are running!");
}
Ok(())
}Sourcepub fn is_ramping(&self) -> Result<bool, Ev3Error>
pub fn is_ramping(&self) -> Result<bool, Ev3Error>
Checks if either motor is currently ramping up to speed.
Returns true during the acceleration phase after a motor command is issued,
before the motor reaches its target speed.
§Errors
Returns an error if the motor state cannot be read.
§Examples
use ev3_drivebase::{DriveBase, Motor, Direction};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let mut drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
drivebase.drive(300, 1000, false)?;
if drivebase.is_ramping()? {
println!("Motors are accelerating!");
}
Ok(())
}Sourcepub fn is_holding(&self) -> Result<bool, Ev3Error>
pub fn is_holding(&self) -> Result<bool, Ev3Error>
Checks if either motor is actively holding its position.
Returns true when a motor has stopped and is in BrakeMode::Hold,
actively maintaining its position against external forces.
§Errors
Returns an error if the motor state cannot be read.
§Examples
use ev3_drivebase::{DriveBase, Motor, Direction, BrakeMode};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let mut drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
drivebase.set_brake_mode(BrakeMode::Hold)?;
drivebase.drive(200, 300, true)?;
if drivebase.is_holding()? {
println!("Motors are holding position!");
}
Ok(())
}Sourcepub fn is_overloaded(&self) -> Result<bool, Ev3Error>
pub fn is_overloaded(&self) -> Result<bool, Ev3Error>
Checks if either motor is overloaded.
Returns true if a motor is drawing excessive current, which typically indicates:
- The robot is stuck against an obstacle
- The motor is trying to move a load that’s too heavy
- Mechanical binding or damage
§Errors
Returns an error if the motor state cannot be read.
§Examples
use ev3_drivebase::{DriveBase, Motor, Direction};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let mut drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
drivebase.drive(300, 1000, false)?;
if drivebase.is_overloaded()? {
println!("Warning: Motors overloaded!");
drivebase.stop()?;
}
Ok(())
}Sourcepub fn is_stalled(&self) -> Result<bool, Ev3Error>
pub fn is_stalled(&self) -> Result<bool, Ev3Error>
Checks if either motor has stalled.
Returns true if a motor is not moving despite receiving power, indicating:
- The robot is blocked by an obstacle
- The wheels are slipping
- Mechanical failure
§Errors
Returns an error if the motor state cannot be read.
§Examples
use ev3_drivebase::{DriveBase, Motor, Direction};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let mut drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
drivebase.drive(300, 1000, false)?;
if drivebase.is_stalled()? {
println!("Warning: Motors stalled!");
drivebase.stop()?;
}
Ok(())
}Sourcepub fn calculate_counts(
&self,
left_distance: i32,
right_distance: i32,
) -> Result<(i32, i32), Ev3Error>
pub fn calculate_counts( &self, left_distance: i32, right_distance: i32, ) -> Result<(i32, i32), Ev3Error>
Calculates encoder counts for a given distance in millimeters.
This internal method converts distance in millimeters to motor encoder counts, taking into account wheel circumference and motor direction.
§Parameters
left_distance: Distance for the left wheel in millimetersright_distance: Distance for the right wheel in millimeters
§Returns
A tuple (left_counts, right_counts) representing the encoder counts for each motor,
with correct sign according to motor direction.
§Errors
Returns an error if encoder information cannot be read from the motors.
Source§impl DriveBase
impl DriveBase
Sourcepub fn wait<F>(&self, cond: F, timeout: Option<Duration>)
pub fn wait<F>(&self, cond: F, timeout: Option<Duration>)
Wait until condition cond returns true or the timeout is reached.
The condition is checked when to the state attribute has changed. If the timeout is None it will wait an infinite amount of time.
Sourcepub fn wait_until_not_moving(&self, timeout: Option<Duration>) -> &Self
pub fn wait_until_not_moving(&self, timeout: Option<Duration>) -> &Self
Waits until both motors are not moving anymore
Source§impl DriveBase
impl DriveBase
Sourcepub fn new(
left_meta: Motor,
right_meta: Motor,
wheel_diameter: f64,
axle_track: f64,
) -> Result<Self, Ev3Error>
pub fn new( left_meta: Motor, right_meta: Motor, wheel_diameter: f64, axle_track: f64, ) -> Result<Self, Ev3Error>
Creates a new DriveBase using the provided motor configurations.
§Parameters
left_meta: Configuration for the left motorright_meta: Configuration for the right motorwheel_diameter: Diameter of the wheels in millimetersaxle_track: Distance between wheel contact points in millimeters
§Errors
Returns an error if:
- The specified motor ports are not connected
- The ports are being used by another device
- The motors cannot be initialized
§Examples
use ev3_drivebase::{DriveBase, Motor, Direction};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
fn main() -> Result<(), Ev3Error> {
let left = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
// Create drivebase with 43.2mm diameter wheels and 185mm axle track
let drivebase = DriveBase::new(left, right, 43.2, 185.0)?;
Ok(())
}Sourcepub fn add_colorsensor(
&mut self,
left_sensor: ColorSensor,
right_sensor: ColorSensor,
) -> &Self
pub fn add_colorsensor( &mut self, left_sensor: ColorSensor, right_sensor: ColorSensor, ) -> &Self
Adds left and right color sensors to the drivebase.
Color sensors can be used for line following and other applications that require detecting surface colors or light intensity.
§Parameters
left_sensor: The color sensor on the left side of the robotright_sensor: The color sensor on the right side of the robot
§Examples
use ev3_drivebase::{DriveBase, Motor, Direction};
use ev3_drivebase::ev3dev_lang_rust::{Ev3Error, motors::MotorPort};
use ev3_drivebase::ev3dev_lang_rust::sensors::{ColorSensor, SensorPort};
fn main() -> Result<(), Ev3Error> {
let left_motor = Motor::new(MotorPort::OutA, Direction::Clockwise);
let right_motor = Motor::new(MotorPort::OutB, Direction::CounterClockwise);
let mut drivebase = DriveBase::new(left_motor, right_motor, 43.2, 185.0)?;
let left_sensor = ColorSensor::get(SensorPort::In1)?;
let right_sensor = ColorSensor::get(SensorPort::In2)?;
drivebase.add_colorsensor(left_sensor, right_sensor);
Ok(())
}Trait Implementations§
Auto Trait Implementations§
impl !Freeze for DriveBase
impl !RefUnwindSafe for DriveBase
impl Send for DriveBase
impl !Sync for DriveBase
impl Unpin for DriveBase
impl UnwindSafe for DriveBase
Blanket Implementations§
§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§unsafe fn clone_to_uninit(&self, dest: *mut u8)
unsafe fn clone_to_uninit(&self, dest: *mut u8)
clone_to_uninit)