Help with quality monitoring system project for cooking oil refinery production

I'm working on a project about the prototype of a cooking oil refining device, coincidentally in the subsystem part of monitoring the quality of the oil produced with the parameters measured are viscosity, turbidity, and color. can anyone help me in designing it because I've been stuck in 4 weeks only in sensor selection and wiring?

For viscosity, maybe a stirrer of some design, driven by electric motor. The more viscous the oil, the more current the motor will draw.

For colour and turbidity, maybe optical sensors.

For colour, 2 different illuminator LEDs, maybe red and green, aimed though a sample of the oil to a single luminance sensor. The LEDs illuminate the sensor in turn. The change in level from the sensor should give an indication of the colour of the oil.

For turbidity, a single LED with a collimated beam shines through the oil sample. A sensor offset from the beam will give a higher reading for higher turbidity.

before getting stuck on this part, I have designed a low budget system with a detailed design on each paramater for viscosity with a falling ball viscometer method using 2 ldr sensors and 2 laser modules, for color using a tcs3200 gy-31 sensor, for turbidity using a dfrobot turbidity sensor or making a turbidity sensor with a color sensor and a ky-016 rgb led rgb led. I feel a little doubtful about the design of the system design that I have made, is it possible?

What are you asking?

A microprocessor as found on Arduino boards is fully capable of monitoring this handful of disparate sensors as inputs, and using outputs to display information or control actuators or motors or whatever.

Read for a few hours on these fora or just google, you will see that there is some good truth to the old adage about the limit being your imagination.

You didn't say you can code your way out of a paper bag, but if you get a grip on some basic programming this doesn't sound like any huge challenge.

a7

sorry I haven't and the details of the problem,

  • On the viscosity of the falling ball viscometer there is a program code problem so that it cannot read when the ball falls and bias occurs because I use a clear pipe. is there a solution?

  • On color related to the validation of sensor readings compared to standard validation measuring instruments, the problem is whether the standard validation measuring instrument is focused on sRGB or should I change it to light wavelengths for reading units?

  • On color I designed a low cost in-line color sensor for turbid liquids based on the phenomenon of light transmission and scattering from RGB LED source with tcs3200. is there any feedback?

Here is the program code link: "cooking oil quality - Pastebin.com"

Since you haven't posted any code, it's hard to solve this, besides it not sounding like a programming issue, but a bad sensor design.

So on that one, post some drawings freehand is find if your mechanical concept and how the parts that comprise this sensor are to be wired to the Arduino.

And if it is code you are struggling with, complete sketch that compiles but doesn't work woukd allow us to help, or if you have a sketch that doesn't compile yet, post that along with the error messages that verification produces.

a7

That sensor is designed to detect colour of reflected light from a surface. To measure colour of a liquid I think you need to measure light passing through the liquid. You might be able to modify the sensor, removing the illuminator LEDs and putting them on a board on the other side of the liquid.

That's designed to measure turbidity of water. Will it work with oil? It works on the same principle I described before: measuring scattered light. I think you need 2 sensors to measure that light. One in the direct path of the beam of light, the other offset from the beam, and protected against receiving light directly from the beam. You estimate the turbidity by comparing one sensor's reading to the other.

I have inserted the link at the bottom of this --->cooking oil quality - Pastebin.com<----

If you can't access the link, here is the program code:

// libraries
#include <Wire.h>
 
//=== Global constants and variables ======
 
// sensor TCS3200 light-to-frequency converter wiring
#define S0 12
#define S1 13
#define S2 26
#define S3 27
#define sensorOut 25
#define LED 14
 
// viscometer
#define laser1 14
#define laser2 2
#define ldr1 4
#define ldr2 5
 
// sensor turbidity
#define turbidity 33
 
 
//------ Variables sensor color ------
int redPW = 200 ;
int greenPW = 200 ;
int bluePW = 200 ;
int clearPW = 20;
 
//------ Variables Viscometer ------
// Constants for viscosity calculation
const float g = 9.8; // Acceleration due to gravity (m/s^2)
const float k = 1.5; // Size of ball in diameter cm or Constant for viscosity calculation
float Ut = 0;
 
