Vehicle detection

[/

I have four HC-SR501 Passive Infrared sensors located at our camp along a small dirt country road connected to a microcontroller to detect how many and in what direction vehicles have been traveling North and South. Microcontroller used is an Arduino R3 with a data logging shield and will write time, date, and which sensor is activated at that particular time to the second to a SD card. Trouble is that the sensors random false trigger lots of times due to light, heat, or whatever? I want to set the system up and let it run for a month or two and then analyze the data using excel spread sheet. The four sensors are labeled N,N2,S2,S in that order from North to South and spaced about 18 feet apart. My code will allow a signal from all pir sensors then not allow any additional signals for the time variable (now set to 5 seconds) using the millis function.
If N,N2,S2,andS come in within a time variable, say 5 seconds, I can be sure it was one vehicle traveling South. Even if three or two sensors come in within the short time variable odds are that it would be viable. But if only one sensor comes in and the time variable expires it would be considered a false trigger and the program should ignore all those. Even if one particular sensor fires multiple times within the time variable it should not be taken as a good signal.
I would prefer to have the Arduino code determine the direction of travel rather than putting the data from the sd card into a excel file if possible.
I can get the data from the sd card, put it into an excel file, print to paper and with pencil in hand scan down looking at the seconds “column C” and the direction abbreviation “column D” and easily pick out the good data and direction of travel from the false hits.

The country road is one lane and probably does not have more than two dozen vehicles pass by in a 24-hour period.
Thanks, Terry
Here is my code so far:
code]

Alarm_To_SD_Card_12_30_17_lockLow_Terry.ino (11.8 KB)

Magnetometers like the HMC5883 work very well to detect vehicles, as vehicles distort the Earth's magnetic field.
Detection distance is a couple of meters, so you might mount one on a post close to the road.

I use one as a gate sensor, to signal that cars are entering or leaving our long driveway. With proper thresholding, there has not been one false alarm in two years, but a few times small vehicles have been missed.

You would need two to determine direction of travel, in which case false alarms could be reduced by requiring both sensors to fire in order, within a certain time.

1 Like

Hi,
It sounds like you have very long wires between the UNO and the sensors.

Are the power supply wires bypassed and are the signal wires bypassed, to stop any EM interference?

Tom.... :slight_smile:

You could try something like this: https://core-electronics.com.au/force-sensitive-resistor-square.html?utm_source=google_shopping&gclid=CjwKCAiA1uHSBRBUEiwAkBCtzR7z37l33SJoCkpUkwGtM2jwkFfrQ3n62LOgP3XQrYyxkeL0gRdCwhoCOgQQAvD_BwE

Assuming you can find something robust enough to seal it to protect against moisture - rubber pond liner for example.

If you had two of them you could also determine vehicle direction.

Or alternatively these: https://hobbyking.com/en_us/ultrasonic-distance-sensor-module-hc-sr04-for-kingduino-1.html?countrycode=AU&___store=en_us

In an outdoor environment I doubt that there would be much that is more efficient at reflecting ultrasonic that a vehicle.

Not sure how they work exactly but you may be able to determine direction based on whether the signal is receding or approaching.

Some sort of sonar setup could perhaps detect the vehicle direction, using the doppler shift of the return ping.

I've suggested a buried vibration sensor in previous threads.

@Jremington
“vehicles distort the Earth's magnetic field.”

How this is explained?

How this is explained?

Basic physics. Magnetic or magnetizable materials, and current carrying wires distort any independent magnetic field in their immediate vicinity.

If you experiment with a magnetometer or electronic compass, or even a regular needle-type compass, you will soon discover that in many environments (such as inside a vehicle) the readout is completely unreliable.

surepic:
@Jremington
“vehicles distort the Earth's magnetic field.”

How this is explained?

Magnetic Permeability

Thanks guys didnt heard of that before.

Hi,
If you look a these two diagrams.
This is with the magnetometer, that measures magnetic flux, or density of the magnetic field lines.
In its sensing state below, it is measuring 3 lines(Simplified for this example),caused by the earths mag field.


