November 21, 2024, 08:37:44 AM

News:

Got VSA?  Want to use your Prop-SX?  Now you can!  See the VSA section of the Library forum for Prop-SX code that works with VSA.


Help, first program

Started by youngti, October 04, 2008, 05:52:49 PM

Previous topic - Next topic

youngti

Okay, now being new at this I might be bitting off more that I can chew.

Here is what I'm trying to do, I have a Grim reaper with a 3 axis skull attached.  It will have two PIR's one on the right and one on the left.  When the right PIR is triggered I want the Nod Srvo to look up and Swivel Servo to move to the right, then have the CAP-200 start playing.  Then when the left PIR is tiriggered the  Nod Srvo to look up and Swivel Servo to move to the left and the CAP will play.  The script loads so I know I don't have any syntax error, but nothing is happening.  Thank you for any help.

Here is my script;

Using a Prop1, ST-200, and CAP-200.

'
'   File...... Reaper
'   Purpose...
'   Author.... Tim Young
'   E-mail....
'   Started... 10/04/08
'   Updated...
'
'   {$STAMP BS1}
'   {$PBASIC 1.0}
'
' =========================================================================


' -----[ Program Description ]---------------------------------------------
   'Program will accept INPUT from right PIR, turn head AND THEN start CAP.
    'THEN on left PIR activation, turn head left AND start CAP.

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


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

SYMBOL     Trigger1     =PIN7                  ' SETUP = DN
SYMBOL     Trigger2     =PIN6                  ' SETUP = DN
SYMBOL     CapAudio     =PIN3                  ' white->OUT3, black->GND
SYMBOL     TiltServo    =PIN2
SYMBOL     NodServo     =PIN1
SYMBOL     SwivelServo  =PIN0

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

SYMBOL  IsOn            = 1
SYMBOL  IsOff           = 0
SYMBOL  AudioOn         = 1
SYMBOL  AudioOff        = 0

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

SYMBOL  pirTimer1        = B2                    ' for debouncing PIR
SYMBOL  pirTimer2        = B3                    ' for debouncing PIR


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

Reset:
  PINS = %00000000
  DIRS = %01111111                              ' set outputs

  PAUSE 30000                                   ' let PIR warm-up


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

Main:
  pirTimer1 = 0
  pirTimer2 = 0

PIR1_Wait:
  PAUSE 10
  pirTimer1 = pirTimer1 + 10 * Trigger1                ' update timer
  IF pirTimer1 < 250 THEN Main

  IF Trigger1 = IsOn THEN Servo1

Servo1:
PULSOUT NodServo, 150                            ' Center the servo
PULSOUT SwivelServo, 250                            ' Move the servo Right

GOSUB CAP_Start
  PAUSE 2000                                    ' adjust for sound

PIR2_Wait:
  PAUSE 10
  pirTimer2 = pirTimer2 + 10 * Trigger2                ' update timer
  IF pirTimer2 < 250 THEN Main

  IF Trigger2 = IsOn THEN Servo2

Servo2:
PULSOUT NodServo, 150                            ' Center the servo
PULSOUT SwivelServo, 10                            ' Move the servo Left

GOSUB CAP_Start
  PAUSE 2000                                    ' adjust for sound

GOTO Main


' -----[ Subroutines ]-----------------------------------------------------
CAP_Start:
  CapAudio = AudioOn                               ' pull OUTx low
  PAUSE 250                                     ' hold for CAP debounce
  CapAudio = AudioOff                              ' release OUTx
  RETURN
' -------------------------------------------------------------------------


' -----[ EEPROM Data ]-----------------------------------------------------

JonnyMac

October 04, 2008, 07:28:40 PM #1 Last Edit: October 04, 2008, 07:31:04 PM by JonnyMac
Uh, yeah... servos are not easy.  I can't remember how many posts where I've reminder our friends that servos must be updated 50 times per second.  Period.  Failing to do so, especially when the servos have a load applied, means that they will misbehave.  The challenge for us, then, is how to construct a program that can monitor inputs while constantly refreshing the servos.  This is called a state-machine and, thankfully, PBASIC has been designed to support his kind of programming.  If you search the forums you'll find several S/M-type programs I've done for others.

