The Ghost Detector 9000

by julespeak in Circuits > Raspberry Pi

1858 Views, 18 Favorites, 0 Comments

The Ghost Detector 9000

The Ghost Detector 9000

Troubled by anomalous specters haunting your home? Perturbed by poltergeists having their way with your personal belongings? Don't let these paranormal entities get the better of you! Construct your very own Ghost Detector 9000 today. Scan your possessions for signs of possession and then detect and download the spirits onto your device. Try to collect as many ghost signals as you can!


At its heart, the Ghost Detector 9000 is intended to be a hackable platform for creating and implementing various ghost-detecting-based games. The Detector can be used as a prop in a costume, as a fun conversation piece at a Halloween party, or even as a game element in a haunted house. Technically speaking, the central component is a Raspberry Pi Zero with two primary I2C peripherals: an Inertial Measurement Unit (IMU) and an Analog-to-Digital Converter (ADC). Sharing of the I2C bus is managed by a server written in the Rust programming language. The Rust program (called the Ghost Processing Unit or GPU) also runs a Madgwick sensor fusion algorithm in order to calculate the heading of the IMU based on a combination of accelerometer, gyroscope, and magnetometer data. The GPU records EMF voltage data on-demand when a trigger signal is received and returns the voltage data when a stop signal is received. The GPU makes data available over a socket connection which can be easily accessed by Python scripts that also run on the Raspberry Pi.

The main game interface of the Ghost Detector 9000 is provided by a Python script that runs alongside the GPU. The Python script reads the state of the buttons on the device, and when a scan is performed, the script will play back the recorded audio data that is sent back from the EMF detector. It uses the power of the measured signal to seed a s p o o k y algorithm to populate an array of ghosts with ghost signal coordinates. The Python script continuously receives heading data from the GPU and then does a little vector math to see if the detector is currently pointed at one of the ghost signals in the array. The script uses the lights on the device to show a pattern that lets you know which way to point and how far you have to go to "lock on" to a ghost. When locked on, you can pull the trigger once more to remove the ghost from the array. The script plays fun little sound effects during the different phases of the game.


My hope is for this project to be approachable from several levels. As an electronics project, assembling the components on a breadboard would be a great path for a beginner, while an expert could consider making a custom PCB and/or custom housing to make the detector look even more authentic. As a programming project, novices could use a pre-compiled GPU or eliminate the GPU all together; if all you want to do is blink some LEDs, respond to buttons, and play sounds, the code for this is all surprisingly simple! Programming enthusiasts will be able to find all code on GitHub, where they may copy and/or modify to their heart's desire. (If you fix any bugs or add any nice features, please submit a PR!) There are various entry points at several levels for the Ghost Detector 9000; if you're totally unsure of where to start, just send me a message, and I'll be happy to point you in the right direction.

In this Instructable, my main goal is to outline the process by which I made my version of the Ghost Detector 9000. If you make a Ghost Detector exactly like this one (at least up to the modules used and the pins on the Raspberry Pi you connect to), then the code in my repo should work exactly as-is. For this reason, I'll provide exact part descriptions where I can, but please, feel free to follow your own inspiration for the way you implement it. Got a nice knob on an old VCR somewhere? Slap it on there! Have a set of nixie tubes lying around? That sounds like a solid ghost counter to me!

Now, let's get detecting! ๐Ÿ“ก

Supplies

pic1.jpg
pic2.jpg

Essential items


  • Raspberry Pi Zero - eBay is probably a good bet until supply chain issues are resolved; looks like they are also in stock at Adafruit
  • I'm using a Raspberry Pi Zero W. If the GPU runs on this RPi, then it will probably run on any of them, but you might have to recompile the Rust code for this.
  • PiSugar 3 - available on tindie
  • I can't recommend this thing enough. It's got tons of features and a nice web interface, and you can even get data from it directly over I2C. I'm using the 1200mAh version for the RPi0, and I'm getting around 2 or 3 hours of battery life with everything running.
  • Peripherals of some kind
  • To use the features of the GPU as it currently exists, you will need an MPU9250 and an ADS1115.
  • At the very least, you should get yourself some individually-addressable RGB LEDs (I used these).
  • I also think a USB sound card is a big plus (I used this sound card with this cable and these headphones).
  • Some momentary switches and knobs are very handy (I used these and these).
  • Anything with a simple on/off signal (so any kind of button, switch, or indicator light) is very easy to add to the Python part, and anything with an I2C protocol is straightforward to add to the Rust part.
  • I think these prototyping hats are great for combining all of your peripherals onto one module.
  • Housing
  • The world is your oyster here. You could 3D print something specifically for this. You could modify an existing item (as I did here, using this flashlight). You could integrate the project into something else you've been cooking up. (Did someone say "ghost-detecting night vision goggles"?) See Step 4 for more details.


