Gravity throw-in liquid sensor (DF Robot) variable readings

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

  1. 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).

  1. 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.

  1. 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");
}
  1. 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.

@olefella
You never select the VREF as EXTERNAL and you have nothing connected to the AREF pin, so your VREF is 5V not 3.3V. Maybe that's why you have errors.

1 Like

Vref is not a power supply.

Have you looked up how large Vin is allowed to be on the UNO specs?

https://docs.arduino.cc/learn/electronics/power-pins/

Can you please post a copy of YOUR circuit, a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, power supplies, component names and pin labels.

This will clarify how your connections are in YOUR circuit.

Can you please post some pictures of your project?
So we can see your component layout.

Thanks.. Tom... :grinning: :+1: :coffee: :australia:

Dangerous diagram from DFRobot.
You must not share sensor supply with Arduino supply.
A shared ground could fry the voltage converter, or at least influence measurements.

I think the voltage converter in the negative wire of the sensor is a much safer solution.

Which is wrong, and dangerous for the Arduino. The Aref pin can't be used to power anything.
The voltage converter must be powered with 5volt, to give the opamp on it enough headroom.

A good thing would be to change Aref of the Uno R3 to 3.3volt.
That will give a more stable readout and a higher resolution.

To do this, add this line to setup().
analogReference(EXTERNAL);
And connect the 3.3volt pin to the Aref pin.

Forgetting step#1 will fry Aref.

Code must of course reflect changing Aref from default to 3.3volt.
Leo..

3% of what.

Resolution (readout steps) could be 5cm.
If you measure the depth of a teacup, then the error could be 50%.
The error of the depth of a pool could be 0.5%.
Leo..

Thanks - actually I didn't use Vref, I used the 5V or 3.3V output (edited out of post above)

Thanks for the usage of Vref, but see edited above - I didn't use Vref actually.

And the two power supplies are indeed separate, which I didn't make clear, but the point about the shared ground is important - in use there will be 3 power supplies ATMega, Sensor, and 24v AC, all sharing the same power board.

Good point. +/- 3% of the depth reading, which was 1000mm in a 20L tube. IE 30mm either way or +/-60ml in 20L. Which doesn't actually make much difference (120L) in a 20,000L or (30L) in a 5,000L water tank where I use 95% for full/empty control limits. I'd rather it is less though, and the 300SMA reduces the error to about 0.5%.

Thanks TomGeorge - as you can see in the amended post I used separate PS's, and didn't use Vref - my mistake.

The pictures of the present setup don't help much, it's just testing the sensor with UNO exactly as per DFRobot diagram and using a battery or laptop PS; and either V5 or V3.3. Here they are anyway, plus a couple of images of the control system which works well apart from sensor errors as described.




You have a sensor with a 5000mm range. A 4-20mA sensor uses 80% of the A/D when Aref is perfectly matched to the voltage converter (0-4mA is lost). Meaning you could ideally have about 800 A/D values maximum over 5000mm. So the resolution is 5000/800 = 6.25mm at best, meaning a 10mm-step (0.1cm) human readable display. If you leave Aref as it is (default), then that 10mm becomes more uncertain because of lower resolution and a potentially unstable 5volt supply.

I see "7686" in your display.
The last digit is nonsense if you only have a resolution of 800 steps.
If you want to display a 5000mm range in mm of water, then you need at least a 13-bit A/D.
The ADS1115 would be a good choice, if used between voltage converter and Arduino.
Leo..

Hi, @olefella

Please do not amend posts, post new complete post when you do corrections to keep the flow of the thread logical.

Thanks.. Tom.. :grinning: :+1: :coffee: :australia:

That 7686 is the L left in the tank with an ultrasonic sensor in a picture of the existing control box, not this gravity sensor I'm testing.

Otherwise I agree, and I did think of an ADC with a bigger range, but it's not worth it in this application.

Your program has VREF = 3300 but you never select the EXTERNAL reference and there is nothing connected to AREF, so your actual VREF = 5.0 V . Thats why you are having problems.

https://www.arduino.cc/reference/en/language/functions/analog-io/analogreference/

+1

@olefella Read post#4 again, this part.

add this line to setup().

analogReference(EXTERNAL);

And connect the 3.3volt pin to the Aref pin.
Leo..

Edit:
You seem to use a Mega. They have a built-in 2.56volt Aref.
It might be easier to just switch to that (no wire link between Aref and 3.3volt).
Just add analogReference(INTERNAL2V56); to setup().
That should give you a stable result with maximum available resolution.
Change
#define VREF 3300
to
#define VREF 2560
or, for nitpickers, to what you measure with a DMM on the Aref pin.

Thanks Wawa and jim-p, I read up on the reference voltages in the Arduino range last night, including more than I needed to know about ADC at:

Nick Gammon on ADC

As suggested I added analogReference(EXTERNAL); and connected the UNO 3.3v pin to the Aref pin. Which effectively provides an upper bound of 3.3v to the 10 bit ADC - matching the IV converters' 0-3v output. (and I power the IV converter from the 5v UNO pin.)

I'm powering the sensor using an 18v battery to provide a stable power supply for this test.

The results are still variable though, and much the same as before, so that didn't fix it.

However the variability is drastically reduced by averaging - increasing the period of the SMA from 1 to 1000 suggested that around 500SMA is about right.

This graph shows the range of results vs the SMA period:

sma period vs errors

I presume this just shows the inherent inaccuracy of the sensor/converter combination. The data sheets show 0.5% for the sensor and +/- 2% for the IVC

Anyway, since I'm now (apparently!) reading +/- 1mm in 1000mm with this test setup its probably as good as it's going to get. Good enough for a water tank anyway.

It seems I need to concentrate on getting a stable voltage out of the laptop power supply.

Thanks Wawa, I thought of that too but the IV converter outputs up to 3V full range (actually a bit more according to the specs), so I thought it better to use the 3.3volt supply as Aref.

So I think I've figured it out - I added a 7815 to the HP laptop PS as illustrated. I could see no voltage variability on max range on the oscilloscope. But I got large errors. Despite putting capacitors on the input and output of the 7815 (crossed out below), changing the laptop power supply for another one, and changing the UNO board, I still needed a SMA of >=5000 to get an error range of 12/1000 mm (as opposed to 2/1000 mm with SMA >=500 using battery power for the sensor). The desktop setup uses one mains outlet for everything - monitors, hard drives, printer, scanner, speakers, PC mainboard. Hopefully reducing ground loop problems, but that looks like it isn't enough.

I then ran the sketch off my laptop, running on battery power, and the error range went back to 2/1000mm with 500SMA - just like the graph above.

So it looks like it's variability in the power supply after all. ?A local ground loop - there's a lot of equipment plugged in - or just inherent variation in the mains supply voltage to the sensors HP laptop PS due to the varying load on the whole desktop circuit. After all the sensors output - via the HP laptop PS - is now being measured by the IV converter which is reliant on the desktop PC power supply to the the UNO. So there are 2 power supplies separated by a lot of equipment each one pulling a load).

I don't know how it will pan out when I transfer it all to the Mega on the control unit in my daughters kitchen, but at least now I have an idea on what to look out for.

Try what I said in the fourth line of post#4.
Leo..

OK will do, thanks.