Molly’s Joystick

July 18th, 2011 by Dr. Responsible

I started work tonight on making the joystick on Molly’s Bar do something.

I used the adafruit Wave Shield to make an arduino play sounds when buttons are pressed.

Here’s the arduino sourcecode:

/*
  MollyBar
  Controls the lighting, music and breathalyzer on Molly's Bar according to the joystick input
*/

#include <FatReader.h>
#include <SdReader.h>
#include <avr/pgmspace.h>
#include "WaveUtil.h"
#include "WaveHC.h"

// The density of output to Serial is determined by the value of this constant
#define DEBUG 0

// Action queue
#define QUEUESIZE 16
volatile int QueueStart = 0;
volatile int QueueEnd = 0;
volatile int QueueSize = 0;
volatile int Queue[QUEUESIZE];

// Buttons
#define BUTTONZERO 6
#define NBUTTONS 6
#define NSOUNDBUTTONS 2
#define DEBOUNCE 100  // button debouncer; don't press the buttons too quickly

// Sound files
char* SoundFileNames[] = { "Shots.wav", "LineEmUp.wav" };

// Wave Shield variables
SdReader card;    // This object holds the information for the card
FatVolume vol;    // This holds the information for the partition on the card
FatReader root;   // This holds the information for the filesystem on the card
FatReader f;      // This holds the information for the file we're play
WaveHC wave;      // This is the only wave (audio) object, since we will only play one at a time

// this handy function will return the number of bytes currently free in RAM, great for debugging!
int freeRam(void) {
  extern int  __bss_end;
  extern int  *__brkval;
  int freememory;
  if((int)__brkval == 0) {
    freememory = ( (int)&freememory ) - ( (int)&__bss_end );
  }
  else {
    freememory = ( (int)&freememory ) - ( (int)__brkval );
  }
  return freememory;
}

// Check for an error with the SD card
void SDErrorCheck(void) {
  if ( !card.errorCode() ) return;
  putstring("\n\rSD I/O error: ");
  Serial.print( card.errorCode(), HEX );
  putstring(", ");
  Serial.println( card.errorData(), HEX );
  while(1);
}

// Setup
void setup() {
  // Set up serial port
  Serial.begin(9600);
  Debug( "Molly's Bar Joystick!", true );

  if (DEBUG) {
    putstring("Free RAM: ");       // This can help with debugging, running out of RAM is bad
    Serial.println(freeRam());      // if this is under 150 bytes it may spell trouble!
  }

  // Set the output pins for the DAC control. This pins are defined in the library
  pinMode( 2, OUTPUT );
  pinMode( 3, OUTPUT );
  pinMode( 4, OUTPUT );
  pinMode( 5, OUTPUT );

  // pin13 LED
  pinMode( 13, OUTPUT );

  // Enable joystick buttons
  for ( byte i = 0; i < NBUTTONS; i++ ) {
    pinMode( BUTTONZERO + i, INPUT );
    digitalWrite( BUTTONZERO + i, HIGH );
  }

  //  if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you
  if ( !card.init() ) {         //play with 8 MHz spi (default faster!)
    putstring_nl("Card init. failed!");  // Something went wrong, lets print out why
    SDErrorCheck();
    while(1);                            // then 'halt' - do nothing!
  }

  // enable optimize read - some cards may timeout. Disable if you're having problems
  card.partialBlockRead(true);

// Now we will look for a FAT partition!
  uint8_t part;
  for ( part = 0; part < 5; part++ ) {     // we have up to 5 slots to look in
    if ( vol.init(card, part) )
      break;                             // we found one, lets bail
  }
  if ( part == 5 ) {                       // if we ended up not finding one  :(
    putstring_nl("No valid FAT partition!");
    SDErrorCheck();      // Something went wrong, lets print out why
    while(1);                            // then 'halt' - do nothing!
  }

  // Tell the user about what we found
  if (DEBUG) {
    putstring("Using partition ");
    Serial.print(part, DEC);
    putstring(", type is FAT");
    Serial.println(vol.fatType(),DEC);     // FAT16 or FAT32?
  }

  // Try to open the root directory
  if ( !root.openRoot(vol) ) {
    putstring_nl("Can't open root dir!"); // Something went wrong,
    while(1);                             // then 'halt' - do nothing!
  }

  // Whew! We got past the tough parts.
  Debug( "Ready!", true );
}

