May 18, 2024, 03:11:15 AM

News:

You can now use Vixen to program your Prop-1 and Prop-2 controllers!  Get started quickly and easily, without having to learn PBASIC.  Details in the Library forum.


Converting Haunted House Prop-1 Program to HC-8

Started by Spooky Dad, June 17, 2011, 08:18:35 PM

Previous topic - Next topic

Spooky Dad

June 17, 2011, 08:18:35 PM Last Edit: June 22, 2011, 09:47:24 PM by Spooky Dad
    JonnyMac

    I've attached the Prop - 1 program that presently executes with a Prop-1 Controller, a DC-16, an AP-8 and a RC-4.  The design goals I am looking to accomplish with the upgrade are listed below.  I could really use one more input.  Did you say the AP-16 had one that could be programmed?  What other input do you need from me?


    • Replace the Prop-1 with the HC-8 as the main controller
    • Have two different program modes - Spooky (Input 0 shows closed loop) and Non-Spooky (Input 0 shows open loop)
    • Have each prop activate indepently (get away from the serial nature of the existing program)
    • Create a random time-out variable for each prop so that it can not be re-triggered for 10 to 20 seconds
    • While the program is waiting for an input, randomly play the sound on the AP-8 in slot 0 (scream).  There is no longer an input dedicated to Entrance since each prop will be tripping independently


  • Input 0 for telling HC-8+ whether the tour should be Spooky or Non-Spooky
  • Input 1 for Prop 1 - MIB (resuse random code)
  • Input 2 for Prop 2 - Cook Pot Trauma (CPT)
  • Input 3 for Prop 3 - Door Prop from Hi-Rez Design
  • Input 4 for Prop 4 - Ghost
  • Input 5 for Prop 5 - Owl
  • Input 6 for Prop 6 - Air Cannon
  • Input 7 for Prop 7 - Snakes (Ankle Tickler)
[/list]

JonnyMac

The HC-8+ has eight TTL inputs that you can use as triggers, plus a dedicated SIO pin for communicating with your AP-8, RC-4, and DC-16 -- I think you're good as far as IO is concerned (as you have one more than you have with the Prop-1).

Keep in mind that you live with your program code and understand it intimately, I don't.  Kind of like with my acting work: when the day's shoot is done I forget the lines -- don't need them any more.  So... you may want to go into more detail than you're presently providings, especially since the HC-8+ will provide for more sophistication. 

And as you won't have an HC-8+ in hand for a while, we can move slowly and use this as a way of learning a bit about programming the Propeller.  Let me suggest you start by downloading the HC-8+ template (in this sub-forum) and checking that you can load it into the Propeller Tool software.

Then:
-- detail the behavior of each prop section
-- explain how to deal with multiple simultaneous inputs (how to handle priority)
Jon McPhalen
EFX-TEK Hollywood Office

Spooky Dad

Perfect on the approach.  The eighth input (not originall listed, but I updated the original post) was for whether or not the Spooky or Non-Spooky Program should be running.  I plan on accomplishing this by using a simple toggle switch on the outside of the haunt so that it turns on some "chicken" lights and puts the props into "display" mode only.  So I will need to detail how each prop works in Spooky and Non-Spooky Mode. 

So same question?  How do I get more inputs?  When will the HC-8+ (am I gonna get to be a beta tester) and break beams be available for purchase? 

bsnut

As Jon point out the HC-8+ has eight TTL inputs that can be use as triggers, plus a dedicated SIO pin for communicating with your AP-8, RC-4, and DC-16. You are showing 9 inputs. 

The only way you can get this input "Spooky or Non-Spooky" is to have extra HC-8+ talking via RS485 to the other HC-8+ for controlling your extra features such as the "Spooky or Non-Spooky" switch. If you don't want to get the extra HC-8+, there is DMX freeware software that you can get, which can be use for "Spooky or Non-Spooky" feature, plus you get extra features that you wasn't planning on.
William Stefan
The Basic Stamp Nut

