• Home
  • About
  • Music
  • Photos
  • Resources

Magic Just Means You’re Not Seeing The Source Code

December 29, 2014 by Devin Henkel 7 Comments

Warning: This post gets pretty detailed and bit-twiddly. So, if your eyes glaze over at the site of code, you may want to read my post about good things going on in comics, instead. 

Spoiler Alert: My Kids Are Nerds

There used to be a place called Magiquest at the local mall here in the Western Suburbs of Chicago. It was, basically, a LARP for kids – think Harry Potter meets scavenger hunt. The experience boiled down purchasing a wand for your kids to use, they got a book of quests to complete, and then they ran around a large space waving their wands at interactive displays that would react to their wand. By pointing their wand at all the correct interactive displays, kids could complete quests and collect runes on their way to leveling up and facing evermore complex quests. My kids fell in love with it.

The local version closed (I think it’s a bowling alley now), but we were fortunate enough to find one at the Great Wolf Lodge in Wisconsin Dells. My kids would have played the game all day, if we had let them. The excitement of controlling things by waving a magic wand at them was apparent. I was thinking of a way to get that same excitement closer to home.

Spoiler Alert: I Am A Big Nerd, Too…

It occurred to me that the Magiquest wands were really nothing more than single-button IR remotes. I knew they must also pass some information about the wand so that the interaction could be associated with the waver, but I was hopeful that I’d be able to find a way to at least identify a MQ wand being waved and find a way to respond to it. I decided to break the challenge down into several smaller engineering challenges.

I decided to go with a Raspberry Pi as my platform. I didn’t have any experience with the micro-computing platforms, but I did have experience with Linux, so it seemed like a more natural transition than Arduino. Plus, there were a number of libraries available to help accomplish my goals.

Challenge 1: Getting The Pi Up And Running

The first challenge was to get a Pi up and running. I splurged and bought the Radio Shack starter kit that included a Raspberry Pi B+. My reasoning was that it came with a breadboard and several sensors and controls that would eventually prove useful. You could certainly get what’s needed for less, but I wanted to start with everything I needed and this was the fastest way there. The kit comes with a NOOBS card, but I new I wanted to use the GPIO right away so I downloaded and installed Occidentalis out of the gate. After downloading the OS, I used SD Formatter to create the bootable image. I plugged the power in and hooked the Pi up to an HDMI-compatible monitor (although, I am using an HDMI > DVI adapter), inserted the card and fired up the Pi. I used the raspi-config to expand the file system and make sure my keyboard and mouse were working. After saving my config, I was greeted with the GUI for the Pi and was able to do any number of basic tasks like use the terminal and browse the web.

Check.

Challenge 2: Control An LED

Now that I had a functioning Pi, the next challenge was to be able to turn on and off an LED using shell commands. I started with this excellent tutorial from Gordon @ Drogon. Doing so requires installing the wiringPi library. I found some good instructions on how to install the library. Once the library is installed, we need to wire up an LED.

I used the ribbon cable and breakout from the Pi Starter Kit to connect to a bread board. The wiring was simple enough. I connected a ground from the breakout to the ground rail. Then, I used a 270 Ω resistor to connect the short/flat side of the LED to the ground rail. Using a jumper, I connected the positive side of the LED to breakout pin #23. The result looks like this:

one-led

At this point I was ready to test. One note, the standard mode of wiringPi has different pin numbers than the Broadcom numbers reflected here. You can set a mode that uses the BCM GPIO numbers, but I stuck with the standard PIN assignments. Gordon has a good GPIO to wiringPi reference that shows that I’m interested in wiringPi pin #4.

Side note, this diagram was created with an awesome app provided by the good folks at Fritzing.

All that was left was to type the shell commands to get 3.3V of power passed to the LED. First we need to set the mode for pin 4 to output, then we need to tell it to turn on. I opened LXTerminal on the Pi and typed:

gpio mode 4 out
gpio write 4 1

And, voila! The LED lit up. Typing,

gpio write 4 0

turned it off again.

Check.

 Challenge 3: Success Still Seems Remote

For this challenge, I needed to make some supplemental investments. First, I ordered the Sensor Pack 900 from adafruit, All I really needed was the IR sensor, which will set you back $1.95, but I got the assortment in anticipation of further projects. I also got the mini-remote, which was $4.95 but, again, you can probably use any remote you have lying around the house.

Once they arrived, I needed to update my wiring to include the IR sensor. I also knew that I wanted to distinguish between the wands, and I needed 2 outputs to make this happen. So, I added a second LED to the setup. Here’s what the result looks like.

ir-sensor

Now, all that was left was to install the necessary libraries and write the code to handle the interaction. For this, I leaned heavily on an excellent tutorial at ozzmaker.com. In addition to wiringPi, you’ll need to install LIRC and its client libraries, as well as make a couple changes to the environment config.

