Wednesday, September 18, 2013

Slow Going Slow

Here is a much anticipated update for my 0 followers and 0 page hits per day.

I laid out the perf board and decided to commit... so I soldered the LEDs, resistors and sockets to the board.

Here is a photo with my rough draft, rats nest wiring diagram. The LEDs are on the other side so they poke out through the 6 holes in the front of the dartboard where the buttons used to be.



 I need to go back to my nice Fritzing diagram to make sure I have everything going to the right place.  I kinda reversed the sides of the duino, so I'll have to update the sketch code to use some different pins, but shouldn't be a big deal... as long as I get the dartboard ribbon connectors in the right order, everything else should be easy enough to adjust.

3 challenges:
1) wiring this up without screwing up
2) the USB mini connector was too large to fit inside the dartboard case when plugged into the duino the way i have it set up
3) since i used a socket for the microprocessor on the duino, this board is a little too tall, so the back cover of the dartboard won't go on

My plans:
1) don't screw it up
2) I bought a left-angle mini USB cable from Star Tech that fits perfectly
3) ugh. I guess I'll cut a window out of the cover and use spacers or something.  Maybe I'll think of something else.  I'll have to consider that it has to hang back up flush against a wall and get hit by darts.

Still need to work on the pygame.

Thursday, September 12, 2013

LED LED LED LED LED LED

I dug up 2 red, 2 yellow and 2 green LEDs, 6 220 Ohm resistors and added them to the dartboard interface.  They are wired to the remaining 6 output pins on the second of the daisy chained 74HC595s.

Then I updated the duino sketch to light them up as status indicators: one set to indicate that the board is connected to the game server and the other to indicate that the game is being played.

I loosely tied these to the existing gamestate and command processing functionality, so both are red by default.  The connected indicator goes to yellow for 1 second when a connection command is received from the game server, then to green when the gamestate goes to stopped.

The playing indicator goes to yellow for a second when a play command is received and then to green when the gamestate is playing.... when playing, these are set along with the matrix row being pinged in the game loop.

So I added these variables:

// status light shift register values (logical and with shiftRows1)
byte connectedRed = 1;
byte connectedYellow = 2;
byte connectedGreen = 4;


byte playingRed = 8;
byte playingYellow = 16;
byte playingGreen = 32;

which work together with these:

// data to send to shift register for each board row/pin
byte shiftRows1[10] = {64,128,0,0,0,0,0,0,0,0};
byte shiftRows2[10] = {0,0,1,2,4,8,16,32,64,128};

I added a new method to set these LEDs:

void setStatusLEDs(byte state) {
  boolean setLEDs = false;
  byte connectedStatus = 0;
  byte playingStatus = 0;
  
  switch (state) {
    case IFACE_HIT:
      connectedStatus = connectedGreen;
      playingStatus = playingYellow;
      setLEDs = true;
      break;
    case IFACE_CONNECT:
      connectedStatus = connectedYellow;
      playingStatus = playingRed;
      setLEDs = true;
      break;
    case IFACE_DISCONNECT:
      connectedStatus = connectedRed;
      playingStatus = playingRed;
      setLEDs = true;
      break;
    case IFACE_PLAY:
      setLEDs = false;
      break;
    case IFACE_STOP:
      connectedStatus = connectedGreen;
      playingStatus = playingRed;
      setLEDs = true;
      break;
    default:
      setLEDs = false;
  }
  
  if (setLEDs) {
    // take the shift out latchPin low to shift it out
    digitalWrite(LATCH_SIPO, LOW);
    
    // shift out the bits (assume we're connected and playing if we're doing this at all):
    shiftOut(DATA_SIPO, CLOCK_SIPO, MSBFIRST, connectedStatus + playingStatus);
    shiftOut(DATA_SIPO, CLOCK_SIPO, MSBFIRST, 0);
    
    //take the shift out latch pin high so the voltage is sent
    // to the next row (or none if looking at the first 2 rows):
    digitalWrite(LATCH_SIPO, HIGH);
  }
}

Which I call in the main loop if the gamestate isn't play:

// the loop routine runs over and over again forever and ever and ever:
void loop() {
  if (gameState == IFACE_PLAY) {
    // check for a hit
    for (int row=0; row < 10; row++) {
       setSipoRow(row);
       processPisoColumns(row);
    }
  }
  else {
    setStatusLEDs(gameState);
    delay(1000);
  }
}

If the gamestate is playing, I added the green lights to the shiftout that iterates over the matrix rows:

