Thursday, December 23, 2010

That’ll be $44+“Tax” (BTW, “tax” is 61%)

Warning: if you are overwhelmed by a joyful Christmas spirit, you should probably not read this right now. It’s a rant.

I don’t get out much. My last concert was…a while ago. There is something about buying tickets that hasn’t gotten any better in the years since, though: ridonkulous fees.

Take, for example, the following invoice for four tickets to Toy Story on Ice (I have kids, ok?):

ticket racket

That’s $44 for the tickets, and $26.75 for…I don’t know what for. They are literally charging 61% extra. These are electronic tickets so they aren’t even trying to hide the evil with these fees. You don’t have bags to haul around like an airline—we’re talking about electrons here.

  • “Handling fee”? This is 100% electronic—what are you “handling”?
  • “Convenience fee”? What the hell is that? I’m buying these online, which saves you money on printing, shipping, logistics, etc. Charging me extra for the privilege of saving you money is just absurd. Can you imagine buying any other product and paying more to download it than having it shipped to you?
  • “Facility fee”? Isn’t that what I bought the tickets for? Or did you forget to book the stadium when you booked Disney and now you’re short $200,000?

What about tax? That’s one that I wouldn’t shy from but you don’t have that there. Odd.

You know what, Quicken Loans Arena (and pretty much any place that sells tickets, probably)? You suck. Let’s make a deal: you keep your tiny, cold seats, $8 sodas and who-knows-what-parking spaces and I’ll keep my money and my sanity. Square?

Tuesday, December 21, 2010

Life Lessons About Glitter (ZOMG IT’S EVERYWHERE)

A week or so back Wife and I were cleaning upstairs while the kiddos dumped out all their toys in the basement. A typical Tuesday. Of course we check on them often and on my rounds I discovered this:

glitter 1

In case it’s not immediately obvious, the kids got into an industrial supply of glitter and went. to. town. Here’s the same photo marked up where we found (and can still find) this horrible, horrible stuff:

glitter 2

Astute readers will note substantial collections in shoes, and all over Thing2. What’s most unfortunate is where the glitter is not: in its glitter containers (not marked, but scattered throughout) or in the two giant, wide-open baskets designated for such activities.

DSC_0087DSC_0100

To appreciate the gravity of this you must understand that I h-a-t-e glitter. Passionately. If an organization existed with the sole objective of outlawing glitter, I would donate both time and money to the cause.

(jump to 3:00)

Upon discovering the horror in my basement, I uttered a single expletive, followed by the undo code “peanutbutter” to wipe it from the children’s memory and immediately commanded wife to stay upstairs and ignore the preceding commotion. Obviously that didn’t work as I have no such power. Thing1 was lucky to hit the sweet spot on the shock curve:

chart(this is inverted because I messed up and didn’t want to start over)

Don’t get me wrong—we made her (help) clean it up and that led to a lot of tears—but I really wasn’t as angry with this whole situation as I would have predicted. That’s the life lesson, I guess. After replacing the upstairs carpet because of the great paint-everywhere-even-on-the-dog-omg-are-you-kidding incident of 2010 (featured on shitmykidsruined.com), a bucket of glitter’s just not so bad.

But glitter is banned from my home. I’m not a fool.

Tuesday, December 14, 2010

Last Minute Gifts: Guide 2010

So you’re out of ideas for that obscure relative or friend you forgot to buy for and you need to pick up something quick before that Super Saver Shipping deadline passes? Here are 10 surefire gift ideas to save face this Christmas:

1. Robot Alligator

robot alligator

Nothing says Merry Christmas like a ferocious alligator. In robot form, you can be assured that the terror will cease only for 4-6 hours each night while Chomp recharges. Particular skilled recipients may have luck with training their new robot alligator to do useful things like eat that annoying dog next door. STOP BARKING DOG. STOP STOP STOP.

2. Peanut Butter

banana

Everybody likes peanut butter. Plus, those that are allergic to it can just re-gift it back to you. If you’re both allergic then this is probably a bad gift idea.

3. Empty Box

empty box

The key to this one is to work on your “surprise face”. When your gift recipient opens the box, you need to act as confused and stunned as they are. Ask what they expected the gift to be and then just tell them that’s what it was until your alligator (allegedly) stole it. This idea works even better if you mail your gifts.

Depending on your relationship to the recipient, this gift has other variations.

4. Old College Textbook

IMG_20101214_163951

