# How to calculate the right and left speed for a tank-like rover?

I am trying to control the Rover 5 robot using an Android app with a touch-based joystick control in the app UI. I want to calculate the speed of the left and right motors in the rover when joystick is moved.

From the joystick, I get two values, pan and tilt. I convert them into the polar coordinate system with r and theta. Where r ranges from 0 to 100 and theta from 0 to 360. I want to derive an equation which can convert the (r, theta) to (left_speed, right_speed) for rover. The speed values also are in the [0;100] range.

Now, here is what I have figured out till now. For any value of r,

If theta = 0 then left_speed = r, right_speed = -r (turning right on spot)
If theta = 90 then left_speed = r, right_speed = r (moving forward at speed r)
If theta = 180 then left_speed = -r, right_speed = r (turning left on spot)
If theta = 270 then left_speed = -r, right_speed = -r (moving backwards at speed r)

For other values, I want it moving and turning simultaneously. For example,

If theta = 45 then left_speed = alpha*r, right_speed = beta*r (moving forward while turning right)

So, basically for any (r, theta), I can set speeds as,

(left_speed, right_speed) = (alpha*r, beta*r)

I need to formulate an equation where I can generalize all these cases by finding alpha and beta based on theta.

How can I do this? Is there is any existing work I can refer to?

• I assume you mean "If theta = 180 then left_speed = -r..." – John Wiseman Nov 2 '13 at 0:50
• Yes, thanks for pointing it out. Edited the question – Punit Soni Nov 2 '13 at 1:14

You're trying to find a formula to convert a given $(r, \theta)$ to left and right thrust percentages, where $r$ represents your throttle percentage. The naive implementation is to base your function on 100% throttle:

• At $0 ^{\circ}$, left and right thrust are equal to $r$
• At $\pm45 ^{\circ}$, one side's thrust equals $r$ and the other side's equals 0
• At $\pm 90 ^{\circ}$, one side's thrust equals $r$ and the other side's equals $-r$
• At $180 ^{\circ}$, left and right thrust are equal to $-r$

This produces a function like the following: The problem with this implementation is that you are only providing the desired $r$ when $\theta$ is at an exact multiple of $90 ^{\circ}$. At all other points, you sacrifice total speed for control. You can see this in the graph: "Absolute Thrust", the amount of thrust being delivered by both motors, is not (and cannot be) constant in this regime. Simply scaling this function is not optimal.

The maximum absolute thrust that can be sustained over the entire range of $\theta$ occurs when $r=50\%$ -- this is what your function should be based on. In this implementation, total thrust remains constant between $\pm45 ^{\circ}$, and absolute thrust is constant no matter what direction is chosen -- the motors trade off their thrust to maintain the desired $r$. Above $r=50\%$, the range of angles where your total thrust can satisfy $r$ begins to shrink -- you begin to sacrifice control for speed.

This produces a python function like the following:

# assumes theta in degrees and r = 0 to 100 %
# returns a tuple of percentages: (left_thrust, right_thrust)
def throttle_angle_to_thrust(r, theta):
theta = ((theta + 180) % 360) - 180  # normalize value to [-180, 180)
r = min(max(0, r), 100)              # normalize value to [0, 100]
v_a = r * (45 - theta % 90) / 45          # falloff of main motor
v_b = min(100, 2 * r + v_a, 2 * r - v_a)  # compensation of other motor
if theta < -90: return -v_b, -v_a
if theta < 0:   return -v_a, v_b
if theta < 90:  return v_b, v_a
return v_a, -v_b


The result is the following: • Thanks Ian. As far as I understood, you are trying to balance the loads on both motors, right? – Punit Soni Nov 3 '13 at 8:12
• Not quite. You are trying to make $(\text{left_speed} + \text{right_speed}) / 2 = r$, instead of having it be dependent on $\theta$. Notice that when $r > 50\%$, the dotted purple line is no longer constant with respect to $\theta$. You want to minimize this effect. – Ian Nov 3 '13 at 17:13
• How did you make those fancy plots? – Josh Vander Hook Nov 4 '13 at 14:45
• I did the plots in Microsoft Excel and produced the animation in Gimp. – Ian Nov 4 '13 at 22:01
• Excellent answer, thanks. There's a small typo, it should read if theta < 0: return v_a, -v_b and not if theta < 0: return -v_a, v_b (the signs are reversed) – smirkingman Feb 20 '18 at 19:46

What you want is angular velocity proportional to the cosine of the angle, it seems, with positive to the right, and negative to the left.

So, since we know that angular velocity is given by $\frac{V_l - V_r}{D}$ where $D$ is the diameter of the robot, we're all set. Try this:

if $\theta\ge0$ and $\theta\le90$: $V_l \gets r$ and $V_r \gets r\sin(2\theta-90)$

if $\theta < 0$ and $\theta\geq-90$: $V_r \gets -r$ and $V_l \gets r\sin(2\theta+90)$

Swap the velocities for the other quadrants. Note, this won't "feel" like driving a car, as moving the stick to the lower-right will turn backwards and rotate right, whereas a car in reverse with the wheel right will move backwards and turn leftward. Just a weirdness of differential drives... You can adjust for this by just applying the fourth quadrant rules to the third quadrant $\theta$ and visa-versa.

I used $\theta \in [-180,+180]$, which you can get by:

$\theta \gets \text{atan2}(\sin\theta,\cos\theta)$ (watch your units though, atan2 is usually radians.

• This look pretty good. I arrived to this solution thinking intuitively. I will give this a try and see how it actually feels when driveing. Thanks. – Punit Soni Nov 5 '13 at 19:58