Holonomic drives 2.0: A video tutorial by Cody

Hey guys!

I’ve finally got around to remaking my infamous holonomic drive video tutorial, this time in a Khan Academy styled two part series covering omni wheels, applications of omni wheels, holonomic drives and how to program both the “X” and “+” holonomic drives we’re all come to know and love.

Original thread - Sorry guys, the old thread was removed.

VIDEO TUTORIALS:

VIDEO 1: Omni wheels and holonomic drives

VIDEO 2: How to program holonomic drives

The signs in this drawing are all flipped, this is because I guessed the rotational
direction of the VEX motors wrong. The code below has been corrected.

The following code assumes that you have not reversed the polarity of the two-wire motor(s) AT ANY POINT,
if you have you will need to either configure that motor as reversed or flip all the signs for that motor.

ROBOTC

// Cody's ROBOTC X Holonomic Code
// =======================
// Usage:	Drive code for "X" Holonomic drive
// License:	Public Domain, use at your own risk.
//
//  ROBOT SEEN FROM ABOVE
//
//        X FRONT X
//      X           X
//    X  P1       P2  X
//            X
//           XXX
//            X
//    X  P4       P3  X
//      X           X
//        X       X

// Controller 1/2, Stick L/R, Axis X/Y
#define C1LX vexRT[Ch4]
#define C1LY vexRT[Ch3]
#define C1RX vexRT[Ch1]

task main() {

	while(true) {
	
		// Y component, X component, Rotation
		motor[FL] = -C1LY - C1LX - C1RX;
		motor[FR] =  C1LY - C1LX - C1RX;
		motor[BR] =  C1LY + C1LX - C1RX;
		motor[BL] = -C1LY + C1LX - C1RX;

		// Motor values can only be updated every 20ms
		wait10Msec(2);

	}

}

// Cody's ROBOTC + Holonomic Code
// =======================
// Usage:	Drive code for "+" Holonomic drive
// License:	Public Domain, use at your own risk.

// Controller 1/2, Stick L/R, Axis X/Y
#define C1LX vexRT[Ch4]
#define C1LY vexRT[Ch3]
#define C1RX vexRT[Ch1]

task main() {

	while(true) {
	
		// Y component, X component, Rotation
		motor[FR] = -C1LX - C1RX;
		motor[LE] = -C1LY - C1RX;
		motor[RI] =  C1LY - C1RX;
		motor[BK] =  C1LX - C1RX;

		// Motor values can only be updated every 20ms
		wait10Msec(2);

	}

}

PROS

// Cody's PROS X Holonomic Code
// =======================
// Usage:	Drive code for "X" Holonomic drive
// License:	Public Domain, use at your own risk.
//
//  ROBOT SEEN FROM ABOVE
//
//        X FRONT X
//      X           X
//    X  P1       P2  X
//            X
//           XXX
//            X
//    X  P4       P3  X
//      X           X
//        X       X

void operatorControl() {

	while(1) {
	
		// Controller 1/2, Stick L/R, Axis X/Y
		int C1LX = joystickGetAnalog(1, 4);
		int C1LY = joystickGetAnalog(1, 3);
		int C1RX = joystickGetAnalog(1, 1);

		// Y component, X component, Rotation
		motorSet(1, -C1LY - C1LX - C1RX);
		motorSet(2,  C1LY - C1LX - C1RX);
		motorSet(3,  C1LY + C1LX - C1RX);
		motorSet(4, -C1LY + C1LX - C1RX);

		// Motor values can only be updated every 20ms
		delay(20);

	}

}

// Cody's PROS + Holonomic Code
// =======================
// Usage:	Drive code for "+" Holonomic drive
// License:	Public Domain, use at your own risk.

void operatorControl() {

	while(1) {

		// Controller 1/2, Stick L/R, Axis X/Y
		int C1LX = joystickGetAnalog(1, 4);
		int C1LY = joystickGetAnalog(1, 3);
		int C1RX = joystickGetAnalog(1, 1);
	
		// Y component, X component, Rotation
		motorSet(1, -C1LX - C1RX); // Front
		motorSet(2, -C1LY - C1RX); // Left
		motorSet(3,  C1LY - C1RX); // Right
		motorSet(4,  C1LX - C1RX); // Back

		// Motor values can only be updated every 20ms
		delay(20);

	}

}

