DriveBase

Struct DriveBase 

Source
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: TachoMotor

The left motor of the drivebase.

§right: TachoMotor

The right motor of the drivebase.

§current_speed: i32

Current 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: Motor

Metadata of the left motor.

§right_meta: Motor

Metadata of the right motor.

§circumference: f64

The circumference of the wheels in millimeters.

§axle_track: f64

The distance between the points where both wheels touch the ground in millimeters.

Implementations§

Source§

impl DriveBase

Source

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(())
}
Source

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

Source

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 reached
    • false: 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 distance is 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

Source

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(())
}
Source

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::Brake or BrakeMode::Hold: Full effect
Source§

impl DriveBase

Source

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

pub fn run_to_rel_pos( &self, left_position: i32, right_position: i32, ) -> Result<&Self, Ev3Error>

Runs the robot to a relative position using the already set speed

§Errors

Errors if it can’t run the command

Source§

impl DriveBase

Source

pub fn set_speed( &mut self, left_speed: i32, right_speed: i32, ) -> Result<(), Ev3Error>

Sets the speed of both motors

§Errors

Errors if it can’t set the speed of either motor

Source§

impl DriveBase

Source

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 center
    • Some(r): Turn along an arc with radius r
      • r = 0: Same as in-place turn
      • r > 0: Outer wheel follows arc at distance r from 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 degree is 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

Source

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 stop
  • Brake: Motors actively brake
  • Hold: 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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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 millimeters
  • right_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

Source

pub fn wait<F>(&self, cond: F, timeout: Option<Duration>)
where F: Fn(&TachoMotor, &TachoMotor) -> bool + Send + Sync,

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.

Source

pub fn wait_until_not_moving(&self, timeout: Option<Duration>) -> &Self

Waits until both motors are not moving anymore

Source§

impl DriveBase

Source

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 motor
  • right_meta: Configuration for the right motor
  • wheel_diameter: Diameter of the wheels in millimeters
  • axle_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(())
}
Source

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 robot
  • right_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§

Source§

impl Clone for DriveBase

Source§

fn clone(&self) -> DriveBase

Returns a duplicate of the value. Read more
1.0.0§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for DriveBase

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Drop for DriveBase

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> CloneToUninit for T
where T: Clone,

§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.