JonnyMac

Technically, there are four more pins that could be used as inputs: the configuration switch has four pulled-up pins that go directly to the processor (unbuffered, so you have to be careful).  There is ground on the option header, so you can easily use one of those pins to select spooky/non-spooky, while having eight trigger inputs plus the dedicated SIO pin.
Jon McPhalen
EFX-TEK Hollywood Office

Spooky Dad

Excellent.  Let's plan on that.  I will be getting to finishing the template by Wednesday night.  The day job keeps calling and calling.  (Thanks for the response, too, bsnut).

Spooky Dad

JonnyMac - I was able to read the template file in the Propeller Software (finally got it installed on my machine) and I have updated it with the details of operation for each of the props, including Inputs (INx), Outputs (Outx), RC-4 relays (RC-4.0 through RC-4.3) and AP-8 sounds (AP-8.0 through AP-8.7). 

JonnyMac

Let's start with serial communications as that's where there is a big difference between PBASIC and Spin.  In PBASIC, we insert SEROUT statements inline as we need them.  Easy.  The problem is that our program is stuck until the command has been sent.  SERIN is worse: if we aren't sitting on SERIN when a byte arrives, we miss it.

Not the case with Spin. One of the standard objects is called FullDuplexSerial (FDS) and provides for buffered serial IO -- bytes can even be sent and received at the same time, and they're buffered so we don't have to wait to TX to finish, and we don't miss bytes coming in, even when we're busy.

There is already one instance of FDS installed and we'll use this for debugging later.  For communicating with the attached devices we will install another.  Here's another difference: with FDS we start it (so that it can be run in the "background") and that assignment includes the pins used, as well as the baud rate.  This means we can't change FDS willy-nilly like we can SERIN/SEROUT.  Small price to pay.

Start by adding a second FDS object to the project, in the OBJ section -- like this:

obj

 term : "fullduplexserial"                                     ' debug serial
 com1 : "fullduplexserial"                                     ' EFX device serial


Here's another cool thing with Spin: You don't use up any extra memory by adding the second copy of FDS.  This is a little tricky to explain, but the memory management allows only one cog (processor) to access memory at a time.  This means that the same FDS code can be used for both objects.  To be clear, each object does get its own set of variables, but this is a very minor amount of memory.

Now we have to start the object so that it is compatible with EFX-TEK coms.  Add this line to the initialization section in the main method.

 com1.start(SIO, SIO, %1100, 38_400)                           ' start EFX serial

As you can see, this is using the same pin for RX and for TX.  The third parameter controls the behavior of this copy of FDS and sets it to us "open true" type comms, and it ignores anything being TX'd so that its own RX buffer doesn't get filled with what we're sending.  Note that I've set the baud to 38.4 as this will also minimize the time to send a command to a device.

And now to talk to the devices.  I've created three methods that you can use in this project and reuse later.  The only dependency is having an FDS object called com1 instantiated.  Note that we have to build commands with individual sections.  Again, this is a very small price to pay for the features we gain from FDS and using the Propeller.

pub set_rc4(addr, relays)

'' Update RC-4 at 'addr' with bits in 'relays'
'' -- replaces: SEROUT Sio, Baud, ("!RC4", addr, "S", relays)

 com1.str(string("!RC4"))                                      ' header
 com1.tx(addr)                                                 ' address
 com1.tx("S")                                                  ' set command
 com1.tx(relays & $F)                                          ' relay bits


pub set_dc16(addr, outs)

'' Update DC-16 at 'addr' with bits in 'outs'
'' -- replaces: SEROUT Sio, Baud, ("!DC16", addr, "S", outsLo, outsHi)

 com1.str(string("!DC16"))                                     ' header
 com1.tx(addr)                                                 ' address
 com1.tx("S")                                                  ' set command
 com1.tx(outs.byte[0])                                         ' low byte
 com1.tx(outs.byte[1])                                         ' high byte

 