Ah! The gift of education. How else are you supposed to unload these things? After lugging around 50 lbs. of dead tree with me from house to house, I finally just started leaving them around my office and giving them away as swag prizes during my presentations.

This gift is best opened while you revel in the value and timelessness of learning.

Bonus points if the person receiving your gift actually enjoys the book’s subject.

5. Coffee

IMG_20101214_164026

It’s awesome.

6. Bag of Snow

IMG_20101213_142832

Nothing captures the spirit of Christmas like a bag of Christmas snow. What makes it Christmas snow? Easy: it came from the North Pole *wink*. If it melts before the recipient opens it, you have yourself a perfect lead in to a pun filled guilt trip.

7. Expired Gift CardIMG_20101214_171618

Those expired or used up gift cards are no good to you…except as wonderful gifts! Dig out that new Sharpie you bought with your now defunct gift card and proudly write whatever value suits you directly on the card. This one’s great because you can just blame those damned computers if your recipient is ever so taboo as to bring up the matter later. Plus no one needs more lotion anyway.

8. Incomplete Decks of Cards

IMG_20101214_165434

Go green this year by reusing your “vintage” playing cards as gifts! No need to combine incomplete decks into whole decks, either—that’s just wasteful.

9. Pictures of Food

IMG_20101213_200120

Recent research has discovered that simply imagining the act of eating helps you eat less. Get ready for a big “thank you” from your gift recipient after you explain as they open their beautifully illustrated card.

10.

I’m out of ideas.

Happy Christmas!

Friday, November 19, 2010

Customer Service: How AirTran Bought Me For $0.50

airtranI recently flew with AirTran and the experience was very pleasant. It didn’t start that way, though:

  • Was I happy paying for a decent seat or a checked bag? No.
  • Was I happy arriving two hours early for my flight and doing the TSA dance? No.
  • Was I happy paying for WiFi? No.
  • Was the gate agent friendly even a little? No.
  • Could the gate agent read our tickets? No.
  • Could the gate agent have been any more curt and uninterested in her job? No…what’s with this woman—she needs a vacation or something.

The thing is, though, none of that mattered once I got on the plane. The courteous and friendly flight crew completely changed my attitude about the whole trip, and it wasn’t by giving me an upgrade or free booze. Instead they merely:

  • Greeted me with genuine enthusiasm
  • Joked with me while I “assisted” with the safety speech (more on that in a minute)
  • Offered free headphones to use with the XM which I value at $0.50

Of course we were served complimentary soda/snacks but most airlines do that. The flight crew (including the captain) set themselves apart by being present in their duties and being authentic. I was particularly swayed by one particular flight attendant. She asked me to hold her bag of safety stuff (seat belt, oxygen mask, etc.) while she demoed them. I said something like, “Of course, no problem, I’m pretty much an expert at this kind of stuff. Do I get (plastic) wings?”

She replied, very coyly, “I’ll get you something *wink/nod*”.

I must digress for a moment to put my delightful wife at ease: even though I was pretty sure she was going to buy me a drink, and I was looking particularly handsome in my “flight suit” this was not flirting and TWSS was completely inappropriate at all times. This (much older) flight attendant was just being nice, as was I.

Back to it: they did the safety thing and then, because I was in an exit row, I promised to rip the side off the plane and guide everyone to flame-free refuge (if necessary).

And then a few minutes later, that nodding flight attendant came back and gave me not a drink, but instead free headphones for the XM, and a pair of those plastic wings normally reserved for children. I protested saying that I was just joking but she insisted and I accepted. It became apparent that I wasn’t actually all that special moments later when she offered free headphones to all nearby passengers (but only kids, me, and probably any adult who asked got the wings, so that’s something).

My point with all this is simple: AirTran erased (for me) all the negative crap associated with air travel by spending a few extra seconds and $0.50.

This is a value-add for sure, and it shocks me that more airlines fail to do it effectively. AirTran seems to realize that all those bad things we hate about flying are constant across all carriers and as a result, they don’t have to fix those problems. Instead, they can distinguish themselves from their competition by much easier means: being slightly more human and slightly more comfortable.

If I’m allowed two points in one post, my second point is this: the passion of a company’s employees is evident whether those employees are behind the scenes building awesomely polished web applications or right up front greeting passengers. Their passion shows and it matters. Better technology, cheaper rates, nicer benefits, more freebies, etc. can’t equally compensate for better employees (or coworkers, friends, etc.).

