Monday, May 27, 2013

Frances's Tracing Game v1.03

I love three-day weekends. They give you time to think!

I've dusted off Frances's tracing game and finally fixed a niggling bug that had been bothering me. I'd taken a shortcut on centering the images on the screen by putting the image in a view that was embedded within a larger view. That solution had been playing passably, but it had annoying side-effects in Jellybean:
  1. Touch-drags that started outside the image didn't register when you dragged inward.
  2. As the drag operation happened, an annoying grey rectangle would flicker around the frame of the inner view. I never figued out the root cause of that.
I therefore ditched the two-view solution and did the math internally to set up the images in the center of the view (there's a convenient Canvas.translate method to do the offsetting for me in terms of drawing, and I do the translation of touch events from view coordinates to image coordinates myself).

There's a lesson in this. Sometimes, an operating system changes and it becomes clear that the OS's developers don't have your use case in mind. When that happens, there are a couple of ways you can respond. But when you're working on a hobby project and don't have the clout to steer the OS project itself, it's often easier to adapt to the changes than it is to push back. Don't be afraid to replace someone else's functionality with your own code. But when you can contribute, do; the svg-android renderer instance that I use seems to have issue with some flavors of transform logic, and if I don't find that this has been fixed in later versions, I plan to patch it and submit the changes back to the maintainers.

The new version of Frances's Tracing Game should be available in the app store some time today.

On a related note, there's one more bug to fix... I'm going to have to figure out what to do about the title. Frances herself is growing out of this game, but her younger sister was born this week. Welcome to the world, Cecilia!

Tuesday, May 14, 2013

Return of the Arduino part 3: mount the transmitter LED and load in the control code.

With the IR sensor and the status indicator LEDs in place, the only remaining steps are to wire up the IR transmitter and load the control software. Relative to everything else, this is the easy part. :)

My IR LED of choice is a 940nm LED that I picked up from Radio Shack. I used a basically direct connection to one of the digital output ports on the Arduino. The only complexity of this part is  the desire to make the IR trasmitter pretty mobile; I need to be able to position the receiver and transmitter separately from each other so I don't need to put a table in front of the TV to hold the enclosure. Since the LED is external to the enclosure and positionable, I grabbed some male-female servo extension cables from Amazon. I snipped one in half and glued the male end to the enclosure, making an external-facing plug.

Plug glued in position on the enclosure.

