#[derive(Clone, Copy, Debug)]
pub struct DiffDrive {
track: f32,
}
impl DiffDrive {
pub fn new(track: f32) -> Self {
Self {
track: magnitude(track),
}
}
pub fn wheel_speeds(&self, linear: f32, angular: f32) -> (f32, f32) {
let half = angular * self.track / 2.0;
(linear - half, linear + half)
}
pub fn body_motion(&self, left: f32, right: f32) -> (f32, f32) {
let linear = (right + left) / 2.0;
let angular = if self.track == 0.0 {
0.0
} else {
(right - left) / self.track
};
(linear, angular)
}
}
fn magnitude(value: f32) -> f32 {
if value < 0.0 {
-value
} else {
value
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn driving_straight_turns_both_wheels_equally() {
let drive = DiffDrive::new(0.5);
assert_eq!(drive.wheel_speeds(1.0, 0.0), (1.0, 1.0));
}
#[test]
fn spinning_in_place_turns_the_wheels_opposite() {
let drive = DiffDrive::new(0.5);
assert_eq!(drive.wheel_speeds(0.0, 2.0), (-0.5, 0.5));
}
#[test]
fn body_motion_inverts_wheel_speeds() {
let drive = DiffDrive::new(0.5);
assert_eq!(drive.body_motion(1.0, 1.0), (1.0, 0.0)); assert_eq!(drive.body_motion(-0.5, 0.5), (0.0, 2.0)); }
#[test]
fn the_two_directions_round_trip() {
let drive = DiffDrive::new(0.42);
let (left, right) = drive.wheel_speeds(1.3, -0.7);
let (linear, angular) = drive.body_motion(left, right);
assert!((linear - 1.3).abs() < 1e-6);
assert!((angular + 0.7).abs() < 1e-6);
}
#[test]
fn a_zero_track_reports_no_rotation() {
let drive = DiffDrive::new(0.0);
assert_eq!(drive.body_motion(1.0, 2.0), (1.5, 0.0));
}
}