ConVEX

// Cody's ConVEX X Holonomic Code
// =======================
// Usage:	Drive code for "X" Holonomic drive
// License:	Public Domain, use at your own risk.
//
//  ROBOT SEEN FROM ABOVE
//
//        X FRONT X
//      X           X
//    X  P1       P2  X
//            X
//           XXX
//            X
//    X  P4       P3  X
//      X           X
//        X       X

msg_t vexOperator(void * arg) {

	// Register this task
	vexTaskRegister("operator");

	while(1) {

		// Controller 1/2, Stick L/R, Axis X/Y
		int C1LX = vexControllerGet(Ch4);
		int C1LY = vexControllerGet(Ch3);
		int C1RX = vexControllerGet(Ch1);
	
		// Y component, X component, Rotation
		vexMotorSet(1, -C1LY - C1LX - C1RX);
		vexMotorSet(2,  C1LY - C1LX - C1RX);
		vexMotorSet(3,  C1LY + C1LX - C1RX);
		vexMotorSet(4, -C1LY + C1LX - C1RX);

		// Exit condition
		if(chThdShouldTerminate()) break;

		// Motor values can only be updated every 20ms
		vexSleep(20);

	}

	return (msg_t)0;

}

// Cody's ConVEX + Holonomic Code
// =======================
// Usage:	Drive code for "+" Holonomic drive
// License:	Public Domain, use at your own risk.

msg_t vexOperator(void * arg) {

	// Register this task
	vexTaskRegister("operator");

	while(1) {

		// Controller 1/2, Stick L/R, Axis X/Y
		int C1LX = vexControllerGet(Ch4);
		int C1LY = vexControllerGet(Ch3);
		int C1RX = vexControllerGet(Ch1);
	
		// Y component, X component, Rotation
		vexMotorSet(1, -C1LX - C1RX); // Front
		vexMotorSet(2, -C1LY - C1RX); // Left
		vexMotorSet(3,  C1LY - C1RX); // Right
		vexMotorSet(4,  C1LX - C1RX); // Back

		// Exit condition
		if(chThdShouldTerminate()) break;

		// Motor values can only be updated every 20ms
		vexSleep(20);

	}

	return (msg_t)0;

}

This is a bit of an experiment, a new way of doing things, etc. If you like the format please let me know and also let me know what other topics you’d like me to cover.

Questions / comments / concerns / grievances below…

-Cody

Amazing tutorial Cody! All teams should watch this! I thought I had a good understanding of holo drives but this changed the way I view a lot of the properties of them!

Khan academy style… oh I love it. Lovely video and codes. I will let my new team members look at it!

Figured I would finish off the set with a video on Mecanum wheels and Mecanum drives.

VIDEO 3: Let’s figure out Mecanum drives

And that pretty much covers omni-directional drives.

VOTE: What should I do next?

A) More / new 3ds max tutorials

B) More / new programming tutorials
Please specify which IDE you would like me to emphasize

C) Inventor tutorials / Let’s play styled CAD’ing

D) Design philosophy semi-ramblings

E) Really basic beginner robotics stuff like gear ratios

F) Something else!
Tell me what…

-Cody

Perhaps an inventor tutorial? Would be much appreciated!

Tips and tricks on how to build CAD drawings more quickly in inventor. My team uses it, but none of us are “proficient” at it. I feel we are probably missing some of the tricks of the trade.

I would enjoy an Inventor 2014 tutorial! I have been attempting to build things, but it takes a long time and it doesn’t come out too well…

Imates help a lot in terms of making work load quicker. Also because they simulate a screw they also act as a rotational constraint and work for joints.

The main thing with getting faster at building in Inventor is the simple stuff like movement. Middle mouse and Shift + middle mouse with practice becomes very natural.

In terms of learning from the basics tutorials exist here

This should get you started at least.

Hey cody - they vids are great thanks. Do you have an easy c template for the controller?

I’m after the one with the wheels mounted in the 4 corners at 45 degree angles

/
\ /

Thanks in advance!!

Al

I don’t own or use EasyC, should be super easy to write this in EasyC though.