I then did away with the white wire (leaving only two channels) and soldered the black wire to the common ground used by the LEDs (the red wire gets a breadboard jumper wire and connected to digital port 13.

The LED side of the wiring is simpler. Cutting the male plug off of another servo extender and stripping out its white wire, I soldered the IR LED onto the remaining wires and added a bit of shrink tubing to clean everything up.

IR LED ready to be installed. Two leads off of it and some shrink-tubing to hold it all in place.

The final software package is available on Github. It's readily configurable for details, but its default configuration is as follows:

  • Listen for a signal from my remote (I happen to have a spare "blue button" that works just great).
  • When the signal is recognized, blink twice and begin a half-hour countdown.
  • At end of countdown, fire the off signal and go back to listenening for input.
 I ran a test (with the timer temporarily overridden from a half-hour to five seconds), and I'm pretty happy with the results!



Overall, this has been a pretty educational project. In the future, I'll try and add the Ethernet shield so that I can wire computer control into the entertainment system.

Monday, May 6, 2013

Return of the Arduino part 2: status indicators are your friends

The essence of user-friendliness is feedback. I won't be rivaling Apple with my little creation, but having more than zero indication that the IR receiver is actually picking up signal is probably wise. So the next step in the project was to mount some LEDs to the case to give me a bit of status indication.

A quick trip to Radio Shack netted me three red LEDs (2.6v, 28mA, 10mcd), one green LED (2.1v, 25mA, 6.3mcd), and a quad of 220-ohm resistors (and some 1K-ohm resistors). One thing I've learned during this process is to verify everything before busting out the permanent-connection hardware; before soldering or gluing anything, I bread-boarded the LEDs and used a slight modification on the Arduino "Fading" demo to confirm that all four LEDs would light. This turned out to be wise; my initial plan had been to use a 1K-ohm resistor between all four cathodes (in parallel) and ground, but I discovered that allowed too much back-current to leak across the LEDs---not desirable at all.

Breadboard. Arduino is connected by wires to four 220-ohm resistors, each leading to an LED, all leading to ground.
Final configuration for the LEDs and resistors on the testing breadboard.

Once I'd verified the configuration, it was time to get to work. Trimming the anode leads a bit on the LEDs, I soldered one resistor to each anode. I then grabbed my Dewalt and 3/16" bit again and bored four parallel holes in the upper half of the case, then glued the LEDs in place. Due to a slight mix-up on my part, the green LED ended up with its resistor on the cathode, but no harm seemed to be done. I soldered all the cathode leads (including the resistor lead from the green LED) into one, and left the anode leads to be connected to the Arduino.

I ran into a bit of a conundrum at this point: with the LEDs living on the top shell, I wanted some flexible wire with some nice, solid end plugs to connect the LEDs to the Arduino control pins, but nothing in my kit really fit the description. Fortunately, I discovered that Radio Shack sells a SideKick basic kit that includes what the kit calls "breadboard jumper wire." It turned out to be the perfect tool for the job if I cut them in half and soldered the loose wire to my LED leads.

With the jumper wires in place, I connected the LED anodes to Arduino pins 6, 9, 10, and 11, and the cathodes to one of the two GND pins. I then wrote a couple of short LED test functions:
// LED control library, by Mark T. Tomczak
// Public domain
// To use:
// * Call SetupLedControl with an array of LED inputs IDs
//   (-1 terminates the array as a sentinel value)
// * Call functions in the library to control the LEDs.

// Control LED firing patterns
// -1 used as sentinel value
int *g_led_control_leds;
int g_led_control_num_leds = 0;

// *leds is the arraay of LED pin IDs, terminated with a sentinel value of -1.
void SetupLedControl(int *leds) {
  g_led_control_leds = leds;
  g_led_control_num_leds = 0;
  while(*leds != -1) {
    g_led_control_num_leds++;
    pinMode(*leds, OUTPUT);
    leds++;     
  }
}

// Blink several times (off-on-off).
// - times: number of times to blink
// - flash_delay_millis: Number of milliseconds to wait
//   before toggling the light on or off. void FlashLights(int times, int flash_delay_millis) {
  for(int i=0; i < times; i++) {
    for(int i=0; i < g_led_control_num_leds; i++) {
      analogWrite(g_led_control_leds[i], 255);
    }
    delay(flash_delay_millis);
    for(int i=0; i < g_led_control_num_leds; i++) {
      analogWrite(g_led_control_leds[i], 0);
    }
    delay(flash_delay_millis);   
  }
}

// This is a fun little function that delays a specified
// number of milliseconds, while showing the time remaining as the
// intensity of several LEDs.
// 
// When all the time is remaining, the LEDs all glow at maximum brightness.
// Elapsing time is shown as the LEDs slowly going out one-by-one. void CountDown(long time_to_countdown_millis) {
  unsigned long start_time = millis();
  // TODO(mtomczak): Arduino millis() function rolls over to 0 after 
  // about fifty days. You should account for this rollover... 
  // possibly build a timer library with some structs to hold that state.

  for(
    long time_elapsed = 0;
    time_elapsed < time_to_countdown_millis;
    time_elapsed = (long)(millis() - start_time)) {
    float percent_remaining = (float)(time_to_countdown_millis - time_elapsed) / (float)(time_to_countdown_millis);
    float led_fraction = 1.0 / (float)(g_led_control_num_leds);
    for (int i=0; i < g_led_control_num_leds; i++) {
      // The logic is exciting here, but it basically boils down to:
      // * consider the time remaining to be divided into a series of "ranges"
      //   (one per LED).
      // * If the time remaining is more than my range, glow maximum intensity.
      // * If time remaining is less than my range, shut off completely.
      // * Otherwise, glow proportional to how much time is left within my
      //   range.
      int output = 255;
      if (percent_remaining < led_fraction * (float)(i + 1)) {
        if (percent_remaining < led_fraction * (float)(i)) {
          output = 0;
        } else { // percent remaining is in range led_fraction * (i, i+1)
          output = (int)((percent_remaining - (led_fraction * (float)(i))) * 255.0 / led_fraction);
        }
      }   
      
      analogWrite(g_led_control_leds[i], output);
    }    
  }
}

