Skip to main content

Projet d'Automatisation et régulation de la viscosité

UE MU5CI823-Optimisation, contrôle et digitalisation des procédés

 

Groupe 2

Noms et Prénoms:

DE LA TAILLE LOLAINVILLE Gregoire (gregoire.de_la_taille_lolainville@etu.sorbonne-université.fr) 21103148

PALAIN Ilies (ilies.palain@etu.sobonne-université.fr) 21400210

HOU Charles (charles.hou@etu.sorbonne-université.fr) 21400213

JIANG Alexandre (alexandre.jiang@etu.sorbonne-université.fr) 21113611

Cursus scolaire : Master 2 de Chimie - Parcours Ingénierie Chimique

Date de commencement du projet : Septembre 2023

 
Date de fin du projet : 

Introduction :

L'objectif de notre projet est de contrôler la concentration d'une solution aqueuse à partir de sa viscosité. Pour cela, nous utiliserons un agent visqueux afin de directement associer la viscosité du mélange à sa concentration en agent visqueux

Matériel utilisés:

Réactifs :

  • Eau
  • Glycérine

Composants:

  • 1 carte Arduino (Carte Arduino UNO Rev 3)
  • 3 pompes (LEX-WATER-PUMP2 Pompe miniature à eau 1,1 L/min)
  • 1 moteur agitateur pour mélanger (Motoréducteur 37025GM-12130)
  • 2 électrovannes (Electrovanne 12 V FDP360L)
  • 4 Relais (Module de relais 5 V SRD-05VDC-SL-C)
  • 1 capteur ultrason (Capteur de détection ultrasons HC-SR04)
  • 1 capteur de température (Capteur de température DS18B20 étanche DFR0198) : TT (Temperature Transmitter)
  • 1 capteur de débit (Capteur de débit YFS401) : FT (Flow Transmitter)
  • 1 BreadBoard
  • 4 récipients

Avancement du projet:

16/10/2025: Lors de la semaine blanche, nous avons entamé une première séance de brainstorming qui nous servait de base préliminaire pour choisir le sujet de notre projet. Nous nous sommes ainsi porté sur un sujet portant sur la régulation du procédé d'une élaboration de biodiesel avec une analyse de sa pureté.

17/10/2025 : Après concertation avec notre tuteur de projet, M. Jérôme PULPYTEL, nous avons décider de modifier notre sujet, tout en gardant l'une des idée de base de l'ancien sujet qui est en rapport avec la viscosité. C'est pour cela que nous sommes donc partis sur l'automatisation de la régulation de la viscosité par une méthode in-situ. 

17/10/2025 jusqu'au 28/10/2025 : Réalisation du schéma de notre projet et la préparation de la liste de matériel nécessaire à notre projet.Cuve de mélange.png

Figure 1 : P&ID de départ

17/11/2025 : Nous allons chercher les matériaux de la liste pour pouvoir ainsi commencer le projet.

19/11/2025: Sciure pour créer les supports pour les deux réservoir des réactifs de départ.

dc3f600f-7195-47d5-a06b-d23c394d57b1.jpeg

Figure 2 : Support en bois après modification

24/11/2025 : Nous débutons le montage. Pour cela, on perce des trous dans la plaque en bois pour permettre le maintien des équipements. De plus, nous perçons les récipients pour permettre l'insertion des tuyaux. Nous installons ensuite les premiers éléments qui sont les récipients, une pompe, une électrovanne et un capteur.

IMG_6749.jpeg

Figure 3 : Assemblage des premiers éléments du projet

IMG_6746.jpeg

IMG_6751.jpeg

Figure 4 : Placement des éléments sous différents angles

26/11/2025 : 1er essai de modélisation du montage électrique sur TinkerCad. Modélisation 3D de l'hélice et de la tige à rattacher au moteur pour nous permettre de mélanger nos liquide. Création d'un support pour le moteur.

Screenshot 2025-11-26 15.55.22.png

Figure 5 : 1er essai de modélisation sur TinkerCad

27/11/2025 : Après un premier envoi de notre essai de modélisation, notre tuteur nous explique qu'il manque des composants sur notre modèle TinkerCad et le code est incomplet. Suite à cela, nous nous décidons de modifier notre envoi de modélisation. En parallèle à cela, nous imprimons en 3D les pales de notre agitateur. Puis nous avons fait des trous dans nos planches pour pouvoir installer les derniers pièces manquantes sur le support.

