Skip to content

Instantly share code, notes, and snippets.

@SBajonczak
Created December 26, 2019 10:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SBajonczak/c900e1682abf211c4fa74768f671bc38 to your computer and use it in GitHub Desktop.
Save SBajonczak/c900e1682abf211c4fa74768f671bc38 to your computer and use it in GitHub Desktop.
Scale Tare Measurements
/*
Open Hive | Scale Adjustment
----------------------------
| Scale ADC HX711
pins hard coded
---------------
D15 D14 Dout, SCK
*/
// -------------------------+------
// variables you can modify | START
// -------------------------+------
// ** load cell characteristic
// ---------------------------
// define here individual values for the used load cell
// this is not type specific! even load cells of the same type /
// model have individual characteristics
//
// - ZeroOffset is the raw sensor value for "0 kg"
// write down the sensor value of the scale with no load and
// adjust it here
// - KgDivider is the raw sensor value for a 1 kg weight load
// add a load with known weight in kg to the scale, note the
// sesor value, calculate the value for a 1 kg load and adjust
// it here
long loadCellZeroOffset = 12022;
long loadCellKgDivider = -21987;
// Testwaage 38 cm - Prototyp 1
// null 12022
// 1 kg -21987
// wait between samples
// 3 sec is a good delay so that load cell did not warm up
// too much and external random influences like wind has time
// to go so that the next sample is more valid
const int waitTimeLoadSamples = 3;
// ** median statistics (for weight)
// ---------------------------------
// number of readings for median samples
// 5 is a good compromise between time cost and stable output
int weightSamplesNumber = 10; // take at least 10 readings for adjusting
// -------------------------+----
// variables you can modify | END
// -------------------------+----
// libraries
// load cell
#include <HX711.h> // https://github.com/bogde/HX711
HX711 loadCell; // Create HX711 object; The parameter "gain" is ommited, a default value of "128" is used by the library.
int adjustScale = true; // flag for adjust vs. operation mode
long weightSensorValue;
float weightKg;
// median statistics to eliminate outlier
#include <RunningMedian.h>
RunningMedian weightSamples = RunningMedian(weightSamplesNumber); // create RunningMedian object
// Forward declarations
void getWeight();
void outputStatistic(int decimal);
void serial_poll();
int serial_read_byte();
long serial_read_number();
void setup() {
// serial communication
Serial.begin(9600);
Serial.println("Scale Adjustment for Open Hive / HX711");
Serial.println("--------------------------------------");
Serial.println();
// load cell / HX711 pin definition: Dout 15, SCK 14
loadCell.begin(15, 14);
// switch off HX711 / load cell
loadCell.power_down();
// adjust scale
// ------------
// Step 1: tare scale
Serial.println(">> Step 1: tare scale");
Serial.println(" ------------------");
Serial.println(" Remove all weight from the scale!");
Serial.println(" (If done, input any character to continue ...)");
Serial.println();
Serial.flush();
// Wait for keypress
serial_read_byte();
// get Weight n times and calculate median
Serial.println("Get raw values for tare: ");
getWeight();
Serial.println();
outputStatistic(0);
// set the median as zero offset value
loadCellZeroOffset = weightSamples.getMedian();
// Step 2: weight lower limit
Serial.println(">> Step 2: weight lower limit");
Serial.println(" --------------------------");
Serial.println(" Load at least 1 kg to the scale so that the raw values are > 0!");
Serial.println(" (If done, input any character to continue ...)");
Serial.println();
Serial.flush();
// Wait for keypress
serial_read_byte();
// get Weight n times and calculate median
Serial.println("Get raw values for lower limit: ");
getWeight();
Serial.println();
outputStatistic(0);
long lowerValue = weightSamples.getMedian();
// Step 3: weight upper limit
Serial.println(">> Step 3: weight upper limit");
Serial.println(" --------------------------");
Serial.println(" Put a know load on the scale! ...");
Serial.println(" ... and input weight in gram ...");
Serial.println();
Serial.flush();
// Read numeric value from serial port
long kgValue = serial_read_number();
// get Weight n times and calculate median
Serial.print("Get raw values for upper limit \"");
Serial.print(kgValue);
Serial.print(" g\":");
Serial.println();
getWeight();
Serial.println();
outputStatistic(0);
long upperValue = weightSamples.getMedian();
// calculate loadCellKgDivider
loadCellKgDivider = (upperValue - lowerValue) / ((float) kgValue / 1000.0f);
// output calculated parameter
Serial.println(">> Done! Your calculated parameters:");
Serial.println(" ---------------------------------");
Serial.println();
Serial.print(" loadCellZeroOffset: ");
Serial.print(loadCellZeroOffset);
Serial.println();
Serial.print(" loadCellKgDivider: ");
Serial.print(loadCellKgDivider);
Serial.println();
Serial.println(" ---------------------------------");
Serial.println();
Serial.println("You can test your calculated settings now!");
Serial.println("(Input any character to continue ...)");
Serial.flush();
// Wait for keypress
serial_read_byte();
Serial.println();
}
void loop() {
// test settings
// ------------
adjustScale = false;
// re-set number of weight sample
// does not work
// weightSamplesNumber = 5;
// RunningMedian weightSamples = RunningMedian(weightSamplesNumber); // create RunningMedian object
getWeight();
Serial.println();
outputStatistic(3);
}
// functions
// ---------
// read raw data
void getWeight() {
// clear running median samples
weightSamples.clear();
// read x times weight and take median
// do this till running median sample is full
do {
Serial.flush();
// Wait some time between samples to reduce influences from heating and wind
delay(waitTimeLoadSamples * 1000);
// power HX711 / load cell
loadCell.power_up();
delay(2); // wait for stabilizing
// read raw data input of ADS1231
weightSensorValue = loadCell.read();
// switch off HX711 / load cell
loadCell.power_down();
// calculate weight in kg
weightKg = ((float)weightSensorValue - (float)loadCellZeroOffset) / (float)loadCellKgDivider;
// add single value to runnig median sample
if (adjustScale == true) {
// use raw values for median statistic
weightSamples.add(weightSensorValue);
// debug raw values
Serial.println(weightSensorValue);
}
else
{
// use calculated kg values for median statistic
weightSamples.add(weightKg);
Serial.print(".");
}
} while (weightSamples.getCount() < weightSamples.getSize());
}
// print statistics for raw values (decimal 0) and kg values (decimal 3)
void outputStatistic(int decimal) {
// debug
Serial.println("Low \tAvg \tMed \tHigh \tDiff");
Serial.print(weightSamples.getLowest(),decimal);
Serial.print("\t");
Serial.print(weightSamples.getAverage(),decimal);
Serial.print("\t");
Serial.print(weightSamples.getMedian(),decimal);
Serial.print("\t");
Serial.print(weightSamples.getHighest(),decimal);
Serial.print("\t");
Serial.println(weightSamples.getLowest()-weightSamples.getHighest(),decimal);
Serial.println();
}
// Poll serial port until anything is received
void serial_poll() {
while (!Serial.available()) {
// "yield" is not implemented as noop in older Arduino Core releases
// See also: https://stackoverflow.com/questions/34497758/what-is-the-secret-of-the-arduino-yieldfunction/34498165#34498165
#if !(ARDUINO_VERSION <= 106) || ARDUINO >= 10605 || defined(ESP8266)
yield();
#endif
};
}
// Read byte from serial port
int serial_read_byte() {
serial_poll();
return Serial.read();
}
// Read numeric value from serial port
long serial_read_number() {
serial_poll();
return Serial.parseInt();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment