Need Help with Grove Turbidity Sensor and ESP32 – Formula Needed

Hi all,

I am working on a project where I am trying to use the Grove turbidity sensor with an ESP32. The specific datasheet for the sensor can be found here (https://files.seeedstudio.com/products/101020752/Turbidity%20Sensor%20specification.pdf).

I have powered the sensor externally with a 5V supply, and in my code, I’m currently using the 3.3V operating voltage with the 4096 resolution of the ESP32. Unfortunately, I don’t have any calibration liquid to calibrate the sensor.

I’ve noticed that other manufacturers, like DF Robot, provide a specific formula for their sensors. For example, the formula given by DF Robot is: y = -1120.4 * x^2 + 5742.3 * x - 4352.9.

My question is, does anyone know of a corresponding formula for the Grove sensor that aligns with the information provided in the datasheet? I’m having difficulty getting accurate readings without it. Any assistance or guidance would be greatly appreciated.
Currently, I’m trying to read the values linearly from 0 to 3.3V, but I suspect this approach might be too imprecise for my needs. Here’s the code I’m using which I adjust and found here:(Turbidity sensor coding - #3 by zhomeslice - Programming Questions - Arduino Forum)

cppCopy code

#include <EEPROM.h> // to store last calibration value (blank, Vclear)

int sensor = 0; // variable for averaging
int n = 25; // number of samples to average
int sensorValue = 0;
float voltage = 0.00;
float turbidity = 0.00;
float Vclear = 3.3; // Output voltage to calibrate (with clear water).

void setup()
{
  Serial.begin(115200);
  EEPROM.get(0, Vclear); // recovers the last Vclear calibration value stored in ROM.
  delay(3000); // Pause for 3 seconds
}

void loop()
{
  // Sensing routine:
  for (int i = 0; i < n; i++) {
    sensor += analogRead(A3); // read the input on analog pin 3 (turbidity sensor analog output)
    delay(10);
  }
  sensorValue = sensor / n; // average the n values
  voltage = sensorValue * (3.300 / 4095.000); // Convert analog (0-4095) to voltage (0 - 3.3V)

  turbidity = 20.00 * (100.00 - (voltage / Vclear) * 100.00); // as relative percentage of 2000 NTU; 0% = clear water; // Factor 20 at the front instead of 100 to limit the result to 2000

  // Serial display
  Serial.print("Raw voltage: ");
  Serial.print(voltage, 3);
  Serial.print(" V, Turbidity: ");
  Serial.print(turbidity, 3);
  Serial.println(" NTU");

  sensor = 0; // resets for averaging
  delay(1000); // Pause for 1 seconds. // sampling rate
}

I’m hoping that someone may have experience with this sensor and can provide insight or guidance on a more accurate method for reading turbidity. If there is a specific formula that can be applied to the Grove sensor, that would be incredibly helpful.

Thanks in advance!

There is a mock-out example in the Seeed wiki documentation that might help you

void setup() {

  Serial.begin(9600); //Baud rate: 9600
}

void loop() {
  int sensorValue = analogRead(A0);// read the input on analog pin 0:
  float voltage = sensorValue * (5.0 / 1024.0); // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  Serial.println(voltage); // print out the value you read:
  delay(500);
}

This code only gives me the voltage values and no conversion to NTU. The question is much more whether one should divide the NTU value linearly on its voltage. I have read the data points from the data sheet and have come to the following result, ratio NTU to Volt:


I have no calibration fluid but this code should work better according to my logic or?
Code:
int sensorPin = A3;
float volt;
float ntu;

void setup() {
Serial.begin(115200);
}

void loop() {
volt = 0;
for (int i = 0; i < 800; i++) {
volt += ((float)analogRead(sensorPin) / 4096) * 3.3; // Conversion for 3.3V, as ESP has a 12-bit ADC
}
volt = volt / 800;
volt = round_to_dp(volt, 2);

// Transformation of voltage values
volt = mapf(volt, 0.0, 3.3, 1.83, 3.68); // Mapping actual voltage to the required range

ntu = 493.17 * pow(volt, 2) - 3749.1 * volt + 7152.3; // Calculating NTU using the provided quadratic equation

// Limiting the NTU value between 0 and 2000
if (ntu < 0) {
ntu = 0;
} else if (ntu > 2000) {
ntu = 2000;
}

Serial.print(volt);
Serial.print(" V, “);
Serial.print(ntu);
Serial.println(” NTU");
delay(500);
}

float round_to_dp(float in_value, int decimal_place) {
float multiplier = powf(10.0f, decimal_place);
in_value = roundf(in_value * multiplier) / multiplier;
return in_value;
}

float mapf(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; // Mapping function for float values
}