Wednesday, November 17, 2010

"Private Practice" is a Really Great Show

bed pan

One of Wife's indulgences is watching "Private Practice". I don't watch it with her but I can't help but overhear it while I work on my own projects. Fortunately I was out of town a few days ago so I was unable to listen in.

If you haven't seen the show, here's a pretty reasonable guess for what all the drama might be about at any given time:

So this guy’s an organ donor but he can't give consent because he's in a coma but his girlfriend wants to give consent for the transplant to save her brother's son but the mans wife (!) insists on obtaining custody of a previously frozen sperm sample first before she'll unblock the surgery right when all the doctors realize that the man is pregnant with a coyote baby and needs his nipples exchanged (left for right) in order to prevent an acute psychological condition (presumably something he’ll still have if he wakes up) from interfering with his job as a cupcake paper wrapper packer which he's really nervous about even though he already knows it's being outsourced to a robot which--here's the twist--is manufactured by his girlfriend's brother's son's stepdad's friend's company.

Like I said, good solid stories here.

I’ve recently learned that Wife might not really care for it either. You see, I normally spew a whole lot of comments like that the entire time the show is playing. But since I was absent this week, she made up her own ridiculousness and shared it with me:

You would freak out live blogging Private Practice.  Ahhhhmazing.  Seriously.  There is a woman who has been in a coma for 2 years and they just found out that she is pregnant and are all OMGsomeonerapedheratthenursinghome which is obviously not what happened because it was (duh) her husband.  Also, a woman just had a bunch of surgeries and stuff and wants to have a baby now and we just found out that her husband was in a car accident (he is fine) but he was with a male prostitute. 

OMG male prostitute guy has HIV

k turns out the guy *is* a male prostitute but the two guys were together for real (like in a relationship)

coma girl lost the baby and her husband said don't worry we'll keep trying

I was pretty close, right? Oh, and my wife is awesome.

Arduino Day 17: Light Driven Beeps

Tip! This post is part of a series on my adventures with Arduino

Today’s build was a fun one for Thing 1. It’s basically just two CdS light sensors tied to a set of LEDs and a buzzer. If you cover either of the sensors (or both), a different tone plays and an LED lights. Like so:

Build

IMAG0809IMAG0806IMAG0800

IMAG0803

Code

There’s nothing too fancy going on here. The only real trick (if you can call it that) is to read in the ambient analog values at startup so you can compare against them later. This is much more effective than hard-coding a threshold.

const int BuzzPin = 5;
const int BuzzDuration = 50; 
const int Tones[] = { 800, 1000, 1200 };
const int LedPins[] = { 9, 10, 11 };
const int CdsPins[] = { 0, 1 };
int ActiveLed = -1;
int CdsSquelch[2];

void setup() {
  Serial.begin(9600);

  pinMode(LedPins[0], OUTPUT);    
  pinMode(LedPins[1], OUTPUT);    
  pinMode(LedPins[2], OUTPUT);    
  pinMode(BuzzPin, OUTPUT);

  // read in the ambient light value to be used as a threshold
  // this is helpful since the amount of ambient light changes all the time
  for(int i = 0; i < 2; i++){
    CdsSquelch[i] = analogRead(CdsPins[i]);
  }  
}

void loop() {
  boolean CdsReads[2];
  int Led;
  
  // convert the CdS values into a boolean
  // - true if the light detected is less than 90% of ambient
  for(int i = 0; i < 2; i++){
    CdsReads[i] = analogRead(CdsPins[i]) < CdsSquelch[i] * .9;
  }

  // if both cells are covered...
  if(CdsReads[0] && CdsReads[1]){
    Led = 1; 
  }  
  // if one cell is covered
  else if(CdsReads[0]){
    Led = 0; 
  }
  // if the other cell is covered
  else if(CdsReads[1]){
    Led = 2; 
  }
  // if neither cell is covered
  else{
    Led = -1; 
  }
  
  // if something is covered, beep and blink
  if(Led != -1){
    Ding(Led); 
    digitalWrite(LedPins[Led], HIGH);
  }
  
  // turn off the previously lit LED if necessary
  if(Led != ActiveLed){
    digitalWrite(LedPins[ActiveLed], LOW);
    ActiveLed = Led;
  }
}

