Reverse Direction Speed Measurement

Hi Guys,

I have created a programm using Interrupts to measure speed and direction of Train.

I have attached my logic below.

I am trying to get same result for opposite direction but can not get appropriate result.

There are 2 Inductive sensors A and B.

When first Sensor A goes HIGH and Then Sensor B goes HIGH programm will measure speed of train.

But It should work when first Sensor B goes HIGH and then Sensor A.

Please help me guys.

#define CMS_to_KMH 0.036// scale factor
#define DISTANCE 15.5 // distance between the two sensors   in centimeter.
#define LED1 4  //  constants LED Pin numbers
#define LED2 5
#define LED3 6
#define LED4 7
#define LED5 8


 int SensorOnePin = 2;
 int SensorTwoPin = 3;

byte SensorOneState;
byte SensorTwoState;
float Speed = 0, KMH = 0, tmp = 0;
boolean GotSecondSensor = false;
unsigned long SensorOne_timer = 0, SensorTwo_timer = 0;

void setup()
{
 Serial.begin(9600);
 pinMode(SensorOnePin, INPUT);
 pinMode(SensorTwoPin, INPUT);
 pinMode(LED1, OUTPUT);
 pinMode(LED2, OUTPUT);
 pinMode(LED3, OUTPUT);
 pinMode(LED4, OUTPUT);
 pinMode(LED5, OUTPUT);
 attachInterrupt(0, ISR0, CHANGE); 
 attachInterrupt(1, ISR1, CHANGE); 
}

void loop(){
  
  
  
 
 }

void ISR0()
{
 SensorOneState = digitalRead(SensorOnePin);
 if(SensorOneState && GotSecondSensor == false)  // Train drives through first "sensor"
 {
   SensorOne_timer = millis(); // record time
   GotSecondSensor = true; // lockout this IF statement and unlock the next IF statement
 }
}
 void ISR1()
 {
  SensorTwoState = digitalRead(SensorTwoPin);
 if(SensorTwoState && GotSecondSensor == true)
 {
   SensorTwo_timer = millis(); //record the time the train reaches the second gate
   Speed = GetSpeed(SensorOne_timer, SensorTwo_timer, DISTANCE); // send the times and the distance into the function.
   Serial.print("Geschwindigkeit im KM/H: ");
   Serial.println(Speed);
   GotSecondSensor = false; // unlock first IF statement and lockout this IF statement.
 }
 }
float GetSpeed(unsigned long T1, unsigned long T2, float distance)
{
 KMH = distance * (CMS_to_KMH); // "(CMS_to_MPH)" -> conversion factor, feet per second to miles per hour
 tmp = (T2 - T1)/1000.00; // since the time we are using is in milliseconds, we need to convert milliseconds to seconds
 Serial.print("Time (seconds): ");
 Serial.println(tmp);

  int myNum = KMH/tmp;
        
byte pins[5] = { LED1, LED2, LED3, LED4, LED5} ;
for (byte i = 0 ; i < sizeof(pins) ; i++)
    digitalWrite (pins[i], ( myNum & (1<<i)) != 0 ? HIGH : LOW) ;
 
 Serial.print("Binar Codiert :");
 Serial.println(myNum, BIN);

return (myNum);
}
unsigned long SensorOne_timer = 0, SensorTwo_timer = 0;

The values stored in these variables are NOT timers. The names should reflect what IS stored in the variables.

I don't see where you deal with the second sensor being triggered first. What I would do is have two booleans, one for each sensor being triggered. I would set them in the ISRs.

I would move all of the code for calculating direction and speed to loop(). I would only execute the code when both booleans were true, at which time I'd reset them to false.

Instead of saving "SensorOne" and "SensorTwo" you should store "FirstSensorTime". If either interrupt happens and FirstSensorTime is zero, just save millis() in FirstSensorTime and you are done. When EITHER interrupt occurs and FirstSensorTime is not zero, subtract FirstSensorTime from millis() to get transit time. Then set FirstSensorTime to zero to prepare for the next cycle.

Use the Rising edge for the interrupt. You don't need interrupts on both edges if you're only acting on the Rising edge.

Unless your switching is very clean you should add debounce timers to ignore interrupts less than a few milliseconds apart.

Thank you for the answer.

I am getting this error.
what could be the cause?

I have checked everything but cant get any idea.

C:\Users\Administrator\Documents\Arduino\sketch_aug30a\sketch_aug30a.ino: In function 'void loop()':