pub play_ap8(addr, seg)

'' Plays segment on attached AP-8
'' -- replaces: SEROUT Sio, Baud, ("!AP8", %00, "P", sfx)  

 com1.str(string("!AP8"))                                      ' header
 com1.tx(addr)                                                 ' address
 com1.tx("P")                                                  ' set command
 com1.tx(seg & %111)                                           ' segment


Jon McPhalen
EFX-TEK Hollywood Office

JonnyMac

I'm sure that someone is wondering why we don't do this:

 com1.str(string("!AP8", addr, "P", seg))

And yes, this is legal code.

Here's why: Spin uses the z-string format which means that a string is terminated with zero.  If either addr or seg where 0 then the command would truncated and not properly transmitted.  For safety, then -- in all applications -- we build the command manually using the .str and .tx methods of FDS.
Jon McPhalen
EFX-TEK Hollywood Office

Spooky Dad

OK.  I'll get on the additions to the code and will repost once I complete this learning assigment.  I do already see how you are establishing the communications and initial program building blocks (modules) to be reused over and over.  I would imagine that the another module to be created (for reuse) is the Random time-out to keep props from retripping.  In retrospect, I also assume that we will be using the HC-8+ for inputs and the DC-16 for all outputs until more are needed.

JonnyMac

June 23, 2011, 05:41:28 PM #10 Last Edit: June 23, 2011, 05:43:57 PM by JonnyMac
One of the great things about Spin is that you can create a loop that runs the same amount of time, no matter what happens within it (conditionals, etc.); the only rule is that the loop timing MUST be longer than the longest possible path through the loop.  For these kinds of programs it's no big deal as Spin runs about 50x faster than PBASIC2, which is about 5x faster than PBASIC1 (general rule, speed varies command by command).

What this means is that we can manage timer variables quite easily without consuming a cog to do it.  This is the generic structure of the main method:

pub main | t

 ' setup hardware and any objects used

 t := cnt                                                      ' create sync point
 repeat

   ' code here repeats every 100ms

   ' update timers

   timer1 := (timer1 - 1) #> 0                                 ' update, limit to 0
   timer2 := (timer2 - 1) #> 0
 
   waitcnt(t += constant(100 * MS_001))                        ' let 100ms timer expire


The waitcnt method waits for the system counter (cnt) to reach a specific value; this loop causes that target to be bumped by 100ms each timer through.  This is really powerful.  If we allow the timers to have a 0.1s resolution, it's easy to manage them as shown in the code above which decrements the timer, limiting the low value to 0 (remember, in Spin we have signed numbers).
Jon McPhalen
EFX-TEK Hollywood Office

Spooky Dad

OK, I have updated and uploaded the new program file, including the pub main | t method, too.  What's next?

bsnut

One of the next things you need to do, is to do the code for the inputs "Spooky not Spooky" and the other triggers to trigger your props. You can also create methods for each of the props that you have.
William Stefan
The Basic Stamp Nut

Spooky Dad

Got it!  I'll be taking a stab at the prop sections (methods) this weekend.  No clue on how to program pulling one of the pins on the controller switch (tied directly to the processor) down (or how to hook up to it).  I would appreciate a little help here.

JonnyMac

On the HC-8+ option header there are two GND pins.  You would simply connect a normally-open button between on of the (four) lines into the processor and ground.  When the button is open you would read "1" due to the pull-up; when the button is pressed the Propeller will read "0".

You can read all four like this:

 cfgPins := ~ina[OPT_BR..OPT_SM] & %1111

The tilde inverts the bits so that 1 becomes 0 and vice-versa, and the last section removes all the other bits from the result.  What you get is a 4-bit value that corresponds to the button state on each input (i.e., "1" = pressed).
Jon McPhalen
EFX-TEK Hollywood Office