Shop OBEX P1 Docs P2 Docs Learn Events
Seeking solution to add time counters on IF /THEN or CASE statements — Parallax Forums

Seeking solution to add time counters on IF /THEN or CASE statements

NauketecNauketec Posts: 51
edited 2008-08-28 00:31 in BASIC Stamp
Howdy All,

I have a sonar sensor that returns a measurement called "sonarRange"
It then gets checked against some IF/THEN/ELSE statements to determine what zone the subject is in and direct the program to GOTO a particular "mode".

The measurement·ranges are called:

Max_Range (greater than 20 feet ter)
Mid_Range (equal to or less than 20 feet
Opt_Range (equal to or less than 5 feet)
Min_Range (equal to or less than 4 inches)

The modes are:

mode1· no subject detected - Breathing
mode2· Subject detected - Wake-Up
mode3· Subject in Mid_Range
mode4· Subject in Opt_Range
mode5· Only after subject is in Opt_Range for desired time
mode6· Subject· in Min_Range - too close


The logic is working fine but what is missing is:

·timer/counter

IF·the subject is in the Opt_Range (mode4) for "T2" amount of time·(10 to 30 seconds)THEN GOTO mode5.
IF subject moves forward to range for mode6 or backwards to range for mode3 and then returns to the range for mode4 the program would goto mode4, the timer/counter would reset. It would· GOTO mode5 only after "T2"·amount of time is reached again.

This is my existing code:

IF· sonarRange > Max_range THEN
··· GOTO mode1 'Breathing"
· ELSEIF ((sonarRange =< Max_range)AND( sonarRange >= Opt_Range)AND(Last_Mode =< Current_mode2))THEN
··· GOTO mode2 'wake up
· ELSEIF ((sonarRange =< Max_range)AND( sonarRange >= Opt_Range)AND(Last_Mode > Current_mode2))THEN
··· GOTO mode3 'wake up
· ELSEIF ((sonarRange < Opt_Range)AND( sonarRange >=Min_Range))THEN
··· GOTO mode4· 'opt range
· ELSEIF sonarRange < Min_Range THEN
··· GOTO mode6· 'too close
· ELSE
··· GOTO mode0 'Diagnostics
ENDIF

·GOTO GeTMax_Range


Please use comments so I can understand it clearly.· I am a newbie and under an extreme deadline to get this working.

Thanks

Daniel

Post Edited (Nauketec) : 8/27/2008 4:37:20 PM GMT

Comments

  • ZootZoot Posts: 2,227
    edited 2008-08-27 17:19
    Gotta hop threads here, eh? FYI -- if edit the subject line of your first post in your thread, it will change the "title" of the thread on the forum index.

    In any case, to pick up from http://forums.parallax.com/showthread.php?p=745020, to say "it doesn't work" or it "just gets stuck" doesn't give us much to go on. The example state machine with counters, did you understand it? The pieces? What it is supposed to do or not do? If you understand the basic concept, then tweaking it or tuning it or changing the decision logic shouldn't be too difficult. If the concept is hazy then maybe a different approach is order.

    My suggestion at this point is tradeoff some responsiveness for ease of time programming on your end -- a state machine is nice because it can *keep checking* the sonar ranging, countdown timers, thresholds, whatever, and respond as needed. If you can trade off some of that responsiveness, then I would just put a pause with a do:loop into your actual modes when you want that mode to run for a set period of time. The main program will drop down to that mode, and just stay there till it's done. Changes in the sonar, swtiches, etc, won't be dealt with until the mode is done and control returns back to the main program.

    You could probably do this without a statemachine if your sensor input and outputs were subroutines that could be called from any place in your program at any time, but you declined my suggestion to do so. And at risk of being repetitive, niceties like PIN definitions (names), and the like would make the program much easier to read and to follow. I don't see a current copy of your program in this thread, so I'm just using the snippet you provided. I'm also presuming you are using the sonar averaging? If so then I am estimating that you will get through your main loop no more than 3 or 4 times per second.

    IF  sonarRange > Max_range THEN
        GOTO mode1 'Breathing"
      ELSEIF ((sonarRange =< Max_range)AND( sonarRange >= Opt_Range)AND(Last_Mode =< Current_mode2))THEN
        GOTO mode2 'wake up
      ELSEIF ((sonarRange =< Max_range)AND( sonarRange >= Opt_Range)AND(Last_Mode > Current_mode2))THEN
        GOTO mode3 'wake up
      ELSEIF ((sonarRange < Opt_Range)AND( sonarRange >=Min_Range))THEN
        GOTO mode4  'opt range
      ELSEIF sonarRange < Min_Range THEN
        GOTO mode6  'too close
      ELSE
        GOTO mode0 'Diagnostics
    ENDIF
     
     GOTO GeTMax_Range
    
    '..... just mode4 for an example
    mode4:
      OUTA = 4 ' etc
      PAUSE 20000 ' do it for 20 seconds
      GOTO Main
    
    



    Now if you want the mode to run for a certain time based on sensor input (like mode5, I think, where the person has to be in a certain range for a certain amount of time, aka "hits") then simple state machine I posted in the other thread is about as simple as *I* can make it. You can eliminate all the counters for states that don't need them. A word size counter on "how many times in range" will give you around 15,000 seconds of time (I'm estimating) that you could count. The state machine in my example is your exact same IF/THEN/ELSEIFs but broken into separate statements -- the ELSE/ELSEIF part, i.e., the next state, requires TWO things to happen for it to kick in -- the sonar range needs to be right, as in your code above, AND the counter needs to have gotten to whatever count YOU decide. So if it takes 100 counts of the person in the optimum range before the next one kicks in, and that's about 25 seconds, you're set. But maybe it needs to be a count of 200 or 10. You'll have to test it.


    Think of it like this:

    IF sonarRange < someRange THEN
        counter = counter + 1 MAX 40  ' a way of saying if ( sonarRange< someRange ) AND ( sonarRange < someRange for 10 seconds )
        mode = "A"                                 ' sonar < -- goto mode A
        IF counter >= 40 THEN               ' sonar < - for 10 seconds or so, go to mode b
             mode = "B"
        ENDIF
    ELSEIF sonarRange > someRange THEN  ' but if range goes large
         IF counter3 < 100 THEN                   ' go here for 25 seconds
              mode = "C"
              counter3 = counter3 + 1 MAX 100
          ELSE                                               ' then go here
              mode = "D"
         ENDIF
    ELSEIF
    
    



    Now the example above doesn't show resetting the counters for the "next" time, for clarity (see my earlier longer example). You may like this kind of if/then/else format better, but it's a bit limiting and you can work yourself into a dead end, but hopefully this makes sense.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php


    Post Edited (Zoot) : 8/27/2008 5:29:41 PM GMT
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2008-08-27 17:55
    mode4:
    DO
      pause 100  ' increments of 0.1 second
      ticks = ticks+1   ' counting units of time
      ' get the sonarRange   ' your subroutine needs to be CALLed here
      IF  (sonarRange > Opt_Range) THEN ticks=0 : GOTO mode3  ' reset ticks and fall back
      IF (sonarRange < Min_Range) THEN ticks=0 :  mode6   ' reset ticks and fall up
    LOOP WHILE ticks<dwellTime  ' otherwise stay in this mode until dwelltime, e.g. dwelltime=300 for 30 seconds.
    
    mode5:
      ' do what needs to be done.
      ' will probably have an ongoing range check to drop back to other modes
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • NauketecNauketec Posts: 51
    edited 2008-08-27 18:06
    Hey Zoot

    Thanks for the tip about threads - I just thought that if there were others that wanted to follow a topic, this way they would not have to pour through all the posts about averaging or whatever.

    About the "fat" in my program - my thoughts as a newbie are to write the code and get it to work in a way I can monitor it easily and then at the end when I know it all works, compress it down by removing the all extra lines of code. That is why the debugs were there for so long - How else would I know if it is working? anyway - it is almost complete and now the next task is to create a means that when a subject is in mode4 for an amount of time it will go to mode5 and stay there as long as the subject is in that range. If the subject moves to the range of mode6 or back to mode3 and then re-enters the range for mode4 the timer resets and begins counting again.

    Once this is done then I might be able to breathe better and try to better understand and use the State Engine. But until then unless someone is willing to write all this code for me for free or for fee, I must can only depend on me to get it done and I think is is always wise to go with what you know first. Even if this is "Bit Banging" it gets the job done and gets it done in a way I can understand it and, if need be, fix or change it.

    So I will try your second suggestion first and then report back once I get it to work then we can discuss how to make it more clean.

    Thanks again for all your help it has been a real learning by fire experiance!

    Daniel
  • ZootZoot Posts: 2,227
    edited 2008-08-27 18:14
    Tracy's code is very similar to what I did, only with his particular clarity smile.gif I've been trying to help and failing miserably smile.gif but one extra comment to Dr. Allen's snippet:

    mode5:
      ' do what needs to be done.
      ' will probably have an ongoing range check to drop back to other modes
      ' without your ranging, sendmode, etc. in a *subroutine* this is not easy... this is what 
     ' I was alluding to above. If the sendmode (OUTA to the slave Stamp) and ranging are
     ' in a sub, you can always "get" the current range whenever/wherever you want in your
    ' program so it makes sense to you. Ditto with sending the mode to the slave.
    
    mode5:
      ' do what needs to be done.
      ' will probably have an ongoing range check to drop back to other modes
       OUTA = 5  ' send mode to slave
       GOSUB get_range  ' get range here without having to go back to main program
       IF sonarRange < someRange THEN  mode5 ' or whatever the decision is -- just stay here till the range goes where you want
       GOTO Main
    
    ' subroutine
    get_range:
       ' SRF10 i2c ranging and/or averaging here
       RETURN
    
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • NauketecNauketec Posts: 51
    edited 2008-08-27 18:28
    Zoot,

    You have been a great asset so please continue!

    Daniel
  • ZootZoot Posts: 2,227
    edited 2008-08-27 19:08
    I don't see an attachment.

    But, I have a suggestion -- put away your main and slave program for an afternoon.

    Make a simple if/then/else tree with counters as has been outlined, but instead of any sonar or switch INPUT use DEBUGIN. Instead of any output, use DEBUG. You won't need any pins, any routines, only a few variables. Try out some routines and watch what happens on screen... enter your "input" on each loop and watch what happens. Experiment. Get the code working then break it. Then revisit your main program with fresh eyes.

    ' {$STAMP BS2p}
    ' {$PBASIC 2.5}
    
    cntr0 VAR BYTE
    cntr1 VAR BYTE
    cntr2 VAR BYTE
    sensor VAR BYTE ' from DEBUGIN -- see the Pbasic Manual
    mode VAR BYTE ' the "output" and current state
    
    Reset:
      DEBUG CLS, "Starting... welcome, Nauketec"
      PAUSE 5000
      DEBUG CLS
    
    Main:
       DEBUG HOME,
             "Top of Loop", CR
       DEBUG "mode:   ", DEC3 mode, CR
       DEBUG "sensor: ", DEC3 sensor, CR
       DEBUG "cntr0:  ", DEC3 cntr0, CR
       DEBUG "cntr1:  ", DEC3 cntr1, CR
       DEBUG "cntr2:  ", DEC3 cntr2, CR
    
    Sensor_Input:
       GOSUB get_range  ' now value is in "sensor"
    
    Decisions_Decisions:
       IF sensor < 128 THEN
           mode = 1
           cntr0 = cntr0 + 1 MAX 255 ' prevent it "rolling over" to zero
           IF cntr0 >= 10 THEN   ' 10x it was less than 128
                mode = 2           ' go to mode 2 for 25 counts
                cntr2 = cntr2 + 1 MAX 255
                IF cntr2 >= 25 THEN
                     cntr2 = 0  ' clear it for next time
                     mode = 1   ' back to mode 1
                ENDIF
           ENDIF
        ELSEIF sensor >= 128 THEN
            cntr0 = 0  ' clear it for next  time it drops below 128
            cntr1 = cntr1 + 1 ' but even if sensor >= 128, we won't change mode till 10 counts pass OR the sensor suddely drops!!!!
            GOSUB get_range
            IF cntr1 >= 10 OR sensor < 32 THEN
                mode = 0   ' go to mode 0
                cntr1 = 0   ' clear for next time
            ENDIF
        ENDIF
    
        GOTO Main
    
    Subroutines_Here:
       get_range:
        DEBUG "Reading sensor: input value 0 - 255:"
        DEBUGIN DEC sensor
        DEBUG CR
        RETURN
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • ZootZoot Posts: 2,227
    edited 2008-08-27 21:06
    See my post above. Try experimenting and watching the input/output of my little debug demo. I think once you find the concept clear, you'll find it's not very difficult to plug the concept into your own code.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • ZootZoot Posts: 2,227
    edited 2008-08-27 22:40
    If it works it's perfect! Nobody sees the code, only the final result, y'know?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • NauketecNauketec Posts: 51
    edited 2008-08-28 00:31
    Hey Zoot and Tracy
    I got it all to work now I am just doing a little burn-in test to see if there are bugs.

    I only have one more small task on the LED micro and the program is DONE!

    Thanks

    Daniel
Sign In or Register to comment.