sketch_aug30a:53: error: return-statement with a value, in function returning 'void' [-fpermissive]

return (myNum);

^

exit status 1
return-statement with a value, in function returning 'void' [-fpermissive]

You have a "return value" statement in a function declared "void" (meaning that it does not return a value).

You should NEVER print inside an interrupt. Have the interrupt set a global flag (declared volatile) and print outside the interrupt.

Hi guys,

I have updated my programm on Rising edge and it works for one direction.

But still problem to detect opposite direction.

@johnwasser

Could you please explain me your logic in detail?

I tried to do so but cant getting required result.

#define CMS_to_KMH 0.036// scale factor
#define DISTANCE 15.5 // distance between the two sensors   in centimeter.
#define LED1 4  //  constants LED Pin numbers
#define LED2 5
#define LED3 6
#define LED4 7
#define LED5 8


 int SensorOnePin = 2;
 int SensorTwoPin = 3;

volatile byte SensorOneState;
volatile byte SensorTwoState;
float Speed = 0, KMH = 0, tmp = 0;
boolean GotSecondSensor = false;
volatile unsigned long SensorOne_timer = 0, SensorTwo_timer = 0;

void setup()
{
 Serial.begin(9600);
 pinMode(SensorOnePin, INPUT_PULLUP);
 pinMode(SensorTwoPin, INPUT_PULLUP);
 pinMode(LED1, OUTPUT);
 pinMode(LED2, OUTPUT);
 pinMode(LED3, OUTPUT);
 pinMode(LED4, OUTPUT);
 pinMode(LED5, OUTPUT);
 attachInterrupt(0, ISR1, RISING); 
 attachInterrupt(1, ISR2, RISING); 
 Serial.println("Start");
}
void loop(){
 
}


void ISR1()
{ 
 SensorOneState = digitalRead(SensorOnePin);
 SensorTwoState = digitalRead(SensorTwoPin);

  
 if(SensorOneState && GotSecondSensor == false)  // Train drives through first "sensor"
 {
   SensorOne_timer = millis(); // record time
   GotSecondSensor = true; // lockout this IF statement and unlock the next IF statement
 }
}
 
 void ISR2()
{
 SensorOneState = digitalRead(SensorOnePin);
 SensorTwoState = digitalRead(SensorTwoPin);
 
 if(SensorTwoState && GotSecondSensor == true)
 {
   SensorTwo_timer = millis(); //record the time the train reaches the second gate
   GotSecondSensor = false; // unlock first IF statement and lockout this IF statement.

   
 KMH = DISTANCE * (CMS_to_KMH); // "(FPS_to_MPH)" -> conversion factor, feet per second to miles per hour
 tmp = (SensorTwo_timer - SensorOne_timer)/1000.00; // since the time we are using is in milliseconds, we need to convert milliseconds to seconds
 Serial.print("Time (seconds): ");
 Serial.println(tmp);

  int myNum = KMH/tmp;
        
byte pins[5] = { LED1, LED2, LED3, LED4, LED5} ;
for (byte i = 0 ; i < sizeof(pins) ; i++)
    digitalWrite (pins[i], ( myNum & (1<<i)) != 0 ? HIGH : LOW) ;
 
 Serial.print("Binar Codiert :");
 Serial.println(myNum, BIN);
 Serial.print("Geschwindigkeit im KM/H: ");
   Serial.println(myNum);
   

 }
}

There are several problems with your current code. First, doing serial printing in an ISR is not a good idea.

Pretend that you are the train. You pass the first sensor. What happens? You pass the second sensor. What happens?

The way I see it, ISR1() gets called, and then ISR2() gets called, which causes the speed to be computed, because all the needed data is present.

Now, pretend that you go the other way. You pass the second sensor. ISR2() is called, but does less because not all the data is present. Then, you pass the first sensor, which notes your presence, and when you arrived.

Now, explain WHY ISR1() does NOT also calculate speed, based on the fact that sensor 2 was triggered first.

By the way, there is nothing magical about ISR in the name. Name the functions something meaningful.

I tried to put calculation part in loop(), but its not working.

Should I write calculation part in both ISR1 and ISR2?

I tried to put calculation part in loop(), but its not working.

We can't see THAT code, nor do we know what you mean by "it isn't working". Of course it works. That it does not do what you expect says more about your expectations than about what actually happens.

Should I write calculation part in both ISR1 and ISR2?