void Ding(int light){
  // e.g. 1 / 2048Hz = 488uS, or 244uS high and 244uS low
  // to create 50% duty cycle
  // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1231194692
  int Osc = 1000000 / Tones[light] / 4; // in microseconds
  
  // compute the number of iterations needed to hold
  // the nfote the desired duration
  int Iterations = Tones[light] * ((float)200 / 1000);
  
  // play tone
  for (long i = 0; i < Iterations; i++ )
  {
      digitalWrite(BuzzPin, HIGH);
      delayMicroseconds(Osc);
      digitalWrite(BuzzPin, LOW);
      delayMicroseconds(Osc);
  }  
}

Sunday, November 14, 2010

Arduino Day 14: Simple Conductivity Sensor

Tip! This post is part of a series on my adventures with Arduino

In keeping with the traffic light theme of the past few days, I built a ridiculously simple conductivity sensor with an analog input. Place something between the two leads to determine if it is highly conductive, somewhat conductive, or barely or not at all conductive. Like this:

Yes, that’s Thing 1’s leftovers from lunch (or maybe Thing 2…). Her sandwich bread is somewhat conductive (yellow), but the ham inside is very conductive (green), as is the apple sauce.

Why is the applesauce dark red? Good Question. It’s homemade, and the best we can figure, the apples just turned brown as they normally do when cut.

Build

The build is identical to the previous few days with a simple analog input added the same way as the CdS cell in another build (I used a 10kΩ resistor instead of 470Ω, though).

IMAG0782

Code

const int BuzzPin = 5;
const int BuzzDuration = 50; 
const int Tones[] = { 1000, 2000, 3000 };
const int LedPins[] = { 9, 10, 11 };
const int SignalPin = 0;

void setup() {
  pinMode(LedPins[0], OUTPUT);    
  pinMode(LedPins[1], OUTPUT);    
  pinMode(LedPins[2], OUTPUT);    
  pinMode(BuzzPin, OUTPUT);
}

// keep track of which LED is lit
int ActiveLed = -1;

void loop() {
  // grab the singal from the analog input
  int Val = analogRead(SignalPin);
  int Led;

  // red (no signal)
  if(Val < 100){
    Led = 2;
  }
  
  // yellow (some signal)
  else if(Val < 500){
    Led = 1; 
  }
  
  // green (lotsa signal)
  else{
    Led = 0;
  }

  // if a different LED should be lit, change it
  if(Led != ActiveLed){
    // turn off the currently lit LED
    digitalWrite(LedPins[ActiveLed], LOW);

    // light the new one
    digitalWrite(LedPins[Led], HIGH);
    Ding(Led);
 
    // remember me
    ActiveLed = Led;
  }
  delay(50);
}

void Ding(int light){
  // e.g. 1 / 2048Hz = 488uS, or 244uS high and 244uS low
  // to create 50% duty cycle
  // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1231194692
  int Osc = 1000000 / Tones[light] / 4; // in microseconds
  
  // compute the number of iterations needed to hold
  // the nfote the desired duration
  int Iterations = Tones[light] * ((float)200 / 1000);
  
  // play tone
  for (long i = 0; i < Iterations; i++ )
  {
      digitalWrite(BuzzPin, HIGH);
      delayMicroseconds(Osc);
      digitalWrite(BuzzPin, LOW);
      delayMicroseconds(Osc);
  }  
}

Next Steps

I’ve got a lot of travel this week so doing projects will be very challenging…but we’ll see!

Saturday, November 13, 2010

Arduino Day 13: Weather Bug

Tip! This post is part of a series on my adventures with Arduino

Today’s quick and simple adaptation of Thursday’s build was suggested by my brother, Chris. It’s a simple traffic light view of the weather:

The app parses XML files from the Internet and extracts a temperature value. If the temperature is less than 30 or over 100, it lights the red LED. If it’s between 30 and 60 or 90 and 100, the yellow LED lights. If it’s in the remaining sweet spot of 60-90, the green LED lights.

  

Build, circuit, schematic, and Arduino code are identical to my previous project.

C# (Updated)