There are a couple of points of interest, as well. First, the file “/etc/lirc/lircd.conf” is where the magic happens. Second, irrecord is a command that helps you set up a lircd.conf file for “well-behaved” remotes. Third, the MQ wands are not well-behaved. Fourth, we start to use C as the programming language to make things happen, so you’ll need to have an up-to-date gcc compiler installed.

Finally, mode2 is a command you will get to know and love. If you stop lirc and start mode2, you can see the raw output of the IR pulses being received by the sensor. This is not important now, but will be in the next challenge.

I followed the steps of the tutorial to a T, using irrecord to capture the output of pressing 1 and 2 on the remote and replaced /etc/lirc/lircd.conf with the new file, restarted /etc/init.c/lirc and compiled an executable based on the code in the tutorial (ignoring button 3), and everything worked. I was able to press 1 and toggle the red LED, and press 2 to toggle the green LED.

Check.

 Challenge 4: Making Magic

This step was where I went most off the gilded path. I needed to break it down into sub-challenges. I needed to understand the signals the wands were sending, adjust the environment and code to support the new signals, and make sure that what I expected to happen was happening. It looked like this:

  1. Record the signals from the wands
  2. Analyze the signals from the wands to understand what they meant
  3. Adjust the lircd.conf file
  4. Edit the C code to respond accordingly
  5. Test

Step 1: Record

So, to record the output from the wands, I used mode2 mentioned in the last challenge. To help collect it, I dumped the output of mode2 into a text file to use for analysis. I did this using

mode2 -r -m -d /dev/lirc0 > wand-one-test.txt

The -r option forces raw mode, and the -m option cleans up the display to make it easier to edit later. Then, I proceeded to wave the wand at the IR sensor multiple times. The output of mode2 includes the wait time between waves, so I used Sublime Text to remove it and use Search/Replace to create a comma-delimited, one-wave-per-line version of the output. I created one for each wand and imported them into the same Excel file. That formed the basis of my analysis.

Step 2: Analyze

When I looked at the files, it became apparent what was going on. For each wand, I created a line with the MIN for all columns, a line for the MAX for all columns, and subtracted to find the range for each entry. I then found the ABS for the difference between wands to see the difference between the two wands. The output looked like this:

analysis

Up front, where the ranges seem consistent across wands, I assume this is identifying that it is a wand. Next, there is a section where the variation is not strong within the responses for each wand, but they are different between wands, so I assume that represents the identity of the wand. At the end, there is a section where there is a high degree of variation within the responses for each wand, so I assume those have to do with the particularities of each wave so they map to acceleration or orientation. The next step was to use this information to make stuff happen.

I created a second tab to calculate the average of the input coming from each wand. I’ve included the spreadsheet to use as a template in the resources section of the site.

 Step 3: Configure