No. You should put the calculation part in a function, and call it from both ISRs. Or from loop().

I have attached my Code.

whenever I try to measure speed from sensor1 to sensor2 direction it works perfect.

But When I tried to compute from Sensor2 to Sensor1 I am getting false reading.
actually I tried different ways to calculate it but cant get correct one.
I just need a hint what shoul I need to do ?

Here is the code for 1 direction.

thank you

#define CMS_to_KMH 0.036// scale factor
#define DISTANCE 15.5 // distance between the two sensors   in centimeter.
#define LED1 4  //  constants LED Pin numbers
#define LED2 5
#define LED3 6
#define LED4 7
#define LED5 8


 int SensorOnePin = 2;
 int SensorTwoPin = 3;

volatile byte SensorOneState;
volatile byte SensorTwoState;
float Speed = 0, KMH = 0, tmp = 0;
boolean GotSecondSensor = false;
volatile unsigned long SensorOne_timer = 0, SensorTwo_timer = 0;

void setup()
{
 Serial.begin(9600);
 pinMode(SensorOnePin, INPUT_PULLUP);
 pinMode(SensorTwoPin, INPUT_PULLUP);
 pinMode(LED1, OUTPUT);
 pinMode(LED2, OUTPUT);
 pinMode(LED3, OUTPUT);
 pinMode(LED4, OUTPUT);
 pinMode(LED5, OUTPUT);
 attachInterrupt(0, Sensor1, RISING); 
 attachInterrupt(1, Sensor2, RISING); 
 Serial.println("Start");
}
void loop(){
 
}


void Sensor1()
{ 
 SensorOneState = digitalRead(SensorOnePin);
 SensorTwoState = digitalRead(SensorTwoPin);

  
 if(SensorOneState == true && GotSecondSensor == false)  // Train drives through first "sensor"
 {
   SensorOne_timer = millis(); // record time
   GotSecondSensor = true; // lockout this IF statement and unlock the next IF statement

 }
}
 
 void Sensor2()
{
 SensorOneState = digitalRead(SensorOnePin);
 SensorTwoState = digitalRead(SensorTwoPin);
 
 if(SensorTwoState == true && GotSecondSensor == true)
 {
   SensorTwo_timer = millis(); //record the time the train reaches the second gate
   GotSecondSensor = false; // unlock first IF statement and lockout this IF statement.

   
 KMH = DISTANCE * (CMS_to_KMH); // "(FPS_to_MPH)" -> conversion factor, feet per second to miles per hour
 tmp = (SensorTwo_timer - SensorOne_timer)/1000.00; // since the time we are using is in milliseconds, we need to convert milliseconds to seconds
 Serial.print("Time (seconds): ");
 Serial.println(tmp);

  int myNum = KMH/tmp;
        
byte pins[5] = { LED1, LED2, LED3, LED4, LED5} ;
for (byte i = 0 ; i < sizeof(pins) ; i++)
    digitalWrite (pins[i], ( myNum & (1<<i)) != 0 ? HIGH : LOW) ;
 
 Serial.print("Binar Codiert :");
 Serial.println(myNum, BIN);
 Serial.print("Geschwindigkeit im KM/H: ");
   Serial.println(myNum);
   

 }
}

I just need a hint what shoul I need to do ?

If you record the time that each sensor is triggered, and compute the speed and direction when both are non-zero and then set them back to 0, the order doesn't matter.

But When I tried to compute from Sensor2 to Sensor1 I am getting false reading.

Why didn't you show us that code?

Try this to see if it works:

const float CPS_to_KPH = 0.036; // scale factor
const float DISTANCE = 15.5; // cm between the two sensors
const float KPH = DISTANCE * (CPS_to_KPH);

const byte LEDPins[] = {4, 5, 6, 7, 8};

const int Sensor1Pin = 2;
const int Sensor2Pin = 3;

unsigned long Sensor1Time, Sensor2Time;
volatile unsigned long DeltaTime;

void setup() {
  Serial.begin(9600);
  pinMode(Sensor1Pin, INPUT_PULLUP);
  pinMode(Sensor2Pin, INPUT_PULLUP);
  for (byte i = 0; i < sizeof LEDPins; i++)
    pinMode(LEDPins[i], OUTPUT);
  attachInterrupt(0, Sensor1ISR, RISING);
  attachInterrupt(1, Sensor2ISR, RISING);
  Serial.println("Start");
}


