November 23, 2024, 08:44:49 PM

News:

Be sure to checkout our Vixen interfaces in the Library forum -- if you want PC automation at near zero cost, EFX-TEK and Vixen is a great combination of tools.


Running a program for a specific amount of time

Started by JackMan, October 07, 2010, 05:12:26 PM

Previous topic - Next topic

JackMan

Is there a way to have this stop after at least 10 minutes has passed? It doesn't need to stop right at the 10 minute mark, it can wait until it gets to "GOTO Main" if 10 minutes has elapsed at that point.

' {$STAMP BS1}
' {$PBASIC 1.0}


'-----[ Constants ]-------------------------------------------------------

SYMBOL  Servo1           = 0                    ' turn


' -----[ Variables ]-------------------------------------------------------

SYMBOL  pos1            = B2                    ' servo 1 position
SYMBOL  idx             = B3                    ' loop controller
SYMBOL  seconds         = B4                    ' for delays
SYMBOL  throttle        = B5                    ' controls speed
SYMBOL  lottery         = W5                    ' random number


' -----[ Initialization ]--------------------------------------------------

Reset:
  LOW Servo1                                    ' setup servo
  lottery = 1031                                ' Seed the random number
  PAUSE 30000

' -----[ Program Code ]----------------------------------------------------

Main:
  FOR pos1 = 150 TO 190 STEP 2                   ' turn to left
    GOSUB Servo_Speed
  NEXT

  RANDOM lottery
  seconds =  lottery // 20 + 1                   ' hold 1 to 20s
  GOSUB Servo_Pause

  FOR pos1 = 190 TO 110 STEP -2                  ' turn to right
    GOSUB Servo_Speed
  NEXT

  RANDOM lottery
  seconds =  lottery // 20 + 1                   ' hold 1 to 20s
  GOSUB Servo_Pause

  FOR pos1 = 110 TO 150 STEP 2                   ' back to center
    GOSUB Servo_Speed
  NEXT

  RANDOM lottery
  seconds =  lottery // 20 + 1                   ' hold 1 to 20s
  GOSUB Servo_Pause

  FOR pos1 = 150 TO 110 STEP -2                  ' turn to right
    GOSUB Servo_Speed
  NEXT

  RANDOM lottery
  seconds =  lottery // 20 + 1                   ' hold 1 to 20s
  GOSUB Servo_Pause


  FOR pos1 = 110 TO 150 STEP 2                   ' back to center
    GOSUB Servo_Speed
  NEXT

  RANDOM lottery
  seconds =  lottery // 40 + 20                  ' hold 20 to 60s
  GOSUB Servo_Pause

  GOTO Main


' -------------------------------------------------------------------------

' refresh servos
' -- randomizes 'throttle' to control speed

Servo_Speed:
  RANDOM lottery                                ' re-stir random #
  throttle = lottery // 5 + 1                   ' throttle is 1 to 5

  FOR idx = 1 TO throttle                       ' control servo speed
    PULSOUT Servo1, pos1
    PAUSE 17
  NEXT
  RETURN

' -------------------------------------------------------------------------

' pause for n seconds while refreshing servos

Servo_Pause:
  IF seconds = 0 THEN SP_Exit                   ' done?
    FOR idx = 1 TO 50                           ' create 1s delay
      PULSOUT Servo1, pos1                      '   while refreshing servos
      PAUSE 17
    NEXT
    seconds = seconds - 1
    GOTO Servo_Pause

SP_Exit:
  RETURN

JonnyMac

Not easily.  You would need a Wx variable to count your milliseconds (every time you insert a PAUSE) and when that hits 60000 (one minute) you would clear it and add one to a Bx variable keeping track of minutes.

The Prop-1 is a great little controller but, as we all do, it has its limits.
Jon McPhalen
EFX-TEK Hollywood Office

bsnut

October 08, 2010, 10:37:45 AM #2 Last Edit: October 08, 2010, 04:40:28 PM by bsnut
Jack,
I have your program on my laptop and need to know if want the whole servo code to run before timing out. I think, I can make it work out.
William Stefan
The Basic Stamp Nut

JackMan

Thanks, but its no big deal. I just added a loop so it goes thru the sequence 5 times and that gets me close enough.

JonnyMac

That's about all you can do with the Prop-1.

