Monday, December 27, 2021

Arduino Low Power battery operated motion activated switch

blogging after 5 years 

As long as I could remember I wanted to make a motion activated switch which can run on batteries for days/months.

2016 I gave it first short . with Arduino pro mini , 18650 3.7V battery , PIR sensor , LDR , servo and dual H bridge driver . After full charge ~4.2V the circuit worked as expected i.e switching ON when it detects motion and turn OFF when there is no motion detected for ~1min .

then once the battery drained to a point around ~3.7V , Arduino started getting reset when ever the servo motor moves . battery didn't have enough power to drive servo and maintain stable voltage . Note I didn't have voltage regulator to save power .

here is the video 


 After the above v1.0 his I have made below changes for v2.0 

instead of one bulky 18650 battery switched to 4 AAA 800mAh 

swapped dual H bridge driver with a single N-channel enhancement MOSFET

v2.0 idle/standby current is 350micro Amps , batteries should easily last for 1-2months 


fritzing  schematic 

this is how the prototype is looking  , working on creating a custom PCB 



//Arduino code for v2.0 goes something like this . will post video and schematic at later time 

#include <LowPower.h>

static const uint8_t LDRPin = A7 ;

static const uint8_t LDRPin_source = 7 ;

static const uint8_t pirPin = 2;

static const uint8_t mosfet_pin = 5;

static const uint8_t servoPin = 8;

uint8_t cnt = 0;

bool is_light_on = false;

byte val;


void ServoOn () {

  digitalWrite(mosfet_pin, HIGH);

  LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_OFF);

}

void ServoOff() {

  digitalWrite(mosfet_pin, LOW);

  LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_OFF);

}


void ServoInitialize() {

  pinMode(servoPin, OUTPUT);

}

void PirInitialize() {

  pinMode(pirPin, INPUT);

}

void LdrInitialize() {

  pinMode(LDRPin_source, OUTPUT);

  digitalWrite(LDRPin_source, LOW);

}

void MotorModuleInitialize () {

  pinMode(mosfet_pin, OUTPUT);

}

void setup() {

  LdrInitialize();

  PirInitialize();

  ServoInitialize();

  MotorModuleInitialize ();

  readAnalogValue();

  delay(30);


  pinMode(LED_BUILTIN, OUTPUT);

  for (cnt = 0 ; cnt < 3 ; cnt++ ) {

    if ( cnt % 2 == 0 ) {

            digitalWrite(LED_BUILTIN, LOW);

    } else {

            digitalWrite(LED_BUILTIN, HIGH);

    }

    delay(1000);

  }


  switch_on();

}

int LdrReading = 0;

void readAnalogValue () {

  digitalWrite(LDRPin_source, HIGH);

  delayMicroseconds(50);

  LdrReading = analogRead(LDRPin);

  delayMicroseconds(5);

  digitalWrite(LDRPin_source, LOW);

}

unsigned long my_time;


void set_angle(int val, int cnt) {

  for ( int i = 0 ; i < cnt ; i++ ) {

    digitalWrite(servoPin, HIGH);

    delayMicroseconds(val);

    digitalWrite(servoPin, LOW);

    LowPower.powerDown(SLEEP_30MS, ADC_OFF, BOD_OFF);

  }

}


void switch_mid() {

  ServoOn ();

  set_angle(100 * 16, 2 * 16 );

  ServoOff();

}

void switch_on() {

  is_light_on = true ;

  ServoOn ();

  set_angle(93 * 16, 2 * 16 );

  ServoOff();

}


void switch_off() {

  is_light_on = false ;

  ServoOn ();

  set_angle(40 * 16, 2 * 16 + 2 );

  ServoOff();

}


void motionDetection()

{

  val = digitalRead(pirPin);

  

  if (val == HIGH && is_light_on == false) {

    readAnalogValue();

    if ( LdrReading > 985 ) {

      switch_on();

    } 

  } else if ( val == LOW && is_light_on == true )   {

    switch_off();

  } 

}


void wakeUp () {  }


void loop () {


  attachInterrupt(digitalPinToInterrupt(pirPin), wakeUp, CHANGE);

  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);

  detachInterrupt(digitalPinToInterrupt(pirPin));

  motionDetection();delay(100);


}