IMG_6837.jpeg

Figure 6 : Pales imprimées en 3D pour l'agitation

IMG_6838.jpeg

Figure 7 : Support comportant tout les emplacements finaux

28/11/2025 : Nous commençons les branchement des modules relais à l'Arduino. Tous les équipements ont d'abord été testé avec le code correspond afin de vérifier leur bon fonctionnement. Ils ont ensuite été placés sur le support avec les différents récipients et les branchements associés.

projet 823 avant.jpeg

Figure 8a : Support comportant les équipements, récipients et branchements (face avant)

projet 823 arriere.jpeg

Figure 8b : Support comportant les équipements, récipients et branchements (face avant)

Du fait d'un débit de sortie de l'eau beaucoup trop faible à cause de la vanne associée, il a été décidé de la remplacer par une pompe. Voici le nouveau P&ID du projet : 

Cuve de mélange (1).png

Figure 9 : Nouveau P&ID de l'installation

26/01/2025 : Il n'a pas été possible d'obtenir de la glycérine pour le projet. Ainsi, la glycérine est remplacée par un autre liquide visqueux, la grenadine, car disponible à bas coût et en grande quantité, la viscosité a été estimé à environ 1500 CP.

On obtient la courbe d'étalonnage suivante, grâce à des différentes mesures d'eau pure, de grenadine pure, et de mélange 50/50, :

 

Figure 10 : Graphique montrant l'évolution du débit en fonction de la viscosité

Nous avons également peaufiné le code Arduino :

// === MACHINE DE REGULATION DE VISCOSITE ===
#include "Ultrasonic.h"

// Valeur de viscosité cible en centipoise (MODIFIER ICI)
const float VISCOSITE_CIBLE = 500.0;  // Entre 1 et 1500 cP

// === PINS ===
const int pumpWaterPin = 2;      // Pompe eau
const int pumpGrenadinePin = 3;  // Pompe grenadine
const int pumpCircuitPin = 4;    // Pompe circuit de mesure
const int transferPumpPin = 5;   // Pompe de transfert
const int transferValvePin = 6;  // Vanne de transfert
const int flowSensorPin = 7;     // Capteur de débit
const int ultrasonicPin = 8;     // Capteur niveau ultrason

// === PARAMETRES ===
const float TOLERANCE_DEBIT = 0.10;    // 10% de tolérance sur le débit
const unsigned long minPulseInterval = 50; // Filtre anti-bruit
const int NIVEAU_MIN = 6;  // Niveau minimum en cm (débordement si < 6cm)

// === VARIABLES MESURE ===
volatile int pulseCount = 0;
int lastState = HIGH;
unsigned long lastPulseTime = 0;
float flowReadings[10];
Ultrasonic ultrasonic(ultrasonicPin);
unsigned long lastLevelCheck = 0;

void setup() {
  Serial.begin(115200);
  
  // Configuration des pins
  pinMode(pumpWaterPin, OUTPUT);
  pinMode(pumpGrenadinePin, OUTPUT);
  pinMode(pumpCircuitPin, OUTPUT);
  pinMode(transferPumpPin, OUTPUT);
  pinMode(transferValvePin, OUTPUT);
  pinMode(flowSensorPin, INPUT_PULLUP);
  
  // Tout éteint au départ
  digitalWrite(pumpWaterPin, LOW);
  digitalWrite(pumpGrenadinePin, LOW);
  digitalWrite(pumpCircuitPin, LOW);
  digitalWrite(transferPumpPin, LOW);
  digitalWrite(transferValvePin, LOW);
  
  Serial.println("========================================");
  Serial.println("  REGULATEUR DE VISCOSITE");
  Serial.println("========================================");
  Serial.print("Viscosité cible: ");
  Serial.print(VISCOSITE_CIBLE);
  Serial.println(" cP");
  Serial.print("Tolérance débit: +/- ");
  Serial.print(TOLERANCE_DEBIT * 100);
  Serial.println("%\n");
  
  // Attente de 3 secondes avant de démarrer
  Serial.println("Démarrage dans 3 secondes...");
  delay(3000);
  
  // ETAPE 1: Injection initiale d'eau
  Serial.println("\n=== INJECTION INITIALE D'EAU ===");
  digitalWrite(pumpWaterPin, HIGH);
  Serial.println("Pompe eau: ON (5 secondes)");
  delay(5000);
  digitalWrite(pumpWaterPin, LOW);
  Serial.println("Pompe eau: OFF\n");
  
  delay(2000); // Pause pour stabilisation
  
  // Boucle de régulation
  regulateViscosity();
}

