root/branches/atorf/NXC/MotorControl2/ControllerCore.nxc @ 658

Revision 658, 27.8 KB (checked in by atorf, 4 years ago)

little cleanup

Line 
1//#!C
2/*
3% Part of MotorControl containing the main PD-controller function, to be
4% included TWICE via preprocessor tricks :-)
5%
6% Signature
7%   Author: Linus Atorf (see AUTHORS)
8%   Date: 2009/06/28
9%   Copyright: 2007-2009, RWTH Aachen University
10%
11%
12% ***********************************************************************************************
13% *  This file is part of the RWTH - Mindstorms NXT Toolbox.                                    *
14% *                                                                                             *
15% *  The RWTH - Mindstorms NXT Toolbox is free software: you can redistribute it and/or modify  *
16% *  it under the terms of the GNU General Public License as published by the Free Software     *
17% *  Foundation, either version 3 of the License, or (at your option) any later version.        *
18% *                                                                                             *
19% *  The RWTH - Mindstorms NXT Toolbox is distributed in the hope that it will be useful,       *
20% *  but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS  *
21% *  FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
22% *                                                                                             *
23% *  You should have received a copy of the GNU General Public License along with the           *
24% *  RWTH - Mindstorms NXT Toolbox. If not, see <http://www.gnu.org/licenses/>.                 *
25% ***********************************************************************************************
26*/
27
28
29// this function CAN and HAS TO BE INCLUDED MULTIPLE TIMES!!!
30
31
32
33// To get functionality for TWO SYNCED MOTORS, do the following:
34// Always take RunMotor, copy-paste it, call it RunMotor2, add another
35// argument port2 to it, and done. BEFORE the function, define RUNMOTOR2_SYNCMODE
36
37// note how RunMotor2 doesn't need to be inline and takes 1 more argument...
38#ifdef RUNMOTOR2_SYNCMODE
39void        RunMotor2(const byte &port, const int &power, const long &tacholimit, const bool &speedreg, const bool &holdbrake, const bool &smoothstart, const byte &port2) {
40#else
41inline void RunMotor(const byte &port, const int &power, const long &tacholimit, const bool &speedreg, const bool &holdbrake, const bool &smoothstart) {
42#endif
43
44/*
45The whole concept works like this:
46There is a loop with static execution time for worst case -- if it's faster,
47there's busy waiting at the end. Durinc decelaration / braking, we control the
48motor with a PD-controller algorithm. The constant loop execution time is
49important, as a varying delta T for the controller is really bad. It would
50require a different set of KP and KD parameters, and the speed calculation the
51way it's currently implemented would also change its sliding integration window,
52so we stick with constant loop timing. Execution speed can vary since in the
53worst case, all 3 motors are controlled by this function, running in 3 threads
54at once. There is a 4th thread to listen for incoming messages, so we only have
551 quarter of the NXT's original CPU power left per thread. We don't want to
56program statically, since than we'd allways have the worst case. Hence the
57dynamic busy waiting at the end, while still intelligently checking if the
58desired motor position has been reached (so the waiting is still useful in some
59way).
60
61So we've got a loop with constant execution time, and a PD-controller during
62deceleration. The motor-power will constantly be set down, linearly, dependent
63on its current position. This way, if it get's stuck (i.e. during braking the
64load somehow increases or the motor blocks), the controller adjusts the power
65accordingly (the controller has a given set-point for power, depending where
66in relation to our position target we stand).
67
68Since the loop is fairly slow in the worst case, we've got time to spare in the
69best case (2 threads running, 1 motor + 1 message listener). During the waiting
70time, we check if the motors get's close to its target -- this only matters
71during BRAKE stage.
72
73Yes, inside the big outer loop, there are different stages. During RAMPUP we can
74implement a manual rampup (power constantly increasing) for a smooth start.
75During driving, nothing happens but measuring speed and deciding when the whole
76braking/deceleration should begin.
77
78Then there's the BRAKING stage, with the already mentioned PD controller in
79action. This is what's actually important. To get precision, we have to very
80closely monitor when our desired target is reached. In order to achieve this,
81we've got the ENDGAME mode.
82
83ENDGAME phase will be entered a couple of degrees before the motor reaches its
84goal. The PD controller should have succeded by now to enforce a really low
85turning speed of the motor (just as we targeted/specified in our desired
86"speed at motor position" deceleration curve lookup table). The most important
87and most critical thing of the whole function is now to come to a stop at
88exactly the right position. All CPU time we have is needed to monitor the
89motor as often as possible and enable the brake at the target position. This
90is whats called the endgame inner loop. To avoid the very unlikely event of a
91lock-up (the motor gets blocked just a tiny degree or two befor its final goal),
92there's also a timeout.
93
94
95The idea of "stages" (or phases) during a main loop was chosen so that short
96movements are possible with the same code/function. If we had different loops
97after each other, we'd have to check for abort conditions all the time, and
98include speed monitoring in each loop.
99This way with stages in one loop, the algorithm (or command flow) can proceed
100from stage to stage, even if the current stage has to be ended premature (i.e.
101a motor is not fully ramped up yet, but already has to start braking in order
102to reach its target safely).
103
104*/
105
106
107
108
109// **** THINGS NOT IN THIS FUNCTION
110// - decision if NO CONTROLLED LOOP is needed (classic way?!)
111// - defer as much decision etc as possible to MATLAB, see below
112
113// **** More lookups needed:
114// - Brakingdist from Speed
115// - Absolute acceleration power during rampup (in discrete steps like 10, 20, etc)
116
117
118// --- Some DECLARATIONS -- not all of them, this is timecritical
119    long i;
120
121    int  powerSgn       = sign(power);
122    long tachoTarget    = powerSgn * tacholimit;
123
124
125// --- Reset counters etc
126//     * See below, now happens implicitely in MotorCmd*Reset
127   
128// --- Decide if SIMPLE FUNCTION needed?
129//     * For small powers!
130//     * For (very?) short distances???
131
132// --- Start driving (important that its EARLY in this function -- for direct commands)
133//     * Runstate RUNNING
134//     * power = +-1
135//     * tacholimit already...
136
137    // do not yet enable speedreg
138    #ifdef RUNMOTOR2_SYNCMODE
139        MotorCmdDoubleReset(port, powerSgn, tacholimit, port2);
140    #else
141        MotorCmdSingleReset(port, powerSgn, tacholimit, false);
142    #endif
143   
144
145    #ifdef ENABLEDEBUGGING_OLDLCDTIMING
146        motorStartedTime = CurrentTick() - receivedMsgTime; // NEW DEBUG
147    #endif
148
149
150// --- Declare and Initialize various variables
151//     * STAGE is RAMPUP
152    int  curStage = STAGE_RAMPUP;
153
154    int  absPower = abs(power);
155
156    int maxAbsBrakingPower;
157    maxAbsBrakingPower = absPower;
158    if (speedreg) {
159        maxAbsBrakingPower += ADDITIONALMAXSPEEDREGBRAKINGPOWER;
160        if (maxAbsBrakingPower > 100) {
161            maxAbsBrakingPower = 100;
162        }//end if
163    }//end if
164
165
166    long absBrakingDist;
167    long brakingStartSpeed;
168    long brakingStartTacho;
169
170    long loopStartTick;
171    long waitEndTick;
172   
173    bool endgameSuccessful = false;
174   
175    long rampupLoopCount = 0;
176    long newPower;
177   
178   
179
180    //PID stuff
181    long err_0 = 0;  // current error (t =   0)
182    long err_1 = 0;  // prev.   error (t = - T)
183    long curPIDPowerUpscaled = absPower * PIDUPSCALING;
184    long newAbsPower;
185    long desiredSpeed;
186
187    // speed stuff
188    long curSpeed;
189    int  SpeedLogIndex = 0;
190    long TachoCountLog[SPEEDHISTORY];
191    long TickCountLog[SPEEDHISTORY];
192
193    // init speedlog
194    for(i = 0; i < SPEEDHISTORY; i++) {
195        TachoCountLog[i] = 0; // should still be 0, was reset just a moment ago
196        TickCountLog[i]  = CurrentTick(); //careful, check if this works...
197    }//end for
198
199
200#ifdef ENABLEDEBUGGING_LCD
201    long loopCount = 0;
202    long lastTick  = CurrentTick();
203    long lastLoopTime;
204    long totalStartTick = CurrentTick();
205    long totalEndTick;
206    long totalControlTime;
207    long endgameLoopCount = 0;
208    string lcdTmp;
209    string lcdTmp1;
210    string lcdTmp2;
211#endif// - - - - - - - - - -
212
213#ifdef ENABLEDEBUGGING_REMOTE
214    string tmp;
215    string tmp1;
216    string tmp2;
217    string tmp3;
218    bool brakingStartMarkerSent = false;
219#endif// - - - - - - - - - -
220
221
222#ifdef ENABLEDEBUGGING_ACOUSTIC
223    PlayTone(300,100);
224#endif
225
226// --- MAIN LOOP ---------------------
227    while(true) {
228   
229//    * record time
230        loopStartTick = CurrentTick();
231       
232        #ifdef ENABLEDEBUGGING_LCD
233            loopCount++;
234            lastLoopTime = CurrentTick() - lastTick;
235            lastTick     = CurrentTick();
236        #endif// - - - - - - - - - -
237       
238
239//    * check STOP CONDITIONS?
240//      - already there?
241//      - direct command stopped us?
242        // this is like an emergency-check to see if endgame should be enabled?
243        //TODO seems obsolete!
244        if ( abs(tachoTarget - MotorTachoCount(port)) >= 2 ) {
245            // we are almost already there :-)
246            // or even too far :-/
247        }//end if
248
249       
250        if ( MotorPower(port) == 0 ) {
251            //direct command must have stopped us!
252            //TODO is this really a clean direct command exit?
253            #ifdef ENABLEDEBUGGING_LCD_SLOW_ANTIBUG
254                TextOut(0, LCD_LINE8, "ABORTED(start)        ");
255            #endif
256            return;
257        }//end if
258       
259
260//    * RECORD SPEED
261//      - with this long loop execution time, use speed history of 2
262//      - 2 vars, toggle between history...
263        curSpeed = ((MotorTachoCount(port) - TachoCountLog[SpeedLogIndex]) * 1000) / (CurrentTick() - TickCountLog[SpeedLogIndex]);
264
265        //TODO optimize speed logging by using only 2 history values and toggling between them
266
267        // record speedlog data to previous index...
268        i = SpeedLogIndex - 1;
269        if (i < 0) i = SPEEDHISTORY-1;
270        TachoCountLog[i] = MotorTachoCount(port);
271        TickCountLog[i]  = CurrentTick();
272
273        // move current index for next reading
274        SpeedLogIndex++;
275        if (SpeedLogIndex > SPEEDHISTORY-1) SpeedLogIndex = 0;
276
277
278//    * if RAMPUP STAGE:
279//      - increase power (set according value from lookup / count loop-passes)
280//      - enter NEXT STAGE when power is reached...
281//      - maybe enable SPEED REG if not already done?
282        if (curStage == STAGE_RAMPUP) {
283            #ifdef ENABLEDEBUGGING_LCD_SLOW_ANTIBUG
284                TextOut(0, LCD_LINE8, "RAMPUP          ");
285            #endif
286           
287            // do we need rampup at all?
288            if (smoothstart) {
289           
290                rampupLoopCount++;
291                // when rampup is done
292                if (rampupLoopCount >= SMOOTHSTARTSTEPS) {
293                    UpdatePower(port, power);
294                    #ifdef RUNMOTOR2_SYNCMODE
295                        UpdatePower(port2, power);
296                    #endif
297                    if (speedreg) { EnableSpeedRegWhithMotorOn(port); }
298                    curStage = STAGE_DRIVING;
299                } else {
300                    // simple linear interpolation between 0->100
301                    newPower = ((rampupLoopCount * 100)/SMOOTHSTARTSTEPS);
302                    // if power < 100 we might be done sooner:
303                    if (newPower > absPower) {
304                        UpdatePower(port, power);
305                        #ifdef RUNMOTOR2_SYNCMODE
306                            UpdatePower(port2, power);
307                        #endif
308                        if (speedreg) { EnableSpeedRegWhithMotorOn(port); }
309                        curStage = STAGE_DRIVING;
310                    } else {
311                        // here's the actual rampup step!
312                        UpdatePower(port, newPower * powerSgn);
313                        #ifdef RUNMOTOR2_SYNCMODE
314                            UpdatePower(port2, newPower * powerSgn);
315                        #endif
316                    }//end if
317                }//end if
318               
319            } else { // no rampup
320           
321                // full power right away
322                UpdatePower(port, power);
323                #ifdef RUNMOTOR2_SYNCMODE
324                    UpdatePower(port2, power);
325                #endif
326                //there's no speedreg for synced driving...
327                if (speedreg) { EnableSpeedRegWhithMotorOn(port); }
328                curStage = STAGE_DRIVING;
329               
330            }//end if
331
332        }//end if
333       
334//    * if DRIVING STAGE:
335//      - look up current braking distance from current speed
336//      - decide: stage change? time to brake?
337//      - enter braking stage, set braking dist!
338//      - disable speed reg if necessary...
339//      Actually do this during either rampup or driving
340//      (that's the whole idea: braking even if already necessary during rampup)
341
342        //optimized, OLD: if ((curStage == STAGE_DRIVING) || (curStage == STAGE_RAMPUP)) {
343        if (curStage <= STAGE_DRIVING) {
344            #ifdef ENABLEDEBUGGING_LCD_SLOW_ANTIBUG
345                if (curStage == STAGE_DRIVING) {
346                    TextOut(0, LCD_LINE8, "DRIVING        ");
347                }//end if
348            #endif
349
350            // we've got two different Bremsweg-Algos (sync driving needs a bit more way ahead)
351            #ifdef RUNMOTOR2_SYNCMODE
352                absBrakingDist = GetAbsBrakingDistFromAbsSpeed2(abs(curSpeed));
353            #else
354                absBrakingDist = GetAbsBrakingDistFromAbsSpeed(abs(curSpeed));
355            #endif
356               
357               
358            // make the following safe for both power signs!
359            if (powerSgn > 0) {
360                // a little dirty preprocessor hack...
361                #ifdef RUNMOTOR2_SYNCMODE
362                if ((tachoTarget -  MotorTachoCount(port)) <= absBrakingDist || (tachoTarget -  MotorTachoCount(port2)) <= absBrakingDist ) {
363                #else
364                if ((tachoTarget -  MotorTachoCount(port)) <= absBrakingDist ) {
365                #endif
366                    //~~~~~~~~~~~~~~~~~~ same code from here
367                    // ok, we're close enough, start braking!
368                    curStage = STAGE_BRAKING;
369                    // record this for later down (for speed lookup)
370                    brakingStartSpeed = curSpeed;
371                    brakingStartTacho = powerSgn * (tacholimit - absBrakingDist);
372                    // disable SPEED REG if needed
373                    if (speedreg) {
374                        // again no need to care about synced driving
375                        DisableSpeedRegWhithMotorOn(port);
376                    }//end if
377                    //~~~~~~~~~~~~~~~~~~ same code until here
378                }//end if
379            } else {
380                #ifdef RUNMOTOR2_SYNCMODE
381                if ((MotorTachoCount(port) - tachoTarget) <= absBrakingDist || (MotorTachoCount(port2) - tachoTarget) <= absBrakingDist) {
382                #else
383                if ((MotorTachoCount(port) - tachoTarget) <= absBrakingDist ) {
384                #endif
385                    //~~~~~~~~~~~~~~~~~~ same code from here
386                    // ok, we're close enough, start braking!
387                    curStage = STAGE_BRAKING;
388                    // record this for later down (for speed lookup)
389                    brakingStartSpeed = curSpeed;
390                    brakingStartTacho = powerSgn * (tacholimit - absBrakingDist);
391                    // disable SPEED REG if needed
392                    if (speedreg) {
393                        // again no need to care about synced driving
394                        DisableSpeedRegWhithMotorOn(port);
395                    }//end if
396                    //~~~~~~~~~~~~~~~~~~ same code until here
397                }//end if
398            }//end if
399           
400
401
402        }//end if
403       
404//    * if BRAKING STAGE:
405//     ( - check endbraking special mode conditions )
406//     (    . maybe skip PID if time for endgame?   )
407//      - PID control
408//        . calc current error
409//        . calc new setpoint
410//        . use KP and KD constants as MACROS (#define), not VARS!
411//        . clip power and set
412        if (curStage == STAGE_BRAKING) {
413            #ifdef ENABLEDEBUGGING_LCD_SLOW_ANTIBUG
414                TextOut(0, LCD_LINE8, "BRAKING        ");
415            #endif
416
417            #ifdef ENABLEDEBUGGING_REMOTE
418                if(!brakingStartMarkerSent) {
419                    SendMessage(OUTBOX, "1050|0|0");
420                    brakingStartMarkerSent = true;
421                }//end if
422            #endif// - - - - - - - - - -
423
424
425            // TODO maybe replace this variable (dont use it) and do it inline?
426            desiredSpeed = GetIdealSpeedFromPos(abs(MotorTachoCount(port) - brakingStartTacho), brakingStartSpeed, absBrakingDist);
427
428            // shift/calculate all errors for current cycle
429            err_1 = err_0;
430            err_0 = curSpeed - desiredSpeed; //replace desiredSpeed with inline?
431
432
433            // use different KD, KP consts for sync:
434            #ifdef RUNMOTOR2_SYNCMODE
435                // Our PD-Controller is still dependent on turning direction...
436                if (powerSgn > 0) {
437                    curPIDPowerUpscaled = curPIDPowerUpscaled
438                                        + (HARDCODED_KD_SYNC * (err_0 - err_1))
439                                        + (HARDCODED_KP_SYNC * err_1);
440                } else {
441                    curPIDPowerUpscaled = curPIDPowerUpscaled
442                                        - (HARDCODED_KD_SYNC * (err_0 - err_1))
443                                        - (HARDCODED_KP_SYNC * err_1);
444                }//end if
445            #else
446                // Our PD-Controller is still dependent on turning direction...
447                if (powerSgn > 0) {
448                    curPIDPowerUpscaled = curPIDPowerUpscaled
449                                        + (HARDCODED_KD * (err_0 - err_1))
450                                        + (HARDCODED_KP * err_1);
451                } else {
452                    curPIDPowerUpscaled = curPIDPowerUpscaled
453                                        - (HARDCODED_KD * (err_0 - err_1))
454                                        - (HARDCODED_KP * err_1);
455                }//end if
456            #endif
457
458
459            // downscaling
460            newAbsPower = curPIDPowerUpscaled / PIDUPSCALING;
461            // clip these values!
462            if (newAbsPower > maxAbsBrakingPower) {
463                newAbsPower = maxAbsBrakingPower;
464            } else if (newAbsPower < 1) {
465                newAbsPower = 1;
466            }//end if
467           
468            //finally set new power!
469            UpdatePower(port, powerSgn * newAbsPower);
470            #ifdef RUNMOTOR2_SYNCMODE
471                UpdatePower(port2, powerSgn * newAbsPower);
472            #endif
473
474           
475
476            #ifdef ENABLEDEBUGGING_REMOTE
477                tmp1 = NumToStr(err_0);
478                tmp2 = NumToStr(desiredSpeed);
479                tmp3 = NumToStr(curSpeed);
480                tmp = StrCat(tmp1, "|", tmp2, "|", tmp3);
481                SendMessage(OUTBOX, tmp);
482            #endif// - - - - - - - - - -
483           
484        }//end if
485
486//    * WAIT
487//      - burn constant CPU time by waiting for max delay...
488//      - keep on checking tachocount for ENDGAME MODE?
489//      - (MAYBE keep on checking direct command cancellation?)
490
491        waitEndTick = loopStartTick + LOOP_DURATION; //precalc loop-end
492        while (CurrentTick() < waitEndTick) {
493
494            //already there? check for endgame mode
495            if (powerSgn > 0) {
496                // this nice little line also detects if the tachotarget is way
497                // out of reach already (not a nice case though)
498                #ifdef RUNMOTOR2_SYNCMODE
499                if ((tachoTarget - MotorTachoCount(port)) <=  ENDGAMEBRAKINGSTARTDIST || (tachoTarget - MotorTachoCount(port2)) <=  ENDGAMEBRAKINGSTARTDIST) {
500                #else
501                if ((tachoTarget - MotorTachoCount(port)) <=  ENDGAMEBRAKINGSTARTDIST) {
502                #endif
503                    curStage = STAGE_ENDGAME;
504                    #ifdef ENABLEDEBUGGING_ACOUSTIC
505                        PlayTone(1000,100);
506                    #endif
507                    break;
508                }//end if
509            } else {
510                // modified to work for negative stuff...
511                #ifdef RUNMOTOR2_SYNCMODE
512                if ((MotorTachoCount(port) - tachoTarget) <=  ENDGAMEBRAKINGSTARTDIST || (MotorTachoCount(port2) - tachoTarget) <=  ENDGAMEBRAKINGSTARTDIST) {
513                #else
514                if ((MotorTachoCount(port) - tachoTarget) <=  ENDGAMEBRAKINGSTARTDIST) {
515                #endif
516                    curStage = STAGE_ENDGAME;
517                    #ifdef ENABLEDEBUGGING_ACOUSTIC
518                        PlayTone(1000,100);
519                    #endif
520                    break;
521                }//end if
522            }//end if
523           
524            //TODO decide whether we need this?
525            //direct command stopped us?
526            if ( MotorPower(port) == 0 ) {
527                //TODO is this really a clean direct command exit?
528                #ifdef ENABLEDEBUGGING_LCD_SLOW_ANTIBUG
529                    TextOut(0, LCD_LINE8, "ABORTED(wait)        ");
530                #endif
531                return;
532            }//end if
533           
534            #ifdef SLEEP_DURING_WAIT_WHEN_DRIVING
535                if (curStage <= STAGE_DRIVING) {
536                    // free some CPU time...
537                    Wait(1);
538                }//end if
539            #endif
540
541        }//end while (times out when static worst case looptime is over (~10 to 20ms)
542
543//    * if SPECIAL ENDGAME BRAKING
544//      - FAST & SIMPLE INNER LOOP!!!
545//        . check position
546//        . enable HARD BRAKE if necessary, jump out of loop
547        if (curStage == STAGE_ENDGAME) {
548            #ifdef ENABLEDEBUGGING_LCD_SLOW_ANTIBUG
549                TextOut(0, LCD_LINE8, "ENDGAME        ");
550            #endif
551            #ifdef ENABLEDEBUGGING_REMOTE
552                SendMessage(OUTBOX, "-300|0|0");
553            #endif// - - - - - - - - - -
554
555
556            // fast inner loop now!
557            // don't forget TIMEOUT or something, avoid possible lock up,
558            // unfortunately it is possible...
559            waitEndTick = CurrentTick() + ENDGAME_INNERLOOP_TIMEOUT; //precalc loop-end
560            // make two loops to save execution time!
561            if (powerSgn > 0) {
562                while (CurrentTick() < waitEndTick) {
563                    #ifdef RUNMOTOR2_SYNCMODE
564                    if (MotorTachoCount(port) >= tachoTarget || MotorTachoCount(port2) >= tachoTarget) {
565                    #else
566                    if (MotorTachoCount(port) >= tachoTarget) {
567                    #endif
568                        //WE'RE THERE!!!
569                        endgameSuccessful = true;
570                        break;
571                    }//end if
572                    #ifdef ENABLEDEBUGGING_LCD
573                        endgameLoopCount++;
574                    #endif
575                }//end while
576            } else { // negative power sign
577                while (CurrentTick() < waitEndTick) {
578                    #ifdef RUNMOTOR2_SYNCMODE
579                    if (MotorTachoCount(port) <= tachoTarget || MotorTachoCount(port2) <= tachoTarget) {
580                    #else
581                    if (MotorTachoCount(port) <= tachoTarget) {
582                    #endif
583                        //WE'RE THERE!!!
584                        endgameSuccessful = true;
585                        break;
586                    }//end if
587                    #ifdef ENABLEDEBUGGING_LCD
588                        endgameLoopCount++;
589                    #endif
590                }//end while
591            }//end if
592
593            //if succesful or not, BRAKE (before debug)!
594            MotorBrake(port);
595            #ifdef RUNMOTOR2_SYNCMODE
596                MotorBrake(port2);
597            #endif
598
599            //now there's a little time for debug...
600            #ifdef ENABLEDEBUGGING_ACOUSTIC
601                if (!endgameSuccessful) {
602                    PlayTone(4000,100);
603                }//end if
604            #endif
605
606            #ifdef ENABLEDEBUGGING_LCD_SLOW_ANTIBUG
607                if (endgameSuccessful) {
608                    TextOut(0, LCD_LINE8, "ENDGAME SUCCESS    ");
609                } else {
610                    TextOut(0, LCD_LINE8, "ENDGAME TIMEOUT    ");
611                }//end if
612            #endif
613           
614            // and this control process is finally over!
615            break;
616           
617        }//end if (stage ENDGAME)
618
619
620    }//end while
621// --- END MAIN LOOP ---------------------
622
623
624    #ifdef ENABLEDEBUGGING_LCD
625        totalEndTick = CurrentTick();
626        totalControlTime = CurrentTick() - totalStartTick;
627    #endif
628
629// --- seems obsolete: if loop exited manually by direct command, exit void!
630//     (because clean exit and then return should all be above inside loop)
631
632// --- monitor braking (as in old MotorControl)
633//     * release when necessary at full stop
634
635    //TODO what happens if during these final and "save" (esasy) stopping/braking
636    // phase, a new direct command arrives and does weired stuff? it will definitely
637    // mess up our current motor state, maybe that's not too bad...
638
639
640    WaitUntilMotorStopped(port);
641
642
643// --- Motor off / idle, over & out?
644    if (!holdbrake) {
645        MotorOff(port);
646        #ifdef RUNMOTOR2_SYNCMODE
647            MotorOff(port2);
648        #endif
649    }//end if
650
651    // tiny wait for motorstop..., sometimes it really is better...
652    Wait(5);
653   
654    #ifdef ENABLEDEBUGGING_REMOTE
655        SendMessage(OUTBOX, "-480|0|0");
656    #endif// - - - - - - - - - -
657   
658   
659   
660// --- Display Debug Info if necessary
661    #ifdef ENABLEDEBUGGING_LCD
662
663   
664        lcdTmp = NumToStr(loopCount);
665        lcdTmp = StrCat("loops=", lcdTmp);
666        TextOut(0,LCD_LINE1, lcdTmp, true);
667
668        lcdTmp = NumToStr(totalControlTime / loopCount);
669        lcdTmp = StrCat("t/loop=", lcdTmp);
670        TextOut(0,LCD_LINE2, lcdTmp);
671
672        lcdTmp = NumToStr((loopCount * 1000) / totalControlTime);
673        lcdTmp = StrCat("loops/s=", lcdTmp);
674        TextOut(0,LCD_LINE3, lcdTmp);
675
676        lcdTmp = NumToStr(lastLoopTime);
677        lcdTmp = StrCat("lastloop=", lcdTmp);
678        TextOut(0,LCD_LINE4, lcdTmp);
679
680        lcdTmp1 = NumToStr(MotorTachoCount(port));
681        lcdTmp2 = NumToStr(tacholimit);
682        lcdTmp = StrCat("tacho=", lcdTmp1, "(", lcdTmp2, ")");
683        TextOut(0,LCD_LINE5, lcdTmp);
684       
685        // endgame duration & count
686        lcdTmp1 = NumToStr(endgameLoopCount);
687        lcdTmp2 = NumToStr(totalEndTick - (waitEndTick - ENDGAME_INNERLOOP_TIMEOUT));
688        lcdTmp = StrCat("endg=", lcdTmp1, " in ", lcdTmp2, "ms");
689        TextOut(0,LCD_LINE6, lcdTmp);
690
691                #ifdef ENABLEDEBUGGING_WAITAFTERLCD
692                        Wait(5000);
693                //until (ButtonPressed(BTNCENTER, false));
694                #endif
695
696    #endif
697   
698    #ifdef ENABLEDEBUGGING_LCD_SLOW_ANTIBUG
699        TextOut(0, LCD_LINE8, "FINISHED        ");
700    #endif
701
702}//end void
703
704
705// the following function must be an excact copy-paste-replica of the RunMotor
706// function from above, but with the name RunMotor2, the additional param port2,
707// RUNMOTOR2_SYNCMODE defined, and always speedreg=false. It also doesn't need
708// to be inline (to save space)...
709
710
Note: See TracBrowser for help on using the browser.