Weight based Servo Trigger

I have a 20KG Load cell with an HX711 and I am looking to trigger servo movement if the load cell detects a predetermined weight reading.

Is anyone able to please help with the coding for this or point me in the direction of some handy resources, as coding isn’t my strongest point?

Here is the version of the code that I have attempted to “mash together”:

#include "HX711.h"
#include <Servo.h> // Include the Servo library 

#define calibration_factor -7050.0 //This value is obtained using the SparkFun_HX711_Calibration sketch

#define LOADCELL_DOUT_PIN  3
#define LOADCELL_SCK_PIN  2
int servoPin = 5; // Declare the Servo pin 

HX711 scale;

Servo Servo1; // Create a servo object 

void setup() {
  Serial.begin(9600);
  Serial.println("HX711 scale demo");

  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
  scale.set_scale(calibration_factor); //This value is obtained by using the SparkFun_HX711_Calibration sketch
  scale.tare(); //Assuming there is no weight on the scale at start up, reset the scale to 0

  Serial.println("Readings:");
  
  Servo1.attach(servoPin);  // We need to attach the servo to the used pin number 
}

void loop() {
  Serial.print("Reading: ");
  Serial.print(scale.get_units(), 1); //scale.get_units() returns a float
  Serial.print(" lbs"); //You can change this to kg but you'll need to refactor the calibration_factor
  Serial.println();
}

Here is the HX711 sample code on its own:

#include "HX711.h"

#define calibration_factor -7050.0 //This value is obtained using the SparkFun_HX711_Calibration sketch

#define LOADCELL_DOUT_PIN  3
#define LOADCELL_SCK_PIN  2

HX711 scale;

void setup() {
  Serial.begin(9600);
  Serial.println("HX711 scale demo");

  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
  scale.set_scale(calibration_factor); //This value is obtained by using the SparkFun_HX711_Calibration sketch
  scale.tare(); //Assuming there is no weight on the scale at start up, reset the scale to 0

  Serial.println("Readings:");
}

void loop() {
  Serial.print("Reading: ");
  Serial.print(scale.get_units(), 1); //scale.get_units() returns a float
  Serial.print(" lbs"); //You can change this to kg but you'll need to refactor the calibration_factor
  Serial.println();
}

And finally here’s the sample servo code:

#include <Servo.h>       //Servo library
 
Servo servo_test;        //initialize a servo object for the connected servo  
                
int angle = 0;    
 
void setup() 
{ 
  servo_test.attach(9);      // attach the signal pin of servo to pin9 of arduino
} 
  
void loop() 
{ 
  for(angle = 0; angle < 180; angle += 1)    // command to move from 0 degrees to 180 degrees 
  {                                  
    servo_test.write(angle);                 //command to rotate the servo to the specified angle
    delay(15);                       
  } 
 
  delay(1000);
  
  for(angle = 180; angle>=1; angle-=5)     // command to move from 180 degrees to 0 degrees 
  {                                
    servo_test.write(angle);              //command to rotate the servo to the specified angle
    delay(5);                       
  } 

    delay(1000);
}

Take a look at your loop() function. This is the code that gets run over and over while the Arduino is powered. Everything outside of this will only run once.

Your loop() only has print statements. That means your Arduino is just going to keep printing things out and doing nothing else. You need the code to check the scale reading and decide if it should move the servo or not. Checking the scale reading appears to be done by calling get_units() on your scale as per your example code (although I am not familiar with this library so I could be missing something). Moving the servo is done by calling write() on your servo as you can see in your example code. I’ll leave it to you to figure out how to make those two work together.

What is the "predetermined weight reading"? What should the servo do if the reading is exceeded?

JCA34F:
What is the "predetermined weight reading"? What should the servo do if the reading is exceeded?

HI,
So the predetermined weight is 2KG and if the reading is exceeded, I would like the servo to maintain its position.
So here is a quick recap of the logic:

  • Servo starts at 0 degrees
  • If the reading is equal to 2KG - turn the servo to 180 degrees
  • If the reading over 2KG - servo remains at 0 degrees
  • In the reading is less than 2KG - servo remains at 0 degrees
    hopefully, this helps

