Moving Car Sensor using Arduino and ESP8266

Hi everyone. I am working on a project where I have to develop a sensor that detects if a car enters or could potentially enter a restricted area. The sensor will be stationary and will communicate via WiFi using an ESP8266. I have researched quite a few sensors and the one that seems to be best is either a radar sensor or magnetometer.

Does anyone have any other suggestions on any reliable sensors that work with the Arduino, can detect cars moving at speeds of 20+ mph, and have quick response times?

Can we have a diagram of this?

I don't think you could use a magnetometer to detect cars.....

Like is it a road, parking lot or something?

Hi. It's on a road. I want it to detect if a car enters into the red area and send an alert if the car is too close or already in the area. The sensor will be located along the edge of the red zone.

You will need two sensors of any type to determine if a car is entering. The time difference between to signals from each sensor will determine if the car is entering or leaving. With only one sensor you need ensure a car cannot leave through the entrance. How much power do you have available and how long will your system need to run?

1 Like

We are looking into using a rechargeable battery seeing as they system will need to run for hours during the day for extended periods of time.

Inductive loop.
They're used everywhere everyday......traffic light control......kentucky fried chicken drivethrough...etc...etc...

2 Likes

Magnetometers work quite well to detect vehicles, moving or not. They do need to be within 2-3 meters of the vehicle for reliable detection, though, and you will probably need to average a few readings. You will detect a distortion in the Earth's magnetic field, so use vector calculations to measure both a change in direction as well as magnitude.

I've been using an LSM303 at the gate to my property for years. Detection time is about 0.1 second using an LSM303.

Here is the code, written for AVRStudio

/*

Gate Alarm. LSM303DLH magnetometer vehicle detector
version 3.3 03/04/2017

eBay Pro Mini board.
this version runs on 4.5 V battery, 8 MHz internal RC

reads LSM303DLH magnetometer module
Transmit data via VirtualWire
uses I2C hardware interface on the atmega328.

RF module connections:

TX on PC3 (A3) blue
RX on PC2 (A2)
GND brown
Vdd red

MCU 		Mag
------		-----
Gnd (Vss)	Pin 1 blue
+5  (Vdd)	Pin 2 red
PC4 (SDA)	Pin 3 yellow Don't forget pullup resistors on SDA and SCL!
PC5 (SCL)	Pin 4 orange


CPU Clock speed is 8 MHz, I2C clock=100 kHz.

*/

// debug print on uart if DEBUG defined
//#define DEBUG

#define F_CPU 8000000UL

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <avr/sleep.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/wdt.h>

#include "I2C.c"
#include "vector.c"

#ifdef DEBUG
// debug printing
#include "uart.c"
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
#endif

#include "VirtualWireC3.c"

// long delay

void delay_ms(int ms) { 
	while (ms--) _delay_ms(1);	
}

// prototypes and globals

void read_mag_raw(int *m);

int readVcc(void);

float R2D = 180.0/3.14159265;

// watchdog timer interrupt, wake from sleep each 1/4 second (approx)

ISR (WDT_vect) {} //nothing to do

//
// MAIN
//