<teaser> If you port this program to an HC-8ss (the "hackable" replacement of the DC-16) then you can use one of the free cogs (processors) to run a precise timer to do exactly what you want.  You can use another processor to take care of the servos without having to do the refreshing in your main code.  You'll get exactly what you want (behavior) with easier-to-manage code.</teaser>
Jon McPhalen
EFX-TEK Hollywood Office

bsnut

Jack,

I worked with your program and this is what I came up with. As Jon was saying, there is no easy way to do it. I had to slow down your program with PAUSE 850, which accounts for BS1 overhead. Give a wing ding and tell me what you think :)
' {$STAMP BS1}
' {$PBASIC 1.0}


'-----[ Constants ]-------------------------------------------------------

SYMBOL  Servo1           = 0                    ' turn


' -----[ Variables ]-------------------------------------------------------

SYMBOL  pos1            = B2                    ' servo 1 position
SYMBOL  idx             = B3                    ' loop controller
SYMBOL  seconds         = B4                    ' for delays
SYMBOL  throttle        = B5                    ' controls speed
SYMBOL  runsecs         = W4                    ' elapsed timer
SYMBOL  lottery         = W5                    ' random number


' -----[ Initialization ]--------------------------------------------------

Reset:
  LOW Servo1                                    ' setup servo
  lottery = 1031                                ' Seed the random number
  runsecs = 0                                   ' elapsed timer set for 10 mins
  PAUSE 30000

' -----[ Program Code ]----------------------------------------------------

Main:
  FOR pos1 = 150 TO 190 STEP 2                   ' turn to left
    GOSUB Servo_Speed
  NEXT
  GOSUB Elapsed_Timer

  RANDOM lottery
  seconds =  lottery // 20 + 1                   ' hold 1 to 20s
  GOSUB Servo_Pause

  FOR pos1 = 190 TO 110 STEP -2                  ' turn to right
    GOSUB Servo_Speed
  NEXT
  GOSUB Elapsed_Timer

  RANDOM lottery
  seconds =  lottery // 20 + 1                   ' hold 1 to 20s
  GOSUB Servo_Pause

  FOR pos1 = 110 TO 150 STEP 2                   ' back to center
    GOSUB Servo_Speed
  NEXT
  GOSUB Elapsed_Timer

  RANDOM lottery
  seconds =  lottery // 20 + 1                   ' hold 1 to 20s
  GOSUB Servo_Pause

  FOR pos1 = 150 TO 110 STEP -2                  ' turn to right
    GOSUB Servo_Speed
  NEXT
  GOSUB Elapsed_Timer

  RANDOM lottery
  seconds =  lottery // 20 + 1                   ' hold 1 to 20s
  GOSUB Servo_Pause

  FOR pos1 = 110 TO 150 STEP 2                   ' back to center
    GOSUB Servo_Speed
  NEXT
  gosub Elapsed_Timer

  RANDOM lottery
  seconds =  lottery // 40 + 20                  ' hold 20 to 60s
  GOSUB Servo_Pause

  IF runsecs >= 600 THEN End_Show

  GOTO Main

End_Show:
  END

' -------------------------------------------------------------------------

' refresh servos
' -- randomizes 'throttle' to control speed

Servo_Speed:
  RANDOM lottery                                ' re-stir random #
  throttle = lottery // 5 + 1                   ' throttle is 1 to 5

  FOR idx = 1 TO throttle                       ' control servo speed
    PULSOUT Servo1, pos1
    PAUSE 17
  NEXT
  RETURN

' -------------------------------------------------------------------------

' pause for n seconds while refreshing servos

Servo_Pause:
  IF seconds = 0 THEN SP_Exit                   ' done?
    FOR idx = 1 TO 50                           ' create 1s delay
      PULSOUT Servo1, pos1                      '   while refreshing servos
      PAUSE 17
    NEXT
    seconds = seconds - 1
    runsecs = runsecs + 1                       ' count up elapsed timer
    GOTO Servo_Pause

SP_Exit:
  RETURN

Elapsed_Timer:
  PAUSE 850
  runsecs = runsecs + 1
  return
William Stefan
The Basic Stamp Nut

BigRez

October 09, 2010, 02:30:46 AM #6 Last Edit: October 09, 2010, 03:48:49 PM by BigRez
Bill -  
There is a little "twitch" at the end of each movement in your program, I think caused by the PAUSE 850 command.  The servo isn't being refreshed during this 850ms pause either so not sure if that's a concern for Jack's needs.  I ran your version a few times and it's currently running about 12 - 13 minutes.