I combined this library with the recognition code from my Arduino IR bridge project so that it would blink twice and then count-down over five seconds when it recognized an IR pattern. Overall, I'm not unhappy with the results!

What I learned

  • This is the part of the project where the insulating properties of hot glue were especially helpful. I basically glued over the forest of wired-together cathodes so that they couldn't short against anything, and I'm pretty pleased with the results.
  • Pay more attention to output ratings on LEDs. There's a noticeable visual difference between the green LED and the much brighter red LEDs (I'm guessing that my eye is reacting logarithmically to the difference between 6.3mcd and 10mcd). If I wanted to back this part out and try again, I'd go with four red LEDs.
Part three will wrap things up by adding the IR emitter and the code to drive the entire project.

Sunday, May 5, 2013

Return of the Arduino part 1: mounting the controller and IR receiver

I've had an Arduino UNO board kicking around my house for about a year. My original plan was to create an input switcher for the TV that would run off the cable remote (it would maintain a bit of internal state and fire the commands to switch TV modes from the current one to the desired one instead of needing to fish around for the TV remote). This was pretty successful, and I published both the IR decoder and the input changer itself on GitHub. But I never got around to enclosing the project and making it "clean."

So this week, I finally purchased an enclosure and power supply for my UNO board. Trying it out, I immediately discovered that the enclosure doesn't really fit my Ethernet shield (which the reviews will tell you gladly; that's what I get for not reading the reviews before purchasing). Since I didn't need the shield, I shed it (I'll probably get another UNO to plug it into later).

Then, I got out my kit and got to work. It's been awhile since I had occasion to solder anything, and I've never done hot glue for an electronics project before. Overall, I'm not unhappy with the results.

Open Arduino enclosure, showing the Arduino board nested in position and the IR decoder glued in place.


I made a hole in the enclosure using a 3/16" bit on my Dewalt drill, angling it diagonally back-and-forth to get a good wide slot (I wanted to make sure the receiver had a nice, wide field-of-view to catch IR signals). I then seated the Arduino board in the enclosure and glued the IR sensor in place with my wife's glue gun (note to self: I've stolen my wife's glue gun and owe her a new one). My gluing technique is hellishly wasteful, but I figure I'll get better with practice. One thing I love about working with glue is that it doubles as an insulator; no more wiggling my fingers in between tiny wire runs to get the electrical tape on there!

Front face of Arduino enclosure, showing the IR decoder visible through the drilled slot.
IR decoder visible through the drilled slot in the side of the enclosure.


Once the glue solidified a bit, I did a quick soldering job and was all set. I wrapped the signal and power wires around the posts in the enclosure also and threw some hot glue on there for mechanical stability (I want to make sure any jostles the wires might take are being supported by the posts and not the Arduino's female pin coupler or the IR sensor's leads).

I then fished a sticker out as a finishing touch. :)

Back-face of enclosure, showing sticker depicting two Androids on skateboards.


I'm very happy with both this sensor and its range. I ran some quick tests with the full enclosure at different ranges using my old remote signal decoder program, and found it was able to sense a good distance away (about 15 feet; plenty for my needs).



What I learned

  • This IR sensor is more temperature-resistant than I'd feared it might be; I ran the soldering without any heat sinks, and no harm was done.
  • Hot glue is actually pretty safe to work with; I'd worried I would get burned, but discovered that it appears to shunt its heat pretty quickly as it transitions to a solid state. solid strands can be touched within a few seconds of being emitted from the nozzle (though blobs should be given about thirty seconds to a minute to gel cleanly; they change opacity a bit on solidification, which is convenient).
  • Hot glue is messy; spiderweb-strands everywhere, needed to go in with pliers to clean it up. Also, I'll be more careful in the future about letting the glue find its way into the seam of the enclosure itself; my enclosure no longer seats quite correctly because one blob of glue bubbled over the top and got into the joint.
Part 2 will discuss extending the software and adding status indicators.