Tools and supplies


  • Some kind of computer for communicating with the RPi
  • If you're only working with the Python part, then really anything will do (you can do all the coding on the RPi itself). If you're going to modify the Rust code, then I would strongly suggest some kind of Linux OS (Ubuntu 22.04.3 LTS is a great option if you're not sure what to pick). [NB - It's possible to compile the Rust code directly on the RPi, but I personally found cross-compiling on a Linux machine to be an easier workflow. Instructions for setting up the cross-compile environment are on the Github page.]
  • Electronics prototyping components - breadboard, jumper wire, LEDs, various resistors, various USB cables
  • The ADC may require additional electronics components, depending on exactly how you want to implement it. See Step 2 below for more information on this.
  • Soldering iron and solder
  • Wire strippers, wire cutters, needle-nose pliers, heat shrink tubing
  • Various screwdrivers (a security bit set is also a good idea if you're modifying an existing device for the housing)
  • Hot glue gun - I like the high-temperature kind
  • Drill and drill bit set
  • Scissors and razor blade
  • Digital calipers or a ruler
  • Stainless steel wire (not strictly necessary, but this helped me to manage the wires of the RGB LEDs)

Prepare the Raspberry Pi

Raspberry_Pi_Logo.svg.png

A tutorial for setting up a Raspberry Pi is beyond the scope of this Instructable. Here I'll just give the rough outline, along with some nice links:

  1. Follow the wonderful getting started guide here: Raspberry Pi Documentation - Getting started
  2. I usually do a headless setup, which involves assigning the credentials of my home Wifi network when creating the boot image. The Raspberry Pi will start an OpenSSH server when it boots. You can then use PuTTY (or similar) to log in to the Pi over SSH.
  3. When setting up new RPis, I typically create a new user and delete the default 'pi' user; see here: Delete pi user in Raspbian - Raspberry Pi Forums (I typically only use the terminal, so the "without pain" solution here works for me just fine). I also disable password login for SSH and enable SSH keys after setting those up; see here: How To Configure SSH Key-Based Authentication on a Linux Server | DigitalOcean.
  4. Get an interface set up
  5. I like to do everything over SSH on the terminal, but I know that's not everyone's cup of tea. You could set up a monitor/keyboard if you'd prefer to operate directly on the RPi; if you've got a spare monitor, this may be the fastest way to get going. You could also set up a VNC server on the RPi and then use a VNC client to use the RPi. The second and third options give you a GUI by default, so that's nice in a lot of ways. [NB - I found that my VNC server was pretty laggy on the RPi0, so I only used it when I really wanted the GUI. Beefier Raspberry Pis probably won't have this issue.]
  6. You'll want to be able to quickly move stuff back and forth from your development computer/laptop to the RPi. If you're using SSH, I'd recommend setting up SSH keys (see above). Some kind of cloud storage (shared between your host computer and the Raspberry Pi) may also be a nice solution.
  7. See the official documentation for more ideas: Raspberry Pi Documentation - Remote access
  8. Install git and clone the ghost detector code from GitHub
  9. You can find all the code here, along with a binary execuatable compiled for the Raspberry Pi Zero W: Julespeak/ghost-detector-9000 (github.com)
  10. Follow the instructions here for starting up the GPU and Python script. There are also instructions for setting up the Rust build environment, if desired.
  11. This repo also includes several Python scripts that were helpful while setting things up.
  12. Set up the PiSugar3
  13. Pretty much everything you need is here: PiSugar 3 Series ยท PiSugar/PiSugar Wiki (github.com)
  14. I removed the magnet from my module since it was making magnetometer calibration difficult.
  15. As I mention in Step 6, I had to add an external power switch. The Wiki mentions that there is a pad on the board for adding an external switch. Now would be a good time to add this and test the connection.

Collect and Test Peripherals

GhostDetectorSchematic.png
GhostDetectorBreadboard.png
pic1.jpg
pic2.jpg

While not strictly required for making the Ghost Detector, the content of this step may still be helpful for context if one wants to improve or extend the design. Feel free to rush through or skip this one if you're in a hurry to detect something spooky.