void Sensor1ISR() {
  Sensor1Time = millis();
  // If this is the second sensor, calculate delta time.
  if (Sensor2Time != 0) {
    DeltaTime = Sensor2Time - Sensor1Time;
    Sensor1Time = 0;
    Sensor2Time = 0;
  }
}


void Sensor2ISR() {
  Sensor2Time = millis();
  // If this is the second sensor, calculate delta time.
  if (Sensor1Time != 0) {
    DeltaTime = Sensor1Time - Sensor2Time;
    Sensor1Time = 0;
    Sensor2Time = 0;
  }
}


void loop() {
  // Copy volatile variables while interrupts are disabled
  noInterrupts();
  // Store time between sensors in milliseconds
  unsigned long delta = DeltaTime;
  DeltaTime = 0;
  interrupts();

  if (delta != 0) {
    Serial.print("Time (seconds): ");
    Serial.println(delta / 1000.0, 3);

    // Calculate actual speed in cm per second.  Since 'delta'
    // is in milliseconds we multiply the distance by 1000.
    float speedCPS = DISTANCE * 1000.0 / delta;

    Serial.print("Geschwindigkeit im CM/S: ");
    Serial.println(speedCPS, 3);

    float speedKPH = speedCPS * CPS_to_KPH;

    Serial.print("Geschwindigkeit im KM/H: ");
    Serial.println(speedKPH, 3);

    int intSpeed = speedKPH;  // Truncate to integer
    for (byte i = 0 ; i < sizeof LEDPins ; i++)
      digitalWrite(LEDPins[i], intSpeed & (1 << i));
  }
}

@ Johnwasser

Thank you very much.

Code works for both the direction but getting wiered Result.

I have attached a snapshot of result.

I am trying to find the error. Let me know if you find something

Thanks again

Unbenannt.PNG

Oops! I got the subtractions reversed so the number was going negative. Here is the corrected version:

const float CPS_to_KPH = 0.036; // scale factor
const float DISTANCE = 15.5; // cm between the two sensors
const float KPH = DISTANCE * (CPS_to_KPH);

const byte LEDPins[] = {4, 5, 6, 7, 8};

const int Sensor1Pin = 2;
const int Sensor2Pin = 3;

unsigned long Sensor1Time, Sensor2Time;
volatile unsigned long DeltaTime;

void setup() {
  Serial.begin(9600);
  pinMode(Sensor1Pin, INPUT_PULLUP);
  pinMode(Sensor2Pin, INPUT_PULLUP);
  for (byte i = 0; i < sizeof LEDPins; i++)
    pinMode(LEDPins[i], OUTPUT);
  attachInterrupt(0, Sensor1ISR, RISING);
  attachInterrupt(1, Sensor2ISR, RISING);
  Serial.println("Start");
}


void Sensor1ISR() {
  Sensor1Time = millis();
  // If this is the second sensor, calculate delta time.
  if (Sensor2Time != 0) {
    DeltaTime = Sensor1Time - Sensor2Time;
    Sensor1Time = 0;
    Sensor2Time = 0;
  }
}


void Sensor2ISR() {
  Sensor2Time = millis();
  // If this is the second sensor, calculate delta time.
  if (Sensor1Time != 0) {
    DeltaTime = Sensor2Time - Sensor1Time;
    Sensor1Time = 0;
    Sensor2Time = 0;
  }
}


void loop() {
  // Copy volatile variables while interrupts are disabled
  noInterrupts();
  // Store time between sensors in milliseconds
  unsigned long delta = DeltaTime;
  DeltaTime = 0;
  interrupts();

  if (delta != 0) {
    Serial.print("Time (seconds): ");
    Serial.println(delta / 1000.0, 3);

    // Calculate actual speed in cm per second.  Since 'delta'
    // is in milliseconds we multiply the distance by 1000.
    float speedCPS = DISTANCE * 1000.0 / delta;

    Serial.print("Geschwindigkeit im CM/S: ");
    Serial.println(speedCPS, 3);

    float speedKPH = speedCPS * CPS_to_KPH;

    Serial.print("Geschwindigkeit im KM/H: ");
    Serial.println(speedKPH, 3);

    int intSpeed = speedKPH;  // Truncate to integer
    for (byte i = 0 ; i < sizeof LEDPins ; i++)
      digitalWrite(LEDPins[i], intSpeed & (1 << i));
  }
}

@johnwasser

Got it.

Code is working perfectly.

This would be a great help.
Thanks again.