There is a holonomic block.

If you look through the joystick functions folder you will find a holomonic program block

It is, almost exactly the same as the PROS or ConVEX code.

(it compiles but I didn’t test with motors)

create a user source code file for this.

// holocode.c : implementation file
#include "Main.h"

// James' EasyC X Holonomic Code
// Based on Cody's PROS Holonomic code
// ===================================
// Usage:   Drive code for "X" Holonomic drive
// License: Public Domain, use at your own risk.
//
//  ROBOT SEEN FROM ABOVE
//
//        ? FRONT ?
//      ?           ?
//    ?  P1       P2  ?
//            ?
//           ?X?
//            ?
//    ?  P4       P3  ?
//      ?           ?
//        ?       ?  

void 
holoCross()
{
    while(1) {
    
        // Controller 1/2, Stick L/R, Axis X/Y
        int C1LX = GetJoystickAnalog(1, 4);
        int C1LY = GetJoystickAnalog(1, 3);
        int C1RX = GetJoystickAnalog(1, 1);

        // Y component, X component, Rotation
        SetMotor(1, -C1LY - C1LX - C1RX);
        SetMotor(2,  C1LY - C1LX - C1RX);
        SetMotor(3,  C1LY + C1LX - C1RX);
        SetMotor(4, -C1LY + C1LX - C1RX);

        // Motor values can only be updated every 20ms
        Wait(20);
    }
}

// James' EasyC + Holonomic Code
// based on Cody's PROS + Holonomic Code
// =====================================
// Usage:   Drive code for "+" Holonomic drive
// License: Public Domain, use at your own risk.

void 
holoPlus()
{
    while(1) {

        // Controller 1/2, Stick L/R, Axis X/Y
        int C1LX = GetJoystickAnalog(1, 4);
        int C1LY = GetJoystickAnalog(1, 3);
        int C1RX = GetJoystickAnalog(1, 1);
    
        // Y component, X component, Rotation
        SetMotor(1, -C1LX - C1RX); // Front
        SetMotor(2, -C1LY - C1RX); // Left
        SetMotor(3,  C1LY - C1RX); // Right
        SetMotor(4,  C1LX - C1RX); // Back

        // Motor values can only be updated every 20ms
        Wait(20);
    }
}

Call from OperatorControl.c as follows

#include "Main.h"

void OperatorControl ( unsigned long ulTime )
    {
    holoCross();
    }

You need to add prototypes to UserInclude.h

// UserInclude.h : header file
#ifndef USERINCLUDE_H_
#define USERINCLUDE_H_

// TODO: add user code here
void    holoCross();
void    holoPlus();

#endif // USERINCLUDE_H_

Now of course, this is only drive code, no lift or intake so in practise you would never actually use in this way. Then again, the same applies to the code posted by Cody in the original post.

Hey guys, have made progress but not quite figured it out.

Please see this thread and help me out! (Didn’t want to spam this one!)

https://vexforum.com/showthread.php?p=371383#post371383

There has been developments but I’m still stuck - please see thread to help! :confused:

Hey Cody,
We are using your code above to program our Mecanum Wheels. I’m not sure where we messed up, but the right joystick does the strafing and the left joystick does the rotation and forward/Reverse. I believe the right joystick should control the rotation and the left should be forward/reverse and strafing. We spent a few hours on it (moving cables and making code adjustments, but had no luck) Any suggestions?

Interesting, I actually don’t have a set of Mecanum wheels (and never have).

A quick fix (for your situation) would be to change…

int C1LX = joystickGetAnalog(1, 4);
int C1LY = joystickGetAnalog(1, 3);
int C1RX = joystickGetAnalog(1, 1);

to…

int C1LX = joystickGetAnalog(1, 1);
int C1LY = joystickGetAnalog(1, 3);
int C1RX = joystickGetAnalog(1, 4);

which effectively swaps the mapping of the left and rich sticks for the X-axis.

Don’t you guys need any control algorithms like P,PD or PID to set the speed of the wheels accurately.

In most cases user controlled X drives do not need control algorithms. The cases where it would be sense are obviously autonomous behavior or if the build quality or motor quality was drastically different across different wheels. For the small stuff the human brain usually just automatically corrects.