// The main execution loop
void loop() {
  // Enqueue any new button press
  int buttonpressed = ButtonPressed();
  if ( buttonpressed >= 0 ) {
    if ( buttonpressed < NSOUNDBUTTONS ) {
      if( Enqueue(buttonpressed) ) {
        Debug( "Enqueued \"", false );
        Debug( SoundFileNames[buttonpressed], false);
        Debug( "\"", true );
      }
      else {
        Debug( "Enqueue failed: queue is full.", true );
      }
    }
    else if (DEBUG) {
      putstring("No action associated with button ");
      Serial.println( buttonpressed, DEC );
    }
  }

  // Dequeue an existing action
  int action = Dequeue();
  if ( action >= 0 ) {
    Debug( "Dequeue \"", false );
    Debug( SoundFileNames[action], false );
    Debug( "\"", true );
    PlayFile(SoundFileNames[action]);
  }
}

// Output to Serial if the DEBUG flag is on
void Debug(char *message, boolean newline) {
  if (DEBUG) {
    Serial.print(message);
    if (newline) {
      Serial.println();
    }
  }
}

// Check to see if a button was pressed
int ButtonPressed() {
  static byte previous[NBUTTONS];
  static long time[NBUTTONS];
  byte reading;
  int pressed;
  byte index;
  pressed = -1;

  for ( byte i = 0; i < NBUTTONS; i++ ) {
    reading = digitalRead( BUTTONZERO + i );
    if ( reading == LOW && previous[i] == HIGH && millis() - time[i] > DEBOUNCE ) {
      // Button pressed
      time[i] = millis();
      pressed = i;
      break;
    }
    previous[i] = reading;
  }

  // return button number (0 - 5)
  return pressed;
}

// Enqueue an action
boolean Enqueue(int action) {
  if ( QueueSize < QUEUESIZE ) {
    QueueSize++;
    Queue[QueueEnd] = action;
    QueueEnd = ( QueueEnd + 1 ) % QUEUESIZE;
    return true;
  }
  return false;
}

// Dequeue an action
int Dequeue() {
  int action;
  if ( QueueSize > 0 ) {
    action = Queue[QueueStart];
    QueueStart = ( QueueStart + 1 ) % QUEUESIZE;
    QueueSize--;
  }
  else {
    action = -1;
  }
 return action;
}

// Plays a full file from beginning to end with no pause.
void PlayComplete(char *name) {
  // call our helper to find and play this name
  PlayFile(name);
  while (wave.isplaying) {
  // do nothing while its playing
  }
  // now its done playing
}

void PlayFile(char *name) {
  // see if the wave object is currently doing something
  if (wave.isplaying) {// already playing something, so stop it!
    wave.stop(); // stop it
  }
  // look in the root directory and open the file
  if (!f.open(root, name)) {
    putstring("Couldn't open file "); Serial.print(name); return;
  }
  // OK read the file and turn it into a wave object
  if (!wave.create(f)) {
    putstring_nl("Not a valid WAV"); return;
  }

  // ok time to play! start playback
  wave.play();
}

And here’s some video of the thing in action:
20110718-200559.mov

Molly’s Bar Gets a Makeover

April 25th, 2010 by Dr. Responsible

Miss Behavior helped me give the bar a makeover this weekend.

Molly’s Bar Gets Labelled

April 20th, 2010 by Dr. Responsible

Oh my god, that was a pain in the ass. But well worth it:

Molly’s Bar, Part X Part 2

April 15th, 2010 by Magneato

Dremel tools are a handy thing. Amateur makers across the land swear you can make anything with a Dremel. More season makers know the actual truth is that you can destroy anything with a Dremel. So you have to be careful what you apply your Dremel tool tool. More specifically make sure it’s something that you don’t want want. That, my friends, is exactly what Dr. Responsible and I had. There are sections of the bar that we want to cut out to spell out the words “Molly’s Bar” in backlit cutouts for our sign. Before we go any further though, let’s get a good look at the new toy.

Ah the Dremel 300. That name might not mean anything to you now, but I have a feeling it will be synonymous badass roughly 10 minutes after this blog post is up.

Here it is opened up. It comes with a lot of cutting, sanding, and polishing bits. Also, very important to our project, it came with a saw guide. This circular piece lets us place the guide flush to the surface we’re cutting to ensure that the cutting bit is perpendicular and, if necessary, at a controlled depth.

I took an exacto knife and traced the printed letters we taped to the bar last week. Pushing hard while cutting, I scored our pattern into the wood to make it easy see when cutting with the Dremel. Then Dr. Responsible used the new toy to cut the letters out. Here’s a video of Dr. Responsible’s First Go at the Dremel. Speaking of strategic removal of unwanted things…