static void Main(string[] args)
{

    var SerialPort = new SerialPort()
    {
        PortName = "COM7",
        BaudRate = 9600
    };

    while (true)
    {
        try
        {
            SerialPort.Open();
            string SerialOutput = null;

            // Miami, Florida
            //var StatusXml = XDocument.Load(@"http://www.weather.gov/xml/current_obs/display.php?stid=KTMB");

            // Akron, Ohio
            var StatusXml = XDocument.Load(@"http://www.weather.gov/xml/current_obs/KCAK.xml");

            // Nome, Alaska
            // var StatusXml = XDocument.Load(@"http://www.weather.gov/xml/current_obs/PAOM.xml");

            float Temperature = float.Parse(StatusXml.Root.Element("temp_f").Value);

            if (Temperature < 30 || Temperature > 100)
            {
                SerialOutput = "2"; // red
            }
            else if (Temperature < 60 || Temperature > 90)
            {
                SerialOutput = "1"; // yellow
            }
            else
            {
                SerialOutput = "0"; // green
            }
            Console.WriteLine("Sending {0}", SerialOutput);
            SerialPort.Write(SerialOutput);

            Thread.Sleep(TimeSpan.FromMinutes(1));
        }
        finally
        {
            SerialPort.Close();
        }
    }
}

Next Steps

More projects!

Friday, November 12, 2010

Arduino Day 12: Seeking Inspiration

Tip! This post is part of a series on my adventures with Arduino

I’ve quite suddenly begun struggling to come up with project ideas that are both possible to implement with my limited components and time, and also interesting (to me at least, if not you).

A friend suggested this list. Instead of a project tonight, I browsed that list and a bunch of other resources and came up with the following, which will tide me over for a couple of days (and hopefully lead to additional projects):

  • VU meter – like lights dancing to music (if you don’t know what a VU meter is, my implementation is certainly going to fall far short of what you are now imagining)
  • Game of Life on an LED grid (waiting for LED grid to arrive)
  • Christmas lights controller (waiting for relays)
  • Four button Simon
  • Four player reaction game
  • Clock (waiting for display)
  • Alarm (waiting for display)
  • Animated pixels (waiting for display)

So, yeah, most of these are waiting on parts (which I ordered two weeks ago…).

baconI’ll be back with some actual circuits as soon as things quiet down here on the home front!

If none of that interests you or you have a few minutes to kill, check out this recipe for preparing bacon (more importantly, the comments).

Thursday, November 11, 2010

Arduino Day 11: Extreme Feedback for Hudson Builds (Includes Chuck Norris Cameo)

Tip! This post is part of a series on my adventures with Arduino

Improving on yesterday’s build, I added in some actual network-sourced data. My little traffic lights now show the build status of one of my projects:

In case you don’t know what any of that was, let me try to explain. At work I build software, and that software is written in code. We have a server monitor our code and automatically try to build it (convert the code into executable software) whenever it changes. We use an awesome tool called Hudson to do this for us. What I’ve built is called an extreme feedback device because it reports a piece of soft data (the build status) in a physical way (beeping lights).

Whenever the build status changes (any of “success”, “building” or “failed”), the board beeps and lights up the appropriate LED (green, yellow or red).

In the future this tool could be tied to a mechanical foam dart gun to physically punish whoever broke the build. Speaking of missiles, I saw Delta Force recently enough to make this connection: Chuck Norris’s motorcycle launched missiles. Yeah.

Chuck Norris in The Delta Force

You might imagine how politically correct and culturally sensitive a 1986 movie about terrorism, with the subtitle “They don't negotiate with terrorists... they blow them away!” is. It’s like 24 with less talk and more explosions.

But a motor cycle that launches missiles. Wow. That picture above, by the way, was presumably from around 25 years ago. Guess how old he was then, and how old he that makes him now:

Norrishuckabee

70. Chuck Norris is seventy years old. And apparently immortal which is extra scary considering, well, you know.

Build (Repeat)

DSC_00113

Circuit (Repeat)

Sketch_bb6

Schematic (Repeat)

Sketch_schem6

Code (Updated)

C#

I started out today by doing all this in Powershell…but ultimately flipped back to full C# because most of my PS code was looking like C# anyway (and I’m very weak with PS).

static void Main(string[] args)
{

    var SerialPort = new SerialPort()
    {
        PortName = "COM7",
        BaudRate = 9600
    };

    try
    {
        SerialPort.Open();
        string SerialOutput = null;

        for(;;)
        {
            var StatusXml = XDocument.Load(@"http://nope/job/jobname/lastBuild/api/xml");

            if (StatusXml.Root.Element("building").Value == "true")
            {
                SerialOutput = "1"; // yellow
            }
            else if (StatusXml.Root.Element("result").Value == "SUCCESS")
            {
                SerialOutput = "0"; // green
            }
            else
            {
                SerialOutput = "2"; // red
            }

            Console.WriteLine("Sending {0}", SerialOutput);
            SerialPort.Write(SerialOutput);
            Thread.Sleep(1000);
        }
    }
    finally
    {
        SerialPort.Close();
    }
}
Arduino
const int BuzzPin = 5;
const int BuzzDuration = 100; 
const int Tones[] = { 1000, 2000, 3000 };
const int LedPins[] = { 9, 10, 11 };

