The liquid level sensor is a variable resistor, which means that it has different levels of resistance depending on the height of the liquid that surrounds it. The spec for the sensor is that it’s 2250Ω when there’s no liquid, 400Ω when the liquid is a foot (or 30 cm) high. But that’s +- 10%, which is a lot when you’re trying to measure depth: if the reading is 30cm, it could be 33cm or 27cm. In a 5gal bucket (with a radius of 14.6cm), +-10% could mean a difference of +-2 liters. Not good.

I put the sensor in the bucket and measured the analog reading at different heights. I got this table:

ar   dp
813  0.1
742 10.3
677 15.3
603 20.3
517 25.3
396 30.0

So when the liquid is 0.1cm deep, the Arduino’s analog reading is 813, and so forth. The relationship between the analog reading and depth is distinctly non-linear.

Many sites, including Adafruit in the product’s tutorial section, suggest that the right way to get the depth is by transforming the analog reading into the sensor’s resistance with this formula: resistance = R1/((1023/ar)-1), where R1 is the resistance of the pullup resistor (see here if you don’t know what I mean: I didn’t before I studied it), and ar is the analog reading. Knowing the resistance at the bucket’s full and empty, you can find any intermediate point linearly: proportion full = (max resistance – this resistance)/(max resistance – min resistance) — remember that we’re at max resistance when the bucket is empty.

Hmm, I thought, that estimate probably won’t get to a good linear approximation of this curve, but ok, let’s try it. I interpolated the points in the graph above four ways: first with a simple linear model dp~ar (blue); then with a 4th-degree polynomial dp~poly(ar,4) (black); then using the resistance in a linear way dp~res (yellow); then with the proportional approximation suggested above (purple).

Ok, the simple linear model with the untransformed analog reading is a total mess, discard it. The other three are more interesting. I think it’s curious that both the resistance models estimate intermediate values poorly. The polynomial with the untransformed analog readings definitely looks like the best fit. My plan is to estimate the depth for every value in the analog scale [0,1023], rounded to millimeters. I’ll copy that into an array in Sketch, then use the analog value as a lookup into the array. Lots of testing coming in the next few days, and I’ll post results if this approach goes awry.