Notifications
Clear all

Under new management??

108 Posts
5 Users
9 Reactions
27.8 K Views
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

No, not the Dronebot Workshop, my remote environment sensors.

As I threatened in another thread, I have now started to save battery life with better "Power Management". I did put a request in for this subject to be featured but it has been met with very little resonance, so I thought I would just go down this rabbit hole alone.

First, my revised and tested sketch:

// Attic sensor

#define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <LowPower.h>

#define SEALEVELPRESSURE_HPA (1013.25)

#include <RF24.h>
#include <RF24Network.h>
#include <SPI.h>

RF24 radio(10,9); // nRF24L01 (CE,CSN)
RF24Network network(radio); // Include the radio in the network
const uint16_t this_node = 01; // Address of this node in Octal format ( 04,031, etc)
const uint16_t node00 = 00; // 

// transmit indicator
#define transmit 6
#define mainPower 7

// function declarations
int checkSum();

Adafruit_BME280 bme; // Create the bme object

typedef struct{
  unsigned long upTime;
  byte station;
  float temperature;
  float pressure;
  float humidity;
  //float visible = 0.00; // dummy value
  //float infrared = 0.00; // dummy value
  float ultraviolet;
  byte checksum;  
  }bme280data;

bme280data myObject; // declare the message object

int timerCycle = 0;

void setup() {
  
  Serial.begin(115200);
  // Print splash sheet to monitor
  Serial.print("*Source file: ");
  Serial.println(__FILENAME__); // Source file name
  Serial.print("Compile date: ");
  Serial.println(__DATE__);
  Serial.print("Compile time: ");
  Serial.println(__TIME__);
  Serial.println();
  
  //Initialise the nrf24l01
  
  SPI.begin();
  radio.begin();
  radio.setAutoAck(1);
  radio.setRetries(2,15);
  radio.setPALevel(RF24_PA_HIGH); // RF24_PA_MIN = 0, RF24_PA_LOW = 1, RF24_PA_HIGH = 2, RF24_PA_MAX = 3
  radio.setDataRate(0); // RF24_1MBPS = 0, RF24_2MBPS = 1, RF24_250KBPS = 2
  radio.setCRCLength(2); // RF24_CRC_DISABLED = 0, RF24_CRC_8 = 1, RF24_CRC_16 = 2
  network.begin(90, this_node); //(channel, node address)

  // Initialise bme280

  if (!bme.begin(0x76)) {
  Serial.println("Could not find a valid BME280 sensor, check wiring!");
  while (1);
  }

  // initialise 5V bus control pin
  pinMode(mainPower, OUTPUT);

  // indicate sketch has started
  pinMode(transmit, OUTPUT);
  digitalWrite(transmit, HIGH);
  delay(1000);
  digitalWrite(transmit, LOW);
  
}

void loop() {

  network.update();
  timerCycle ++;
  
  LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART0_OFF, TWI_OFF);
  
  if(timerCycle >= 8){ // occurs every 8*8 seconds

    // to be implemented after hardware rebuild
    // digitalWrite(mainPower, HIGH); // turn on 5V bus
    // delay(100); // allow system to settle
    
    myObject.upTime = 0.00; //dummy value may be deprecated
    myObject.station = 10; // 10 = attic, 20 = balcony
    myObject.temperature = bme.readTemperature();
    myObject.pressure = bme.readPressure() / 100.0F;
    myObject.humidity = bme.readHumidity();
    myObject.checksum = checkSum();

    myObject.ultraviolet = 0.00; // dummy value

    digitalWrite(transmit, HIGH); // transmission start indicator
  
    RF24NetworkHeader header(node00); // (Address where the data is going)
    bool ok = network.write(header, &myObject, sizeof(myObject)); // Send the data

    delay(1);
    digitalWrite(transmit, LOW); // transmission stop indicator 
        
    timerCycle = 0;

    // digitalWrite(mainPower, LOW); // turn off 5V bus
    
  }
}

int checkSum(){
  
  unsigned char *buffer=(char*)malloc(sizeof(myObject));
  memcpy(buffer,(const unsigned char*)&myObject,sizeof(myObject));

  int result = buffer[0];
  for(int i=1; i<sizeof(myObject) - 1; i++){
    result ^= buffer[i];
  }
  
  free(buffer);

  return result;
  }

What has changed?

The millis() function no longer controls the frequency of broadcasts, this is achieved by waking up the Arduino every 64 seconds to read the values from the sensors, broadcast them to the base station and then return to idle/sleep mode.

Judging by what I have read on this subject, I may achieve about 3-4mA current saving. Considering that the whole setup is pulling about 35 to 40 mA, that is a 10% reduction.