void setup() {
  Serial.begin(9600);

  pinMode(LedPins[0], OUTPUT);    
  pinMode(LedPins[1], OUTPUT);    
  pinMode(LedPins[2], OUTPUT);    
  pinMode(BuzzPin, OUTPUT);
}

int ActiveLed = 0;

void loop() {
  if (Serial.available() > 0) {
    // read the incoming byte:
    int Byte = Serial.read();
    
    int Led = Byte - 48;
    
    if(0 <= Led && Led <= 2 && ActiveLed != Led){

      // clear all pins to make debugging (i.e. messing up the state of the app) easier
      digitalWrite(LedPins[ActiveLed], LOW);
      digitalWrite(LedPins[Led], HIGH);
      
      ActiveLed = Led;
      Ding(Led);
    }
  }
}

void Ding(int light){
  // e.g. 1 / 2048Hz = 488uS, or 244uS high and 244uS low
  // to create 50% duty cycle
  // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1231194692
  int Osc = 1000000 / Tones[light] / 2; // in microseconds
  
  // compute the number of iterations needed to hold
  // the nfote the desired duration
  int Iterations = Tones[light] * ((float)200 / 1000);
  
  // play tone
  for (long i = 0; i < Iterations; i++ )
  {
      digitalWrite(BuzzPin, HIGH);
      delayMicroseconds(Osc);
      digitalWrite(BuzzPin, LOW);
      delayMicroseconds(Osc);
  }  
}

Next Steps

I’ve got a busy weekend coming up so I’ll probably just spend a little time refining what I have. I’m open to ideas, though!

Wednesday, November 10, 2010

Arduino Day 10: PC Input

Tip! This post is part of a series on my adventures with Arduino

I’m starting to lay the groundwork for a larger project that will be driven from network data. I don’t have an Ethernet shield so I’ll drive this from USB. Today’s exercise is simply to verify that I can write data to the board from a higher level program on my computer. In this case, I’m using C#.

Build

DSC_0011

Circuit

Sketch_bb

Schematic

Sketch_schem

Code

C#
using System;
using System.IO.Ports;
using System.Threading;

namespace ArduinoDay10
{
    class Program
    {
        static void Main(string[] args)
        {
            var SerialPort = new SerialPort()
            {
                PortName = "COM7",
                BaudRate = 9600
            };

            SerialPort.Open();

            for(int i = 0; i < 50; i++)
            {
                var SerialOutput = (i % 3).ToString();
                Console.WriteLine("Sending {0}", SerialOutput);
                SerialPort.Write(SerialOutput);
                Thread.Sleep(500);
            }

            SerialPort.Close();
        }
    }
}
Arduino
const int BuzzPin = 5;
const int BuzzDuration = 100; 
const int Tones[] = { 1000, 2000, 3000 };
const int LedPins[] = { 9, 10, 11 };

void setup() {
  Serial.begin(9600);

  pinMode(LedPins[0], OUTPUT);    
  pinMode(LedPins[1], OUTPUT);    
  pinMode(LedPins[2], OUTPUT);    
  pinMode(BuzzPin, OUTPUT);
}

void loop() {
  if (Serial.available() > 0) {
    // read the incoming byte:
    int Byte = Serial.read();
    
    int Led = Byte - 48;
    
    if(0 <= Led && Led <= 2){
      Ding(Led);
      delay(50);
    }
  }
}

void Ding(int light){
  // e.g. 1 / 2048Hz = 488uS, or 244uS high and 244uS low
  // to create 50% duty cycle
  // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1231194692
  int Osc = 1000000 / Tones[light] / 2; // in microseconds
  
  // compute the number of iterations needed to hold
  // the nfote the desired duration
  int Iterations = Tones[light] * ((float)200 / 1000);
  
  // light on
  digitalWrite(LedPins[light], HIGH);
  
  // play tone
  for (long i = 0; i < Iterations; i++ )
  {
      digitalWrite(BuzzPin, HIGH);
      delayMicroseconds(Osc);
      digitalWrite(BuzzPin, LOW);
      delayMicroseconds(Osc);
  }  
  
  // light off
  digitalWrite(LedPins[light], LOW);
}

Next Steps

Ultimately I want to drive this from a Hudson CI build feed so I’ll continue working on that in the coming days.

Tuesday, November 9, 2010

Arduino Day 9: Simon(ish) Game

Tip! This post is part of a series on my adventures with Arduino

I built another game on top of yesterday’s circuit. I think you’ll probably recognize it:

The first time Wife tried this (she pretends to be interested, which I’m pretty sure is love) she shocked me by playing for six minutes straight, successfully knocking out a 27 bit sequence. Random chance would put that at 1 in 134217728 (0.0000007%)…it’s probably legit.

imageSpeaking of 007, did anyone see those last two Bond movies? Daniel Craig is way, way more badass than Pierce Brosnan. Nothing personal, P, but Daniel Craig could go on a hunger strike, float around on the international space station for 6 months (where he will lose considerable muscle and bone mass), return to relax peacefully among nature (squirrels and birds and whatnot), and still break your hand (and possibly arm) with his face when you sucker punch him in it. And only then would he go get something to eat like a taco or burger or something.

I know the above to be true when compared to Roger Moore, also, because I saw his “performance” in Moonraker and it was lame. I admit that I haven’t recently seen any of the other Bonds.

Build

DSC_0012DSC_0013

Special thanks to Wife’s awesome camera for giving me all that sweet, delicious bokeh you see above. Apparently I’m required by law to list this info, too: 116mm 1/50 f/4.8 ISO200.

Circuit

Sketch_bb

Schematic

Sketch_schem

Code

This program follows a typical “game loop” approach where the game is in one of a few states waiting for something to happen at any given time. The only thing close to a trick is how I maintain a sequence of tones. Rather than compute and store a known sequence, I just use the built in random number generator. Since I can seed the generator with whatever I want, I can replay the same sequence over and over again.

It worked out very nicely, actually, and all I have to do to start a new game is reseed the generator to a random value.

const int BuzzPin = 5;
const int BuzzDuration = 100; 

int ButtonPins[] = { 3, 7 };
int Tones[] = { 2000, 3000, 1000 };
int LedPins[] = { 4, 6, 5 };

void setup() {
  for(int i = 0; i < 3; i++){
    pinMode(LedPins[i], OUTPUT);    
    Ding(i);  // boot test
  }
}

// our main loop will look at the game state to 
// figure out what to do
enum GameState {
  InsertCoin, // waiting for player to start game
  Teach,      // buzzing a random sequence, increasing by one element each time
  Test,       // checking user-entered sequence
  Boo         // you've lost
};

// start in the finished state because that sets up some things for us
GameState State = InsertCoin;

// pick a seed value for the random number generator
// we'll reuse this each time the sequence is played so we get the same sequence
int Seed;

// keeps track of how many tones there are in the sequence
int Taps;

void loop() {
  switch(State){
    case InsertCoin:
      // light up both sides to suggest the user tap one to start
      digitalWrite(LedPins[0], HIGH); 
      digitalWrite(LedPins[1], HIGH); 
      
      GetPress();

      // let's go!
      Taps = 0;
      Seed = analogRead(0); // pick a new sequence seed

      digitalWrite(LedPins[0], LOW); 
      digitalWrite(LedPins[1], LOW); 

      State = Teach;
      delay(1000);
      
      break;
    
    case Teach:
      // add one to the sequence and play what we have so far
      Taps++;

      randomSeed(Seed);
      for(int i = 0; i < Taps; i++){
        Ding(random(0,2));
        delay(100);
      }

      State = Test;
      break;
      
    case Test:
      randomSeed(Seed);
      for(int i = 0; i < Taps; i++){
        int Tap = GetPress();
        int ExpectedTap = random(0,2);
        if(Tap != ExpectedTap){
          // you fail
          State = Boo; 
          return;
        }
      }      
      
      // if we make it through the entire test, good job!
      // add another note
      State = Teach;
      delay(1000);
      break;
      
    case Boo:
      for(int i = 0; i<5; i++){
        Ding(2);
      }
  
      State = InsertCoin;
      delay(1000);
      break;
  }
}

