v5 auton turns precision [RMS Py]

Hi,

Team asked me to look into an inconsistency with their auton turns (they say they ruled out mechanical issues such as friction, bent shafts, bad bearings, dirty wheels, loose things etc). Basically we use the code below for our turns. We just used common sense on this. We looked for examples on the RMS site but everyone seems to use this drivetrain class which is designed for only 2 motors. I’m very confused about it, because I have not seen any decent Turning Point bot with only 2 drive motors (except the entry level clawbots). Most have 4 or 6 wheels with 4 drive motors.

The issue we are seeing is as follows: With a battery fresh of the charger, turn works the way it is programmed, consistently. When the battery drops to 85% or less, the turn is significantly wider (as in it should be 90-ish degrees but it’s 95-ish now, just enough to completely miss flags). We only have one battery that came with the v5 kit (Vex never shipped last year’s orders - different topic) but we did borrow batteries from others here and there and observed the same behavior. We also noticed that not all batteries are the same. Some drop to 95% after we run our auton, some dip to 80%. Ours seems to hold well, maybe we take care of it better. Some will probably say “so what’s your problem, just use fresh batteries all the time if that makes it consistent” - not that easy to do in competition, even with a few batteries, they are always on/of the charger and sometimes you need to queue with a 3 bar battery.

The only explanation I could come up with is that in order to stop on a dime with the rotate_for, the PID software tells motor to hold by pumping a large amount of current (I read somewhere stall current is about 2.5 Amps and limited by firmware? Is this right?). So to stop all 4 motors with the PID/Hold, battery needs to be able to discharge a lot of amps fast, but a good LiFePO4 cell should be able to handle this (some, like the A123 cells, have a discharge rate of 30 Amps). As the capacity decreases, the battery can supply less amps for the motors to hold? It’s a lame explanation considering I don’t know what kind of cells Vex uses (no way we are dismantling our only batt) and no idea what goes on inside that motor firmware and that on Vex’s site it clearly says “the motor will perform the same for every match and every autonomous run, regardless of battery charge or motor temperature.” Is all this completely wrong? Then why 2 different turns? What are we doing so wrong?

We dropped the “power” to 30% and all of the sudden the turns are consistent, both with fully charged and depleted battery, except that now it is more of a crawl and we can’t make the 15 seconds…

In a nutshell, this is the code we use for the turns:

def spin_left(motor_revs, motor_power):
    motor_br.rotate_for(vex.DirectionType.FWD, motor_revs, vex.RotationUnits.REV, motor_power, vex.VelocityUnits.PCT, False)
    motor_fr.rotate_for(vex.DirectionType.FWD, motor_revs, vex.RotationUnits.REV, motor_power, vex.VelocityUnits.PCT, False)
    motor_fl.rotate_for(vex.DirectionType.REV, motor_revs, vex.RotationUnits.REV, motor_power, vex.VelocityUnits.PCT, False)
    motor_bl.rotate_for(vex.DirectionType.REV, motor_revs, vex.RotationUnits.REV, motor_power, vex.VelocityUnits.PCT, True)

spin_left(0.95,60)

Is there a different/better way to code precise turns with the v5 encoder/PIDs with RobotMesh/Python? Thanks.

When you stated that your turns worked precisely with 30% speed, it leads me to believe that the root of your problem may be wheel slippage. The v5 motors do in fact perform pretty much the same on most battery percentages. As for wheel slippage, when your motors accelerate, there is a small amount of time where the motors are spinning and the robot is still accelerating, so the motor encoder values may change before the position does. I’ve dealt with this before and I solved the problem by creating my own custom PID that controls how quickly the wheels can accelerate, essentially combining the concepts of a slew rate into PID. This way minimizes the amount of slip allowing our turns to be accurate and consistent. Good luck with your turns and PM me if you have any questions and I’ll try to help.

1 Like

even with PID it can sometimes get off. What you can do is get the voltage of the battery and run the motors based on it.

AKA: 
if(batteryV<=.8){
   doNothing();
} else {
   //code to scale battery voltage so that it runs the same all the time
}

The drivetrain class calls down to the positional rotateFor commands, so it will be little different than the function you’ve written here. All the drivetrain class does extra for you is do the math of wheelbase width vs. wheel circumference to transform a turn angle into a certain number of motor revolutions.

If you want something better than the built-in PID control of the motors, you will have to write it. If you are overshooting, that means you will want to have code that watches for the upcoming target position and begins slowing down before you reach it. Something like the following logic:

#this is not code
function of a motor, number of rotations, and a max_speed:
    record starting position
    spin motor at max_speed in the direction of rotations
    do until remaining distance <= 0:
        set motor speed to the smaller of max_speed or a function of remaining distance
    stop motor

function of remaining distance:
    return constant1 * remaining distance + constant2

Basically, the secret to stopping on a dime is to begin stopping before you reach the dime.

If you have troubles with wheel slippage as you accelerate, you will need to add a third value to compare against: some function of time since the motion began. It would increase as time went on, but you would still always pick the smallest of the three (max speed, function of (remaining distance), function of (elapsed time)) as the speed for the motor to try for.