When a metal object, in this case metal vehicle, passes close the field lines distort through the truck, because it is metal.

The number of lines now being measured is 5. So the truck can be detected by looking for quick level changes in the background earths mag field

Hope it helps..

Tom.. :slight_smile:

TomGeorge:
Hi,
If you look a these two diagrams.
This is with the magnetometer, that measures magnetic flux, or density of the magnetic field lines.
In its sensing state below, it is measuring 3 lines(Simplified for this example),caused by the earths mag field.


When a metal object, in this case metal vehicle, passes close the field lines distort through the truck, because it is metal.

The number of lines now being measured is 5. So the truck can be detected by looking for quick level changes in the background earths mag field

Hope it helps..

Tom.. :slight_smile:

The science is well established. Just Google or search on eBay “loop detector”. Many many options which are very cheap.

BulldogLowell:
The science is well established. Just Google or search on eBay “loop detector”. Many many options which are very cheap.

Yes, but they use a loop of wire, the magnetometer is an IC it doesn't need a loop to work.

If you have, however, already decided on the sensors to use, maybe you should then look again at
reorganising your code and then add the part to determine the vehicle direction. Which ever sensor you use,
you'll probably still have to handle spurious results although some choices are better than others.
I'd progress like this:

  1. Get your data structure right to represent the relevant data from a sensor. Maybe something like:
   struct sensorData_t {
      uint32_t startMs;      // millisecond count at detection on sensor
      uint16_t count;        // number of hits on the sensor during detection window
  };
  1. Now create an array of the above structure for the four sensors
  struct sensorData_t sensorData[4] ;  // sensor 0 is your sensor N, sensor 2 is your N2 etc.
  1. Now you can represent the passage of a vehicle, also with sample data:
                  N                                                      N2                                               S2                                                S
   ------------------------------------------       .------------------------------------------       .------------------------------------------       .------------------------------------------
   sensorData[0].startMs  sensorData[0].count        sensorData[1].startMs  sensorData[1].count        sensorData[2].startMs  sensorData[2].count        sensorData[3].startMs  sensorData[3].count     
            107                1                             0                  0                                 1182               1                             2765                1

The example shows sensor 0 (your sensor N ) has had one hit during the detection window at ms = 107.
Sensor 1 (your NS failed to detect anything) and sensor 2 had one hit at ms = 1182.
So it is clear the vehicle is travelling North to South.
Also, it is clear that the data is valid for this detection example because (a) two or more sensors had
a hit during the detection window and (b) no individual sensor had multiple hits.

  1. To collect the data, you have to do something like this (pseudo code) in a loop
   if ( vehicle detected ) {
      if ( status ==  notInDetectionWindow ) { 
          // we're not already in a detection window
          set timer to millis()  // this starts our 5 second detection window
          set status = inDetectionWindow
      }
      // load data for the current sensor which detected the vehicle into data structure
      sensorData[ sensorNumber ].startMs = millis() ;  //overwritten in the case of multiple hits.
      sensorData[ sensorNumber ].count++  ;
   }

   if ( status == inDetectionWindow && timer expired ) {
      analyseResults() ;
      dumpResults_to_SD_card() ;
      clear_SensorData_Array();   // reset all values to zero
      status = notInDetectionWindow ;
   }
  1. To analyse the results, do something like this:

  2. Step through the data structure, to check that there are no cases of a single sensor
    getting more than one hit. If not reject entire detection.

  3. Step through the data structure, to check that at least 2 sensors had a single
    hit. If not reject entire detection.
    If we've got this far we can use the result.

  4. Step forwards through the structure to get the startMs value of its first valid
    detection.

  5. Step backwards through the structure to get the startMs value of its last valid
    detection.
    Use the results of 3 and 4 to determine the vehicle direction.

