Ultrasound Localization

The transmitter board with a receiver hooked up to an NXT.


This page describes an ultrasound-based localization system designed for use with Lego Mindstorms NXT. It uses four stationary transmitters in a 48" square and as many mobile receivers as desired. The transmitters are pulsed in a known sequence. The receiver uses deviations in the received signal from the transmitted sequence to determine its location. For example, if it measures a longer pause between the first and second pulse than was transmitted, it knows that it is closer to the first transmitter because sound took longer to travel from the second transmitter than the first. The transmitter can then communicate its location to the NXT over standard cables using either I2C or analog.


Simply plug the receiver board into the NXT and power it with either (NOT BOTH) the jumper or a 9V battery.

Serial Interface

At the beginning of your RobotC code, call the setupSonar() function (from move.h). Then you can call the getXYsonar() function in your RobotC code to get your position.

Analog Interface

The one part of the system that can be a bit unreliable is the I2C communication between the Arduino and the NXT. The analog interface is more reliable, but less accurate than the serial interface. About an inch of acccuracy is lost in the conversion from digital to analog and back to digital. The analog interface is intended as a backup, and we generally recommend using the serial interface. To use this interface, you must call the getXYanalog() function at least once every 40 ms. If you do this, the xa and ya variables will each be updated every 0.8 seconds (though not simultaneously).

For Best Results



The frame is made from standard 3/4" schedule 40 PVC. It should be set up with the transmitter boards above the cross bars. It can be collapsed for easy transportation. The lower crossbars (marked by blue arrows pointing towards them on the inside of the T-brackets) are removable. This should include the bar that has no wires running along it and the bar opposite that one. It may require considerable force to pull them apart.

Transmitter Board

At each corner of the frame is mounted an identical transmitter board, which contains a 40 kHz ultrasound transmitter and circuitry to drive it. The Transmitter is driven by a pair of BD135G NPN BJTs and 470 ohm pull up resistors off of a nominally 24V power supply (closer to 30V in reality). The inputs are the 0-5 V logic output directly by the arduino controller through a 470 ohm current-limiting resistor. There are also capacitors (1 uF ceramic + 10 uF electrolytic) to stabilize the power supply.


The transmitter is controlled by an Arduino Uno screwed to the PVC frame. It gets its power from a 5V regulator run from the 24V supply on the nearest transmitter board (it gets hot). The 8 outputs (2 for each transmitter board) are plugged into pins 2-9. There is also an LED plugged into PIN 10, which blinks when the system is running. It is only an indicator and can be removed if found annoying. The computer runs this code. It pulses the transmitters in sequence starting with the nearest and continuing counter-clockwise with 50 ms pauses in between. After the 4th transmitter, it pauses for 250 ms, meaning the entire cycle takes 400 ms (2.5 Hz). A pulse lasts for 1 ms (40 periods at 40 kHz) and consists of alternately raising the control lines to the appropriate transmitter for half periods. The Arduino Uno's each have slightly different clock speeds, so the pause duration in the code must be individually calibrated to get a uniform pulse sequence across boards.


The board primarily runs on 5V power. It also has a regulator to produce a 1.8V reference. The transmitter has one terminal connected to the 1.8V reference and the other terminal leads into an active high-pass filter with a gain of 20 and a cutoff frequency of about 32 kHz. The output of the op-amp is then fed into a comparator. A voltage divider is used to create another reference a few mV above the 1.8 reference. When the op-amp signal exceeds this reference, the comparator drives an interrupt on the Arduino Pro Micro (5V/16MHz). The Arduino uses this code to process the incoming data. From the time of the interrupts, it gets its relative distance to the transmitters (e.g. x inches closer to transmitter B than to transmitter A). It then does gradient descent to find it's x, y position in world coordinates. The origin is the transmitter near the transmitter Arduino Uno (x and y axis marked in blue on the PVC frame). The result is communicated to the NXT over either the I2C serial interface or through an analog voltage.


The board can run directly off of the NXT's power. To do this, place a jumper on the two header pins in the upper right corner. However, the NXT provides about 4.75 V, which is a bit low. It works when the NXT's batteries are fully charged, but gets somewhat iffy as the batteries get lower. As an alternative, you can plug in a 9V battery and power the board off of the regulator built into the Arduino. If you do this, remove the jumper, or you will be pushing power into the NXT, which it is not designed for. Supposedly it's idiot-proof enough to be buffered against this, but it can't be good for it.


With questions or feedback contact:
Eric Whitman