Turn any display into a motion-triggered video system! Useful for interactive displays or a cheeky Halloween frights!
The Raspberry Pi has a number of GPIO (general purpose input output) pins. Each of these can be set as inputs or outputs. When set to input, change of logic level (low or logic 0 to high or logic 1 or the opposite) can be detected. The change of logic level could be caused by a switch opening or closing, landing of a UFO, a cockatoo’s screech, or in our case movement detection. Well, it’s not so much movement detection, but detection of heat (i.e., a person moving in the path of a PIR (Passive Infra-Red) sensor). So what happens when a warm body is detected? You could trigger a relay, make a sound, or in the case of aliens landing you could shoot your DIY RPi 100GW laser - or more sensibly, as we’ve done in this project, play a movie! This application would be ideal for a museum or interactive exhibition; on entry of a patron into any particular room, a movie could play providing detail of the art, sculpture or exhibit on display.
How Do PIR Sensors Work?
Firstly, what does PIR mean? PIR is an acronym for “passive infrared”. It’s passive because it doesn’t produce any energy to do its job. Warm objects (like people) emit an amount of heat. Some of the heat that we lose from our body is carried away as infrared (IR) energy, which a PIR senses. The construction of a PIR sensor can vary but in general, it has a material (stuff you won’t find at Coles or Bunnings like gallium nitride, caesium nitrate, polyvinyl fluorides and others), which generates energy when exposed to heat. The sensor has a small plastic lens that helps to concentrate IR from a largish area onto the IR-sensitive material of the sensor. A change in the amount of IR light falling on the sensor causes a voltage change on its output. This voltage change can be used to do useful things like activate a relay, or as in our case, provide a trigger for a RPi or Arduino to take action.
CAN I SEE INFRARED LIGHT?
The simple answer is no. When you look at a rainbow you can see seven distinct colours of light. Do you remember ROY G BIV? Red, orange, yellow, green, blue, indigo and violet are the colours of the rainbow. Each colour has a particular frequency or wavelength. Red is lowest, violet is highest. IR has a frequency lower than red light, hence the term “infra”. The human eye can’t see it, but you can feel it as radiant heat, especially from the sun. At the other end of the spectrum (literally) is ultraviolet (i.e., higher than violet). Some animals can see or more accurately sense, IR or UV.
HANDY HINT: An interesting use of your mobile phone’s camera is to check that problematic remote control laying around in your lounge room. Simply press a button on the remote and aim the phone’s camera at it. If the remote is producing IR light, then you will see it as a purple glow on your phone’s screen.
A TALE OF THREE MOVIE PLAYERS
There’s not a lot of choice of video players for the RPi. Rasbian includes OMXPlayer, so it is available to us straight away. Most makers know VLC, which is a brilliant free movie viewer, but the freely downloadable version is not hardware-accelerated (i.e., the heavy lifting of decoding the movie’s compressed video is done in software). A RPi can handle a small movie but is completely swamped playing in full screen mode.
That’s two movie players so where’s the third? Well, it’s also VLC, but a version that supports hardware acceleration. You can’t download this but you can download the source, and then compile it yourself. Set aside an hour if you decide to this; it is worthwhile.
So, which is better? They each have their pros and cons:
|Command line only?|
|Full screen only?|
|Can have multiple instances?|
|Supports many video formats?|
During development we tried each of these. OMXPlayer is fast but is command line driven. It doesn’t handle a lot of video formats but it is possible to convert the video format to, say, AVI and it generally works fine. It is acceptable for this project.
A NOTE ABOUT GRAMMAR & CODE: The RPi uses Linux, which is case sensitive in many regards. One of these is the name of programs. In the case of OMXPlayer, we must write it as "omxplayer" to ensure the code runs correctly.
The standard VLC can be opened multiple times simultaneously, to display multiple videos on one screen, but is slow. It has a GUI, which is irrelevant to this project but can be command line driven. Due to the speed issues it is next to useless for this project.
Hardware-accelerated VLC is fast, but always full screen and non-interactive while playing. It handles most (if not all) video formats. There’s a little work needed to “make” the accelerated version, but it’s only once.
There’s not much between OMXPlayer and accelerated VLC, so it is up to you as to which one you choose to use.
This project is based around PIR sensors. It uses one, but in development we used three. You could use as many as the number of available GPIO pins allows.
|1 x Raspberry Pi 3||XC9000||Z6302B|
|1 x PIR Sensor||XC4444||Z6382|
|Four Core Alarm Cable||WB1590||W2341|
BUILDING THE CIRCUIT
For the prototype we used a breadboard to allow multiple connections to VCC and 0V, and to extend the connections to the PIR output pins. In practice you could mount the sensors in the corner of a room. As they need two connections for power and another for the output, four core alarm cable would be a good choice for connecting them to your RPi, or you could use Cat5 cable for a simpler solution.
This is a single RPi/single movie/single screen version but has options for movie player, movie to play and pin/s for PIRs. We're using omxplayer as it's fast.
Note: It's fussy with movie format, runs full screen and is not interactive. It doesn't need to be interrupt driven, as there are checks in place to prevent multiple PIR detections launching multiple simultaneous movie launches.
import RPi.GPIO as GPIO
PIR1_PIN = 11
# pick a pin
#PIR2_PIN = 12
#PIR3_PIN = 13
child1 = 0
returncode1 = 0
running1 = False
#movieplayer = "vlc"
movieplayer = "omxplayer"
movie = '/home/pi/Videos/drop.avi'
Now we need to set up some variables. We’ve defaulted to using OMXPlayer but you can experiment with VLC if you like. We’ve specified a simple movie to test the project.
Next we set the mode of the GPIO pin naming. This can be quite confusing as there are two options for the model 3B, and there have been variations with older boards. The prototype is based on the most modern RPi - the 3B - which has two options: GPIO.BOARD or GPIO.BCM. GPIO.BCM means use GPIO numbers not pin numbers. GPIO.BOARD means use the actual pin numbers on the Pi’s 40-pin header, not GPIO numbers. This URL shows the pinout and provides further detail: www.raspberrypi-spy.co.uk/2012/06/ simple-guide-to-the-rpi-gpio-header-and-pins/
We then set the pin that is connected to the PIR sensor as an input.
if movieplayer == "vlc":
opt = '--play-and-exit'
opt = ''
Since an option has been included to pick between OMXPlayer or VLC, we need to consider whether to pass a second optional argument to VLC ('--play-and-exit'), which tells VLC to close when the movie has been played. If using OMXPlayer, we don’t pass anything but the filename to play.
print ("Motion detection will trigger a movie to run (CTRL+C in shell to exit)")
if running1 == False:
print ("Motion detected on PIR #1")
child1 = subprocess.
Popen([movieplayer, movie, opt])
# launches a movie player and passes a filename.
running1 = True
print("Movie 1 is running")
Here we indicate that the program is running, then wait for a signal from the PIR. As we may get multiple “movement” signals from the PIR, we use the variable “running1” to indicate whether we are currently responding, or we are free to display it now. “child1” is a process object created when we launch the movie player.
Note: Along with possible multiple signals from the PIR, the output signal may remain high (logic 1) for five or more seconds. Without appropriate measures this could trigger multiple “movements” when in fact there may have been only one movement detected.
# poll for movie finished
if running1 == True:
# Popen returns an object.
# Poll that object to see if running.
returncode1 = child1.returncode
if returncode1 == 0:
running1 = False
print("Movie 1 has finished")
# sleep for 1 second between polls
Once we have a movie running, we need to be able to determine when it has finished so that we can respond to the next movement trigger, and display the movie again. This is done with child1.poll(), which will return 0 when the process (the movie viewer) has completed. We let the system take a breather between polls with the time.sleep(1).
This cleanly terminates the program when control-c is entered into the shell.
WHERE TO FROM HERE?
The prototype was built to have one RPi sense movement, and display one movie on one screen. There’s no reason, especially considering the cost, not to expand this to multiple instances of the “one RPi showing one movie” idea. Do you have a large sculpture exhibition? Why not detect a patron entering any particular exhibit room and play a movie related to the sculpture?
As the PIR sensors provide a voltage level compatible with RPi or Arduino, you can write a program to control the world; well, your immediate vicinity anyway! You can easily activate a buzzer, a relay, a motor, or light LEDs. With some extra electronics you could even send an SMS or send a signal via WiFi. Just don't point the PIR where it can see the screen. Our protoype was built with three sensors, so it is easy to process input from many points around your home or building.