Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2024:iotelea:dalya.tobescu [2024/05/26 21:52]
dalya.tobescu
pm:prj2024:iotelea:dalya.tobescu [2024/05/26 23:04] (current)
dalya.tobescu
Line 98: Line 98:
 {{:​pm:​prj2024:​iotelea:​whatsapp_image_2024-05-26_at_19.38.50.jpeg?​500}} {{:​pm:​prj2024:​iotelea:​whatsapp_image_2024-05-26_at_19.38.50.jpeg?​500}}
  
-Am rezolvat problema cu Black Boxes, adaugand un potentiomtru ​cu ajutorul caruia setez luminozitatea ecranului. Am adaugat led-ul care imi indica cand cantarul este in Plate Function si un buton cu care intru in Plate Function.+Am rezolvat problema cu Black Boxes, adaugand un potentiometru ​cu ajutorul caruia setez luminozitatea ecranului. Am adaugat led-ul care imi indica cand cantarul este in Plate Function si un buton cu care intru in Plate Function.
  
 ===== Software Design ===== ===== Software Design =====
  
 +==Inainte de orice implementare software, a trebuit sa calibrez celula de incarcare:​==
 +1) Am pregatit un obiect cu o greutate cunoscută. Mi-am folosit cântarul de bucătărie și am cântărit o sticluta de parfum (160g).
 +
 +2) Am incarcat următorul cod pe placa Arduino. Am scris următorul cod ținând cont de instrucțiunile de calibrare a celulei de sarcină furnizate de documentația bibliotecii.
 +
 +3) Am determinat factorul de calibrare si l-am inclus in codul proiectului meu.
 +
 +<​code>​
 +
 +#include <​HX711_ADC.h>​
 +#if defined(ESP8266)|| defined(ESP32) || defined(AVR)
 +#include <​EEPROM.h>​
 +#endif
 +
 +//pins:
 +const int HX711_dout = 2; //mcu > HX711 dout pin
 +const int HX711_sck = 3; //mcu > HX711 sck pin
 +
 +//HX711 constructor:​
 +HX711_ADC LoadCell(HX711_dout,​ HX711_sck);
 +
 +const int calVal_eepromAdress = 0;
 +unsigned long t = 0;
 +
 +void setup() {
 +  Serial.begin(57600);​ delay(10);
 +  Serial.println();​
 +  Serial.println("​Starting..."​);​
 +
 +  LoadCell.begin();​
 +  //​LoadCell.setReverseOutput();​ //uncomment to turn a negative output value to positive
 +  unsigned long stabilizingtime = 2000; // preciscion right after power-up can be improved by adding a few seconds of stabilizing time
 +  boolean _tare = true; //set this to false if you don't want tare to be performed in the next step
 +  LoadCell.start(stabilizingtime,​ _tare);
 +  if (LoadCell.getTareTimeoutFlag() || LoadCell.getSignalTimeoutFlag()) {
 +    Serial.println("​Timeout,​ check MCU>​HX711 wiring and pin designations"​);​
 +    while (1);
 +  }
 +  else {
 +    LoadCell.setCalFactor(1.0);​ // user set calibration value (float), initial value 1.0 may be used for this sketch
 +    Serial.println("​Startup is complete"​);​
 +  }
 +  while (!LoadCell.update());​
 +  calibrate();​ //start calibration procedure
 +}
 +
 +void loop() {
 +  static boolean newDataReady = 0;
 +  const int serialPrintInterval = 0; //increase value to slow down serial print activity
 +
 +  // check for new data/start next conversion:
 +  if (LoadCell.update()) newDataReady = true;
 +
 +  // get smoothed value from the dataset:
 +  if (newDataReady) {
 +    if (millis() > t + serialPrintInterval) {
 +      float i = LoadCell.getData();​
 +      Serial.print("​Load_cell output val: ");
 +      Serial.println(i);​
 +      newDataReady = 0;
 +      t = millis();
 +    }
 +  }
 +
 +  // receive command from serial terminal
 +  if (Serial.available() > 0) {
 +    char inByte = Serial.read();​
 +    if (inByte == '​t'​) LoadCell.tareNoDelay();​ //tare
 +    else if (inByte == '​r'​) calibrate();​ //calibrate
 +    else if (inByte == '​c'​) changeSavedCalFactor();​ //edit calibration value manually
 +  }
 +
 +  // check if last tare operation is complete
 +  if (LoadCell.getTareStatus() == true) {
 +    Serial.println("​Tare complete"​);​
 +  }
 +
 +}
 +
 +void calibrate() {
 +  Serial.println("​***"​);​
 +  Serial.println("​Start calibration:"​);​
 +  Serial.println("​Place the load cell an a level stable surface."​);​
 +  Serial.println("​Remove any load applied to the load cell."​);​
 +  Serial.println("​Send '​t'​ from serial monitor to set the tare offset."​);​
 +
 +  boolean _resume = false;
 +  while (_resume == false) {
 +    LoadCell.update();​
 +    if (Serial.available() > 0) {
 +      if (Serial.available() > 0) {
 +        char inByte = Serial.read();​
 +        if (inByte == '​t'​) LoadCell.tareNoDelay();​
 +      }
 +    }
 +    if (LoadCell.getTareStatus() == true) {
 +      Serial.println("​Tare complete"​);​
 +      _resume = true;
 +    }
 +  }
 +
 +  Serial.println("​Now,​ place your known mass on the loadcell."​);​
 +  Serial.println("​Then send the weight of this mass (i.e. 100.0) from serial monitor."​);​
 +
 +  float known_mass = 0;
 +  _resume = false;
 +  while (_resume == false) {
 +    LoadCell.update();​
 +    if (Serial.available() > 0) {
 +      known_mass = Serial.parseFloat();​
 +      if (known_mass != 0) {
 +        Serial.print("​Known mass is: ");
 +        Serial.println(known_mass);​
 +        _resume = true;
 +      }
 +    }
 +  }
 +
 +  LoadCell.refreshDataSet();​ //refresh the dataset to be sure that the known mass is measured correct
 +  float newCalibrationValue = LoadCell.getNewCalibration(known_mass);​ //get the new calibration value
 +
 +  Serial.print("​New calibration value has been set to: ");
 +  Serial.print(newCalibrationValue);​
 +  Serial.println(",​ use this as calibration value (calFactor) in your project sketch."​);​
 +  Serial.print("​Save this value to EEPROM adress ");
 +  Serial.print(calVal_eepromAdress);​
 +  Serial.println("?​ y/n");
 +
 +  _resume = false;
 +  while (_resume == false) {
 +    if (Serial.available() > 0) {
 +      char inByte = Serial.read();​
 +      if (inByte == '​y'​) {
 +#if defined(ESP8266)|| defined(ESP32)
 +        EEPROM.begin(512);​
 +#endif
 +        EEPROM.put(calVal_eepromAdress,​ newCalibrationValue);​
 +#if defined(ESP8266)|| defined(ESP32)
 +        EEPROM.commit();​
 +#endif
 +        EEPROM.get(calVal_eepromAdress,​ newCalibrationValue);​
 +        Serial.print("​Value ");
 +        Serial.print(newCalibrationValue);​
 +        Serial.print("​ saved to EEPROM address: ");
 +        Serial.println(calVal_eepromAdress);​
 +        _resume = true;
 +
 +      }
 +      else if (inByte == '​n'​) {
 +        Serial.println("​Value not saved to EEPROM"​);​
 +        _resume = true;
 +      }
 +    }
 +  }
 +
 +  Serial.println("​End calibration"​);​
 +  Serial.println("​***"​);​
 +  Serial.println("​To re-calibrate,​ send '​r'​ from serial monitor."​);​
 +  Serial.println("​For manual edit of the calibration value, send '​c'​ from serial monitor."​);​
 +  Serial.println("​***"​);​
 +}
 +
 +void changeSavedCalFactor() {
 +  float oldCalibrationValue = LoadCell.getCalFactor();​
 +  boolean _resume = false;
 +  Serial.println("​***"​);​
 +  Serial.print("​Current value is: ");
 +  Serial.println(oldCalibrationValue);​
 +  Serial.println("​Now,​ send the new value from serial monitor, i.e. 696.0"​);​
 +  float newCalibrationValue;​
 +  while (_resume == false) {
 +    if (Serial.available() > 0) {
 +      newCalibrationValue = Serial.parseFloat();​
 +      if (newCalibrationValue != 0) {
 +        Serial.print("​New calibration value is: ");
 +        Serial.println(newCalibrationValue);​
 +        LoadCell.setCalFactor(newCalibrationValue);​
 +        _resume = true;
 +      }
 +    }
 +  }
 +  _resume = false;
 +  Serial.print("​Save this value to EEPROM adress ");
 +  Serial.print(calVal_eepromAdress);​
 +  Serial.println("?​ y/n");
 +  while (_resume == false) {
 +    if (Serial.available() > 0) {
 +      char inByte = Serial.read();​
 +      if (inByte == '​y'​) {
 +#if defined(ESP8266)|| defined(ESP32)
 +        EEPROM.begin(512);​
 +#endif
 +        EEPROM.put(calVal_eepromAdress,​ newCalibrationValue);​
 +#if defined(ESP8266)|| defined(ESP32)
 +        EEPROM.commit();​
 +#endif
 +        EEPROM.get(calVal_eepromAdress,​ newCalibrationValue);​
 +        Serial.print("​Value ");
 +        Serial.print(newCalibrationValue);​
 +        Serial.print("​ saved to EEPROM address: ");
 +        Serial.println(calVal_eepromAdress);​
 +        _resume = true;
 +      }
 +      else if (inByte == '​n'​) {
 +        Serial.println("​Value not saved to EEPROM"​);​
 +        _resume = true;
 +      }
 +    }
 +  }
 +  Serial.println("​End change calibration value"​);​
 +  Serial.println("​***"​);​
 +}
 +</​code>​
 +
 +
 +==Descriere detaliată a codului:==
 +==Biblioteci incluse:==
 +* LiquidCrystal.h:​ pentru controlul afișajului LCD.
 +
 +* HX711_ADC.h:​ pentru citirea datelor de la senzorul de greutate HX711.
 +
 +
 +<code c>
 +#include <​LiquidCrystal.h>​
 +#include <​HX711_ADC.h>​
 +</​code>​
 +
 +==Definirea pinilor și inițializarea componentelor:​==
 +
 +* Pinii DOUT_PIN și SCK_PIN sunt definiți pentru senzorul HX711.
 +
 +* Obiectul LoadCell este creat pentru a interacționa cu senzorul HX711.
 +
 +* Pinii pentru afișajul LCD sunt definiți (rs, en, d4, d5, d6, d7), iar obiectul lcd este creat.
 +
 +* Pinii buttonPin, ledPin și plateButton sunt definiți pentru butoanele de control și LED.
 +
 +<​code>​
 +// Define HX711 pins
 +#define DOUT_PIN 2
 +#define SCK_PIN 3
 +
 +// Initialize the HX711
 +HX711_ADC LoadCell(DOUT_PIN,​ SCK_PIN);
 +
 +// Initialize the LCD library with the numbers of the interface pins
 +const int rs = 13, en = 12, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
 +LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
 +
 +const int buttonPin = 8;  // Define the pin for the button
 +const int ledPin = 9; 
 +const int plateButton= 10;
 +</​code>​
 +
 +==Funcția setup:==
 +* Setează pinul ledPin ca ieșire și pinurile buttonPin și plateButton ca intrări.
 +* Inițializează comunicarea serială la 57600 baud.
 +* Inițializează conexiunea la senzorul HX711 și setează factorul de calibrare.
 +* Resetează senzorul la zero.
 +* Inițializează afișajul LCD și afișează un mesaj de bun venit timp de 3 secunde.
 +
 +<​code>​
 +void setup() {
 +  // initialize the LED pin as an output:
 +  pinMode(ledPin,​ OUTPUT);
 +  // initialize the pushbutton pin as an input:
 +  pinMode(buttonPin,​ INPUT);
 +  pinMode(plateButton,​ INPUT);
 +  ​
 +  Serial.begin(57600);​
 +
 +  // Start the connection to HX711
 +  LoadCell.begin();​
 +  LoadCell.start(1000);​ // Allow the load cells to stabilize for 1000ms
 +  LoadCell.setCalFactor(-386.62);​ // Set the calibration factor
 +  // -386.92
 +  // -385.88
 +  LoadCell.tare();​ // Reset the scale to zero
 +
 +  // Initialize the LCD
 +  lcd.begin(16,​ 2);
 +  lcd.setCursor(1,​ 0); // Set cursor to the first row
 +  lcd.print("​Cook Pro"); // Print out to LCD
 +  lcd.setCursor(4,​ 1); // Set cursor to the second row
 +  lcd.print("​Measure"​);​ // Print out to LCD
 +  delay(3000);​
 +  lcd.clear();​
 +}
 +</​code>​
 +
 +==Funcția loop:==
 +* Citirea și afișarea greutății măsurate de senzorul HX711.
 +* Verifică dacă greutatea este stabilă și dacă este prima rulare.
 +* Afișează greutatea pe afișajul LCD, fie ca greutate simplă, fie ca greutate ajustată pentru un suport (tavă).
 +* Gestionează resetarea și funcția de suport prin intermediul butoanelor:
 +* Dacă buttonPin este apăsat, resetează greutatea și afișează mesajul de resetare.
 +* Dacă plateButton este apăsat, activează funcția de suport și afișează mesajul corespunzător.
 +
 +<​code>​
 +
 +void loop() {
 +  static float lastWeight = 0;
 +  static bool isStable = false;
 +  static bool isFirstRun = true;
 +  static bool plate = false;
 +  static float plateWeight = 0;
 +  static int ledBrightness = 0; // Variable to store LED brightness
 +
 +  LoadCell.update();​
 +  float weight = LoadCell.getData();​
 +
 +  Serial.print("​Weight:​ ");
 +  Serial.print(weight,​ 2); // Print the weight with 2 decimal places
 +  Serial.println("​ g");
 +
 +  // Retrieve data from the load cell
 +  if (isFirstRun) {
 +    lastWeight = 0.0; // Set lastWeight to 0.0 for the first run
 +    isFirstRun = false; // Set isFirstRun to false after the first run
 +  }
 +
 +  // Check if weight is stable
 +  if (abs(weight - lastWeight) < 0.05) { // Adjust the threshold as needed
 +    isStable = true;
 +  } else {
 +    isStable = false;
 +  }
 +
 +  if (weight < 0) {
 +    weight = 0;
 +  } else if (weight > 0 && weight < 1) {
 +    weight = 0;
 +  }
 +
 +  if (isStable) {
 +    if (!plate) {
 +      lcd.clear();​
 +      lcd.setCursor(0,​ 0); // Set cursor to the first row
 +      lcd.print("​Weight:​ ");
 +      lcd.print(weight);​ // Print the weight with 2 decimal places
 +      lcd.print("​ g");
 +    } else {
 +      if (weight < 20 && weight > 15) {
 +        plateWeight = weight;
 +        weight = 0;
 +      }
 +      if (weight > plateWeight) {
 +        weight = weight - plateWeight;​
 +      }
 +      lcd.clear();​
 +      lcd.setCursor(0,​ 0); // Set cursor to the first row
 +      lcd.print("​Weight:​ ");
 +      lcd.print(weight);​ // Print the weight with 2 decimal places
 +      lcd.print("​ g");
 +
 +      lcd.setCursor(0,​ 1); // Adjust cursor position
 +      lcd.print("​With plate"​);​
 +    }
 +  }
 +
 +  lastWeight = weight;
 +
 +  // Check if the button is pressed
 +  if (digitalRead(buttonPin) == HIGH) {
 +    analogWrite(ledPin,​ 0); // Turn off the LED
 +    Serial.println("​Reset button pressed"​);​
 +    plate = false;
 +    weight = 0;
 +    lcd.clear();​
 +    lcd.setCursor(0,​ 1); // Set cursor to the second row
 +    lcd.print(" ​   Reset... ​   ");
 +    LoadCell.start(1000);​
 +    LoadCell.tare();​ // Reset the scale to zero
 +    delay(1000);​ // Allow some time for the reset to stabilize
 +    lcd.clear();​
 +  }
 +
 +  // Plate button functionality with PWM
 +  if (digitalRead(plateButton) == HIGH) {
 +    Serial.println("​PLATE FUNCTION"​);​
 +    plate = true;
 +    lcd.clear();​
 +    lcd.setCursor(0,​ 1); // Set cursor to the second row
 +    lcd.print("​ Plate function ");
 +    LoadCell.start(1000);​
 +    LoadCell.tare();​ // Reset the scale to zero
 +    delay(1000);​ // Allow some time for the reset to stabilize
 +    lcd.clear();​
 +
 +    // Gradually increase LED brightness using PWM
 +    for (int brightness = 0; brightness <= 255; brightness += 5) {
 +      analogWrite(ledPin,​ brightness);​
 +      delay(10);
 +    }
 +  }
 +
 +  // Decrease LED brightness over time
 +  if (ledBrightness > 0) {
 +    ledBrightness -= 5;
 +    if (ledBrightness < 0) {
 +      ledBrightness = 0;
 +    }
 +    analogWrite(ledPin,​ ledBrightness);​
 +  }
 +
 +  delay(100); // Update every 100ms
 +}
 +</​code>​
 +
 +==Funcționalități cheie:==
 +* Stabilizarea greutății:​ Codul verifică dacă greutatea citită este stabilă (variația este sub un prag specificat).
 +
 +* Resetare: Butonul de resetare setează greutatea la zero și resetează senzorul.
 +
 +* Funcția de suport: Un buton suplimentar activează o funcție care ajustează greutatea pentru a scădea greutatea suportului (tăvii).
 +
 +* Acest program este util pentru aplicații unde este necesară măsurarea precisă a greutății,​ cum ar fi în bucătării pentru măsurarea ingredientelor sau în alte aplicații de cântărire.
  