void loop() {
  // Programme terminé, ne fait rien
}

void regulateViscosity() {
  int iteration = 1;
  
  while (true) {
    // Vérification du niveau toutes les 5 secondes
    if (millis() - lastLevelCheck >= 5000) {
      checkLevel();
      lastLevelCheck = millis();
    }
    
    Serial.println("========================================");
    Serial.print("ITERATION #");
    Serial.println(iteration);
    Serial.println("========================================\n");
    
    // Mesure du débit
    float avgFlow = measureFlow();
    
    // Calcul de la viscosité mesurée par interpolation
    // Points d'étalonnage : (1, 0.815), (750, 0.772), (1500, 0.688)
    float viscositeMesuree;
    
    if (avgFlow >= 0.772) {
      // Entre eau et mélange : interpolation linéaire
      // De 0.815 L/min (1 cP) à 0.772 L/min (750 cP)
      viscositeMesuree = 1 + (0.815 - avgFlow) / (0.815 - 0.772) * (750 - 1);
    } else {
      // Entre mélange et grenadine : interpolation linéaire
      // De 0.772 L/min (750 cP) à 0.688 L/min (1500 cP)
      viscositeMesuree = 750 + (0.772 - avgFlow) / (0.772 - 0.688) * (1500 - 750);
    }
    
    // Limite les valeurs entre 1 et 1500 cP
    if (viscositeMesuree < 1) {
      viscositeMesuree = 1;
      Serial.println(">>> (Débit très élevé, viscosité limitée à 1 cP)");
    }
    if (viscositeMesuree > 1500) {
      viscositeMesuree = 1500;
      Serial.println(">>> (Débit très faible, viscosité limitée à 1500 cP)");
    }
    
    Serial.print("\n>>> Viscosité mesurée: ");
    Serial.print(viscositeMesuree, 1);
    Serial.println(" cP");
    
    // Calcul du débit cible par interpolation inverse
    float debitCible;
    
    if (VISCOSITE_CIBLE <= 750) {
      // Entre eau et mélange
      debitCible = 0.815 - (VISCOSITE_CIBLE - 1) / (750 - 1) * (0.815 - 0.772);
    } else {
      // Entre mélange et grenadine
      debitCible = 0.772 - (VISCOSITE_CIBLE - 750) / (1500 - 750) * (0.772 - 0.688);
    }
    
    Serial.print(">>> Débit cible: ");
    Serial.print(debitCible, 2);
    Serial.print(" L/min  |  Débit mesuré: ");
    Serial.print(avgFlow, 2);
    Serial.println(" L/min");
    
    // Calcul de l'écart sur le débit
    float ecartDebit = abs(avgFlow - debitCible) / debitCible;
    Serial.print(">>> Écart débit: ");
    Serial.print(ecartDebit * 100, 1);
    Serial.println("%");
    
    // PREMIERE ITERATION : on ignore et on passe à la suivante
    if (iteration == 1) {
      Serial.println("\n--> Première itération: aucun ajustement");
      Serial.println("Pause de stabilisation (2 sec)...\n");
      delay(2000);
      iteration++;
      continue;
    }
    
    // Vérification si dans la tolérance (à partir de l'itération 2)
    if (ecartDebit <= TOLERANCE_DEBIT) {
      Serial.println("\n*** DEBIT CIBLE ATTEINT! ***\n");
      transferMixture();
      Serial.println("\n========================================");
      Serial.println("  PROCESSUS TERMINE AVEC SUCCES");
      Serial.println("========================================\n");
      break;
    }
    
    // Ajustement nécessaire
    if (avgFlow > debitCible) {
      // Débit trop élevé (trop fluide) => Ajouter grenadine
      Serial.println("\n--> Débit trop élevé: Ajout de GRENADINE (3 sec)");
      digitalWrite(pumpGrenadinePin, HIGH);
      delay(3000);
      digitalWrite(pumpGrenadinePin, LOW);
    } else {
      // Débit trop faible (trop visqueux) => Ajouter eau
      Serial.println("\n--> Débit trop faible: Ajout d'EAU (3 sec)");
      digitalWrite(pumpWaterPin, HIGH);
      delay(3000);
      digitalWrite(pumpWaterPin, LOW);
    }
    
    Serial.println("Pause de stabilisation (2 sec)...\n");
    delay(2000);
    
    iteration++;
  }
}

