Over the last couple of days, now that Robogames 2013 has come and gone, I’ve been working on projects that are more experiments than anything else. A few weeks before Robogames, I noticed that there were sonars for real cheap on http://www.wrighthobbies.com/. At the time I didn’t realize that these were all over the internet and are essentially a cheap Chinese knockoff of devices like the Ping))) and SRF04/5. These sonars are dirt cheap, buying in bulk from Ebay can lead gets you prices approaching $1.50 a unit. Seems insane, considering I’ve bought a 5 pack of Ping)))s for $100, but one can by a pack of 10 of these little guys for $15. Needless to say I didn’t have high expectations for them. So I ordered a couple so that I could test against my collection of Ping)))s and SRF04s. Much to my surprise, they perform just as well as the Ping))) and the SRF04. I don’t know how long they will be available at this price, so I ordered a whole lot more of them. Their interface is the same as an SRF05, and you can connect the trigger pin and the echo pin and use only one I/O line per sonar, giving it the same interface as a Ping))).
One of my personal side projects is the Beaglebot, a small, tabletop or hardwood roving bot that I want to entirely operate using the Beaglebone, as in, without external AVRs, arduinos, etc. So I set out to understanding Linux kernel development so that I could write kernel drivers for all of my hardware. I was very happy to discover that kernel module development is actually really easy, nothing like driver development is with Windows. Within a week I had an LED driven by PWM and you could control its max brightness and blink rate from sysfs. At this point I was feeling confident enough to tackle driving a sonar from my Beaglebone. My testing of the sonars previously had used an Arduino Uno and interrupts to keep the CPU free from having to wait on the sonars to respond and to be able to do stuff during measurements, etc. This is exactly how you should write drivers for operating systems. So I wrote my sonar driver. And when I loaded it up and debugged it as best I could, I was disheartened that I could not get the sonar working properly, for I was getting extremely variant or random measurements. With all of my experience with microcontrollers, my thought had been that interrupt handlers would execute when interrupts occurred, but it’s a bit more complicated than that. Interrupts aren’t handled immediately, but rather put onto a queue which is sorted by priority and processed sequentially. This is not good for a device where its input is time dependent. So I began to explore other options and discovered that the Beaglebone has two high speed microcontroller cores, known as PRUs (Programmable Realtime Units), built into the CPU that can access the entirety of the memory map, meaning that they can access all of the memory, all of the IO, and the communications buses. They both have an interrupt to the CPU so that they can signal when they’ve completed some action, in this case, that the sonar has taken a reading. Before toying with the code, we have to hook up the sonar to the Beaglebone. The HC-SR04 is a 5V device, and will not operate at any less than that. As the beaglebone, along with every other ARM Cortex based system, has a maximum voltage of 3.3V, we have to protect the beaglebone from the sonar. Essentially all I did for this was connect an NPN transistor between one of the beaglebone’s IO pins and ground. This is fine considering that each of the IO lines on the beaglebone has a configurable pullup or pulldown resistor, we just have to note that the signal is now inverted. The base of the transistor is connected through a 220 ohm resistor to the echo line of the sonar. From experimenting, turns out 3.3V is enough to cause the sonar to trigger, so we can hook one of the beaglebone’s IO lines right up to the trigger pin. The schematic is essentially this
And this is what the setup looks like
The software I have provided on github assumes that the sonar’s trigger is using GPIO1_6 and the inverted echo signal is on GPIO1_7. The operation of the HC-SR04 sonar is fairly straight forward. One sends a trigger pulse of at least 10 microseconds. The device then waits for the echo line to activate (in our inverted case, high to low transition) and measures the time from there until it deactivates (low to high in our case). This time is the round trip flight time of the sonar pulse. Divide this number by 58, and you have the distance to target in centimeters.
The code on the Beaglebone side is a bit less straightforward. Unfortunately there is no higher level language available for the PRU than PRU Assembler. Oh well I suppose. The guide on how to use the sample code is here on my github: https://github.com/Teknoman117/beaglebot/tree/master/hcsr04-demo In the mean time, here is a YouTube video of my sonar code in action