// Define variables for time and viscosity calculation
unsigned long startTime;
unsigned long endTime;
float time = 0;
 
 
//------ Variables sensor turbidity ------
float TU=0.0;
float TU_value=0.0;
float TU_calibration=0.0;
float temp_data=25.0;
float K_Value=3347.19;
 
//----- setting firebase -----
#include <Arduino.h>
#if defined(ESP32)
  #include <WiFi.h>
#elif defined(ESP8266)
  #include <ESP8266WiFi.h>
#endif
#include <Firebase_ESP_Client.h>
 
//Provide the token generation process info.
#include "addons/TokenHelper.h"
//Provide the RTDB payload printing info and other helper functions.
#include "addons/RTDBHelper.h"
 
// #include <HardwareSerial.h>
// HardwareSerial SerialPort(2);
 
// Insert your network credentials
#define WIFI_SSID "xxxxx"
#define WIFI_PASSWORD "xxxxx"
 
// Insert Firebase project API Key
#define API_KEY "xxxxxx" /*database testfinalprojet
 
// Insert RTDB URLefine the RTDB URL */
#define DATABASE_URL "xxxxx" 
 
//Define Firebase Data object
FirebaseData fbdo;
 
FirebaseAuth auth;
FirebaseConfig config;
 
unsigned long sendDataPrevMillis = 0;
int count = 0;
bool signupOK = false;
 
 
// === Setup code, runs once =========================
 
