Programming Mecanum Wheels

“That would be Prudent”.

Oh, OK… You use the Immediate Value of the Joysticks to get your Value and Move On with the Processing…
I wasn’t sure if you needed the “raw values” any place else in your Code, like for Graphing or Trending.

“Trust, but Verify”.

I am planning on putting all these questions to Good Use, in the next week… :wink:

( One Presidential Quote, One Anti-Presidential Quote, in One Post… )

Are you using the 4" Omnis, or the 2"?? I just got a Second Pair of 2" Omnis, so I have 4 Total now…

Hmm… I could try that with Double 2" Omnis, on a Single Motor, on each side, in the Middle of each Side… Like a Square Bot, with Four more Motors, one on each Corner, driving One 4" Mecanum Wheel.

Thanks for the Code Snippet!!!

So if I wanted to incorporate the MINPOWER I was talking about earlier, I would do this:

const int MINPOWER = 20;
const int DEADZONE = 2;
const float EXPONENT = 1.3;
const float DIVISOR  =  pow(127, **EXPONENT**) / (**127 - MINPOWER**);

int chAddition = vexRT[Ch3] + vexRT[Ch1] + vexRT[Ch4];
chAddition = abs(chAddition) > 127 ? sgn(chAddition) * 127 : chAddition;
int motorValue = (int) (pow(**abs**(chAddition), EXPONENT) / DIVISOR + **MINPOWER)**;
motor[wheel] = motorValue > DEADZONE ? sgn(chAddition) * motorValue : 0;

correct?

I’ve looked over your previous post as well as this, but I still don’t quite understand what you’re trying to achieve by using MINPOWER.

One thing to consider when using math functions such as this is that they can be quite computationally expensive on embedded systems. It’s actually not too bad with ROBOTC, perhaps 100uS, but one common optimization is to pre-calculate everything and create lookup table (LUT) when the code first starts and then use an index into that in the main control loop. There is one example where I did that at the end of this post. You are trading memory for speed.

Thank you for mentioning this; computing at least 4 things to the 1.3rd power each iteration was making me sort of queasy.
Here’s a little look up table for the algorithm I described before:


#define EXPONENT 1.5
#define DEADZONE 7
//Both of these are example numbers.
const float divisor  =  pow(127, (EXPONENT - 1));
int chAddTable[255];
for(byte i = 127; i >= 0; i--){
  int motorValue = (int) (floor(pow(i, EXPONENT) / divisor));
  motorValue = abs(motorValue) > DEADZONE ? motorValue : 0;
  chAddTable[127 - i] = -1 * motorValue;
  chAddTable[127 + i] = motorValue;
}

You can directly get the motor power by doing:
int chAddition = add channels here;
chAddition = abs(chAddition) > 127 ? sgn(chAddition) * 127 : chAddition;
motor[wheel] = chAddTable[chAddition + 127];

  • Disclaimer: I haven’t actually tested any of this, and it may perform horribly/not work.

There is some range of power near zero that, when you send it to the motors, is too low of a power for the robot to actually move (too much friction). The MINPOWER makes it so that when you move the joystick just past the DEADZONE, the robot will actually start to move. It really helps the drivers who are trying to do very fine movements because they don’t have to keep moving the joystick forward until the robot finally starts to move; they know that the robot will start to move if they just barely push the joystick forward.

This seems like a ridiculously good idea.
A few questions though:
What does this do?

for(i=0;i<128;i++) {
stuff }

My guess is that it increments i (starting at i=0) each time it goes through the loop until i gets to 127, at which point it stops running the loop. Do you have to declare i? Or does it declare it automatically when you run that loop?

What is the test6 in that thread actually doing? I have no idea how tables work in RobotC (or any other language for that matter, except my graphing calculator’s language, which hasn’t been a tremendous help for learning RobotC, I must say).

My justification to myself for asking these very noobish questions is that hopefully someone else can learn from the answer in the future.

Thanks!
I think I understand what this is doing. Would you put the table-creating (snipped) part in pre-auton in competition code?

And concerning:


for(byte i = 127; i >= 0; i--)