To use the Ghost Detector code as-is, you will need to reproduce the circuit shown in the pictures above. I would strongly recommend connecting everything on a breadboard (see the pictures for a suggested layout) and doing some testing before proceeding. In the next step, I will describe how I assembled the components.


Test Various Modules


I have a habit of buying various electronics modules that seem fun or interesting (GPS receivers, LIDAR modules, various sensors & etc). These are pretty easy to find on places like SparkFun, Adafruit, or even Amazon. When testing a new module, I like to start by just soldering on the header pins (usually provided with the module) so that I can get it on a breadboard. I have a big collection of jumper wires (again, check SparkFun, Adafruit, or similar) and breadboards that I can use to connect things to the various development boards that I have. I usually put male header pins on all of my boards so that I can easily get those connected to a breadboard, too.

No matter what your device, the best place to start is with the simplest "Hello, world!" idea that you can imagine. Typically, you can just Google "<my module> raspberry pi python" or similar to find a getting started guide. For the specific components in my rendition of the Ghost Detector 9000, these are the starting points that were useful for me:

When you've got simple communication going, it's time to play! Go with whatever idea takes you. It's usually pretty simple to find Python code snippets for various ideas from Stack Exchange or similar. There's a wealth of great content on YouTube from various makers who do cool things with Raspberry Pis, and there's many great projects to be found here on Instructables! (Here's a fun one to implement using the LED strip: Cyclone LED Arcade Game : 4 Steps - Instructables)


Ghostfinder Protip: I think it's a good idea to put the various modules through their paces like this to (1) confirm that everything is working and (2) develop code for testing the operation of each of the components individually. I often found it helpful to go back to this early code as I was putting the pieces together. I have several test scripts in the repo with the rest of the code for this project. If the MPU-9250 and the ADS1115 are both connected to the Raspberry Pi's pins as shown in the schematics, then the GPU itself can also be used to test these two modules.


Details on the EMF Detector Circuit


The main custom part of the Ghost Detector electronics is the EMF detector circuit (the bit at the top of the schematic in the first picture). As far as analog circuits go, it's pretty simple and pretty scrappy. Essentially, it's a non-inverting amplifier with unity gain at DC and high gain (100x) for AC signals. The input to this op amp circuit comes from a series RLC resonator, with a resonant frequency around 1 kHz. The Q factor of the resonator is low, which is fine since we want this circuit to produce voltage fluctuations over a wide range of frequencies. It can be excited by everything from 60 Hz line noise to the GHz frequencies that come from the microwave.

The tricky part of this circuit is working with a single supply voltage (i.e. I just have +3.3V or +5V and GND, not a dual supply like ยฑ3.3V or ยฑ5V). To manage this, I bias the input signal near the midpoint of the ADC's range. The op amp circuit itself uses a 5V supply voltage (due to the choice of op amp), so I also have to divide the output before I can send it to the ADC. I do this with a simple resistor divider. The main difficulty in all of this was due to the op amp that I was able to scrounge, the ADA4899-1 (which is a great, low-noise op amp, but not the best fit for this application). If I had this all to do again, I would probably go with something like the LM358 (as is done here: Electromagnetic Field (EMF) Detector With LM358 : 6 Steps (with Pictures) - Instructables).

So I'll present the circuit that I came up with. This is by no means a "good" EMF detector, but it is a technically working EMF detector. When constructing it, I was mostly just throwing spaghetti at the wall to see what was going to stick. Once I had it all soldered up, I used a script that I wrote to read from the ADC, and I took some data while moving the detector around my apartment. I got a huge signal from the microwave, and I also got a reasonable signal from my washing machine and various wall wart power adapters that I had. I would probably increase the gain by at least 10x (by increasing the value of R1) if it wasn't annoying to make that change.

Finalizing the Electronics Package

pic1.jpg
pic2.jpg
pic3.jpg

My plan for getting everything into the housing was to split up the electronics in the schematic above into two parts: the electronics package (the Raspberry Pi, the I2C modules, the EMF circuit, the battery) and the wiring harness (the buttons, the lights, the USB sound card). The electronics package is connected to the wiring harness with headers (and the USB cables). In this step, I present the custom hat that I made as part of the electronics package.