iflow1:
So here is a quick recap of the logic:

  • Servo starts at 0 degrees
  • If the reading is equal to 2KG - turn the servo to 180 degrees
  • If the reading over 2KG - servo remains at 0 degrees
  • In the reading is less than 2KG - servo remains at 0 degrees

A good design starts with well thought out requirements. I can practically guarantee you that the reading will never be EXACTLY 2KG. So, the servo will do nothing.

You need to establish an acceptable +/- range around 2KG inside of which the servo will move to 180. Also, to prevent continuous jitter if the reading is hovering around a threshold, you need some hysteresis applied to the high/low trigger points

Also, you haven't specified what should happen if the reading does trigger servo movement but then goes outside the target range. Should the servo then go back to 0?

Fair points actually. Thanks for this.

Would you say 1.8KG-2.2KG is a decent enough range?

Also, I’m not entirely sure what you mean by applying “hysteresis”. Are you able to kindly explain a bit further?

And finally with regards to “what happens if the reading does trigger servo movement but then goes outside the target range”, yes the servo should go back to 0

iflow1:
Also, I’m not entirely sure what you mean by applying “hysteresis”. Are you able to kindly explain a bit further?

Even with the +/-0.2 Kg band, there's still the chance that the actual reading will be very near one of those points (say it's 1.79 Kg). As the reading moves around that point (ADC noise, load cell creep, temperature dependence, etc), it will cross back and forth over the threshold (1.8 Kg in this case). This will cause your servo to jitter back and forth. To solve this you would put some Hysteresis around the two threshold points.

gfvalvo:
Even with the +/-0.2 Kg band, there’s still the chance that the actual reading will be very near one of those points (say it’s 1.79 Kg). As the reading moves around that point (ADC noise, load cell creep, temperature dependence, etc), it will cross back and forth over the threshold (1.8 Kg in this case). This will cause your servo to jitter back and forth. To solve this you would put some Hysteresis around the two threshold points.

QUICK UPDATE:
So I’ve sort of managed to figure it out however there are a few kinks:

  • When it hits the target weight (which in this example is 3.4) the servo keeps moving between 0 and 180 and doesn’t hold the 180 positions as intended.
  • It also still does this when it exceeds the target weight. However, It is supposed to reset the servo to position 0 in this case.
  • With regards to setting up a target range and the Hysteresis, I’m not sure how I would go about implementing these.

Are you able to knildy help with these?
Here Is the code I’ve been able to come up with:

#include "HX711.h"
#include <Servo.h> // Include the Servo library

#define calibration_factor -7050.0 //This value is obtained using the SparkFun_HX711_Calibration sketch

#define LOADCELL_DOUT_PIN  3
#define LOADCELL_SCK_PIN  2
int servoPin = 5; // Declare the Servo pin

HX711 scale;

Servo Servo1; // Create a servo object
float units;

void setup() {
  Serial.begin(9600);
  Serial.println("HX711 scale demo");

  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
  scale.set_scale(calibration_factor); //This value is obtained by using the SparkFun_HX711_Calibration sketch
  scale.tare(); //Assuming there is no weight on the scale at start up, reset the scale to 0

  Serial.println("Readings:");
 
  Servo1.attach(servoPin);  // We need to attach the servo to the used pin number
}

void loop() {
  Serial.print("Reading: ");
  Serial.print(scale.get_units(), 1); //scale.get_units() returns a float
  Serial.print(" lbs"); //You can change this to kg but you'll need to refactor the calibration_factor
  Serial.println();

 Serial.print("Reading: ");

 
 units = scale.get_units(), 10;
     if (units > 3.4)
     {
       Servo1.write(180); 
     }
     else
     {
       Servo1.write(0); 
       delay(1000); 
     }
}
  units = scale.get_units(), 10;

I am not familiar with the library, but this looks very odd
What do you see if you print units after that line of code ?

Should it perhaps be

  units = scale.get_units(10);

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