void setup() {
  pinMode(S0, OUTPUT);
  pinMode(S1, OUTPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);
  pinMode(sensorOut, INPUT);
  pinMode(LED, OUTPUT);
  pinMode(turbidity, INPUT);
  pinMode(laser1, OUTPUT);
  pinMode(laser2, OUTPUT);
  pinMode(ldr1, INPUT);
  pinMode(ldr2, INPUT);
 
   // Setting laser
  digitalWrite(laser1, HIGH);
  digitalWrite(laser2, HIGH);
 
  digitalWrite(LED, HIGH);
 
  // Setting frequency-scaling to 20%
  digitalWrite(S0, HIGH);
  digitalWrite(S1, LOW);
 
 
  Serial.begin(115200); // use the serial port to print out the resultant data
 
 
  //inisialisasi firebase dan wifi
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("Connecting to Wi-Fi");
  while (WiFi.status() != WL_CONNECTED){
    Serial.print(".");
    delay(300);
  }
  Serial.println();
  Serial.print("Connected with IP: ");
  Serial.println(WiFi.localIP());
  Serial.println();
 
  /* Assign the api key (required) */
  config.api_key = API_KEY;
 
  /* Assign the RTDB URL (required) */
  config.database_url = DATABASE_URL;
 
  /* Sign up */
  if (Firebase.signUp(&config, &auth, "", "")){
    Serial.println("ok");
    signupOK = true;
  }
  else{
    Serial.printf("%s\n", config.signer.signupError.message.c_str());
  }
 
  /* Assign the callback function for the long running token generation task */
  config.token_status_callback = tokenStatusCallback; //see addons/TokenHelper.h
  
  Firebase.begin(&config, &auth);
  Firebase.reconnectWiFi(true);
 
}
 
 
void loop() {
  // put your main code here, to run repeatedly:
  //==== sensor tcs3200 ====
    // Calibration Values
  int redMin=50;// Red minimum value 40
  int redMax=346;//346 Red maximum value 470
  int greenMin=85;// Green minimum value 40
  int greenMax=348;//348 Green maximum value 510
  int blueMin=40;// Blue minimum value 30
  int blueMax=262;//262 Blue maximum value 390
  int clearMin=0;
  int clearMax=500;
 
 
  /*frequency reading
  red 50 | distance 0cm
        90 | 1cm distance
        140 | 2cm distance
        195 | 3cm distance
        270 | 4cm distance
  green 70 | distance 0cm
        130 | 1cm distance
        195 | 2cm distance
        245 | 3cm distance
        300 | 4cm distance
  blue 37 | distance 0cm
        72 | 1cm distance
        125 | 2cm distance
        170 | 3cm distance
        208 | 4cm distance
  */
 
  
 
  int redValue;
  int greenValue;
  int blueValue;
  int clearValue;
 
  // Remap the value of the Frequency to the RGB Model 
  // Syntax - map(value, fromLow, fromHigh, toLow, toHigh)
  // Frequency Model fromLow = 0, Frequency Model fromHigh = 600
  // RGB Model toLow = 0, RGB Model toHigh = 255
  
  //Read Red Pulse Width
  digitalWrite(S2,LOW);
  digitalWrite(S3,LOW);
  // Read the output Pulse Width
  redPW = pulseIn(sensorOut,LOW);
  redValue=map(redPW,redMin,redMax,255,0);
  delay(200);
 
  // Read Green Pulse Width
  digitalWrite(S2,HIGH);
  digitalWrite(S3,HIGH);
  // Read the output Pulse Width
  greenPW = pulseIn(sensorOut,LOW);
  greenValue=map(greenPW,greenMin,greenMax,255,0);
  delay(200);
 
  // Read Blue Pulse Width
  digitalWrite(S2,LOW);
  digitalWrite(S3,HIGH);
  // Read the output Pulse Width
  bluePW = pulseIn(sensorOut,LOW);
  blueValue=map(bluePW,blueMin,blueMax,255,0);
  delay(200);
 
  // read clear no filter pulse width
  digitalWrite(S2,HIGH);
  digitalWrite(S3,LOW);
  // Read the output Pulse Width
  clearPW = pulseIn(sensorOut,LOW);
  clearValue=map(clearPW,clearMin,clearMax,255,0);
  delay(200);
 
  //==== end sensor tcs3200 ====
 
  //==== start viscometer ====
  int value1 = analogRead(ldr1);
  int value2 = analogRead(ldr2);
  int average = (value1 + value2) / 2;
 
  if (average > 500) {
    startTime = millis() / 1000.0;
    while (average > 500) {
      value1 = analogRead(ldr1);
      value2 = analogRead(ldr2);
      average = (value1 + value2) / 2;
    }
    endTime = millis() / 1000.0;
    time = (endTime - startTime);
    Ut = (10 / time);
 
    float viscosity = 2 * g * k * (7800 - 1000) / (9 * Ut); // Calculate viscosity
    Serial.print("Viscosity: ");
    Serial.print(viscosity);
    Serial.println(" cP");
 
    delay(500);
  }
  //==== end viscometer ====
 
  //===== sensor turbidity =====
  int sensorValue = analogRead(33);// read the input on analog pin 0:
  float TU = sensorValue * (5.0 / 1024.0); // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  TU_calibration=-0.0192*(temp_data-25)+TU;  
  TU_value=-865.68*TU_calibration + K_Value;
  
  if(TU_value<=0){TU_value=0;}
  if(TU_value>=3000){TU_value=3000;}
  //Serial.print("TU Value:");
  //Serial.print(TU_value); // print out the value you read:
  //Serial.println("NTU");
  delay(500);
  //==== end sensor turbidity ====
 
 
  if (Firebase.ready() && signupOK && (millis() - sendDataPrevMillis > 1000 || sendDataPrevMillis == 0)){
    sendDataPrevMillis = millis();
    // Write an Int number on the database path test/int
    if (Firebase.RTDB.setInt(&fbdo, "DATA_SENSOR/TURBIDITY", TU_value)){
      Serial.println("PASSED");
      Serial.println("PATH: " + fbdo.dataPath());
      Serial.println("TYPE: " + fbdo.dataType());
    }
    else {
      Serial.println("FAILED");
      Serial.println("REASON: " + fbdo.errorReason());
    }
    
     Write an Float number on the database path test/float
    if (Firebase.RTDB.setFloat(&fbdo, "DATA_SENSOR/VISCOMETER", viscosity)){
      Serial.println("PASSED");
      Serial.println("PATH: " + fbdo.dataPath());
      Serial.println("TYPE: " + fbdo.dataType());
    }
    else {
      Serial.println("FAILED");
      Serial.println("REASON: " + fbdo.errorReason());
    }
 
    // Write an Float number on the database path test/float
    if (Firebase.RTDB.setString(&fbdo, "DATA_SENSOR/COLORRED", redValue)){
      Serial.println("PASSED");
      Serial.println("PATH: " + fbdo.dataPath());
      Serial.println("TYPE: " + fbdo.dataType());
    }
    else {
      Serial.println("FAILED");
      Serial.println("REASON: " + fbdo.errorReason());
    }
 
    // Write an Float number on the database path test/float
    if (Firebase.RTDB.setString(&fbdo, "DATA_SENSOR/COLORGREEN", greenValue)){
      Serial.println("PASSED");
      Serial.println("PATH: " + fbdo.dataPath());
      Serial.println("TYPE: " + fbdo.dataType());
    }
    else {
      Serial.println("FAILED");
      Serial.println("REASON: " + fbdo.errorReason());
    }
 
    // Write an Float number on the database path test/float
    if (Firebase.RTDB.setString(&fbdo, "DATA_SENSOR/COLORBLUE", blueValue)){
      Serial.println("PASSED");
      Serial.println("PATH: " + fbdo.dataPath());
      Serial.println("TYPE: " + fbdo.dataType());
    }
    else {
      Serial.println("FAILED");
      Serial.println("REASON: " + fbdo.errorReason());
    }
 
    // Write an Float number on the database path test/float
    if (Firebase.RTDB.setString(&fbdo, "DATA_SENSOR/COLORCLEAR", clearValue)){
      Serial.println("PASSED");
      Serial.println("PATH: " + fbdo.dataPath());
      Serial.println("TYPE: " + fbdo.dataType());
    }
    else {
      Serial.println("FAILED");
      Serial.println("REASON: " + fbdo.errorReason());
    }
  }
 
  
}