I'm pretty experienced with soldering up prototype boards, so I just improvised with the prototyping hat that I linked to above. I think having everything attached to a small breadboard would also be a great way to keep things small. Of course, the most compact option would be to design a custom PCB hat. Personally, I think making a custom PCB based on a breadboarded design is a great way to get started with making your own circuit boards. If you want to go the extra mile, you could also copy the circuits on each of the modules to integrate them directly onto your custom hat. (The leadless package of the MPU-9250 requires some expert-level soldering and tools, but it can be done by hand.) However, at this point, getting pre-assembled boards may be the way to go. Whatever you do, it's good to reign in as many wires as you can. Ultimately, you'll want to cram the electronics package into some housing, so it's good to make this part compact.

On my custom hat (see included pictures), I soldered on the MPU-9250 module, the ADS1115 module, and the EMF detector circuit described above. I added several male and female headers onto the hat so that I could access +3.3V, +5V, GND, and about 10 of the GPIO pins of the RPi0. (At this point, I still wasn't sure what all I wanted to attach to the housing, so I wanted to leave my options open.) The PiSugar PCB is screwed onto the bottom of the RPi0. Together this whole assembly is the electronics package.

The final size of the electronics package was about 1.25" by 2.75" by 1.5". I removed the magnet that is normally used to attach the LiPo battery to the PiSugar board so that I would have some extra freedom to move this around inside the housing. (This also made magnetometer calibration much easier.)

Choose Your Housing

og_flashlight.png

One of my favorite things to do is to go shopping for things to hack. It's best to have an idea for all of the peripherals that you want to add to your detector and a rough idea of the size of everything. I had measurements of the electronics package, and I also knew that I wanted to get a couple of buttons and a knob on there, in addition to the RGB LEDs (which I still wasn't sure how I was going to mount). I wanted to have the detector held at arm's length and scanned around the room, so it had to be lightweight and handheld.

For the aesthetics, I was trying to imagine something that might be created by Prof. E. Gadd from Luigi's Mansion. It's supposed to look both sophisticated and hacky. Importantly, I wanted it to look like a normal object that had some advanced functionality added to it. The flashlight package seemed like a natural fit, so I took to Amazon, looking for flashlights that looked like they had a lot of empty room on the inside.

At first, I was trying to find a more normal flashlight (๐Ÿ”ฆ), but I couldn't find anything that I thought was large enough to also have plenty of room for the LEDs that I wanted to add. I eventually came across these "spotlight flashlights", and as soon as I saw the one above, I knew that it was the right fit.

From inspection of the photos on the Amazon page, it looked like the housing of the flashlight was composed of two halves, which I figured would make it easy to add the electronics package. I also saw that the flashlight has a little storage compartment in it for storing the power cord, so this was a good indication that there may be a lot of spare room in the housing.


Ghostfinder Protip: The flashlight is just one possible packaging of the detector! My original idea was to create something like the P.K.E. Meter from Ghostbusters (one could consider buying a replica from Target and putting the Ghost Detector electronics package into that!). Really your only constraint here is the size, which is determined by how small you're able to make the electronics package.

Add a Wiring Harness to the Housing

pic1.jpg
pic2.jpg
pic3.jpg
pic4.jpg
pic5.jpg
pic6.jpg
pic7.jpg
pic8.jpg
pic9.jpg
pic10.jpg
pic11.jpg

Once you've settled on a housing, you'll want to add all of your peripherals to the housing and solder up headers to everything so that things can be easily attached to the electronics package. Collectively, I'm referring to the peripherals and the wires attached to the housing as the "wiring harness."

