The world's first
"robot" was arguably Herbert Televox, built by Westinghouse. At the
time, Herbert's ability to listen to commands over the phone and report back
data was ground-breaking. Herbert Televox itself was really a standard electric
box with a complex assortment of switches, timing and buzzers. The box was
placed into a robot-shaped cutout when demonstrating its capabilities.
Herbert Televox. The box in its stomach is an advanced (for the 1920's) control unit; the robot body is simply the 1920's version of cheap plywood. |
I built a scale
model of Herbert Televox for a talk with early-in-career programmers where I
work. The scale model had the ability to detect a phone being picked up and
measure the depth of a water reservoir. I wanted a live demo with a phone
connected to the scale model Herbert Televox, and a water sensor from the
Herbert Televox into a little model reservoir. The reservoir is really just a
small glass dish. Then I'd pick up the phone, actually dial some numbers, and
then Herbert Televox would buzz once, twice, or three times based on the
reservoir depth.
What I needed for a demo
To power the smarts
of my Herbert Televox I used a Particle Photon, an Arduino-based
microcontroller with Wi-Fi capability. After struggling with debugging with
just an LED, I added a small Adafruit_SSD1306 OLED display. In order that I
added them, the Herbert Televox abilities are:
- Can detect a phone going off-hook and light the blue LED
- Can write to an OLED display with debugging information
- Can read the water sensor and split it into one of three different water levels
- Can ring a small buzzer based on the level of the water
- Can wait a period of time after the phone goes off-hook before buzzing the buzzer
The Arduino base of
the Particle Photon makes some of this very easy. For example, it was easy to
set up an analog to digital convert (ADC) for the phone off-hook detection. But
the nature of programming the Arduino made handling timing awkward; I'll show
my solution.
Connecting a phone and writing to an OLED
Diagram of a rotary phone showing the handset, the cradle in which it's placed, and the on-hook/off-hook switch |
Although a phone
jack is large enough for 6 wires, and is normally wired up with four wires (the
inner four), a classic rotary phone works off of just two wires: one red, and
the other green. The two wires form a loop with a certain resistance. Every operation
of the phone (taking the handset off-hook, dialing, and talking) will change
the resistance across the wires in a way that can be easily detected by the
Arduino.
To connect my demo
phone to the Particle Photon Arduino, I used a RJ11
right-angle jack breakout board which I bought from Amazon, but it's also
available for less straight from the maker along with an enticing set of other
boards. I plugged the phone into the jack and ran some wires from the nice
terminal strips on the breakout board to the Arduino.
CZH Labs D-1039 Phone Breakout board (<$10) |
Wiring setup for measuring phone resistance |
In particular, the
connections are
- Put the Particle Photon into a breadboard
- Terminal 3 (green) to ground
- Terminal 4 (red) to a spare row on the breadboard
- From the same row, connect a 1K resistor to Vcc
- From the same row, connect a wire to A0 on the Photon
The resistance of
the phone and the fixed 1K resistor forms a voltage divider that runs from Vcc
to ground. When the phone is on-hook, it has a rather high resistance so that
the voltage at A0 will be close to Vcc and an AnalogRead of the pin will return
4096 (the maximum value). When the phone is off-hook AnalogRead of pin A0 will
read about 1680 with a variation of about 50.
The actual code to
read the phone off-hook starts at line 57
// To blink the LED, first we'll turn it
on...
digitalWrite(bluePin, HIGH);
phone = analogRead (phonePin);
measure = analogRead (measurePin);
speed = phone/64;
// on hook = 4096 off hook = 1680+-50 or so
int isOffHook = (phone < 2500);
// …
// A BUNCH OF OTHER CODE
// …
// Report the analog phone value via blue LED
delay(speed);
if (isOffHook) hookTimeDelta += speed;
digitalWrite(bluePin, LOW);
delay(speed);
if (isOffHook) hookTimeDelta += speed;
When the phone is
off-hook (a person has picked it up), I track the amount of time that the phone
has been off-hook. That's because I will need to delay actually buzzing the
buzzer for 2 seconds or so after the phone is picked up. When the phone is not
off-hook, the hookTimeDelta is reset to
zero (it get reset to zero a lot, but that’s OK).
I get a speed to
flash the blue LED based on the phone analog value; I use a constant 64 to make
for a "nice" flash speed (not too fast, not too slow). This value was
picked based on observation.
After mucking around
trying to debug the analog values using just the LED flashes, I got smart and
wired up an OLED so that I'd get a little display. This was super useful;
debugging these microcontrollers without a decent debugger is pretty painful.
On each loop, I erase the OLED and print the phone analog reading; that's how I
know the exact range of analog readings for the phone.
Quick and easy water sensor (list #3)
The water sensor is
just a length of insulated twisted-pair telephone wire (I snagged 25 feet of
50-pair telephone wire from a dumpster 20 years ago, and have been using it as
my go-to wire ever since). I scraped off 1-cm long sections of insulation in three
places: at the very end and then twice more spaced apart by about 3 cm. Then I
taped the wires together so that the bare sections are right next to each other
just a few millimeters apart.
This crude sensor
was then read in by analog pin A1 in the exact same way that the phone analog
value is read: the water sensor is part of a voltage divider. One of the water
sensor wires is at ground, the other is the mid-point, and then there's a resistor
from the mid-point to Vcc. I used a 1K resistor because it was supplied as part
of the Photon Particle kit. I then wrote the resulting values into the OLED
debugging screen, and discovered that it wasn’t nearly sensitive enough.
The easy way to pick
a fixed resistor for these simple voltage dividers is to use a resistor that's
approximately the same as the variable resistance that you're measuring. For
the water sensor, 1K was much too low, so I scrounged up a 10K resistor from a
different kit.
Once I had a set of
analog reading from the water sensor that seemed to be far enough apart that
they would be clearly distinguished, I simply dipped and undipped the water
sensor to get some useable split-points and then set an nbuzz variable to be the number of buzzes that I wanted.
Ringing a buzzer (list #4)
The Photon Particle
kit I have includes a small buzzer. I followed the instructions, connecting it
to digital pin D0 and initializing that pin with the pinMode function to be an OUTPUT pin. There are two commands, tone and noTone
to turn the buzzer on and off. After a few experiments, I settled for buzzing
the buzzer at 40 Hz for 200 milliseconds with a 500 millisecond gap between
them. At the same time I set up a didBeep
variable which starts at 0 (false) and is set to 1 (true) when I beep. The
variable is also set back to 0 whenever the phone is on-hook. This ensures that
I only beep once per off-hook event.
Waiting to buzz (list #5)
It's not good just
to buzz as soon as the phone is picked up. For an effective demo, the presenter
will need to pick up the phone, dial, and then pause, all while explaining what
the device will do. I solved this problem with two variables: the hookTimeDelta time count that's increased by
the time value passed in to each delay()
function, and an didBeep variable that
says whether I've done the beep for any particular off-hook event.
The actual code for
deciding to buzz is then just
if
(isOffHook == 1 && hookTimeDelta > 2000 && !didBeep)
{
didBeep
= 1;
}
This will guarantee
that the buzzes only happen once, and after a delay. Dialing is a different
story. I decided against actually detecting the phone dial digits for the much
simpler detection of whether the phone is dialing at all. Detecting the phone dialing
is trivial: when rotary (technical: pulse-dial) phones are dialing, internally
the phone is just going on and off hook. The existing code that detects on and
off hook is sufficient to pause the buzzer while dialing.
The way the delay
works is that every time the phone is seen to be on-hook (which includes the
pulses from dialing), the hookTimeDelta value is reset to zero. This means that
the buzzing will be automatically delayed every time the phone is dialed!
From a presenter
point of view, the demo involves picking up the handset and talking while
dialing. So long as the dialing keeps happing, the buzzing is delayed. The
presenter can choose when to stop dialing and let the buzzing happen!
The good and the bad
Three great parts of
using the Particle Phone Arduino Wi-Fi controller:
- The over-the-air downloads worked very smoothly. I could edit my code in their editor and press the "download now" button to flash the chip; this was as fast as could be expected.
- Debugging by writing to an OLED was a real time saver, especially since there no other obvious debugger in their environment.
- The simple A2D conversions were super useful for connecting the water sensor and phone.
Some less than good
parts:
- The default Photon setup is
that connecting to the development Wi-Fi is required for the program to run. I
learned this on the day of my presentation, far from my development area.
The actual code didn't work for the demo at all.
The solution is to put SYSTEM_THREAD(ENABLED); in your code - The Arduino concept of "setup" and "loop" was awkward in practice. This little robot really needs a state machine, but that's not the simple path for Arduino.
- The Particle Photon
documentation didn't mention what the actual OLED type was, even though
it's part of the Particle Photon dev kit. I had to poke around for too
long to find the libraries and then figure out how to use the libraries.
Turns out it's an Adafruit SSD1306.
#include
Conclusion
Herbert Televox was
an awesome robot, even if it was just the 1920's version of cheap plywood.
Making a modern version was an effective prop for a bigger presentation.
You can see the
original Herbert Televox at the http://www.themansfieldmuseum.com/
No comments:
Post a Comment