After all was said and done, we got the word “BAR” cut out of the front. Doesn’t it look nice?

Next week, we’ll finish cutting out “MOLLY’S” and get started on backlighting the sign. We’ll use the same plexiglas and tissue paper plan from the top of the bar. See you all next week.

Molly’s Bar, Part X

April 7th, 2010 by Magneato

Are you at a bar right now? Take a good look at your bar. Now back to Molly’s Bar. Now back to the one you’re at. Sadly your bar is not Molly’s Bar. Molly’s Bar now has paper outlines of her fabulous sign to be. Tonight Dr. Responsible and I put marked out with fantastic precision where the back-lite, cut-out sign letters will be. One day these amazing holes in wood will shine bright pink across the great playa horizon to alert all that they might get a drink here. How about that? I’m on a horse.

Molly’s Bar, Parts 4,5,6,7,8 and 9

March 31st, 2010 by Dr. Responsible

Well, we’ve been very busy working on Molly’s Bar, but far too lazy to post to the blog. Here’s a long series of photos we’ve taken along the way. BTW, the lady is Kendra, the newest member of Pink&Black Labs.

Molly’s Bar, Part 3

January 19th, 2010 by Dr. Responsible

On Sunday night, we built a rig to cut clean arcs using my jigsaw. The rig is just a 6′ 1×4 with a rigid attachment to both the jigsaw and the arc’s center. We put 4 nails through one end of the 1×4, spaced appropriately to allow the jigsaw to mate with it. We then cut a notch out of the board to allow for the movement of the blade. At a distance equivalent to the desired radius, we drilled a hole slightly too big for a #10 screw, and attached the screw to the center point of the desired arc. Here I am preparing to use it on our electronics bed:

As you can see, it came out pretty great:

We used the same setup to cut out the shelving. Here we are enjoying the fruits of our labors:

Up next: spacers and a plexiglass bar surface.

Molly’s Bar, Part 2

January 14th, 2010 by Dr. Responsible

Last night we finished building and fastening the legs to the floor of the bar, including putting washers on all the screws holding the legs on:

The best idea we’ve had so far on this project is to use cabling to sturdy the frame. Magneato and I both came up with this idea at the same time over lunch; it’s pretty great that we both get to have had the best idea on the project. Last night we decided to put cabling only on every other leg, but it’s easy to add more if we later determine that the bar is flimsy. Here’s a close up view of the cabling:

Fun fact: the alcohol sensor arrived today, so we might end up wiring that together on Sunday.

Mojito Molly’s Bar, Part I

January 11th, 2010 by Magneato

Today Dr. Responsible and I, aided by our two guest stars, Cherry and Tricia went to Home Depot to get materials and then began construction of a new bar we’re building for Mojito Molly and Camp Tissue and a Plan for Burning Man 2010. The bar would be a large 180 degree arc, 8 feet in diameter. The front is to be made of plywood with our logo, and Molly’s name carved out of the front with back lights shinning through. The top will have plexiglass surface with  wood bottom. The space between the wood and plexiglass will be occupied with LED lights, stereo speakers, and electronic circuits which are yet to be fully planned out. One this is for sure though, we’ll be adding the new Alcohol Sensor we picked up at SparkFun to it.

Not to forsake at all function with form, the bar is designed to have two counter spaces on either side. The bar top ends just a foot shy of the whole structure on either side to allow for a lower counter space that’s the right hight for chopping and using a blender. A shelf will run underneath the bar top and act as store for bottles.

Tonight we tackled the materials purchasing, built the legs, and got them attached to the floor. We’re happy with the progress. The next time we meet up we plan to reinforce the legs with wire. If we have more time, we’ll get started on cutting the top, shelf, and counters to shape with the jig saw.

Website

January 8th, 2010 by Dr. Responsible

I started in our main website tonight. It’s not much yet, but I think it shows promise.

It was kind of aggravating to find a solution for a curved corners. They pretty much all have serious pitfalls (with the exception of the not-yet-well-supported CSS3 border-radius property). In the end, I decided on RoundedCornr.

  • molly: I'm glad that you appreciate that that is the best...
  • molly: <3 <3 <3...
  • molly: OMG THE BEAUTY OF IT!!! SUCH DRINKS I WILL MAKE YO...
  • Dr. Responsible: I switched over to ...

Powered by WordPress

Blossom Theme by RoseCityGardens.com