Here are the steps that I followed when modifying the flashlight:

  1. Open up the housing and see what all can be removed. My flashlight had a big LiPo battery, a controller board, and then a detachable white plastic bracket that holds everything. I pulled out the battery and desoldered the wires from the controller PCB so that I could remove it. I left the blub of the flashlight as-is, and I also left in the trigger, since I wanted to use it in the interface.
  2. Do a test fit to get an idea of where the electronics package will go in within the housing. It's good to figure out exactly what the orientation will be at this point. I used this to get an idea for how long I would need to make the various wires in the harness.
  3. Measure the diameter of the buttons and knobs you want to attach, and then drill holes in the housing for these. Attach buttons and knobs firmly to the housing. I ended up using two momentary switches and a rotary encoder. While doing this part, I would sometimes put the two halves back together so that I could test how the whole thing felt. This helped to pin down the best button position. Ergonomics!
  4. Add two additional holes: one big one for the USB cable to pass through and one smaller one for the RGB LED cable to pass through.
  5. Draw up a schematic for how to do the electrical connections (see what I ended up with back in Step 2). All of the momentary switches are connected to +3.3V at one end and to one of the RPi GPIO pins (via a 2 kOhm series resistor) at the other end. [NB - I just assumed that the flashlight trigger was also a momentary switch, but this would have been a good moment to confirm that with a multimeter.] The RGB LEDs require one +3.3V connection, one GND connection, and one GPIO connection. I wanted to minimize connections to the RPi, so I ended up with just one +3.3V connection, one GND connection, and 7 GPIO connections, all of which I labeled. The two sides of the shell actually share the same +3.3V connection, so there's an additional pair of headers to connect the two shells together electrically.
  6. Wire it up! There's definitely some art to this part, so I can't describe the steps exactly. Try to stay as close the edge of the housing as possible. Keep wires in tight bundles rather than letting them dangle in big loops. Use heatshrink tubing or hot glue to add insulation when necessary. You can use the thick wire from the clipped leads of resistors to make semi-rigid connections that will hold their position well. Hot glue is your absolute best friend here; when you reach a nice state with the wiring, use a bead of hot glue to tack it into place. After this, you can proceed to tug on the wires or let them go, and you know that everything before the hot glue will remain where it is. With these ideas in mind, I worked my way from all of the peripherals out to a bundle of wires with headers for each of the sides of the shell.
  7. Test all the buttons. I wrote a simple little Python script (see the repo) to read the state of all of the buttons and print their state a couple of times a second. With this script, it's easy to confirm that everything is connected and numbered correctly. I did this all at once, but a more conservative approach might have been to test all of the peripherals at an earlier stage, e.g. after soldering the first wires to the peripheral. There's never any harm from testing more often. I have to say, it's very satisfying every time I see a working button.
  8. Finally, do a rough test fit to make sure there's enough room for the electronics package. You will be very grateful for any space that you're able to make at this stage.

Close Everything Up

pic1.jpg
pic2.jpg
pic3.jpg
pic4.jpg
pic5.jpg

The whole rub here for me was my plan with the RGB LEDs. I knew that I wanted to glue those to the housing, since that was the easiest thing, but I figured that this would mean I would be unable to open up the housing non-destructively. I was worried that the ring of LEDs would break apart while trying to remove the black rubber bumper. So I wanted to make sure that I had enough access to everything that I needed from outside of the housing. Importantly, I needed to be able to (1) charge the battery of the PiSugar (requires USB-C connection) and (2) turn the PiSugar on and off (requires access to a small button on the PiSugar PCB).

At first, I had a pipe dream that I would be able to remove the electronics package without disassembling the detector. After doing some test fits, in which I tried to connect everything and close it up, I realized that there was basically zero additional room. The biggest "gotcha" for me was the height of the headers that I was using to connect to the electronics package. These take up a lot of room, and I had not been accounting for them in the fits that I was doing throughout the previous step. The length of the little USB cable was also constraining the orientation of the electronics package; I ended up having it at a funky angle.

During the test fits, it was clear that I wasn't going to have easy access to the power button or the USB-C port on the PiSugar. For the USB-C power, I just added a cable that I had lying around. For the power, I soldered two header wires in parallel with the power button on the PiSugar. With the benefit of hindsight, I should have soldered to some pads provided on the PiSugar PCB (see Step 1.4 above), but instead I did this with the cruddy iron that I had available. It was working at first, and I decided to try potting it with hot glue. This worked up until the point that I had tightened screws to attach the two shells together. I ended up having to take this power connection back out for surgery a couple of times, but I eventually got it in a fairly stable configuration. I figured that, in the worst case, I would be able to reach in and touch the actual power button with dental tools or something. For now, I just need to essentially "hot wire" the RPi0 by shorting these two wires together.

The whole thing was an incredibly tight fit. I considered opening up some holes in the housing to add more room, but eventually I found an arrangement that worked. Think of it like one of those packing puzzles, I guess. Except if you push too hard it breaks your precious solder connection and you have to take the whole thing apart again. ๐Ÿฅฒ

When you've finally tightened all of the screws, test the buttons, test the LEDs, test the audio, and test the GPU. I have simple scripts for doing all of these tests, along with some instructions for how to set up the RPi for these things, all in the repository: Julespeak/ghost-detector-9000: The Ghost Detector 9000 (github.com). Let me know if something appears to be missing, and I will add it.

Add the LED Circle

pic1.jpg

At this point, we're nearly done! The remainder is more aesthetic than technical, so there's some freedom to do different things here. At first, my thought was to make something like airplane landing lights (akin to the P.K.E. meter interface). As I was working on the housing, I started liking the idea of a ring around the front face of the flashlight. The LEDs are addressed as an array, so I thought that it would be pretty simple to do interesting circular light patterns with simple for loops.

