Tellymate is an Arduino shield that outputs all Serial.print() commands to a television (NTSC or PAL composite video). I’ve had one kicking around for a couple of years now. I bought it thinking that I’d like to build a “new” kind of interface/display. I even bought an inexpensive portable TV/DVD player for the purpose. That project is still on my ‘to-do’ list, but I had another problem—that Tellymate solved simply and elegantly.
I’ve been picking at the Media Circus project for about year, making improvements, letting it run to see if any bugs cropped up. Media Circus is a scrolling marquee that displays amusing headline news mashups. It receives updates from Twitter once a day, early in the morning. To do this, it needs to self-reset. This is not simply a matter of running a wire from a digital output pin to the Reset pin on the Arduino. A dependable self-reset requires a delay and ‘safety switch’ circuit.
The Problem…
Because the unit resets only once a day, I needed several days to test it. It seemed to work as designed with more frequent resets using a test program, but when I incorporated my reset code into the Media Circus sketch and let it run, I discovered that it would reset the first time, but never again. I needed to know what was going on in the program. Using the Arduino IDE, if you want Arduino to tell you what state it’s in at various points, you drop in Serial.print() statements and then open Arduino’s Serial Monitor. For short runs, this works, but Serial Monitor sometimes crashes if you give it lots of data to display over a long period of time. Additionally, when the system resets, it closes the Serial Monitor.
My next thought was to bypass Serial Monitor and attach a small LCD screen to show the various values. I tried the Arduino built-in LiquidCrystal library, but it didn’t work for me with the particular arrangement of hardware and software—I wasn’t able to figure out precisely why. Next, I tried a different library, arduinoshiftreglcd, which worked with the MEGA and the Ethernet Shield, but failed when in the presence of the Ethernet or EthernetUDP libraries. I was about to look at the New LiquidCrystal library, when I remembered the Tellymate.
The Solution…
Tellymate doesn’t require any additional code: if you can print to the Serial Monitor, it will show up on the TV. But there are two very simple functions that Batsocks provides that were useful to me: screen_clear and cursor_move. My TV display shows the number of seconds since midnight, the rough geographic location (Beijing/Moscow/London/Halifax/Vancouver) and Daylight Savings Time/Standard Time, and the epoch time at reset. This has finally allowed me to find—and solve—the problem!
An electric lamp doesn’t like anyone to see it when it’s turned on. It hides under a bushel basket and when it’s exposed, it fades out. When the basket is replaced, it lights back up.
This is another project in the series “The Technology of Good Intentions”: these works are intended to focus the viewer on the role of failure in design.
The entire assemblage uses two X-10 modules: an PL513 Power Line Interface (PDF) and an LM465-equivalent lamp module. The PL513 provides an interface from the microcontroller to the X-10 protocol, and the LM465 accepts commands (such as dim light and brighten light) to control the light.
Why X-10?
A primary project requirement was the ability to have the microcontroller dim and brighten the lamp on command. I investigated three ways of doing this:
Making a light dimmer using a triac and opto-isolation. This is easier said than done. I found that there are complications, such as buzzing, radio-frequency interference, and of course, safety, since I was playing with 120v AC current. I experimented with triac control using low-voltage AC, and decided it wasn’t worth the effort in trying to overcome the drawbacks just to save a few dollars.
Buying a hardware-store light dimmer switch and using an actuator—such as a servo or stepper motor—to engage the dimming and brightening. At an early stage of the design process, I had decided that the project was much more complicated than I first thought, and I wanted to avoid making it look like a Rube Goldberg device.
Using the X-10 system, which transmits commands through household AC power. The Power Line Interface module uses 4 wires to connect to a 5-volt microcontroller, via a standard RJ11 telephone plug.
I had used the X-10 as an automatic light dimmer years ago, and though I found it sometimes quirky, it worked 95% of the time and was super-safe. Plus, no moving parts were involved. I chose door number three.
How’s It Work?
The overturned basket is closed. The user activates the gadget using a foot-switch.
The switch sends an electrical pulse to a box enclosing two interlinked ATMEGA168 microcontrollers. In this case, the “Master” controller receives the foot-switch signal.
The Master ATMEGA signals the “Slave” controller to direct a servo motor to open the basket. The sole purpose of the Slave controller is to generate the pulse-width modulation commands to the servo motor.
The Master controller also sends a “dim lamp” message to the X-10 power line interface, which is plugged into a 120-volt power wall socket. The interface translates the 5-volt pulse generated by the Master controller into an encoded series of pulses on a 120 kHz carrier wave, on top of the 60 Hz AC power signal.
The commands generated by the X-10 power line interface are received by the X-10 lamp module.
The lamp under the basket dims as the basket opens.
Why TWO Microcontrollers?
The Master Control microcontroller handles the foot-switch input, orchestrates the timing of the opening/closing of the basket (using commands to the Slave Control unit) and the lamp dimming. Initially, I had no idea that the project would require two; there are enough analog and digital pins on one microcontroller to do it all, but—and I’m not absolutely certain about this because I didn’t keep detailed notes about this—I think that I was forced into a dual processor arrangement because of the complexity of the program timing. As I designed the circuit, I came to the realization that the timing required by the various elements was going to be difficult for me to accomplish as an amateur C-coder if I tried to stuff it all into one controller. So I don’t want to say that “it can’t be done with one chip”. I just decided that it was simpler for me to compartmentalize the various tasks with hardware. So I added another ATMEGA168, at an added cost of about $5.00.
Physical Considerations
The Lamp
Before starting the design, I had ordered an LED light bulb from Dealextreme: this 128-LED bulb uses an E27 socket (the familiar screw-in type found in most incandescent and compact fluorescent bulbs) and draws 6 watts. It has a diffusion enclosure that makes it look somewhat like a typical light bulb. This LED bulb was preferable because I wanted the light to stay on under the basket when it was closed. It’s lower current draw resulted in less heating in a small enclosed space. There was only one problem: when combined with the X-10 dimmer, I discovered that this bulb wasn’t fully ‘dimmable’!
After I recovered from this mild disappointment, I elected to use a clear “BT” shaped halogen lamp. Halogens put out a lot of heat, so I had to add a routine to dim the lamp after a short delay whenever the basket covered the lamp. Additionally, although this dimming routine never failed while it was on the testbed, I was concerned that this X-10 ‘dim’ command might, at times, fail to dim the lamp, heating the inside of the basket, causing a fire hazard. So I added a second level of safety: a CDS cell monitors the light level when the basket is fully closed. After the basket closes and the unit goes into idle, the state of the light sensor is polled: if the light level is above a certain level, the X-10 issues an immediate “light off” command. This certainly doesn’t cover all contingencies—especially if the X-10 suddenly fails while the lamp is on—but I’m less concerned about the fire hazard issue now.
Construction Notes The servo and linkages are bolted together using Meccano hardware. The main hinge that connects the base of the basket with the base is also Meccano: to secure the hinge, I used a dab of thread locker on the bolts. The servo is a heavy-duty unit (SG-5010) that has metal gears and a stall torque of 3kg. As I found in design and testing, this amount of torque is enough to wrap the 17 gauge steel linkage wire around the servo shaft!
The Next Iteration…
The next version, if there is one, will dispense with the X-10 control and use high-powered DC LED illumination. Rather than a light in the centre of the base, I would consider attaching the lighting to the inside of the basket.
Using an Arduino, a simple three-wire ultrasonic rangefinder, and an RGB distance indicator, you can park your car with precision.
Contrary to most people I know who have garages, we still use ours to store our car. And when we did a minor garage renovation—actually, it was more of a cleanup and reorganization—I decided to build a gadget that would give us an indication of how close we are to the back (inside) wall of the garage.
There are many devices available for drivers to help them gauge their car’s position. My brother Ralph has a simple low-tech solution: hang a tennis ball from the ceiling. Works great as long as you always enter the garage leading with the front of the car. Other solutions include a laser, a stopper on the floor, a photo-electric beam, and an ultrasonic rangefinder from GE—Not General Eccentric. Those other guys.
The GE device is battery-operated and uses a red/yellow blinking LED for driver feedback. This device can be configured to display red at a distance of 1, 2, or 3 feet from the rangefinder.
My device operates using a wall transformer (actually, I’m using spare capacity from the transformer that powers my Oil Tank Level Sender project) and employs a non-blinking RGB LED that glows green until the car bumper reaches 30 inches distance to the rangefinder, orange from 30 inches to 12 inches, red from 12 inches to 6 inches, and blue/purple 6 inches or less.
Here’s the sketch, which is adapted from the David Mellis/Tom Igoe “Ping Sensor” example that comes with the current Arduino IDE:
/* Ping))) Sensor
This sketch reads a PING))) ultrasonic rangefinder and returns the
distance to the closest object in range. To do this, it sends a pulse
to the sensor to initiate a reading, then listens for a pulse
to return. The length of the returning pulse is proportional to
the distance of the object from the sensor.
The circuit:
* +V connection of the PING))) attached to +5V
* GND connection of the PING))) attached to ground
* SIG connection of the PING))) attached to digital pin 7
http://www.arduino.cc/en/Tutorial/Ping
created 3 Nov 2008
by David A. Mellis
modified 30 Jun 2009
by Tom Igoe
This example code is in the public domain.
*/
// this constant won't change. It's the pin number
// of the sensor's output:
const int pingPin = 7;
const int redPin = 6;
const int greenPin = 5;
const int bluePin = 4;
void setup() {
// initialize serial communication:
//Serial.begin(9600);
pinMode (redPin, OUTPUT);
pinMode (greenPin, OUTPUT);
pinMode (bluePin, OUTPUT);
}
void loop()
{
// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
long duration, inches;
// The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(15);
digitalWrite(pingPin, LOW);
delayMicroseconds(20);
// The same pin is used to read the signal from the PING))): a HIGH
// pulse whose duration is the time (in microseconds) from the sending
// of the ping to the reception of its echo off of an object.
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);
// convert the time into a distance
inches = microsecondsToInches(duration);
if (inches > 30) {
digitalWrite(greenPin, HIGH); // green LED
digitalWrite(redPin, LOW);
digitalWrite(bluePin, LOW);
}
else if (inches <= 30 && inches > 12) {
digitalWrite(greenPin, HIGH);
digitalWrite(redPin, HIGH); // orange LED
digitalWrite(bluePin, LOW);
}
else if (inches <= 12 && inches > 6) {
digitalWrite(redPin, HIGH); // red LED
digitalWrite(greenPin, LOW);
digitalWrite(bluePin, LOW);
}
else {
digitalWrite(redPin, HIGH); // purple LED
digitalWrite(greenPin, LOW);
digitalWrite(bluePin, HIGH);
}
delay(100);
}
long microsecondsToInches(long microseconds)
{
// According to Parallax's datasheet for the PING))), there are
// 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
// second). This gives the distance travelled by the ping, outbound
// and return, so we divide by 2 to get the distance of the obstacle.
// See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
return microseconds / 74 / 2;
}