Arduino Rain Gauge Calibration

49K5577

Intro: Arduino Rain Gauge Calibration

Introduction:

In this Instructable we 'construct' a rain gauge with Arduino and calibrate it to report daily and hourly rainfall. The rain collector I am using is a re-purposed rain gauge of the tipping bucket type. It came from a damaged personal weather station. However there are a lot of great Instructables on how to make one from scratch.

This Instructable is a part of a weather station I am making and is a documentation of my learning process disguised as a tutorial:)

Characteristics of the Rain Gauge:

  • measurements of daily and hourly rainfall is in inches for easy upload to Weather Underground.
  • debouncing code for the magnetic switch is not included to keep the code simple.
  • being more of a tutorial the finished product is more of a prototype of a prototype.

STEP 1: Some Theory

Rainfall is reported/measured in millimeters or inches which has the dimension of length. It is indicative of how high, every portion of rain area got the rain, if the rain water had not dissipated and drained away. So, a 1.63 mm of rainfall would mean that if I had a flat leveled tank of any shape the rain water collected would be of a height 1.63 mm from the tanks bottom.

All rain gauges have a rainfall catchment area and a rainfall amount measurement. The catchment area is the region over which the rain is collected. The measuring object would be some kind of volume measurement for a liquid.

So the rainfall in mm or inches would be

rainfall height = volume of rain collected / catchment area

In my rain collector, the length and breadth were 11 cm by 5 cm respectively giving a catchment area of 55 sq.cm. So a collection of 9 milliliters of rain would mean 9 cc/55 sq.cm = 0.16363... cm = 1.6363... mm = 0.064 inches.

In the tipping bucket rain gauge, the bucket tips 4 times for 9 ml (or 0.064... inches of rain) and so a single tip is for (9/4) ml = 2.25ml (or 0.0161.. inches). If we take hourly readings (24 readings per day before resets) keeping three significant digit accuracy is decent enough.

Thus, at each bucket tip/tumble, the code accesses it as 1 on-off-on sequence or one click. Yes, we have reported 0.0161 inches of rain. To repeat, from the Arduino point of view

one click = 0.0161 inches of rain

Note 1: I prefer the International System of Units, but Weather Underground prefers the Imperial/US units and so this conversion into inches.

Note 2: If calculations are not your cup of tea, head over to Volume of Rainfall which provides perfect help for such matters.

STEP 2: Parts for This Project

Most of the parts were lying around and a fair listing (for formality) is

  1. Arduino Uno (or any other compatible)
  2. Rain Gauge from old damaged weather station.
  3. Breadboard.
  4. RJ11 to connect my Rain Gauge to the breadboard.
  5. 10K or higher resistor to act as a pull up resistor. I have used 15K.
  6. 2 pieces of male-to-female jumper wires
  7. 2 male-to-male jumper wire.
  8. USB Cable; A Male to B Male

Tools:

  • Syringe (12 ml capacity was used).

STEP 3: The Rain Collector

The photos of my rain collector should make thing clear to many. Anyway, the rain that falls on its catchment area gets channeled to one of the two tipping-buckets inside it. The two tipping-buckets are connected like a see-saw and as the rain water weight ( 0.0161 inches of rain for mine ) tips one bucket down it gets emptied and the other buckets goes up and positions itself to collect the next rain water. The tipping motion moves a magnet over a 'magnetic-switch' and the circuit gets electrically connected.

STEP 4: Circuit

To make the circuit

  1. Connect digital pin #2 of Arduino to one end of the resistor.
  2. Connect the other end of the resistor to the Ground pin (GND).
  3. Connect one end of the RJ11 jack to the digital pin #2 of Arduino.
  4. Connect the other end of the RJ11 jack to the +5V pin of Arduino (5V).
  5. Plug the rain gauge to the RJ11.

The circuit is complete. Jumper wires and breadboard make the connections easier to make.

To complete the project connect the Arduino to the PC using the USB cable and load the sketch provided below.

STEP 5: The Code

The sketch RainGauge.ino (embedded at the end of this step) is well commented and so I shall point out three sections only.

One part counts the number of tipping-bucket tips.

if(bucketPositionA==false && digitalRead(RainPin) == HIGH){
	...
	...
}

Another part checks time and computes the rain amount

if(now.minute()==0 && first == true){
	hourlyRain = dailyRain - dailyRain_till_LastHour;
	......
	......

and another part clears the rain for the day, at midnight.

if(now.hour() == 0){
	dailyRain = 0;
	.....

STEP 6: Calibration & Testing

Disconnect the Rain Collector from the rest of the circuit and perform the following steps.

  1. Fill up the syringe with water. I fill mine with 10 ml.
  2. Keep the Rain Collector on a level surface and pour out the water from the syringe bit by bit.
  3. I keep a count of the tipping buckets. Four tips were enough for me, and drained 9 ml from the syringe. According to calculations (see theory section) I got the amount of 0.0161 inches of rain per tip.
  4. I include this information into my code in the beginning.
const double bucketAmount = 0.0161;

That's all to it. For more accuracy, one can include more digits like 0.01610595. Of course your calculated numbers are expected to vary if your Rain Collector is not identical to mine.

For testing purposes

  1. Connect the Rain Collector to the RJ11 socket.
  2. Connect the Arduino to the PC using the USB cable.
  3. Open the serial monitor.
  4. Pour previously measured amounts of water and observe the output when the hour completes.
  5. Do not pour any water but wait for the next hour to complete. The hourly rain must be zero in this case.
  6. Keep the PC with the connected circuit powered overnight and see if the daily rain and hourly rain get reset to zero at midnight. For this step, one can also change the PC's clock to a suitable value (to watch the outputs on the serial monitor live).

STEP 7: Afterthoughts & Acknowledgements

The resolution of the rainfall readings in my case is 0.0161 inches and cannot be made more accurate. Practical circumstances may decrease the accuracy further. Weather measurements do not have the accuracy of quantum mechanics.

Part of the code was borrowed from Lazy Old Geek's Instructable.

54 Comments


Calibrating with only 4 bucket tips will allow a huge error possibility. On the order of 25% of the actual measurement. I would want maybe 100 tips, give or take. Then my max calibration error is 1% of the per-tip measurement.


Think about it this way. How much water might be left in the last bucket, uncounted?  Well, JUST less than the amount it tips for. I haven't read anyone's calibration procedure yet that takes this into account. But the solution in general is to calibrate over a lot more counts.


Also if there is any variation in the per-count measurement of the tipping bucket, more counts will average that out.

From the photos in this project, it's clear it uses the same Misol Electric tipping bucket sensor available from the manufacturer through Amazon for around $25. It also shows up occasionally from other internet suppliers, at varying prices. Either Misol is the original manufacturer, or perhaps as a Chinese supplier, they've just duplicated someone else's design. Misol supplies no specs for it. The occasional other suppliers who do offer a spec seldom agree. I found it, and it is an attractive package. I'm confident my tests should be applicable to this project. And the principles are worthwhile for calibrating any rain sensor.

TL;DR: My best calibration estimate is a rainfall equivalent of .0136 in/bucket or .345 mm/bucket. (But I have doubts about the sensor's accuracy.)

That's based on pouring a carefully measured 32 oz of water through the sensor, and getting a detected count of 254 bucket tips from a Raspberry Pi Zero W with 200 ms debounce on the I/O pin used. The interface was setup in Python using the RPi.GPIO library. (And a shout-out to ChatGPT and Copilot for helping me write and debug the code quickly without being experienced at Python! It helped me put the rain sensor routine into an interrupt driven background thread to minimize response latency. And to write data to the same SQLite DB in both that background thread, and a foreground thread that polls a temp/humidity sensor every 5 min and records that to the same DB. Ultimately I'll expand the foreground thread to interface with a web UI and to control a relay to the rain sensor input on my lawn sprinkler controller.) 

At 254 tips, this should pretty effectively average out any random variation, as well as eliminate any significant error from a partial bucket left unmeasured at the last. (Notably though, it won't eliminate a systematic variation.)

But from later findings, I have little confidence in this sensor now. I'll explain later. First my procedure:


Carefully measuring the inside top cross-section of the funnel, I get 10.9 x 4.97 cm, which multiplies to 54.173 cm squared. Seeing that the corners are chamfered is a good argument to round that down to 54.0 cm squared area. I carefully filled a 32 oz measure with water to meter through the sensor. And I carefully leveled the sensor.

After a first run through to test procedure, I decided the safest approach is to pour that volume slowly, using a large-ish syringe. This avoids spillage, and helps maintain a slow flow rate. Experiment strongly suggests it's possible to exceed the device's ability to accurately measure.

As noted, I got 254 tips counted. So take that 254 bucket tips, and 32 oz volume, convert units, and you get 1.863 ml/bucket. Apply the 54 cm squared funnel catch area with 1.863 cc volume, and you get .345 mm or .0136 inches equivalent rainfall. And based on the times logged for the first and last bucket tips, I work this test out to a rainfall rate of 10.2 inches per hour. ChatGPT tells me the fastest rainfall on record recorded 12 inches in 42 minutes, for a rate of 17 inches/hour. (If ChatGPT isn't hallucinating. But this doesn't matter enough to fact-check it.) So if the sensor is reasonably accurate up to around 10 in/hr that's not bad.

So far so good. But this is the end of good.


My first rough calibration counted only 172 tips, which equates to .0201 in or 3.45 mm rainfall. On that attempt, I just poured directly from the measure into the funnel. I quickly realized it's easy to back up the funnel, due to its tiny opening. At that rate, the bucket tips at most around once per second. But the question is: Is that the maximum flow rate of the opening, or the maximum rate the bucket can tip back and forth? If the latter, then water is overflowing the bucket.

Give that my slow test counted 82 more tips, it's a good bet the buckets overflow. So after my slow test using the syringe, I did a third test, pouring fast enough to always keep the funnel backed up and never stop. That test counted only 167 tips. So this is pretty compelling evidence that the faster you pour through the funnel, the more water gets lost uncounted. 254, 172, and 167 tips, from slowest to fastest. .Now, the fastest test only took 1:13 min, for an equivalent rain rate of 170 in/hr. So that's far beyond anything the sensor will ever encounter in real life. But it demonstrates the bucket's capacity is the limiting factor. Slow flow is a requirement.

Ultimately I would need to repeat my slow calibration tests, attempt to get some kind of measurable control and consistency over my flow rate, and prove what the maximum rate is and whether my best calibration so far is the most accurate. But I don't have any flow meters and valves to be truly scientific.


However one last observation makes me despair that this gauge may never be very accurate. 

I removed the funnel top to expose the tipping bucket mechanism (as shown in the photos with this project). With the base still held level, I poured water from the syringe into first one side and then the other to watch it tip. The concerning discovery is that each tip leaves a SUBSTANTIAL blob of water that never pours out! The bucket is definitely tilted downward, but apparently there is surface tension attraction that makes a blob try to "stick". So not all the water drains out ordinarily.

Unless this happens very consistently on every tip, at all times and conditions, then this could be a big problem for accuracy. More so on small rainfalls than large. OTOH, if it is consistent enough, then it might average itself out and end as just part of an insignificant remaining last partial bucket. Repetition and statistics could shed light on that possibility. In the unlikely chance that I have the patience . . .

If I install an Adafruit datalogging/RTC shield will the program work without modification and show the real time? I have the RTC library installed.

Hello sir,
From where can i get or buy the RJ11 connector?
Buenas Noches Estoy haciendo mi proyecto de una estacion climatologica pero como puedo implementar ese codigo en una placa de desarrollo esp8266
Hello Sir,

I want the calculations to be shown every 1 minute. How can I do that?
Hello,

Thanks for the help. I am trying to simulate this on Proteus before implementing this in real life for school project. However, I am stuck.
In the image you can see, I have connect the rain gauge to Digital Pin #2 of Arduino.

But I am not getting any reading. Can you please help?
My tipping rain bucket seems to generate ticks when its not raining. Mounted level etc, but registers 5 to 10 times on dry days. Cable is about 10m long, not sure if that might cause it? Some weak correlation to wind but not strong and sometimes happen with no wind. Not sure if I should look for mechanical or electrical problem
You may have an electric disturbance from other nearby equipment. A small ceramic MLC capacitor of about 0.1 uF both across the reed switch and parallel connection on the circuit board may help. Avoid running the wire alongside any power cables and if you must cross over, do so orthogonally (perpendicular) to the other cable.
I am seeing the same problem.... What was your solution??
As for denouncing, a simple IC chip with Schmidt Trigger inverters will help when used in conjunction with a small RC passive filter. You'd have to experiment a little with RC values.
Excellent work! I had to install it for a client and you saved me! By any chance, did you also work with the other parts of the kit: the wind vane and the anemometer? I can see 4 wires from the RJ11 but not sure how to plug them.
Thanks again
Thank you for your instruction!

Some supplements:
You need to install the adafruit RTCLib library via arduino library manager (https://www.arduino.cc/en/guide/libraries) or manually (https://github.com/adafruit/RTClib) to compile the code. Alternatively you could use a (real) real time clock module. This is a bit more difficult. Perhaps you could add this important "library"-step in your instructable.

You could also add an other resistor (100 Ohm) in series to the reed switch to give it a longer life.
I posted a question, but I deleted it since I figured out the solution, so this post will make more sense. Here it goes, my rain bucket has the same dimension as the example posted here: 11cm by 5cm = 55 sq cm, and 10 ml give me 6 tips or clicks, so 10/55 = (0.1818 sq cm X 10 = 1.8181ml), convert it to inches(1.8181ml/25.4) I get 0.0715 inches, these inches divided by 6 ( 0.0715/6) the result is: 0.0119 inches of rain per tip/click, am I right?

The solution was found after analyzing DanB339 post.

By the way, I adapted your code to the Particle Photon environment, the code works just fine.

Thanks a lot , and keep up the good hobbies.

Here are a couple pictures showing the entire Personal Weather Station (PWS) that's also feeding weather data to Wunderground.
Hello, my rain gauge is 19.1 ml in 12 buckets. How can I calculate this in square meters? I would be glad if you could help.
Awesome to see your solar powered weather station and thank you for your kind words.
Your 0.0119 inches of rain per tip/click is correct. Yet it is different from my 0.0161 inches/click. We are differing by about 26%. This has come from the fact you got 6 tips for 10 ml while I got 4 tips for 9 ml. Not same. So I have to make sure that my 4 tips for 9 ml is correct or not. Sadly, I do not have the rain collector anymore. However all this has pointed that we need to repeat our calibration observations with great great care. One way would be to use more liquid and observe for more bucket tips.

Your query has made me a wiser person, thank you.
Hello, great piece of code and reusing old parts.
How would I change this code to get 10 minute totals.
Also what is the 5v used for as mine works with just a ground and pin 2?

Thanks again.
Brad
"Also what is the 5v used for as mine works with just a ground and pin 2?"

- When the magnetic switch is connected, it is "sure to read" 5 volts.
(https://www.instructables.com/id/How-to-use-a-Push...)

Below is the code to watch the rain in 10 minute intervals (Not tested, only compiled).
---------------------------------------------------------------------------------------------------------------

/*
description: Basic Rain Gauge with arduino with serial monitoring
Reports the daily-rain and rain-in-last-1o-minutes in inches
acknowledgement: part of the code copied and modified from
https://www.instructables.com/id/Arduino-Weather-S...
liscence: GNU GPL. https://www.gnu.org/licenses/gpl.html
*/

#include "RTClib.h"
#include <Wire.h>
#define RainPin 2 // The Rain input is connected to digital pin 2 on the arduino


bool bucketPositionA = false; // one of the two positions of tipping-bucket
const double bucketAmount = 0.01610595; // inches equivalent of ml to trip tipping-bucket
double dailyRain = 0.0; // rain accumulated for the day
double rain_Last_10_mins = 0.0;
double dailyRain_till_Last_10_mins = 0.0;

RTC_Millis rtc; // software RTC time


void setup(void) {
Serial.begin(9600); // start the serial port at 9600 bauds
rtc.begin(DateTime(__DATE__, __TIME__)); // start the RTC
pinMode(RainPin, INPUT); // set the Rain Pin as input.
delay(4000); // i'm slow in starting the seiral monitor (not necessary)
Serial.println("Ready!!!"); // not necessary too
}


void loop(void){
DateTime now = rtc.now();

// ++++++++++++++++++++++++ Count the bucket tips ++++++++++++++++++++++++++++++++
if ((bucketPositionA==false)&&(digitalRead(RainPin)==HIGH)){
bucketPositionA=true;
dailyRain+=bucketAmount; // update the daily rain
}

if ((bucketPositionA==true)&&(digitalRead(RainPin)==LOW)){
bucketPositionA=false;
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

if(now.second()== 0 && now.minute()%10==0){ // execute only in 10 minute intervals

rain_Last_10_mins = dailyRain - dailyRain_till_Last_10_mins; // calculate the last 10 minutes rain
dailyRain_till_Last_10_mins = dailyRain; // record the last 10 minutes rain for next calculation

// fancy display for humans to comprehend
Serial.println();
Serial.print(now.hour());
Serial.print(":");
Serial.print(now.minute());
Serial.print(": Total Rain for the day = ");
Serial.print(dailyRain,8); // the '8' ensures the required accuracy
Serial.println(" inches");
Serial.println();
Serial.print(" : Rain in last 10 minutes = ");
Serial.print(rain_Last_10_mins,8);
Serial.println(" inches");
Serial.println();
}

if(now.hour()== 0) {
dailyRain = 0.0; // clear daily-rain at midnight
rain_Last_10_mins = 0.0; // we do not want negative rain at 00:10
}
} // end of loop
Hi, Abhijit Borah! Thanks for this, I'll be able to use this code for our project.
But "Rain in last 10 minutes" is always 0 and the values every 10 mins just adds up into "Total Rain for the day". Can you help me to determine where the problem is? Thank you!!!
Thanks Abhijit. That works fine.
I would like to input this into asksensors through my ethernet hat. Is this something you have looked at?
More Comments