Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to "verify" your details, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ Electronics ➜ Microprocessors ➜ Solar powered Arduino

Solar powered Arduino

Postings by administrators only.

Refresh page


Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Sun 29 Mar 2015 01:14 AM (UTC)

Amended on Mon 06 Apr 2015 02:50 AM (UTC) by Nick Gammon

Message
Following on from my posts about low power consumption (http://www.gammon.com.au/power) I got enthusiastic when I saw a thread Arduino powered by a capacitor by heliosoph.

So since I had a 1W, 6V solar panel from Adafruit (Flexible 6V 1W Solar Panel) I thought I would try my hand at making a solar-powered capacitor storage, powering an Atmega328P.

Solar panel:



I found it helpful to tape the wires onto the back of the solar panel with strong adhesive tape, as a form of strain relief, otherwise you tended to pull the wires off as you carried it around:






I also had to hand a 0.47F (that is, 470000µF) super-capacitor, rated at 5.5V.

Super-capacitor:




Why a capacitor? Why not a battery?


Batteries have problems. If you have ever owned a solar-powered torch, as I have, or solar-powered garden lights, you often find that, after a couple of years, they fail because of the limited number of times you can charge and discharge a NiCad battery.

So, the problems are:


  • Limited number of charge/discharge cycles*
  • They don't like being discharged too far
  • They don't like being overcharged
  • They don't like being discharged too fast
  • They don't like being charged too fast



* Charge cycles

According to Comparison Table of Secondary Batteries a NiCad battery can be charged 1000 times and a NiMh battery 300 to 500 times (both if properly maintained).

This is hardly exciting stuff for a device "in the field" as 1000 cycles will be 1000/365 = 2.7 years, and 500 cycles half that.


However capacitors, by their nature, usually have thousands of charge/discharge cycles, often during a single second. That is their nature. So they are more suited to long-term situations where you keep charging and discharging them, not always at a predictable rate.

Transmitter


My planned use for this set-up is as some kind of probe or monitor. For example, to monitor:


  • Temperature
  • Humidity
  • Light level
  • Events (such as a door opening)
  • Barometric pressure


Now this is only useful if the gathered information can be transmitted somewhere (or recorded on an SD card). Indeed, commercially available weather stations do exactly that.

I chose a NRF24L01 transceiver module, available from eBay for less than a dollar. For example:





For a couple more dollars you can get an aerial, which extends the range, like this:



As you can see from the labels, you talk to the chip with standard SPI protocol, with a couple of extra signals for selecting the chip. This chip runs on 3.3V which adds the challenge of getting a suitable voltage for it to run.

Charging the capacitor


My preliminary circuit was:



R1 (220 ohm) is designed to current limit the current through D1.

D1 is a 5.6V zener diode. 5.6V is a bit too much for the processor, however the output goes through D2 which would have a forward voltage drop of 0.7V, thus giving the processor around 4.9V.

D2 limits reverse current flow back from the capacitor through D1 or the solar panel, when there is not enough sunlight. (The reverse current through D1 was quite high at 5V).

Testing seems to show that it works OK, in fact in direct sunlight the voltage at the processor 5V pin was getting up to 5.2V.

This gives us a good range of voltages for the processor. It can run as low as 1.8V (if you scale the processor down to 4 MHz) and as high as 5.5V. This gives a good operating range of 1.9V to 5.1V or so. Also the transmitter has a lowest operating range of 1.9V.

Energy in capacitor


Given information about Coulombs, Joules and Watts we can extract these formulae:

Quote:

One coulomb is also the amount of excess charge on a capacitor of one farad charged to a potential difference of one volt:


    C = F * V



Quote:

One joule can also be defined as:

The work required to move an electric charge of one coulomb through an electrical potential difference of one volt, or one '"coulomb volt" (C·V). This relationship can be used to define the volt.

The work required to produce one watt of power for one second, or one "watt second" (W·s) (compare kilowatt hour - 3.6 megajoules). This relationship can be used to define the watt.


    J = C * V
    J = W * s



Where: C = Coulombs, J = Joules, A = amps, s = seconds, F = farads, V = Volts, W = watts

However from http://www.engineeringtoolbox.com/capacitors-energy-power-d_1389.html and http://hyperphysics.phy-astr.gsu.edu/hbase/electric/capeng.html the energy available is actually the average voltage (V) multiplied by the charge (C) and thus the available energy is:


  J = 0.5 * F * V * V


Now to work out how many useful Joules we have in the capacitor from (say) 4.5V to 2.0V:



Start with 0.5 * 0.470 F * 4.500^2 V = 4.759 Joules 
End   with 0.5 * 0.470 F * 2.000^2 V = 0.940 Joules 
Used           = 4.759 J - 0.940 J   = 3.819 Joules 

Capacitor starts with: 0.5 * 0.470 F * 4.500^2 V = 4.759 Joule
Capacitor ends with:   0.5 * 0.470 F * 2.000^2 V = 0.940 Joules
Therefore the capacitor can usefully hold 4.759 - 0.940 = 3.819 Joules 


Power consumption


Let's assume that we use an average of 10 µA. And let's assume that this is at an average voltage of (4.5 + 2) / 2 = 3.25 volts.

Thus the average power consumption is:


0.000010 A * 3.25 V = 0.0000325 W


Since a Joule is a Watt * Second, therefore we can run for:


J = W * s
s = J / W

s = 3.819 J / 0.0000325 W
s = 117500 s (1958.3 minutes, that is, 32.639 hours)


On the face of it, this little capacitor will keep us running for over a day! That should keep the processor alive during some overcast days.

In practice, I have been testing with it under a verandah (under cover) but outside, due to concerns about rain hitting the processor board. Thus it virtually never gets direct sunlight, but only diffuse light which bounces off the ground, nearby building, etc.

If this works for me, then if you install a similar device in a shady place (like, under a tree) you should get similar results.

3.3V supply for the transmitter


If we want our capacitor to range from 2V to 5V we need to reduce that to 3.3V for the transmitter module. This modified schematic adds a MCP1700 Low Quiescent Current LDO 3.3V voltage regulator.



It has a low drop out (LDO) of 178 mV quoted. It also has a low 1.6 μA typical quiescent current. In other words, if the transmitter is off, the voltage regulator should only consume 1.6 µA. This should be acceptable.

I used 1 µF SMD (surface mounted) capacitors mounted underneath the board, thus they are not visible in the photos below.

Wiring it up to the Atmega328P


I used a "breadboard" Arduino (http://www.gammon.com.au/breadboard) to minimize power consumption (eg. from voltage regulators, USB interface chips).

This ran from the internal crystal at 8 MHz. So the only extra components needed would be a pull-up resistor for /RESET, a couple of decoupling capacitors (0.1 µF), and an SPI header for reprogramming after making changes.

The NRF24L01 module is connected like this:



NRF24L01     Atmega328p
----------   ----------------

  VCC         --> 3.3V supply
  Gnd         Gnd
  CSN         Pin 16 (SS)   - D10
  CE          Pin 15        - D9
  MOSI        Pin 17 (MOSI) - D11
  SCK         Pin 19 (SCK)  - D13
  IRQ         N/C
  MISO        Pin 18 (MISO) - D12

-------------------------
Indicator LED   -> Pin 14 - D8
(via 330 ohm resistor and jumper pins)


Note that the pins are the pins on the processor chip. If you are testing with an Arduino Uno or similar use the Dx pin numbers (eg. Digital pin 13 is SCK).

I had an LED via a resistor and also a couple of jumper pins so I could see the LED flash when it was transmitting. To reduce power consumption you could disconnect the LED by removing the jumper.

The capacitor, voltage regulator, diodes, resistor, and a small switch were mounted on a piece of prototyping board.



The switch was to disconnect the solar panel for simulating night during testing.

There is an additional pin marked "to watchdog board" which will be explained later. The incoming red and black wires from the solar panel are passed through one of the mounting holes as a form of strain-relief, otherwise they tend to work their way loose as you move it around.

Sending board code


Below is the code on the Atmega328P "sending" board:


// Program to send its own voltage reading by NRF24L01 to another processor.
// Author: Nick Gammon
// Date: 15th March 2015

// NB: Compile for Lilypad/328 because of the 8 MHz clock
//     Note that we divide clock by 2 so we can run at 1.8V
//     Thus, delays will be twice as long.
//  Fuses:  Low: E2  High: DF  Ext: FF
//      That sets 8 MHz internal clock, and brownout detection disabled

#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/power.h>

const byte LED = 8;
const byte CHIP_ENABLE = 9;
const byte CHIP_SELECT = 10;

// watchdog interrupt
ISR (WDT_vect) 
  {
  wdt_disable();  // disable watchdog
  }  // end of WDT_vect

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"

// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

void setup () 
  {
  // slow clock down to 4 MHz
  
  clock_prescale_set (clock_div_2);

  // set pins to OUTPUT and LOW  
  for (byte i = 0; i <= A5; i++)
    {
    // skip radio pins
    if (i >= 9 && i <= 13)
      continue;
    pinMode (i, OUTPUT);    
    digitalWrite (i, LOW);  
    }  // end of for loop

  ADCSRA = 0;  // disable ADC
  power_all_disable ();   // turn off all modules

  }  // end of setup

void sendVoltage ()
  {
  // Set up nRF24L01 radio on SPI bus plus pins 9 & 10
  
  RF24 radio(CHIP_ENABLE, CHIP_SELECT);
  
  power_all_enable();
  digitalWrite (SS, HIGH);
  SPI.begin ();
  digitalWrite (CHIP_ENABLE, LOW); 
  digitalWrite (CHIP_SELECT, HIGH);
  
  //
  // Setup and configure rf radio
  //
  radio.begin();

  // optionally, increase the delay between retries & # of retries
  radio.setRetries(15, 15);

  // optionally, reduce the payload size.  seems to improve reliability
  radio.setPayloadSize(8);

  radio.openWritingPipe (pipes[0]);
  radio.openReadingPipe (1, pipes[1]);

  radio.startListening ();
  delay (10);
  radio.stopListening ();

   // Take the voltage, and send it.  This will block until complete
 
  ADCSRA =  bit (ADEN);   // turn ADC on
  ADCSRA |= bit (ADPS0) |  bit (ADPS1) | bit (ADPS2);  // Prescaler of 128
  ADMUX = bit (REFS0) | bit (MUX3) | bit (MUX2) | bit (MUX1);
  
  bitSet (ADCSRA, ADSC);  // start a conversion  
  while (bit_is_set(ADCSRA, ADSC))
    { }
 
  // and again, <sigh>
  bitSet (ADCSRA, ADSC);  // start a conversion  
  while (bit_is_set(ADCSRA, ADSC))
    { }
  
  unsigned int reading = ADC;
  delay (10);
  
  bool ok = radio.write (&reading, sizeof reading);
  
  radio.startListening ();
  radio.powerDown ();
  
  SPI.end ();
  // set pins to OUTPUT and LOW  
  for (byte i = 9; i <= 13; i++)
    {
    pinMode (i, OUTPUT);    
    digitalWrite (i, LOW); 
    }  // end of for loop
  ADCSRA = 0;  // disable ADC
  power_all_disable();
  
  }  // end of sendVoltage

unsigned int counter;

void loop () 
  { 

  // every 64 seconds send a reading    
  if ((++counter & 7) == 0)
    {
    digitalWrite (LED, HIGH);
    sendVoltage ();
    digitalWrite (LED, LOW);
    } // end of 64 seconds being up

    // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset
  WDTCSR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval 
  WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0);    // set WDIE, and 8 seconds delay
  wdt_reset();  // pat the dog
  
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  sleep_enable();
  sleep_cpu ();  
  sleep_disable();

  }  // end of loop


The RF24 library came from http://maniacbug.github.com/RF24

It basically uses techniques described in the http://www.gammon.com.au/power link. Most of the time the board is asleep, woken up by the watchdog timer every 8 seconds. The first thing done in setup is to divide the clock speed by two, and since we are already running from the internal 8 MHz oscillator, this gives us 4 MHz operating speed. I compiled this for the Lilypad w/Atmega328 board in the IDE. Since we have divided the clock speed by two all delays will be twice as long as advertised.

However the watchdog timer has its own oscillator, so the interval is still (roughly) 8 seconds.

Every 8 lots of 8 seconds (ie. every 64 seconds) it calls sendVoltage() to transmit its internal VCC voltage to the other board (the receiver board).

Expected power consumption


Running at (say) 4.5V and 20°C we expect to use around 5.5 µA with the watchdog enabled:



Also the MCP1700 voltage regulator claims to use 1.6 µA under no load, and the NRF24L01 transceiver uses 900 nA (0.9 µA) in power-down mode. So, adding that up:


5.5 + 1.6 + 0.9 = 8 µA


This is indeed what I measured.

However there is also the power consumed when transmitting, and this won't be trivial. Even though it is only once a minute, we expect the average consumption to be somewhat higher than 8 µA.

Taking last night as an example, I measured:


4.57V at 8:45 p.m.
3.99V at 7:12 a.m.

Total number of seconds = 44820 s

Average voltage =  (4.57 + 3.99) / 2 = 4.28V

Start with 0.5 * 0.470 F * 4.570^2 V = 4.908 Joules 
End   with 0.5 * 0.470 F * 3.990^2 V = 3.741 Joules 
Used           = 4.908 J - 3.741 J   = 1.167 Joules 


On that particular day:


  • Sunset was at 7:20 p.m.
  • Dusk was at 7:46 p.m.
  • Dawn was at 7:03 a.m.
  • Sunrise was at 7:29 a.m.


Since:


J = W * s

Then:

W = J / s

Thus:

1.167 J / 44820 s = 0.00002604 W (26 µW)

And assuming an average voltage of 4.28V

0.00002604 W / 4.28 V = 0.0000061 A (6.1 µA)


This seems a bit low, however the processor would use less power as the supply voltage drops, so it is just believable.

Brownout detection


In my early tests I enabled brown-out detection. The reason for this was that if the voltage drops below the processor operating voltage (1.8V) then the processor may lock up in a state from which it does not recover. Then it would need to be reset. Now if this lock-up persisted for long enough that the capacitor drained completely, then it could power up the next morning, however without brown-out detection it might lock up again during the power-up process.

So, I enabled brownout detection on the chip (this is a fuse setting) and set it to 1.8V.

However a problem occurred. With brown-out enabled the chip uses a lot more power!



You can see from the datasheet that enabling brown-out detection consumes another 20 µA (this is for the reference voltage it compares against). Now we have the irony that, in order to recover from a low-power situation, we have to consume over three times as much current (28 µA compared to 8 µA when asleep), which itself will cause a low power situation!

An additional problem arises if the chip goes into brownout. The brown-out detection forces the chip into reset. In reset it consumes a lot more power, like 7.8 mA (that is, 7800 µA compared to 28 µA). As you can imagine, consuming almost 8 mA drains the capacitor very quickly, with the result that, next morning it is almost completely discharged, and it takes an hour or so for the sun to raise the voltage enough for it to power back up.

This problem could probably be fixed (to an extent) by using a large capacitor (say, 4 farads) which would therefore have more chance of making it through the night without discharging, but for the capacitor I had to hand (0.47 F) I just removed the brown-out detection.

You can also tweak how often the transmitter sends the data. Initially I was sending every time it woke up (every 8 seconds) which also would have contributed to running the capacitor down. For further fine-tuning you might stop transmitting once the self-detected VCC voltage was below a certain level.

Separate watchdog processor


I still worried, though, that if the chip locked up due to some extensive storm or something, it might not recover without manual intervention. And if it was mounted in some inaccessible place (like the back of a Bengal tiger, or on top of a high tree) it could be tricky to get to it and reset it.

So the idea of a separate "watchdog processor" was born. (I know you can buy chips that do this sort of stuff, but it is interesting to make your own).

This is an ATtiny85 whose sole purpose in life is to wait for 30 minutes after it is powered up, and then drive a pin high for a millisecond or so. This pin will be connected, via a MOSFET, to the /RESET pin of the main Atmega328P board. Thus the main board will be reset. Then once it has done this it goes to sleep ... forever.

Well not really forever. The ATtiny85 is powered by its own, much smaller (440 µF) capacitor, taken from before D2 on the original circuit. Thus this smaller capacitor only gets charged during daylight hours, and will soon exhaust its charge once night falls (which happens regularly). Thus this "watchdog" chip is a "daylight hours" chip. On the watchdog chip we enable the brownout detection, to make sure it starts up reliably, setting it to 2.7V. The extra current the brownout detection uses is not a problem - during the day - because it is constantly being refreshed by sunlight.

The net effect will be that, each morning, once the sunlight reaches the solar panel, that the ATtiny capacitor will charge (however limited in voltage by the charge on the 0.47F super-capacitor) and when it reaches 2.7V it will leave reset, and then wait for another 30 minutes (this is to stop it constantly resetting the main board if a cloud passes over the sky).

Effectively this guarantees that the main board is reset at least once a day, thus pulling it out of any potential brownout condition.

The MOSFET is there because otherwise the /RESET pin may climb to 5V which may be well over VCC of the ATtiny85 and damage it.

Schematic for the second capacitor and diode:



And the ATtiny85:





Now when the ATtiny sends pin 5 HIGH (PB0 or D0 in the sketch) it sinks the voltage on the /RESET pin of the Atmega328P. That resets it.

Code:


// Reset solar panel watchdog
// Author: Nick Gammon
// Date: 22 March 2015

// ATMEL ATTINY 25/45/85 / ARDUINO
// Pin 1 is /RESET
//
//                  +-\/-+
// Ain0 (D 5) PB5  1|    |8  Vcc
// Ain3 (D 3) PB3  2|    |7  PB2 (D 2) Ain1 
// Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1
//            GND  4|    |5  PB0 (D 0) pwm0
//                  +----+

/*

 After reset waits for TIME_TO_WAIT minutes, then brings D0 (pin 5) high for long
 enough to activate a MOSFET and reset the other board.
  
 Fuses: Low: E2 High: DD
 
 (Brownout at 2.7V)
 
*/


#include <avr/sleep.h>    // Sleep Modes
#include <avr/power.h>    // Power management
#include <avr/wdt.h>      // Watchdog timer

const byte MOSFET = 0;          // pin 5 
unsigned long counter = 0;
 
const float TIME_TO_WAIT = 30; // minutes
const unsigned long SLEEPS_TO_WAIT = TIME_TO_WAIT * 60.0 / 8.0;  // 8 second sleeps

// watchdog interrupt
ISR (WDT_vect) 
  {
   wdt_disable();  // disable watchdog
  }  // end of WDT_vect

#if defined(__AVR_ATtiny85__)  
  #define watchdogRegister WDTCR
#else
  #define watchdogRegister WDTCSR
#endif
  
void setup ()
  {
  wdt_reset();  
  pinMode (MOSFET, OUTPUT);
  ADCSRA = 0;            // turn off ADC
  power_all_disable ();  // power off ADC, Timer 0 and 1, serial interface
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  }  // end of setup

void loop ()
  {
  counter++;
  
  if (counter >= SLEEPS_TO_WAIT)
    {
    digitalWrite (MOSFET, HIGH);
    delayMicroseconds (10000); 
    digitalWrite (MOSFET, LOW);
    // our job here is done
    sleep_enable ();       // ready to sleep
    sleep_cpu ();          // sleep                
    }
  
  goToSleep ();
  }  // end of loop
  
void goToSleep ()
  {
  noInterrupts ();       // timed sequence coming up
  // pat the dog
  wdt_reset();  
  
  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset, clear existing interrupt
  watchdogRegister = bit (WDCE) | bit (WDE) | bit (WDIF);
  // set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
  watchdogRegister = bit (WDIE) | bit (WDP3) | bit (WDP0);    // set WDIE, and 8 seconds delay
  
  sleep_enable ();       // ready to sleep
  interrupts ();         // interrupts are required now
  sleep_cpu ();          // sleep                
  sleep_disable ();      // precaution
  }  // end of goToSleep 


The 2N7000 has a maximum VDS rating of 60V, so it can handle a higher voltage on the drain than the ATtiny85 is operating on.



Data receiving sketch


To test all this out I used a second NRF24L01 transceiver, connected to a Uno, located inside the house. This time since a power-point was available nearby I didn't worry about power saving.

I connected up a 8-digit LED readout as described here: http://www.gammon.com.au/forum/?id=11516&reply=5#reply5

That uses a library I wrote to simplify communicating with the LED board (mentioned on that page).


// Program to receive a reading from a NRF24L01
// Author: Nick Gammon
// Date: 15th March 2015

#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include <bitBangedSPI.h>
#include <MAX7219.h>

//
// Hardware configuration
//

/*

NRF24L01     Uno
----------   ----------------

  VCC         --> 3.3V pin
  Gnd         Gnd
  CSN         D10 (SS) 
  CE          D9
  MOSI        D11 (MOSI) 
  SCK         D13 (SCK)
  IRQ         N/C
  MISO        D12 (MISO)

MAX7219        Uno
----------     ----------------

 VCC            +5V
 Gnd            Gnd
 MAX7219 LOAD   D6  (/CS) line (active low)
 MAX7219 DIN    D7  (data in)
 MAX7219 CLK    D8  (clock)
 
*/

// Set up nRF24L01 radio on SPI bus plus pins 9 & 10

RF24 radio (9, 10);

// 1 chip, bit banged SPI on pins 6, 7, 8
MAX7219 display (1, 6, 7, 8);  // Chips / LOAD / DIN / CLK

//
// Topology
//

// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };


void setup(void)
  {

  //
  // Print preamble
  //

  Serial.begin(115200);
  Serial.println ("RF24 receiver - now with voltages!.");

  //
  // Setup and configure rf radio
  //

  radio.begin();

  // optionally, increase the delay between retries & # of retries
  radio.setRetries(15,15);

  // optionally, reduce the payload size.  seems to
  // improve reliability
  radio.setPayloadSize(8);

  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1,pipes[0]);
  
  //
  // Start listening
  //

  radio.startListening();

  //
  // Dump the configuration of the rf unit for debugging
  //

  radio.printDetails();
  
  display.begin ();
  display.sendString ("StArt");

  }  // end of setup

