Arduino Pac-Man part 2 – It lives!

In the first entry of this series, I discussed what led me to experimenting with video output on an Arduino UNO. Today I will begin retracing my steps of what I did on the night of February 9th, 2014, which led to be creating the basic structure of an unplanned Pac-Man style video game.

To hook video up to an Arduino, all you need is two resistors and an RCA connector. I used an old audio/video cable for a digital camera, and had to visit my local Radio Shack to pick up one of the resistors I did not already have. On the TVout project page, you will see you need 1K ohm resistor, and a 470 ohm resistor. Each resistor connects to specific pins of the Ardunio, then they are wired together on the other side and connected to the center (video) wire of the RCA cable/jack. The shield wire of the RCA cable/jack goes to the Arduino ground. That’s all there is too it. Here is a cluttered photo of how I wired things up, using an iTead Studios screw shield to make things a bit easier, and a random terminal block screw thing just to hold some wires together:

20140210-122859.jpg

To install the TVout library, visit the Google-hostred project page and download the zip file. I extracted the zip file, and then from the Arduino IDE I selected “Sketch -> Import Library -> Add Library…”

Screenshot 2014-02-09 13.09.27

After this, I was able to create a new project based on one of the included TVout examples:

Screenshot 2014-02-09 13.10.51

I built and uploaded this example project, and watched it run on the only thing I had handy with composite video input: some old video goggles I bought from a liquidator clearance years ago for dirt cheap. These low resolution displays were useless for most things, but would have more resolution than what the TVout could provide: 120×96 default.

The demo looks like this (video from YouTube user Cottees):

It lives! I must have connected the two wires and two resistors properly!

Now, with video output, the first thing I wanted to do was create my own sketch that drew something. I gutted the demo leaving just the bare lines of code:

n

#include <TVout.h>

TVout TV;

void setup()
{
  TV.begin(NTSC, 120, 96);

  TV.clear_screen();

  TV.draw_circle(TV.hres()/2,TV.vres()/2,TV.vres()/3,WHITE);
}

void loop()
{
}

This simple sketch draw a circle in the middle of the display. Once I had this working, my next thought was to test animation by making the circle bounce around the screen. I added variables to track X and Y position, and movement for X and Y (either +1 or -1, or 0 if not moving). I also added edge detection so the ball wouldn’t fly off the screen. (The TVout library appears to be coded for speed and does little if any error checking – drawing things outside of displayed screen crashed my UNO).

The circle blazed across the screen leaving a trail of pixels.

n

#include <TVout.h>

TVout TV;

void setup()
{
  TV.begin(NTSC, 120, 96);

  TV.clear_screen();
}

void loop()
{
  uint8_t  x, y;    // X and Y position of ball
  int8_t   xm, ym;  // X and Y movement of ball

  // Center of screen
  x = TV.hres()/2;
  y = TV.vres()/2;

  // Start moving to the right, and down.
  xm = 1;
  ym = 1;

  // We will do our own control loop here.
  while(1)
  {
    TV.draw_circle(x, y, 4, WHITE);

    x = x + xm;
    if (x<4 || x>TV.hres()-4) xm = -xm;
    y = y + ym;
    if (y<4 || y>TV.vres()-4) ym = -ym;
  }
}

To resolve this, I added some code to erase the circle before drawing it at a new position. This created much flickering, so I used the “wait for frame” function so I could slow things down and do the drawing/erasing at the end of a screen being updated.

n

#include <TVout.h>

TVout TV;

void setup()
{
  TV.begin(NTSC, 120, 96);

  TV.clear_screen();
}

void loop()
{
  uint8_t  x, y;    // X and Y position of ball
  int8_t   xm, ym;  // X and Y movement of ball

  // Center of screen
  x = TV.hres()/2;
  y = TV.vres()/2;

  // Start moving to the right, and down.
  xm = 1;
  ym = 1;

  // We will do our own control loop here.
  while(1)
  {
    // Wait for end of screen to be drawn.
    TV.delay_frame(1);

    // Erase circle
    TV.draw_circle(x, y, 4, BLACK);

    x = x + xm;
    if (x<4 || x>=TV.hres()-4) xm = -xm;
    y = y + ym;
    if (y<4 || y>=TV.vres()-4) ym = -ym;

    TV.draw_circle(x, y, 4, WHITE);
  }
}