I was also liking the interface idea of the ring having one glowing LED to show you which direction to point the detector. For this reason, I wanted to have the zeroth LED (by index of the array) be the one furthest to the right when looking at the circle from behind. I figured that having the +x direction aligned with index zero would make the math easier later on, and I think it did. (See the main python script for the various techniques.)

To actually make the light circle, I used a bead of hot glue on the outer black housing on one side of where I wanted an LED, and then I held the LED in place by hand. I arranged all of the LEDs with the ICs facing outwards since I thought this looked cooler and more science-y. After two minutes of holding the LED in place, I add a bead of hot glue to the other side and then I stick the next LED on and hold it in place for two minutes. In this process, I try to keep the wires between the modules as neat and uniform as possible; I'm going for hacky, not ugly. For the high temperature glue that I was using, I didn't need very much to make a solid connection. You may want to test on something disposable first to get an idea for how much glue you need.

The exact number of lights is not important. The direction-pointing math will work out regardless of light number. Some of the patterns may have to be adjusted, but sufficiently dazzling light shows can probably be found in all cases. It's good to plan ahead for the total number and try to keep the spacing even. The spacing at the end of my light strand is less even than the first part, and it still bugs me a bit. When you glue on the last LED, just cut the wire to separate from the remaining LEDs in the strand. When I did this, I left enough room to solder on an extension if I ever wanted to.

One could consider 3D printing a bracket to fit onto the flashlight that is meant to hold all of the LEDs. If I had fast access to a printer, I may have gone this route, but in the end, I do like the look of the LEDs just glued on there. It looks more scrappy this way, which I think better fits the vibe of the build.

I added a loop of stainless steel wire to cinch the loopy wires between the LED modules. I tried to keep everything looking neat and intentional while I do this. We're shooting for "wiring inside the DeLorean" here.

Test the Detector

pic1.jpg
pic2.jpg
pic3.jpg

If you've been following along, we've been testing pretty thoroughly throughout, but now the full Ghost Detector 9000 package should be runnable. Start this up following the description in the repo: Julespeak/ghost-detector-9000: The Ghost Detector 9000 (github.com).

When the GPU and Python interface are running, here is how you use it:

  1. Initialize the AHRS - Hold the detector in an orientation where the custom hat of the electronics package is facing upwards. Do a long press of Button #2; hold the button until the blue light circle fills and then release. Hold the detector still until the lights go from solid blue to a single blue light moving in a circle. This is the magnetometer calibration phase. Rotate the device in all directions; spin it; turn it; twist it; bop it! (Don't actually bop it.) When the LEDs go solid blue again, move the detector back into the neutral position (i.e. holding it like a normal flashlight). When the LEDs flash blue, initialization is complete.
  2. Scan objects - Press and hold the trigger while holding the detector near the object under test; a chase pattern appears on the lights as you hold the button. Release the trigger. It's probably best to scan for 10 seconds or less. When the trigger is released, the detector begins transferring measured EMF detector data and displays a circle pattern with yellow lights. When audio processing is complete, the lights turn off and the recorded audio is played back over the headphone jack. The detector does a dice roll to determine if a ghost has been detected, using the power of the measured signal as the seed for the RNG (it's very mysterious how ghosts are able to use this mechanism to present themselves, but this is a subject beyond the scope of this article). If the lights turn green and a nice sound is played, no ghosts have been detected. If the light is yellow and a phoneline disconnected sound plays, then the results are inconclusive; scan the object again. If the lights flash red and a bad sound is played, a ghost has been detected! When this happens, do not panic and remember your training. You can continue to scan objects for more ghosts or you can move on to step #3. To check the current number of ghosts that the detector is tracking, do a short press of Button #1; the detector announces the current number of ghosts over the headphones. Beware that only 5 ghost signals can currently be tracked by the detector since this helps keep the detector hardware within the spookiness limit approved by OSHA*.
  3. Hunt for ghosts - Hold the detector out in front of you at arm's length. Stand in one position and scan around with the detector like you're trying to shine the flashlight at all areas of the room around you. The detector works best when it's moved with simple, deliberate motions, instead of quick, jerky motions. When you get close to a ghost signal, a light will appear on the light circle which is pointing you in the direction of the ghost signal. Rotate the detector in the direction of the light. As you get closer to the source of the signal, more lights in the ring will be lit. The detector plays a ping sound which gets faster as you approach the correct direction. When you are pointed straight at a ghost, the lights will start to flash red; you are now "locked on" to the ghost. While locked on, press the trigger to capture the ghost. The ghost will be removed from the room, and the number of ghosts tracked by the detector will be reduced by one. (Try a short press of Button #1 to see!)
  4. Shutdown the detector - To stop the whole shebang, do a long press of the Knob; hold the Knob until the red light circle fills and then release. This will send a shutdown message to the GPU and it will also exit the Python script. Thanks for playing!


