CRITICAL UPDATE - ERROR IN MOTOR COMPENSATION SUBROUTINEI finally installed a "quick change" wiring harness on Rachi's chair so that I can attach my CAN+Roboteq system when she's not using it and swap back the Dynamic DX when she is, and I discovered a majorly stupid logic error in the Motor Compensation subroutine that makes compensation almost completely ineffective. The result was exactly what John has experienced: sluggish initial acceleration and then "woosh". (Far less evident on Will's chair with its low-impedance brushless motors.) Fixing this is a mandatory change, but before you make the changes that follow below, set your MotorResistance values to something you are sure is absolutely safe. MotorCompensation is going to work MUCH better after this change, and you definitely don't want a runaway chair.
The problem is in two lines in a section starting about line 349:
- Code: Select all
349 IF (abs(oldC1-C1) <= 3) OR (GetTimerState(3) = 0) THEN
350 C1 = oldC1
351 END IF
352 IF (abs(oldC2-C2) <= 3) OR (GetTimerState(3) = 0) THEN
353 C2 = oldC2
354 END IF
355 IF (C1<>0) OR (C2<>0) THEN
356 SetTimerCount(3, BrakeDelay) 'reset timer anytime stick not centered
357 SetTimerState(3, 0) 'start timer
358 END IF
The
GetTimerState(3) = 0 in lines 349 and 352 should be
GetTimerState(3) = 1! Like this:
- Code: Select all
349 IF (abs(oldC1-C1) <= 3) OR (GetTimerState(3) = 1) THEN
350 C1 = oldC1
351 END IF
352 IF (abs(oldC2-C2) <= 3) OR (GetTimerState(3) = 1) THEN
353 C2 = oldC2
354 END IF
355 IF (C1<>0) OR (C2<>0) THEN
356 SetTimerCount(3, BrakeDelay) 'reset timer anytime stick not centered
357 SetTimerState(3, 0) 'start timer
358 END IF
What's going on here?
John had noticed that if a stopped chair was jostled, the motors, acting as generators, produced enough current that MotorCompensation changed C1 and C2 a bit which could cause the brakes to release. I did two things to fix this. The first was just to not apply MotorCompensation (that is, use the oldC values) if the change was <= 3 (out of 1000). This helped, but at least on the bench I could still force a motor hard enough to get the brake to release, so I added something else.
Why is the existing code wrong?
Whenever the stick is out of neutral (line 355), a timer is started, and continuously re-started so it stays running as long as the stick is out of neutral. If the stick is in neutral, the timer starts counting down and if it keeps on counting down for BrakeDelay milliseconds when it finishes and changes state. BUT, GetTimerState is 0 when the timer is RUNNING, not when it is STOPPED! The first time through loop with the stick off center, the timer hasn't yet been started, GetTimerState = 1 and MotorCompensation is applied. Then the timer starts, and the next time through the loop GetTimerState = 0, and C1 and C2 stay at oldC1 and oldC2, with only as much motor compensation as was calculated when the stick just started to move off center not the motor compensation corresponding to where the stick is now. And it will continue using this too-low amount of compensation until the stick again is at neutral for BrakeDelay milliseconds.
How does changing 0 to 1 fix this?
The first time through loop with the stick off center, the timer hasn't yet started, GetTimerState will return 1, and there's no motor compensation (see note below as to why this is a good thing). Then the timer starts, so the next time through the loop a few microseconds later, and every other time through the loop as long as the stick is out of center, a freshly calculated motor compensation gets applied. If the stick is moved, or the load changes (as it will as rpm changes), the new, correct motor compensation is again applied. That's the way things should work!
Yesterday, when I first hooked up the new controller and started testing with the speed pot turned all the way down I couldn't turn in place, and going fore-aft or turning while moving gave the sluggish then zoom response. Scary, even with speed pot at minimum, because I was doing this in our living room - can't be running at any speed with the whole controller rig just sitting on the rear deck of the chair. So I started to increase MotorResistance, and wasn't seeing any great effect even with absurdly high values, and the numbers in Roborun weren't showing any change with supposedly increased compensation either. Could my calculations be off by a factor of 10 or 100? I started to put some print statements in the script to see where things were going awry, and that 0 instead of 1 stuck out like a sore thumb.
Today I fixed that, remembered to turn MotorResistance way back, and I could now turn in place (just barely at pot min - some tuning still needed on that), but the chair was now accelerating correctly out of the gate without the adrenaline effect. Now I started to increase MotorResistance - nothing, nothing, TOO MUCH, and instead of just juddering, it seemed OK moving forward or back, but then just didn't stop - right into runaway. Adrenaline was back, and the first time I wasn't really prepared to pull the emergency stop plug until the chair was jammed in the corner of the living room. Dialed back MotorResistance, and all seems well at 150 milliohms (the Dynamic is set at 120, it starts to judder at 150, so my calculations aren't too far off ). The lack of juddering with resistance set just a bit high may be because throttle/steering changes <= 3 are discarded by the script - they may "count" in the Dynamic. So be extra cautious - the first sign of getting motor resistance too high may be not being able to stop!
So far, with MotorCompensation working as it should, AccelMotorComp and DecelMotorComp seem to have much less effect than they did when motor compensation wasn't correct. They may not be needed or even useful at all. Now that I have my own test bed, especially once I have a way to tie the controller to the chair, I'll be able to find out. You also may want to turn accel and decel down as the chair will get moving better without need for excessive values. Will may also find that the acceleration pot is less needed.
Ciao,
Lenny
NOTE: Why is it a good thing for there to be no motor compensation the first time through the loop after moving the stick out of neutral? When you move the stick out of neutral, the brakes are released, but it takes a finite amount of time for the disk to move. The first time through the loop you could be applying compensation with a locked rotor. Though this will self-correct the next time through the loop, it's probably easier on the motor and controller to have this slight delay (some microseconds, at most 1 msec) before boosting PWM.