This may be tricky to understand at first -- take your time and try to understand it before making any modifications.  Note that you'll have to edit in your actual servo position values for the wait state and the two sides -- I used 150 (center) for everything just to get the program in place.

' =========================================================================
'
'   File...... Reaper.BS1
'   Purpose...
'   Author.... Jon Williams, EFX-TEK
'              Copyright (c) 2008 EFX-TEK
'              Some Rights Reserved
'              -- see http://creativecommons.org/licenses/by/3.0/
'   E-mail.... jwilliams@efx-tek.com
'   Started...
'   Updated... 04 OCT 2008
'
'   {$STAMP BS1}
'   {$PBASIC 1.0}
'
' =========================================================================


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


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


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

SYMBOL  Trigger1        = PIN7                  ' SETUP = DN
SYMBOL  Trigger2        = PIN6                  ' SETUP = DN
SYMBOL  CapAudio        = PIN3                  ' white->OUT3, black->GND
SYMBOL  Tilt            = 2
SYMBOL  Swivel          = 1
SYMBOL  Nod             = 0

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

SYMBOL  IsOn            = 1                     ' for active-high in/out
SYMBOL  IsOff           = 0

SYMBOL  Baud            = OT2400


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

SYMBOL  state           = B0                    ' program state
SYMBOL  show            = B1                    ' left or right
SYMBOL  pirTime1        = B2                    ' debounce for left PIR
SYMBOL  pirTime2        = B3                    ' debounce for right PIR
SYMBOL  nodPos          = B4                    ' servo position
SYMBOL  swivelPos       = B5
SYMBOL  tiltPos         = B6

SYMBOL  timer           = W5                    ' show timer


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

Reset:
  PINS = %00000000                              ' clear everything
  DIRS = %00001111                              ' set outputs

  nodPos = 150
  swivelPos = 150
  tiltPos = 150

  state = 0
  timer = 1500                                  ' warm-up delay


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

Main:
  PULSOUT Nod, nodPos
  PULSOUT Swivel, swivelPos
  PULSOUT Tilt, tiltPos                         ' not used?
  PAUSE 15                                      ' pad for ~20 ms

  IF timer = 0 THEN Run_State                   ' skip if expired
    timer = timer - 1                           '  update timer


Run_State:
  BRANCH state, (Warm_Up, Check_PIRs, Start_Audio, Run_Left, Run_Right)
  state = 0


Warm_Up:
  IF timer > 0 THEN Main
    pirTime1 = 0
    pirTime2 = 0
    state = 1

    GOTO Main


Check_PIRs:
  pirTime1 = pirTime1 + 20 * Trigger1
  pirTime2 = pirTime2 + 20 * Trigger2

Check_1:                                        ' check left PIR
  IF pirTime1 < 100 THEN Check_2
    state = 2
    show = 3                                    ' save side to run
    CapAudio = IsOn
    timer = 13                                  ' 13 x 20ms = 260ms
    GOTO Main

Check_2:                                        ' check right PIR
  IF pirTime1 < 100 THEN Main
    state = 2
    show = 4
    CapAudio = IsOn
    timer = 13
    GOTO Main


Start_Audio:
  IF timer > 0 THEN Main                        ' let audio pulse finish
    CapAudio = IsOff                            ' turn it off
    state = show                                ' point to show
    timer = 2000 / 20                           ' adjust for sound length
    GOTO Main


Run_Left:
  nodPos = 150                                  ' update head pos
  swivelPos = 150
  tiltPos = 150
  IF timer > 0 THEN Main                        ' let audio finish
    GOTO Reset


Run_Right:
  nodPos = 150
  swivelPos = 150
  tiltPos = 150
  IF timer > 0 THEN Main
    GOTO Reset


' -----[ Subroutines ]-----------------------------------------------------


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


' -----[ User Data ]-------------------------------------------------------
Jon McPhalen
EFX-TEK Hollywood Office