Here's another version I came up with.  This one uses less than 50% of the memory (I'm always stretching the prop-1 limits so this is important to me) and it allows you to easily add additional movements in the EEPROM area if needed. I've run it several times and it seems very close - always stopping right about at 10 minutes.  (There's a VARIANCE constant which defines how close to 10 minutes we need to be.)  Give it a try...


' =========================================================================
'   File......
'   Purpose...
'   Author....
'   E-mail....
'   Started...
'   Updated...
'
'   {$STAMP BS1}
'   {$PBASIC 1.0}
' =========================================================================

' -----[ Program Description ]---------------------------------------------


' -----[ Revision History ]------------------------------------------------


' -----[ I/O Definitions ]-------------------------------------------------


' -----[ I/O Definitions ]-------------------------------------------------

SYMBOL  Servo1          = 0                    ' turn

' -----[ Constants ]-------------------------------------------------------
'=================== CONFIGURABLE VALUES BELOW ============================
SYMBOL  MAXSPEED        = 5             ' max loop speed value (throttle)
SYMBOL  MAXHOLD         = 20            ' Max seconds to hold between moves steps
SYMBOL  STEPSPEED       = 2             ' servo movement steps (1-x; larger makes movement more choppy)
SYMBOL  TIMEVARIANCE    = 8000          ' Quit if new cycle starts within x cs of MAXRUNTIME
SYMBOL  MAXRUNTIME      = 60000         ' Max Runtime in cs (will quit near this value; max 65535)
                                       ' If you need more than 65535, consider adding an iteration
                                       ' counter so that you can do x iterations of 65535cs each


' -----[ Variables ]-------------------------------------------------------
SYMBOL  posTo           = B3                    ' servo position to move TO
SYMBOL  svoPos          = B4                    ' servo position in loops
SYMBOL  idx             = B5                    ' loop controller
SYMBOL  looper          = B6                    ' controls speed / loops
SYMBOL  ptr             = B7                    ' EEPROM Pointer
SYMBOL  cSecLeft        = W4                    ' elapsed timer in centiseconds (ms Left)
SYMBOL  lottery         = W5                    ' random number


' -----[ Initialization ]--------------------------------------------------

Reset:
 LOW Servo1                                    ' setup servo
 lottery = 1031                                ' Seed the random number
 cSecLeft = MAXRUNTIME                         ' elapsed timer set to MAXRUNTIME (miliseconds)
 PAUSE 30000                                    ' 30 second startup pause?

' -----[ Program Code ]----------------------------------------------------
' assumes we do a full set of cycles (left, right, center, right, center) before
' checking if we're at MAXRUNTIME yet.
Main:
 ptr = 0                                       ' reset EEPROM location
 svoPos = 150                                  ' Set initial "FROM" location

 ' If we're within a few seconds of MAXRUNTIME, then go ahead and quit
 IF cSecLeft < TIMEVARIANCE THEN End_Show     ' <--- adjust this if needed


Do_Next:
 READ ptr, posTO                               ' get position to go "TO"  (already have FROM)
 IF posTO = 0 THEN Main                        ' completed cycle?  reset values and do more if true

Turn_Loop:
 IF svoPos = posTO THEN Turn_End               ' If we've hit the target, we're done turning
 GOSUB Move_Servo                              ' move the servo

 IF posTO > svoPos THEN Increment              ' determine increment or decrement
 svoPos = svoPos - STEPSPEED MIN posTO         ' negative direction; decrement
 GOTO Turn_Loop
Increment:
 svoPos = svoPos + STEPSPEED MAX posTO         ' positive direction; increment
 GOTO Turn_Loop                                ' go back and loop again

Turn_End:
 GOSUB Servo_Pause                             ' perform a random length pause before next move
 ptr = ptr + 1                                 ' increment EEPROM pointer (for next read)
 GOTO Do_Next                                  ' then we'll go back and get the next "FROM"

End_Show:
 END