int main(void)
{
	int m[3],i=0;

	// read the magnetometer 16 times each sample (at 220 Hz, about 75 ms)
	unsigned int nreadings=16,test=0,max_test=0;

	vector fm, fm_avg, diff;

    float d2;
	float n_avg = 1.0/nreadings;

	unsigned int bmsg[3]; //binary value message buffer

	char passcounter = 128; //keep alive watchdog timeout of ~60 seconds

	DDRB = 1<<PB5; //LED output (D13)
	for (i=0; i<2; i++) {
		PORTB |= (1<<PB5); //on
 		delay_ms(1000);
		PORTB &= ~(1<<PB5); //off
		delay_ms(500);
		}

	DDRC = 0;                              // all inputs
	PORTC = (1 << PORTC4) | (1 << PORTC5); // enable pull-ups on SDA and SCL, respectively

#ifdef DEBUG
	uart_init(9600);
	stdout = &mystdout; //Required for printf init
	delay_ms(10); //let TX stabilize in idle
	printf("I,Gate V3.3\r\n");
#endif

	I2C_Init();  // initialize I2C interface (check F_CPU and TWI register settings)

	//check for LSM303DLM presence
	//set up magnetometer

	char who_am_i_m=I2C_ReadRegister(0x3c,0x0F); //should be 0x3C

	if (who_am_i_m != 0x3C) { 
	while (1) {  //device not found. blink LED rapidly
		PORTB |= (1<<PB5); //on
 		delay_ms(300);
		PORTB &= ~(1<<PB5); //off
		delay_ms(300);
		}
	}  // and hang

//#ifdef DEBUG	
//	printf("I,%02X\r\n",who_am_i_m);
//#endif

	// disable accelerometer and set data rate & sleep mode for magnetometer

	I2C_WriteRegister(0x30,0x20,0x00); // accelerometer, CTRL_REG1_A = 0 power down
	I2C_WriteRegister(0x3C,0x00,0x1C); // magnetometer, MR_REG_A = 0x1C (220Hz data rate)
	I2C_WriteRegister(0x3C,0x02,0x03); // magnetometer, MR_REG_M = 3 (sleep)

	// set up VirtualWire transmit (A3 or PC3)
	
	vw_setup(1000);	 // Bits per sec

	// initialize low pass filter for average mag vector

	read_mag_raw(m);

	fm_avg.x = m[0];
	fm_avg.y = m[1];
	fm_avg.z = m[2];

#ifdef DEBUG	
	printf("M,%d,%d,%d\r\n",m[0],m[1],m[2]);
	delay_ms(10); //finish printing before sleep
#endif

	// power reduction
	// disable ADC

	ADCSRA = 0; 

// set PRR Power Reduction Register (set PRADC after ADCSRA=0)

//Bit 7 - PRTWI: Power Reduction TWI
//Bit 6 - PRTIM2: Power Reduction Timer/Counter2
//Bit 5 - PRTIM0: Power Reduction Timer/Counter0
//Bit 4 - Res: Reserved bit
//Bit 3 - PRTIM1: Power Reduction Timer/Counter1
//Bit 2 - PRSPI: Power Reduction Serial Peripheral Interface
//Bit 1 - PRUSART0: Power Reduction USART0
//Bit 0 - PRADC: Power Reduction ADC

	PRR |= (1<<PRTWI)|(1<<PRTIM0)|(1<<PRTIM2)|(1<<PRSPI)|(1<<PRADC)|(1<<PRUSART0);

/*  sleep modes on ATmega328p
 SLEEP_MODE_IDLE
 SLEEP_MODE_ADC 
 SLEEP_MODE_PWR_DOWN 
 SLEEP_MODE_PWR_SAVE
 SLEEP_MODE_STANDBY 
 SLEEP_MODE_EXT_STANDBY
*/	
	set_sleep_mode(SLEEP_MODE_PWR_SAVE);

	// clear various "reset" flags
	MCUSR = 0;
	// allow changes, disable reset
	WDTCSR = (1<<WDCE) | (1<<WDE);
	// set interrupt mode and an interval
	WDTCSR = (1<<WDIE) | (1<<WDP2) | (1<<WDP0); // set WDIE, and 1/2 second timeout
	wdt_reset(); // reset it


	// main loop. Sleep, wake up on watchdog, make measurements

	while(1) {  //loop to read and print battery voltage and compass bearings

		sleep_enable();
		cli(); //time critical steps follow
		MCUCR = (1<<BODS) | (1<<BODSE);	// turn on brown-out enable select
		MCUCR = (1<<BODS);        		//Brown out off. This must be done within 4 clock cycles of above
		sei();
		sleep_cpu();

		PRR &= ~((1<<PRTWI)|(1<<PRADC)); //turn ADC and I2C back on

#ifdef DEBUG
		PRR &= ~(1<<PRUSART0); //usart on
#endif

	// read magnetometer
	fm.x = 0.;
	fm.y = 0.;
	fm.z = 0.;

	for (i=1; i<nreadings; i++) {

	read_mag_raw(m);

	fm.x += m[0];
	fm.y += m[1];
	fm.z += m[2];
	}

	fm.x *= n_avg; //average the readings
	fm.y *= n_avg;
	fm.z *= n_avg;

	diff.x = fm.x - fm_avg.x; //difference to background
	diff.y = fm.y - fm_avg.y;
	diff.z = fm.z - fm_avg.z;

	//low pass filter, after differencing

	fm_avg.x += (fm.x - fm_avg.x)*0.02;  
	fm_avg.y += (fm.y - fm_avg.y)*0.02;
	fm_avg.z += (fm.z - fm_avg.z)*0.02;

	// distance^2 from this point to average

	d2 = diff.x*diff.x + diff.y*diff.y + diff.z*diff.z + 0.5;

	if (d2 < 999.0) test=d2;
	else test = 999; //big enough!


	if(test > max_test) max_test=test; 

#ifdef DEBUG
		{
		int mx=diff.x+0.5;
		int my=diff.y+0.5;
		int mz=diff.z+0.5;
		printf("O,%d,%d,%d,%d\r\n",mx,my,mz,test);
		delay_ms(2); //wait till printing done for sleep
		}
#endif

		passcounter++;

// the magic alarm value 14 (below) was determined by experiment

// send a message, either upon alarm or at regular intervals

		if( (test > 14) || passcounter == 0) {  //alarm or keepalive, every ~60 seconds           
			
			bmsg[0] = test;
			bmsg[1] = max_test;
			bmsg[2] = readVcc();
			
			vw_send((uint8_t *)&bmsg,sizeof(bmsg));
	    	vw_wait_tx(); // Wait until message is sent

			ADCSRA = 0; // disable ADC
			PRR |= (1<<PRTWI)|(1<<PRADC); //turn ADC and I2C off
#ifdef DEBUG
			PRR |= (1<<PRUSART0);  //usart off
#endif
			} // end if (value>alarm)

		if(passcounter == 0) {
			max_test = 0; //reset max for next interval
			passcounter = 128; //next timeout in ~60 seconds
			}
		}
}


