Fixing driver control

My team has an X drive holonomic(ITZ) and a standard 4 motor tank drive(NBN) we are testing. The X drive sort of glides/veers to one side during forward motion. The tank drive veers to the right. Does anyone have any simple solutions for these problems besides looking for binding somewhere in the mechanics?

We isolated each wheel on the tank drive and recorded its revolutions over a 20 second period using an encoder and the RobotC debugger. I attached a chart of what the data looked like. This isn’t the actual data; I left that at work, but there were some major discrepancies. Each of these wheels is direct drive to the motor. Is there a way to compensate for the discrepancies even though the input will be varying frequently?

I would also like to make the controller use a lower speed factor near the center of the sticks, and a higher rate of change closer to the limits. Does anyone have any sample code for something like this?

Simple solutions would all be mechanical assuming your code is correct. Make sure your gearing is identical, distribute weight as evenly as possible, etc.
Alternatively, you can use your discretion in reducing the power sent to faster motors to try and even them out (this can be simple with constants or complex with fancy math).

As for the speed factor, I think you want something like this pseudocode:

motor = (joystick / abs(joystick)) × sqrt(abs(joystick)) × 11.3;

joystick / abs(joystick)

will return ±1 to signify direction


≈ sqrt(127)

Something even more simple would be to tie the front wheels together and the back wheels together with long axles. Good luck with turning :stuck_out_tongue:

Edit: I’m all seriousness, for the c drive I would really just recommend closing it in on all sides because the few times we haven’t done that it bends, causing it to drift. And as someone said below weight balancing is VERY important. All the c drive I’ve built that don’t have good balance ended up being a nightmare to program.

@Barin Thank you for those ideas, I will try the code tomorrow. We have gone over the mechanicals and distributed the weight fairly evenly. Do you have a complicated solution that will help?

Sort of… I don’t have code handy but I can give you the general idea.

I’ll make a new post in this thread shortly when I come up with a half-decent explanation.

Maybe I missed it. Were those test rotations under load (intentionally) or not? If in place but not under load, that indicates something different than in place and under load.

As for the coding, don’t do the square root suggestion. That does exactly the opposite of what you said you want. For example, if your controller is at 64 (half way), you’ll get sqrt(64)11.3=811.3=90 (rounding for integers). That means you’ll almost always be running at nearly full speed unless you’re really, really careful around the middle of the joystick. Presumably you want more control at low speeds to make fine-tuning orientation and distance easier, and if you want speed you’ll just push right to the end. Also, it’s not a good habit to read the controller repeatedly; you want to read it once and then use that value repeatedly. Here are a few simpler ones in mixed pseudocode/code:


int speed = 0;


int speed =0;

(Note: The order of multiplication and division is important in the second example. If you cube high speeds, it gets too big for int. If you divide by 127 too early, you’ll get too much rounding. So you multiple, then divide, then multiply, then divide.)

@Coffee @callen Thanks that is very helpful.

Oh, I forgot a piece. Replace both speed recalculations (third line in each example) with

if (abs(speed)<#)
the calculation I wrote above (squared or cubed)

Edit: The reason for this twofold. The first is that sometimes the joystick won’t quite read 0 when released. The second is that if it really is 0, you don’t want to divide by it and get an error.

IDK about the X drive. Our team tried an X for our first competition last year and we struggled with it endlessly. It constantly drifted and kept stalling out even on 1:1 torque motors with plenty of mechanical tuning and code fixes.

As for the tank drive, I have two suggestion (which can be combined):

  1. Try writing a PID control based on acceleration/velocity. You can use accelerometers and integrate directly or encoders and find deltas. You can run tests and hard code values of the constants after a long test then use them in your competition code.

  2. Try a master/slave encoder correction algorithm. My school had a first year FRC team this year and the chassis build quality was pretty horrendous. The robot drifted a good 30+ degrees to the right in less than 8 seconds. Since the build team refused to fix it, I had to use code. The very simple master/slave correction worked miracles, almost making up for the hardware issues. You can look at this for an example:

the code is really messy though since we had very little time to program and test given the amount of time the first-year builders needed. But it should illustrate the concept. You can also google stuff. Hopefully that helps.

Also like some others explained, squaring the inputs from your sticks will achieve the second part of your question.

Master/slave can be useful. But if one if off, you can just use one encoder in the pair.

NW/SE is one value and NE/SW is the other value. You will either average the sensors or master slave them if they are deemed accurate. TBH is another alternative to speed control on the slave wheel. Or ingorming one can be done but you will want it back for rotation control.

Make sure the IME’s really are reading the same thing for the same distance. Slowly drag the robot in the 45 degree direction where two wheels would be turning and the other two are following. See if the encoders over the same distance are really truly giving nearly the same readings. If the readings are off in one, then there is probably different gears inside one of the motors. Do it for each wheel set.

Or one encoder could be dirty. Wipe off the lenses and make sure the disc is clean to read or does not have scratches. If gouged, it will not read right and repaint it if you can or buy a new one.

@callen @Team80_Giraffes Would you recommend an arrangement like this to reduce the amount of encoders and to increase consistency?

I personally have not had any issues with IME’s, however I know that a lot of people here on the forum say that it is prone to resetting due to static. If it was me, I would say use the IME.

Did you resolve anything about the different motors running at different speeds with the same settings?

The best place for a quad encoder is usually on an undriven wheel so it doesn’t record travel if the motor is forcing the wheel to spin while the robot isn’t moving. But there could well be other constraints not allowing for this. Where you want to put it could certainly work. Would it interfere with anything?

We are redesigning the drive train around the drawing above, so we haven’t attempted to identify the source of the discrepancy. I am having the team measure the rotational speed of each of our motors (20+) in standard 393 configuration, in identical conditions, and recording the results in a spread sheet. Then we will know what we are starting with and can begin with closely matched motor sets. So far the max has been 1.68 rev/sec and the min has been 1.43 rev/sec.

We should have plenty of clearance to fit the encoders where ever is optimal. What you said makes a lot of sense.

Is your drive turning to one side in autonomous or driver control or both?

For autonomous, you will need to make a program in which the encoders on both sides try to equal out so the drive will go in a serpentine pattern but it will drive straight. YOU can also use a gyro for this.

For driver control, I don’t know how to fix the turning problem. I don’t know but maybe a PID control program can help?!?!

use this on the side that goes slower