The next step is to create a file to replace /etc/lirc/lircd.conf in order to have lirc listen for the right signals. The code looks like this (replace the codes with the codes from your wand:

begin remote 

   name     WANDS 
   flags    RAW_CODES 
   eps            30 
   aeps           100 

   frequency      37500

   ptrail          0 
   repeat     0     0 
   gap          110000 

      begin raw_codes

            name FIRST_WAND
               238      856      244      860      243      856
               238      865      265      848      213      861   
               236      856      242      860      239      859 
               236      861      522      631      240      859 
               237      863      233      858      235      859
               523      636      520      633      240      855 
               238      869      508      635      521      633   
               522      635      525      627      260      847   
               237      858      240      857      524      629 
               236      857      236      861      521      632 
               522      639      226      868      234      859 
               242      856      236      857      239      856   
               240      860      239      844      523      632 
               367      766      236      860      239      858 
               237      856      242      854      239      858 
               237      860      379      757      380      751   
               260      837      236      860      237      860   
               521      634      376      748      367      755 
               371      755      238

            name SECOND_WAND
               244      880      294      849      286      846   
               253      881      254      882      250      897   
               239      884      255      889      252      880   
               273      861      547      663      537      656
               235      896      539      652      535      659   
               556      655      230      888      241      890   
               538      658      546      645      242      891
               546      659      533      656      533      666
               234      898      535      660      238      898
               236      898      527      662      533      674
               223      894      539      663      249      866   
               255      879      257      879      284      851   
               273      860      250      886      542      658
               236      888      262      877      285      844
               288      848      254      879      253      879
               259      877      402      771      375      774
               250      881      546      666      236      885
               249      886      253      880      249      884
               398      766      407
                  
      end raw_codes
end remote

 

The first thing to notice is that the flags are set to RAW_CODES. This is because we are going to use the raw codes from the wands, rather than a hex value. Next, give a name to the codes for each wand that is easy to remember and use in the code that makes the whole thing work. You want to copy this file over /etc/lirc/lircd.conf and then enter:

sudo /etc/init.d/lirc restart

And, then, LIRC is running with the new codes in place.

Step 4: Code

The next step is to create an executable to make it all work. First, create a file called wands-example.c and use the following code. I started with ozzmaker’s code for the remote:

#include <wiringPi.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <lirc/lirc_client.h>
#include <time.h>

void flipLED(int led);

//the wiringPi pin numbers
#define LED1 4
#define LED2 5

#define ON 1
#define OFF 0

int main(int argc, char *argv[])
{
	struct lirc_config *config;

	//timer for buttons
	int buttonTimer = millis();

	char *code;
	char *c;

	//initiate pins
	if (wiringPiSetup () == -1)
		exit (1) ;

	pinMode (LED1, OUTPUT);
	pinMode (LED2, OUTPUT);

	//initiate lirc
	if(lirc_init("lirc",1)==-1)
		exit(EXIT_FAILURE);

	//read default lirc config at/etc/lirc/lircd.conf
	if(lirc_readconfig(NULL,&config,NULL)==0)
	{
		while(lirc_nextcode(&code)==0)
		{
			if(code==NULL) continue;{
				if(millis() - buttonTimer > 400){
					if(strstr (code,"FIRST_WAND")){
						printf("Abracadabra!\n");
						flipLED(LED1);
						buttonTimer = millis();
					}
					if(strstr (code,"SECOND_WAND")){
						printf("Alla kazam!\n");
						flipLED(LED2);
						buttonTimer = millis();
					}
				}
			}
			free(code);
		}
		lirc_freeconfig(config);
	}
	lirc_deinit();
	exit(EXIT_SUCCESS);
}

void flipLED (int led)
{
	if(digitalRead(led)==ON)
		digitalWrite(led, OFF);
	else
		digitalWrite(led, ON);
}

After the includes and defining some constants, the first thing to do is start LIRC and set up the wiringPi pins. Then, it starts listening for an event. Once an event is fired, it looks for the codes we set in the lircd.conf file for the different wands. If there’s a match on a wand, I had it fire off a message to the console, then toggle one of the LEDs. Once I saved the code, I compiled it with gcc:

gcc -o wands wand-code.c -lwiringPi -llirc_client

As ozzmaker suggests, I created an empty LIRC file the first time I ran it:

touch /etc/lirc/lircrc

Then, to run it, type:

sudo ./wands

There were no errors, so all that was left was to get the kids to grab their wands and give it a test run.

Step 5: Test

I showed the kids where the IR sensor was and told them to shake their wands at it. After a few waves, I saw “Abracadabra!” print on the screen and the green LED lit up. It took a few more waves, but the red one came on and turned off, too. So, I went in and made some adjustments to the lircd.conf file. The EPS and AEPS lines are settings that determine error thresholds. EPS is a relative percentage for error forgiveness, while AEPS is absolute in milliseconds. Making these numbers larger allows greater variations to be recognized as hits, but too large a variation would make it difficult to distinguish between the wands. After some trial and error, I landed on an EPS of 35 and an AEPS of 200. The wands now work 9 times out of 10.

Check, and… Mate!

Conclusion

This is really only the first step on a journey to bring the magic of Magiquest home. Since our original test, we’ve made some progress extending the physical computing output to control other things using the wand. I’ll write about that in another post.

Another thing I’d like to try is to create multiple lircd.conf entries for each wand and tighten up the error thresholds so we can get soft, medium, and hard waves of the wand registering and handle them differently.

The greatest part about all of this is that my kids have seen how the power of computing can extend into the real world and it has inspired them to think of new ways to use physical computing. They already have plans to make a haunted house for Halloween using the wands. I think I will probably move to Arduino sensors and use the RPi as a central server to handle event processing. That way, we can have more sensors at a lower cost, use the Pi to control physical computing outputs, and track an individual wands interactions to create sequenced events.

When all is said and done, it took me approximately a week of time after the kids went to bed to get this far. Hopefully, my experience helps you up the learning curve and get up and running even more quickly. If you have Magiquest wands and no Magiquest nearby, this opens up some possibilities to bring the magic into your home. If you do, I look forward to seeing the cool things you make happen.

Filed Under: Compelling, Innovation, Interrobang Tagged With: Magiquest, Physical Computing, Prototyping, Raspberry Pi

Follow Me

  • Instagram
  • LinkedIn
  • RSS
  • Tumblr
  • Twitter
  • YouTube

On Twitter

Tweets by @devinhenkel

Email Updates

Tags

Algolia analytics apple apps Behavioral Economics blogging Business Cosmology Culture Data design Ease-of-Use Education Facebook google humor information Innovation Interface iPad iPhone Literature Marketing and Advertising Microsoft parody Privacy process Science search Search Engines social media Social network strategy Technology television twitter VR wave Web search engine Wordle

On Google+

Google+