Hi all.
I am a relatively new Arduino user. I have done many of the basic tutorials, and I have created a project that activates a servo based on tripping a PIR sensor.
I am working on a project to make a scale that I can set objects on, and the scale will detect each new object (after a zero reading), count the number of items weighed, keep track of the cumulative total, and then provide a running average weight based on those values.
This is my first post; hopefully I will format it correctly and provide all the data needed.
I am using an Arduino Nano from REXQualis. It is an ATmega328P and CH340 chip. I can program it with the Arduino IDE fine. I am using an HX711 board and 1KG load cell:
I wired my project according to this video:
I am using the HX711_ADC-master library.
My HX711 board does not appear to have a ground plane and testing with a multimeter does not show continuity between E- and GND. I have read some threads here that indicate that this might cause problems, but I'm not clear on how the problem might manifest itself.
I can communicate with the load cell and I am getting reasonable results that closely match a known weight.
I have a few problems that I need help with.
First, the scale does not return zero at no load. Even when I press T to tare the scale, values are close to zero but not zero, and they are not consistent, they dance around. This is not a horrible problem, because I am going to assume that any value under 100 grains (about 6 grams) is an empty scale.
Likewise, when I put a known weight on the scale, it does not repeatably give the same output value. It is close, but again, it dances around. This is bad, because when I put the same object on the scale I would expect the same value to be returned every time.
My biggest problem, however, is trying to determine when the scale has stabilized, so that the value I then capture is the real weight of the object set on the scale.
What I am noticing is that when I set an object on the scale, it "ramps up" to the value, and then when I remove it, it "ramps down". This is a problem because the way my code is set up as soon as the value is over 100 grains, it captures that value as the weight. But the scale is only then on its way up to the real weight.
You can see the output of my code from Serial Monitor here:
You can see that when I set an object on the scale, it first reports as too light, and then when it gets inside the OK range it reads as OK.
I tried to built a "stabilization" factor in but I don't think it's working. I basically said if the absolute value of the previous weight - the current weight is > .25 grains then keep weighing. But even if it worked right this is still a poor solution because the weight could be off by .25 grains.
What I'd like is a way to get the final, stabilized weight of the object in between zero conditions.
Thanks in advance.
Here is my code:
/*
-------------------------------------------------------------------------------------
HX711_ADC
Arduino library for HX711 24-Bit Analog-to-Digital Converter for weight_grains Scales
Olav Kallhovd sept2017
-------------------------------------------------------------------------------------
*/
/*
Settling time (number of samples) and data filtering can be adjusted in the config.h file
For calibration and storing the calibration value in eeprom, see example file "Calibration.ino"
The update() function checks for new data and starts the next conversion. In order to acheive maximum effective
sample rate, update() should be called at least as often as the HX711 sample rate; >10Hz@10SPS, >80Hz@80SPS.
If you have other time consuming code running (i.e. a graphical LCD), consider calling update() from an interrupt routine,
see example file "Read_1x_load_cell_interrupt_driven.ino".
This is an example sketch on how to use this library
*/
#include <HX711_ADC.h>
#if defined(ESP8266)|| defined(ESP32) || defined(AVR)
#include <EEPROM.h>
#endif
//pins:
const int HX711_dout = 4; //mcu > HX711 dout pin
const int HX711_sck = 5; //mcu > HX711 sck pin
//HX711 constructor:
HX711_ADC LoadCell(HX711_dout, HX711_sck);
const int calVal_eepromAdress = 0;
unsigned long t = 0;
float weight_grains = 0; // Variable for holding the weight in grains.
int Counter = 0; // Counter for items being weighed.
float CumulativeWeight = 0 ;// Cumulative weight of items being weighed.
float LastWeight = 0; // Variable for the weight of the previous item weighed.
const float StabFactor = .25 ; // The tolerance for determining if the weight has stabilized or not, in grains.
int NewScaleStatus = 0; // A flag to know whether the state of the scale has changed.
int OldScaleStatus = 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
float calibrationValue; // calibration value (see example file "Calibration.ino")
//calibrationValue = 696.0; // uncomment this if you want to set the calibration value in the sketch
#if defined(ESP8266)|| defined(ESP32)
EEPROM.begin(512); // uncomment this if you use ESP8266/ESP32 and want to fetch the calibration value from eeprom
#endif
EEPROM.get(calVal_eepromAdress, calibrationValue); // uncomment this if you want to fetch the calibration value from eeprom
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()) {
Serial.println("Timeout, check MCU>HX711 wiring and pin designations");
while (1);
}
else {
LoadCell.setCalFactor(calibrationValue); // set calibration value (float)
Serial.println("Startup is complete");
}
}
void loop() {
LoadCell.setSamplesInUse(1);
while (abs(CheckScale() - weight_grains) > StabFactor) {
weight_grains = CheckScale();
delay(5000);
Serial.println("stabilizing1...");
}
if (weight_grains > 100) {
if (weight_grains < 500) { // object is too light.
NewScaleStatus = 1;
if (NewScaleStatus != OldScaleStatus) {
Serial.print("Weight is too light! ");
Serial.println(weight_grains);
}
OldScaleStatus = NewScaleStatus;
} else if (weight_grains > 600) { // object is too heavy .
NewScaleStatus = 2;
if (NewScaleStatus != OldScaleStatus) {
Serial.print("Weight is to heavy !");
Serial.println(weight_grains);
}
OldScaleStatus = NewScaleStatus;
} else { // object is OK.
NewScaleStatus = 3;
if (NewScaleStatus != OldScaleStatus) {
Serial.print("Weight is OK!");
Serial.println(weight_grains);
}
OldScaleStatus = NewScaleStatus;
}
} else { // scale is empty.
NewScaleStatus = 4;
if (NewScaleStatus != OldScaleStatus) {
Serial.println("Scale is empty.");
}
OldScaleStatus = NewScaleStatus;
}
// receive command from serial terminal, send 't' to initiate tare operation:
if (Serial.available() > 0) {
char inByte = Serial.read();
if (inByte == 't') LoadCell.tareNoDelay();
}
// check if last tare operation is complete:
if (LoadCell.getTareStatus() == true) {
Serial.println("Tare complete");
}
}
float CheckScale() {
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();
newDataReady = 0;
t = millis();
weight_grains = (i * 15.4324);
//Serial.print("Load_cell output val: ");
//Serial.println(weight_grains);
}
}
return weight_grains;
}