November 22, 2024, 07:58:57 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.


My elevator simulator

Started by GOT, July 07, 2008, 09:46:04 PM

Previous topic - Next topic

GOT

OK, here is my very first attemp at BASIC STAMP program so don't laugh.  I know it is too long (the nested FOR/NEXT loops can be collapsed into a sub rutine) but left it long for readability.  I now know that the $20 I spent on a servoPal was money well spent (I'm not using it in this program, though. I will rewrite things later once I get a handle on this program).  I do have several questions:
1)  What are the limits for a CON definition?  I have a number larger than 256.  Can it be negative?
2)  Can you use negative numbers in your variables?  Looks from the document you gave me that you can't.
3)  In my Open_Servos_1, I update the servo postion by one click every 40 ms.  Is that too many updates too fast?  Would it be better to update it 2 clicks every 80 ms or 3 clicks every 120 ms?
4)  In my Open_Servos_2, I am approximating a cosine function so that I maintain constant linear motion of the shutters.  I guess I should have used a DATA table for this but I was not sure how to handle the EPROM stuff properly.  Could you help me out here?  Can I store negative numbers in the DATA table?
5)  Here is the stuff you have been warning me about.  I update floor numbers and turn on/off motors in between servo refreshes.  Is this ok (I haven't needed any LED dimming yet in the program) or will there be issues?  Should I decrease the PAUSE time? Ideally, the servos will finish opening the shutters and the motor will immediately start lowering the panel.  Keeping in mind that this is not Disneyland, do I have any hope of success at a relatively quick motor response?

'   {$STAMP BS2}
'   {$PBASIC 2.5}
'
' =========================================================================


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


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


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

Sio                           PIN     15                      ' SETUP = out; no ULN
Trigger                     PIN     14                      ' SETUP = DN


TopMotorR   PIN 10
TopMotorF           PIN  9
SideMotorR   PIN  8
SideMotorF              PIN 7

LedsSide            PIN     6
LedsCenter   PIN     5
LedsOuter        PIN     4

Servos          PIN     3

Latch           PIN     2                       ' latch 74HC595 outputs
Clock           PIN     1                       ' shift clock to 74HC595
Dpin            PIN     0                       ' data pin to 74HC595


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

IsOn            CON     1
IsOff           CON     0

MtrFwd          CON     0
MtrRev          CON     1
ServoOffset   CON   450   ' servo 450 = fully closed, 1000 fully open



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

state           VAR        Byte                    ' program state
timer          VAR        Byte                    ' for input debouncing
level           VAR        Byte                    ' for LED brightness
pos            VAR        Word                 ' servo position, 0 - 550
tick      VAR      Word      'timer
tock      VAR      Byte      'timer


floors          VAR     Word                    ' up to 16 floors


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

Reset:
  OUTS = %0000000000111000                      ' LEDs on
  DIRS = %0000001111111111

  state = 0
  timer = 0

  floors = %0000000000000001                    ' 1st floor indicator on
  GOSUB Update_Floors

  pos = 110                                     ' 20% closed position (inital state)


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

Main:
  PULSOUT Servos, (pos + ServoOffset)                     ' refresh servos
  PAUSE 18

  BRANCH state, [Get_Trigger, Run_Elevator, Reset_Program]
 
  GOTO Main

Get_Trigger:
  timer = timer + 20 * Trigger                  ' scan input
  IF (timer > 100) THEN                       ' wait for valid trigger
    state = 1                                   ' advance state
    timer = 0                                   ' clear for next state
  ENDIF
  GOTO Main

Run_Elevator:
     GOSUB Open_Servos_1
   floors = 2                     'floor indicator to 2
   GOSUB Update_Floors
   PULSOUT Servos, (pos + ServoOffset)              ' refresh servos
     PAUSE 18
   SideMotorF = IsOn            'start side motor down
   
   GOSUB Open_Servos_2

   
   SideMotorF = IsOFF            'cut power to side motor
   TopMotorF = IsOn            'start top motor down

   FOR(tock = 0 TO 150)
      PULSOUT Servos, (pos + ServoOffset)       ' refresh servos for three sec
        PAUSE 18
   NEXT

   floors = 3
   GOSUB Update_Floors         'floor indicator to 3
   TopMotor = IsOFF            'cut power to top motor

   FOR(tock = 0 TO 200)
      PULSOUT Servos, (pos + ServoOffset)       ' refresh servos for 4 sec
        PAUSE 18
   NEXT
   
   TopMotorR = IsOn            'start top motor up
   SideMotorR = IsOn            'start side motor up

   FOR(tock = 0 TO 150)
      PULSOUT Servos, (pos + ServoOffset)       ' refresh servos for three sec
        PAUSE 18
   NEXT

   TopMotor = IsOFF            'cut power to top motor
   GOSUB Close_Servos_1

   floors = 2               'floor indicator to 2
   GOSUB Update_Floors
   GOSUB Close_Servos_2

   floors = 1               'floor indicator to 1
   GOSUB Update_Floors

     state = 2
   GOTO Main



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

' Transfers the contents of 'floors' to 74HC595s
' -- floors 1 to 8 are connected to '595 closest to Prop-2

Update_Floors:
     SHIFTOUT Dpin, Clock, MSBFIRST, [floors.BYTE1, floors.BYTE0]
     PULSOUT Latch, 1
     RETURN


Reset_Program:
   OUTS = %0000000000111000                      ' LEDs on
     DIRS = %0000000000111111

     state = 0
     timer = 0

     floors = %0000000000000001                    ' 1st floor indicator on
     GOSUB Update_Floors

     pos = 110                                     ' closed position
   RETURN

Open_Servos_1:               'open servos to 50% in 7 sec
   
   FOR(tick = 0 TO 330)
      PULSOUT Servos, (pos + ServoOffset)                   ' refresh servos
        PAUSE 18
      IF(tick.BIT0) THEN         'open servo one click every other refresh
         pos = pos + 1
      ENDIF
   NEXT
   RETURN
   

Open_Servos_2:               'open servos to 100% (accelerating )
   
   FOR (tick = 0 TO 7)
      FOR(tock = 0 TO 25)
         PULSOUT Servos, (pos + ServoOffset)                   ' refresh servos
           PAUSE 18
      NEXT
      pos = pos + 9
   NEXT
   
   FOR (tick = 0 TO 5)
      FOR(tock = 0 TO 25)
         PULSOUT Servos, (pos + ServoOffset)                   ' refresh servos
           PAUSE 18
      NEXT
      pos = pos + 10
   NEXT

   FOR (tick = 0 TO 5)
      FOR(tock = 0 TO 25)
         PULSOUT Servos, (pos + ServoOffset)                   ' refresh servos
           PAUSE 18
      NEXT
      pos = pos + 11 + tick
   NEXT

   FOR (tick = 0 TO 3)
      FOR(tock = 0 TO 25)
         PULSOUT Servos, (pos + ServoOffset)                   ' refresh servos
           PAUSE 18
      NEXT
      IF (tick = 0) THEN pos = pos + 19
      ENDIF
      IF (tick = 1) THEN pos = pos + 23
      ENDIF
      IF (tick = 2) THEN pos = pos + 54
      ENDIF
   NEXT
   RETURN



Close_Servos_1:               'close servos to 50% (decelerating )

   FOR (tick = 0 TO 3)
      FOR(tock = 0 TO 25)
         PULSOUT Servos, (pos + ServoOffset)                   ' refresh servos
           PAUSE 18
      NEXT
      IF (tick = 0) THEN pos = pos - 54
      ENDIF
      IF (tick = 1) THEN pos = pos - 23
      ENDIF
      IF (tick = 2) THEN pos = pos - 19
      ENDIF
   NEXT

   FOR (tick = 0 TO 5)
      FOR(tock = 0 TO 25)
         PULSOUT Servos, (pos + ServoOffset)                   ' refresh servos
           PAUSE 18
      NEXT
      pos = pos - 11 - tick
   NEXT

   FOR (tick = 0 TO 5)
      FOR(tock = 0 TO 25)
         PULSOUT Servos, (pos + ServoOffset)                   ' refresh servos
           PAUSE 18
      NEXT
      pos = pos - 10
   NEXT

   FOR (tick = 0 TO 7)
      FOR(tock = 0 TO 25)
         PULSOUT Servos, (pos + ServoOffset)                   ' refresh servos
           PAUSE 18
      NEXT
      pos = pos - 9
   NEXT

   RETURN


Close_Servos_2:               'closes servos to 20% in 7 sec
   
   FOR(tick = 0 TO 330)
      PULSOUT Servos, (pos + ServoOffset)                   ' refresh servos
        PAUSE 18
      IF(tick.BIT0) THEN         'open servo one click every other refresh
         pos = pos - 1
      ENDIF
   NEXT
   RETURN


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




JonnyMac

July 23, 2008, 01:17:38 PM #31 Last Edit: July 23, 2008, 01:19:44 PM by JonnyMac
Quote from: GOT on July 23, 2008, 11:33:40 AM
1)  What are the limits for a CON definition?  I have a number larger than 256.  Can it be negative?