-<note tip> 
-TODO 
-</​note>​ 
  
 ===== Rezultate Obţinute ===== ===== Rezultate Obţinute =====
Line 116: Line 530:
  
 ===== Concluzii ===== ===== Concluzii =====
 +
 +Am considerat acest proiect extrem de interesant și util în viața de zi cu zi, oferindu-mi satisfacția de a-l realiza de la zero. Deși am întâmpinat câteva dificultăți,​ în special în partea de calibrare, am reușit să le depășesc. Modulul HX711 este foarte sensibil și necesită o poziționare precisă pentru a măsura corect greutatea. Am rezolvat această problemă adăugând un suport stabil pentru cântar, asigurându-mă că forța aplicată acționează într-o direcție specifică asupra load cell-ului și că toate componentele sunt bine fixate. Această ajustare a fost esențială pentru obținerea unor măsurători precise și consistente.
  
 ===== Download ===== ===== Download =====
  
 <note warning> <note warning>
-TODO+{{:​pm:​prj2024:​iotelea:​cantar_bucatarie.ino.zip|}}
 </​note>​ </​note>​
  
 ===== Jurnal ===== ===== Jurnal =====
- +    * 05.05.2024: Creare pagina wiki 
-    * Trebuie sa rezolv ​problema ​cu Black Boxes+    * 13.05.2024: Comandare piese hardware 
 +    * 15.05.2024: Crearea schemelor pentru circuit 
 +    * 17.05.2024: Asamblarea circuitului hardware 
 +    * 19.05.2024: Rezolvare ​problema ​LCD ului (Black boxes) 
 +    * 20.05.2024: Scriere cod si calibrarea load cell-ului 
 +    * 21.05.2024: Adaugare buton de reset 
 +    * 22.05.2024: Adaugarea butonului de Plate Function si a LED-ului 
 +    * 24.05.2024: Retusarea codului si a circuitului
  
 ===== Bibliografie/​Resurse ===== ===== Bibliografie/​Resurse =====
Line 132: Line 555:
 https://​www.diyengineers.com/​2022/​05/​19/​load-cell-with-hx711-how-to-use-with-examples/​ https://​www.diyengineers.com/​2022/​05/​19/​load-cell-with-hx711-how-to-use-with-examples/​
 https://​nicuflorica.blogspot.com/​2018/​02/​cantar-electronic-pentru-greutati-mic.html https://​nicuflorica.blogspot.com/​2018/​02/​cantar-electronic-pentru-greutati-mic.html
 +
 +==Resurse Software==
 +https://​randomnerdtutorials.com/​arduino-load-cell-hx711
 +
 +https://​www.instructables.com/​Tutorial-How-to-Calibrate-and-Interface-Load-Cell-/​
  
 <​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​Export to PDF</​a></​html>​ <​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​Export to PDF</​a></​html>​
  
pm/prj2024/iotelea/dalya.tobescu.1716749529.txt.gz · Last modified: 2024/05/26 21:52 by dalya.tobescu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0