// Returns a set of raw magnetic readings

void read_mag_raw(int *m)
{
	unsigned char sr=0;

	I2C_WriteRegister(0x3C,0x02,0x01); //make single measurement 0x02=MR_REG_M
	delay_ms(4);  //4 ms ~ 220 Hz
	sr=I2C_ReadRegister(0x3C,0x09); //check RDY bit of Status Reg
//	while ((PINC & 2) == 0) {  //DRDY input on A1 (PC1)
	while ((sr&1) == 0) {  //DRDY bit
		delay_ms(1);
		sr=I2C_ReadRegister(0x3C,0x09);
	}

	//  read 3 16 bit values, device automatically returns to SLEEP mode

	I2C_Start(0x3C);
	I2C_Write(0x03); 	// OUTXH_M
	I2C_Start(0x3D);	// repeated start as read
	unsigned char mxh = I2C_ReadACK();
	unsigned char mxl = I2C_ReadACK();
	unsigned char myh = I2C_ReadACK();
	unsigned char myl = I2C_ReadACK();
	unsigned char mzh = I2C_ReadACK();
	unsigned char mzl = I2C_ReadNACK();
	I2C_Stop();

	*m++ = (mxh << 8) | mxl;
	*m++ = (myh << 8) | myl;
	*m   = (mzh << 8) | mzl;
}

// function to read 1.1V reference against AVcc
// return battery voltage in millivolts
// must be individually calibrated for each CPU

int readVcc(void) {

  int result;

   ADCSRA = (1<<ADEN);  //enable and
   ADCSRA |= (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2);  // set prescaler to 128

  // set the reference to Vcc and the measurement to the internal 1.1V reference

   ADMUX = (1<<REFS0) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1);
   delay_ms(1); // Wait for ADC and Vref to settle

   ADCSRA |= (1<<ADSC); // Start conversion
   while (bit_is_set(ADCSRA,ADSC)); // wait until done
   result = ADC;
  
   // second time is a charm

   ADCSRA |= (1<<ADSC); // Start conversion
   while (bit_is_set(ADCSRA,ADSC)); // wait until done
   result = ADC;
  
   // must be individually calibrated for EACH BOARD

  result = 1148566UL / (unsigned long)result; //1126400 = 1.1*1024*1000
  return result; // Vcc in millivolts
}

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.