I’m currently working on a school project involving a servo motor and an ultrasonic sensor. The goal of the project is to have the sensor track an object as it moves around. However, I'm facing an issue where the sensor isn't following the object correctly in all directions.
I've written some code, but it seems that the servo motor doesn't track the object as intended, especially when the object changes direction. I'm not sure what the problem is, and I would greatly appreciate it if someone could take a look at the code and suggest improvements or identify where the error might be.
If anyone has experience with object tracking using ultrasonic sensors and servo motors, your help would be invaluable!
Here’s the code I’ve been working on:
#include <Servo.h>
// Defines Trig and Echo pins of the Ultrasonic Sensor
const int trigPin = 10;
const int echoPin = 11;
long duration;
int distance;
int lastDistance = -1; // Variable to store the last measured distance
Servo myServo;
void setup() {
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
Serial.begin(9600);
myServo.attach(12); // Defines the pin to which the servo motor is attached
myServo.write(90); // Start position at 90 degrees (middle)
}
void loop() {
int maxDetectionRange = 50; // Maximum range to detect objects (50 cm)
int currentAngle = 90; // Start at the center
int stepFast = 5; // Fast step size for initial movement
int stepSlow = 1; // Slow step size when object is stationary
while (true) {
distance = calculateDistance();
if (distance > 0 && distance <= maxDetectionRange) {
// Check if the object has moved
if (distance != lastDistance) {
// Object is moving, track it with faster speed
currentAngle = trackObject(currentAngle, stepFast);
lastDistance = distance; // Update the last known distance
} else {
// Object is stationary, reduce speed
currentAngle = trackObject(currentAngle, stepSlow);
}
} else {
// Object lost, scan in both directions to find it again
currentAngle = scanForObject(currentAngle, stepFast);
lastDistance = -1; // Reset the last known distance
}
myServo.write(currentAngle);
delay(20); // Small delay for smooth movement
}
}
// Function to track and follow the object
int trackObject(int currentAngle, int step) {
int maxScanAngle = 180;
int minScanAngle = 0;
distance = calculateDistance();
if (distance > 0 && distance <= 50) {
if (distance < lastDistance && currentAngle > minScanAngle) {
// Object is getting closer, move to the left
currentAngle -= step;
} else if (distance > lastDistance && currentAngle < maxScanAngle) {
// Object is getting farther, move to the right
currentAngle += step;
}
}
// Ensure the angle stays within bounds
currentAngle = constrain(currentAngle, minScanAngle, maxScanAngle);
return currentAngle;
}
// Function to scan for the object if it is lost
int scanForObject(int currentAngle, int step) {
int maxScanAngle = 180;
int minScanAngle = 0;
// Scan right
for (int i = currentAngle; i <= maxScanAngle; i += step) {
myServo.write(i);
delay(20); // Reduced delay for faster scanning
distance = calculateDistance();
if (distance > 0 && distance <= 50) {
return i; // Return the angle where the object is detected
}
}
// Scan left
for (int i = currentAngle; i >= minScanAngle; i -= step) {
myServo.write(i);
delay(20); // Reduced delay for faster scanning
distance = calculateDistance();
if (distance > 0 && distance <= 50) {
return i; // Return the angle where the object is detected
}
}
return currentAngle; // Return the current angle if the object is not found
}
// Function for calculating the distance measured by the Ultrasonic sensor
int calculateDistance() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration * 0.034 / 2;
return distance;
}
Tell us in your own words how you are attempting to follow the object in all directions. You would need at least two and possibly three sensors to follow the object.
The goal of my project is to track an object using a single ultrasonic sensor mounted on a servo motor. The idea is that the sensor continuously rotates from 0 to 180 degrees, scanning for an object. Once the object is detected within a certain distance (in this case, 50 cm was not sufficiant), the servo motor should adjust its position to keep the object centered in its field of view. However, I'm finding that the sensor doesn't effectively follow the object when it changes direction, especially if the object moves from left to right. The tracking seems to only work in one direction, and when the object moves out of the initial direction, the sensor doesn't always adjust properly to follow it. I understand that using multiple sensors could provide more accurate tracking in multiple directions. Do you have an example how to set um the 2-3 Sensors on the servo motor?
Thank you for this information! It looks like my ultrasonic sensor's 15-degree cone and the associated coverage area might be contributing to the issues I'm seeing with tracking. Since the sensor has such a narrow detection cone, it seems like it might be missing the object when it moves outside of this area.
Would you recommend any specific adjustments to the servo movement or suggest adding additional sensors to cover a wider area? Any other tips to optimize the setup for better tracking would be greatly appreciated!
Obviously with three sensors it's easier because you can compare distance between them continuously, but 1 sensor approach is more interesting.
Maybe you should set some threshold to be considered different movements. You should have a logic to separate left/right movements from backward/forward movements.
case1 distance same, no movement
case2 distance changes slowly, bw/fw movement
case3 distance changes a lot suddenly (measuring backround, not object), L/R movement >> make fast scan
Can you post some images of your project?
So we can see your component layout.
Can you please post a copy of your circuit, a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, power supplies, component names and pin labels.
What was the logic behind moving the servo left or right depending on whether the object was moving away or towards you.
if (distance < lastDistance && currentAngle > minScanAngle) {
// Object is getting closer, move to the left
currentAngle -= step;
} else if (distance > lastDistance && currentAngle < maxScanAngle) {
// Object is getting farther, move to the right
currentAngle += step;
Doe that make sense to you?
I think it explains your left/right problem.
I did not look, but it seems you are only moving the sensor in one direction when it senses something. Also, are you stopping the movement while you are sensing and NOT moving again until either an echo is received or there is a time-out from the sensor code?
Your code is obscure, so try some different ideas.
One would be to scan and determine the range of angles over which you receive an echo. The center of that range is a good guess for the "best" angle to use. If that changes, maybe the object has moved.
It is a bad idea to power the servo from the Arduino 5V output, as you can damage the Arduino doing so. The servo can also cause other types of malfunctions. Use a separate power supply, like 4xAA:
When you receive the "shortest distance" echo, that will be the center of the object... store the angle... steer toward that angle. The more scans across the object, the more precise the "object center" is known... but that takes time away from pinging and steering... you would need to find the best balance of scan, ping, steer.
Here are the results of an experiment I did a while back, to see how ultrasonic ranging actually "views" the world. The experiment was instructive and suggests caution in interpreting the ranging results.
I used a much higher quality ranger (one capable of recording multiple echos), than the HC-SR04, scanning the room in ~2 degree steps.