' -------------------------------------------------------------------------
' moves the servos
' -- randomizes 'looper' (throttle) to control speed.
Move_Servo:
 RANDOM lottery                                ' re-stir random #
 looper = lottery // MAXSPEED + 1              ' looper is 1 to MAXSPEED
 FOR idx = 1 TO looper                         ' control servo movement "speed" by looping
    GOSUB Pulse_Servo                          ' pulse servo and calc timing
 NEXT
 RETURN


' -------------------------------------------------------------------------
' pause for 1-20 seconds while also refreshing servos
Servo_Pause:
 looper =  lottery // MAXHOLD + 1            ' hold 1 to MAXHOLD seconds
SP_Loop:
 FOR idx = 1 TO 50                           ' create approx 1s delay (50 * 19ms)
    GOSUB Pulse_Servo                        ' pulse servo and calc timing
 NEXT
 looper = looper - 1                         ' subtract a second (minimum was 1)
 IF looper > 0 THEN SP_Loop                  ' keep looping if not done
 RETURN


' -------------------------------------------------------------------------
' Pulses servo, decrements timer value, stirs randomizer
Pulse_Servo:
  RANDOM lottery                               ' re-stir random #
  PULSOUT Servo1, svoPos                       ' refresh servo
  PAUSE 17                                     ' 17ms pause (total routine about 20ms)
  cSecLeft = cSecLeft - 2 MIN 1                ' about 2cs (20ms) each time this is done (includes overhead)
  RETURN


' Values are the servo positions used in the loops.  The servo ALWAYS starts at 150.
' These values then are listed as the TO positions, which become the next FROM
' position.  So, the FROM and TO pairs are:
'    150 & 190,  190 & 110,  110 & 150,  150 & 110, 110 & 150
' Zero indicates end of a set.  Each set should always end at 150.
Show_Data:
 EEPROM (190, 110, 150, 110, 150, 0)

'Code Last edited at 10/9/10 14:46


Jon - I just read up a little on the propeller chip which is what I believe you said is in the HC-8ss. Wow!  I hope someday I'll be creative enough to be able to use even half of that capability.

JackMan

Great job Mike, that works pretty well. Can I just change the value of MAXRUNTIME to adjust the total time?

Bill,
  Your program worked although as Mike pointed out it caused a slight twitch in the servo at the end of each movement.

  Thanks for the input guys. I've been doing pretty well at my own programming but some of these tricks are way out of my league.  :o

JonnyMac

Sorry to rain on the parade, but this is a problem

SYMBOL  MAXRUNTIME      = 600000

The maximum value in the BASIC Stamp 1 -- variable or constant -- is 65535.

Jon McPhalen
EFX-TEK Hollywood Office

JackMan

You know, I saw that too but I downloaded the program and tested it. It ran very close to 10 minutes and then stopped.  ???

bsnut

Good work Mike and you found the other way skin the cat. The program that is.

Jack,
You may want to remove the PAUSE 850 and the GOSUB Elapsed_Time from the program and see if this takes care of the problem and still maintains the 10 min that you want.

I was debating myself on this one. I didn't think it will cause the servo to twitch.

When Jack or someone else puts another servo program, I guess I need to break out the servo that I have.
William Stefan
The Basic Stamp Nut

BigRez

Dang it!  Thanks Jon.

It's just by chance that it stopped at about 10 minutes.  I'll bet if you changed it to 15, 20 or some other number of minutes it could be way off.  (I added a DEBUG line to show that value and sure enough, it isn't what was expected.)

I knew there was something amiss... ;D  So, an easy fix to the program is to change from ms timing to cs timing.  (600000 becomes 60000, 8000 becomes 800, and then only subtract 2 from the timer.) Done that and running a few tests, but gotta run to coach a game... Post the revised code later.

BigRez

Code above was corrected to work with cs rather than ms timing.  This means the timing is a little less fine but still gets the job done.  Also allows you to specify a larger "step" value (currently set a 2) whereas before it wouldn't work correctly.  Still only uses about 50% of the memory.

JackMan

How do you change ms to cs in a program? I know it has something to do with the timing assigned to a Wx variable but I'm not sure how the change is accomplished.

BigRez

The programming isn't changing how the prop-1 functions, only how it loosly keeps track of "elapsed time."

We know that 1000ms = 100cs = 1 second.  So the variable which holds the amount of time left to run (cSecLeft) counts cs rather than ms. 

This variable is decremented when the servo is pulsed. Since we are figuring about 20ms each time it did that, we'll subtract 2cs (20ms) from the counter.