const float InternalReferenceVoltage = 1.086; // as measured
unsigned long lastReading;
unsigned int counter;

void loop(void)
  {
    // if there is data ready
  if ( radio.available() )
    {
      // Dump the payloads until we've gotten everything
      unsigned int voltage;
      bool done = false;
      while (!done)
      {
        // Fetch the payload, and see if this was the last one.
        done = radio.read( &voltage, sizeof voltage );
        counter++;
        if (counter > 9999)
          counter = 0;
        
        float results = InternalReferenceVoltage / float (voltage + 0.5) * 1024.0; 
        int elapsedTime = (millis () - lastReading) / 1000;
        Serial.print (counter);
        Serial.print (". ");
        Serial.print ("Reading = ");
        Serial.print (voltage);
        Serial.print (", Voltage = ");
        Serial.print (results);  
        Serial.print (" - elapsed time: ");
        Serial.println (elapsedTime);
        lastReading = millis ();

        char voltageBuf [8];
        dtostrf (results, 4, 2, voltageBuf);  // number, width, decimal places, buffer 
        char buf [9];
        sprintf (buf, "%3s %4i", voltageBuf, counter);
         
        display.sendString (buf);

      }  // end reading the payload
    }  // end of data available
  }  // end of loop


Receiver in operation, showing 5.00V and 7715 readings received so far:



Finished transmitter:



(Some parts on the "bare bones" board are not used in this project).

Range


Most of my testing was carried out with the transmitter quite close (about 3m away). For further testing I checked at 20m (seemed to work OK) and 30m (worked marginally). This was also going through the brick walls of the house, which would have dropped the range a bit.

Conditioning the capacitor


Super-capacitors apparently improve their energy retention by being "conditioned", that is being charged up and left charged for a few days. If you build up this project and find that it does not perform as well as expected, let it run for a few days to condition the capacitor. Alternatively, pre-charge the capacitor on a 5V supply and leave it there for a few days.

According to Jim Remington from the Arduino Forum, he initially measured a self-discharge rate of 23 µA with a new super-capacitor, dropping to 4.3 µA after an overnight charge of 5V. Other web pages I have seen suggest that a few days of charging may give even better results.

Charging time


The time to charge a capacitor is given as:


A = F * dV/ds

Rearranged to be:

A / F = dV/ds

The solar panel nominally supplies 1W at 6V (ie. around 160 mA) so we have:

0.160 A / 0.47 F = 340 mv / second

So for the capacitor to reach 5V it will take:

5 / 0.340 = 14.7 seconds


This sounds fast to me, but the formula seems to be backed up here.

They expressed the formula in a different way:


s = (F * V) / A

s = (0.47 * 5) / 0.160 = 14.6875 seconds


So (somewhat unbelievably) the capacitor can charge up in 15 seconds, given ideal conditions. This would appear to suggest that using a larger capacitor could be warranted, if we wanted to power more devices.

Conclusion


This all worked pretty well. Recent testing shows that the voltage is down to around 4.5V in the early evening, dropping to around 4V the next morning, and dropping still further to about 3.5V until the sun comes up and hits the solar panel.

You could, of course, vary the design considerably. For example:


  • Use a larger capacitor, to handle longer evenings, or to have more power to hand, for example to operate a door or camera.
  • Record to an SD card instead of transmitting data
  • Transmit using a mobile phone instead of a transceiver board. This could considerably extend the range of the device.
  • Send readings more, or less, frequently.
  • Send other readings, such as temperature, humidity, barometric pressure, soil moisture, etc.
  • Mount the whole thing on a custom circuit board, put it in a waterproof box, and have the solar panel on the lid. It could probably be made quite small.


I found that it charged quite quickly once the sun came up, particularly if hit by direct sunlight. Even under shade, it still operates fine, easily charging by around 10 a.m.

Solar power calculator


Using a small Lua script we can calculate the running time given a few parameters (change the first few lines) about the capacitance to hand, the expected start and end voltage, and the average current consumption.


-- Solar panel consumption calculator

-- See: http://www.gammon.com.au/forum/?id=12821
--      http://en.wikipedia.org/wiki/Coulomb
--      http://en.wikipedia.org/wiki/Joule
--      http://en.wikipedia.org/wiki/Watt

-- put in your parameters here ...

capacitance   = 0.47  -- in farads, eg. 47e-6 for 47 µF
startVoltage  = 4.5   -- in volts
endVoltage    = 2.0   -- in volts
current       = 10e-6 -- in amps, eg 10e-6 for 10 µA, 10e-3 for 10 mA


averageVoltage = (startVoltage + endVoltage) / 2
averagePower = current * averageVoltage  -- watts

startJoules = 0.5 * capacitance * startVoltage^2
endJoules =  0.5 * capacitance * endVoltage^2
usedJoules = startJoules - endJoules
seconds = usedJoules / averagePower

print (string.format ("Start with 0.5 * %0.3f F * %0.3f^2 V = %0.3f Joules",
       capacitance, startVoltage, startJoules))

print (string.format ("End   with 0.5 * %0.3f F * %0.3f^2 V = %0.3f Joules",
       capacitance, endVoltage, endJoules))

print (string.format ("Used           = %0.3f J - %0.3f J   = %0.3f Joules",
       startJoules, endJoules, usedJoules))

print (string.format ("Average voltage = %0.3f V", averageVoltage))
print (string.format ("Average power   = %0.9f W (%0.3f mW, %0.0f µW) ", averagePower, averagePower * 1e3, averagePower * 1e6))
print (string.format ("Running time    = %0.f s (%0.1f minutes, %0.3f hours)", seconds, seconds / 60, seconds / (60 * 60)))


Output:


Start with 0.5 * 0.470 F * 4.500^2 V = 4.759 Joules 
End   with 0.5 * 0.470 F * 2.000^2 V = 0.940 Joules 
Used           = 4.759 J - 0.940 J   = 3.819 Joules 
Average voltage = 3.250 V 
Average power   = 0.000032500 W (0.033 mW, 33 µW)  
Running time    = 117500 s (1958.3 minutes, 32.639 hours) 





[EDIT] Amended formula for energy in capacitor from FV2 to be (1/2)FV2.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Reply #1 on Fri 16 Feb 2018 02:24 AM (UTC)
Message
Tom Boyd has written a lengthy page about implementing the ideas shown above.

Tom has developed a printed-circuit board designed to implement the capacitor-based solar-powered system. Read it for more details!

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


69,889 views.

Postings by administrators only.

Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.