Will i start at 127 when it goes through the loop for the first time? Or 126? Meaning does it do the – or the ++ at the end of the loop or at the beginning?
Is the “byte” necessary?


    int x1 = THRESHOLD(vexRT[Ch4], 15);
    int y1 = THRESHOLD(vexRT[Ch3], 15);
    int x2 = THRESHOLD(vexRT[Ch1], 15);
    int y2 = THRESHOLD(vexRT[Ch2], 15);
  int yComp = ((abs(y1) > abs(y2)) ? y1 : y2);
  int turnComp = ((abs(x2) == 0) ? x1/2 : x1);
  int strafeComp = ((abs(x1) == 0) ? x2/2 : x2);
    output_Left_Front = LIMIT(127, -127, yComp + turnComp + strafeComp);
    output_Left_Rear = LIMIT(127, -127, yComp + turnComp - strafeComp);
    output_Right_Front = LIMIT(127, -127, yComp - turnComp - strafeComp);
    output_Right_Rear = LIMIT(127, -127, yComp - turnComp + strafeComp)

That’s exactly what I do. 50% power if both joysticks, 100% power if only one.

As an aside, what I found with the mecanum wheel robot I drove at worlds, was that driving diagonally cause the drive motors to overheat and trip their breakers VERY quickly, especially when coming into contact with other robots. This more than likely had something to with the rather poor weight distribution (the arm was so long that most of the weight of the robot was over the front wheels). My solution to this problem was to “lock” the strafe, such that if the average of the two horizontal channels (1 and 4?) was above a tolerance, the robot would ONLY strafe (at a power given by the average of the two channels), otherwise the robot would control and drive like a normal tank. This greatly reduced the risk of motor overheating. The obvious downside to this approach is that it limits the degrees of control you get, but on the whole it was worth it.

As I mentioned, the robot could have been built better and would have likely not suffered from this problem, but if you ever run into it this is a potential solution.

Use the Holonomic function, it works like a charm.

That problem stemmed from the fact that when driving diagonally, you are only using two of the motors, and those two motors are only at 70% torque because they are driving at an angle, so you effectively have 1.4 motors driving your robot diagonally (instead of the 4 when strafing, going straight, or turning).

In addition to this, although it may not be a huge contributor, the wheels which aren’t moving are being “dragged” so there is a lot of friction.

Well the rollers are being “dragged” (across their axis of rotation, so it’s not too bad), but if you aren’t going at a perfect 45-degree angle, the wheels that had the “dragging” rollers should be powered enough so that no wheels have to actually force other wheels to turn.

As you can see here, there is a force acting on the unpowered wheels by the robot chassis, which will cause extra friction on the rollers (that force is pushing the rollers parallel to their axis of rotation and therefore in a direction in which they cannot spin).

Sorry, dontworryaboutit, I didn’t see your post until now.

That’s where I would put it, but you could really put it anywhere. putting it in the pre-auton just saves you a few milliseconds of time.

The i will start at 127. The increment occurs at the end of the loop. I used byte just because you don’t need the two bytes of memory used by an int here. It’s one byte of space, so it doesn’t really matter. You can also make the array out of bytes instead of ints as well though.

Do you have an already built code sample that does something like this? We have four motors (call them left ft, right ft, left rr, right rr) that are each powered directly to mecanum wheels.

I’m interested in helping our team members to get to the next level on some of the code needed to more smoothly control this setup - also having a two speed setup would be ideal as the current gearing is pretty fast for the new drivers or when trying to do slow maneuvers.

Thanks!

To get maximum control at all speeds I would recommend 24C’s array for motor values seen here

https://vexforum.com/t/24cs-motor-control-value-remapping/23959/1

What it does
Pushing a joystick to half way is 63

using a standard drive system you run a motor at 63 power but as Jordan proved that is roughly 75% speed rather than 50% speed

What the array does is it allows a robot to run at linear speeds
1/2 on joystick runs 1/2 speed
and so on

There are some complicated images up there, so I took the liberty of showing you this one.
mecanum-diagram.jpg

Hi, can someone please provide the same they have for v5, in Vex Coding Studio, because our team is really struggling to get the drive to move

@Drow, please close. @Vexellent please post only one thread when you have a question. Please do not revive 6 year old threads, make new a new thread if the old one has no responses in recent months. You must have done a search to find this thread, which is good – but try sorting the results by latest to find current content.

Recently, this question was asked for vexcode blocks (Mecanum Drive Coding on VEXCode Blocks), perhaps you can us that to figure out the text code.

2 Likes