I will organize this post as follows: I will begin with a dissection of your approach to traction control, a general explanation of a few things, and then an explanation of our team’s approach to traction control. I apologize in advance for the length of this post, but I want to be thorough.
First, your code: as currently posted, I see a few reasons why it’s not performing as expected. For clarification, the way I interpret your intentions is that you will take the velocity from the encoders, compare it to the expected velocity from the omniwheel encoder, and adjust the speed once slippage occurs. So, here goes: …
// make sure that there’s enough of a difference
const float slipThreshold = 30.0;
if (fabs(transVel - omniVel) < slipThreshold)
return desiredWheel;
This will always return “desiredWheel” if you are inputting values directly from GetY() or the direct float which drives the speed controller; if you are using PWMs, then I’m not sure if this threshold is sufficient; it seems fairly high, since it would be about 25% (assuming -128 to 128) or the possible scale for PWMs. Perhpas you can shift the slipThreshold so that it can, in fact, be violated.
// calculate what speed we are saying we should go at
// This should be whatever the omni wheels say
float correctSpeed = omniVel / maxSpeed;
I haven’t looked at the CIM motor charts (what’s the exact term for them? they display motor torque, output shaft speed, etc), but are CIMs fully linear? If so, this will work; if not, then this will have slight differences and cause a jumpy control system. This gives you the current motor output based on the current velocity and the maximum speed of the robot, assuming CIMs are linear; to apply Occam’s Razor, wouldn’t it be simpler just to record the last time the wheels were not slipping as the correct motor output for the current velocity?
// at this point, we can return correctSpeed
// however, this makes it really jerky, so we this following instead:
// Average them, to still give the drivers some control
return (desiredWheel + correctSpeed) / 2.0;
This will take the inputted desired wheel speed, take the current wheel speed, average them, and return that motor output. The way I see it, all this does is reduce the sensitivity of the joysticks by about 1/2 – if the current wheel speed is 0, and the joystick input is 1.0 (full forward), you’re still going to get slippage, at least temporarily.
A few last general issues I see with your code.
First, the omniwheel is in the middle of the robot, right? If it’s not in the exact same position as the wheel you are adjusting, you’re going to have issues when you turn because the velocities will be slightly different; this will result in a very jumpy, buggy control system.
Second, you’re using the slip after the slip occurs, but then you have already lost about 1/6 of your possible acceleration, and the system will either lose acceleration or allow slipping x times per second, depending on how fast your corrections are. This is the only way you can do it with velocity; my suggestion is that you use acceleration instead of velocity. With a little experimentation (even just by tweaking a constant in the code) and taking the derivative of the velocity, you can cap the acceleration greater than the max you will get while slipping, but less than the acceleration which would allow slippage. This should be somewhere around 0.50 to 0.55 m/s^2, using provided coefficients of friction (which have been found to be inaccurate, thus the necessary tweaking).
Lastly, my team’s approach to traction control: we have one encoder on each drivetrain; one for the left, one for the right. We take the distance from the encoder and derive it to get v, then derive it again to get a. If a is greater than a certain threshold, we adjust the outputted motor speeds proportionally (the constant has been found experimentally to allow good, smooth acceleration without slipping). If anyone would like to see our algorithm, or get further explanations of how we do it, you can PM me; I’d gladly share the code, I just don’t want to lengthen this post more than I already have, and the code doesn’t necessarily make sense taken out of context (without the classes I have defined, and the variables I have declared).
If you would like any more assistance, I’d be glad to help you in any way. Communication is not limited to CD, if AIM or Facebook would be easier to do.
Disclaimer: This is my second year doing this, and my second year programming. I am not familiar with PID loops; everything here is what I’ve picked up this season.