Hints:

  • In Step #3 above, you are essentially trying to find a particular orientation or heading of the detector which matches the direction of a ghost signal. All of the ghost signal coordinates are far away from the detector; imagine you are trying to point at objects in the distance. Coordinates are chosen such that they are mostly in the space in front, to the sides, and above you.
  • The heading reported by the AHRS can sometimes get funky. Occasionally this can be fixed by just zeroing the current heading, which is done with a short press of Button #2 while holding the detector in a neutral position. If this doesn't do the job, then repeat the full AHRS initialization in Step #1 above.
  • Sometimes the ghost direction lights get the vertical angle backwards (i.e. it tells you to go up instead of down). If you've played FPS games, then you're familiar with this kind of inversion, and I think it becomes intuitive after a while. I think this issue is related to calibration and probably related to the weird orientation of the electronics package, but I never really focused on it to pin it down. As I've been playing with the detector recently, I find this to be part of the challenge.
  • It's important to do AHRS initialization with gravity pointed downwards. This requirement should be fixed in future software revisions, but for now, just remember which orientation of the detector results in the custom hat of the electronics package facing upwards.


* The Office of Spooky and Haunted Affairs, not to be confused with the U.S. government agency of the same name.

Hack the Detector

pic1.jpg

If you've made it this far with your detector and you've detected and captured your first ghost, then Dr. Emmett Brown III, PhD would like to extend his congratulations on becoming an amateur paranormal investigator! Please accept the attached headshot as a prize. Feel free to print, frame, and install on your mantle.