Yes, you can have CON values larger than 256 (max is 65535) and they can be negative (-32768 to 32767).  Keep in mind, however, that the BASIC Stamp uses 16-bit (word) two's-compliment format for negative numbers, so any variable that could be negative must be a word.  Also, the two's-compliment format does not support multiplication of division; addition and subtraction only.


Quote from: GOT on July 23, 2008, 11:33:40 AM
2)  Can you use negative numbers in your variables?  Looks from the document you gave me that you can't.

Yes, but it only works with words.


Quote from: GOT on July 23, 2008, 11:33:40 AM
3)  In my Open_Servos_1, I update the servo position by one click every 40 ms.  Is that too many updates too fast?  Would it be better to update it 2 clicks every 80 ms or 3 clicks every 120 ms?

No, you're fine -- you're not going to overrun the servo.  My friend, Peter (www.socalhalloween.com), built a specialized servo controller that refreshes the servos every 10, even though the frame data stored in the controller is for every 20 ms.  What his controller does is calculate the in-between position for updates between standard frames; he thinks it gives smoother movement.  You can judge for yourself by checking out his animatronic creations (videos online).


Quote from: GOT on July 23, 2008, 11:33:40 AM
4)  In my Open_Servos_2, I am approximating a cosine function so that I maintain constant linear motion of the shutters.  I guess I should have used a DATA table for this but I was not sure how to handle the EPROM stuff properly.  Could you help me out here?  Can I store negative numbers in the DATA table?