Next, I wondered how many more balls I could bounce before it started to slow down. I changed my X and Y variables to arrays, and used a #define to set the number of balls. I also made a #define for the ball size, and could use this for checking the edge of the screen. If a circle size is 4, the center will be at the specified X and Y coordinate, and the circle will be drawn 4 pixels away from that. So, if you tried to “draw_circle(0, 0, 4)”, the left and top of the circle would be drawn off the screen. To adjust, X and Y should never go lower than the circle size, and should never go larger than screen width/height minus circle size. (Note the use of “BALLSIZE-1” in the example below. TVout will report the horizontal size as 120, and vertical size as 96. The pixels are actually 0-119 and 0-95, so you subtract one to get the end pixel.)

n

#include <TVout.h>

TVout TV;

#define BALLS    10 // Number of balls to bounce.
#define BALLSIZE 4  // Size of balls.

void setup()
{
  TV.begin(NTSC, 120, 96);

  TV.clear_screen();
}

void loop()
{
  uint8_t  x[BALLS], y[BALLS];    // X and Y position of ball
  int8_t   xm[BALLS], ym[BALLS];  // X and Y movement of ball
  uint8_t  i;       // counter

  // Initialize balls.
  for (i=0; i<BALLS; i++)
  {
    // Random position
    x[i] = random(BALLSIZE, TV.hres()-BALLSIZE-1);
    y[i] = random(BALLSIZE, TV.vres()-BALLSIZE-1);

    // Start moving to the right, and down.
    xm[i] = 1;
    ym[i] = 1;
  }

  // We will do our own control loop here.
  while(1)
  {
    // Wait for end of screen to be drawn.
    TV.delay_frame(1);

    for (i=0; i<BALLS; i++)
    {
      // Erase balls.
      TV.draw_circle(x[i], y[i], BALLSIZE, BLACK);

      x[i] = x[i] + xm[i];
      if (x[i]<=BALLSIZE || x[i]>TV.hres()-BALLSIZE-1) xm[i] = -xm[i];

      y[i] = y[i] + ym[i];
      if (y[i]<=BALLSIZE || y[i]>=TV.vres()-BALLSIZE-1) ym[i] = -ym[i];

      TV.draw_circle(x[i], y[i], BALLSIZE, WHITE);
    }
  }
}

Ten circles was still fast. Twenty showed some slowdown. But it still looked cool. To make it cooler, you could randomize the ball directions:

n

    // Random direction
    xm[i] = random(2)*2 - 1;
    ym[i] = random(2)*2 - 1;

The random(2) function will return 0 or 1, so multiplying that by 2 produces 0 or 2, and subtracting 1 from that produces -1 or 1. (It took me a bit to figure this out. Math is hard.)

My next thought was to put a player character on the screen and allow it to be moved by the joystick. (This could also be done by the serial console and keyboard presses.) I initially drew a square to make it look different from the circles, but then I had to do different math for screen edge detection since X and Y of a square is the top left corner. I decided to use a filled circle. I would move it around using the analog joystick.

n

#include <TVout.h>

TVout TV;

#define BALLS      10 // Number of balls to bounce.
#define BALLSIZE   4  // Size of balls.
#define PLAYERSIZE 6  // Size of player. 

#define ANALOGXPIN 0  // Pin 0 is X on iTead joystick
#define ANALOGYPIN 1  // Pin 1 is Y on iTead joystick

void setup()
{
  TV.begin(NTSC, 120, 96);
  Serial.begin(9600);

  TV.clear_screen();
}

