Arduino Pong

Yeah, just a couple of resistors (the values don't have to be exact) and an RCA jack.

Make sure you have the 75() resistor correct or else you may not see anything on your tv! also check the voltages with a multi meter can save your tv from more current then nesserary or worse! Have fun

Hi everybody,

here a code derivated of arduino pong,

enjoy it,

Ops,

sorry: http://organismo.art.br/interfaces/wikka.php?wakka=ArduinoTvanalogica

Hello, I am working on an interface that converts midi signals into visuals. I based this on the arduino pong code. Now I am on the end of my ideas. the 2 parts: Midi Input Signal and Arduino pong works seperately perfekt but its so hard for me to connect them. I hope there is someone out who can help me
I did the midi input shown here: it works

#include <MIDI.h>
/*
  Basic I/O MIDI tutorial
  by Franky
  28/07/2009
*/

#define LED 13               // LED pin on Arduino board

void setup() {
  pinMode(LED, OUTPUT);
  MIDI.begin(4);                  // Launch MIDI with default options
                        // input channel is set to 4
}

void loop() {
  if (MIDI.read()) {
    digitalWrite(LED,HIGH);     // Blink the LED
    MIDI.sendNoteOn(42,127,1);  // Send a Note (pitch 42, velo 127 on channel 1)
    delay(1000);            // Wait for a second
    MIDI.sendNoteOff(42,0,1);   // Stop the note
    digitalWrite(LED,LOW);          
  }
}

here is now my code that I build :frowning:
The midi request doesn 't work. My goal is to show different pictures with different midi nots from my drumcomputer.
If Midi Note 1 and Velocity 1 arrives show Picture 1
If Midi Note 1 and Velocity 1 arrives show Picture 12
its important that the programm asks the whole time if there is a new Midi note.
....
here is the code mixed with the arduino pong code. Now I can just see 2 does because the programm steps in the following else if part

else if(midi < 40 & midi < 30)
{
digitalWrite(ledPin, HIGH);
grayPixel(5,10);
setPixel(10, 20);
//clearScreen();
}

this is the code

//Arduino Tv framebuffer
//Alastair Parker
//2007
#include <MIDI.h>
// Video out voltage levels
#define _SYNC 0x00
#define _BLACK 0x01
#define _GRAY 0x02
#define _WHITE 0x03
// dimensions of the screen
#define WIDTH 38
#define HEIGHT 14
//number of lines to display
#define DISPLAY_LINES 240
// update speed for the main loop of the game
#define UPDATE_INTERVAL 1
// maximum velocity of the ball
#define MAX_VEL 10
// time to wait while paused
#define DONE_WAITING 30
// input pins for the player pots
#define PLAYER_LEFT_PIN 2
// currently the same pin
#define PLAYER_RIGHT_PIN 3
//video pins
#define DATA_PIN 9
#define SYNC_PIN 8

int ledPin = 13;
int midi = 0;

// the video frameBuffer
byte frameBuffer[WIDTH][HEIGHT];
// loop indices
byte index, index2;
// pal video line loop
byte line;
// current drawing line in framebuffer
byte newLine;
// loop counter to for the main loop delay
int waitingCount = 0;
// if we should be waiting for something to happen
boolean waiting=true;
// value of the counter controlling the freq of updates
byte updateCounter=0;

// positions and velocity of the ball
byte ballXPos = 14;
byte ballYPos = 7;

int readMidi(){
  int midi_type = 0;

  if (MIDI.read()) {
    switch(MIDI.getType()) {            // Get the type of the message we caught
    case PC:
      midi_type = MIDI.getData1();
      return midi;
      //BlinkLed(MIDI.getData1());      // Blink the LED a number of times 
      // correponding to the program number 
      // (0 to 127, it can last a while..)
      break;
      // See the online reference for other types
    default:
      break;
    }
  }
}
void drawVisualisation(){
  int midi = 0;
  midi = readMidi();

  if(midi = 0){
    //digitalWrite(ledPin, HIGH);
    setPixel(10, 2);
  }
  else if(midi < 10 & midi > 0 )
  {
    //digitalWrite(ledPin, HIGH);
    //clearScreen();
    setPixel(10, 3);
  }
  else if(midi < 20 & midi > 10)
  {
    //digitalWrite(ledPin, HIGH);
    //clearScreen();
    setPixel(10, 4);
  }  
  else if(midi < 30 & midi > 20)
  {
    //digitalWrite(ledPin, HIGH);
    //clearScreen();
    setPixel(10, 5);
  }  
  else if(midi < 40 & midi < 30)
  {
    digitalWrite(ledPin, HIGH);
    grayPixel(5,10);
    setPixel(10, 20);
    //clearScreen();
  }
  else if(midi > 100)
  {
    //digitalWrite(ledPin, HIGH);
    //clearScreen();
    setPixel(10, 20);
    grayPixel(30,30);
  }      
}




// draw a pixel to the buffer
void setPixel(byte x,byte y)
{
  frameBuffer[x][y]= _WHITE;
}

void grayPixel(byte x, byte y)
{
  frameBuffer[x][y]= _GRAY;
}

// draw a black pixel to the buffer
void clearPixel(byte x,byte y)
{
  frameBuffer[x][y]= _BLACK;
}

// draw a paddle
void drawPaddle(byte x,byte y,byte col)
{
  frameBuffer[x][y]= col;
  frameBuffer[x][y+1]= col;
}

void drawBall(byte col)
{
  frameBuffer[ballXPos][ballYPos]=col;
}

//draw the title message
void drawArduinoPong()
{
  //arduino
  /* int counter;
   for(counter=1; counter<32;counter++){
   setPixel(counter, 10);
   //clearPixel(counter-1, 10);
   }
   
   for(counter=1; counter<32;counter++){
   setPixel(2, counter);
   //clearPixel(counter-1, 10);
   }
   for(counter=1; counter<32;counter++){
   grayPixel(4, counter);
   //clearPixel(counter-1, 10);
   } 
   for(counter=1; counter<32;counter++){
   setPixel(8, counter);
   //clearPixel(counter-1, 10);
   }
   for(counter=1; counter<32;counter++){
   grayPixel(12, counter);
   //clearPixel(counter-1, 10);
   } */
}

// clear the screen
void clearScreen()
{
  for (index = 0; index < WIDTH; index++)
    for (index2=0;index2<=HEIGHT;++index2)
    {
      frameBuffer[index][index2] = _BLACK;
    }
}



// the setup routine
void setup()
{
  MIDI.begin();                  // Launch MIDI with default options
  cli();
  pinMode (SYNC_PIN, OUTPUT);
  pinMode (DATA_PIN, OUTPUT);
  digitalWrite (SYNC_PIN, HIGH);
  digitalWrite (DATA_PIN, HIGH);
  loop();
  clearScreen();
  //drawArduinoPong();
}

void loop()
{
  // iterate over the lines on the tv
  drawVisualisation();
  for ( line =0;line< DISPLAY_LINES;++line)
  {

    // HSync
    // front porch (1.5 us)
    PORTB = _BLACK;
    delayMicroseconds(1.5);
    //sync (4.7 us)
    PORTB = _SYNC;
    delayMicroseconds(4.7);
    // breezeway (.6us) + burst (2.5us) + colour back borch (1.6 us)
    PORTB = _BLACK;
    delayMicroseconds(0.6+2.5+1.6);


    //calculate which line to draw to
    newLine = line >>4;
    delayMicroseconds(1);

    //display the array for this line
    // a loop would have been smaller, but it messes the timing up
    PORTB = frameBuffer[0][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[1][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[2][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[3][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[4][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[5][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[6][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[7][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[8][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[9][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[10][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[11][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[12][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[13][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[14][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[15][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[16][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[17][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[18][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[19][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[20][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[21][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[22][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[23][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[24][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[25][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[26][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[27][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[28][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[29][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[30][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[31][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[32][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[33][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[34][newLine];
    delayMicroseconds(1);
    PORTB = frameBuffer[35][newLine];
    delayMicroseconds(1);

    // klugdge to correct timings
    PORTB = frameBuffer[36][newLine];
    PORTB=PORTB;
    PORTB=PORTB;
    PORTB=PORTB;
    delayMicroseconds(3);
  }


  //vsync
  PORTB = _SYNC;

  // if delaying for some reason
  if(waiting)
  {
    // increment the waiting counter
    waitingCount++;
    //digitalWrite(ledPin, HIGH);
    // delay(200);
    // digitalWrite(ledPin, HIGH);
    readMidi();
    drawVisualisation();



    // wait for the remainder of the sync period
    delayMicroseconds(610);
  }
  // not waiting
  else
  {
    // increment the update delay counter
    updateCounter++;
    if( updateCounter >= UPDATE_INTERVAL)
    {

      // remainder of sync period
      delayMicroseconds(10);
      updateCounter=0;
    }
    else
      // remainder of sync period
      delayMicroseconds(250);
  }

  drawVisualisation();

}

ok i think i am very near. THX lg munki

i will try this for sure

Hi,
I'm working with an Arduino Mega which has a 16mHz Quartz, do you think it will work well, or do I have to change the code?
(Sorry for my bad English, I'm French ;D)

this is awesome!

Interesting Project...

Thank you ;D

Absolutely amazing!!!

Sorry for kicking the project, but it is worth it.

I have made this project and I have used (TIP!) two variable resistors for pin 8 (synch) and instead of the 75 Ohm. That makes it easier to reach those values.

The game works in part:

  • startup is crystal (clear)
  • playing is very bad, the problem is with the updates (they should fall between scanlines but they don't making the screen flicker)
  • between two rounds (after a 'ball' is missed) the screen is nice again.

putting UPDATE_INTERVAL to 100 helps (although it flickers after that), but the games is unplayable then...

I use CLI so that should be ok. I have a duemilanove with an 328 uC.

[UPDATE:]
It was caused by delayMicroseconds(10); around line 558. removing that made my game work at least ;).

Is the 75 Ohm resistor really needed? The linked page that explains signal generation put this resistor INSIDE the TV. The Other arduino TV-library did not recommend this resistor either!

I don't think it's neccesary for most TVs. The 75ohm resistor is implied as being in the TV.
See this thread at AVRFreaks for probably more information than you wanted (note that the resistor values are slightly different because of the inline diodes).

Hope it`s ok to bump this thread again.
I have a small problem. I get the loading image fine, and every time the game pauses I have a clear image, but when the ball moves, the screen jumps alot. I can see the paddle move, so it works aswell.
Anyone have some thoughts?

This is an awesome project, if I can get it to work I`ll make my own cases and PCB, and give as DIY-kits to my 10-12 year old cousins. "This is what we played in the old days" :slight_smile:

I just saw jopiek`s update "It was caused by delayMicroseconds(10); around line 558. removing that made my game work at least ."

It didn`t work when I removed that line. But when I changed the delay to around 75 almost all flickering was gone.

I was inspired by this post to create my own implementation of Pong with my newly acquired Arduino. Though NTSC isn't really my thing, so I made use of this awesome TV out library:

http://code.google.com/p/arduino-tvout/

It comes complete with fun intro screen with a "ball" that slowly eats away at the title (spoiler alert: it doesn't ever eat the whole thing, it checkerboards it as you might expect if you think hard about the mechanics of it) and a "Game Over" screen. Here are some more little tidbits:

  • The game plays to a score of 7 right now because I didn't feel like implementing multi-digit scores.
  • There's no color at all (just black and white). I have no idea how to make it color, since I don't know anything about how the TV interface works.
  • It can be played using one "controller" or two. I only had one potentiometer at the time, so it's configured for one controller that controls both paddles. But having two controllers should work just fine. Just alter the WHEEL_TWO_PIN setting.
  • Paddle sizes are configurable if you want to mess with that.
  • Most of the #defines can be tinkered with to alter the game experience except for "LEFT" and "RIGHT" which are used exclusively for scoring, so just ignore those.
  • There's a very simple hardware setup. I found that only a couple resistors (a 1K and 330) were required for both TVs I tested on.
    Supposedly, with minor modification, the game should work on PAL TVs. But I haven't tried it and small parts of my code are resolution-dependent, so your mileage may vary.

If you don't care to build your own, you can just check out a video here:

(note that I added the "eats away at the title" feature after making the video, so just use your imagination there).

You can see a picture of my hardware setup, along with complete source code, here:

Imgur

I'm very new to Arduino programming (only been doing in a couple weeks), so be gentle when it comes to commenting on my hardware.

Thats great PlayMoney I was going to mention my library in this thread, then you had created a full pong game on top of it, if I had a pot that did not require a screw driver to operate I would have to try it.

As far as color goes thats beyond the scope of the library, gray scale is possible with some slight modifications to the library but it would require twice as much memory.

PAL is super easy just change _NTSC to _PAL when you call begin.

Great work PlayMoney.
But I did have to insert a 75 Ohm resistor between ground and signal on the RCA connector. On a PAL tv that is.

And the speed was way to slow :D, but I found out that I could modify the "if(frame % 3 == 0)" to get different speeds

@robinh: what was the behavior before you added the 75ohm resistor? I've been trying to figure out what circumstances lead to the need for the 75ohm resisotor. How does one know they need it? Which TVs would require it? Thanks.

The behavior was no picture, only sound (I have added some basic audio out through RCA as well).

I knew it worked with 75 Ohm, cause I had used it when I breadboarded the circuit. But when I moved it over to a protoboard I tried without 75 Ohm since several people here mentioned that it wasn`t needed.

The tv is a Full HD 37"