Made with Magic players - part 1

Background

It didn't take long for the forum users over at DoityourselfChristmas.com forum to come up with some basic software to enable an Arduino to both record and playback the infrared codes sent out during the Made with Magic shows in the Disney Parks.  Many of us got our start by taking advantage of those venerable scripts.

But getting the Arduinos to synchronize their play backs with external video players presents some challenges.  It can be hard to get both players to start at exactly the same time and, once the Arduino is playing, the clock often 'drifts' and causes things to go out of sync.  That's why it was particularly interesting when the folks from Home Imagineering posted this video to YouTube.  Check it out.  The sync is perfect.  So how can the rest of us pull off something like that?  Over the last couple of years, a lot of us have been asking that question.

Wait, doesn't the new Connect 3.0 resolve this?

Shop Disney Parks appMaybe some time in the future, using future Made with Magic devices, the 'at home' participation issue will be taken care of.  But for all of us with more than a few pre-Connect 3.0 devices, it won't be a solution.  The new devices don't seem to relay the Bluetooth commands to the older devices.  Consequently, the older stuff doesn't respond to the home broadcasts.  And preliminary tests with the new Ear Hats suggest that they don't respond that well to the codes from the previous shows.  So, for now, if you have older devices and want to glow along with recordings from the old shows, you're gonna need something other than the Connect 3.0 platform to do the deed.  On the other hand, if all you have are the new Connect Ear Hats, there's no need to read on.  The following probably won't work that well for you.  Sorry.

Searching for Sync

As I already mentioned, the Christmas show folks got after this early on.  They have come up with some solutions, but what they've come up with may not be what most us have been hoping for.  Their goals are different.  What they're looking for is a way to treat the Made with Magic targets like two simple pixels that can be controlled from one or the other of the holiday lights programmers.  To an extent, they've been more or less successful in accomplishing that goal.  Let me see if I can summarize what's been accomplished.

Made with Magic devices as simple pixels

One early approach is summarized on materdaddy's website.  As I understand it, a controller program sends out color signals to an Arduino using the Renard protocol.  The Arduino accepts the Renard signals, decodes them and maps the requested colors to the closest supported Made with Magic equivalent, then relays that request to an attached infrared emitter and on to the targeted devices.  Essentially, this is a color on/color off solution that doesn't support the entire specturm of Made with Magic's capabilities.  But it may suffice for folks creating their own shows.

More recently, djred2000 has added fade support and replaced the Arduino with a ESP8266 to handle E1.31 transport.  That's a definite improvement but still won't support all the capabilities of the Made with Magic protocol and won't help in replaying recordings of the actual Disney show codes.  That's fine since that's not the goal of the folks who are developing their own, original shows.  It's not what they are trying to accomplish.  So we need to look elsewhere for our solution.

Running players in parallel

John Storms devised a strategy that can work with the full spectrum of Made with Magic codes.  I can't seem to put my finger on his more detailed write ups right now, but I think most of it is covered in the video on the right. It works using a separate Perl script that is launched during the playback of a Light-o-Rama sequence.  The Perl script sends out signals to a infrared emitter over an ethernet network.  The Light-o-Rama program and the Perl script aren't strictly synchronized but probably stay close enough to sync as they both use the same computer clock for timing.  It seems to work OK.

So maybe this is the approach to emulate.  By running the media player and MwM player on the same computer, the clock drift problems encountered when trying to use the Arduinos as the MwM player may be less of an issue.  And using a dedicated MwM player program allows working with the actual MwM codes from the park recordings.  As a result, we get to use the full spectrum of what MwM has to offer and get more reliable sync.  Now we're getting somewhere.

The one problem with the described setup is that it tends to be a bit pricey.  The LOR software will cost around $70-140.  You'll need a computer to run that setup - but you'll need one of those to accomplish almost all proposed solutions - so that's not a big issue.  You'll need to patch into a home network and know how to do that.  The iTach IP2IR component is around $100.  That puts the cost of this setup north of $200 - to control a $30 MwM item.  And it may take a bit more geek than some folks are willing to put up with.  Hmmm.  When I think about it, the cost is not really too bad when considering the enjoyment that comes from being able to re-experience the thrills at home.  Still, it would be great to bring down that cost.  Let's see what we can do.

Kicking the tires on the Falcon Player

The combination of the relatively inexpensive Raspberry Pi board with the open source Falcon Player software has pretty much taken over the Christmas show crowd.  For good reason.  The hardware page from the Falcon Player manual explains that Raspberry can play synchronized audio/video, support interaction through the GPIO pins, serve as a pixel controller and/or drive external targets via DMX/E1.31.  Impressive.  And the Falcon Player software offers a comfortable web interface to work with. 