youngti

All I have to say is WOW!  That's a lot more than I expected, thank you.  I was totaly off on most of my code.  I now that you have said that a how to is on your list of to do things, but is there a book that deals with PBASIC?

JonnyMac

Keep in mind that I have a head start on you; I started programming at 17 (I'm now 46) and I was one of the first adopters of the BS1 (core of the Prop-1) when it came out 14 years ago.  Also, I write programs every day, whether I need them or not -- this is how I stay sharp and develop new tricks.  I also do programming on advanced processors like the SX and sometimes apply what I learn there to the Prop-1 (your program is an example of that).

I'm one that would rather do something right than quickly so I don't think my book will be ready until next Spring.  Still, there's no reason to wait on me as there are a ton of resources you could turn to.  Now, some of the code you'll find isn't as clean or organized as mine, but it works and you can learn something.

* PBASIC Help file
* BS1 Application Notes: http://www.parallax.com/Portals/0/Downloads/appnt/stamps/bs1Appnotes.pdf
* Nuts & Volts articles: http://www.efx-tek.com/php/smf/index.php?topic=595.0

The key is not to wait until you have an absolute need; program all the time if you want to get good at it.  Go through these forums and solve problems for others -- that's how I got really good at the BS1 way back in the pre-Internet days when Parallax had a BBS where BS1 users could post questions and answers; I downloaded the questions and uploaded the answers.  Solving problems for others is a great way to improve your skills.
Jon McPhalen
EFX-TEK Hollywood Office

youngti

Thank you again for all the suggestions.

I'm posting the code agian as I modified it to get the look left, look right how I wanted.  But I have a couple of questions.  I put the audio in a sub, because I wanted the head to stay in the position during the full play.  That works, but I may hve broken somthing else.  Now only trigger1 is kicking in the head move and audio.  And then neither trigger will kick in.  Also can you tell me what value I need to change to shorten the trigger wait for another activation?  The audio bits only run about 30 to 60 seconds and I wan a new mone playing a little quicker.  I have read you need to be carfule because you may get false triggers, but I want to get it as close as possible.

I am very thankful for all you have helped me with.  My wife, kids and the neightborhood are all excited.


                    ' =========================================================================
'
'   File...... Reaper.BS1
'   Purpose...
'   Author.... Jon Williams, EFX-TEK
'              Copyright (c) 2008 EFX-TEK
'              Some Rights Reserved
'              -- see http://creativecommons.org/licenses/by/3.0/
'   E-mail.... jwilliams@efx-tek.com
'   Started...
'   Updated... 04 OCT 2008
'
'   {$STAMP BS1}
'   {$PBASIC 1.0}
'
' =========================================================================


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


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


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

SYMBOL  Trigger1        = PIN7                  ' SETUP = DN
SYMBOL  Trigger2        = PIN6                  ' SETUP = DN
SYMBOL  CapAudio        = PIN3                  ' white->OUT3, black->GND
SYMBOL  Tilt            = 2
SYMBOL  Swivel          = 1
SYMBOL  Nod             = 0

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

SYMBOL  IsOn            = 1                     ' for active-high in/out
SYMBOL  IsOff           = 0

SYMBOL  Baud            = OT2400


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

SYMBOL  state           = B0                    ' program state
SYMBOL  show            = B1                    ' left or right
SYMBOL  pirTime1        = B2                    ' debounce for left PIR
SYMBOL  pirTime2        = B3                    ' debounce for right PIR
SYMBOL  nodPos          = B4                    ' servo position
SYMBOL  swivelPos       = B5
SYMBOL  tiltPos         = B6

SYMBOL  timer           = W5                    ' show timer


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

Reset:
  PINS = %00000000                              ' clear everything
  DIRS = %00001111                              ' set outputs

  nodPos = 190
  swivelPos = 150
  tiltPos = 150

  state = 0
  timer = 1500                                  ' warm-up delay


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

Main:
  PULSOUT Nod, nodPos
  PULSOUT Swivel, swivelPos
  PULSOUT Tilt, tiltPos                         ' not used?
  PAUSE 15                                      ' pad for ~20 ms

  IF timer = 0 THEN Run_State                   ' skip if expired
    timer = timer - 1                           '  update timer


Run_State:
  BRANCH state, (Warm_Up, Check_PIRs, Start_Audio, Run_Left, Run_Right)
  state = 0


Warm_Up:
  IF timer > 0 THEN Main
    pirTime1 = 0
    pirTime2 = 0
    state = 1

    GOTO Main


Check_PIRs:
  pirTime1 = pirTime1 + 20 * Trigger1
  pirTime2 = pirTime2 + 20 * Trigger2

Check_1:                                        ' check left PIR
  IF pirTime1 < 100 THEN Check_2
    state = 2
    show = 3                                    ' save side to run
    CapAudio = IsOn
    timer = 13                                  ' 13 x 20ms = 260ms
    GOTO Main

Check_2:                                        ' check right PIR
  IF pirTime1 < 100 THEN Main
    state = 2
    show = 4
    CapAudio = IsOn
    timer = 13
    GOTO Main

Run_Left:
  nodPos = 190                                  ' update head pos
  swivelPos = -5
  tiltPos = 150
  GOSUB Start_Audio
  IF timer > 0 THEN Main                        ' let audio finish
    GOTO Reset


Run_Right:
  nodPos = 180
  swivelPos = 300
  tiltPos = 150
  GOSUB Start_Audio
  IF timer > 0 THEN Main
    GOTO Reset


' -----[ Subroutines ]-----------------------------------------------------
Start_Audio:
  IF timer > 0 THEN Main                        ' let audio pulse finish
    CapAudio = IsOff                            ' turn it off
    state = show                                ' point to show
    timer = 2000 / 20                           ' adjust for sound length
RETURN

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


' -----[ User Data ]-------------------------------------------------------

JonnyMac

Okay, if you're going to change my programs without understanding them then you're gonna make me mad... and we all know what happens when I get mad.  ;D 

Click on this link if you don't know.
-- http://www.jonmcphalen.com/common/graphics/jon_mcphalen_02.jpg

State machine programs are a different ball of wax; subroutines are not needed because each state is being handled when it should, and starting the audio player is one of the states.  After the audio start pulse is terminated the timer is setup for the length of play -- you never told me how long that is (details like this are important....) so I used the 2000 milliseconds that you had.  It's in this section:

Start_Audio:
  IF timer > 0 THEN Main                        ' let audio pulse finish
    CapAudio = IsOff                            ' turn it off
    state = show                                ' point to show
    timer = 2000 / 20                           ' adjust for sound length
    GOTO Main


Change the red number to the length (in milliseconds) of your sound.

The delay between shows is handled by this line in the Reset section:

  timer = 1500                                  ' warm-up delay

You said you wanted 30 seconds; 1500 units x 20 milliseconds = 30 seconds.  Take your new delay (in milliseconds) and divide it by 20; it might be easier to write the line like I did in the audio section above.  Let's say you want to drop it down to 10 seconds -- do it like this:

  timer = 10000 / 20                            ' warm-up delay

In case you're wondering, yes, this program needs to be written the way it is because of the requirement for servos to be constantly refreshed.  Interesting that the advent of servo controllers (started by Scott Edwards) followed quickly on the heels of the BASIC Stamp processor -- the idea was to take the burden of constant refreshing off the Stamp and onto the slave controller.
Jon McPhalen
EFX-TEK Hollywood Office

youngti

Once again I thank you, you are the master.  Yes I've seen what happens when you get mad.  Don't want to do that.  I understand what the values do now.

JonnyMac

Thanks for understanding -- that's a fairly sophisticated program for a Prop-1 and I'd like to know that it works as designed.  Let us know.
Jon McPhalen
EFX-TEK Hollywood Office

youngti

Wow, it's doing just what I wanted.  Adjusting the timing does the trick.  Currently I have it down to 5 secs and on the longer audio, the head will swivel to left, then right when PIR is activated.

Thank you so much, I'm going to play around with the timing.

youngti