Low-power battery operated laser beam interruption counter/detector

I have made considerable progress on this project. I withdraw my initial assessment that this is a dead end. Read on.
A friend is very involved with the support of local walking trails. His group wants to gather usage statistics, and he is in the process of developing a device that can count the number of users that cross a wooden footbridge and the time/date that occurs. A key design issue is power conservation; this would be a battery-operated device. He’s using a microwave detector. We chatted about his work, and for the fun of it I tried to develop an alternative method using very inexpensive laser components. Although I was successful from an electronics standpoint, the system likely will not work in an outdoor environment, for reasons I’ll detail later. However, I think it’s an interesting design and may be applicable to other use cases.
The use case is to detect an individual (or perhaps a bicycle) traveling at low speed through a counting portal, such as a trailhead, doorway, or driveway. It is anticipated that traffic will be relatively light, perhaps anywhere between 20 and 100 events per day.
There are four core components:
The latter two devices are ridiculously cheap and are ubiquitous on eBay and Amazon. The transmitter is a small 5mW laser. The receiver is an interesting little guy. It has an ISO203 sensor plunked on a board that is used for a thermal sensor. When illuminated, the output is low. When not illuminated, the output goes high. There’s a discussion of this device here: https://forum.arduino.cc/t/documents-about-laser-sensor-ds18b20/1090450 (scroll to the bottom for an explanation of the device.)
Typically, a beam interruption application has the laser receiver and transmitter pair always on, and the MCU code (on an Arduino, for example) in the loop() polls a pin attached to the output of the sensor. An alternative is to read the sensor output as an interrupt. In either scenario, the sensor, MCU, and transmitter are always powered on. Even if the output of the sensor to the MCU were used as an interrupt to wake a sleeping MCU, the laser requires approximately 25 mA continuously. That’s a lot for a battery-operated device that might get serviced once every two or three weeks.
However, if we are trying to detect low-frequency, long-duration events, continuous sampling of the laser beam is not needed. I’m not sure the Nyquist theorem is totally applicable, but it comes close. Let’s say it will take a human 0.2 seconds to walk through a doorway; the beam will be interrupted for 0.2 seconds. If we sample at twice that rate, we will detect the event. That means we turn on the laser and sensor ten times a second and do not leave the devices on continuously. If sampling can take place quickly, these power-hungry components have a very short duty cycle.
In practice, this works. The ESP32 is programmed to wake from deep sleep every 100 msec. A HIGH signal is sent to the logic level MOSFET (I love these things!!!), which then supplies power to the laser and sensor. The sensor output is read. If LOW, power to the sensor/laser is turned off and the MCU goes back to sleep. If the sensor output is HIGH, the MCU remains on. It continues to poll the sensor until the sensor is LOW. This approach prevents a single slow transit from being counted as multiple transits. Once the sensor is LOW, the event is processed. In my little experimental setup, this involved turning on an LED for a few hundred msec. In a real application, I’d likely access an external RTC running on a coin battery (like a DS3231 module with a CR2032 backup battery) to get a time stamp and then write to an SD card. The circuit then goes back to sleep. Both the laser and sensor are connected to the same MCU; a mirror is used to reflect the laser beam back to the sensor.
The power implications of this approach are considerable. The measured current draw with the MCU running and laser/sensor on is about 70 mA. The measured current draw with the MCU in deep sleep and laser/sensor off is about 3.5 mA. Removal of the power-on LED from the MCU board would reduce power consumption by at least another 1 mA. An on-power-up-read sensor cycle is approximately 60 microseconds. Let’s do a worst-case scenario and say that in real life, querying a DS3231 and writing to an SD card would take 100 msec and require 60 mA current (peripherals plus MCU). Finally, let’s assume that we are using my favorite rechargeable battery, the venerable 18650, and that 2000mAh are available. Although the laser devices call for 5V, the sensor and laser ran just fine directly from the battery at 3.7V. No need for level shifting or DC-DC converters.
With these assumptions, let’s do some back-of-the-envelope calculations. How many mAh will the device consume in 24 hrs, assuming 100 people per day go through the doorway?
I don’t know if someone has tried this before. If they have, kudos to them and I relinquish any claim to originality. However, if this is a new hack, I hope it is useful to someone. I acknowledge the utility of the ESP32 example code for deep sleep in the Arduino environment and the wonderful Random Nerd Tutorial on the subject, available here: https://randomnerdtutorials.com/esp32-deep-sleep-arduino-ide-wake-up-sources/
Final point. Mechanically, this is a difficult arrangement. The sensor target is tiny, and the laser beam is of narrow diameter (for heaven’s sake—it’s a laser!). Achieving (and maintaining) alignment of the beam and sensor has proven difficult. Even small vibrations associated with walking across a wooden bridge might cause misalignment. Weatherproofing, bug-proofing, and protection from ambient light would complicate construction as well. This is not a good candidate for outdoor use. However, I do think that the concepts involved are of value and might be applicable to other situations, such as an indoor doorway. I may try this with a SAMD21-based board and see if we do any better.
#define FETpin 32
#define LEDpin 23
#define SENSORpin 34
#define SENSEinterval 100000ULL //ten samples per second
long t1;
long t2;
//put in stuff to support a DS2321, programmed in another sketch and with a coin battery
void setup() {
pinMode( SENSORpin, INPUT); // sensor
pinMode( LEDpin, OUTPUT); //LED
pinMode( FETpin, OUTPUT); //FET pin
digitalWrite( LEDpin, LOW);
digitalWrite( FETpin, LOW);
//put in stuff to support a DS2321, programmed in another sketch and with a coin battery
esp_sleep_enable_timer_wakeup(SENSEinterval);
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
digitalWrite(FETpin, HIGH);
delayMicroseconds(50);
if (digitalRead( SENSORpin) == HIGH) {
do { //keep cycling until beam is not interrupted
digitalWrite(FETpin, LOW);
delay(100); //delay 100 msec and see if beam is still interrupted
digitalWrite(FETpin, HIGH);
delayMicroseconds(50);
//when the beam is sensed again, exit loop and do something useful
} while (digitalRead( SENSORpin) == HIGH);
DoSomethingUseful();
digitalWrite( FETpin, LOW);
esp_deep_sleep_start();
}
else {
digitalWrite( FETpin, LOW);
esp_deep_sleep_start();
}
}
void DoSomethingUseful() {
digitalWrite(FETpin, LOW);
digitalWrite( LEDpin, HIGH);
delay(300);
digitalWrite( LEDpin, LOW);
//query an RTC (I like DS2321)
//write to SD card or flash memory
}
void loop() {
//loop is not used. Code executes from the beginning of setup each time the device awakens
}
The use case is to detect an individual (or perhaps a bicycle) traveling at low speed through a counting portal, such as a trailhead, doorway, or driveway. It is anticipated that traffic will be relatively light, perhaps anywhere between 20 and 100 events per day.
There are four core components:
- ESP32 Thing from Sparkfun or generic ESP32 board
- Logic level N MOSFET of your choice
- Laser sensor transmitter
- Laser sensor receiver
The latter two devices are ridiculously cheap and are ubiquitous on eBay and Amazon. The transmitter is a small 5mW laser. The receiver is an interesting little guy. It has an ISO203 sensor plunked on a board that is used for a thermal sensor. When illuminated, the output is low. When not illuminated, the output goes high. There’s a discussion of this device here: https://forum.arduino.cc/t/documents-about-laser-sensor-ds18b20/1090450 (scroll to the bottom for an explanation of the device.)
Typically, a beam interruption application has the laser receiver and transmitter pair always on, and the MCU code (on an Arduino, for example) in the loop() polls a pin attached to the output of the sensor. An alternative is to read the sensor output as an interrupt. In either scenario, the sensor, MCU, and transmitter are always powered on. Even if the output of the sensor to the MCU were used as an interrupt to wake a sleeping MCU, the laser requires approximately 25 mA continuously. That’s a lot for a battery-operated device that might get serviced once every two or three weeks.
However, if we are trying to detect low-frequency, long-duration events, continuous sampling of the laser beam is not needed. I’m not sure the Nyquist theorem is totally applicable, but it comes close. Let’s say it will take a human 0.2 seconds to walk through a doorway; the beam will be interrupted for 0.2 seconds. If we sample at twice that rate, we will detect the event. That means we turn on the laser and sensor ten times a second and do not leave the devices on continuously. If sampling can take place quickly, these power-hungry components have a very short duty cycle.
In practice, this works. The ESP32 is programmed to wake from deep sleep every 100 msec. A HIGH signal is sent to the logic level MOSFET (I love these things!!!), which then supplies power to the laser and sensor. The sensor output is read. If LOW, power to the sensor/laser is turned off and the MCU goes back to sleep. If the sensor output is HIGH, the MCU remains on. It continues to poll the sensor until the sensor is LOW. This approach prevents a single slow transit from being counted as multiple transits. Once the sensor is LOW, the event is processed. In my little experimental setup, this involved turning on an LED for a few hundred msec. In a real application, I’d likely access an external RTC running on a coin battery (like a DS3231 module with a CR2032 backup battery) to get a time stamp and then write to an SD card. The circuit then goes back to sleep. Both the laser and sensor are connected to the same MCU; a mirror is used to reflect the laser beam back to the sensor.
The power implications of this approach are considerable. The measured current draw with the MCU running and laser/sensor on is about 70 mA. The measured current draw with the MCU in deep sleep and laser/sensor off is about 3.5 mA. Removal of the power-on LED from the MCU board would reduce power consumption by at least another 1 mA. An on-power-up-read sensor cycle is approximately 60 microseconds. Let’s do a worst-case scenario and say that in real life, querying a DS3231 and writing to an SD card would take 100 msec and require 60 mA current (peripherals plus MCU). Finally, let’s assume that we are using my favorite rechargeable battery, the venerable 18650, and that 2000mAh are available. Although the laser devices call for 5V, the sensor and laser ran just fine directly from the battery at 3.7V. No need for level shifting or DC-DC converters.
With these assumptions, let’s do some back-of-the-envelope calculations. How many mAh will the device consume in 24 hrs, assuming 100 people per day go through the doorway?
- What’s the baseline sleep usage? If we assume 2 mA for 24 hours, that’s 48 mAh.
- The device turns on for 60 microseconds 10 times per second, using 70 mA while on. That means 600 us per second, 36000 us per minute, 2160000 us per hour, or 2.16 seconds per hour, times 24 or (rounding) 52 seconds per 24 hours. 52 seconds is 52/3600 of an hour, or .0144 hr. That means .0144 X 70 mA is just over 1 mAh. Now we’re up to 49 mAh.
- 100 people times 100 msec per person is 10 seconds per day processing events. 10 seconds is .003 hours X 60 mA is approx. .2mAh. Let’s round unfavorably and call the total 50 mAh per day.
- 40 days on a single charge! Clearly, the primary driving factor in power consumption is NOT processing events but sitting on standby. The use of an MCU that had an even lower deep sleep power consumption might well result in a longer battery life.
- Continuous on is easy: 70 mA x 24 is 1680 mAh, or under a day and a half.
I don’t know if someone has tried this before. If they have, kudos to them and I relinquish any claim to originality. However, if this is a new hack, I hope it is useful to someone. I acknowledge the utility of the ESP32 example code for deep sleep in the Arduino environment and the wonderful Random Nerd Tutorial on the subject, available here: https://randomnerdtutorials.com/esp32-deep-sleep-arduino-ide-wake-up-sources/
Final point. Mechanically, this is a difficult arrangement. The sensor target is tiny, and the laser beam is of narrow diameter (for heaven’s sake—it’s a laser!). Achieving (and maintaining) alignment of the beam and sensor has proven difficult. Even small vibrations associated with walking across a wooden bridge might cause misalignment. Weatherproofing, bug-proofing, and protection from ambient light would complicate construction as well. This is not a good candidate for outdoor use. However, I do think that the concepts involved are of value and might be applicable to other situations, such as an indoor doorway. I may try this with a SAMD21-based board and see if we do any better.
Code
#define FETpin 32
#define LEDpin 23
#define SENSORpin 34
#define SENSEinterval 100000ULL //ten samples per second
long t1;
long t2;
//put in stuff to support a DS2321, programmed in another sketch and with a coin battery
void setup() {
pinMode( SENSORpin, INPUT); // sensor
pinMode( LEDpin, OUTPUT); //LED
pinMode( FETpin, OUTPUT); //FET pin
digitalWrite( LEDpin, LOW);
digitalWrite( FETpin, LOW);
//put in stuff to support a DS2321, programmed in another sketch and with a coin battery
esp_sleep_enable_timer_wakeup(SENSEinterval);
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
digitalWrite(FETpin, HIGH);
delayMicroseconds(50);
if (digitalRead( SENSORpin) == HIGH) {
do { //keep cycling until beam is not interrupted
digitalWrite(FETpin, LOW);
delay(100); //delay 100 msec and see if beam is still interrupted
digitalWrite(FETpin, HIGH);
delayMicroseconds(50);
//when the beam is sensed again, exit loop and do something useful
} while (digitalRead( SENSORpin) == HIGH);
DoSomethingUseful();
digitalWrite( FETpin, LOW);
esp_deep_sleep_start();
}
else {
digitalWrite( FETpin, LOW);
esp_deep_sleep_start();
}
}
void DoSomethingUseful() {
digitalWrite(FETpin, LOW);
digitalWrite( LEDpin, HIGH);
delay(300);
digitalWrite( LEDpin, LOW);
//query an RTC (I like DS2321)
//write to SD card or flash memory
}
void loop() {
//loop is not used. Code executes from the beginning of setup each time the device awakens
}
Updates vom Autor
edringel@alum.mit.edu vor 1 Jahr
To recap, the purpose of this device is to monitor trail activity. Nothing fancy—just record that someone (or a trail bike) had passed through the detection portal and record the time. The data has real-world value in our local trail system's planning, maintenance, and funding.
Design constraints were that it be battery-operated and that it would need servicing (data collection and recharging) one each month. Laser beam interruption seemed a logical option, but even small, low-power lasers consume considerable power relative to the constraints of battery-operated devices. However, intermittent operation of the laser and the sensing device can markedly reduce power consumption. As I indicated in the original post, we can take advantage of a person’s or bicycle's relatively slow passage through the sensing portal. If we “sample” the portal 10 times per second, we will detect an event of at least one fifth’s second duration (supported by the Nyquist theorem of digital signal processing.)
Although not built for this purpose, the cheap laser-sensor kits sold on Amazon and eBay (for example, Amazon product https://www.amazon.com/gp/product/B09TP51ZTJ) can be operated intermittently. Intermittent sampling combined with the MCU sleeping between samples reduces power consumption significantly. The time stamp is obtained from a DS3231 module with a backup coin battery and a simple SD card module. These peripherals are powered off unless/until there is a detection event. Example devices: RTC: https://www.amazon.com/HiLetgo-AT24C32-Arduino-Without-Battery/dp/B00LX3V7F0, SD module https://www.amazon.com/dp/B09YYG6BT3. There are other DS3231 board styles, but a board with coin battery backup is an absolute requirement. Because my final choice of MCU runs at 3.3V, a simple SD card reader without level-shifting circuitry was sufficient.
After some experimentation, I settled on a Sparkfun ESP32 Thing as my MCU. I experimented with a SAMD21-based board. It was easy to program and worked great, but using existing low-power libraries, the device cycled in and out of deep sleep unacceptably slowly. The ESP32 handles deep sleep differently and requires different, somewhat unusual programming techniques. However, the board cycled rapidly, well within my design goals, and when all was said and done, the programming was pretty straightforward once I wrapped my head around it. The Sparkfun ESP32 thing board has the advantage of a robust 600 mA LDO voltage regulator, and I powered my RTC, the SD card reader, and the laser sensor from the board’s 3.3V output (Although the Amazon product page states that the laser and sensor require 5 volts, the sensor ran just fine from 3.3 and I powered the laser from the 3.7V battery.) Because the ESP32 runs at 3.3V, no level shifting was required for the SD card.
Power to the RTC, SD card reader, laser, and sensor is controlled by three N-channel logic-level MOSFETs. I am using CEP8030L devices. There are any number of good quality devices that are fully on with 3.3V applied to the gate and have milliohm internal resistance. However, I am not entirely happy with this arrangement. As the reader can see from the schematic, it results in a floating ground when the peripheral devices are turned off. This may be OK for a light bulb or a motor, but maybe not so much for sensitive electronics. The floating ground issue may also be responsible for why I needed to provide separate power MOSFETs for the RTC and SD card reader. I may end up experimenting with P-channels and see if I can get it to work in the context of the MCU constantly (partially) resetting itself. If it does work, I will evaluate the effect on power consumption. I also have a SAMD51-based board on order, and I will see if it cycles more quickly than its SAMD21 older sibling. Deep sleep cycling on the SAMD boards does not result in a partial reset, and may be more amenable to a situation where holding the output pin high prevents the MOSFET from turning on. In the end, this may be more of a theoretical than a real issue.
My other concern had to do with the mechanical aspects of the setup. The sensor is a small target, and the laser beam is of equally small size. The electronics package sits on one side of the trail, and a mirror reflects the laser beam back. Let’s assume the trail portal is 3m across; that means the beam travels 6m. If I am doing the math correctly, a torque of 1/5 degree in the laser would be enough to shift the beam 1 cm. Attaching the electronics and mirror to trees or lightly built structures might thus be a problem. However, my mechanical engineer friend, with whom I am collaborating on this project, thinks we can make an arrangement that will be stable and “aimable”. The worst-case scenario is that the device would be usable/useful in a more sheltered environment such as an indoor doorway.
So finally, let’s return to the power issue. I abused the poor MCU board and removed the power LED. How long will an 18650 battery last? Let’s assume 2000mAh is available.
Measured current in different states:
Deep sleep: 0.84 mA (with the power LED in place, 2.5 mA!)
Sensing: 24 mA
Query RTC and write to the SD card: 50 mA
Time in each state:
Let’s assume deep sleep is continuous: 24 hrs.
The sense cycle takes 0.13 msec. Assuming 10 samples per second, the device spends 254 seconds per day sensing if no one enters the sensing zone. Because of the way a portal crossing is detected, there are extra sensing cycles associated with a detection event. If we posit 5 extra cycles for a detection (probably high), and we assume 200 crossing per day, that’s an extra 1000 cycles, which is 130 msec. We can ignore that.
The write cycle takes 55 msec. Assuming 200 people per day use the trail, that’s 11 seconds per day recording events.
Power consumption per 24 hrs:
Sleep: 20 mAh
Sense: .06 mAh
Write: .007 mAh
Slightly under 100 days. Not sure I believe it, seems too good to be true, but we’ll check it out.
More to come if/when we get a good mechanical package, change the FETs, and/or change the MCU.
I’ve included an updated schematic, an updated .ino file, and an updated picture. The schematic includes an SPDT switch that allows the laser to remain on continuously for aiming.
Laser interrupt schematic update.pdf (23kb)
laser_interrupt_esp32_sleep_2.ino (3kb)