If we can find a way to fold in some MwM code processing into the Falcon platform, this could become an attractive platform for anyone interested in an inexpensive, multimedia enabled MwM player.  Ideally, software would make it possible to simply add a couple IR LEDs to the GPIO pins and this would be a truly inexpensive solution.  So let's see what we can do.

Setting up the Falcon Player

To setup the Falcon Player software on a Raspberry, download the zip file from GitHub.  Use a computer to format an SD card with at least 8GB and unzip the downloaded file to that card.  Grab a thumb drive to use to store files on and plug it into a USB port of the Raspberry.  Attach an HDMI cable to a TV or suitable monitor.  Transfer the SD card to the slot in the Raspberry and power up the Raspberry.  A whole bunch of Linux output should show up on the TV screen as the software gets installed.  Once you see the FPP login: prompt, you know you're done.  Look at that output and find the line that contains FPP - found IP(s).  That will give the numbers you'll need to enter into a browser to connect up to the FPP control panel.  So fire up a browser, enter those numbers as the address (include the periods!) you want to access and give it a try.  That should bring up the Falcon Player control panel.  If you have problems, check out the Falcon Player manual.

Setting up a Made with Magic player

Next thing we need is a Made with Magic player for the Raspberry.  Ideally, we'd just port one of the Arduino scripts to the Raspberry and go with that.  The Wiringpi library is installed during the Falcon installation.  That lib provides a set of tools that resemble the familiar Arduino equivalents for working with the GPIO pins and facilitates the task of porting the code from the Arduino to the Pi.  That's the good news.  The bad news is that the wiringpi PWM timings aren't reliable enough to allow for the type of bit-banging used with the Arduinos and/or ESP8266s. It's not even close for the softPWM functions. 

Bit-banging head against the wall

Not willing to give up without a fight, I noted that there is at least one available hardware PWM GPIO pin in the Raspberry that can be used.   I found a useful guide for how to use the wiringpi lib functions to setup and use that pin.  By including in a program:

    wiringPiSetup();//required to initialize wiring lib
    pinMode(1,PWM_OUTPUT);//wiring pin 1 = BCM pin 18 = header pin 12
    pwmSetMode(PWM_MODE_MS);//this mode prevents balanced mode
    pwmSetClock(252);//19.2MHz base/252 = 76kHz
    pwmSetRange(2);
    pwmWrite(1,1);//1 is 50% duty cycle of 2 range

I was able to get a 38kHz frequency measured on header pin 12 .  That looked promising.  But all attempts failed to simulate the inverted 2400 baud data by toggling pwmWrite(1,0)/pwmWrite(1,1)  in ~417usec pulses.  OK.  That was to be expected given everything written about the timing problems with the wiringpi lib.  But I had to take a shot, just in case.

The 38kHz carrier is usually the harder part to accomplish and the UART output is usually more reliable.  So it was encouraging that a 38kHZ oscillator could be setup on that GPIO pin.  That made the next thing to try was simply leaving the PWM pin oscillating and connect the anode of an IR LED (+) to the PWM pin and the cathode (-) to the TX pin and send the bytes out the UART in the usual manner.  To my surprise, that didn't work, either.  Hmmm.  Always works with an Arduino.  So?  Maybe it has something to do with the PWM pin being shared with the 3.5mm audio jack?  Wasn't using that, but maybe that had something to do with it.  Dunno.  But it looks like a simple, standalone solution is going to be harder to come with than first imagined.

Switch to pigpio lib or outsource the task to Arduino?

There's an alternative to the wiringpi library that claims to provide much better timing precision - the pigpio library.  It looks good and it's a bit easier to wrap around the described functions.  But I'm pretty committed to the Falcon setup right now and don't know how well the wiringpi and pigpio libs will peacefully coexist and/or what sort of mayhem the pigpio library might cause the rest of the Falcon Player stuff.  And if it does work, the output current from a single Pi pin is not going to be that impressive.  Additional work will be needed to amplify the weak IR signal.  The standalone approach is beginning to look less appealing.

Once the idea of generating the 38kHZ carrier by the Raspberry was abandoned, a number of external alternatives were tried, including 555 timers, 3.3V Arduinos and fiddling with serial through the GPIO pins.  Some of those did work but all were way too messy to recommend.  The best solution seems to be using a common Arduino Uno and/or Mega attached by USB cable to the Raspberry.  This approach solves a multitude of Arduino/Raspberry problems.  Not the least of which is the 3.3V/5V incompatibility.  And it seems to work. 

