Need Help, Weight Chain

Dear ALL, I’m very new on arduino :confused: ,
I need help to solve at my project.

Description on my project
I use load cell, motor stepper (to move chain), motor servo (to reject product), LCD, Keypad
and the Function
If I push button “A” Motor running
If I push button “B” load cell Weighing after 2 second arduino will decided good/bad product and send order to servo to move from position 0 to 90.(problem motor servo can’t hold position at least 2 second) another problem how to make motor stepper move after 2 second arduino decide good/bad product)

Problem:

  1. How to show up the text on LCD while i turn on the motor(Fyi, i already try to combine on void motor i input “program LCD” but the result is LCD blank and motor run very slow?
  2. How to make servo at pos 90’(bad) little bit hold the position while we push the product?
  3. How to make stepper move while arduino decide product good/bad?

Thanks
Best Regards

Doni

this is the program:(i combine all programs as possible)

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Keypad.h>
#include <HX711_ADC.h>
#include <EEPROM.h>
#include <Servo.h>

//Servo
Servo servo;
int pos = 0;

// Keypad
const byte ROWS = 4;
const byte COLS = 4;
char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {46, 44, 42, 40};
byte colPins[COLS] = {38, 36, 34, 32};
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

// LCD
LiquidCrystal_I2C lcd(0x27, 20, 4);

//HX711
const int HX711_dout = 6; //mcu > HX711 dout pin
const int HX711_sck = 7; //mcu > HX711 sck pin
const int calVal_calVal_eepromAdress = 0;
long t;
HX711_ADC LoadCell(HX711_dout, HX711_sck);

//Sensor PX dan IR
int ir = 31;
int px = 30;

unsigned long preMil = 0;
unsigned long previousMicros = 0;
const long interval = 1500;
int PULPin = 3;    // PUL- pin
int DIRPin = 2;    // DIR- pin
int PULState = HIGH;
int B = 0;
float j;
float i;


void setup() {
  // servo
  servo.attach(9);

  // Setup HX711
  Serial.begin(9600); delay(10);
  Serial.println();
  Serial.println("Starting...");

  float calibrationValue; // calibration value
  calibrationValue = 696.0; // uncomment this if you want to set this value in the sketch
#if defined(ESP8266) || defined(ESP32)
#endif
  value from eeprom

  LoadCell.begin();
  long stabilizingtime = 2000; // tare preciscion 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()) {
    Serial.println("Timeout, check MCU>HX711 wiring and pin designations");
  }
  else {
    LoadCell.setCalFactor(calibrationValue); // set calibration factor (float)
    Serial.println("Startup is complete");
  }
  while (!LoadCell.update());
  Serial.print("Calibration value: ");
  Serial.println(LoadCell.getCalFactor());
  Serial.print("HX711 measured conversion time ms: ");
  Serial.println(LoadCell.getConversionTime());
  Serial.print("HX711 measured sampling rate HZ: ");
  Serial.println(LoadCell.getSPS());
  Serial.print("HX711 measured settlingtime ms: ");
  Serial.println(LoadCell.getSettlingTime());
  Serial.println("Note that the settling time may increase significantly if you use delay() in your sketch!");
  if (LoadCell.getSPS() < 7) {
    Serial.println("!!Sampling rate is lower than specification, check MCU>HX711 wiring and pin designations");
  }
  else if (LoadCell.getSPS() > 100) {
    Serial.println("!!Sampling rate is higher than specification, check MCU>HX711 wiring and pin designations");
  }

  //Setup LCD
  lcd.clear();
  lcd.begin();
  lcd.backlight();

  //Setup Stepper
  pinMode (PULPin, OUTPUT);
  pinMode (DIRPin, OUTPUT);

  //Setup Sensor PX dan IR
  pinMode(px, INPUT);
  pinMode(ir, INPUT);
}

void MSON()//Motor Stepper ON
{
  digitalWrite(DIRPin, LOW);
  unsigned long currentMicros = micros();
  if (currentMicros - previousMicros >= interval)
  {
    previousMicros = currentMicros;
    if (PULState == HIGH)
    {
      PULState = LOW;
    }
    else {
      PULState = HIGH;
    }
    digitalWrite(PULPin, PULState);
  }
  //  unsigned long curMil = millis();
  //  if (curMil - preMil >= 100)
  //  {preMil = curMil;

  //  }
}