void loop()
{
  uint8_t  x[BALLS], y[BALLS];    // X and Y position of ball
  int8_t   xm[BALLS], ym[BALLS];  // X and Y movement of ball
  uint8_t  i;       // counter

  uint8_t  px, py;                // X and Y position of player

  // Initialize balls.
  for (i=0; i<BALLS; i++)
  {
    // Random position
    x[i] = random(BALLSIZE, TV.hres()-BALLSIZE-1);
    y[i] = random(BALLSIZE, TV.vres()-BALLSIZE-1);

    // Random direction
    xm[i] = random(2)*2 - 1;
    ym[i] = random(2)*2 - 1;
  }

  // Initialize player.
  px = TV.hres()/2;
  py = TV.vres()/2;

  // We will do our own control loop here.
  while(1)
  {
    // Wait for end of screen to be drawn.
    TV.delay_frame(1);

    for (i=0; i<BALLS; i++)
    {
      // Erase balls.
      TV.draw_circle(x[i], y[i], BALLSIZE, BLACK);

      x[i] = x[i] + xm[i];
      if (x[i]<BALLSIZE || x[i]>TV.hres()-BALLSIZE-1) xm[i] = -xm[i];

      y[i] = y[i] + ym[i];
      if (y[i]<=BALLSIZE || y[i]>=TV.vres()-BALLSIZE-1) ym[i] = -ym[i];

      TV.draw_circle(x[i], y[i], BALLSIZE, WHITE);
    }

    // Erase player
    TV.draw_circle(px, py, PLAYERSIZE, BLACK, BLACK);

    // Read joystick (0-1023) and convert to screen resolution.
    px = analogRead(ANALOGXPIN)/(1024/TV.hres());
    if (px<PLAYERSIZE)
    {
      px = PLAYERSIZE;
    } else if (px>TV.hres()-PLAYERSIZE-1)
    {
      px = TV.hres()-PLAYERSIZE-1;
    }

    py = analogRead(ANALOGYPIN)/(1024/TV.vres());
    if (py<PLAYERSIZE)
    {
      py = PLAYERSIZE;
    } else if (py>TV.vres()-PLAYERSIZE-1)
    {
      py = TV.vres()-PLAYERSIZE-1;
    }

    // Draw player.
    TV.draw_circle(px, py, PLAYERSIZE, WHITE, WHITE);
  }
}

At this point, I was starting to think a simple game might be “dodge the circles” and the player would see how long they could survive moving their larger filled circle around while trying to avoid all the bouncing, smaller circles.

But I wasn’t done experimenting with TVout yet. There was still more it could do, with bitmaps, to draw things that weren’t just lines or circles.

Next time, I will discuss how I turned my filled circle in to a simple Pac-Man type character, which made the rest of the night turn in to an attempt to recreate that game.

Arduino Pac-Man project

See also: part 1, part 2, part 3, part 4, part 5, part 6, part 7, part 8, part 9 and part 10.

Here is a quick demo of something I wrote last night for an Arduino UNO. I have an iTead Studios Screw Shield attached to it ($3.50, to simplify hooking up wires), and an iTead Joystick Shield ($4.50, for input). Then, using only two resistors and an RCA cable, plus a clever library, I was able to start programming a Pac-Man style game on the Arduino. This is the first of a multi-part series of articles explaining the steps in this project.

When I first began playing with an Arduinio Duemilanove at work in 2012,  I learned how to program it by reading through the reference material at the main Arduino website. I had heard of Arduino, but had never learned anything about it, so I was quite impressed with all the various libraries that were available to handle everything from serial communication to I2C protocol. One of the more surprising discoveries was that you could do  video output by wiring up two resistors to an RCA phono jack. Clever programming allowed the Arduino to create the scan line signals that would produce a low resolution black and white composite video screen. Here is the information page on it, showing a simple diagram of how you wire things up:

http://playground.arduino.cc/Main/TVout

At the time, I thought we might be able to use low-cost Arduinos to output some information displays at a local haunted house event (wait times, “now serving” queue management systems, etc.) but I never pursued it.

Later, I found out about two projects that were based on this TVout concept to produce retro Arduino video games: Hackvision, and the Video Game Shield.

The Hackvision was a custom Arduino device (based around the UNO) with directional and fire buttons right on the circuit board, as well as RCA jacks for audio and video output. It is currently available in a kit for $33.95, or fully assembled for $43.95.

The Video Game Shield is an add-on shield for an Arduino UNO that provided RCA jacks for audio and video output, as well as connectors for two Nintendo Wii nunchuck controllers. It is available in a kit for $22.50.

A third, similar project, called the Gamby, is a shield that includes a low resolution LCD display as well as bottoms, and turns an Arduinio in to a portable Gameboy-style gaming device. It is available in a kit for $25.

If you visit the project websites, you will find some example videos of games written for these add-ons. Due to the different ways that input is handled, games written for one platform do not play on the others (and I think the Gamby has a different video system). It does appear that games written for the generic TVout library are easily ported between systems.

Some of the games that have been written include clones of Space Invaders, Pong, Tetris, and Asteroids. The Gamby site has quite a few other titles (like a Joust clone) that I do not think have been ported to the other platforms.

I have recently become re-interested in retro video games. Two  retro video arcades have recently opened here in Des Moines, Iowa. (UP-DOWN opened in October 2013, followed by  Barcadium opened in January 2014.) Being able to step back in time and play games like Space Invaders (1978) and Pac-Man (1980) makes me feel both young again, and very old, as I realize most of the visitors to these arcades were not even born when I was first inserting quarters in these machines when they were brand new.