Here's the approach.  It starts with a previously described setup for the Arduino.  The Arduino will respond to the input from the Raspberry as if it were typed in from the serial console. It handles the character-to-byte processing and the actual IR output.  The Raspberry handles the timing aspect and transmits the raw character data to the Arduino over the USB connection.  Simple, really.  The Arduino script and the Raspberry binary/source codes are in the attached zip file, along with some other goodies I'll mention in a little bit.

Setting things up

Using a computer that is connected to the same network as the Falcon Player (which you already setup, right?), unzip the file downloaded from this link.  It contains a number of files that will help get you started.

Now, open a web browser and plunk in the ip address for the Falcon Player and bring up it's web control panel.  Navigate to the uploads page by clicking Content Setup->File Manger->Uploads Tab.  Use the Select Files Button to open where you unzipped the files on your local computer and upload the following files to the appropriate sections:

File Section
mwmplayer Uploads
mwmplayer4.c Uploads
Jinglebells360.mp4 Video
jingle_bells.mwm Uploads
jinglebells.sh Scripts
msep.mp3 Audio
MSEP_dht0009_ESP.txt Uploads
msep.sh Scripts

Next, fire up the Arduino IDE and upload the ArduinoMWMController2.ino script that's also in the file you just extracted.  This is a derivative of the script described previously, with the exception that console output is turned off, no modifications are made to the submitted codes and the serial baud rate is cranked up to 230400!  Check the previous article for setup details.  In testing, I found that one of the Uno knock offs I have could only handle 115200 baud.  A 3.3V Mini Pro couldn't muster anything more than 57600!  So, if you are having problems later on, it may be a baud rate issue.

Let's assume for the moment that the Arduino is fine with the 230400 baud rate and working as expected.  Unplug the USB cable from your computer and plug it into the USB slot on the Raspberry.  If your Raspberry power supply is sufficient, it should also power the Arduino just fine.  Head back to the Falcon Player web console on your computer, get into the File Manager Scripts tab and select the msep.sh item and hit the run button.   With any luck at all, your TV should start up and Made with Magic codes should spew out from your Arduino.  If extremely lucky, the two might even be in sync!  This is the music and codes from the Main Street Electrical Parade and was sync'd by community member Jorge.  Think kindly of him as you enjoy the show!  You could also try the jinglebells.sh script to see a video with codes, but only the first half of that video syncs reasonably with the codes.  The back half goes out of sync.  I haven't yet spent the time to fix that.

So what if things aren't in sync or, worse yet, you don't see any Made with Magic response at all?  Read on.

What to check if it doesn't work on the first try

Things are out of sync

There are lots of reasons why things may not sync for you at first.  Your Pi, and/or SD card, may not be the same speed as mine.  I developed all this using a circa 2011 Pi and whatever SD card was available at the time.  Not a highly tuned, state of the art setup.  It's likely your Pi does things quicker.  Similarly, if the aspect of the target TV isn't the same as the video to be played, the omxplayer may have to do some recoding and the time it takes to do that may vary. 

So how can the scripts be edited to adjust the delays?  This can be done from the Falcon Player control panel.  Under the scripts tab, there's an edit button.  Select the script to edit and click the edit button.  It opens the file to edit towards the bottom of the page.  It's easy to miss that.  Scroll down and you should find what needs editing.  The scripts are derivatives of the PlayVideo.sh script that came with the initial Falcon install:

----------------------------------------------------------------------------------------------

#MWMDELAY in milliseconds
MWMDELAY=3500
#BAUD RATE
BAUD=230400
#MwM file to play.
MWMFILE="jingle_bells.mwm"
#Media file to play.
MEDIAFILE="Jinglebells360.mp4"
#MEDIADELAY in seconds.  decimals for less than 1 sec
MEDIADELAY=0
#TYPE is either music or videos
TYPE="videos"

###################################################################
# Set some environment variables
. /opt/fpp/scripts/common

sudo  /home/fpp/media/upload/mwmplayer  -d $MWMDELAY  -b $BAUD -f $MWMFILE &
sleep $MEDIADELAY
sudo -u fpp /usr/bin/omxplayer --no-keys $MEDIADIR/$TYPE/$MEDIAFILE &

----------------------------------------------------------------------------------------------

I think most entries are self explanatory.  Edit the stuff above the ###### line and be mindful of the quotes and DO NOT insert any blanks before or after the = character.  If you needed to downgrade the baud rate for your Arduino, adjusting the baud rate here may be necessary to get things to start happening.