// this function blocks until a button is pressed
int GetPress(){
  int P1; int P2;
  
  do {
    P1 = digitalRead(P1ButtonPin);
    P2 = digitalRead(P2ButtonPin);

  } while(!(P1 || P2));
  
  int Key = P1? 0 : 1;
  Ding(Key);

  return Key;  
}

void Ding(int light){
  // e.g. 1 / 2048Hz = 488uS, or 244uS high and 244uS low
  // to create 50% duty cycle
  // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1231194692
  int Osc = 1000000 / Tones[light] / 2; // in microseconds
  
  // compute the number of iterations needed to hold
  // the nfote the desired duration
  int Iterations = Tones[light] * ((float)200 / 1000);
  
  // light on
  digitalWrite(LedPins[light], HIGH);
  
  // play tone
  for (long i = 0; i < Iterations; i++ )
  {
      digitalWrite(BuzzPin, HIGH);
      delayMicroseconds(Osc);
      digitalWrite(BuzzPin, LOW);
      delayMicroseconds(Osc);
  }  
  
  // light off
  digitalWrite(LedPins[light], LOW);
}

Next Steps

I’ll try to knock out another simple game tomorrow, and hopefully by Thursday I’ll have another component or two to play with. If not, I might be cracking open some household electronics for parts…

Export an iTunes Playlist to Android

After hunting around the iTunes menus, I was unable to find a convenient way to export an entire playlist to a folder that I could drop onto my Android phone.

Then I tried drag and drop…and it worked!

First, connect your phone to your PC. On the phone, pull down the notifications/ongoing bar and tap the USB item. It will probably say “Charge only”. Change this to “Disk drive” and tap “Done”

screenshot_44screenshot_45

Then on your computer, open up an Explorer window (Win+E):

image

Drill into the bigger disk (F: in my case) and look for an MP3 folder. Now go into iTunes and select all the songs you want from the library or a playlist.

Drag those songs into the MP3 folder:

image

Wait…

image

Of course any files with DRM won’t play, but the regular MP3s and unprotected M4As (most of my collection) will work just fine. Let’s see what Android does now. Reverse the above procedure to put the phone back into Charge mode and launch Music:

screenshotscreenshot_1

It takes a little while to build up the lists, but it does work, and you don’t have to wait for it to finish before playing.

Certainly not as slick as an iPod/iPhone, but for occasional (manual) syncing, it does the job.

Adventures in Unsubscribing (Spoiler: It Ends in “Grrrrr”)

I get a lot of email and a lot of it is “corporate spam”—mail that companies think they get to send to me because we have some sort of existing relationship. Here’s an example from Microsoft:

image

How do I unsubscribe? Check the footer, of course!:

image

They cleverly use “contact preferences” instead of the far, far more appropriate word “unsubscribe”, and manage to link not “contact preferences” but instead “Microsoft Privacy Statement”. It takes way, way too much thinking to figure out how to unsubscribe from this thing.

OK, so I click the link for “Microsoft Privacy Statement” even though that’s not really what I want and land here:

image

There are SEVEN different sets of preferences I need to check to unsubscribe from everything (I added the highlights). SEVEN! This is a software company…can’t you guys write some software to do this for me?!

I followed a partner email link to get here so after reading way, way too much, I see that I need the fourth link, which takes me to another site where I’m supposed to click “Manage Your Account” (after logging in!):

image

Are you kidding me?! Not only is this not an unsubscribe page, there’s no link called “Manage Your Account”. Let’s do “View…” instead:

image

Nice! The site is totally broken in Chrome. I’ll continue to the “Membership Center”:

image

Umm…MS, Imma Let you finish but 1995 has the best browser war messages of all time. ALL TIME! You’re telling me that I have to use IE for this thing? I’m not a browser zealot, but this is ridiculous. I’ll proceed anyway and weather the “rendering issues”:

image

OK, I guess not. Fine, I’ll use IE (and log in again):

image

After digging through the menus, I finally found “Manage Program E-Mails”. Let’s see what that does:

image

YES! Finally! Or…wait. That’s not what I want at all! I want to keep those notifications. I don’t want the marketing stuff. Where’s the marketing preferences?!

I give up. Grrrrr.

Here’s what Microsoft needs instead:

image

Easy to find unsubscribe link. Clicked and I see:

image

Done (no login required!). The only way Monitorus could improve this would be by adding an “undo” button here.

Microsoft, let me know where I can send this.