Sunday, July 19, 2009

The Arduino as a Sequencer

There are a number of simple projects that use the Arduino (or another ATmega168/328 platform) as a tone generator and/or sequencer. In a fit of activity one night, I realized that with a broken pair of headphones and some spare wire, I had everything I needed to make my Arduino into a fun noise generator as well.

Thus began work on the sequencer_1 code.

Sequencer_1

The first iteration of the sequencer software that I put together for my Arduino was pretty basic, re-using a lot of existing example code (such as the frequency-output function freqout). It was very simple, with all of the interesting stuff happening in the loop function:
  • check for the "record" button
  • check the status of the scale and note knobs
  • put any recorded note/scale combinations into the sequence at the current index
  • read the tempo knob
  • play the current note/scale for however long the tempo requires it to be played
  • set the speaker pin HIGH for a little while
  • then set the speaker pin LOW for a little while
  • advance the index of the sequence
It's a simple square wave emitter, taking very little code. It has a mildly annoying halt in-between steps of the sequence. This is because it has to stop the playback on the speaker pin in order to do everything else (advance the sequence, check the record button, etc). This halt manifested as audible noise, almost like a "pop." Even if you played the same tone for multiple steps in the sequence, it would be broken up by that artifact, rather than sounding like a single held note.

Sequencer_2

The second iteration of the sequencer software started to make use of the internal interrupt handlers. It attached Timer1 at a very high frequency and used it to flip the speaker pin between HIGH and LOW based on a dividing counter. The Timer2 interrupt was used at a lower frequency to service the tempo. The loop method was still used, but now it only performed the recording of the sequence. The input and output were nearly identical to the sequencer_1, except now there was no gap between the steps of the sequence-- a note could be held and would sound like a single solid tone.

Sequencer_3

Both of the previous sequencers had used a minimal number of parts, but had only been capable of outputting a square wave. I wanted to get into some analog action, so it was time to try and output a wave.

First I needed to figure out how to programmatically determine what voltage I should be attempting to produce at any given moment. I would commit an interrupt to updating the output voltage at a sampling frequency of around 10kHz. A second interrupt would act as the tempo handler. Whenever the tempo would update, it would set a global multiplier and divider pair. The divider becomes a counter which decrements each time the sampling interrupt fires. When it reaches zero, an output level is selected from a pre-defined table representing the sine wave. The index into this table is incremented by the multiplier each time the divider counter reaches zero. This has the net result of simulating a sampled wave at the appropriate frequency.

To actually convert the given calculated value into a voltage, a serial-to-parallel chip is fed the byte. When it latches, the eight-bit output is fed into a digital-to-analog converter. In my initial build, a simple R/2R ladder DAC worked out fine, but required a voltage divider on the output (to drop the signal to a normal 1.5V line-level range) as well as a passive low-pass filter to quiet down some component noise.

Code

The code so far is over at my Google Code page

Friday, May 22, 2009

Arduino Pinball Hacking

My pinball machine does not have a functional MPU. The MPU is the board that has the logic for the rules of the particular game, and it communicates with the phyisical aspects of the pinball machine (the solenoids, the lights, and the switch matrix). Without a working MPU, the pinball machine doesn't do much of anything at all. Luckily for me, replacement MPUs exist for older machines like mine, and are relatively inexpensive.

I've been messing around with the Arduino lately. It's an excellent little embedded platform for hobbyists and goofing around, and you can do serious work with it as well.

I decided that it would be pretty spiffy if I were to create an MPU replacement using an Arduino. The interfaces to the other boards (lights, solenoids) and the switch matrix is documented with great detail in the manual for the machine itself. There are full schematics, as well as a number of repair tutorials available on the internet. There was even a project to create an ISA controller card doing just what I want my Arduino to do.

I envision my project progressing as such:
  1. get a switch matrix scanning routine and associated hardware working. This will permit me to monitor the ball on the playfield from a PC connected to my Arduino via the USB cable.
  2. get a lamp refreshing routine and associated hardware working. This will permit my controlling PC to set the state of the playfield lights
  3. get a solenoid triggering routine/hardware working. This will permit my controlling PC to pop bumpers and play chimes, etc.
  4. get a score display routine/hardware working. This gets me the ability to set the scores on the back-box, and is the last piece of direct interaction.
  5. write a simple game rule set that runs on the PC that allows me to play the pinball machine
  6. figure out how to make the Arduino autonomously follow that game rule set (either a library of the hard-coded game rules, or some sort of super-simple byte-code indicating events to watch for and what to do to the score and bumpers and lights, etc)