This led me to dusting off the old MAME emulator and once again exploring various classic arcade games. I was particularly intrigued by some of the late 1970s games that came out before the arcade scene got popular. These games used low resolution, black and white graphics and simple sound effects. I couldn’t help but think “I could have written this.” But back then, “no one” had a computer – especially not some seven year old kid growing up in Houston, Texas (like I was). So no, I could not have written any of those games, back then, two decades later, I did create and sell my own Space Invaders clone for the Radio Shack Color Computer running under OS-9. If I could have done that in 1978, maybe I would be a millionaire right now ;-)

Up next: It lives!

OUYA as a retro arcade emulator (MAME, etc.)

I sometimes get things from Amazon.com to write reviews about. I will be doing a review on the OUYA “game machine” soon, but wanted to start documenting some technical things here.

OUYA is a cheap ($99 list price) Android based game console:

It is about the shape and size of a Rubik’s Cube, and it comes with a wireless joypad that looks like a Playstation or Xbox style controller. It has a power supply and HDMI cable included, and batteries for the remote. What they include for “documentation” doesn’t even tell you where the batteries go.

Installing batteries requires popping off the joystick palm covers on the left and right side. Here is a site that explained how to do this:

https://support.ouya.tv/entries/24235612-Where-do-I-insert-the-batteries-

Once you hook the box up to a TV using the HDMI cable, you power it up (note: the power switch goes on top; I had mine upside down for the first day I had it), and then use the joypad to hook it up to your WiFi network. (Tip: Make an OUYA account, which you will need, on a computer beforehand. It will be much easier than using the joypad.)

The system will want to download software updates. Mine spent hours, appearing to just be stuck. I started it over and over, and eventually it worked, and the system restarted so I could use it.

The next steps will be installing emulators (MAME4droid, and various others), and a file manager utility (pwnfile). I also installed an FTP server (easier for me than copying files over from a USB stick) but if you plan to have your game ROMs on a USB stick, you won’t need anything else, really.

I will document some of the things I ran in to, and how I got all the files configured.

More to come…

2014 Arduino projects for Halloween

I have been tasked with creating two control systems for some Halloween attractions this year. I have a small budget for building the prototypes, and if they work, then I will be building a dozen or so of the units. I thought it might be fun to document the entire process here.

There are two projects:

1. A device will sense motion, then begin playing sound and toggle four outlets in a sequence that goes along with the audio.

2. A device will sense its location, and play a specific sound based on that location. It will have a fallback mode where buttons will trigger the sounds, for manual operation.

I plan to use low-cost Arduinos since there are many add-on Shields available for it to handle things like this.

Audio could be played in high quality using a cheap ($20) MP3 add-on, or, with a small amount of hardware (and a cheap SD card reader), lower quality audio can be played directly by the Arduino.

For triggering, the I/O pins will be used, hooked to a motion sensor. For the proximity sensor, I am researching iBeacon style tech (BLE, bluetooth low energy) or IR (infrared). Right now, it seems we could use cheap IR remotes, with a button taped down beaming and endless pulse. The Arduino can hook up a $1 IR receiver and software could decode the pulses to see which zone it is in.

For the outlets, there are $8 high voltage relay boards that can be wired to the Arduino’s Digital Out pins, and even a cheap $7.50 4-channel relay shield that can handle 120 volts 3 amps on each relay. The Shield is a nice idea, but dumping 120V in to the Arduino could be a problem if there was any kind of short.

I will document the various products I have found so far, soon.

To be continue…

TRON arcade game joystick research

  • 2014/01/28: Updated information on 4-way restrictor for flight stick.
  • 2015/02/18: A note about the HAPP joystick, and restrictor plates being made for it.

A friend of mine is in the process of building a custom arcade controller for home use. Here is some of the research that may be of interest to others trying to replicate the 1982 TRON arcade game controls. (A flight stick with a trigger button, and a paddle spinner controller).

The TRON handle can be bought from Groovy Game Gear. They claim they are using the original molds and also used the original color key chip to match the color as close as possible to the originals that were made in 1982:

http://groovygamegear.com/webstore/index.php?main_page=product_info&products_id=319

This handle is designed to replace the one for an original arcade stick, but folks have been modifying other types of joysticks to make it attach. No details on this, yet.

Next, there is a low-cost trigger stick from RetroCade.us. It is available in several places:

$20 – Paradise Arcade Shop in Hawaii:

http://www.paradisearcadeshop.com/imported-joysticks/299-import-flight-stick.html

They also sell it on Amazon.com, for $22, but shipping is cheaper there (currently $26.83 for the stick and shipping):

RetroCade.us also sells it direct through Holland Computers:

http://www.hollandcomputers.com/store/pc/Arcade-flight-yoke-stick-Joystick-eight-way-joystick-with-two-fire-buttons-and-firm-grip-p8069.htm

The stick is incorrectly described (on Amazon and at Holland) as a 4/8 way switchable stick. It is not. You need a restrictor plate to make it 4-way like the arcade TRON stick is. I have not located a restrictor plate for this joystick yet, but Paradise Arcade Shop says they may be able to custom make one.

Update: There is also a higher priced HAPP joystick commonly used for TRON:

http://forum.arcadecontrols.com/index.php?topic=78233.0

That stick is also an 8-way, but my same friend who is building the custom arcade controller now has a 3-D printer and has designed a 4-way restrictor plate for this. He will be offering them for sale, so contact me if you are interested.

As for spinner controllers, there seems to be two candidates. One is sold by Groovy Game Gear. It is the Turbo Twist 2 and it runs about $70:

http://groovygamegear.com/webstore/index.php?main_page=product_info&products_id=268

Ultimarc also sells a spinner for the same price called the SpinTrak:

http://www.ultimarc.com/SpinTrak.html

No details on which one is better for this purpose.

More to come…

Adafruit EZ-Key makes Bluetooth keyboard support cheap ($20)

Check this out — the new EZ-Key module from Adafruit:

http://www.adafruit.com/products/1535

This tiny device is a “ready to use” Bluetooth interface. Give it power, and then hook up to 12 (?) switches and when they are switched, a keyboard signal will be sent out via Bluetooth. The device can also be reprogrammed to send different keystrokes for each switch, or hooked to a micro (like Arduino or Teensy) and used to send whatever you want, such as iCade “key up, key down” characters.

As soon as I get one to review, I will post more details.

Back to work… Soon… Arduino arcade interface.

Last August, I got very busy with side jobs that kept me from working on any of these Arduino-related projects. I hope to get back to work on them soon. Right now, I pretty much don’t work on anything unless it’s tied to generating some form of income.

I hope to get around to posting the work I did on a USB joystick to iCade interface. The code used an Arduino with USB HID support (Leonardo, I believe), and a cheap USB Host add-on shield. A standard USB Playstation style joystick could be plugged in, then it would emit USB keypresses that match the iCade protocol. Ultimately, I want this code to be configurable, so you could open up a USB serial console on a host computer and walk through text menus to configure what you want each joystick button to send (similar to programming MAME input controls). That way, it would work with “anything”.

I also want it to accept standard key inputs (like the XArcade Tankstick emits) and convert them, as well, allowing it to basically convert anything to an iCade format.

With the recent discovery of a $20 USB HID transmitter from ADAFruit (http://www.adafruit.com/products/1535), it would now be possible to make it send the iCade commands via Bluetooth, though this is not plug-n-play. Ultimately, I’d like to see that part made in to an Arduino shield. The requirement of soldering and complex wiring kills these things from being used by casual hobbyists.

More to come…

UltraProjector (v1) and Mac and ffmpeg

I have previously been able to convert video files to work with the UltraProjector using an old (2006) copy of “mencoder”. I now have been able to do it using the standard “ffmpeg” command. Here are the options, and I will try to clean them up and explain later:

I downloaded the “ffmpeg” command line utility from here:

http://www.evermeet.cx/ffmpeg/

And these are the options I was using to convert an MPEG4 video file to an AVI file that plays on the UltraProjector:

ffmpeg -i creepy.mp4 -c:v libxvid -vtag XVID -r 24 -b:a 128K -ar 44100 -acodec mp2 -b:v 512k -s qvga creepy.avi

  • -c:v libxvid … use the xvid video converter
  • -vtag XVID … put “XVID” as the video tag inside the file (not sure if this is necessary)
  • -r 24 … 24 fps (higher frame rate may work for simple videos, but may play slower)
  • -b:a 128k … audio quality 128kbits
  • -ar 44100 … audio sample rate 44khz
  • -acodec mp2 … audio codec MP2 (not sure if it handles other formats or not)
  • -b:v 512K … max video bitrate. Experiment with larger numbers for better video, but at some point it will break.
  • -s qvga … output size to 320×240