Jump to content
mpymike

MPY Halloween Ghost Project

Recommended Posts

MPY Halloween Ghost Project
 
This project is a scary ghost for halloween. It is setup in the front garden to scare away the hordes of trick-or-treaters.
When a passing trick-or-treater approaches the ghost will scream and move back and forth along side the garden path.
 
It uses two MSP430s, One for the Ghost to detect passing trick-or-treaters and a second MSP430 to pull the Ghost on a loop of string. See it in action in the video.
 
 


 
 
The Ghost
 
The msp430 in the ghost is mounted onto a breadboard with a battery pack stuck to the back.
An HC-SR04 ultrasonic detector is used to detect objects between 5-8 feet away. The sound comes from a 1.5" 100 ohm speaker from pololu.com and a random flashing high intensity LED are used to frighten away anyone who approaches too close.
 
I used a low cost 433MHz RF TX module from elecrow.com to send a signal to the pully motor controller. This worked very well it had plenty of range once I added a 12" length of wire as an antenna.
 
post-3-0-37873600-1382978131_thumb.jpg
 
The circuit is pretty simple. I used a 4.5v battery pack and a diode to drop the supply for the MSP430 to a safer level. The TX module and the ultrasonic detector needed the higher supply voltage.  I found the HC-SR04 ultrasonic detector to be quite difficult to use. It had a lot of dead positions where it would not detect reliably, (could probably be caused by multipath reflections giving false echos). I had to
make the code detect echos that were within a narrow range.
The speaker is driven directly from the MSP430 timer output. Frequency being controlled by the timer period and the volume controlled by the pulse width. 
 

post-16401-0-94589300-1382996531_thumb.png

 
The circuit is mounted onto a breadboard. The ultrasonic module was a bit floppy and needs to be held in place firmly as the whole thing gets shaken around quite a bit. it isn't very permanent, but hopefully I will still be able to use it next halloween.
 

post-16401-0-01783400-1382996552_thumb.png
 
The program is written in MPY (a simplified variant of Python), and the syntax should be easy enough to understand.


######################################################################
#
# ghost_screamer.mpy  
# 
# ~~~~  Scary Halloween Ghost  ~~~~ 
# Uses an Ultrasonic Detector on P1_5/P1_4 to detect 
# presence of passing trick-or-treaters. When detected
# it flashes LED (P1_0) randomly, makes a whooooh sound and
# sends a pulse to the Tx module
# The ultrasonic detector produces a variable width
# pulse (ECHO on P1_5) whose pulse width is proportional
# to the distance. Pulses that are too long or to short
# are ignored as these a false triggers. This was done
# as the ultrasonic detector HC-SR04 is prone to produce 
# rogue pulses.  
# ( Mike Asker 18-Sep-2013 www.mpyprojects.com)
# 
######################################################################

TRIG = P1_4
ECHO = P1_5
TX   = P1_3
SPKR = P1_6
LED  = P1_0
 
######################################################################
def timer():
    '''Define a timer function. This will be run every 6ms as a watchdog timer interrupt
    This will handle any things we want to do in the background.
    Like sending TX data and flashing the LED'''
    
    global tcount
    global r
    tcount += 1
    
    # Toggle the data signal to the TX module 
    # (I think it needs to be kept modulated for the RX receiver to work.
    # Change the TX pulse form 1ms to 2ms if we want to send a '1' (this is a very 
    # low rate signal!) This is being done once every timer tick (6ms)
    out(TX,1)
    if enable_tx > 0:
        wait(2)
    else:
        wait(1)
    out(TX,0)
    
    # Flash the LED
    if tcount % 10 == 0:
        tcount = 0
        # If the volume is turned on, (ie we have detection)
        # flash the Led in a random manner
        r = random(r)
        if r > 10000 and volume > 0:
            out(LED,1)
        else:
            out(LED,0)
            

    
####################################################################
# Main program starts here
####################################################################

# Setup the pin directions
pindir(LED,OUT)     
pindir(SPKR,PULSEOUT)
pindir(TRIG,OUT)
pindir(ECHO,IN)
pindir(TX,OUT)

volume = 10
tone = 900
tcount = 0
volume_inc = 1
tone_inc   = 5


