This tutorial shows how to detect movement direction in two dimensions using an Arduino Uno and two HC-SR04 ultrasonic distance sensors. I wrote my sketch to detect movement from left to right or from right to left, but it should be possible to adapt for other use cases, like detecting movement into or out of a room.
The setup relies on a very simple premise: By placing a pair of sensors in close proximity, we can infer the direction of movement from the order in which the two sensors detect it.
How it works
To understand what it means for a sensor to detect movement in this context, it might help to first understand how an ultrasonic distance sensor works. Very simply, a sensor like the HC-SR04 works similarly to a bat’s sonar: by sending out an ultrasonic pulse that bounces when it encounters a barrier, like a wall, a person, or an object. After it bounces, the pulse returns to the sensor, which computes the distance to the barrier based on the time it took for the pulse to return.
The HC-SR04 uses two specialized pins to accomplish this, in addition to its power and ground pins: a “trigger pin,” which sends out the signal, and an “echo pin,” which receives the returning signal after it bounces.
This distance detection happens continuously, whether anyone moves in front of the sensor or not, which means we need some additional logic to detect whether someone is passing by. In my code, I define the maximum distance that I care about detecting movement at; if a sensor’s distance measurement drops below that, I consider the sensor “triggered.” The right distance limit will depend on your application, but might correspond to the width of a walking path, the width of a doorway, or the size of a room.
When a sensor is triggered, the program records a timestamp in milliseconds since the code started running. Once both sensors have triggered, the program compares the timestamps for the two sensors to determine the order they triggered and output the direction of movement.
What you need
The list of components for a basic direction detector is fairly short:
- Arduino Uno microcontroller, or equivalent (I used an ELEGOO board)
- Two HC-SR04 ultrasonic distance sensors
- Eight female-to-male Dupont wires
- Two male-to-male jumper wires
- Breadboard
- Power connection (I used a USB cable connected to my laptop)
For a more permanent installation you’d probably want something more robust, but this worked well as a proof of concept.
A single HC-SR04 sensor can be connected directly to an Arduino Uno board with four female-to-male Dupont wires, with no other components required. With two sensors, I used a breadboard to allow both sensors to share 5V power and ground connections, as you’ll see in the schematic below.
Wiring schematic
The schematic shows how I wired everything up. Here, it’s important to make sure each sensor’s trigger pin and echo pin connects to the Arduino pins designated as trigger and echo in the code: the two are not interchangeable, and if you get the wires switched around, the sensors will not work!
You’ll also want to make sure you have an ironclad sense of which of the two sensors is 1/left and which is 2/right, and wire them accordingly. I used different wire colors to keep track, but you could also label them.
Setup
The picture below shows the real-life version. When testing, I tried to lay the sensors as flat as possible and in as close to a straight line as possible. To detect walking movement past the sensors rather than the movement of my hand above them, I’d want to position them vertically instead of horizontally.
Code
Finally, here’s the code to make it all work. I wrote at least three different versions of this program: one meant to use an array to store the two sensors that triggered last, one meant to be able to detect more than one movement in a specified period of time, and finally this one, which was the only one I was able to get to work reliably in the time available.
Because this is the simple version, there are edge cases it doesn’t account for, like if two people were to pass the sensors going opposite directions at the exact same time. I’ll want to keep experimenting with the code to try to account for more complex scenarios, but for a basic 2D movement detector, this worked pretty well!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
/* CPLN 571 Tutorial Elisabeth Ericson 2022-03-29 This sketch borrows lightly from ELEGOO Lesson 10. It uses two HC-SR04 ultrasonic distance sensors to detect movement direction in two dimensions. */ // include library for sensor-specific functions #include "SR04.h" // ultrasonic sensor library // set pins for ultrasonic sensors #define trig_pin_1 12 // pin for sending sensor #1 trigger signal #define echo_pin_1 11 // pin for receiving sensor #1 echo signal #define trig_pin_2 9 // pin for sending sensor #2 trigger signal #define echo_pin_2 8 // pin for receiving sensor #2 echo signal // initialize two sensor objects SR04 sensor1 = SR04(echo_pin_1, trig_pin_1); // left sensor SR04 sensor2 = SR04(echo_pin_2, trig_pin_2); // right sensor // initialize variables long d1; // sensor 1 distance long d2; // sensor 2 distance long t1 = 0; // sensor 1 timestamp; initialize as 0 long t2 = 0; // sensor 2 timestamp; initialize as 0 unsigned long start_time; // time since program start float max_distance = 50; // movement sensing range (in cm) void setup() { Serial.begin(9600); // initialize serial monitor at 9,600 baud delay(1000); // pause start_time = millis(); // get program start time } void loop() { // get distance values from both sensors d1 = sensor1.Distance(); d2 = sensor2.Distance(); // if either sensor distance drops below limit, record timestamp if (d1 < max_distance) { t1 = millis(); } else if (d2 < max_distance) { t2 = millis(); } if (t1 > 0 && t2 > 0) { // if both sensors have nonzero timestamps if (t1 < t2) { // if left sensor triggered first Serial.println("Left to right"); // direction is left to right } else if (t2 < t1) { // if right sensor triggered first Serial.println("Right to left"); // direction is right to left } else { Serial.println(""); // else print nothing (shouldn't happen) } // after printing direction, reset both timestamps to 0 t1 = 0; t2 = 0; } } |
I could almost certainly take out the last “else” statement in the direction block, because the only way it could trigger is if both sensors recorded identical timestamps down to the millisecond, which I don’t think should happen given the way the rest of the code is set up. It got left in as a vestige of some earlier debugging, but I may go back and update this post once I’ve had a chance to confirm that nothing unexpected happens if I take it out.
Demonstration
I wish I could’ve increased the font size on the serial monitor to show the result more clearly, but the output does correctly print “Left to right” and “Right to left” as I move my hand back and forth over the sensors.
And there you have it! A minimalist movement direction detector using an Arduino and two ultrasonic distance sensors.
I’ll be using it as a building block for a motion-activated LED strip that displays different light patterns depending on the speed and direction of movement, but you might also use it for a light that turns on or off depending on whether you you enter or exit a room, and probably all sorts of other fun interactive projects I haven’t thought of.
Leave a comment if you found this tutorial useful, if you built anything based on it, or if you have ideas for how to improve it!
4 replies on “Detecting movement direction with two ultrasonic distance sensors”
Hi I have installed all the available library function in IDE but still there is no library function detected by my IDE
I mean the used function in this code. I have HC_SR04 not SR04
Hello,
I tested the code and this works fine.
Is there a way this also works with a TOF sensor like (VL53L1X)?
I am not so good in programming.
Geert
Hello, c
Can you tell me which library you used for the HC-RS04?
Greetings Henk