float measureFlow() {
  Serial.println("=== MESURE DU DEBIT ===");
  Serial.println("Pompe circuit: ON");
  digitalWrite(pumpCircuitPin, HIGH);
  
  // 10 mesures de 1 seconde chacune
  for (int i = 0; i < 10; i++) {
    pulseCount = 0;
    unsigned long startTime = millis();
    
    // Mesure pendant 1 seconde
    while (millis() - startTime < 1000) {
      int currentState = digitalRead(flowSensorPin);
      
      if (lastState == HIGH && currentState == LOW) {
        unsigned long currentTime = millis();
        if (currentTime - lastPulseTime > minPulseInterval) {
          pulseCount++;
          lastPulseTime = currentTime;
        }
      }
      lastState = currentState;
    }
    
    // Calcul du débit
    float flowRate = (pulseCount / 450.0) * 60.0;
    flowReadings[i] = flowRate;
    
    Serial.print("Mesure ");
    Serial.print(i + 1);
    Serial.print("/10: ");
    Serial.print(flowRate, 2);
    Serial.println(" L/min");
  }
  
  // Arrêt de la pompe
  digitalWrite(pumpCircuitPin, LOW);
  Serial.println("Pompe circuit: OFF");
  
  // Calcul de la moyenne
  float sum = 0;
  for (int i = 0; i < 10; i++) {
    sum += flowReadings[i];
  }
  float avgFlow = sum / 10.0;
  
  Serial.print("\nDébit moyen: ");
  Serial.print(avgFlow, 2);
  Serial.println(" L/min");
  
  return avgFlow;
}

void transferMixture() {
  Serial.println("\n=== TRANSFERT DU MELANGE ===");
  Serial.println("Pompe transfert + Vanne: ON (30 sec)");
  
  digitalWrite(transferPumpPin, HIGH);
  digitalWrite(transferValvePin, HIGH);
  
  delay(30000);
  
  digitalWrite(transferPumpPin, LOW);
  digitalWrite(transferValvePin, LOW);
  
  Serial.println("Pompe transfert + Vanne: OFF");
  Serial.println("Transfert terminé!");
}

void checkLevel() {
  long distance = ultrasonic.MeasureInCentimeters();
  
  Serial.print("[NIVEAU] Distance: ");
  Serial.print(distance);
  Serial.println(" cm");
  
  if (distance < NIVEAU_MIN) {
    Serial.println("\n!!! ALERTE: RISQUE DE DEBORDEMENT !!!");
    Serial.print("Distance mesurée: ");
    Serial.print(distance);
    Serial.print(" cm < ");
    Serial.print(NIVEAU_MIN);
    Serial.println(" cm");
    
    // Arrêt de toutes les pompes
    digitalWrite(pumpWaterPin, LOW);
    digitalWrite(pumpGrenadinePin, LOW);
    digitalWrite(pumpCircuitPin, LOW);
    
    Serial.println("\n=== VIDANGE D'URGENCE ===");
    
    // Vidange
    digitalWrite(transferPumpPin, HIGH);
    digitalWrite(transferValvePin, HIGH);
    
    delay(30000);
    
    digitalWrite(transferPumpPin, LOW);
    digitalWrite(transferValvePin, LOW);
    
    Serial.println("\n========================================");
    Serial.println("  ERREUR: NIVEAU CRITIQUE ATTEINT");
    Serial.println("  Vidange effectuée - Programme arrêté");
    Serial.println("========================================\n");
    
    // Arrêt du programme
    while(1) {
      delay(1000);
    }
  }
}