I'm trying to control an Arduino-powered motorized toy with a differential drive. However, I want to code it the motor movements with a direction vector.


(1,0) = forward
(-1,0) = backward
(0,1) = turn left, pivoting on center axis
(0,-1) = turn right, pivoting on center axis
(1,1) = forward-left, pivoting on left wheel
(1,-1) = forward-left, pivoting on right wheel

I thought the equation to convert these to the literal motor signals was:

float mag = sqrt(dirX*dirX + dirY*dirY);
float left = dirX - dirY;
float right = dirX + dirY;

This seems to work for the first 4 cases, but fails for the last two, where it results in an un-normalized vector.

One potential fix would be to simple wrap left and right in min() to stop it from going over 1.0, but that feels like a hack, and would possibly lose resolution. Is there a more elegant fix?


If you want to take it to to the extreme, I always use an algorithm called Diamond Coordinates. It is described in this PDF. It performs perfectly, and I keep a C# and Java implementation handy. I'll probably be doing a Python one soon :)

enter image description here

| improve this answer | |

Part of the problem is that "direction vector" is a bit vague in this context. Here are two popular ways of doing this:

(x = right speed, y = left speed)

This is like "tank drive", where two joystick's up/down axis are used to drive; you don't really need to do any math to get motor outputs.

(m = output magnitude, d = left/right balance)

I've heard this called "arcade drive", where one joystick's up/down is m and left/right is d.

Your equations are correct; the bounds check is unavoidable. Linear vector spaces just are not going to arbitrarily bound themselves at 1 for you. you could make it so "full speed ahead" doesn't actually max out the motor speeds; then when you turn it could still speed up one side a bit, but that is obviously still suboptimal.

You could try normalizing left and right, then multiplying by "m" again. The magnitude would be constant so you wouldn't have to do any bounds checking, but you would lose the pivoting on the center behavior you want, and full forward would be slower. You could also try making "d" an angle, and then choosing left and right with sine and cosine, probably shifted 45 degrees. That has the same problems.

I like to try driving it a bunch of different ways and see what handles best.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.