Measuring speed using Ultrasonic sensor

Hi everybody,

I'm using HC-SR04 ultrasonic sensor to measure speed of a vehicle . The code is simple and reasonable but i don't know why the measured speed value is zero! Here is the code :

#define trigPin1 4
#define echoPin1 2

void setup() {
  Serial.begin(9600);
  pinMode(trigPin1, OUTPUT);
  pinMode(echoPin1, INPUT);
  pinMode(13,OUTPUT);
    pinMode(7,OUTPUT);

}
  void loop() {
  
  long duration, distance,x,passtime,carspeed;
  
  digitalWrite(trigPin1, HIGH);
  delayMicroseconds(2);
  digitalWrite(trigPin1, LOW);
  duration = pulseIn(echoPin1, HIGH);
  distance = (duration/2) / 29.1; 
  
if (distance == 20)  {
  x = millis();
      digitalWrite(7,HIGH);
         Serial.print(distance);

}
  
  if (distance == 10){
    digitalWrite(13,HIGH);
      passtime = (millis() - x)/1000;
   carspeed = 0.1/passtime;
   Serial.println(carspeed);
}}

You should rethink how the program is supposed to work.

What happens if the measured distance is never exactly equal to 20?

Even if a distance reading does happen to be exactly 20, there is no reason that a reading of exactly 10 will follow shortly.

Why should carspeed = 0.1/passtime?

Note: ALL variables associated with millis() should be [u]unsigned long[/u].

An object is moving towards the sensor so definitely there will be a reading when distance = 20 and another when distance = 10, calculating the pass time between these distances and taking 20-10= 10 cm (in meters it's 0.1). so we have distance and time taken by the object so 0.1/passtime is actually its speed !

Seif: An object is moving towards the sensor so definitely there will be a reading when distance = 20 and another when distance = 10, calculating the pass time between these distances and taking 20-10= 10 cm (in meters it's 0.1). so we have distance and time taken by the object so 0.1/passtime is actually its speed !

you cannot guarantee there is a READING when the distance is 20, you can only guarantee that there is a MOMENT when the distance is 20.

Readings take time too and it might happen that first reading says 21 and the second 19 and you miss 20.

speed = delta distance / delta time.

so in code you should try

distance1 = sonicRead();
t1 = micros();
distance2 = sonicRead();
t2 = micros();

speed = (distance2 - distance1) * 1.0 / ( t2 - t1);  // force float division

s = d/t

You can then either set t and measure d or set d and measure t.

Why not get a reading for distance after say 2 seconds.

Measure distance 1-------> Wait 2 Seconds --------->Measure Distance 2.

speed (m/s) = (d1 (m) -d2 (m))/(2 seconds)

I generally avoid using floating point numbers with microcontrollers but I think this is one of those times floating point math has an advantage over integer math.

Even though I think floats are helpful in this project, integers are generally more precise. I'd avoid converting the pulse durations to distances until the last moment.

Instead of calculating two distances, subtract the two pulse durations and then calculate the distance based on this difference. This should reduce the rounding errors associated with converting back and forth between integers and floats.

Here's my speed calculation.

float objectSpeed = deltaPulseDuration * DELTA_T_TO_SPEED / measurementInterval;

Here's what I used for "DELTA_T_TO_SPEED".

const float IMPERICAL_CONVERSION = 56.0;
const float MICROSECONDS_PER_SECOND = 1000000.0; 
const float DELTA_T_TO_SPEED = MICROSECONDS_PER_SECOND / IMPERICAL_CONVERSION;

"IMPERICAL_CONVERSION" is based on measurements made using my ultrasound. This value doesn't seem like it agrees with theory but it agrees with my 30cm, 40cm and 60cm observations. It sure bugs me that this value isn't what I get when I use the speed of sound in the calculation.

I'm still unsure when I should use a floating point number and when I should use integers but I decided to use a float for "measurementInterval" but "timeMark" and "previousTimeMark" are integers.

  float measurementInterval = timeMark - previousTimeMark;

This is the sort of output I'm getting while the sensor is moving toward the computer monitor. I think the speed values seem reasonable.

duration = 3354 us, dist = 59.89 cm, deltaPDur = 168 us, deltaDist = 3.00 cm, interval = 108872.00 us, speed = 27.56 cm/s
duration = 2976 us, dist = 53.14 cm, deltaPDur = 378 us, deltaDist = 6.75 cm, interval = 108496.00 us, speed = 62.21 cm/s
duration = 2667 us, dist = 47.63 cm, deltaPDur = 309 us, deltaDist = 5.52 cm, interval = 108196.00 us, speed = 51.00 cm/s
duration = 2286 us, dist = 40.82 cm, deltaPDur = 381 us, deltaDist = 6.80 cm, interval = 107804.00 us, speed = 63.11 cm/s
duration = 2016 us, dist = 36.00 cm, deltaPDur = 270 us, deltaDist = 4.82 cm, interval = 107532.00 us, speed = 44.84 cm/s
duration = 1545 us, dist = 27.59 cm, deltaPDur = 471 us, deltaDist = 8.41 cm, interval = 107064.00 us, speed = 78.56 cm/s
duration = 1284 us, dist = 22.93 cm, deltaPDur = 261 us, deltaDist = 4.66 cm, interval = 106792.00 us, speed = 43.64 cm/s

"deltaPDur" is the change in the duration between the new and the previous pulse.

I'm certainly willing to post my full code, but I don't want to spoil the fun for anyone else who may be playing along.

Hi everyone!

I nedd your help.

i want arduino code for measuring the speed of moving object using ultrasonic sensor....??? Here i'm using a above logic....see below

distance1 = sonicRead(); t1 = micros(); distance2 = sonicRead(); t2 = micros(); speed = (distance2 - distance1) * 1.0 / ( t2 - t1);

But in this case.....IDE shows error that 'sonicRead' was not declared in this scope . p

Akky_Navghane: Hi everyone!

I nedd your help.

i want arduino code for measuring the speed of moving object using ultrasonic sensor....??? Here i'm using a above logic....see below

distance1 = sonicRead(); t1 = micros(); distance2 = sonicRead(); t2 = micros(); speed = (distance2 - distance1) * 1.0 / ( t2 - t1);

But in this case.....IDE shows error that 'sonicRead' was not declared in this scope . p

You need to post your code and the exact error message you see.

error is 'sonicRead' was not declared in this scope.

code is: int trigPin = 2; int echoPin = 3; float duration; double distance1=0; double distance2=0; double t1=0; double t2=0; double speed=0; double distanceCm = 0;

void setup() { pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); }

void loop() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW);