My basic setup looks like this. I have a block of six Eneloop AA rechargeables (nominal voltage 7.2V). When fully charged I am getting about 8.5V, this drops to 6.5V over a period of about 44 hours and then the system just closes down.

The next stage will undoubtedly give me a much larger reward. You can probably guess what I am going to do next when looking at the commented out code. I intend to power all the sensors from a bus that is switched on and off as required using an NPN transistor, a resistor attached to base and pin 7 of the Arduino. I have measured the current consumption of the sensors and this combined adds up to about 17mA, plus the 3mA saved in the Arduino would theoretically halve the power requirement and double the battery life.


   
Duce robot and ZeFerby reacted
Quote
frogandtoad
(@frogandtoad)
Member
Joined: 6 years ago
Posts: 1458
 

@pugwash

Just a thought... have you considered using an RTC module to control the sleep time and cut power?

 


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

@frogandtoad

Just a thought... have you considered using an RTC module to control the sleep time and cut power?

No, I haven't considered it. I wanted to keep the remotes as simple as possible. I will give it some thought, as the RTC, I believe, has an IRQ function which could also be used with the LowPower.h library.


   
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 6 years ago
Posts: 1458
 

@pugwash

Ok, no worries!

Posted by: @pugwash

the RTC, I believe, has an IRQ function which could also be used

Yeah, I'm not sure if they all have an IRQ function, but I have seen a couple that do which is a good feature to have.  I have seen some examples in the past where people also use sensor, such as an LDR or motion sensor to trigger power off overnight, etc...


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

What I have been wondering is, that only seven pins on the nrf24 are used. The eighth pin is labelled IRQ but I have not found any documentation of its use. I was wondering if it fires an IRQ when a message is received, would this be enough to wake up the Arduino and process the message. I guess I am going to have to connect one channel of my oscilloscope to the IRQ and the other to the data output pin, just to find out what is really happening.


   
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 6 years ago
Posts: 1458
 

@pugwash

I haven't checked that, but if you check out the previous reference I gave you, it will most likely cover how that IRQ works:

Have you by any chance checked out the following methods?:

void RF24::powerUp(void);
void RF24::powerDown(void);

RF24 class reference

Same link I provided last time 🙂


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

@frogandtoad

void RF24::powerUp(void);
void RF24::powerDown(void);

I had completely forgotten about those, and as the nrf24 is the main power consuming culprit, pulling about 13mA. There may be a "quick and dirty" intermediate solution.


   
frogandtoad reacted
ReplyQuote
(@dronebot-workshop)
Workshop Guru Admin
Joined: 6 years ago
Posts: 1119
 
Posted by: @pugwash

No, not the Dronebot Workshop, my remote environment sensors.

Well, that's a relief!

?

Posted by: @pugwash

I did put a request in for this subject to be featured but it has been met with very little resonance

Actually I was planning on accepting it, and combining it with another similar suggestion. But I was also surprised that there wasn't much feedback on it.

"Never trust a computer you can’t throw out a window." — Steve Wozniak


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

@dronebot-workshop

Actually I was planning on accepting it, and combining it with another similar suggestion. But I was also surprised that there wasn't much feedback on it.

Then perhaps this thread will act as a litmus test for whether you should or not!


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

@frogandtoad

Have incorporated radio.powerDown() and uploaded the sketch. So far so good! I am getting info coming back, so nothing wrong there.

"The proof of the pudding is in the eating"

Now I just have to wait 44 hours or so to see whether I am getting any power savings ? 

If this works, I shall publish the revised code with results!


   
ReplyQuote
Duce robot
(@duce-robot)
Member
Joined: 6 years ago
Posts: 694
 

@dronebot-workshop

It seems like it could be effective even with the sixty plus amphrs on the robot .are all of these sketches going to be a part of one gigantic program or separate working together within an environment ?


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

This is the sketch I am currently testing. It uses the radio.powerDown() function of the RF24.h library and the power returns automatically as soon as I call the network.write() function. And this looks quite promising so far.

//Attic sensor

#define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <LowPower.h>

#define SEALEVELPRESSURE_HPA (1013.25)

#include <RF24.h>
#include <RF24Network.h>
#include <SPI.h>

RF24 radio(10,9); // nRF24L01 (CE,CSN)
RF24Network network(radio); // Include the radio in the network
const uint16_t this_node = 01; // Address of this node in Octal format ( 04,031, etc)
const uint16_t node00 = 00; // 

// function declarations
int checkSum();

Adafruit_BME280 bme; // Create the bme object

// transmit indicator
#define transmit 6
//#define mainPower 7

typedef struct{
  unsigned long upTime;
  byte station;
  float temperature;
  float pressure;
  float humidity;
  //float visible = 0.00; // dummy value
  //float infrared = 0.00; // dummy value
  float ultraviolet = 0.00; // dummy value
  byte checksum;  
  }bme280data;

