' © Wolfstone, 2005 ' ========================================================================= ' ' File....... BeastOperation.bs1 ' Purpose.... Animate the Crate Beast ' Author..... Dennis Griesser ' E-mail..... wolfstone@pobox.com ' ' {$STAMP BS1} ' {$PBASIC 1.0} ' ' ========================================================================= ' -----[ Program Description ]--------------------------------------------- ' ' Control program for the Crate Beast Halloween prop. ' ' For information about the I/O, peripheral boards, etc, please see ' BeastControllerSetup.txt ' ' -----[ Revision History ]------------------------------------------------ ' ' BeastOperation_01.bs1 - 24 October 2005 ' BeastOperation_02.bs1 - 29 October 2005 ' BeastOperation_03.bs1 - ' BeastOperation_04.bs1 - 14 October 2007 - First version practical to use. ' Supports triggered beast and lid. ' BeastOperation_05.bs1 - 16 October 2007 - Add sound and autonomous mode. ' BeastOperation_06.bs1 - 16 October 2007 - Version for code review. ' -----[ I/O Definitions ]------------------------------------------------- SYMBOL TrigBeast = PIN7 ' input trigger on P7 SYMBOL TrigLid = PIN6 ' input trigger on P6 SYMBOL RedLED = PIN5 ' output debug feedback on P5 SYMBOL GreenLED = PIN4 ' output debug feedback on P4 SYMBOL Fog = PIN3 ' output "shoot fog" on P3 SYMBOL Sio = 0 ' serial I/O on P0 ' -----[ Constants ]------------------------------------------------------- ' Communication with other boards: ' DC-16 Digital Control Board ' AP-8 Audio Player SYMBOL Baud = OT2400 ' serial rate to talk to everybody SYMBOL AddrDC16 = %00 ' address of DC-16 board (%00 - %11) SYMBOL AddrAP8 = %00 ' address of AP-8 board (%00 - %11) ' Solenoids: SYMBOL DoorOpen = 1 ' Open Door SYMBOL DoorClose = 2 ' Close Door SYMBOL ArmOpen = 3 ' Open Arm SYMBOL ArmClose = 4 ' Close Arm SYMBOL BeastOpen = 13 ' Open Beast SYMBOL BeastClose = 14 ' Close Beast SYMBOL LidOpen = 15 ' Open Lid SYMBOL LidClose = 16 ' Close Lid SYMBOL IsOff = 0 SYMBOL IsOn = 1 ' -----[ Variables ]------------------------------------------------------- SYMBOL RndNum = W0 ' 16-bit random number (and seed for next one) SYMBOL Solenoid = W1 SYMBOL Delay = W2 SYMBOL AutoCount = W3 SYMBOL Cycles = B8 SYMBOL WantedBits = B9 ' Using GOSUB on the BS1 requires variables B12 and B13 (W6) ' -----[ EEPROM Data ]----------------------------------------------------- ' -----[ Initialization ]-------------------------------------------------- Reset: ' 76543210 ' bit positions DIRS = %00111111 ' make P7-P6 inputs, P5-P0 outputs PINS = %00000000 ' all outputs off ' Clear the digital output board. SEROUT Sio, Baud, ("!DC16", AddrDC16, "X") ' turn off all solenoids ' Reset all solenoids to Normally Closed position. ' We have to do this because the solenoids are bistable. Solenoid = BeastClose ' close beast GOSUB PulseSolenoid Solenoid = ArmClose ' close arm GOSUB PulseSolenoid Solenoid = LidClose ' close lid GOSUB PulseSolenoid Solenoid = DoorClose ' close door GOSUB PulseSolenoid ' -----[ Program Code ]---------------------------------------------------- ' Come here after a performance is complete. ' This code also works to prepare for the very first performance. ' DonePerforming: 'DEBUG "DonePerforming", CR ' Wait until input trigger is gone, in case the performance was shorter than the trigger. AwaitNoTrigger: IF TrigBeast = IsOn THEN AwaitNoTrigger 'IF TrigLid = IsOn THEN AwaitNoTrigger ' Re-seed autonomous mode. ' With current main code ' count of 1000 ~= 5 seconds ' count of 12000 ~= 1 minute ' max count ~= 5 minutes AutoCount = RndNum ' The main loop primarily sits and spins until it sees an incoming command. ' The exception is autonomous mode. ' MainLoop: 'DEBUG "MainLoop", CR ' If there is a trigger for beast attack, do that performance. IF TrigBeast = IsOn THEN DoBeast ' If there is a trigger for banging the lid, do that performance. IF TrigLid = IsOn THEN DoLid ' ----- ' Nothing specifically requested! ' ----- ' Spend spare time randomizing. GOSUB TumbleRandom ' ----- ' This section controls autonomous mode. ' Do something interesting occasionally, even if nothing specifically requested. ' ' WARNING - Only do things that are safe in case somebody is standing nearby. ' ----- AutoCount = AutoCount -1 IF AutoCount > 0 THEN MainLoop ' Autonomous mode triggered - do something interesting! ' ' RndNum should contain plenty of entropy. ' 76543210 ' bit positions ' %00000011 ' use these bits for random sound selection (if we decide to make sound) ' %00000100 ' depending on this bit, make a (random) sound ' %00001000 ' depending on this bit, make some motion ' With this arrangement, autonomous mode should average: ' 25% of the time - just make a (random) sound ' 25% of the time - just bang the lid ' 25% of the time - bang the lid and make a (random) sound ' 25% of the time - do nothing ' Maybe make some sound - 50/50 chance. WantedBits = RndNum & %00000100 IF WantedBits = 0 THEN SkipSound WantedBits = RndNum & %00000011 SEROUT Sio, Baud, ("!AP8", AddrAP8, "P", WantedBits) ' play random sound, one of 0-3 SkipSound: ' Maybe make some fog - 50/50 chance. WantedBits = RndNum & %00010000 IF WantedBits = 0 THEN SkipFog ' Fog = IsOn PAUSE 1000 ' shoot fog for 1.0 second ' Fog = IsOff SkipFog: ' Maybe make some motion - 50/50 chance. WantedBits = RndNum & %00001000 IF WantedBits = 0 THEN DoLid ' DoLid won't come back here! It will GOTO DonePerforming ' Done with autonomous performance. GOTO DonePerforming ' ----- ' This routine controls the whole "Show The Beast" function. ' ' WARNING - Beast attack slams the doors open and pops the beast. You don't ' want this happening when somebody is bending down to look at the doors! ' Never run beast attack in autonomous mode! ' ' Ideally, this would be a subroutine, but the PROP-1 is too limited. ' When this routine is done, it will unconditionally GOTO DonePerforming. ' ----- DoBeast: 'DEBUG "DoBeast", CR ' Start the sound SEROUT Sio, Baud, ("!AP8", AddrAP8, "P", 4) ' play sound 4 = beast attack ' Open doors Solenoid = DoorOpen GOSUB PulseSolenoid PAUSE 100 ' wait .1 second for doors to open ' Show Beast Solenoid = BeastOpen GOSUB PulseSolenoid PAUSE 3000 ' wait 3.0 second for Beast to deploy and scare! ' Hide Beast Solenoid = BeastClose GOSUB PulseSolenoid PAUSE 500 ' wait .5 second for Beast to withdraw ' Close doors Solenoid = DoorClose GOSUB PulseSolenoid GOTO DonePerforming ' ----- ' This section controls the whole "Bang The Lid" function. ' ' Ideally, this would be a subroutine, but the PROP-1 is too limited. ' When this routine is done, it will unconditionally GOTO DonePerforming. ' ----- DoLid: 'DEBUG "DoLid", CR GOSUB TumbleRandom ' Expression evaluation strictly left-to-right! ' Cycles = RndNum & 7 ' range 0-7 ' Cycles = Cycles + 2 ' range 2-9 Cycles = RndNum & 7 + 2 ' range 2-9 'DEBUG Cycles FOR Cycles = Cycles TO 1 STEP -1 ' Bang the lid up and down, once. ' Each bang is exactly the same as the other bangs. ' Open lid Solenoid = LidOpen GOSUB PulseSolenoid 'PAUSE 100 ' Close lid Solenoid = LidClose GOSUB PulseSolenoid 'PAUSE 300 ' Pause between bangs for small random time GOSUB TumbleRandom ' Expression evaluation strictly left-to-right! ' Delay = RndNum & 15 ' range 0-15 ' Delay = Delay + 3 ' range 3-18 ' Delay = Delay * 10 ' range 30-180 Delay = RndNum & 15 + 3 * 10 ' range 30-180 'DEBUG Delay PAUSE Delay NEXT ' end of loop FOR Cycles GOTO DonePerforming END ' -----[ Subroutines ]----------------------------------------------------- ' Using GOSUB on the BS1 requires variables B12 and B13 (W6), making those ' variables unavailable for general program use. ' Fire one solenoid _coil_ and return it to rest state. ' ' Since the valves are bistable, it is a good idea to remove ' power after every operation is complete. Also, some air flows ' as long as the coil is energized, so we want to minimize that. ' ' Removing power does not change the position of the pneumatic ' valve! It just saves some power, saves air, and precludes ' accidently energizing both the NC and NO solenoids. ' PulseSolenoid: ' Fire the solenoid that we want. SEROUT Sio, Baud, ("!DC16", AddrDC16, "P", Solenoid, IsOn) ' turn on ' Wait for the solenoid/valve to switch. ' According to our experiments (backed by the LTV data sheet), ' it takes up to 30 mSec for the valve to switch. PAUSE 100 ' wait .10 second for valve to respond 'PAUSE 30 ' wait .03 second for valve to respond ' The valve has switched. Remove the solenoid power. SEROUT Sio, Baud, ("!DC16", AddrDC16, "P", Solenoid, IsOff) ' turn off ' After sending a command, we must wait a little while for the parallel ' board to finish executing before we send another command. PAUSE 5 ' wait .005 second for parallel board RETURN ' Tumble random generator ' ' Each call to RANDOM generates 1 bit of entropy, with the previous ' 15 bits shifted to the left. This subroutine calls RANDOM several ' times in order to get more entropy. ' TumbleRandom: RANDOM RndNum RANDOM RndNum RANDOM RndNum RANDOM RndNum RANDOM RndNum RETURN