// sets the SIPO shift register to power the correct row
void setSipoRow(int rowNumber) {
  // take the shift out latchPin low to shift it out
  digitalWrite(LATCH_SIPO, LOW);
  
  // shift out the bits (assume we're connected and playing if we're doing this at all):
  shiftOut(DATA_SIPO, CLOCK_SIPO, MSBFIRST, shiftRows1[rowNumber] + connectedGreen + playingGreen);
  shiftOut(DATA_SIPO, CLOCK_SIPO, MSBFIRST, shiftRows2[rowNumber]);
  
  //take the shift out latch pin high so the voltage is sent
  // to the next row (or none if looking at the first 2 rows):
  digitalWrite(LATCH_SIPO, HIGH);
}

And when a command is processed which changes the gamestate, i set the lights to yellow for a second when transitioning between red and green:

// automatically called between loops when serial data is available
void serialEvent() {
    switch (Serial.read()) {
      case IFACE_QUERY_STATE:
        Serial.print(gameState);
        break;
      case IFACE_CONNECT:
        if (gameState == IFACE_DISCONNECT) {
          setStatusLEDs(IFACE_CONNECT);  // sets connected LED to yellow for a sec
          delay(1000);
          gameState = IFACE_STOP;
          Serial.write(IFACE_CONNECT);
        }
        break;
      case IFACE_DISCONNECT:
        if (gameState != IFACE_DISCONNECT) {
          setStatusLEDs(IFACE_CONNECT);  // sets connected LED to yellow for a sec
          delay(1000);
          gameState = IFACE_DISCONNECT;
          Serial.write(IFACE_DISCONNECT);
        }
        break;
      case IFACE_PLAY:
        if (gameState == IFACE_STOP) {
          setStatusLEDs(IFACE_HIT);  // sets play LED to yellow for a sec
          delay(1000);
          gameState = IFACE_PLAY;
          Serial.write(IFACE_PLAY);
          playCharge();
        }
        break;
      case IFACE_STOP:
        if (gameState == IFACE_PLAY) {
          setStatusLEDs(IFACE_HIT);  // sets play LED to yellow for a sec
          delay(1000);
          gameState = IFACE_STOP;
          Serial.write(IFACE_STOP);
        }
        break;
      default:
        break;  
    }
}

The updated sketch is in git.

I also downloaded Fritzing to try to make some nicer circuit diagrams and came up with this one for the dartboard interface:


They didn't have a part for the boarduino, so I used the Arduino Micro.  They didn't have a part for the 74HC589, so I created my own, based on the 74HC595 included in the core parts list.  I used Inkscape to work on the SVG files required for the Fritzing parts.  The Fritzing diagram and the custom part are both in git.  I started to work on a custom USB Boarduino part but don't know if I will have the time and patience to finish it.

I think Fritzing is beyond cool.

I also cut down my perfboard/pcb to the same size as the original in the dartboard, marked off the mounting screws and posts from the original and used an x-acto to make 4 holes for the posts and screws on either end.  It fits rather nicely, so now I just need to figure out how to fit all my components on there and wire it up.



Wednesday, September 11, 2013

Mmmmmmm, Pi - Another Milestone

Got the Raspberry Pi yesterday.  I had already downloaded an installation disk image (NOOBS) and saved it to an 8GB sans disk (following the quick start guide).  It was easy as.... well, something very easy.

When I got the Pi, I plugged in keyboard and mouse to 2 USBs, HDMI from Pi to TV, and network cable... then the mini USB power adapter.  It started right up and went through configuration screens.  I enabled SSH and changed everything from the UK to my locale and changed my password, then did the updates.  Everything worked just swell.

It already has Python installed and Pygame and git.  I opened a terminal window and installed the python package manager, pip:

sudo apt-get install python-pip

Then the python web framework, Flask, since I think I might use this to interface with smartphones/pads as controllers at some point:

sudo pip install flask

Then I added my git credentials to my .netrc file.  I used the same ones that I put in my windows _netrc file in an older post.  Something like:

cd ~
echo "machine code.google.com login me@gmail.com password [GeneratedPassword]" > .netrc
chmod 600 .netrc

Then added a folder to store my code and cloned my git repo there:

mkdir Code
cd Code
git clone https://TimKracht4@code.google.com/p/no-arms-darts/ 

So then I wanted to try to see if I could just plug in the dartboard via the arduino and run it on the PI.  I needed another USB port for that, so I got out a powerd USB hub, plugged it into the Pi and plugged the keyboard, mouse and arduino into the hub.  I loaded up the python IDE, IDLE,  and opened the serial test script and ran it.  It complained because it couldn't find the Serial module... so I opened the lightweight web browser, Midori, and tried to download the PySerial tarball, but I kept getting empty files.... so I tried pip, something like:

sudo pip install pyserial

Which did the trick.  so I went back to IDLE and tried running the code again.  This time it complained about not being able to find the "COM5" serial port.  Makes sense since COM5 is on my windows laptop.  To find out what pi port the duino was connected to, I first unplugged the duino from the USB hub, then checked out what all was in the /dev folder for tty connections:

ls -alt /dev/tty*

Then I plugged in the duino, waited a few seconds and ran the command again.  The second time around there was a new entry, /dev/ttyusb0, so I figured this was the guy.  I modified the script like so:

ser = serial.Serial("COM5", 9600) # windows
ser = serial.Serial("/dev/ttyusb0", 9600) # *nix

Saved and ran it again and then saw the output scroll as the Pi connected to the duino, then the dartboard speaker beeped "Charge!" when it entered play mode, then correctly reported what segments I pressed on the dartboard contact film matrix thingy.

So another milestone, I successfully (and quite easily) ported the python code from my windows laptop to my Raspberry Pi and have both talking with the duino/dartboard circuit.

Just for kicks, I loaded my Jumpman intro into IDLE and it ran flawlessly.

Next steps: hardware=cut perfboard/pcb down to size and move breadboard prototype over to it.  considering adding LED indicators where the 6 game buttons are --- maybe a couple RGB leds, one for connection to the game server (red not connected, yellow/orange connecting, green connected) and one for play mode (red stopped, orange paused, green playing) and then 4 more LEDs to do whatever with.  Or maybe instead of 2 RGB, just 2 red, 2 orange, 2 green and use 3 separate indicators for each state... that will tie up all 6 button holes with something that is reasonably useful and I won't have to think of something else to use LEDs for, like wasting time with blinking patterns or something... although I know where you can find some sweet LED blinking code. So if I get the pcb built, then screw it into the dartboard case and close it up and hope it doesn't fall apart when I start throwing darts at it.

Next steps: software=still need to jump in and code the game engine in pygame.  Have been jotting down ideas here and there, but now is the time to act, now is the time to code. Need to try to convince myself to use a simple, working design and refactor bells and whistles later. I think I want to try to auto-detect the serial port that the duino is on as a first step, then do a simple game menu maybe, and then the game play for a simple game, like around the clock.

l8r

Saturday, September 7, 2013

Python Serial Talkies, Interface Milestone 2

I tweaked the arduino dartboard interface sketch a little bit and wrote a test python script to talk to the dartboard.  I used PySerial to handle the USB port.  It was easy to implement and is working well so far.

I put a little handshake business in there, but otherwise really trust that everything will work just swell all the time.  It worked almost immediately, so I got to spend a long time fiddling with minutia.  

I let it sit for a couple days and then kept noticing the snipped wires from the dartboard's speaker dangling near the small breadboard that attaches to the dartboards ribbon connector.  So I found the Arduino tones example, wired the speaker to the breadboard, grounding one and sending the other to arduino digital pin 12, through a 100 Ohm resistor and added a generic playMelody procedure in the interface sketch.

// based on the arduino tones example, plays the given melody
void playMelody(int melody[], int noteDurations[], int notecount) {
  // don't even try to play nothin' if we don't got no speaker
  if (HAS_SPEAKER) {
    noTone(SPEAKER_PORT);
    
    // iterate over the notes of the melody:
    for (int thisNote = 0; thisNote < notecount; thisNote++) {
  
      // to calculate the note duration, take one second 
      // divided by the note type.
      //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
      int noteDuration = 1000/noteDurations[thisNote];
      tone(SPEAKER_PORT, melody[thisNote], noteDuration);
  
      // to distinguish the notes, set a minimum time between them.
      // the note's duration + 30% seems to work well:
      int pauseBetweenNotes = noteDuration * 1.30;
      delay(pauseBetweenNotes);
      
      // stop the tone playing:
      noTone(SPEAKER_PORT);
    }
  }
}

Then a playCharge procedure which is called when the interface changes to the play state.

void playCharge() {
  int notes[] = {NOTE_G3, NOTE_C4, NOTE_E4, NOTE_G4, NOTE_E4, NOTE_G4};
  int durations[] = {8, 8, 8, 4, 8, 2};
  int noteCount = 6;
  
  playMelody(notes, durations, noteCount);
}


...
      case IFACE_PLAY:
        if (gameState == IFACE_STOP) {
          gameState = IFACE_PLAY;
          Serial.write(IFACE_PLAY);
          playCharge();
        }
        break;
...

It's totally awesome.

I ordered me a raspberry pi and will be working on the pygame dartboard game engine.

Monday, September 2, 2013

Inside the Board, Interface Milestone 1