interrupt_setup( WATCHDOG_TIMER, WDT_ADLY_1_9, timer)  # setup an interval timer 6ms
eint()                                                 # start the interupt timer running
pulse_enable(0)                                        # enable the timer0 used for the speaker

# Enter a continuous loop
while 1:
    
        # Output a trigger pulse to start the ultrasonic detector
        out(TRIG,1)
        wait_cycles(50)
        out(TRIG,0)

        # Wait a millisecond before we start to look for the echo
        # this gives enough time for the ECHO signal to go high
        # at the start of the pulse        
        wait(1)
        ecount=0
        echo = 0
        
        # While the ECHO signal is high loop round once every 10us
        # and increment ecount. Break out of the loop when echo
        # goes low, the value of ecount will be the pulse width
        # (units of 10us) 
        while ecount < 200:
            if echo == 0 and inp(ECHO) == 0:
                echo = ecount
            ecount += 1
            wait_cycles(10)

        # If the width is within the narrow range of 400us - 600us
        # then we have detected a trick-or-treater        
        if echo > 40 and echo < 60:
            
            # Send a '1' to the RF module
            enable_tx = 1
            
            # Make a whoooh sound!
            tone = 900              # Set an initial tone frequency value
            tone_inc   = 10         # Start with an initial +ve tone increment
            for i in range(5):      # Repeat the whoooh 5 times
                for j in range(20):
                    # Increment the tone frequency to make the spooky whooo sound
                    # but only within narrow limits. When it hits a limit change
                    # the direction of the increment, so the tone will go up and then
                    # down
                    tone += tone_inc              
                    if tone > 1100 or tone < 800:  # if the tone hits the limits invert the increment   
                        tone_inc = -tone_inc
                    volume = tone/2          # Set max volume to max by making the width half the period
                    pulse_period(0,tone)
                    pulse_width(0,volume)
                    wait(50)                 # update the tone once every 50ms
                enable_tx = 0                
                # Switch off the TX module after the first whooo
                # because we need to give only a short pulse to the RX module
                # otherwise it will keep running  

        #switch off the speaker after we are finished with the whooo by setting the volume value to 0
        volume = 0
        pulse_width(0,volume)
        wait(100) 
        
       
            
    

 
The Pully Motor Controller
 
This is mounted onto a piece of hardwood attached to the house by the front door.
 
post-3-0-13640800-1382977959_thumb.jpg
 
It contains a pully driven by a 12v gear motor. I upped the voltage to 17v as I wanted more power from it!
I used an old 17v laptop supply as it could supply plenty of current.
 
The motor controller was a low cost L298N module I got from Aliexpress. This was able to handle the current and the higher operating voltage.
 
I mounted a Launchpad board. Any of the normal DIL MSP430 chips can be used as the code only takes 1800 bytes of flash.
 
There are two pushbutton switches to allow the motor to be manually controlled while I was working on it.
There are two infrared detectors to detect when the ghost has reached the end of its travel, both to the left and to the right. I got the infrared detectors from buildsmarterrobots.com, but I don't think he is selling them anymore.(other detectors can be used instead).

 post-3-0-49063000-1382977923_thumb.png

The circuit uses a 3.3v regulator for the Launchpad MSP430 supply and for the infrared detectors. I needed to add a 33ohm power resistor to this regulator to reduce the power the regulator was dissipating as the drop from17v to 3.3v together with the rather large current taken by the infrared detectors meant the poor regulator was getting too hot. By adding this resistor it reduced the voltage drop across the regulator, and so lowering its power dissipation.  The L298N motor controller and the RF Receiver use a 5v supply, I used a 5.1v zener diode for this supply (I would of used a 5v regulator, if I had one)

 

post-3-0-59238600-1382978005_thumb.jpg
 
Here's the MPY code for the ghost pully controller
 

######################################################################
#
# ghost_chaser.mpy  
# 
# Program to move a ghost along a line
# ( Mike Asker 18-Sep-2013 www.mpyprojects.com)
# 
######################################################################

SWLEFT  = P2_7
SWRIGHT = P2_6

MOTOR_A1IN = P1_0  # also the Red LED     >> MOTOR RIGHT 
MOTOR_A2IN = P1_6   # also the Green LED   >> MOTOR LEFT

RX    = P1_5 
RXLED = P1_4

