Toggle navigation
Heuristic42
Blog
Opengl
Meta
Rendering
1
created
May 30 at 5:22
Calling Babel from Django for React+JSX
Sharing my frustrations so you can enjoy them too... :) As...
–
pknowles
edited
May 22 at 18:57
Microsoft Natural Ergonomic 4000 Replacement
![my old natural 4k][1] **They stopped making it!** I'm ac...
–
pknowles
comment
May 22 at 16:00
Prime Mover - Processor (final problem) [Spoilers!]
this should be fixed now
–
pknowles
edited
May 18 at 22:15
Clip Space
Clip space is a linearly dependent vector space between eye s...
–
pknowles
created
May 18 at 21:56
Clip Space
Clip space is a linearly dependent vector space between eye s...
–
pknowles
edited
May 18 at 19:50
Vector Spaces
A number of vector spaces are discussed below and widely used...
–
pknowles
edited
May 18 at 19:43
Projection Matrix
A projection is fundamental to [cameras](/8/rendering/cameras...
–
pknowles
edited
May 18 at 18:32
Matrices
Matrices are 2D arrays of numbers, grouped as such to enable ...
–
pknowles
edited
May 14 at 21:47
DerBard: Custom Split Mechanical Keyboard Prototype
In my last post I talked about a [MS Natural 4K replacement](...
–
pknowles
created
May 14 at 21:46
Matching complex shapes for a custom keyboard in Fusion360
For my [custom mechanical keyboard](/blog/55/derbard-custom-s...
–
pknowles
comment
May 8 at 0:32
Matrices
[deleted]
–
anonymous
comment
May 7 at 23:30
Microsoft Natural Ergonomic 4000 Replacement
Yes indeed :). Thanks for the reminder. I found some time to ...
–
pknowles
created
May 7 at 23:27
DerBard: Custom Split Mechanical Keyboard Prototype
In my last post I talked about a [MS Natural 4K replacement](...
–
pknowles
created
May 7 at 22:32
Anatomy of a custom keyboard
This is my quick summary and background before talking detail...
–
pknowles
comment
Apr 28 at 10:29
Microsoft Natural Ergonomic 4000 Replacement
Any update on this? I'm in the same boat as you are, have bee...
–
anonymous
comment
Mar 5 at 8:16
Matrices
[deleted]
–
anonymous
comment
Jan 4 at 16:45
Microsoft Natural Ergonomic 4000 Replacement
I currently have 3 or 4 Ergo 4Ks and use one almost every day...
–
anonymous
comment
Oct 28 '22
Microsoft Natural Ergonomic 4000 Replacement
Interesting about the Microsoft Ergonomic board! Wish they we...
–
anonymous
comment
Oct 27 '22
Microsoft Natural Ergonomic 4000 Replacement
I'm in the same boat as you. I have 3 Microsoft Ergo 4000s l...
–
anonymous
created
Oct 2 '22
Microsoft Natural Ergonomic 4000 Replacement
![my old natural 4k][1] **They stopped making it!** I'm ac...
–
pknowles
created
Sep 30 '22
PIP and the user directory
This is a quick note about python + pip best practices: ***ne...
–
pknowles
created
Jan 17 '22
Starting KDE plasma wayland with Fedora 35 and nvidia drivers
A quick bit of background: X11 is a compositor and Wayland is...
–
pknowles
comment
Jan 5 '22
Making a real EMF Reader
Wow, It is that famous Ghost buster, isn’t it?. Very unique,...
–
anonymous
edited
Jan 3 '22
Making a real EMF Reader
The game **phasmophobia** by [Kinetic Games](https://kineticg...
–
pknowles
…
View All
Log in
Making a real EMF Reader
leave this field blank to prove your humanity
Article title
*
Article revisions must have a non-empty title
Article body
*
The game **phasmophobia** by [Kinetic Games](https://kineticgames.co.uk/) ([on steam](https://store.steampowered.com/app/739630/Phasmophobia/)) is about finding and identifying a ghost. It is unique in that it's just about identifying the ghost. There is no combat. Players use various items to help narrow down which ghost it is. One item is an [EMF reader](https://phasmophobia.fandom.com/wiki/EMF_Reader) that detects ghost activity. With an ameteur electronics background and a new 3D printer I built a real one as a gift. It actually works! It will "find ghosts" (with clever use of `rand()`) and actually measure magnetic fields. ![enter image description here][1] # Details It uses a MEMS magnetometer and an arduino nano to control everything. It's powered with the insides of an off-the-shelf battery pack. It can... - Measure direction - Measure the magnetic field strength - Generate random "ghost events", which may occur at a given direction or field strength and then move! - Play a tone with a buzzer and has 5 LEDs to show the "EMF level" - Charge via USB - yes, it's bettery powered - Be re-programmed by the same USB - Change modes with the press of a button, e.g. to adjust the "sensitivity" and display debug information - Display the magnetic field strength (one debug mode) and coarse direction (3 debug modes for each plane) # Pictures ![outside][2] ![inside][3] ![button][4] # Building The 3D model was built in fusion360. You can download it on [thingiverse](https://www.thingiverse.com/thing:5185602). It's based on a few reference screenshots taken at 4k. I've included them at the bottom of the page. Scale was actually loosely based on an arduino uno before I changed plans to use a nano. Point being it's likely inaccurate but still sits comfortably in the hand. It's designed to print without support and clip together with friction. ![enter image description here][5] ![enter image description here][6] The print went surprisingly well, with the exception of the part shrinking and lifting up off the bed. This is the first large print I've done and it was a new experience. It wasn't such a problem on the base, but there's a giant gap between the the two parts at the back when they're connected. I gather a hotter bed temperature might help, but I should also give more base surface area to the model for better adhesion. ![enter image description here][7] ![enter image description here][8] The label was created by hand too. I exported a fusion360 sketch to inkscape, then adding the colored bars and text with a mixture of fonts. I printed it with a regular inkjet and covered it with clear tape before cutting it out with a hobby blade. The SVG is included in the model download. ![enter image description here][9] The most physically challenging part was probably soldering the data lines from the battery pack's micro USB plug to the arduino nano's USB cable. That this worked was one of my favorite parts of this build. There's a surprising lack of information out there about getting a rechargable power pack that works with arduino projects. I'd highly recommend this approach, but I wish off the shelf kits with a separate battery and power module/charging controller existed. The battery pack was just a cheap one I found on amazon. ![enter image description here][10] The functional button for changing modes was actually an afterthought. I had modelled the button to match the game and be pressable, but hadn't had time to think about hooking it up to a real momentary button. By chance, the battery added the perfect height to be able to sit a push button between it and the top of the device. OK, I had to file down the plastic bit of the momentary button ~1mm but then it worked perfectly. Matching the notches in the battery pack's charging board to the 3D model didn't go so well and I needed to scrape away a lot of plastic before it would sit correctly. I also ended up drilling a hole for an M2 bolt to hold the board down as friction was not enough. If I printed it again this would need reworking! I almost superglued the power switch slider and luckily forcing it one way and the other unstuck it before it dried. ![enter image description here][11] # Magnetometer There are a few devices that measure magnetic fields. Initially I bought a Hall effect sensor. This was not what I wanted and not nearly sensitive The most challenging part of the software was calibrating the magnetometer. It works great out of the box with nothing nearby, but as soon as there's a giant batter right next to the sensor suddenly all the readings are way off. ![enter image description here][12] ![enter image description here][13] I started with the simple approach of an offline calibration step. I tried MotionCal from [adafruit.com](https://learn.adafruit.com/adafruit-sensorlab-magnetometer-calibration?view=all) which gets you to run some precompiled exe from the net (fun times) but that project wasn't able to parse the samples from the serial connection that I was printing. At least this is my guess after looking at [the code](https://github.com/PaulStoffregen/MotionCal/blob/master/serialdata.c#L197). I ended up cobbling together my own calibration in a python script. This reads magnetometer samples --- three x,y,z values --- from the arduino's serial output, displays them and re-runs calibration in realtime to see what's happening. It also caches them to disk so that sampling can be done just once while reworking the calibration algorithm. Code is available on [github](https://github.com/pknowles/emf_reader). At first I tried some random sphere fitting algorithms I found online, but they were not giving satisfying results at all. Perhaps this was because they were trying to maintain direction accuracy. An accurate direction was much less important for me in this project as I mainly wanted the magnetic field strength. To this end, I used least squares to take the output of the above algorithms and arbitrarily tweak all 12 calibration values to better fit the samples to a sphere. This was done with scipy's "optimize" library, where the 12 values were a standard 3x3 matrix and x,y,z offset. The result is shown below: ![enter image description here][14] I would have loved to make the calibration keep happening dynamically over time. This is pretty simple to do but without some useful libraries such as Eigen I couldn't be bothered. There is an Eigen for Arduino (including one that is meant to fit in the limited program space of a Nano) but it's pretty involved to set up especially when it needs some STL. # Software There's not much going on in the software really. In the default state the EMF reader sits in a delay() loop, waking up randomly to trigger a ghost event. An event is either a target direction or magnitude (or a constant always-on state just for fun). The target value interpolates between two values over time to make the "ghost" appear to move. The thresholds are chosen to be near the current values to increase the chance of detection, but also require you to be moving the device around in order to "find" the ghost event. When the current measurement gets close enough to the value, it displays a reading and generates a tone. The EMF level is based on the current magnitude, but may as well just be random. Surprisingly, many electronics and wiring in walls alters the magnetic field enough for the magnitude events to be meaningful. I.e. moving the device near a wall will actually trigger a reading. In other cases, the direction reading works OK too, but it's pretty clear that it's a direction and not near some physical object in the house. For the tone, I think the frequency from the game is ~650-700hz and it wobbles a bit during a hunt. # Reference images ![enter image description here][15] ![enter image description here][16] ![enter image description here][17] ![enter image description here][18] ![enter image description here][19] [1]: https://img.heuristic42.com/img/74e8a5b99881.jpg [2]: https://img.heuristic42.com/img/61b4f000faed.jpg [3]: https://img.heuristic42.com/img/fed216813218.jpg [4]: https://img.heuristic42.com/img/c465daf0ae46.jpg [5]: https://img.heuristic42.com/img/aae3a250f736.jpg [6]: https://img.heuristic42.com/img/46d9c47fefff.jpg [7]: https://img.heuristic42.com/img/f0ccf682d218.jpg [8]: https://img.heuristic42.com/img/aecc4832c12e.jpg [9]: https://img.heuristic42.com/img/a66d6ddde375.jpg [10]: https://img.heuristic42.com/img/ad5ccfab6b4a.jpg [11]: https://img.heuristic42.com/img/126f231a7570.jpg [12]: https://img.heuristic42.com/img/47a5e4385e8c.jpg [13]: https://img.heuristic42.com/img/0f388f0930df.jpg [14]: https://img.heuristic42.com/img/d573e5e5cbb7.png [15]: https://img.heuristic42.com/img/644112b7ae7b.jpg [16]: https://img.heuristic42.com/img/fb6e5f79bc53.jpg [17]: https://img.heuristic42.com/img/38bbd2b7aad5.jpg [18]: https://img.heuristic42.com/img/1536b85bcd46.jpg [19]: https://img.heuristic42.com/img/0a9e3e860748.jpg
Toggle Preview
Edit message
*
A description of the changes made
Discard Draft
Save Draft
leave this field blank to prove your humanity
×
Flag
the thing you clicked
for moderator attention.
Reason choice:
Spam, promoting, advertising without disclosure
Rude, inappropriate, generally offensive
Too arrogant or demeaning to others
Other
Reason:
The reason for raising the flag
×
Error
Error failed to load