Finally got around to opening up the dartboard.



It was pretty much what I expected based on the other projects I have seen... 2 clear plastic sheets with conductive patterns printed on them.  An insulator sandwiched between them with holes allowing the plastic sheets to make contact when pressed together.


The dartboard wedges are really big plastic buttons that press these sheets together to make contact, registering a hit.

 The sheets terminate in a pair of short ribbon cables crimped to a ribbon connector which is soldered to the dartboard's small pcb brain. The pcb has a small lcd display, 2 sets of rubber buttons and wires running to a small speaker, an ac power adapter jack, and a battery compartment.



What I didn't expect was the configuration and layout of the 2 contact sheets.  I was hoping for something like a 10x10 matrix, but instead it is a 7x10 matrix.  This means that the inner and outer single-score wedges are wired together and pretty much eliminates some of the games I wanted include.  Oh well.  Maybe I'll hack the sheets to split them into separate connections for v2.

The way these are wired... the board is split into 2 halves: from the 9 wedge clockwise around to 10 and then from 15 around to 14.  The sheet with 7 wires has 3 connections on each half - 1 each for the single, double and triple segments.  The 7th connection on this sheet is for the bulls-eye.  The other sheet has 10 wires... each wire goes to 2 wedges, one on each half of the board, and with 2 wires also connecting to the bulls-eye - one to the single bull and the other to the double.




So when you hit a triple 20, you hit a wire connected to both the 20 and 16 wedges on one sheet and you hit a wire connected to the triple ring on the 9 through 10 half of the other sheet; or row 6, column 0; or boardMatrix[6][0].  Should be easy enough to hook this thing up to the duino, huh?




First thing i did was cut the wires to the batteries, ac jack and speaker and unscrew the pcb from case.  Next, I grabbed a soldering iron and solder sucker and desoldered the 20-pin ribbon connector.  This connector also happened to be glued to the pcb, so a combination of rubbing alcohol, screwdriver and needle-nose pliers finished the job.


 There were some solder lumps on the pins still, so I used the iron to pull some of this off and smooth out all the pins so they could fit into a breadboard.


I started out using just one 595 shift register and 2 duino data pins to send a signal to the board's 10 wired sheet, but for some reason i wasn't making any connections from the duino data pins.  The multimeter showed 5v coming from the pins, going into the ribbon connector and even from the conductive sheet, yet when the connection was made from these data pins directly to the dartboard, hardly any voltage was coming out the other side.  I don't know why.  I am curious, but would rather get this working than figure that out... so I just daisy chained another 595 for the other 2 lines and this worked very well. Possibly unnecessary given the available duino data ports,  but so it goes and so it goes and so it goes.

The final circuit has the duino activating "rows" one at a time in sequence on the 10 side, using the daisy chained 595 serial-to-parallel shift registers.  Then the duino checks all 7 "columns" in sequence on the 7 side, through a single 589 parallel-to-serial shift register, looking for a hot wire.  If it finds such a wire, then it stores the row and column that made the connection, and looks up the wedge value and multiplier segment for that row,column.  This row, column is considered to be in a "pressed" state.  The duino continues to loop through the rows and columns and once this hot row,column is no longer hot, it is considered "unpressed" and a message with some details is sent out the Serial.

When the dart hits the board, the button is pressed for a whole bunch of cycles and we only want to treat it as a single hit.  That's why I just keep track of what was hit and only consider it to be really hit when the button is no longer pressed.  Other projects I have seen just run a delay command when a button press is detected, but I like this unpressed approach better.  I might try a 2d array to hold the state of all buttons, which could be another improvement, but I think this should work for now.

 When I first wired it up, I had a few wires out of place and some of the wedge/multiplier mappings backwards, but these were easy to track down and fix and the whole thing was pretty simple to implement on both the hardware and software sides.  I tested all buttons manually and everything is in working order.


I think this can be considered a milestone.  Cool beans.

So the first version of the sketch is out on git.



Next hardware step is to move my circuit from the breadboards to a pcb about the same size as the board's original pcb, so I can just screw it into place.  Then I'll want to find an extry long mini usb cable.  I'm going to try to find a grommet to fit where the ac power jack sits in the dartboard case and have the usb go through there.  I might eventually try to find another small LCD to use to display my own nonsense.... but that's probably not necessary.

Next software step is to conjure some python code to receive these Serial messages and do something useful.  And order a raspberry pi.  My dog has no nose. "How does he smell?"  Awful.

I have some pics I took along the way which I may or may not add later.  This is the worst blog ever, but I'm happy about the progress I made with the dartboard and Arduino interface, so whatevs, b's.