bme280data myObject; // declare the message object

int timerCycle = 0;

void setup() {
  
  Serial.begin(115200);
  // Print splash sheet to monitor
  Serial.print("*Source file: ");
  Serial.println(__FILENAME__); // Source file name
  Serial.print("Compile date: ");
  Serial.println(__DATE__);
  Serial.print("Compile time: ");
  Serial.println(__TIME__);
  Serial.println();
  
  //Initialise the nrf24l01
  
  SPI.begin();
  radio.begin();
  radio.setAutoAck(1);
  radio.setRetries(2,15);
  radio.setPALevel(RF24_PA_MAX); // RF24_PA_MIN = 0, RF24_PA_LOW = 1, RF24_PA_HIGH = 2, RF24_PA_MAX = 3
  radio.setDataRate(0); // RF24_1MBPS = 0, RF24_2MBPS = 1, RF24_250KBPS = 2
  radio.setCRCLength(2); // RF24_CRC_DISABLED = 0, RF24_CRC_8 = 1, RF24_CRC_16 = 2
  network.begin(90, this_node); //(channel, node address)

  // Initialise bme280

  if (!bme.begin(0x76)) {
  Serial.println("BME280 not detected!");
  while (1);
  }

  // initialise 5V bus control pin
  //pinMode(mainPower, OUTPUT);

  // indicate sketch has started
  pinMode(transmit, OUTPUT);
  digitalWrite(transmit, HIGH);
  delay(1000);
  digitalWrite(transmit, LOW);
  
}

void loop() {
   
  timerCycle ++;

  LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART0_OFF, TWI_OFF);
  
  if(timerCycle >= 8){ // occurs every 8*8 seconds
    
    network.update();
    
    //digitalWrite(mainPower, HIGH); // turn on 5V bus
    //delay(100); // allow system to settle
    
    myObject.upTime = 0.00; //dummy value may be deprecated
    myObject.station = 10; // 10 = attic, 20 = balcony
    myObject.temperature = bme.readTemperature();
    myObject.pressure = bme.readPressure() / 100.0F;
    myObject.humidity = bme.readHumidity();
    myObject.checksum = checkSum();
  
    digitalWrite(transmit, HIGH); // transmission start indicator
    
    RF24NetworkHeader header(node00); // (Address where the data is going)
    bool ok = network.write(header, &myObject, sizeof(myObject)); // Send the data
  
    delay(1);
    digitalWrite(transmit, LOW); // transmission stop indicator 

    timerCycle = 0;
    radio.powerDown();

    //digitalWrite(mainPower, LOW); // turn off 5V bus
   
  } 
}

int checkSum(){
  
  unsigned char *buffer=(char*)malloc(sizeof(myObject));
  memcpy(buffer,(const unsigned char*)&myObject,sizeof(myObject));

  int result = buffer[0];
  for(int i=1; i<sizeof(myObject) - 1; i++){
    result ^= buffer[i];
  }
  
  free(buffer);

  return result;
  }

This version only powers down the nrf24 module, so there are further possibilities to cut off power to the BME280 and the UV detector, saving a few more mAs.

But one thing is really bugging me and that is the two LEDs which are lit up constantly, one on the Nano and the other on the 9V to 5/3.3V power bridge. The LED on the power bridge is a 3mm LED which should be easy enough to remove. Judging by the 102 SMD resistor, the LED on the Nano is consuming up to 5 mA, one eighth of the total power consumption, so it has to go!

I have tried de-soldering it to no avail, this now looks like a job for a Dremel.


   
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 6 years ago
Posts: 1458
 

@pugwash

Nice work... this project has come a long way since you first posed it 🙂


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 6 years ago
Posts: 923
Topic starter  

@frogandtoad

Thanks, this has been a pleasure and learning experience for me. When I first joined this forum I gave it some thought on how to breathe life into the framework that Bill @dronebot-workshop had created because now it was up to us. I have started quite a few threads on diverse topics but this project has given me more satisfaction than any other topic. Certainly the exchange between what I call "The Hard Core Four (@pugwash, @frogandtoad, @zeferby and @robo-pi)" has been both educational and amusing at times.

Furthermore, I hope this will be useful to others further down the road.


   
frogandtoad and ZeFerby reacted
ReplyQuote
frogandtoad
(@frogandtoad)
Member
Joined: 6 years ago
Posts: 1458
 

@pugwash

Thank you too!
Coincidentally my thoughts as well, and I'm always happy to help, when I know what the hell I'm talking about! 🙂

Cheers!


   
ReplyQuote
Page 1 / 8