# mecanum/holonomic/omni drive

This is what our team has learned so far. I’m posting it here for the benefit of any team still struggling with, or wanting to learn more, about holonomic drive.

You can use the holonomic drive VI provided in LabVIEW (which requires polar coordinate inputs),

OR

You can write your own omni code (as our team did), which uses -1 to +1 joystick output values, as follows:

Let x, y, and z be the rev/fwd, slide left/right, and spin CCW/CW axes, respectively, which each vary from -1 to +1.

So:

x= -1 corresponds to full speed reverse, x= +1 corresponds to full speed forward,

y= -1 corresponds to full speed slide left, y= +1 corresponds to full speed slide right,

z= -1 corresponds to full speed spin CCW, z= +1 corresponds to full speed spin CW

If your joystick outputs don’t look like the above (eg the signs are reversed), simply convert them.

Let w1, w2, w3, and w4 be the commands to send to each of the 4 wheels, where w1 is front left, w2 is front right, w3 is rear left, w4 is rear right, as viewed from the top.

set the four wheel speed commands as follows:

w1 = x + y + z

w2 = x - y - z

w3 = x - y + z

w4 = x + y - z

You’re almost done. All that remains is to normalize the above commands so that their range is -1 to +1. Proceed as follows:

• look at the magnitude (absolute value) of each of the four commands, and select the MAXIMUM. for sake of discussion, call this maximum value Wmax

• if Wmax is less than or equal to 1, no scaling is required. Just use the four w commands as-is

• if Wmax is greater than 1, then divide EACH of the four w values by Wmax.

That’s all there is to it. Send each w command to the corresponding wheel.

One note of caution: make sure the polarity of the motors on each side of the bot is wired correctly (each wheel must be spinning in the “forward” direction when it gets a +1 command). The easier way to observe this is to elevate the bot and push the joystick forward; all four wheels should be spinning forward.

~

Is this designed for use with mechanum or omni wheels? I think the outputs to the motors are significantly different between the two.

I believe this algorithm will work equally well for:

• straight-mounted mecanum wheels arranged in an “O” pattern as viewed from the bottom (which is the same as an “X” pattern when viewed from the top)*

and

• omni wheels mounted at 45 degrees so as to form an “O” pattern (as viewed from either the top or the bottom)

The important point is that the axis of rotation of the roller which is in contact with the ground should be perpendicular (or nearly so) to a line drawn from the center of the bot out to the wheel in question (regardless of whether the wheel is omni or mecanum)

~

I gave our programmers three programming assignments at the beginning of the build season related to this, to write pseudo code to drive a mecanum drive setup (I broke it into neat little chunks for them).

http://lib.store.yahoo.net/lib/yhst-33833170891817/MecanumWheelSpecSheet.pdf

A discussion on vectors is useful in teaching mecanum wheels, and an understanding of vectors is critical in making sure the robot’s wheels are correctly placed (The whole “diamond” versus “X”, and an ability to spin).

Thinking about it in terms of “This wheel must spin this way when you want the robot to travel in this direction” is useful, and breaking it into one part at a time makes it more manageable.

The way I presented it our team was along these lines:

• which way must each of the four wheels spin in order to go forward?

• which way must each of the wheels spin in order to spin clockwise?

• which way must each of the wheels spin in order to slide right?

Then, once they figured that out, the “aha” moment was understanding that these actions could be superimposed using simple addition to get an algorithm which would allow the robot to execute all three maneuvers at the same time, in any proportion desired.

~

The Holonomic drive never worked for our team, instead what I did was i established each of the 4 wheel motors independently and set values from the joystick. Speed was set using the “Set” method and wired straight from the joystick axis values. Naturally, there is an algorithm to flip motor speeds appropriately to allow functionality of the Mecanum Wheels.

Using this method allows a side of the robot to be front, as in ours, and also allows those who don’t like coordinates to get the job done. Just thought that that idea should be broadcast, and good luck!

Hello Egg,

I’m not sure I understand what you said, but you’ve captured my interest. Could you elaborate just a bit please?

What exactly didn’t work? Is it that you had trouble converting the joystick outputs to polar coordinates, or some other problem?

What what does it mean to “establish” each of the 4 wheel motors “independently”? How is this different from, for example, what I posted?

Not sure what “wired straight from the joystick values” means. What would be an example of something not wired straight from the joystick values?

Thanks

~

The Holonomic drive never worked for autonomous (getting, setting, etc.), so we did what i was explaining later in the post. In the WPI library, you can establish individual Jaguar/Victor motors, each with their own separate values. Naturally, with something like Mechanum wheels, this would be perferred when each motor spins in a unique way.

The “wiring” aspect was the moving of numbers from the “get” method in the joystick class to the “Set speed” method.

The Pseudo code looks something like this…

Jaguar motor1 = new Jaguar(1);
Jaguar motor2 = new Jaguar(2);
Jaguar motor3 = new Jaguar(3);
Jaguar motor4 = new Jaguar(4); <-- that is declaring everything separate
Joystick joy = new Joystick(1);

… code…

if(joy.getAxisY() == -1)
{
motor1.setSpeed(joy.getAxisY());
motor2.setSpeed(joy.getAxisY()*-1); <-- setting everything seperate
motor3… you get the point.
}

Essentially, I re-created the Holonomic drive without actually using the Holonomic Drive in Labview. I didn’t use it because 1. it didn’t appear to work when i tried it and 2. I can just as easily overload it. Hopefully this cleared things up for you.

NOTE: Pseudo done as if in Java