Sonar / Echolocation with an Arduino
The first time I saw a Maxbotix Ultrasonic Rangefinder, I knew I had to have one. My mind filled with thoughts of bats and dolphins, echolocating. I'm the kind of geek-slash-animal-lover who, as a kid, used to swim underwater making noises trying to echolocate like a dolphin. (I probably shouldn't admit to that. And anyway, it never worked.)Only in the last few years have I learned that some blind people actually do echolocate, though not underwater. But it takes a long time to learn, and not everyone can do it. Wouldn't it be great (especially if you were blind) if you could build something you attach to a hat or glasses? You could walk around hearing pings indicating whether you're about to walk into anything, or get walked into. How cool is that?
I already had a sonar rangefinder, which I used for a simple proximity webcam demo in a talk on plug computing.
With the demo over and the device known to work, I could finally try making a sonar device.
Clicks in earbuds
I wanted to use earbuds -- no reason everyone else should need to hear your sonar as you walk around. But how do you do that?
The obvious way works, as it turns out. Connect one earbud wire to one of the Arduino's digital outputs (via a resistor, to reduce the volume), the other to ground. Of course you can connect both earbuds to the same output, or to different outputs if you want to send different signals to each ear.
Then program the Arduino to set the line high, pause a short time, then set it low again, like this:
#define EARBUD 1 /* pin number */ #define clicklen 10 /* milliseconds */ #define timeout 2000 /* milliseconds */ void loop() { while (1) { digitalWrite(EARBUD, 1); delay(clicklen); digitalWrite(EARBUD, 0); delay(timeout); } }
This gives a short click ever 2 seconds. Once the rangefinder is hooked up, I'll make timeout a variable and adjust it according to the rangefinder signal.
I used cheap earbuds: the digital output is sending a square wave and probably isn't good for earbuds, so don't risk a set you care about.
I had to experiment to find a good resistor value to keep the volume audible but quiet enough not to be annoying. 10k was about right for my dollar-store earbuds. Of course, if you were actually building this device you'd want to use a potentiometer so you'll be able to adjust the volume as you walk, or use earbuds that come with one.
One sound-on-arduino page I found put a capacitor inline with the resistor ... to smooth out the waveform? I tried a 47 uF capacitor, but it didn't make any difference I could hear.
Adding the rangefinder
The rangefinder plugs in just like in my proximity webcam project: Power on the rangefinder to 5v on the Arduino, Gnd to ground, and AN (analog signal) to the Arduino's analog pin 1.
Then I just need to read the rangefinder output and map it to an appropriate delay between clicks. That took some tuning. Initially I just made the equation linear, for simplicity, and I experimented to see when I wanted to hear the clicks getting closer together. Something like this, added at the beginning of loop():
#define FACTOR 15 #define MINRANGE 20 float range = analogRead(RANGEFINDER); int timeout = FACTOR * (range-MINRANGE);
Pretty cool -- now I could hear the clicks get really close together as I put my hand in front of the sensor.
But when I took the device outside, I found sometimes it would stop making noise for a long time, or even forever. Some of that was due to an earlier equation I used, where the values could sometimes be negative. (With the equation I showed above, they probably won't be -- I've never seen the rangefinder return single digits.) So I added a minimum:
#define MIN_TIMEOUT 5 if (timeout < MIN_TIMEOUT) timeout = MIN_TIMEOUT;
That got rid of the "stops clicking and never starts again" problem. But I still had delays that were too long: if you face an open area, you might have a timeout of 6 seconds, and you could easily turn and walk into a tree before those 6 seconds are up. So I made a maximum timeout of 2 seconds: it will never go longer than that between checks.
#define MAX_TIMEOUT 2000 if (timeout > MAX_TIMEOUT) timeout = MAX_TIMEOUT;
Much better! Now I could walk around and -- usually -- get warned before I got too close to obstacles.
You can grab the source and a Makefile for my test program program at sonarduino.
It's not perfect. Sometimes it gets a spurious reading from the rangefinder, and waits too long before warning you. It would really be better if it continued to check during those long timeouts.
And the rangefinder really doesn't give very reliable results much beyond a meter and a half. There are other models of rangefinder, and you'd probably want to experiment with several models before trying to use one of these gizmos to walk around at normal speed. You might even want to have two different types of
So this is just a start. I'm not going to give dolphins or bats any competition yet, and it's certainly not good enough that a blind person could use it to walk around at full speed. But it's a fun project, very easy to build, and I'm looking forward to playing with it further.
[ 16:54 Sep 18, 2011 More hardware | permalink to this entry | ]