Introduction: Motion Sensitive Projected Ghosts Using Raspberry Pi Zero

Picture of Motion Sensitive Projected Ghosts Using Raspberry Pi Zero

Projected ghosts are fun, but they're a bit passive for my tastes. It can break the immersion of your haunt if the ghosts simply ignore your guests. So why not have them react to your guests by jumping out and scaring them as they approach? With a Raspberry Pi, it's possible!

This player supports multiple movies each paired with a jump scare movie. It also features a fast-forward button that allows you to cycle through the videos to get to the one you really like.

List of materials

  1. A projector capable of accepting an HDMI input
  2. Something to project onto
  3. Ghost footage, such as that from AtmosFX. The video you choose should have "roaming" footage with the ghost wandering around, and scare footage, where the ghost or monster jumps out at the audience.
  4. A Raspberry Pi. I am using the Zero, which cost me 99 cents from Micro Center. But you can use any HDMI capable Raspberry Pi.
  5. A Mini-HDMI to HDMI cable if using the Pi Zero, or an HDMI cable if using a Pi.
  6. A microUSB power supply for the Raspberry Pi.
  7. A USB to microUSB cable for connecting the Pi to your computer.
  8. A passive infrared (PIR) sensor. The one I am using here is a Parallax 555-28027 rev A, which I bought about 5 years ago from the now all but defunct Radio Shack. Any PIR sensor that works with 5V TTL signals will probably work. If you don't know what any of that means, just make sure your PIR sensor works on 5V. You can learn more about logic voltage levels here.
  9. An 8 GB or larger Micro SD card.
  10. A normally open (off) momentary button
  11. Wire, solder, etc.
  12. A breadboard for prototyping

Step 1: Set Up Your Raspberry Pi

Picture of Set Up Your Raspberry Pi

Install Raspbian on the Raspberry Pi

Before going any further, you'll need to install Raspbian onto your Raspberry Pi. This is the Raspberry Pi operating system. Without it, the Pi won't do much. There are detailed instructions on Raspberry Pi's own website, and in other locations around the web.

Essentially, there are two ways you can do it. You can use an installer called NOOBS, or you can directly install Raspbian. If you prefer to use NOOBS, follow the instructions on Raspberry Pi's website here. If you prefer to install Raspbian directly, Adafruit has a nice step by step instruction set here. The end result should be the same.

Enable SSH on the Pi

We need to connect to our Raspberry Pi from our computer in order to copy over our movies at the very least. You may prefer to use your computer's keyboard to program the Pi as well. We also need to install a few Python packages to support our code. The simplest way to accomplish all of this is to enable SSH on the Raspberry Pi.

Full instructions on enabling SSH are on the Raspberry Pi website here.

By default, SSH access is disabled on the Raspberry Pi as of Raspbian Jessie. To enable it, create a file called "ssh" in the top level directory on the Pi Micro SD card. Just mount your Micro SD card on your computer. From any OS, you can just create an empty text file and name it "ssh" with no extension using the editor of your choice. Alternatively, if you are on Mac or Linux, you can navigate to the SD card root directory in a terminal window and enter "touch ssh".

On your computer, you can connect to the Pi using an SSH client. On a Mac or Linux, you can use the commands "ssh" and "scp" in a terminal window. On Windows, you can use the programs "Putty" and "WinSCP". Putty and ssh will allow you to log into the Pi remotely, and WinSCP and scp will allow you to copy files to and from the Pi remotely.

Before you can use either of these programs, you need your Pi's unique IP address. There are any number of ways to get this information. The easiest is to connect a display (like your projector) and a keyboard to the Pi. After it boots, open a terminal window and type "hostname -I" to get the IP address. Other methods are detailed here.

Enable Overscan

Connect your projector and a keyboard to the Pi Zero and boot to the desktop. You'll notice the image does not fill the whole screen. Under the Raspberry menu, click Preferences and Raspberry Pi Configuration. Under the System tab, there is an option called "Overscan" that is set to "disabled". Change to "enabled", and the image will fill the entire screen.