Here is the P&ID of the subsystem that I designed

I don't see a reason for any of the calls to delay(). It seems as if you are just giving the microprocessor a little nap after each thing that looks like it might be taxing.

The microprocessor can, and you might even say wants to, run flat out. It will not quit over the harsh working conditions of constantly doing your bidding.

Lose the delays or justify them. I hope you know delay means, in this context, sitting right there doing nothing.

I noticed pulseIn(). It will time out by default after one second. If you know a better value for giving up, you should add it as the third parameter to the calls. Check the documentation.

I did not see any code that accounts for pulseIn() timing out, so you may be using meaningless return values.

You use map(). That works, but be aware it will happily extrapolate, so it is often found in the wild near the use of the constrain() macro, either to clip the input domain or the output range.

You only print the mapped values, perhaps printing the values before would be helpful.

Use a 21st century baud rate 115200 if you have no need to poke along at 9600. This will mean you can print more without any adverse effects side issues around timing. That may not be important here, just a tip.

There is no good reason to work with a sketch that does all three sensors. I suggest you to get three sketches working, one for each sensor. I don't think there is any interaction in the code between the sensors, so it would be easier for you, and us, to focus on one thing at a time.

You've posted new code. What is different, what are you trying? Are these minor tweaks here and there, or are you trying a different basic algorithm?

Of course we could all look to see and figure that out. It is more efficient and you'll get more attention if you just say a few words about this.

And you've said nothing yet about how and whether the new codes works any better, so it's hard to help you fix it or suggest experiments.

I'm not in the lab. When I can I will see if any of this is amenable to being simulated. For me sometimes running code is faster than reading it to the point of understanding.

HTH

a7

Yesterday the UA flew about your code for a bit between other things. Here are some further comments and questions.

As for the calculations in all three functions, I suggest again that you print raw sensor values and all intermediate values so you can examine them and confirm they are doing what you want. This is not a coding problem at all. I can only trust all the maths, only you can verify the results.

This test in the viscosity function

  // check if the ball has reached the first sensor
  if (average > 500) {
    // start the timer

gets executed less than once every 2800 milliseconds. If it fails, the function exits. The probability of this catching the ball at the precise moment the top sensor first "sees" it is so low as to be effectively zero.

Even if the function was entered somewhat more frequently, it would still be with problems.

What makes the ball drop? You must monitor the top sensor continuously to catch that moment. Unless done carefully, this will only work when you know a ball is on its way. If you do code so as to wait on a ball, include some kind of time out and error reporting. I do not know haw fast the two other sensor systems can function. It is likely that the viscosity test will have to own the processor for the duration, as it might now if it happened to catch the ball in between the top and bottom LDRs

How does an average of two LDRs work to provide input to the process for the two times you are interested in? Have you observed the LDRs' response?

Just in a vacuum out here I would think that the top LDR would be used to detect entry into the measured path, and the bottom to detect exit, allowing for the elapsed time to be used in the calculations.

Or we just have no clue about how that part is supposed to work. :expressionless:

a7

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.