But the detecting has only just begun! There are many cool places to go with the detector from here. I've prepared a list of several ideas for extensions with the detector. I'm putting โœ… next to ideas that I think would be good for beginners, โญ next to stuff that I think would be cool but challenging, and ๐Ÿ… next to ideas that I think are significant but rewarding projects.

  • โœ… Implement a health bar for ghosts. You have to lock on to a ghost for a few seconds before it can be captured. While locked on, the color of the LEDs slowly changes from green to red.
  • โœ… Add randomly generated parameters to the ghosts in the array. Include a ghost name, origin, type, etc. When the ghost is captured, the ghost dictionary element should be moved to a "captured ghosts" array. Print out information about the ghosts that were captured when the game is over.
  • โœ… When a ghost is detected, there could also be a dice roll to determine how many ghosts are added to the array. The ghosts could also vanish and reappear. This may be done by periodically choosing a new set of coordinates for each ghost. The frequency of the relocation should be determined by a user-selectable difficulty level.
  • โœ… Add a new button or indicator of some kind to the detector. Follow along with the existing Python script to see how to implement this. One nice idea would be to use a single-digit LCD display (or a Nixie tube!) to show the ghost count. An additional button or switch could be used to switch between detector modes (e.g. scan only versus scan with the option to generate a ghost). Such a feature could be useful for the overall illusion of the detector; you could have a secret button to push to guarantee a ghost detection so that it will go off when you scan something particularly cursed.
  • โœ…/โญ Come up with new game modes. One idea that I had was a mode that acts kind of like a Ouija board. It picks a random word and then makes you do the ghost hunt to unlock the letters one at a time. Another idea is to have different kinds of ghosts added to the array which could have different capture conditions. One potential condition is to have some ghosts require the user to pass an LED-based "Simon says" game before the ghost can be captured.
  • โœ…/โญ Implement the rotary encoder. Getting this working in isolation should be easy but integrating it into the full detector application may be a challenge. It would be useful to use the rotary encoder for navigating menus or for manipulating audio (see below). The rotary encoder could also be used during capture games to increase the challenge (e.g. require the user to use the knob to "follow" a signal while the audio is being processed).
  • โœ…/โญ Use or replace the main bulb of the flashlight. Of course, this only applies if you've also gone the flashlight way, but if you have, it would be great to do something with that light. One idea I had was replacing with a near-UV LED for a blacklight effect. A more advanced hack would be to replace the flashlight bulb with a circular screen of some kind. This could be used to display additional gimmicks related to the ghost games (e.g. show a ghost icon when a ghost is detected; show a question mark for a bad signal; etc.).
  • โญ Make the ghosts move around the room. Implement a function in the Python script that advances the ghost position based on a randomly generated velocity. Introduce a difficulty level parameter that determines the maximum allowed ghost velocity.
  • โญ Add a new I2C device. For a time, I was hoping to include a LIDAR module which used I2C communication. Something like this could be useful for mapping out the space around the user. The EmfHost of the GPU is a good template for a simple I2C device host.
  • โญ Add a speaker of some kind. The easy route would be to use a rechargeable speaker with a 3.5mm plug, but this would have to be integrated into the aesthetic of the detector. The more difficult route would be to add a transistor to one of the RPi's GPIO pins and use PWM to drive a speaker directly. One of my first ideas was to use one of those cheap greeting card speakers which I thought would give it a very tinny sound that I wanted.
  • โญ/๐Ÿ… Implement audio processing on the RPi. This could be done as post-processing in Python using scipy libraries or similar. It could also be done within the GPU, which would be a more substantial effort. I figured that the rotary encoder would be a good control for whatever audio processing system is used, e.g. the knob could be used to adjust the center frequency of a bandpass filter. My dream was to have live audio playback while the trigger is pressed where you are able to change something about the audio processing using the knob while the audio is coming in. It would likely require significant architecture changes and different libraries to enable this, but I do believe that it's doable with this hardware.
  • โญ/๐Ÿ… Run a voice detection algorithm on recorded audio data. With sufficiently noisy data, it may be possible to find spooky words. PocketSphinx is an existing portable solution for this, but I have no idea how well it will run on the RPi0. Consider getting a beefier Raspberry Pi if going this route or using calls to an external server. It may be possible to massage data to the point that it can reliably sound like certain words, which could be chosen from a predetermined list of spooky words. At the craziest level, I'm imagining training your own neural network on a bad collection of data (e.g. a bunch of different noise samples which you then label as one of a few spooky words).
  • โญ/๐Ÿ… Improve detector positioning. One of the scrapped ideas in this project was a GPS module. A GPS signal may be a good long-term correction for a positioning algorithm based on heading and accelerometer data. There exist more sophisticated IMU modules which do this kind of thing by default, so that's also an option. With some effort and know-how, it's possible to get cm-scale resolution from GPS with a nice receiver. Another positioning trick is SLAM, which may be acheivable using a LIDAR module or a camera. Improved positioning would enable tracking of ghost positions within a room; the user would be able to move around the room and get different perspectives on the ghost signals. This kind of stuff is still very interesting to me, so it will likely end up in some future project, if not a future version of the Ghost Detector.
  • โœ…/โญ/๐Ÿ… Design a new detector housing. Consider moving to a larger flashlight to provide more room for buttons and lights; this also helps when getting everything to fit if you want to lower the difficulty of that part. Consider designing a custom 3D printed housing that looks more like a professional piece of equipment. Consider going full magician and making the whole thing concealable except for a single small item, like a dowsing rod or special pendant; use an RF link to send data between the magic peripheral and the Raspberry Pi, which will be elsewhere on your person.
  • ๐Ÿ… Design a custom PCB for the whole electronics package. One hat could contain both the MPU and the ADC, in addition to the connectors required for attaching to the wiring harness. Smaller form factor connectors should be picked to make the whole thing as small as possible. With the additional space savings, it should be possible to fit it all into an even smaller housing, e.g. a more standard flashlight.
  • ๐Ÿ… Create a dedicated real time frontend. Right now, the I2C communication and the RGB LED communication are both happening using peripherals of the Broadcom chip on the Raspberry Pi. All of the AHRS math and the I2C bus sharing is done with the Rust program, so there is non-deterministic timing when the program runs (i.e. the time between reads of the MPU or updates of the quaternion are not constant). This is working well enough for now, but it could be running more consistently and faster if all of the math were being done in the real-time part. The first way I can think to implement this is by switching to either a baremetal program running on the RPi or an RTOS; I'd imagine that some big software overhauls would be required with this. My personal plan for version 2.0 of the detector (or whatever the next gimmick is) is to move to a Xilinx SoC and do all of the I/O and math on the FPGA. Follow my future projects if you're interested in seeing where that goes.


Happy hacking! ๐Ÿ‘ป๐Ÿ“ก