hatestheinternet

Wired for Sound

Having successfully replaced Tommy's battery in an earlier bout of geekery, I decided it was time to set about making him do something useful. Since he didn't come with a remote, the first step was locomotion.

Toy remote controls really aren't that complicated. For the most part, they're hand held frequency generators that output certain tones based on certain inputs from their controls. This frequency is modulated onto (usually) a 27MHz or 49MHz carrier wave which is then demodulated by the toy and used to trigger the appropriate motors, servos, lights, etc.

Since I still couldn't say 100% whether or not Tommy worked, I decided to forego building or hacking an existing transmitter and, as you can see in the post image above, decided to do some quick MacGyvering. One of the coolest features of the Omnibot is its ability to record commands on tape and play them back, so I dug out my old cassette adapter and hooked it up to my sound board. To double check, I played some music in Songbird and his eyes flashed and he made noise just like he's supposed to. With the first hurdle cleared, I headed on to the second: Frequencies.

A while ago I'd downloaded a couple programs that could supposedly drive the Omnibot, but they didn't seem to work and I couldn't remember where I'd nabbed them to do some futzing around. Thankfully, The Old Robots Web Site has a section on programming the Ominibot with a link to a downloadable WAV of the demo tape RadioShack shipped with their Robie Sr. robots (which were essentially Omnibots in a different body). He seemed to move around and make a right mess of my desk while the demo tape played, so I fired up Soundbooth and saved out some WAVs of all his control tones. Files in hand, the next stop involved (as all true geekery tends to at some point) PERL.

I found a frequency tracking PERL module called Freqext.pm which figures out the frequency of the various samples by using the PDL::FFT module to track zero crossings. Naturally, a WAV recorded off a casette didn't show a steady frequency, but Freqext dumps its findings to a text file and they were easy enough to figure out paging through it with less.

I first debated using HTML5 for my simple remote control, but quickly slapped myself across the face and fired up Flash Builder to write a quick frequency generator in a class called Tomy. Clag aside, it took about a dozen lines:

var _freq:int = 0;

var _gen:Sound = new Sound();
_gen.addEventListener(SampleDataEvent.SAMPLE_DATA,sigGenerator);
_gen.play();

private function sigGenerator(ev:SampleDataEvent):void {
  var n:Number;
  for( var x:int=0;x<4092;x++ ) {
    n = Math.sin((x+ev.position)*_freq*2.0*Math.PI/44100);
    ev.data.writeFloat(n);
    ev.data.writeFloat(n);
  }
}

The astute among us will note that the _freq variable above is hard coded to 0, so the generator won't actually generate anything. To remedy this, I created a few useful constants with the frequencies (in Hz) from PERL:

public static const MOVE_FORWARD:int = 3275;
public static const MOVE_BACKWARD:int = 4070;
public static const MOVE_LEFT:int = 4500;
public static const MOVE_RIGHT:int = 4200;

With these in place, I just needed a way to change what the generator was doing. I made a quick crosshairs in the middle of the stage using beginFill(), drawRoundRect() and endFill(). Next, I raided the Oxygen icon set for its directional arrows and, before adding them to the stage, set their name to match the appropriate directional constant. All that was left was a quick mouse listener:

function onMouseUp(ev:MouseEvent):void {
    if( ev.target.name && ev.target.name.indexOf("MOVE_") === 0 )
      _freq = Tomy[ev.target.name];
    else
      _freq = 0;
  }
}

I attached the handler to the Stage object itself so anywhere on the screen that wasn't an arrow would serve as an "Oh Shit" button and fired it up. Everything seemed to work as expected and I was even finished in time to attach him to my X10's headphone jack and have him meet @theguelphgirl at the back door when she came home from work.

Now that Tommy is capable of running under his own steam and I've gotten a handle on how to make him actually do something the geekery can begin in earnest, so stay tuned for more Adventures with Tommy. I know, I suck at names.

Do you want to play?

For those of you who have something capable of running Flash and an old Omnibot of some kind sitting around, you can click the links below to download my ghetto controller. Note that this code is not optimized in any way, shape or form and if I were to continue down this path, my first task would be to show the frequency generator some serious love. Also note that I wouldn't even go so far as to call this code alpha level and should be used at your own risk. It worked for me on the two platforms I tested, but YMMV.

To make it go, you'll a cassette adapter (think Discman). Simply put the adapter in the tape deck (it won't close all the way, but it doesn't need to), press Play and put the robot in Program mode (the middle gray button in the group of three beside the power switch). It doesn't matter if you have the volume turned up or down, the Omnibot is smart enough to not play its control tones.

I'd imagine it would also be possible to record the tones to tape and go about it that way, but who has any of those kicking around anymore?

Code

I used to host the source and binaries for this monstrosity here, but I've since moved them to Github. Here's the link if you want to play with it: https://github.com/therealjaypo/tomy-remote. The requirements are listed in the repo's README.md.