Hi,
I want to build a project with Arduino to measure the speed of passing cars.
My idea is to use two sensors placed a fixed distance apart (for example 1 meter) and measure the time a car needs to pass between them. Then I want to calculate the speed.
I am not sure which sensors I should use. I was thinking about IR sensors, but I don’t know if they are fast and reliable enough for cars.
My questions:
Which sensors are best for detecting fast moving cars?
Are IR break beam sensors a good choice?
Is there a better method to measure speed with Arduino?
The Police would probably say handheld radar or fixed cameras, for civil authorities.
Cameras are used on gantries to calculate average speed, typically through roadworks.
The cameras can quickly record licence plates of many vehicles.
Hand held radar has the advantage of targeting specific vehicles.
A problem with roadside sensors is the possibility of picking up other vehicles in other directions.
IR is very fast. It could be used in break beam or reflective mode.
For temporary vehicle speed surveys, traditionally rubber tubes are laid across the road to activate pneumatic pressure switches.
Tell us a bit more about why you want to do it and things like is this on public roads, racetracks etc.
That will help with suggestions.
IR sensors can work, but standard reflective IR is often a poor choice for measuring car speed accurately. The main problem is that many IR sensors have a fairly wide detection cone rather than a precise line. That means a car passing close to the sensor may trigger sooner than one passing farther away, so your “start” and “stop” points can shift depending on lane position, vehicle size, angle, and reflectivity. Over just 1 meter, that can create significant error.
Range and environment matter too. Reflective IR sensors often have limited distance, and sunlight, rain, or dirt can reduce reliability outdoors.
A true break-beam setup (emitter on one side, receiver on the other) is much better than reflective IR because it creates a defined crossing point, but alignment and weather still matter. Better options are often narrow laser/photogates for precise timing, or radar, inductive, or magnetic sensors.
If using two sensors, increasing the spacing to several meters instead of 1 meter will also improve accuracy because small timing errors matter less.
a few information that would matter as well :
What speed range are you measuring?
Indoor or outdoor use?
Fixed lane position or variable distance from the sensor? Road width?
Required accuracy?
Can the cars only go one direction? Is it a two lane with cars going each direction? I could see a beam break situation not being accurate if the beam goes all the way across both lanes. It can't identify WHICH car is breaking which beam.
Not sure of your budget, but there are plenty of premade traffic sensors on the market. Magnetometers, inductance loops, doppler radar, microwave radar, beam breaks, etc...
I used a small doppler/microwave sensor on a jobsite to open a gate when a car drives by. The owner would not let me cut the driveway to install loops and due to other reasons, the magnetometers had to be installed to far away. The sensor I chose works great and the range is adjustable to only detect in the exit lane, not all the way across the driveway.
An idea might be to have a pressure sensor strip.
so you can detect the moment the tires go over the strip.
Use two strips e.g. 1 meter apart and then the math becomes.
E.g. when the time difference is e.g. 24 milliseconds
speed = distance / time => 1 m / 0.024 s = 41.7 m/s = 150 km/h
time = 23 millis
speed = distance / time => 1 m / 0.023 s = 43.5 m/s = 156.5 km/h
Measuring the time in micros() would improve accuracy with a factor 1000 in theory, but lets assume the smallest stepsize = 20 microseconds
speed = distance / time => 1 m / 0.024000 s = 41.67 m/s = 150.00 km/h
speed = distance / time => 1 m / 0.024020 s = 41.63 m/s = 149.88 km/h
One should use a sensor that gives an interrupt to get best timing accuracy.
/*
Measures time difference between two digital events on ATmega328P.
Wiring:
- Sensor A (start event) connected to D2 (INT0)
- Sensor B (end event) connected to D3 (INT1)
- Both sensors must output clean rising edges (0 → 1 transition)
Timer:
- Timer1 runs at 16 MHz with no prescaler (62.5 ns per tick)
- No overflow handling is implemented
Assumption:
- Time difference between A and B is < 4.096 ms
(otherwise Timer1 overflow will corrupt the measurement)
Method:
- INT0 captures start condition (A)
- INT1 captures end condition (B) only after A occurred
- Delta is computed using Timer1 ticks
Design intent:
- Both ISRs are intentionally kept extremely similar and minimal
- Same instruction pattern (read TCNT1, store, set state)
- This reduces asymmetry in interrupt handling latency
- The goal is that any fixed interrupt overhead is as comparable as possible
so it cancels out when computing the time difference
*/
volatile uint16_t timeA = 0;
volatile uint16_t timeB = 0;
enum CaptureState : uint8_t {
WAITING_FOR_A,
WAITING_FOR_B,
CAPTURE_COMPLETE
};
volatile CaptureState state = WAITING_FOR_A;
ISR(INT0_vect) {
uint16_t t = TCNT1;
if (WAITING_FOR_A == state) {
timeA = t;
state = WAITING_FOR_B;
}
}
ISR(INT1_vect) {
uint16_t t = TCNT1;
if (WAITING_FOR_B == state) {
timeB = t;
state = CAPTURE_COMPLETE;
}
}
void setup() {
Serial.begin(115200);
pinMode(2, INPUT);
pinMode(3, INPUT);
TCCR1A = 0; // normal mode
TCCR1B = (1 << CS10); // Timer1 clock = F_CPU (no prescaler)
TCNT1 = 0; // reset counter
EICRA =
(1 << ISC01) | (1 << ISC00) | // INT0 triggers on rising edge
(1 << ISC11) | (1 << ISC10); // INT1 triggers on rising edge
EIFR =
(1 << INTF0) | // clear pending INT0 flag
(1 << INTF1); // clear pending INT1 flag
EIMSK =
(1 << INT0) | // enable INT0
(1 << INT1); // enable INT1
}
void loop() {
if (CAPTURE_COMPLETE == state) {
noInterrupts();
uint16_t a = timeA;
uint16_t b = timeB;
state = WAITING_FOR_A;
interrupts();
uint16_t deltaTicks = b - a;
float deltaMicroseconds = deltaTicks * (1000000.0 / F_CPU);
Serial.print("Delta us: ");
Serial.println(deltaMicroseconds);
}
}
Assuming one could do the 4 micros precision (might keep code portable ;)
speed = distance / time => 1 m / 0.024000 s = 41.67 m/s = 150.00 km/h
speed = distance / time => 1 m / 0.024004 s = 41.66 m/s = 149.98 km/h
(delta = 1 cm/s )
If the 1 meter is in reality 1 mm longer
speed = distance / time => 1.001 m / 0.024000 s = 41.71 m/s = 150.15 km/h
(delta = 4cm/s)
Note that timing of 4 micros result in accuracy of ~1 cm/s scale
For the distance to match that level one need to have 1 meter +- 0.25 mm
(or use 4 meter +- 1 mm.)
First order conclusion
So to have an accuracy of 0.1 m/sec
The problem of sensing individual tires can only be done if the sensor distance is closer than any vehicle with two or more axles close to each other. Think of car + trailer, trailer with two or more axles, truck with many axles. Finally, think of a kid on a bicycle that crosses one sensor at an angle and misses the second sensor. I remember doing that!
Indeed analytics is not trivial,
however if one knows the speed based upon first wheel, one can make an educated guess about the minimum distance between cars. A trailer will be much closer than the next car.
So I think one can determine the individual cars 99 out of 100.
Getting only one sensor means either kids or an airplane so those can be ignored ;)
Hello, first of all, thank you for wanting to help me. I want to measure speeds between 1, 20, and 40 km/h. I will be using it outdoors. The lane markings are fixed, and the road width is 5 meters. The speed range is 5-40 km/h.