I've amended this post in the light of helpful comments below, apologies for my lack of detail.
The background is about 18 months ago made a control unit for my daughter to read the levels in, and transfer water between, two water tanks (5,000 and 25,000L) with safety cut-off so they didn't spill over or run dry. Essentially a set-and-forget system operated from her kitchen.
This comprised an Arduino ATMega 2560 R3, LED screen, 2 relays controlling 24v AC irrigation taps, various switches, and 2 x A02YYUW ultrasonic sensors. 12V DC supply. All cabling shielded. (Diagram not supplied as it's not relevant here). This has worked well except I had unforseen problems with the ultrasonic sensors. Their placement in the tanks was important, they needed a hood to shield from stray sound reflections and harmonics, and they returned abnormal readings in noisy weather (rain and wind) - apart from the coding being a bit tricky because of timing problems. (If I'd known all this before I started I'd have used different sensors).
It all worked OK - I limited the read errors and actually used a 300SMA on % tank levels which gave stable usable parameters even if the instantaneous readings weren't.
But I didn't like the errors, so now I'm going to try swapping the ultrasound sensors for these Gravity Throw in liquid sensors. But I found it wasn't straightforward to set up - largely, it seems, because of induced noise from the sensor power supply (I want to use an HP 19V laptop supply), and perhaps because of the relatively low resolution of the 10bit DAC on the UNO I'm using to test the setup.
I think I've got it I sorted out and my solution is here for others' benefit. Refer also to this Core-electronics forum post where Matt64566 had similar problems.
Variable readings throw-in sensor
- As received, I used the code supplied by DF Robot here:
https://wiki.dfrobot.com/Throw-in_Type_Liquid_Level_Transmitter_SKU_KIT0139
I found the sensor read incorrectly (deeper than measured). A calibration value was added to the reported measurement. (Note the actual part of the sensor you measure down to is just beyond the cable attachment to the SS cylinder).
- See the DF Robot diagram for my setup. It's exactly the same as this picture - I used either an HP laptop 19v DC power supply or an 18V battery (from Makita 18v drill) as a power supply for the sensor - with the +ve lead detouring to the Voltage converter module as in the diagram.
I then ran either the Arduino UNO Vout of 5v or 3.3v to the Gravity: Analog Current to Voltage Converter (which takes a low current and is within the 50mA capacity of the 3.3v output). NOTE: The Arduino UNO has a separate power supply from the PC (and not the 18v battery/19V PS which is only for the sensor).
[Gravity: Analog Current to Voltage Converter (for 4~20mA Application) - DFRobot]
(Gravity: Analog Current to Voltage Converter (for 4~20mA Application) - DFRobot)
The battery should have eliminated sensor power supply errors, and I think it did.
- even with a battery as power to the sensor I had to average the results - I used 100SMA, but anything from 50+ points seems to work.
This is the setup from DFRobot as used, followed by my code, modified from the DFRobot supplied code, for stable readings.
/***********************************************************
DFRobot Gravity: Analog Current to Voltage Converter(For 4~20mA Application)
SKU:SEN0262
GNU Lesser General Public License.
See <http://www.gnu.org/licenses/> for details.
All above must be included in any redistribution
Code modified by Olefella
****************************************************/
/* -use battery 18v for sensor and 3.3Vout from UNO for I>V converter. start averaging 100 readings - success, stable output. (Remove time delay in original code, recalibrate, add 2 separate functions 'readdata' and 'getavedepth'). Changing to 5Vout from UNO means recalibrating sensor.
*/
#define ANALOG_PIN A2
#define RANGE 5000 // Depth measuring range 5000mm (for water)
#define VREF 3300 // ADC's reference voltage on your Arduino,typical value:5000mV or 3300v stabilised
#define CURRENT_INIT 4.00 // Current @ 0mm (uint: mA)
#define DENSITY_WATER 1 // Pure water density normalized to 1
#define calibration 2.78 //2.78 for 3300mV, 0.855 for 5000mV
#define AVEPERIOD 100
int movingAvg[AVEPERIOD]; // The array to store the moving average
int16_t dataVoltage;
float dataCurrent, depth, avedepth; //unit:mA
unsigned long timepoint_measure;
void setup() {
Serial.begin(9600);
pinMode(ANALOG_PIN, INPUT);
}
void ReadData() {
dataVoltage = analogRead(ANALOG_PIN) / 1024.0 * VREF;
dataCurrent = dataVoltage / 120.0; //Sense Resistor:120ohm
depth = (dataCurrent - CURRENT_INIT) * (RANGE / DENSITY_WATER / 16.0); //Calculate depth from current readings
depth = depth * calibration;
if (depth < 0) depth = 0.0;
}
void Getavedepth() {
//this just averages the raw data reading from the sensor by AVEPERIOD points Returns avedepth as a global variable
float sum = 0; //care - sum goes over 16 bit int limit so has to be a float
for (int i = 0; i < AVEPERIOD; i++) {
ReadData();
movingAvg[i] = depth;
sum += movingAvg[i];
}
avedepth = sum / AVEPERIOD;
}
void loop() {
Getavedepth();
//Serial print results
Serial.print("depth:");
Serial.print(avedepth);
Serial.println("mm");
}
- With this setup I got stable accurate readings, but when I switched to the HPlaptop power supply the readings became more variable. It didn't matter if I used the 5v or 3.3v (separate depth calibration needed for each supply) so I suspect a more stable voltage supply for the sensor is essential. I'll use a couple of capacitors and a 7815 for that.