void weighing()
{
  lcd.print("weight : ");
  lcd.setCursor(15, 2);
  lcd.print("gram");

  static boolean newDataReady = 0;
  const int serialPrintInterval = 500; //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);
      float j = i / 10;
      lcd.setCursor(8, 2);
      lcd.print(j);
      if (j >= 60 && j <= 71.0)
      {
        lcd.setCursor(0, 3);
        lcd.print("Good");
      }
      if (j < 60 || j > 71.0)
      {
        lcd.setCursor(0, 3);
        lcd.print("Bad");
      }
      newDataReady = 0;
      t = millis();
    }
  }

  // receive command from serial terminal, send 't' to initiate tare operation:
  if (Serial.available() > 0)
  {
    float i;
    char inByte = Serial.read();
    if (inByte == 't') LoadCell.tareNoDelay();
  }

  // check if last tare operation is complete:
  if (LoadCell.getTareStatus() == true)
  {
    Serial.println("Tare complete");
  }

}

void loop()
{
  if (B == 0)
  {
    lcd.setCursor(0, 0);
    lcd.print("Tekan tombol untuk");
    lcd.setCursor(1, 1);
    lcd.print("A : START MOTOR");
    lcd.setCursor(2, 2);
    lcd.print("B : START Weighing");
  }
  char customKey = customKeypad.getKey();
  switch (customKey)

    if (B == 3)
    {
      lcd.setCursor(0, 0);
      lcd.print("Press button for");
      lcd.setCursor(1, 1);
      lcd.print("A : START MOTOR");
      lcd.setCursor(2, 2);
      lcd.print("B : START Weighing");
    }
  if (B == 1)
  { MSON();
  }
  if (B == 2)
  {
    for (int x = 0; x < 201 ; x++)
    { weighing();
      Serial.println("Progress Weighing");
    }
    for (int x = 200; x >= 1 ; x--)
    {
      Serial.println("Servo");
      if (j >= 60 && j <= 71.0)
      {
        Serial.println("good");
        servo.write(0);
      }
      else
      { Serial.println("bad");
        servo.write(90);
      }
      lcd.clear();
      B = 1;
    }
  }
}

please place [code ] tags around your sketch, it will make it much easier to read

OK. Thanks for your advice. now better.

@doni09, please also use the AutoFormat tool to lay out your code consistently. You have several different styles for blocks of code and it makes it too difficult to read.

...R

:smiley: OK, already use the Autoformat. thanks a lot for your advice.

I would use “flags” to syncronize the project.

bool servoRejecting = false; // servo reject flag, to prevent stuff from happening while rejecting product
uint32_t servoRejTime = 0; // to keep track of rejection time
uint16_t servoRejLimit = 2000;
in your void loop()

else
{ Serial.println(“bad”);
servo.write(90);
servoRejecting = true;
servoRejTime = millis();
}

// the if-statement below is implemented as a way of prohibiting the servo to return to 0 (good).
if (servoRejecting) {
if (millis() - servoRejTime >= servoRejLimit) {
servoRejecting = false;
servo.write(0);
}
}

} // end loop

To write stuff to display:
#define motorStart 1
#define motorStop 2
#define servoKeep 3
#define servoReject 4

uint8_t displayData = 0;
uint32_t lastDisplayUpdate = 0;
uint16_t displayInterval = 1000; // interval between each display update

