Water Salinity-meter
Hello,
In this Instructable we will explain in detail how to build a water salinity-meter. This was a project for the minor Delta Expert at the Delft University of Technology. It is a relatively low cost and easy sensor to build. We made it to look nice, but it can be done in any other way, as long as the circuit and code are the same.
The sensor works by measuring the resistance between two electrodes. It also measures temperature to compensate for temperature changed resistance.
Good luck on this adventure!
Supplies
- Arduino Uno (Any brand will do)
- Breadboard, welding clamps or perfboard
- (Jumper) cables
- Three resistors (10k Ohm, 1k Ohm and 4.7k Ohm)
- Temperature sensor (for example DS18B20 waterproof)
- Two copper electrodes (like nails or pins)
- Button
- LCD display for Arduino (for example I2C)
- Soldering
- Hot glue gun
- Laptop for coding
Optional:
- Powerbank for use without laptop
The Resistivity Sensor
The first step in making the salinometer is the wiring. There are 4 seperate parts to the sensor; the resistivity sensor, the thermometer, the button and the display.
Wiring
Let's start with the resistivity sensor. For this we need the following:
- Two electrodes
- 1k Ohm resistor
- (Jumper) cables
- Arduino UNO
- Breadboard / welding camps / perfboard and soldering equipment
Since the aim is to measure seawater, we want to avoid electrolysis which makes the electrodes oxidize and that in turn will make the resistance increase rapidly over the first second of the measurement. To avoid electrolysis we put an AC current over the electrodes. Since an Arduino is DC we have to use a trick to make something that is close to AC; we use two digital pins between which we rapidly switch around the polarity. A HIGH pin will be the positive and a LOW pin will be the negative.
See the schematic for the wiring. Note that we use a "known" resistance which is being used to measure the "unknown" resistance of the water.
Coding
We use a relatively simple code to measure the resistivity. It consists of two parts. One part switches around the polarity and the other takes a measurement when the 8-pin is HIGH and the 7-pin is LOW.
The code for the sensor alone to work is below. This can be used to test if it is working.
Tip: Use a known resistor on the electrodes to see if the values from the serial monitor are correct
int analogPin = 0; int dtime = 500; int raw = 0; int Vin = 5; float Vout = 0; float R1 = 1000; float R2 = 0; float buff = 0; float avg = 0; int samples = 5000; void setup(){ pinMode(8,OUTPUT); // define ports 8 and 7 for AC pinMode(7,OUTPUT); Serial.begin(9600); // start serial } void loop(){ float tot = 0; for (int i =0; i<samples; i++) { digitalWrite(7,HIGH); digitalWrite(8,LOW); delayMicroseconds(dtime); digitalWrite(7,LOW); digitalWrite(8,HIGH); delayMicroseconds(dtime); raw = analogRead(analogPin); if(raw){ buff = raw * Vin; Vout = (buff)/1024.0; buff = (Vin/Vout) - 1; R2= R1 * buff; //Serial.print("Vout: "); //Serial.println(Vout); //Serial.print("R2: "); //Serial.println(R2); tot = tot + R2; } } avg = tot/samples; Serial.print("The average resistance is: "); Serial.print(avg); Serial.println(" Ohm"); }<br>
Wiring the Button
Now to we add a button to start a measurement. We need the following components:
- Button
- 10k Ohm resistor
- (Jumper) cables
The wiring is above.
Adding the Thermometer
For this example the DS18B20 waterproof digital thermometer was used. Any other thermometer can be used, but in this guide only the wiring for the DS18B20 will be provided.
Required components:
- Thermometer
- 4.7k Ohm resistor(or any other if specified by other manufacturer)
- (Jumper) cables
The wiring is above.
LCD Display
Finally we add the LCD display. We used the I2C display, which only has 4 pins. In this guide only the wiring for that display will be shown(Please note that in the schematic another LCD display was used. This is only for visuals).
Required components:
- LCD display
- (Jumper) cables
The wiring is shown above.
Coding
We already showed a bit of code after the wiring of the resistance sensor to find out if everything was working. Now we will add the full code to work with the entire sensor.
#include <Wire.h> //These two libraries are for the LCD #include <LiquidCrystal_I2C.h> #include <OneWire.h> //These two libraries are for the temp sensor #include <DallasTemperature.h> //Data wire from thermometer is plugged into digital pin 12 on the Arduino #define ONE_WIRE_BUS 12 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); LiquidCrystal_I2C lcd(0x27, 16, 2); int analogPin = 0; int dtime = 500; int raw = 0; int Vin = 5; float Vout = 0; float R1 = 1000; float R2 = 0; float buff = 0; float avg = 0; int samples = 5000; int state = 0; int button = 0; int buttonPin = 5; float CalibrationTemp = 21.0; //This is the temperature from which calibration is done. Change if needed float CorrectionFactor = 1.02; //Correction factor found by us. Change if needed float dTemp = 0; //Initial value for temperature difference //State 0 = rest //State 1 = measure //State 2 = print void setup(){ sensors.begin(); // start up temperature library pinMode(8,OUTPUT); // define ports 8 and 7 for AC pinMode(7,OUTPUT); pinMode(12,INPUT); //Setup the thermometerpin as input pinMode(buttonPin,INPUT); //Setup buttonpin as input Serial.begin(9600); // start serial lcd.begin(); //start up LCD lcd.clear(); //clear LCD memory } void loop(){ //REST button = digitalRead(buttonPin); if (button == HIGH) { //Check is the button is pressed and go to another state to start measuring lcd.clear(); lcd.setCursor(4,0); lcd.print("Starting"); lcd.setCursor(2,1); lcd.print("measurement"); state = 1; } //MEASURE if (state == 1) { float tot = 0; for (int i =0; i<samples; i++) { digitalWrite(7,HIGH); digitalWrite(8,LOW); delayMicroseconds(dtime); digitalWrite(7,LOW); digitalWrite(8,HIGH); delayMicroseconds(dtime); raw = analogRead(analogPin); if(raw){ buff = raw * Vin; Vout = (buff)/1024.0; buff = (Vin/Vout) - 1; R2= R1 * buff; //Serial.print("Vout: "); //Serial.println(Vout); //Serial.print("R2: "); //Serial.println(R2); tot = tot + R2; } } avg = tot/samples; Serial.print("Average resistance is: "); Serial.print(avg); Serial.println(" Ohm"); state = 2; // Send the command to get temperatures sensors.requestTemperatures(); float temp = sensors.getTempCByIndex(0); //print the temperature in Celsius Serial.print("Temperature: "); Serial.print(temp); Serial.print("C | "); dTemp = temp - CalibrationTemp; avg = avg * pow(CorrectionFactor, dTemp); Serial.print("Corrected resistance is: " + String(avg)); } //PRINT if (state == 2) { //Here the value found is printed and the values for different sorts of water are defined if (avg > 2000) { Serial.println("This is demineralised water."); lcd.clear(); lcd.setCursor(1,0); lcd.print("Demi water"); lcd.setCursor(1,1); lcd.print("AVG: " + String(avg)); delay(1000); state = 0; } else if (avg > 1000) { Serial.println("This is fresh/tap water."); lcd.clear(); lcd.setCursor(1,0); lcd.print("Tap water"); lcd.setCursor(1,1); lcd.print("AVG: " + String(avg)); delay(1000); state = 0; } else if (avg > 190) { Serial.println("This is brackish water."); lcd.clear(); lcd.setCursor(1,0); lcd.print("Brackish water"); lcd.setCursor(1,1); lcd.print("AVG: " + String(avg)); delay(1000); state = 0; } else if (avg < 190) { Serial.println("This is seawater."); lcd.clear(); lcd.setCursor(1,0); lcd.print("Sea water"); lcd.setCursor(1,1); lcd.print("AVG: " + String(avg)); delay(1000); state = 0; } } }<br>
Calibrating
Since the measured resistivity could not immediately give the salinity level of the water, it is required to calibrate the sensor. The very first important step in this process is to have the electrodes at a fixed distance from eachother. The measured resistance will change when the distance between the electrodes changes.
Calibrating was done by taking multiple samples of demineralised water and adding different amounts of salt to them. The resistance was measured. The process was fairly easy, but is necessary to have a working sensor which can also say something about the salinity
The temperature might also need calibrating. Our sensor was already calibrated, so will not discuss calibrating the thermometer in this guide.
Calibrating the correction factor is a bit more work. The correction factor generally lies between 2-4% change in resistance for each degree temperature change. This is however not always correct. The method to find the correction factor is by taking a sample of water and changing the temperature while measuring the resistance. The easiest way to do this is by taking hot water and measuring the resistance while it cools down. From this data a correction factor can be computed. You know your correction factor is correct when the "Corrected resistance" does not change while the water cools down.
Housing and Finishing
Since this sensor will be used in water, it is important to shield all electrical components from the water. For this sensor we built three seperate housings; for the electrodes, for the Arduino and wiring and for the LCD display with the button.
The electrodes were put in a black plastic casing with two holes in the front and one in the back. A hot glue gun was used to make everything waterproof. As said in previous step, it is very important to have the electrodes at a fixed distance from eachother. Make sure they are tighly glued or fixed in place.
The Arduino and wiring were put in a protective box for plugs. This was an exact fit and waterproof at once. You might find something else like this, but for us this was perfect. From one side the power cable could be let in and from the other side the electrodes and thermometer cables could be let out.
The LCD and button were put in a case made for the LCD display we conviently had lying around.
With some hot glue everything was "neatly" put together and made into one sensor.
P.S. Any of these housings could of course also be self-designed and manufactured(3D printed).