Banana Show full post »

Motor Control Solutions

I noticed that many BEST students and competitors believe that speed is the most important parameter.  But evaluating the BEST playing fields, speed is not really as important as maneuverability and flexibility.  To make your robot maneuvering easy and consistent, your motors must run at the same commanded speed all the time.

The problem is that Vex Cortex motors normally run slower as the Vex battery voltage falls from 8 volts (fully fast-charged) down to about 6.4 volts , the level were the Cortex stops running motors.

To help offset the declining motor speed, I came up with the following solution for my home-grown robot.  This is a plywood-framed tall robot built of BEST-ordered parts along with many salvaged parts from my 40 years of electrical device junk collection.  I call it “JR-1” for Junk Robot #1.

First I needed a RobotC equation to calculate the remaining battery power.   As any old electrical engineer would do, I first looked to see how others had solved this problem.   (Rule#1:  Don’t re-invent the wheel.)   On one of the Vex forums, I found a calculation of the % Battery Remaining using the Cortex parameter “nImmediateBatteryLevel”.  I substituted the average level “nAvgBatteryLevel”, which is the average over the past 20 samples, for me a much more useful indicator of the battery condition.  The RobotC program lines become:

#define Battery_Low   6.4

#define Battery_High  8.00

float Battery_Remain  =  ((nAvgBatteryLevel  /  1000.0) - Battery_Low)  /  (Battery_High - Battery_Low)  *  100.0;

Then I needed a way to adjust my motor speeds based on the Battery_Remain factor.  I designed my robot to work at the Vex-recommended speed level of 50%, or 64 out of 127 maximum speed setting.  That means that I have a possible adjustment range of approximately 50% or 64 up to 127.  Because I wanted my adjustment factor to be simple to use, I settled on a Power Multiplier of 1.0 up to 2.0.  Using a multiplier eliminates any possible problem with divide-by-zero errors, and any problem that an Addition or Subtraction factor might run into, such as making the final number out-of-range (not within 0 to 127).

Adjusting the Battery_Remain to produce a linear power adjustment multiplier from 1.0 to 2.0, produces the following equations:

Slope =  (change in Y)/ (change in X) =  (2max – 1min) / (0 – 100)  =  -1/100

Y-Offset = Ymin – (Xmin x Slope) = 1.0 – (100 x -1/100) = 1.0  –  (-100/100) = 1.0 + 1.0  =  2.0

Power Multiplier = (Slope x Battery_Remain) + Y-Offset = (-1/100 x Battery_Remain) + 2.0 = (Battery_Remain/-100) + 2.0

With these RobotC lines:

float PowerMul  =  (Battery_Remain  /  -100)  + 2.0;

motor[driveRtSmallMotor] = PowerMul * 64;     //  Motor on port 2 is run at 50% power, adjusted for voltage drop

motor[driveLtSmallMotor] = PowerMul * 64;      //  Motor on port 6 is run at 50% power , adjusted for voltage drop

 The above equations worked pretty good to keep my robot running at a constant reliable speed for making straight runs and during turning.  At least at first.  Then I noticed a strange anomaly, which I discovered by making many dozens of test runs.  For the first 100% to 60% of Battery Remaining, my Port 2 motor-driven right wheel runs faster than the Port 6 motor-driven left wheel.  Per the usual explanation, I thought it was due to my building defects, the left bearing and axle tighter than the right, or misaligned.  But then from 60% down to about 40%, the speed difference disappeared completely.  I thought that the bearings and axles had worn in and the friction difference had disappeared.  But then from 40% down to 0% (7.04 volts down to 6.4 volts), the Port 6 motor-driven left wheel runs faster than the right wheel!  This pattern repeated many times using 2 different batteries and many states of motor and bearing temperatures.  I do not think it could be explained by friction factors.  The only satisfactory explanation I came up with is some factor in the Cortex control program firmware.

 To adjust for this variable, I used some If statements to create new additional PowerMulRight and PowerMulLeft variables, with the following RobotC lines:

 if (Battery_Remain  >  60)
PowerMulLeft = (Battery_Remain / -100) + 1.965;
PowerMulRight = PowerMul;
if (Battery_Remain < 40)
PowerMulLeft = PowerMul;
PowerMulRight = (Battery_Remain / -100) + 1.965;
if (Battery_Remain  >=  40 & Battery_Remain  <= 60)
PowerMulLeft = PowerMul;
PowerMulRight = PowerMul;

 Perhaps others have discovered the same problem but a better solution.  If so, please post it here.

Quote 0 0
That is a great post!  Lots of math and actual experimental results documented, and a call for alternative ideas.

The only satisfactory explanation I came up with is some factor in the Cortex control program firmware.

Call this H1.  Is there any way to disprove it?
What other hypotheses did you consider and discard as unsatisfactory?

Here are some ideas for alternative hypotheses:
H2: The motors have different response running CW vs CCW rotation.
H3: The L,R motors have different non-linear response to pwm input voltage
H4: The MC#29 on L,R ports (2, 6) have different non-linear pwm output to input pwm.
H5: The L,R ports (2,6) have different non-linear pwm output response to motor power setting (-127..+127)
H6: Some combination of all of the above.

Some of these can be tested/falsified by swapping motors, swapping ports, swapping MC#29, driving backwards, swapping batteries, and/or hacking your robot to have both motors drive the same direction.  

Your innovative solution uses experimentally determined constants,
- for your current setup,
- based on closed loop feedback of battery voltage,
- to create open-loop drive strength settings
    that compensate for all of H1..H5 together, so it doesn't matter what is the root cause.

 Perhaps others have discovered the same problem but a better solution.  If so, please post it here.

Here are two alternative (not necessarily better) solutions I have seen described elsewhere:

A.  Use some wheel encoder feedback from real wheel speed.  This closes the loop around all the H1..H5 factors, and potentially get better response if there were changes in the combinations of factors, like swapping motors/MC#29/ports/batteries, or aging of components, without requiring re-characterization.
  The FTC Teknik DC motor controller can use this method;  but as soon as the motor stalls, the controller slams on full voltage, and can burn out the motor if it is jammed.

B.  I've heard of people characterize their setup per motor for input setting to actual Motor speed output.  Then create a lookup table to linearize it.   If both L and R motors are linearized, then they will also be matched.
   Your equations implement a piece-wise linear translation, that also includes battery voltage feedback, based on your 3 point characterization.
     A lookup table can implement any arbitrary non-linear response curve, so it is a little more flexible, but it takes more work and input data to do the characterization.
Quote 0 0
I have considered your H1 to H6 hypotheses.  While thinking about those, I came up with another based on my experiences.

Call this H7 - The PWM electronic cross-over induced voltage and noise hypothesis.

After thinking about similar electrical problems that I have encountered in industrial plants with Variable Speed Motor Drives (which have PWM outputs although for AC motors), I think that electrical noise (induced fields around the wires) may be a big factor in my speed-control problem.

The usual remedy for controlling electrical noise that is bleeding over to other circuits is to use shielded cables (cables that have a metallic shield of some type, such as a foil covering or a net of fine wires, that completely covers the cable, so that the stray electrical noise cannot easily bleed out into the environment, and into other cables or other devices.  Usually the shield is grounded to the nearest 0-volts grounding point (to keep the shields at 0 volts), but because the Vex robot system does not have a ground point, I have not done the grounding step - yet.  Hopefully a ground point will not be necessary for this case.

I don't think there are any shielded cables available from Vex, so I decided to convert my existing Vex 3-wire cables by covering them with aluminum foil tape or aluminum duct tape (available at hardware stores and outlets, and HVAC supply houses).  Today I spent several hours wrapping and covering the motor cables that have Pulse-Width Modulation.  I also added a shield to the Gyroscope cable to prevent stray induction from being imposed upon its signal.  I may go back later and shield the remaining analog signal cables (encoders, accelerometer) also.

Tonight my robot ran smoothly and consistently for the first time.  Most of the operating difference between right and left motors seems to have disappeared (at least at the 40% battery level).  Now I can reduce my fudging equation factors to nearly nothing, after I run it for awhile and see how it performs as the battery voltage goes from 8 volts down to 6.4 volts.
Quote 0 0
That certainly is an interesting data point.
   Does your H7 mean that external noise is coupled into the PWM circuits?  probably PWM into MC#29 would be the most susceptible?
   Or do you mean that the PWM noise is escaping from the PWM into the cortex, or wifi, etc?

I occasionally hear about adding a capacitor across the motor terminals to help filter noise, or shielding, or twisting the wires so that the magnetic fields cancel out in a shorter distance aka "twisted pair".

You mention both "3-wire cables",  and "cables that have Pulse-Width Modulation".
My understanding is that the 3-wire cables from Cortex to MC#29 H-bridge carry PWM with a 2ms period, or 10ms period, and a 1ms +/- pulse for speed information,
while the 2-wire output to the motor is  both +/- polarity, and 0-100% pwm duty cycle at 1KHz period.  
  Which PWM cables did you shield, just the 3-wire from Cortex to H-bridge?

   I would guess that the most likely noise cross over would be between the high current motor PWM, and the low voltage control PWM,
 but many people report wifi connection problems also, particularly when the wifi key is mounted directly under a motor.

Quote 0 0
Every electrical wire that has a current also generates a magnetic field around the wire (call it Wire #1).  Any other wire (#2) that passes through the #1 field is subject to have an induced voltage added (or subtracted depending on the direction of the field) from its own current.  This in general is often referred to as electrical "noise".

The noise source can be the normal PWM current, and the problem is that it will cause an induced voltage in nearby wires.  A PWM generator is always a prime noise source, due to the rapid electronic on-off switching that controls the voltage in the circuit.  PWM induced currents often effect other nearby wires.  In this case the left motor current can effect the right motor current and vice-versa, specially if the wires are routed near each other and do not have shielding.  I am sure that this was happening for my motors, and now after shielding, they are running much more consistently.

In my former electrical design-and-build industrial jobs, almost all of the PWM variable speed motor drive power cables, from the VFD drives out to the motor, required shielding or metal conduits which served the same function.  The control signal cables from the control room to the drive were also always shielded.  Otherwise nearby equipment could be affected in a negative way.  But those were usually 240 or 480 volt  A.C. motors, so the higher voltage made the problem worse.  For a 7.2 volt system, the problem should be much less, but not insignificant where precise speed control is desired.  All 2/conductor 4-to-20 miliampere 24 volt DC signal cables in an industrial plant have to be shielded for the same reason.

I added shielding to the 3-wire cable from the Cortex motor terminals to the #29 Motor Controllers, and then completely enclosed the controllers in foil, and then from the controllers out the 2-wire cables to my terminal block, then around the terminal block, and then from there around the #16 AWG 2-conductor twisted pairs out to my motors.  In other words, a 100% shield from Cortex to motors.  This theoretically will prevent any inductive field ("noise") from escaping the cables, and also prevent any outside fields from entering the cables.  The goal is to keep each PWM-controlled voltage exactly as it was created, neither adding to or subtracting from it until it reaches the motor.   That is the theory anyway, but there is always leakage around the terminal blocks because the shield has to stop short so as not to create a short-circuit between the terminals.

The terminal block was a real challenge.  What I did was measured and cut a piece of the aluminum duct tape to fit around the block from end-to-end and back again, long enough to wrap completely around the TB.  Then I pressed the top tape against the screw terminals, making a pattern in the aluminum foil.  Then I used a hole punch to punch out holes for each screw position.  Then I removed the backing and pressed the foil down around the screw-head shrouds, and continued wrapping around the end and back down the bottom.  So the terminal block is shielded, but each individual terminal is not shielded from its neighbor.  The only way to do that is if you have a TB designed for shielding.  I will attach a picture showing such a signal-cable block that I invented several years ago.  Maybe Vex (or someone else) would like to manufacture it?

Quote 0 0