duration = pulseIn(echoPin, HIGH); distanceCm = duration * 0.034 / 2; Serial.print(distanceCm); Serial.print("cm"); Serial.println(); delay(100);

distance1 = sonicRead(); t1 = micros(); distance2 = sonicRead(); t2 = micros(); speed = (distance2 - distance1) * 1.0 / ( t2 - t1);

Serial.print(speed); Serial.println(); delay(100); }

That's right. You keep calling some function called sonicRead but you haven't written any function by that name. You can't call functions that don't exist in your code.

It also appears that you have got some odd mash-up of code - you only need the code that relies on sonicRead (when you write it), and not the preceding range stuff.

 digitalWrite(trigPin, LOW);
   delayMicroseconds(2);
   digitalWrite(trigPin, HIGH);
   delayMicroseconds(10);
   digitalWrite(trigPin, LOW);

   duration = pulseIn(echoPin, HIGH);
   distanceCm = duration * 0.034 / 2;
   Serial.print(distanceCm);
   Serial.print("cm");
   Serial.println();
   delay(100);

Get rid of that (or turn it into sonicRead)

Thanks but i also want to calculate the speed of that moving object... Can you give me a exact code?

You've already got the code to calculate the speed, you just need to write the code to get the two range readings.

plzzz can u help me to sort out these??

I haven't compiled this, so obviously I haven't tested it - I don't have the hardware

const byte trigPin = 2;
const byte echoPin = 3;

void setup()
{
 pinMode(trigPin, OUTPUT);
 digitalWrite(trigPin, LOW);
 pinMode(echoPin, INPUT);
}

void loop()
{
   float distance1 = sonicRead();
   unsigned long t1 = micros();
   float distance2 = sonicRead();
   unsigned long t2 = micros();
   float speed = (distance2 - distance1) * 1.0 / ( t2 - t1);

   Serial.println(speed);
   delay(100);
}

float sonicRead ()
{
   digitalWrite(trigPin, HIGH);
   delayMicroseconds(10);
   digitalWrite(trigPin, LOW);

   unsigned long duration = pulseIn(echoPin, HIGH);
   return duration * 0.034 / 2;
}

Thanks a lot :kissing: :kissing: :kissing: #Yo

plzzz can u help me. send the full code.

The code is tested and working fine. It also includes LED blinking code.
Do make sure to insert it in the correct pin.

// defines pins numbers
const int trigPin = 9;
const int echoPin = 10;

// defines variables
long duration;
int distance1=0;
int distance2=0;
double speed=0;
int distance=0;

void setup() 
{
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
pinMode( 7 , OUTPUT);
Serial.begin(9600); // Starts the serial communication
}


void loop() 
{

//calculating speed
   distance1 = ultrasonicRead(); //calls ultrasoninicRead() function below
   
   delay(1000);//giving a time gap of 1 sec
   
   distance2 = ultrasonicRead(); //calls ultrasoninicRead() function below
   
   //formula change in distance divided by change in time
   speed = (distance2 - distance1)/1.0; //as the time gap is 1 sec we divide it by 1.
   
//Displaying speed
  Serial.print("Speed in cm/s  :  "); 
  Serial.println(speed);

   
// LED indicator
if (distance >0 && distance <5) 
{
    digitalWrite( 7 , HIGH);
    delay(50);                  // waits for a second
}

if (distance > 5 && distance <10 ) 
{
    digitalWrite( 7 , HIGH);
    delay(50);                  // waits for a second
    digitalWrite( 7 , LOW);    // sets the LED off
    delay(50);                  // waits for a second
}

if (distance >10  && distance < 20) 
{
    digitalWrite( 7 , HIGH);
    delay(210);                  // waits for a second
    digitalWrite( 7 , LOW);    // sets the LED off
    delay(210);                  // waits for a second
}

if (distance >20  && distance < 35) 
{
    digitalWrite( 7 , HIGH);
    delay(610);                  // waits for a second
    digitalWrite( 7 , LOW);    // sets the LED off
    delay(610);                  // waits for a second
}


}

float ultrasonicRead ()
{
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);

// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);

//calculating distance
distance= duration*0.034/2;

// Prints the distance on the Serial Monitor
Serial.print("Distance in cm : ");
Serial.println(distance);

return distance;

}

speedF.ino (2.27 KB)