Skip to content

Differential Drive

A differential drive system is how robots and vehicles, like tanks, move around. Instead of using a steering wheel, they have two sets of wheels (generally 1-2 in each set on each side) (or tracks) that can spin at different speeds.

Picture a tank: if both tracks move forward at the same speed, the tank moves straight. If the left track moves faster than the right, the tank turns right. If one track moves forward and the other moves backward, the tank spins in place. This is how many robots, including Roombas and Mars rovers, navigate!

Mapping Diagram
Differential Drive Movement Diagram.
A tank has \( v_\text{left} = 40 \) and \( v_\text{right} = 10 \) (both wheels moving forward). What does it do?

Advantages/Disadvantages

Differential drive is one of the most common drivetrains in mobile robotics because it's mechanically simple and cheap: two motors and two (or more) wheels are all you need, with no steering linkage to build or maintain. It can also spin in place, letting a robot rotate freely in tight spaces where a car-like vehicle would need to do a multi-point turn.

That simplicity comes with tradeoffs, though:

  • It's non-holonomic — the robot can't strafe sideways, so reaching a point beside it means turning first, then driving.
  • Wheel slip causes the robot's estimate of its own position (from wheel odometry) to drift from where it actually is, so accurate driving often needs extra sensors (IMU, encoders, vision) to correct for it.
  • Precise turning depends on both wheels tracking their commanded velocities closely — a small mismatch compounds into significant heading error over a long drive.
A differential drive robot needs to reach a point 2 meters directly to its right, ending up facing the same direction it started. Because the robot is non-holonomic, what must its path look like?

The Math For It

What are Inverse Kinematics?

The inverse kinematics formulas allow us to determine the necessary velocities to set for each wheel (or motor on an actual robot) to easily control the movement of the entire robot. This could include actions like rotating, moving forward, or moving backward.

Pass in: Forward/Angular velocities

Get: The velocities to set for each wheel/motor.

Variable Names

Forward Velocity (\(v_\text{forward}\)): The speed at which the robot goes straight ahead.

Angular Velocity (\(\omega\)): The speed at which the robot turns.

Track Radius (\(r_\text{track}\)): The distance between the center of the entire robot and the midpoint of a set of wheels(left or right).

Equations/Formulas

Velocities to set the right wheels: \(v_\text{right} = v_\text{forward} + r_\text{track} \cdot \omega\)

Velocities to set the left wheels: \(v_\text{left} = v_\text{forward} - r_\text{track} \cdot \omega\)

Using the inverse kinematics formulas, if \( v_\text{forward} = 20 \), \( \omega = 0.5 \), and \( r_\text{track} = 10 \), what is \( v_\text{right} \)?

What are Forward Kinematics?

Forward kinematics answer the opposite question from inverse kinematics: given the speeds you're actually able to command each wheel/motor to spin at, what forward and angular velocity does that produce? This is the direction a real robot works in — you send a velocity command to each of the two motors, and the robot's motion is whatever falls out of those two numbers and the distance between the wheels.

Pass in: The velocities of each wheel/motor.

Get: Forward/Angular velocities.

Equations/Formulas

Forward velocity: \(v_\text{forward} = \frac{v_\text{right} + v_\text{left}}{2}\)

Angular velocity: \(\omega = \frac{v_\text{right} - v_\text{left}}{2 \cdot r_\text{track}}\)

A robot has \( v_\text{left} = 30 \), \( v_\text{right} = 50 \), and \( r_\text{track} = 20 \). Using the forward kinematics formulas, what is \( \omega \)?

Demo

Drive the robot below by setting v_left and v_right directly — the same two commands you'd actually send to the motors on a real robot. Forward kinematics converts them into Forward Velocity (\(v_\text{forward}\)) and Angular Velocity (\(\omega\)), shown in the panel below, and those are what actually move the robot on the canvas. Because \(\omega\) now depends on Track Radius, changing it changes the real trajectory — not just a readout.

Things to try:

  1. Set v_left equal to v_right — the robot drives in a straight line, since \(\omega = 0\).
  2. Make v_left and v_right unequal — the robot curves, turning toward whichever wheel is slower.
  3. Set v_left and v_right to equal and opposite values — the robot spins in place, since \(v_\text{forward} = 0\).
  4. Keep the gap between v_left and v_right fixed and increase Track Radius — the turn now visibly widens, because the same wheel-speed difference produces a smaller \(\omega\) on a wider base.

Top-Down View

Body Velocity (from Forward Kinematics)

v_forward0.0
ω0.00
Driving straight
A robot has \( v_\text{left} = 25 \) and \( v_\text{right} = -25 \). Using forward kinematics, what does it do?

The Code

View Differential Drive code(simulation) on GitHub

KEY SNIPPETS OF CODE

The inverse kinematics is implemented in the inverse_kinematics method of the Robot class which includes the formulas covered in the previous part of the lesson:

1
2
3
def inverse_kinematics(self, v_f, v0):
    self.vr = v_f + self.track_radius * v0  # Velocity of right wheels
    self.vl = v_f - self.track_radius * v0  # Velocity of left wheels

This involves setting each set of wheels(left and right), with the velocity calculated from the inverse kinematics. This way we are able to make our robot move.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
def setVelocity(self): # setting velocity on the left and right wheels(you set wheels to left and right not individual in tank drive)

            for wheel in self.wheels_left:
                p.setJointMotorControl2(
                    bodyIndex=self.robot_id,
                    jointIndex=wheel,
                    controlMode=p.VELOCITY_CONTROL,
                    targetVelocity=self.vl,
                    force = 50 # i think the torque on a jackal
                )
            for wheel in self.wheels_right:
                p.setJointMotorControl2(
                    bodyIndex=self.robot_id,
                    jointIndex=wheel,
                    controlMode=p.VELOCITY_CONTROL,
                    targetVelocity=self.vr,
                    force = 50 # i think the torque on a jackal
                )