Sonar Scanner

As part of an ongoing project I sourced a mounting bracket for an HC-SR04 ultrasonic sensor sitting on top of a 9g servo motor that can be used to rotate the sensor through a 180 degree arc. I also wanted to include a DHT11 temperature sensor to help determine a more accurate speed of sound.

The final setup will probably be run from an Arduino Nano but before planning that I wanted to run some tests on a handy Uno as that has more power supply pins immediately available. The actual rats nest is shown.

Here are how the components are wired up to the Arduino.

The DHT11 I have is mounted on a little board that includes a pull-up resister between Vcc and the data pin and in fact only exposes Vcc, Ground and data out pins. This is the most common format around as far as I can see and adds up to a nice package that has reasonable accuracy (within 2C in the range 0C to 50C). I downloaded and installed the DHT library from Adafruit to read the sensor although there are others around.

The test rig code is pretty straightforward. I allowed a short pause before reading the temperature sensor and then using the returned value to calculate a value for the speed of sound in air – actually the time required for sound to travel 1 kilometre. Humidity and air pressure both have marginal impacts upon the speed of sound but temperature is key.

There are two main test routines. One rotates the ultrasound sensor on one degree steps over a defined arc. This routine includes reading distance measurements from the sensor but as they are displayed on the serial monitor through an asynchronous USB UART the values flashing past are probably going to be a bit historical. So I also added a testDistance() function and used that to measure the accuracy of the output. Results were good – well within a centimetre over my test range of 10cm to 100cm.

#include <Servo.h> #include "DHT.h" #define SERVOFORWARD 80 #define SWEEPINTERVAL 16 #define DHTTYPE DHT11 template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; } Servo mServo; const uint8_t tPin = 7; const uint8_t rPin = 8; const uint8_t dhtPin = 2; const uint8_t servoPin = 9; bool sonarSweep = true; float soundSpeed = 331.3; DHT dht(dhtPin, DHTTYPE); void setup() { Serial.begin(115200); delay(3000); //let the temperature sensor adjust float t = dht.readTemperature(); Serial << "Temp: " << t << "C\n"; soundSpeed = 10000 / (soundSpeed + t * 0.606); // adjusted time for 10K Serial << "Speed of sound: " << soundSpeed << '\n'; delay(1000); initSonar(); } void initSonar() { pinMode(tPin, OUTPUT); pinMode(rPin, INPUT); mServo.attach(servoPin); mServo.write(SERVOFORWARD); // center the servo sweep(60); //testDistance(); } void testDistance(){ while(true){     Serial << "range: " << getDistance() << '\n';     delay(1000); } } void sweep(int angle) { int pos =; // read the start position int lmt; uint32_t curMillis, lastMillis; curMillis = lastMillis = millis(); while(sonarSweep) {     for(lmt = SERVOFORWARD + angle; pos <=lmt; pos++) {      mServo.write(pos);      while(curMillis - lastMillis < SWEEPINTERVAL) {         curMillis = millis();      }      lastMillis = curMillis;      Serial << "range: " << getDistance() << '\n';      }     for(lmt = SERVOFORWARD - angle; pos >= lmt; pos--) {      mServo.write(pos);      while(curMillis - lastMillis < SWEEPINTERVAL) {         curMillis = millis();      }      lastMillis = curMillis;     } } } int32_t getDistance() { // Send sound pulse digitalWrite(tPin, LOW); delayMicroseconds(2); digitalWrite(tPin, HIGH); delayMicroseconds(10); digitalWrite(tPin, LOW); // Read echo pulse length int32_t pulseWidth = pulseIn(rPin, HIGH); // Calculate and return distance int32_t distance = (pulseWidth/soundSpeed) / 2; return distance; } void loop() { }

The constant SERVOFORWARD can be tweaked to align the sonar module so that it faces forwards (installation dependent).

SWEEPINTERVAL can be tweaked to adjust the speed of the scan rotation.

As mentioned, the serial monitor output in the sweep() function is there for entertainment purposes only. One plan is to get the function to raise an alert when a predefined distance on a specific bearing is detected and to otherwise maintain a 2 dimensional "map" in the form of a set of distances and bearings.

Now all I need do is work up a nice tidy Arduino Nano implementation that can communicate over a serial interface (I2C looks favourite) to whatever will be central to the project.

Edit: There is now a second post on my sonar scanner and it can be found here.

Next up is a trial rig for an infra-red laser scanner.


Popular posts from this blog

Arduino Regular Expressions

Unicode output from an Arduino.

ESP32 Camera