Yes, you can store negative numbers in a DATA statement but, again, you must use words and the Word modifier in the data statement.  here's an example table:

Move_Table      DATA    Word 3, Word 2, Word 1
                DATA    Word 0
                DATA    Word -1, Word -2, Word -3


And here's a bit of code to read it:

Main:
  FOR idx = 0 TO 6
    READ Move_Table + (idx * 2), Word direction
    DEBUG "Move ", DEC idx, " = ", SDEC direction, CR
  NEXT


Note the Word modifier used with READ and that the index value is multiplied by two in order to get the correct address of the targe word in the table.


Quote from: GOT on July 23, 2008, 11:33:40 AM
5)  Here is the stuff you have been warning me about.  I update floor numbers and turn on/off motors in between servo refreshes.  Is this ok (I haven't needed any LED dimming yet in the program) or will there be issues?  Should I decrease the PAUSE time? Ideally, the servos will finish opening the shutters and the motor will immediately start lowering the panel.  Keeping in mind that this is not Disneyland, do I have any hope of success at a relatively quick motor response?

To be honest, I think you're just going to have to run the program and fine tune -- there's really no way for me to evaluate operation based just on the source code.  Let me suggest that when you get all your hardware assembled that you start writing mini test programs to check out each section related to hardware.  Yes, it's a little tedious, but in the end will save you loads of trouble-shooting time.


Additional Notes:
-- Your program doesn't compile; you've got parenthesis in FOR-NEXT constructs that don't belong.
-- You need to send a bit image to the '595 for the floors, so floor one is %00000001, 2 is %00000010, etc.

Congrats, though, on jumping and and going for it.  It's painful at first, I know, but in the end you'll be better for the experience, especially since you seem to build some very involved props.

Jon McPhalen
EFX-TEK Hollywood Office

GOT

I have been trying to find something on the proper syntax for the DATA EEPROM thing.  No luck.  I understand what you showed, I just don't know if that is how you are always supposed to handle a data table.  In your documents, you always use bit notation for your data, never use modifiers and don't multiply anything by 2.  If I just want to store some numbers from 1 to 100, what would that look like?

JonnyMac

If you're going to store any number less that 256 (a byte) you can do it with straight data statements like this:

Fibbo           DATA    1, 2, 3, 5, 8, 13, 21, 34

And then you can read the table using the name and an index like this:

  FOR idx = 0 TO 7
    READ Fibbo + idx, offset
    ' do something with offset
  NEXT


Note that for very small tables that are only used once, you can use LOOKUP like this:

  LOOKUP idx, [1, 2, 3, 5, 8, 13, 21, 34], offset
Jon McPhalen
EFX-TEK Hollywood Office

GOT

I am using a Hitec 455BB servo (specs say 4.8V speed is 0.21 sec and 6V speed is 0.16 sec) and in order to match the timing I want, I have started playing with the PAUSE time of the refresh.  If I use a PAUSE of 18ms, my arm completes the swing in about 6 sec (which is what you would expect for a 20ms refresh).  A PAUSE of 12ms takes about 5 sec (not 4) and a PAUSE of 9ms, my arm completes a swing in about 4 sec (not 3 sec).  Since the servo is lagging behind the program, am I going to get in trouble using a 9ms refresh?  Will the program get ahead of itself and do something nasty?  I am looking for generalities here rather than how this applies to my specific program.

FOR pos = 0 TO 300
   PULSOUT Servos, (pos + ServoOffset)                     ' refresh servos
     PAUSE idx
NEXT

JonnyMac

Using 9 ms as your refresh duration won't hurt anything, but as you've discovered, you may need to adjust loop iterations due to the shortened timing.
Jon McPhalen
EFX-TEK Hollywood Office