Salinity Measurementswith an Arduino
ME 121Mechanical and Materials Engineering
Portland State University
Goals of this presentation areReview operation of the salinity sensor
• Motivate need for turning power on and off• Location of sensor in the voltage divider circuit
Create functions for averaging sensor input• Encapsulate code for re-use with different sensors• Keep main loop code more compact
Salinity measurementPrinciples of operation• Ions migrate to the electrodes
having the opposite charge• Ions exchange electrons at the
probes, which causes current flow• Ion concentrations increase over
time while power is on• Turn power on only during brief
measurement period to prevent ion build-up on probes
!"!
"#!!
!"!
$%!&'!
!"!
#$"!#$!
#$!
#$%!
#$"!
!" !
#$"!! "!
!"!
&'"!
'%&!
'%&!&'"!
'!
'!!"!
!"!
()*+,!-!*./+(0*)!!"#$$%#&%'"'()*#+$,!
1(23*+,!-!4,+510*)!!-./+%#&%'"'()*#+$,!
#$"!
#$"!
#$"!
#$"!
()*!
()*!
()*!
()*!()*!
()*!#$"!
#$"!
#$"!
#$"!
()*!()*!
()*!
()*!
()*!
#$"!
/*)!6/74(0*)!!
()*!8(9!/:!(!:;,12(2*4!/*)!!
Salinity measurement with voltage divider
Sensor circuit is a voltage divider• Arduino cannot measure resistance
directly.• Use a voltage divider to measure
change in voltage due to change in resistance
• Sensor resistance decreases as salt concentration increases
• Measure voltage across the fixed resistor – Why?
salinty sensor(variable resistance)
10 kΩ
Analog input
Digital output
Study questionsHow does analog input value vary when …• Electrical resistance of water decreases?• Electrical resistance of water becomes very large?
If the resistance of the sensor varied linearly with salinity, would the analog input reading (voltage) also vary linearly with salinity?
salinty sensor(variable resistance)
10 kΩ
Analog input
Digital output
!"#$ = !&'()
(* + ()R2 is the fixed (10 kΩ) resistor
R1
R2
Programs for reading the salinity sensorRead one value at a time
• Encapsulate in a function so it can be reused
Read multiple values and return the average• Keep averaging calculations in the function
Both Arduino codes use the same circuit
Outline of salinity measurement codeAlgorithm
1. Turn on 5V power with digital output pin2. Wait for initial voltage transient to settle3. Read voltage across fixed resistor4. Turn off the power
salinty sensor(variable resistance)
10 kΩ
Analog input
Digital output
Single reading of salinity sensor
salinty sensor(variable resistance)
10 kΩ
Analog input
Digital output
int salinity_power_pin = 4; // Digital I/O pin, Global variable
void setup() {Serial.begin(9600);pinMode(salinity_power_pin, OUTPUT);
}
void loop() {
int salinity_input_pin = A2;int reading;
digitalWrite(salinity_power_pin, HIGH); // Turn on sensordelay(100); // Wait to settlereading = analogRead(salinity_input_pin); // Read voltagedigitalWrite(salinity_power_pin, LOW); // Turn off sensor
Serial.println(reading);}
Why move the sensor reading code into auser-defined function?Make the code reusable
• Reusable by other sensors in the same program• Reusable in other programs: write and debug once, reuse
more than once
Isolate details• Simplify and shorten the code in the loop function• Use simple variable names in local function, and more
descriptive names in the loop function
Make the code easier to maintain• Code in the user-defined function can be improved without
(necessarily) making changes in the loop function• Code in the user-defined function does not need to change
as the loop function changes, e.g. adding new variables or features.
A function to make a single readingint salinity_power_pin = 4; // Digital I/O pin, Global variable
void setup() {Serial.begin(9600);pinMode(salinity_power_pin, OUTPUT);
}
void loop() {
int salinity_input_pin = A2; // Analog input pinint salinity;
salinity = sensor_reading(salinity_power_pin, salinity_input_pin);Serial.println(salinity);
}// -------------------------------------------------int sensor_reading(int power_pin, int input_pin) {
int reading;
digitalWrite(power_pin, HIGH); // Turn on the sensordelay(100); // Wait to settlereading = analogRead(input_pin); // Read voltagedigitalWrite(power_pin, LOW); // Turn off the sensorreturn reading;
}
Salinity reading occurs inone line of loop function
A function to make a single readingint salinity_power_pin = 4; // Digital I/O pin, Global variable
void setup() {Serial.begin(9600);pinMode(salinity_power_pin, OUTPUT);
}
void loop() {
int salinity_input_pin = A2; // Analog input pinint salinity;
salinity = sensor_reading(salinity_power_pin, salinity_input_pin);Serial.println(salinity);
}// -------------------------------------------------int sensor_reading (int power_pin, int input_pin) {
int reading;
digitalWrite(power_pin, HIGH); // Turn on the sensordelay(100); // Wait to settlereading = analogRead(input_pin); // Read voltagedigitalWrite(power_pin, LOW); // Turn off the sensorreturn reading;
}
Copy values to inputs.Variable names can be different.
return copies the result toa variable in the calling function.
power_pin and input_pin are local variables inside the function.
Improve the user-defined functionCode in the loop function has variables for the inputs and outputs
• salinity_power_pin to supply 5V power• salinity_input_pin to make analog reading• salinity receives the result of the measurement
Change the internal details of the reading without affecting loop• Add averaging to the function• Variable names local to the function are not visible to loop
Account for variability in analog input readings
Output of the salinity sensor is not constant• Variation is due to electrical noise and system unsteadiness• Small variations are OK• We need to look at the data graphically
0 5 10 15
550
600
650
700
time (s)
Ana
log
read
ing
Mean = 634.2
Account for variability in analog input readings
If salinity is truly constant (not varying in time), then• Averaging the data is reasonable• Confirm data quality with a dot plot or histogram
A dot plot puts a “dot” for each reading• Result is stacks of dots along the horizontal axis• A “good” dot plot has a strong central tendency – a tall central stack at the
average value• The spread in the stacks is a measure of variability
Analog input readings
620 625 630 635 640 645 650
Mean = 634.2Std. dev. = 6.5
0 5 10 15
550
600
650
700
time (s)
Ana
log
read
ing
Mean = 634.2
Account for variability in analog input readings
A histogram groups the readings in bins – same data as a dot plot• Shape of the histogram depends on width of the bins• A “good” histogram t has a strong central tendency – a tall central stack at
the average value• The spread in the bins is a measure of variability
Mean = 634.2Std. dev. = 6.5
Since averaging smooths out the variation in the readings, let’s add averaging to our code
The average
The standard deviation<latexit sha1_base64="(null)">(null)</latexit>
<latexit sha1_base64="(null)">(null)</latexit>
Evaluate the sum with a loopDefine s as a variable to hold the sum
Add one term at a time to s
Code becomes this, with xi replaced with analogRead(pin)
<latexit sha1_base64="(null)">(null)</latexit>
sum = 0.0;
for (int i; i<=n; i++) {reading = analogRead(input_pin);sum = sum + reading;
}ave = sum/float(n);
<latexit sha1_base64="(null)">(null)</latexit>
Code to compute the average of n readings
To compute
Use this code snippet
<latexit sha1_base64="(null)">(null)</latexit>
int n; // Number of readingsint reading; // Value of current analog input readingfloat sum; // sum of x_i (sum of readings)float ave; // average of n readings
sum = 0.0;
for (int i; i<=n; i++) {
reading = analogRead(input_pin);sum = sum + reading;delay(10); // pause briefly between readings
}ave = sum/float(n);
Add current reading to accumulated sum
Set initial value of sum to zero
} Declare variables once,outside of the loop!
Same effect in more compact code
Original code snippet
More compact version using the += operator
int n; // Number of readingsint reading; // Value of current analog input readingfloat sum; // sum of x_i (sum of readings)float ave; // average of n readings
sum = 0.0;for (int i; i<=n; i++) {reading = analogRead(input_pin);sum = sum + reading;delay(10);
}ave = sum/float(n);
int n; // Number of readingsfloat sum; // sum of x_i (sum of readings)float ave; // average of n readings
sum = 0.0;for (int i; i<=n; i++) {sum += analogRead(input_pin);delay(10);
}ave = sum/float(n);
Replaces two linesreading = analogRead(…)sum = sum + reading;
Arduino sketch to average readingsint salinity_power_pin = 4; // Digital I/O pin, Global variable
void setup() {Serial.begin(9600);pinMode (salinity_power_pin, OUTPUT);
}
void loop() {int salinity_input_pin = A2; // Analog input pinint n = 15; // number of readings to averagefloat salinity; // Average reading is a float
salinity = sensor_reading_ave(salinity_power_pin, salinity_input_pin, n);Serial.println (salinity);
}// -------------------------------------------------float sensor_reading_ave(int power_pin, int input_pin, int nave) {float ave, sum;
digitalWrite(power_pin, HIGH); // Turn sensor ondelay (100); // Wait to settlesum = 0.0;for (int i; i<=nave; i++) {sum += analogRead(input_pin); // Accumulate the sumdelay(10); // Pause, briefly
}digitalWrite(power_pin, LOW); // Turn sensor offave = sum/float(nave); // Compute averagereturn ave;
}
int salinity_power_pin = 4; // Digital I/O pin, Global variable
void setup() {Serial.begin(9600);pinMode (salinity_power_pin, OUTPUT);
}
void loop() {int salinity_input_pin = A2; // Analog input pinint n = 15; // number of readings to averagefloat salinity; // Average reading is a float
salinity = sensor_reading_ave(salinity_power_pin, salinity_input_pin, n);Serial.println (salinity);
}// -------------------------------------------------float sensor_reading_ave (int power_pin, int input_pin, int nave) {float ave, sum;
digitalWrite (power_pin, HIGH); // Turn sensor ondelay (100); // Wait to settlesum = 0.0;for (int i; i<=nave; i++) {sum += analogRead(input_pin); // Accumulate the sumdelay(10); // Pause, briefly
}digitalWrite (power_pin, LOW); // Turn sensor offave = sum/float(nave); // Compute averagereturn ave;
}
Arduino sketch to average readings
Copy values to inputs.
return copies result to a variable in the calling function.
power_pin, input_pin and nare local variables in the function.
Summary1. Salinity sensor is used in a voltage divider2. Salinity sensor is turned on only while readings are taken3. User-defined function computes the average
You should know• How to build the voltage divider circuit• How to write a re-usable function that computes average of analog input