Thanks 6v6gt,
Great, I think that is what I am looking for. I will try to find a way to include your idea into my existing code. You are right, what ever kind of sensors used still would need the exclusion process and that's where the real work is. I like your thought process, I just could not visualize how to incorporate arrays into the code being used. The code used will accept one input from a sensor then ignor any additional inpute from that particular sensor for a time variable <now set to 5000> while still listening for any of the other three sensors.
Cheers,Terry

For those looking for a solution, I've written some code for an 328P (barebone) to take a measurement every second and sleep in between the measurements. If the measured value exceeds a threshold, it sends out a signal and goes back to sleep to re-measure.
Sending is done with a HC-12 module (too easy!) which is first powered up with a mosfet as a high-side switch.

#include <Arduino.h>
#include <Wire.h>
#include <HMC5883L.h>
#include <avr/sleep.h>
#include <avr/wdt.h>

#define hc12 Serial
#define green 2  // HW32
#define mosfet 4 // activated before sending with the HC-12

HMC5883L compass;

uint32_t cmdMillis = 0; // holds the time since last command mode. Needs a minimum of 200ms
#define cmdWaitMillis 200

// watchdog interrupt
ISR(WDT_vect)
{
   wdt_disable(); // disable watchdog
}

void hc12_wake()
{
   digitalWrite(mosfet, LOW);
   delay(20); // hc12 only seems to need a few ms of startup time. 20ms is for safety
}

void hc12_sleep()
{
   digitalWrite(mosfet, HIGH);
}

int32_t readout;     // stores the new readout. This value is compared to the lastReadout.
int32_t lastReadout; // stores the previous readout.
#define threshold 35 // if this threshold is exceeded, some value is sent using the HC12
void intervalAction()
{
   Vector raw = compass.readRaw();
   // and store them as signed integers:
   readout = int32_t(raw.XAxis);

   if ((readout - lastReadout > threshold) || (lastReadout - readout > threshold))
   {
      hc12_wake(); // do this asap
      // send two times to make sure it is received
      hc12.write('c');
      delay(100);
      hc12.write('c');
      delay(100);
      hc12_sleep();
   }
   lastReadout = readout;
}

void sleepAVR()
{
   // disable ADC
   ADCSRA = 0;

   // clear various "reset" flags
   MCUSR = 0;
   // allow changes, disable reset
   WDTCSR = bit(WDCE) | bit(WDE);
   // set interrupt mode and an interval
   WDTCSR = bit(WDIE) | bit(WDP2) | bit(WDP1); // set WDIE, and 1 second delay
   wdt_reset();                                // pat the dog

   set_sleep_mode(SLEEP_MODE_PWR_DOWN);
   noInterrupts(); // timed sequence follows
   sleep_enable();
   interrupts();
   sleep_cpu();
}

void setup()
{
   //  POWER SAVE
   if (1)
   {
      // write all outputs to LOW to save power
      pinMode(A6, OUTPUT);
      digitalWrite(A6, LOW);
      pinMode(A7, OUTPUT);
      digitalWrite(A7, LOW);

      for (uint8_t i = 0; i <= 22; i++)
      {
         if (i != 0 && i != 1 && i != 18 && i != 19 && i != 22) // leave RST SDA SCL Rx Tx
         {
            pinMode(i, OUTPUT);
            digitalWrite(i, LOW);
         }
      }
   }
   // blink on boot to show we're alive and to give the system time to power-up
   digitalWrite(green, HIGH);
   delay(500);
   digitalWrite(green, LOW);

   hc12.begin(9600);

   // Initialize HMC5883L
   while (!compass.begin())
   {
      digitalWrite(green, HIGH);
      delay(50);
      digitalWrite(green, LOW);
      delay(50);
      digitalWrite(green, HIGH);
      delay(100);
      digitalWrite(green, LOW);
   }
}

void loop()
{
   digitalWrite(green, HIGH);
   intervalAction();
   digitalWrite(green, LOW);

   sleepAVR();

   // cancel sleep as a precaution
   sleep_disable();
}