I don't see any MwM response

Baud rate changed from 230400?

As just mentioned above, editing the baud rate in the Falcon scripts might be what's needed if you're not running at 230400 baud. 

Arduino connected to different port than in the mwmplayer program?

Beyond that, it's possible that the mwmplayer is trying to access the wrong USB device.  The code is setup to try the two most likely Arduino assignments: /dev/ttyUSB0 and /dev/ttyACM0.  Both were seen while developing that script.  But you may have other devices already at those positions and may need to edit the mwmplayer4.c code and recompile it.  In the Falcon control panel, click Help->SSH Shell.  You may see something come up complaining about this being an insecure link and asking to add an exception.  Agree to all that until you come to a login prompt.  The login parameters are: user fpp and password falcon.  That should do it.  At the prompt, type in:

ls /dev/tty*

Unplug the Arduino and then run that command again and see what changed.  That should be what the system thinks is your Arduino USB connection.  You'll need that to alter the mwmplayer4.c script.  Now go back to Content Setup -> File Manager -> Uploads and select the mwmplayer4.c item and download it.  Using your favorite editor, find this part:

                //sp = serialOpen("/dev/ttyAMA0",(int)bd);//GPIO
                sp = serialOpen("/dev/ttyACM0",(int)bd);
                if(sp == -1){
                    sp = serialOpen("/dev/ttyUSB0",(int)bd);
                }
                if(sp == -1){
                    printf("couldn't connect to serial\n");
                    exit(EXIT_FAILURE);
                }
If your Arduino is at something like /dev/ttyUSB1 or /dev/ttyACM1 or some other number, make that adjustment here, and save the changes to a file on your computer with the same file name.  Then use the Falcon control panel to upload the revised mwmplayer4.c file to the Uploads section.  Now back to Help -> SSH Shell.  If you need to login again, do so.  Then type:

cd media/upload
gcc -Wall -o mwmplayer mwmplayer4.c -lwiringPi

That should recompile the mwmplayer program and get you going.

Are your infrared LEDs connected properly?

When chaining IR LEDs it's easy to get one backwards or otherwise connected improperly.  So check that to see if that is the problem.  They are, afterall, diodes and function very effectively as such when put together wrong.

Is your serial port connected to the Bluetooth module instead?

The Raspberry Pi models with Bluetooth now dedicate the better UART (PL011) to the Bluetooth module.  I see that the Falcon Player attempts to change that.  Let's make sure that got done.  Get back into the SSH Shell and check:

cat /boot/config.txt

You want to see these lines:

# Switch Pi v3 onboard serial and Bluetooth to allow DMX on Pi v3
dtoverlay=pi3-miniuart-bt

and 

cat /boot/cmdline.txt

You want to see a line with:

console=ttyAMA0

If you don't see those lines, then it's possible you're using the mini UART for serial communications and it is known to be a bit flaky.  Try decreasing the baud rate in the mwmplayer4.c script and modify the .sh scripts to see if that works.

Nothing is coming out of the TV

Most likely, the HDMI input for the Raspberry Pi isn't selected.  Check TV instructions for how to select a different HDMI input.  Usually the HDMI port numbers are on the TV where you plug in the cable.

With older Raspberrys with analog audio out ports, maybe that's where the audio is being directed?  You might give that a try and see.

Ok, So is all this worth it?

I've found this setup to work fairly well and be reasonably reliable.  Now, the question is: is it cheaper than existing solutions and worth the effort?  Let's estimate the Raspberry cost to be $35.  Add in an SD card, thumb drive, power supply and HDMI cable.  I see packages for around $60+ with all those items + a case.  OK.  Then we need an Arduino for around $10.  You'll need some IR LEDs, too.  Let's estimate $5 for those.  Add in some shipping costs and I come up with $80+ to do this if you don't already have some of the components on hand.  That's not too bad but it's still just less than the cost of three Ear Hats and only works well with older Made with Magic devices. 

It's too soon to know how the new Ear Hats can be controlled.  So maybe the best bet is to buy one of the newer Pis with Bluetooth built in just in case that turns out to be the control mode of the future.

Upcoming modifications

In an upcoming post I'll go over how to add in external triggers to fire off playbacks with things like motion detectors and/or Made with Magic wand devices by connecting them to the GPIO pins on the Raspberry.  I've been using a wand to randomly select and playback an Osborne Lights show with each click of the send button.  Now that's bringing the magic home!  Stay tuned for details.