void loop{
… // other stuff in your code
if (millis() - lastDisplayUpdate >= displayInterval) {
switch (displayData) {
case motorStart: {
lcd.write(“motor started”);
displayData = 0;
lastDisplayUpdate = millis();
} break;
case servoReject: {
lcd.write(“Rejected chain”);
displayData = 0;
lastDisplayUpdate = millis();
} break;
} // end switch
} // end loop

void MSON() {
if (!servoRejecting) { // run motor only while not rejecting the product
displayData = motorStart;
… // the rest of the code
} // end if !rejecting
else { // we are rejecting the product
// do other stuff while waiting…
}
} // end MSON

Im using a LCD in my project too and im very fond of macros, to simplify the code a bit.
for example:

#define reportWeight(text1,text2,text3) lcd.home(); lcd.print(text1); lcd.setCursor(15,2); lcd.print(text2); lcd.print(text3); // << defined a macro “reportWeight”

uint8_t measuredWeight = 0;

void loop() {
reportWeight("weight : ",measuredWeight ,“gram”);
}
this would be translated by the compiler into:
void loop() {
lcd.home();
lcd.print("weight : ");
lcd.setCursor(15,2);
lcd.print(“0”); // havent updated “measuredWeight” in my example…
lcd.print("gram);
}

OK, i will learn it and try it.Thanks a lot for your time and advice.

@doni09, you have a variable named B which seems to be important but that is a meaningless name so I have no idea what it is intended to represent. Also, don't use single character variable names (except in a FOR loop) as it is impossible to find them all with a search

You have this line

switch (customKey)

but there are no associated CASE statements

And at line 65 there is this

value from eeprom

which, I assume, will cause a compile error

And if you make changes to your program please post the revised version in your next Reply so that it can, if necessary, be compared with the original version.

...R

dear @xarvox, can you give me more detail the position whrere i must put your code, example this side

bool servoRejecting = false;  // servo reject flag, to prevent stuff from happening while rejecting product
uint32_t servoRejTime = 0;  // to keep track of rejection time
uint16_t servoRejLimit = 2000;
in your void loop()
  ....
    else
     { Serial.println("bad");
       servo.write(90);
       servoRejecting = true;
       servoRejTime = millis();
      }
   ....

// the if-statement below is implemented as a way of prohibiting the servo to return to 0 (good).
 if (servoRejecting) {
    if (millis() - servoRejTime >= servoRejLimit) {
      servoRejecting = false;
      servo.write(0);
    }
 }
......
} // end loop

sory for my miss understanding, I littel bit confuse about that.

@Robin2

for this side Code: [Select]
switch (customKey)

yeah I'm wrong, because if I want to use the keypad i must write the commend like this
"char customKey = customKeypad.getKey();
switch (customKey)"
because i want push the button (exmp "A","B" or "C") to easy run the void

thanks for the correction and line 65 it is from library.

I will fix my problem and i will update.

I'm still stuck at where 2 motor can running together ( motor stepper, motor servo) motor stepper for move second product forward to push first product goes to reject area. and try build program from xarvox to make motor servo hold the position

my previous reply was a bit vague, so ill try to be more specific. :slight_smile:

Before we start; im unsure of your timing requirements, but the function “micros()” returns the number of microseconds since boot/reset and overflows (goes from max value back to minimum) in about 70 minutes.
1 second = 1 000 000 microseconds.

the function “millis()” returns the same type of values, but in milliseconds instead, giving you 49 days or so before overflowing.
1 second = 1000 milliseconds, 1 millisecond = 1000 microseconds.

I prefer a function to check if time has elapsed, just to clear up the code, but im not like everyone i guess. :slight_smile:

// global variables:
// unsigned long is the same as uint32_t..
uint32_t NOW = 0; // container to store "now-value"
uint32_t lastServo = 0;   // container to store the last servo update time (last NOW)
uint32_t servoLimit = 2000;  // limiter, dont use/reset servo within this limit.

void checkElapsed(uint32_t timer, uint32_t limiter) {
  return NOW - timer > limiter ;
}

// use where needed:
void loop() {
  NOW = millis();  // this line saves "current" millis() into the variable NOW.
  if (checkElapsed(lastServo,servoLimit) { // check if time elapsed is more than limit
     lastServo = NOW;                             // store new last updated time
     // do the servo stuff
  }
}

The code above is a simple replacement for the “delay()” function and the “delay()” should be avoided since it locks up the controller during the delay (it wont take input or do anything else).

Now, in order to reject your product, the servo needs to go to 90degrees and hold that position for 2 seconds.
During that time you dont want to use the motor to feed more product into the servo, if i understand you correctly.

So by adding a few flags (bool variable) to check for, we can control if we should change the servo position or not.

// global variables
bool servoIsRejecting = false; // will be set to true while the servo is rejecting
bool doReject = false; // will be set to true when we need to reject the product

//check weight...
void checkWeight() { // not your function, just an example..
  if (weight < minVal || weight > maxVal) {
    doReject = true;
  }
} // end example function

void loop() {
  NOW = millis(); // store current "time"
  if (!servoIsRejecting) {       // if we´re NOT rejecting workpiece (note the ! before variable)
    // feed next item into the weigh station
    MSON();
  }

  checkWeight();  // check weight

  if (doReject) {  // if we want to reject current workpiece
    if (servoIsRejecting) { // and we´re already rejecting the workpiece
      if (checkElapsed(lastServo,servoLimit) { // check if time has elapsed
        servoIsRejecting = false;  // time has elapsed, reset the flags and return the servo to home position
        doReject = false;
        servo.write(0);
      }
    } // end servoISRejecting
    else {                            // else, we´re not already rejecting the workpiece
      servoIsRejecting = true; // set the rejection flag
      lastServo = NOW;     // store the current time
      servo.write(90);      // and set the servo to reject position
    }
  }// end doReject
} // end loop

By doing it “my” way, your controller is free to do other stuff while waiting, write to LCD or serial for instance.
The loop keeps cycling thru the code, but the flags wont reset until the time has elapsed.

I can rewrite your program for you, but im guessing its for a commercial business witch means i would have to charge you for it… :slight_smile:

@xarvox thanks a lot for your reply, I will learn it an try it. And FYI this is not for commercial business. to be honest this is not for selling I build this for improve our production. home industry. if you need prove i will send the pictures to you. :smiley:

I think you misunderstood me. I don't think you're selling the project code, i think the program is to be installed in a production line that generates an income. :slight_smile:
A home industry would usually be considered a commercial business, at least if its making money.

In other words, suggestions and some support is free, but if i were to make something for you (while you make money off my work), i should be compensated. :slight_smile:

ok, I understand now, I will try if I cant maybe we can bargain the cost with you XP. thanks again

The best way to learn i by doing :slight_smile:
I remember when i was "your age", it was so darn hard to understand what folks were trying to tell me, but the most important thing is not to give up, eventually things become clear(er).

yess, agree. thanks for your support. I can do this. ;D

Dear all sory for late reaply. i just want to say thanks for your support. and I got this program.

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Keypad.h>
#include <EEPROM.h>
#include <Servo.h>
#include "HX711.h"
#define DOUT A2
#define CLK A3
#define IP A1

//LoadCell
HX711 scale(DOUT, CLK);
float calibration_factor = 688.50;
float G;

//Servo
Servo servo;

// Keypad
const byte ROWS = 4;
const byte COLS = 4;
char hexaKeys[ROWS][COLS] = {
 {'1', '2', '3', 'A'},
 {'4', '5', '6', 'B'},
 {'7', '8', '9', 'C'},
 {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {32, 34, 36, 38};
byte colPins[COLS] = {40, 42, 44, 46};
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

// LCD
LiquidCrystal_I2C lcd(0x27, 20, 4);

int B = 0;
const int str = 28;
const int stp = 29;
int IR = 30;
int IPV = 0;


//buzzer
const int Bz = 11;
int bzstate = HIGH;
unsigned long pm = 0;
const long itr = 750;

void Weight()
{
 scale.set_scale(calibration_factor);
 G = (scale.get_units()) / 10;
 Serial.println(G);
 lcd.print("g");
 lcd.setCursor(8, 2);
 lcd.print(G);
 if (G >= 69.2 && G <= 70.09)
     {
       lcd.setCursor(0,3);
       lcd.print("GOOD");
     }
 else if (G < 5 )
     {
       lcd.setCursor(0,3);
       lcd.print("    ");
     }
 else 
     {
      lcd.setCursor(0,3);
      lcd.print(" BAD"); 
       }    
 
}
void Weight1()
{
 scale.set_scale(calibration_factor);
 G = (scale.get_units()) / 10;
 Serial.println(G);
 lcd.setCursor(3, 0);
 lcd.print("No Weight");
 lcd.setCursor(0, 2);
 lcd.print("Weight : ");
 lcd.setCursor(18, 2);
 lcd.print("g");
 lcd.setCursor(8, 2);
 lcd.print(G); 
}
void buzzer()
{
 unsigned long cm = millis();
 if (cm - pm >= itr) {
   pm = cm;
   if (bzstate == HIGH) {
     bzstate = LOW;
   } else {
     bzstate = HIGH;
   }
   digitalWrite(Bz, bzstate);
 }
}

void setup() {
 //LoadCell
 Serial.begin(9600);
 scale.set_scale();
 scale.tare();

 // IR IP
 pinMode (IR, INPUT);
 pinMode (IP, INPUT);

 //Setup step
 pinMode(str, OUTPUT);
 pinMode(stp, OUTPUT);
 digitalWrite(str, LOW);
 digitalWrite(stp, LOW);

 //Setup LCD
 lcd.clear();
 lcd.begin();
 lcd.backlight();
 delay (2000);

 // servo
 servo.attach(8);
 servo.write(0);


 //Setup LCD
 lcd.clear();
 lcd.begin();
 lcd.backlight();

 //Setup bz
 pinMode(Bz, OUTPUT);
 digitalWrite(Bz, LOW);
 delay(50);
 for (int x = 0; x < 100 ; x++)
 {
   Weight1();
   if (G < -0.2 || G > 0.2)
   {
     digitalWrite(Bz, LOW);
   }
   else {
     digitalWrite(Bz, HIGH);
   }
 }
 digitalWrite(Bz, HIGH);
 lcd.clear();
}

void loop()
{
 if (B == 0)
 {
   digitalWrite(str, LOW);
   digitalWrite(stp, LOW);
   lcd.setCursor(1, 0);
   lcd.print("A : START");
   lcd.setCursor(1, 1);
   lcd.print("B : RESTART");
   lcd.setCursor(1, 2);
   lcd.print("C : HOME");
   lcd.setCursor(1, 3);
   lcd.print("D : WEIGHT");
 }
 char customKey = customKeypad.getKey();
 switch (customKey)
 {
   case 'A':
     B = 1;
     lcd.clear();
     break;
   case 'B':
     setup();
     lcd.clear();
     B = 0;
     break;
   case 'C':
     B = 0;
     lcd.clear();
     break;
   case 'D':
     B = 2;
     lcd.clear();
     break;
 }
 if (B == 1)
 {
   digitalWrite(str, HIGH);
   digitalWrite(stp, LOW);
   lcd.setCursor(0, 1);
   lcd.print("Motor Run");
   lcd.clear();
 }
 IPV = analogRead(IP);
 if (digitalRead(IR) == 0 && B == 1)
 {
   digitalWrite(stp, HIGH);
   digitalWrite(str, LOW);
   for (int x = 0; x < 28 ; x++)
   {
     digitalWrite(stp, HIGH);
     digitalWrite(str, LOW);
     Weight();
     servo.write(0);
   }
   digitalWrite(stp, LOW);
   digitalWrite(str, HIGH);
   for (int y = 60; y >= 1 ; y--)
   {
     Serial.println("Servo");
     if (G < 69.2 || G > 70.09)
     {
       servo. write(30);
       buzzer();
     }
     else
     {
       servo.write(0);
     }
     lcd.clear();
     lcd.setCursor(0, 1);
     lcd.print("Motor Run");
     lcd.clear();
     if ( y == 1)
     {
       servo.write(0);
     }
     digitalWrite(Bz, HIGH);
     B = 1;

   }
 }
 if (B == 2)
 {
   digitalWrite(str, LOW);
   digitalWrite(stp, LOW);
   Weight();
 }
}

But i have another problem. noise from loadcell/HX711 load cell cant reach stabil , during running the reading wigth rise from 0,03-0,08 up to 0,1 until 0,2 that make the result not same on product, any one know?

doni09:
But i have another problem. noise from loadcell/HX711 load cell cant reach stabil , during running the reading wigth rise from 0,03-0,08 up to 0,1 until 0,2 that make the result not same on product, any one know?

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

How far is the loadcell from the module and the controller?
What are you using for a power supply?

Thanks.. Tom.. :slight_smile: :slight_smile:

Dear TomGeorge,

This is the picture, please check, and for the distance already on picture. yes i use power supply. loadcell to HX711 78 CM and hx to power supply and arduino 20 cm

I hope my problem can be solved

Thanks

Best Regards

Doni Susanto

Hi,
OPs circuit;


Have you got gnd of the module connected to gnd of the controller?
What model controller are you using?
What voltage is the powersupply?
Is this your complete circuit?

Thanks.. Tom.. :slight_smile:

Dear TomGeorge,
I forget to drawing it, but connect to PSU the GND,
model controler arduino Mega 2560,
PSU is 5 V
this is not complete circuit, only load cell to arduino

thanks

Best Regards

Doni Susanto