Share your computer's internet connection (Windows, Pi Zero only)

We need an internet connection. At least temporarily. If you're on Windows, all you have to do is go to your network settings, and find your internet connection. Right click this connection and enable sharing. I'm being somewhat vague here because the exact wording and procedure is slightly different for Windows 7, 8, and 10. Here's a nice tutorial that will show you how to piggyback your computer's internet connection in WIndows 10.

Update Raspbian and grab the packages you need

On the Pi, either directly or via SSH, enter the following in a terminal window:

sudo apt-get update
sudo apt-get -y install build-essential python-dev python-pip python-pygame supervisor omxplayer

(mimicking Adafruit's video looper install script). The first command updates Raspbian's package list, and the second installs a bunch of things we'll need. Mostly, we need pygame, supervisor, and omxplayer. Some of these are probably already installed with Raspbian by default. That's fine--the installation will simply skip them.

  • Pygame is a game writing interface, but we're only going to use it to keep the screen blacked out when no ghost videos are playing.
  • Supervisor is a really easy to use program that runs in the background and automatically starts other programs as needed. We'll use this to make the Pi go straight into our video player when it boots up. That way we won't need a keyboard or mouse to start it every time.
  • omxplayer is a simple command line movie player for the Pi.

Help, I didn't understand any of this

Everything here up to the last step where we installed project specific packages is generic Raspberry Pi setup. You can find many more detailed sites online detailing how to do all of this. A good place to start is Raspberry Pi's own website.

Step 2: Add Headers to the Pi Zero (optional)

Picture of Add Headers to the Pi Zero (optional)

You may have noticed that the Pi Zero does not come with any kind of header, male or female, attached to its GPIO (general purpose IO) pins. Instead, there are only holes. You'll have to solder in your own. The standard Pi has male header pins. I decided to use female headers for rapid prototyping, much like the Arduino.

Attaching a header is really straight forward. If your headers are longer than 20 pins, trim them to fit, and insert the pins into the holes on the board. Holding the board steady, solder the end pins in place, heating and adjusting as necessary to fit the header flush against the Raspberry Pi. When you're comfortable with the placement, solder the remaining 18 pins in place.

Repeat for the other row of header pins.

Step 3: Connect the PIR Sensor and the Fast-forward Button

Picture of Connect the PIR Sensor and the Fast-forward Button

The GPIO pins for the Raspberry Pi are used to connect to the outside world. Some of these pins provide power, some provide ground, and some provide general purpose input and output (GPIO). Except for the first few models, the GPIO pins on the Pi are standardized, and are the same regardless of whether you are using a Pi or a Pi Zero. The GPIO pins are arranged as in the figure above (from

The PIR sensor

Most PIR sensors, including the Parallax model I'm using here, have three connections: +5V power, ground (GND), and output. The output is digital, and will be either high (motion detected) or low (no motion). There may or may not be a switch or jumper with which you can control the sensitivity of the sensor. Since this will be a Halloween setting with lots of cars, wind, and trick-or-treaters, you probably want to set the sensitivity as low as possible.

I recommend prototyping on a breadboard. Using jumper wires or a breadboard, connect the +5V pin of the PIR sensor to any of the +5V pins on the Pi (red circles in the image). We're sourcing our power from the PI, which should be fine. The current draw of your typical PIR sensor is well within the tolerance of the Pi (though you should check your datasheet to be certain). Connect the ground pin to any of the ground pins on the Pi GPIO headers (black circles in the image). Finally, connect the output pin to any of the yellow numbered pins in the figure. Make a note somewhere of the pin number you chose. You'll need it for the code.

The fast-forward button

The fast-forward button only needs two connections. You can either make the button trigger high or trigger low. Triggering high means pushing the button connects its GPIO pin to +5V. Triggering low means pushing the button connects its GPIO pin to ground. A well-known problem with buttons is that when they're not pressed, the GPIO pin is in an unknown state, or "floating". The solution to this is attach the button's GPIO pin to its untriggered state with a large resistor. For example, if we are triggering low, we want to attach the pin to +5V with a large resistor called a pull-up resistor (because it's pulling the voltage up). The resistor means the connection uses very little power, and it also means that when the button is pushed, the trigger state is the path of least resistance.

Fortunately, the Pi includes pull up resistors internally. So we want our button to trigger low. We have to enable the pull-up resistor on the software side, but we'll talk about that later. Connect one of the button terminals to one of the GND pins on the Pi, and the other to one of the numbered GPIO pins. Again, make note of the pin number.

Step 4: Copy Your Videos to the Pi

Picture of Copy Your Videos to the Pi

You can do this one of several ways. You can shut down the Pi, remove the Micro SD card, and pop it into your computer. Inside your user directory, you can create a folder to hold the videos. Copy the movie files to that directory, and you are done.

Alternatively, if your Pi is already attached to your computer via USB, you can use SCP to copy the files to your Pi. If you use a graphical client such as WinSCP on Windows, you provide WinSCP with the address of the Pi and your user credentials. The default user name is pi and the default password is raspberry. Navigate to the place on the pi where you wish to copy the movies (creating new folders as needed), and copy the files from your computer to your Pi.

If you have the DVD rather than the digital movie files, you'll have to convert the DVD to digital files first, but this exercise is left to the reader.

I've copied my videos to /home/pi/Videos/ghosts. Inside that folder, I've copied the videos for AtmosFX's black background videos in both landscape and portrait format for four different ghosts. For each each ghost/orientation combo, there's a video of the ghost wandering around, a video of the ghost "phasing" through the wall, and jump scare videos corresponding to each. Your directory structure is a matter of taste, but you'll need to know it for the code.This is my structure, showing the files only for the first subdirectory:


Step 5: The Code

The latest version of the code is available on GitHub here. To get this code onto your Pi, log in and type

git clone

This will create a folder called "videoscarer" containing the file

You need to modify this code to suit your installation. In particular, you'll need to make sure that the variables "normVideos" and "scareVideos" contain python lists of your videos. Both lists need to be the same length, and they need to correspond one-to-one. That means that the video in the first slot of "normVideos" needs to correspond to the jump scare video in the first slot of "scareVideos". The code will jump from the video in the current slot of normVideos to the video in the same slot of scareVideos when the PIR sensor is activated.

VideoScarer class features

  • Support for a fast-forward button (easily extrapolated to a rewind button if you wish)
  • Support for PIR sensor triggering
  • Customizable interval between valid PIR triggers (set to 10 seconds in the attached code)
  • Black screen during video switches and rest periods hides the desktop automatically

Credit for the screen blanking portion goes to Adafruit's VideoLooper. You may wish to incorporate some of their features as well, but I've kept the code as simple as possible. Note that the Adafruit code has a small bug--it's unstoppable. PyGame traps keyboard (including ctrl-c, rendering their SIGINT handler unusable), so you need to add the PyGame event handling that VideoScarer has in order to honor quit key sequences like ctrl-c. This won't matter anyway if you don't have a keyboard attached, and you're just SSHing into the PI. I did during debugging, so it mattered a great deal to me.

Also of note is the seemingly unnecessary timer resetting after each video begins to play. When I tested the PIR sensor triggering without videos playing, I noticed that the PIR sensor would trigger whenever videos started, leading to a constant loop of scare videos. After some playing around and some research, I found that video playing is so power consuming that the reference voltage for the PIR sensor changes, and it incorrectly registers a hit. The PIR stabilizes fairly quickly, so we just need to wait a bit. About 10 seconds works. Since this was already my "scare interval", I just reused that variable. The other alternative is to have a separate power supply for the PIR sensor, but that seems like overkill to me.

Code explanation

  1. Initialize the VideoScarer class
    1. set up the Pi's GPIO using the Broadcom numbering scheme
    2. Initialize the PIR sensor with an interval between activations called "scareInterval"
    3. Initialize the fast-forward button
    4. Check the video lists
    5. Black out the screen using PyGame. Unfortunately, this also disables the ability to quit our player with Ctrl-C, so we'll handle that later.
    6. Set up the player command. We're using omxplayer, a lightweight movie player that comes with Raspbian. You may want to alter the volume level and the output here, as indicated in the comments.
  2. Attach SIGTERM and SIGINT to the kill subroutine of VideoScarer. These lines actually do nothing if PyGame is running.
  3. Run VideoScarer
    1. Check if the user pressed Ctrl-C or ESC. If so, quit
    2. If nothing is playing, advance to the next video and play it.
    3. Check the PIR sensor. If it has been set off, play the scare video
    4. Check the fast-forward button. If it has been pressed, skip to the next video and play it
  4. Kill VideoScarer.
    1. Shut down omxplayer
    2. Quit PyGame

A test run

You may want to run the code directly to give it a test before installing. You can either open IDLE for Python 3 (under the Raspberry Menu->Programming) and run it from there, or you can open a terminal and run the module as (substituting your directory)

python3 -u /home/pi/Documents/videoscarer/

Step 6: Making It Run Automatically

Picture of Making It Run Automatically

We're using the Supervisor daemon to run our program automatically. You need to create a file describing the program you're trying to run in the syntax that Supervisor understands. The file goes into the Supervisor directory, where it's automatically loaded. The commands should be self-explanatory. We're just telling Supervisor to automatically restart our video scarer if it crashes for some reason.

1. Open a text editor on your Pi (or your computer) and type:

command=python -u /home/pi/Documents/

2. Save this file as/etc/supervisor/conf.d/videoscarer.conf on your Raspberry Pi.

3. Restart Supervisor by entering service supervisor restart in a terminal on the Raspberry Pi

Step 7: Installing Everything

Picture of Installing Everything

Solder your circuit together

So far, we've put our circuit together on a breadboard. Now that we know it's working, we should make it more permanent. The PIR sensor is rather expensive, so I don't really recommend permanently attaching it. Fortunately, most of them use a "servo" connector, which will connect nicely to a 3 pin female header. I'm using some old Cat5e (ethernet wire) that I had sitting around, because it has plenty of conductors inside a single sleeve.

  1. Strip back your wires and choose 3.
  2. Solder the 3 pin female header in place.
  3. At the far end, strip back the same 3 wires.
  4. Solder single pin male headers to each.
  5. Plug the male headers into the appropriate pins on your Pi.
  6. Plug the 3 pin female header into the PIR sensor.
  7. Solder two wires to the button. I recommend using a separate length of wire for the button, even though there may be plenty of wires in the cable you used for the PIR sensor. That way you can put the button somewhere else, so that you don't set off the PIR sensor when you fast-forward.
  8. Solder single pin male headers on the opposite end.
  9. Plug into the appropriate pins on your Pi.

Protect the Pi

Put the Raspberry Pi into some sort of enclosure. An Altoids tin works well, though it may require some cutting. There are also any number of commercial enclosures. Tie knots in your PIR and fast-forward button wires on the inside of the enclosure to keep the Pi header pins from pulling loose if something yanks on the wires. It will happen on Halloween.

I used one of those recloseable containers that sandwich meat comes in. I like to turn them upside down and mount the Pi (or Arduino or ESP8266, etc) on the bottom of the lid with some twisted wire. It makes a nice, see-through cover with space for peripherals and wires.

Mount the PIR sensor and the button

Place your PIR sensor somewhere where it will be triggered by your guests. You will probably find it necessary to restrict the PIR sensor's field of view. A toilet paper tube works well for this purpose, restricting the view to a narrow beam. Disguise the sensor as best you can and hide the wire running back to the Pi.

Place the fast-forward button somewhere discrete but out of the line of sight of the PIR sensor. It can even be mounted on your Pi enclosure, because you probably won't use it often.

Set up your projector

You'll probably want to hide your projector somewhere discrete. Just keep in mind that even the newer LED models generate a lot of heat, so give it some breathing room. I'm rear projecting onto some black chiffon fabric I picked up from JoAnn's Fabric. AtmosFX sells its own rear projection fabric, and there are a number of DIY options. This guy does a good job comparing fabrics for rear projecting in front of a window.

Place your Pi enclosure somewhere near the projector, and connect the Pi's power and HDMI output. In my case, my projector had a USB port, so I used that to power the Pi, eliminating the need to plug the Pi into the wall. The Pi should boot up and automatically start the show.

That's it! You should be able to scare the snot out of some kids now. Or door-to-door salesmen.


moyong25 (author)2017-10-22

Very cool! I’m new at this so I need your assistance. I’m using Raspberry pi 3 for this project. I noticed that when I run the script and no movement is detected by the PIR sensor, it would automatically play the next video after 10 seconds. How would I edit the code so that it would just play to the next video whenever the PIR is triggered or the button is pressed? I would really appreciate the help! Thanks!

moyong25 (author)moyong252017-10-22

After studying the code and some trial and error, I figured it out. I had to set the time on the PIR sensor shorter than 10 seconds. It works!

fadecomic (author)moyong252017-10-23

Glad you got it working. 10 seconds is the default lock out on re-triggering the PIR sensor. If it's playing the next video after only 10 seconds, I may have a bug. I will look into it.

cwolsey (author)2017-10-12

I love it! I see you load in videos which are horizontal and vertical. How do you pick which one to play?

fadecomic (author)cwolsey2017-10-12

Thanks! In the code, I just selected the landscape videos manually. If you look at lines 48-53, I combine all the landscape videos into one list and all the portrait videos into another. Then in lines 55-56, I just set "normVideos" and "scareVideos" to the landscape list. You can change these to the vertical list (which I probably will for Halloween myself).

cwolsey (author)fadecomic2017-10-12

Ah I see just subsitute

normVideos = normVideos_alllsscareVideos = scareVideos_allls

for ...

normVideos = normVideos_allvertscareVideos = scareVideos_allvert

What would I have to do just to have it display black. Only playing the scare video when PIR is triggered? I could just subsitute the normal videos for all black ones but there is bound to be a neater version.

cwolsey (author)cwolsey2017-10-12

could I just change line 142 to ...



I am wanting to hide the projector and only have you notice the projection when it plays a scare video.

fadecomic (author)cwolsey2017-10-12

You'd have to comment out line 142 and line 156-158. That will keep the "normal" videos from playing. You probably also want to copy lines 115-117 and paste them after line 111, so that the videos advance after each scare.

cwolsey (author)fadecomic2017-10-12

That works amazingly well! I did just give my seven year old such a fright that it took a good half an hour to calm her down before she went to sleep. I think you should publish a fork with just the ghost popping out. It is mint.

fadecomic (author)cwolsey2017-10-12

I cannot test it yet, but I created a branch called scare-only here:

All you have to do is set normVideos = None

This is slightly different from the changes I proposed above. This branch will do either. Set normVideos to a list to operate as in the Instructable, or set normVideos = None to only play the scare videos.

cwolsey (author)fadecomic2017-10-12

Legend! I will give it a go

About This Instructable




Bio: Nerd. Geek. Billionaire crimefighter.
More by fadecomic:Voice Synchronized Grim Reaper CostumeMotion Sensitive Projected Ghosts Using Raspberry Pi ZeroInteractive Stranger Things Jack-o-Lantern
Add instructable to: