Category Archives: Hardware

Part 1: How I got started with Arduino.

See also: Part 1, Part 1b, Part 2, and Part 3.

I remember hearing about some open-source hardware platform with a weird name a few years ago, but at the time I had little interest. I thought my hardware days were behind me, and even when they weren’t, I was never really in to hardware that much beyond soldering cables and making simple circuits. This is the story of how all this changed.

But first, allow me to regress…

In September 2012, I was helping out at a local haunted house at Sleepy Hollow Sports Park in Des Moines, Iowa. My association with them began in 2004 when they were starting to work with Festivals International to build the permanent home of the Des Moines Renaissance Faire. When they found out I was a “computer guy,” I was asked if I knew much about electronics and automation. This led me to building prop controller boxes (based on the EFX-TEK Basic Stamp Prop-1 boards) for their haunted houses.

My little boxes, built using as much off-the-shelf RadioShack stuff as possible (to allow for quick local repairs if needed), would trigger 12V solenoids that controlled pneumatic pistons to move various props or figures. We built a motion-activated gas chamber prop (complete with gas, lights, and several animations including standing up), and several other pop-up type figures. The first test-run of the gas chamber prop can be found on YouTube:

It was a great learning experience, and I wrote a BasicStamp program that allowed multitasking two (or more) prop sequences in the same box. I later found out this was written about by Jon Williams in an article found in Nuts and Volts magazine (available here as a PDF file, though he misspells my name). If there is ever any interest in BasicStamp programming, I would be happy to share more on those projects as well.

Anyway, I didn’t really do anything again with hardware until last year, instead focusing more on audio and video effects. In 2011, Sleepy Hollow brought on a local hauntrepenuer named Nathaniel who had been doing very elaborate backyard haunts in Urbandale, Iowa for years. Nathaniel introduced us to PC-based show control systems. We tested out his system by converting the “Torture Chamber” museum at the Renaissance Faire in to a computer controlled light and sound tour… And suddenly had lines never seen before at the attraction. A pre-opening test video can be found on YouTube:

The wiring of lights and speakers in the torture chamber was just the beginning. We continued to wire up the entire haunted castle (which was not open during the Renaissance Faire) and had our own Haunted Mansion style experience that October, complete with a ghostly narrator that followed guests from room to room. A duplicate computer system was used to run a pre show and some lighting effects at a new laser tag zombie shootout attraction. It was a ton of work, but a great learning experience.

And that’s where the Arduino came in. Or would, a year later.

In 2012, we did further upgrades to the torture chamber, haunted castle, and zombie shootout, and even added an all-new haunted house. The hobbyist-grade software we were using was already having difficulties keeping up. We had encountered several issues with it the past season, so we began to explore various other options. We even evaluated some high end professional products like Venue Magic. Unfortunately, there wasn’t a budget for something like that so we had to make due with cheap netbooks and whatever we could cobble together.

However, during our evaluation of Venue Magic (initially in a trial “runs forever, but cannot save” mode), I started exploring how it handled inputs. It did not support any of the input hardware we already had, so we looked in to some other solutions (in the $150 price range). They all seemed expensively complex for our needs. The cheap interfaces we had acted like simple USB serial devices, sending serial data when a switch was triggered… which gave me an idea.

At work, someone had an old Arduino Duemilanove. I borrowed it over lunch and found that it could easily act as a USB serial device, and quickly had something hacked together that would read the status of the digital input pins and emit a letter for each pin triggered. My original code looked something like this:

#define DI_PIN_START  2
#define DI_PIN_END    14
#define DI_PIN_COUNT  (DI_PIN_END-DI_PIN_START)

int pinStatus[DI_PIN_COUNT];

void setup()
{
  // Initialize the pins and pinStatus array.
  for (int thisPin=0; thisPin < DI_PIN_COUNT; thisPin++ )
  {
    pinMode(thisPin+DI_PIN_START, INPUT_PULLUP);
    pinStatus[thisPin] = digitalRead(thisPin);
  }

  // Initialize the serial port.
  Serial.begin(9600);

  while(!Serial) {
    ;
  }
}

void loop()
{
  int status = -1;

  for (int thisPin=0; thisPin < DI_PIN_COUNT; thisPin++)
  {
    status = digitalRead(thisPin+DI_PIN_START);
    // Is pin status different from last time we read it?
    if (pinStatus[thisPin]!=status)
    {
      pinStatus[thisPin] = status;
      Serial.println(char((97+thisPin)-(status*32)));
    }
  }
}

On startup, it would read and store the current state of each pin, then in a loop, if a pin changed, it would print either an UPPPERCASE or lowercase letter, based on the pin. Pressing and releasing the first pin would send “A” then “a”, for example. This proof-of-concept showed it would work, and I went down to Radio Shack and purchased my own Arduino Duo to begin experimenting.

I will share more code in future posts, and explain how that simple bit of code turned into something much more elegant.

To be continued…

Teensy 2.0 iCade source code

(Edited on 02/12/2013 to fix the source code formatting, and to add a photo.)

NOTE: There is a native method of compiling code for the Teensy, using a C compiler, but this source code was built using the Teensyduino add-on. It enables the standard Arduino IDE GUI to build code for the Teensy. You have to install the Arduino IDE first, then you install the Teensyduino add-on on top of it.

“As seen on the Teensy Project Page.”

Teensy 2.0 as an Atari 2600 joystick interface for iOS

This is my source code for the Teensy 2.0 iCade/Atari joystick interface. It could easily be made to work on an Arduino that has USB HID support (Arduino Leonardo, Esplora) and enough digital I/O pins. It is a bit bulky because I emit various status messages for testing, but I will at some point provide a stripped down version. I also have a version that uses the Debounce library which appears even smaller, but I like completely self-contained code where possible.

I have not got back to clean this up, so it includes some items commented out and such, but I wanted to provide this for those asking about it.

Or, this code could be modified to run on the new Arduino Esplora, which already has joystick buttons on it and USB HID output to act like a keyboard/mouse to whatever it’s hooked up to:

http://www.radioshack.com/product/index.jsp?productId=18450286#

Keep in mind, the Teensy 2.0 is a low power device and it seems the 20mah of the iPad is enouhg to power it (running in low power mode, no LEDs, etc.). This may not be the case with an Arduino, and they may require hooking up via a powered hub before connecting to the iPad.

//*-----------------------------------------------------------------------------

Teensy iCade Input
by Allen C. Huffman (alsplace@pobox.com)

Monitor digital inputs, then emit a USB keyboard character mapped to an iCade
button depending on the pin status. The character will be the "hold" character
for pin connected (N.O. button push) and "release" character for pin
disconnected (N.O. button released).

Pin 11 is reserved for blinking the onboard LED as a heartbeat "we are alive"
indicator.

This software was written to allow a Teensy 2.0 to interface between arcade
buttons and an iPad via USB and Camera Connector Kit.

2012-12-04 0.0 allenh - Initial version, based on my ArduinoAIDI code.

-----------------------------------------------------------------------------*/
#define VERSION "0.0"
#define LED_OFF

//#include <eeprom .h>
//#include <avr/wdt.h>

/*
iCade keyboard mappings.
See developer doc at: http://www.ionaudio.com/products/details/icade

WE     YT UF IM OG
AQ< -->DC
XZ     HR JN KP LV

Atari joystick port, looking at the male DB9 on the Atari.
See: http://old.pinouts.ru/Inputs/JoystickAtari2600_pinout.shtml

1 2 3 4 5/  Up Dn Lt Rt PA
6 7 8 9/    Bt +5  Gd PB
*/

/*
The following I/O pins will be used as digital inputs
for each specific iCade function.
*/
#define UP_PIN 0
#define DOWN_PIN 1
#define LEFT_PIN 2
#define RIGHT_PIN 3
#define BTN1_PIN 4
#define BTN2_PIN 5
#define BTN3_PIN 6
#define BTN4_PIN 7
#define BTN5_PIN 8
#define BTN6_PIN 9
#define BTN7_PIN 10
#define BTN8_PIN 12

/*
The following keys are the iCade sequence (hold, release)
for each function. Send "W" to indicate UP, and "E" when
UP is released.
*/
#define UP_KEYS "we"
#define DOWN_KEYS "xz"
#define LEFT_KEYS "aq"
#define RIGHT_KEYS "dc"
#define BTN1_KEYS "yt"
#define BTN2_KEYS "uf"
#define BTN3_KEYS "im"
#define BTN4_KEYS "og"
#define BTN5_KEYS "hr"
#define BTN6_KEYS "jn"
#define BTN7_KEYS "kp"
#define BTN8_KEYS "lv"

#define DI_PIN_COUNT 12 // 12 pins used.
#define DI_PIN_START 1  // First I/O pin.
#define DI_PIN_END 20   // Last I/O pin.

byte myPins[DI_PIN_COUNT] =
{UP_PIN, DOWN_PIN, LEFT_PIN, RIGHT_PIN,
BTN1_PIN, BTN2_PIN, BTN3_PIN, BTN4_PIN,
BTN5_PIN, BTN6_PIN, BTN7_PIN, BTN8_PIN};

char iCadeKeymap[][DI_PIN_COUNT] =
    {UP_KEYS, DOWN_KEYS, LEFT_KEYS, RIGHT_KEYS,
     BTN1_KEYS, BTN2_KEYS, BTN3_KEYS, BTN4_KEYS,
     BTN5_KEYS, BTN6_KEYS, BTN7_KEYS, BTN8_KEYS};

char iCadeDesc[][DI_PIN_COUNT] =
    {"Up", "Down", "Left", "Right",
     "Btn1", "Btn2", "Btn3", "Btn4",
     "Btn5", "Btn6", "Btn7", "Btn8"};

/* We want a very short debounce delay for an arcade controller. */
#define DI_DEBOUNCE_MS 10 // 100ms (1/10th second)

#define LED_PIN 11
#define LEDBLINK_MS 1000

/*---------------------------------------------------------------------------*/

/* For I/O pin status and debounce. */
unsigned int digitalStatus[DI_PIN_COUNT];        // Last set PIN mode.
unsigned long digitalDebounceTime[DI_PIN_COUNT]; // Debounce time.
// unsigned long digitalCounter[DI_PIN_COUNT];         // Times button pressed.
unsigned int digitalDebounceRate = DI_DEBOUNCE_MS; // Debounce rate.

/* For the blinking LED (heartbeat). */
unsigned int ledStatus = LOW;            // Last set LED mode.
unsigned long ledBlinkTime = 0;          // LED blink time.
unsigned int ledBlinkRate = LEDBLINK_MS; // LED blink rate.

unsigned int pinsOn = 0;

/*---------------------------------------------------------------------------*/

void setup()
{
    // Just in case it was left on...
    // wdt_disable();

    // Initialize the serial port.
    Serial.begin(9600);

    // Docs say this isn't necessary for Uno.
    // while(!Serial) { }

    showHeader();

    // Initialize watchdog timer for 2 seconds.
    // wdt_enable(WDTO_4S);

    // LOW POWER MODE!
    // Pins default to INPUT mode. To save power, turn them all to OUTPUT
    // initially, so only those being used will be turn on. See:
    // http://www.pjrc.com/teensy/low_power.html
    for (int thisPin = 0; thisPin < DI_PIN_COUNT; thisPin++)
    {
        pinMode(thisPin, OUTPUT);
    }

    // Disable Unused Peripherals
    ADCSRA = 0;

    // Initialize the pins and digitalPin array.
    for (int thisPin = 0; thisPin < DI_PIN_COUNT; thisPin++)
    {
        // Set pin to be digital input using pullup resistor.
        pinMode(myPins[thisPin], INPUT_PULLUP);
        // Set the current initial pin status.
        digitalStatus[thisPin] = HIGH; // digitalRead(thisPin+DI_PIN_START);
        // Clear debounce time.
        digitalDebounceTime[thisPin] = 0;
        // digitalCounter[thisPin] = 0;
    }

    // Set LED pin to output, since it has an LED we can use.
    pinMode(LED_PIN, OUTPUT);

    Serial.println("Ready.");
}

/*---------------------------------------------------------------------------*/

void loop()
{
    // Tell the watchdog timer we are still alive.
    // wdt_reset();

#ifndef LED_OFF
    // LED blinking heartbeat. Yes, we are alive.
    if ((long)(millis() - ledBlinkTime) >= 0)
    {
        // Toggle LED.
        if (ledStatus == LOW) // If LED is LOW...
        {
            ledStatus = HIGH; // ...make it HIGH.
        }
        else
        {
            ledStatus = LOW; // ...else, make it LOW.
        }
        // Set LED pin status.
        if (pinsOn == 0)
            digitalWrite(LED_PIN, ledStatus);
        // Reset "next time to toggle" time.
        ledBlinkTime = millis() + ledBlinkRate;
    }
#endif

    // Check for serial data.
    if (Serial.available() > 0)
    {
        // If data ready, read a byte.
        int incomingByte = Serial.read();
        // Parse the byte we read.
        switch (incomingByte)
        {
        case '?':
            showStatus();
            break;
        default:
            break;
        }
    }

    /*-------------------------------------------------------------------------*/

    // Loop through each Digital Input pin.
    for (int thisPin = 0; thisPin < DI_PIN_COUNT; thisPin++)
    {
        // Read the pin's current status.
        unsigned int status = digitalRead(myPins[thisPin]);

        // In pin status has changed from our last toggle...
        if (status != digitalStatus[thisPin])
        {
            // Remember when it changed, starting debounce mode.
            // If not currently in debounce mode,
            if (digitalDebounceTime[thisPin] == 0)
            {
                // Set when we can accept this as valid (debounce is considered
                // done if the time gets to this point with the status still the same).
                digitalDebounceTime[thisPin] = millis() + digitalDebounceRate;
            }

            // Check to see if we are in debounce detect mode.
            if (digitalDebounceTime[thisPin] > 0)
            {
                // Yes we are. Have we delayed long enough yet?
                if ((long)(millis() - digitalDebounceTime[thisPin]) >= 0)
                {
                    // Yes, so consider it switched.
                    // If pin is Active LOW,
                    if (status == LOW)
                    {
                        // Emit BUTTON PRESSED string.
                        Serial.print(iCadeDesc[thisPin]);
                        Serial.print(" pressed  (sending ");
                        Serial.print(iCadeKeymap[thisPin][0]);
                        Serial.println(" to iCade).");
                        Keyboard.print(iCadeKeymap[thisPin][0]);
                        // digitalCounter[thisPin]++;
                        pinsOn++;
#ifndef LED_OFF
                        digitalWrite(LED_PIN, HIGH);
#endif
                    }
                    else
                    {
                        // Emit BUTTON RELEASED string.
                        Serial.print(iCadeDesc[thisPin]);
                        Serial.print(" released (sending ");
                        Serial.print(iCadeKeymap[thisPin][1]);
                        Serial.println(" to iCade).");
                        Keyboard.print(iCadeKeymap[thisPin][1]);
                        if (pinsOn > 0)
                            pinsOn--;
                        if (pinsOn == 0)
                            digitalWrite(LED_PIN, LOW);
                    }
                    // Remember current (last set) status for this pin.
                    digitalStatus[thisPin] = status;
                    // Reset debounce time (disable, not looking any more).
                    digitalDebounceTime[thisPin] = 0;
                } // End of if ( (long)(millis()-digitalDebounceTime[thisPin]) >= 0 )

            } // End of if (digitalDebounceTime[thisPin]>0)
        }
        else // No change? Flag no change.
        {
            // If we were debouncing, we are no longer debouncing.
            digitalDebounceTime[thisPin] = 0;
        }
    } // End of (int thisPin=0; thisPin < DI_PIN_COUNT; thisPin++ )
}

/*---------------------------------------------------------------------------*/

void showHeader()
{
    int i;
    // Emit some startup stuff to the serial port.
    Serial.print("iCadeTeensy ");
    Serial.print(VERSION);
    Serial.println(" by Allen C. Huffman (alsplace@pobox.com)");
    Serial.print(DI_PIN_COUNT);
    Serial.print(" DI Pins (");
    for (i = 0; i < DI_PIN_COUNT; i++)
    {
        Serial.print(myPins[i]);
        Serial.print("=");
        Serial.print(iCadeDesc[i]);
        Serial.print(" ");
    }
    Serial.print("), ");
    Serial.print(digitalDebounceRate);
    Serial.println("ms Debounce.");
}

/*---------------------------------------------------------------------------*/

void showStatus()
{
    showDigitalInputStatus();
}

/*---------------------------------------------------------------------------*/

void showDigitalInputStatus()
{
    Serial.print("DI: ");

    for (int thisPin = 0; thisPin < DI_PIN_COUNT; thisPin++)
    {
        // Read the pin's current status.
        Serial.print(iCadeDesc[thisPin]);
        Serial.print("=");
        Serial.print(digitalRead(myPins[thisPin]));
        Serial.print(" ");
        // Serial.print(" (");
        // Serial.print(digitalCounter[thisPin]);
        // Serial.print(") ");
    }
    Serial.println("");
}

/*---------------------------------------------------------------------------*/

// End of file.

Hook an Atari 2600 joystick up to an iPad, thanks to Teensy 2.0

  • 2014/03/16 Update: The source code to this is now on GitHub. Check the Arduino link at the top of each page of this site.

“As seen on the Teensy Project Page.”

I recently gained some experience using Arduinos to control inputs in a local haunted house attraction, and that has opened up quite a world of projects. During my research, I learned about the Teensy 2.0, a cheap (starting at $16, http://www.pjrc.com/teensy/index.html) controller that is similar to Arduino, but had more I/O pins than the Arduino Uno, plus had the ability to act like a USB keyboard or mouse. This enables it to send keystrokes or mouse movements/clicks to a computer, as if it were receiving them from an input device.

So, using the $19 version of Teensy 2.0 (that has header pins) and some wires, I was able to connect my Atari Flashback 2 joystick to an iPad via the USB adapter. I wrote a small program that reads the I/O pins of the Teensy 2.0, then sends out USB keyboard commands that emulate the iCade arcade controller.

My project was noted on the Teensy 2.0 project page:

http://www.pjrc.com/teensy/projects.html

I will be posting full notes and the code as soon as I have a moment to work on it.

Teensy 2.0 as an Atari 2600 joystick interface for iOS

The tale of two Drobos

Picture if you will, two second generation (FireWire/USB) Drobo hard drive enclosures from Data Robotics. Both are connected to a Belkin hub via USB, which is then plugged in to a Late 2009 model MacBook.

Drobo 2 contains four matching Seagate ST31500341AS hard drives (7200 RPM).

Drobo 1 is in the process of being upgraded to more storage, so it currently contains three Western Digital WD20EARS 2TB “green” drives (5900 RPM) and one Seagate ST31500341AS 1.5TB hard drive (7200 RPM).

My thinking was that one I started putting in the slower “green” drives, that Drobo would be the slower of the two, so I spent days moving dormant “backup” type data to Drobo 1, and kept Drobo 2 for stuff that might need more speed (like iMovie files).

Imagine my surprise when I did a disk speed benchmark using the excellent (and free) AJA System Test. According to this program, Drobo 1 (with the slower drives) has a write speed of around 24MB/s and a read speed of around 25MB/s. (It varies slightly between subsequent reruns of the test, but these numbers are good enough for this article.)

Drobo 2 (with the four matching faster drives) is probably going to be faster, right? Or at the very least, the same speed if Drobo itself is a bottleneck. So imagine my surprise when Drobo 1 cranked out about half speed – 13MB/s write and 12MB/s read!

What gives? I re-ran the test a number of times on the different virtual drives (each Drobo is configured to show five 1TB volumes, currently). I even went as far as plugging a single Drobo directly to the MacBook and testing, and doing the same with the other one. I kept getting about half speed on the second unit.

I know the Drobo supposedly slows down when it is full, so I did some searching. Drobo 1 was in the green (after upgrading three of the 1.5TB drives to 2TB), and Drobo 2 was showing yellow.

A quick search at the Drobo website shows that they claim a slowdown happens when it goes red, due to extra work being done by the unit to find room for data. Should this also affect read speed? And neither of my units were red.

As an experiement, I moved even more data off the yellow Drobo 2, until it was also green.

I re-ran the speed test and saw only a very minor increase in speed.

So a day later I decided to create this blog entry hoping someone else may find it in a Google search and give me some thoughts on what is going on here.

But as I run the test right now, I find that both Drobos are back to reading and writing around 25 MB/s! Huh? I still expect the one with the “slower” drives to be slower, but perhaps Drobo itself is a bottleneck and faster drives really don’t help much.

What happened to return the speed after a week of slowness? Perhaps Drobo is migrating data in the background and moving things around for performance?

Does anyone know how these things work?

Magic sometimes scares me. Especially when it is protecting all my data!