It's auspicious, but it seems like it could be many hours of fun!

This would permit me to take off-the-shelf Bally replacement parts and create my own pinball games!

Given the above features as a "version 1.0" of the project, I've already got some "2.0" plans in my head. For instance, the hardware for the controller could act as a man-in-the-middle for an authentic MPU. It could both monitor exactly what the real MPU is doing (and report it to the PC) and it could completely override the MPU. It could trick the MPU by showing fake switch presses.

Tuesday, May 19, 2009

The Mechanical Sudoku Turk

I've come up with an excellent art/tech project just now. The basic concepts are to create a Mechanical Turk aimed at solving sudoku puzzles. A player would input the puzzle via a keypad and switches on the panel of the machine, and pull a lever. The turk would come alive and start banging and clacking and tooting and clunking as it "mechanically solved" the puzzle. The actual brains would be a simple program on an embedded platform hiding inside the console, obscured by the gearing and woodwork. Different solution steps would produce different mechanical events, set to a specific metre. If the puzzle could not be solved, then an error buzzer would fire, and it would go into "tilt" mode. Instructions on the face would indicate how to reset the tilt mode, and claim your fortune. A successful solve would play a short unique sequence of notes and emit the fortune card.

Friday, April 3, 2009

The Pinball Machine

I've inherited a Bally's Evel Knievel pinball machine. It had spent the last decade buried under some miscellaneous junk in my father's garage, but it is now sitting in a partially disassembled state in my library.

Let me start out by saying that the back-glass is in beautiful condition.

Everything else looks pretty bad. The playfield is scratched and very dirty. The protective mylar shapes that had been applied over portions of the field are worn. The rubbers are cracked in places, and the plastics are yellowing and some are slightly deformed. The MPU is dead, so I haven't tested any other components yet.

I've got a replacement rubbers set, and have begun tear-down for a full clean and wax of the playfield, and a full bulb replacement while I'm there. While it has only been in the garage for a decade or so, it's been nearly twenty years since I recall it being in a playable state, and even then most of the bulbs were burnt out, so I figure I may as well do them all now while I'm knee-deep in things.

I will be very happy if I can get it to play again. Once that's achieved, I think I may attempt to sand and re-paint the sides. I've seen numerous places online offering stencil kits for this particular machine. The hardest part would be matching the colors!

I'm having a spectacular time figuring out how it all works. Every time I make another discovery, I am amazed at how well-thought-out the whole thing is.

Please forgive me if this post lacks coherency, it's currently 11:56pm, and my brain wanted to be asleep hours ago.

Pictures of Pinball Progress

Saturday, January 3, 2009

Enhancements for IceHUD and Grid

Here are a pair of add-ons for World of Warcraft that I've been using to tweak the behavior of IceHUD and Grid.

IceHUD_HungerForBlood allows rogues to follow the duration of their HfB buff, and has some coloration niceness to see how many stacks of it you have on you. This was originally the only HfB bar for IceHUD, but now it is actually a replacement for a buggier bar that is already included.

GridOnly is a tiny mod that attaches an extra layout option to Grid, "Hide default party frames." This is for people who want to use Grid and only Grid to view party and raid membership.

Both of these are hosted over on my Google Code project.

Thursday, January 1, 2009

Talented Export Popup

If you're using the excellent World of Warcraft talent addon Talented, you may have been frustrated with its exporting feature, which will only output the URL to your talent build to the most recent chat channel. The following (extremely long) macro will take the currently selected talent tree from Talented, and will put the export URL into a popup window, where you can actually copy it.

/script StaticPopupDialogs["Z"] = {text="URL:",button2=OKAY,timeout=0,hasEditBox=1,hasWideEditBox=1,OnShow=function() getglobal(this:GetName().."WideEditBox"):SetText(Talented:ExportWowheadTemplate(Talented.template)) end}; StaticPopup_Show("Z")