IRLED = P1_2
IRTOP = P1_7
IRBOT = P1_3

STOP   = 3   
LEFT   = 1
RIGHT  = 2
MIDDLE = 0 

#########################################
def left():
    global motor
    out( MOTOR_A1IN, 1)
    out( MOTOR_A2IN, 0)
    motor = LEFT
    out(IRLED, 1)

#########################################    
def right():
    global motor
    out( MOTOR_A1IN, 0)
    out( MOTOR_A2IN, 1)
    motor = RIGHT
    out(IRLED, 1)
    
##########################################    
def stop():
    global motor
    out( MOTOR_A1IN, 0)
    out( MOTOR_A2IN, 0)
    motor = STOP
    out(IRLED, 0)

##########################################
def ghost_dance():
    '''Pull the ghost back and forth a few times
    and then pull it all the way to the door (right)
    wait a while and then pull it all the way
    back to the front gate (left)'''
    
    global position
    position = MIDDLE
    wait(5000)
    right()
    wait(1000)
    for i in range(3):
        left()
        wait(300)
        right()
        wait(300)
    
    stop();   wait(2000)
    right();  wait(3000)
    stop();   wait(5000)
    left()
    
    
    while position == MIDDLE:
        if motor == LEFT and inp(IRTOP) == 0:
           stop()
           position = LEFT
    
    wait(5000)
    stop()

#############################################################
## Main program starts here ##
#############################################################

# Set the pin direction of all the IO pins
pindir(IRLED, OUT)
pindir(IRTOP, IN)
pindir(IRBOT, IN)

pindir(SWLEFT,  INPU)
pindir(SWRIGHT, INPU)
pindir(S2, INPU)
pindir(MOTOR_A1IN, OUT)
pindir(MOTOR_A2IN, OUT)
pindir(RX, IN)
pindir(RXLED, OUT)

out(RXLED, 0)
position = MIDDLE
out(IRLED, 0)
stop()

print( 'prog started' )

rx_count = 0
lcount = 0
c0 = 0
c1 = 0
rx = 0
rx_prev = 0
detect = 0

wait(3000)    # leave some time to allow the supplies to settle.

while 1:    

   # If the ghost is moving out (left) and the top ir sensor is activated 
   # then we've hit the endstop, swtich off the motor
   if motor == LEFT and (inp(IRTOP) == 0 or inp(IRBOT) == 0) and inp(SWLEFT) == 1:
       stop()
       position = LEFT

   # If the ghost is moving inwards (right) and the bottom ir sensor is activated 
   # then we've hit the endstop, swtich off the motor
   if motor == RIGHT and (inp(IRBOT) == 0 or inp(IRTOP) == 0 ) and inp(SWRIGHT) == 1:
       stop()
       position = RIGHT

              
   # Make the ghost run under button control
   if inp(SWRIGHT) == 0:
       right()
       position = MIDDLE
       
   else:
       if inp(SWLEFT) == 0:
           left()       
           position = MIDDLE

   # Stop the motor if the opposite button is pressed while
   # while running
   if inp(SWRIGHT) == 0 and motor == LEFT:
       stop()
       wait(1000)
   if inp(SWLEFT) == 0 and motor == RIGHT:
       stop()
       wait(1000)
    
    
   # Look for an RX signal from the Ghost which indicates that the
   # tick-or-treater has been detected. If detected then make
   # the ghost do a little dance
   rx = inp(RX)
   c0 = 0 
   c1 = 0
   
   # First make sure the motor is already stopped,
   # then if the we have a falling edge on the RX signal
   # count how long it stays low (c0),
   # and then count how long it stays high (c1)
   if motor == STOP and rx_prev == 1 and rx == 0:    
       while inp(RX) == 0:
           c0 += 1  
       while inp(RX) == 1:
           c1 += 1
   

       out(RXLED,0)
       # Save the c1 high count, and if it is the within the correct limits
       # then we have a '1' and we have detected the trick-or-treater, lets dance!
       rx_count = c1
       if rx_count > 150 and rx_count < 220:
           detect = 1
           out(RXLED, 1)     # switch on the detection LED 
           ghost_dance()
       else:
           detect = 0
           out(RXLED, 0)
                 

   lcount += 1
   rx_prev = rx

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...