PDA

View Full Version : Seeking solution to add time counters on IF /THEN or CASE statements



Nauketec
08-27-2008, 10:49 AM
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

Zoot
08-28-2008, 12:19 AM
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 (http://1uffakind.com/robots/povBitMapBuilder.php)
1uffakind.com/robots/resistorLadder.php (http://1uffakind.com/robots/resistorLadder.php)

Post Edited (Zoot) : 8/27/2008 5:29:41 PM GMT

Tracy Allen
08-28-2008, 12:55 AM
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 (http://www.emesystems.com)

Nauketec
08-28-2008, 01:06 AM
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

Zoot
08-28-2008, 01:14 AM
Tracy's code is very similar to what I did, only with his particular clarity http://forums.parallax.com/images/smilies/smile.gif I've been trying to help and failing miserably http://forums.parallax.com/images/smilies/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 (http://1uffakind.com/robots/povBitMapBuilder.php)
1uffakind.com/robots/resistorLadder.php (http://1uffakind.com/robots/resistorLadder.php)

Nauketec
08-28-2008, 01:28 AM
Zoot,

You have been a great asset so please continue!

Daniel

Zoot
08-28-2008, 02:08 AM
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 (http://1uffakind.com/robots/povBitMapBuilder.php)
1uffakind.com/robots/resistorLadder.php (http://1uffakind.com/robots/resistorLadder.php)

Zoot
08-28-2008, 04:06 AM
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 (http://1uffakind.com/robots/povBitMapBuilder.php)
1uffakind.com/robots/resistorLadder.php (http://1uffakind.com/robots/resistorLadder.php)

Zoot
08-28-2008, 05:40 AM
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 (http://1uffakind.com/robots/povBitMapBuilder.php)
1uffakind.com/robots/resistorLadder.php (http://1uffakind.com/robots/resistorLadder.php)

Nauketec
08-28-2008, 07:31 AM
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