JorisKingma:
For those looking for a solution, I've written some code for an 328P (barebone) to take a measurement every second and sleep in between the measurements. If the measured value exceeds a threshold, it sends out a signal and goes back to sleep to re-measure.
Sending is done with a HC-12 module (too easy!) which is first powered up with a mosfet as a high-side switch.

#include <Arduino.h>

#include <Wire.h>
#include <HMC5883L.h>
#include <avr/sleep.h>
#include <avr/wdt.h>

#define hc12 Serial
#define green 2  // HW32
#define mosfet 4 // activated before sending with the HC-12

HMC5883L compass;

uint32_t cmdMillis = 0; // holds the time since last command mode. Needs a minimum of 200ms
#define cmdWaitMillis 200

// watchdog interrupt
ISR(WDT_vect)
{
  wdt_disable(); // disable watchdog
}

void hc12_wake()
{
  digitalWrite(mosfet, LOW);
  delay(20); // hc12 only seems to need a few ms of startup time. 20ms is for safety
}

void hc12_sleep()
{
  digitalWrite(mosfet, HIGH);
}

int32_t readout;     // stores the new readout. This value is compared to the lastReadout.
int32_t lastReadout; // stores the previous readout.
#define threshold 35 // if this threshold is exceeded, some value is sent using the HC12
void intervalAction()
{
  Vector raw = compass.readRaw();
  // and store them as signed integers:
  readout = int32_t(raw.XAxis);

if ((readout - lastReadout > threshold) || (lastReadout - readout > threshold))
  {
     hc12_wake(); // do this asap
     // send two times to make sure it is received
     hc12.write('c');
     delay(100);
     hc12.write('c');
     delay(100);
     hc12_sleep();
  }
  lastReadout = readout;
}

void sleepAVR()
{
  // disable ADC
  ADCSRA = 0;

// clear various "reset" flags
  MCUSR = 0;
  // allow changes, disable reset
  WDTCSR = bit(WDCE) | bit(WDE);
  // set interrupt mode and an interval
  WDTCSR = bit(WDIE) | bit(WDP2) | bit(WDP1); // set WDIE, and 1 second delay
  wdt_reset();                                // pat the dog

set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  noInterrupts(); // timed sequence follows
  sleep_enable();
  interrupts();
  sleep_cpu();
}

void setup()
{
  //  POWER SAVE
  if (1)
  {
     // write all outputs to LOW to save power
     pinMode(A6, OUTPUT);
     digitalWrite(A6, LOW);
     pinMode(A7, OUTPUT);
     digitalWrite(A7, LOW);

for (uint8_t i = 0; i <= 22; i++)
     {
        if (i != 0 && i != 1 && i != 18 && i != 19 && i != 22) // leave RST SDA SCL Rx Tx
        {
           pinMode(i, OUTPUT);
           digitalWrite(i, LOW);
        }
     }
  }
  // blink on boot to show we're alive and to give the system time to power-up
  digitalWrite(green, HIGH);
  delay(500);
  digitalWrite(green, LOW);

hc12.begin(9600);

// Initialize HMC5883L
  while (!compass.begin())
  {
     digitalWrite(green, HIGH);
     delay(50);
     digitalWrite(green, LOW);
     delay(50);
     digitalWrite(green, HIGH);
     delay(100);
     digitalWrite(green, LOW);
  }
}

void loop()
{
  digitalWrite(green, HIGH);
  intervalAction();
  digitalWrite(green, LOW);

sleepAVR();

// cancel sleep as a precaution
  sleep_disable();
}

It looks like a useful example.
Is the compass also powered via the mosfet or can its quiescent current consumption be ignored here ?

This, incidentally, will not do what you expect because A6 and A7 have no digital features.

     // write all outputs to LOW to save power
      pinMode(A6, OUTPUT);
      digitalWrite(A6, LOW);
      pinMode(A7, OUTPUT);
      digitalWrite(A7, LOW);