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.
Just a thought... have you considered using an RTC module to control the sleep time and cut power?
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.
Ok, no worries!
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...
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.
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);
Same link I provided last time 🙂
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.
No, not the Dronebot Workshop, my remote environment sensors.
Well, that's a relief!
?
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
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!
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!
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 ?
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.
Nice work... this project has come a long way since you first posed it 🙂
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.
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!