Skip to content

Commit 6a73cc7

Browse files
author
GatCode
committed
Add First Implementation
1 parent 74b08a7 commit 6a73cc7

File tree

5 files changed

+225
-0
lines changed

5 files changed

+225
-0
lines changed

examples/basic/basic.ino

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include "HX711.h"
2+
#include "ScaleStabilizer.h"
3+
4+
// Scale
5+
const int DOUT_PIN = 23;
6+
const int SCK_PIN = 22;
7+
HX711 scale;
8+
9+
// Scale Stabilizer
10+
const int WINDOW_SIZE = 10;
11+
const double WEIGHT_THRESHOLD = 0.01;
12+
ScaleStabilizer stabilizer;
13+
14+
void setup() {
15+
Serial.begin(115200);
16+
17+
scale.begin(DOUT_PIN, SCK_PIN);
18+
scale.set_scale(720);
19+
scale.tare();
20+
21+
stabilizer.begin(WINDOW_SIZE, WEIGHT_THRESHOLD);
22+
}
23+
24+
void loop() {
25+
double adcReading = scale.get_units();
26+
stabilizer.add(adcReading);
27+
Serial.println(stabilizer.getStablilizedReading());
28+
}

library.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "ScaleStabilizer",
3+
"version": "1.0.0",
4+
"description": "A library to stabilize load cell readings",
5+
"keywords": "scale, load cell, HC711",
6+
"repository":
7+
{
8+
"type": "git",
9+
"url": "https://github.com/GatCode/ScaleStabilizer.git"
10+
},
11+
"authors":
12+
[
13+
{
14+
"name": "GatCode",
15+
"email": "gatcode@wdw.one",
16+
"url": "https://www.gatcode.com",
17+
"maintainer": true
18+
}
19+
],
20+
"license": "MIT",
21+
"platforms": "*"
22+
}

library.properties

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
name=ScaleStabilizer
2+
version=1.0.0
3+
author=GatCode <gatcode@wdw.one>
4+
maintainer=GatCode <gatcode@wdw.one>
5+
sentence=A library to stabilize load cell readings.
6+
paragraph=A library to stabilize load cell readings.
7+
category=Sensors
8+
url=https://github.com/GatCode/ScaleStabilizer

src/ScaleStabilizer.cpp

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#include "ScaleStabilizer.h"
2+
3+
/*!
4+
* @brief simple average calculation
5+
*/
6+
double ScaleStabilizer::getAvg() {
7+
double sum = 0;
8+
9+
for (int i = 0; i < _windowSize; i++) {
10+
sum += _window[i];
11+
}
12+
13+
return sum / _windowSize;
14+
}
15+
16+
/*!
17+
* @brief checks if all the elements in the moving _window are the same
18+
*/
19+
bool ScaleStabilizer::isBufferMonotone() {
20+
for (int i = 0; i < _windowSize; i++) {
21+
if (_window[i] != _window[0]) {
22+
break;
23+
}
24+
}
25+
}
26+
27+
/*!
28+
* @brief init of the stabilizer
29+
*/
30+
void ScaleStabilizer::begin(int windowSize, double weightThreshold) {
31+
_windowSize = windowSize;
32+
_weightThreshold = weightThreshold;
33+
_window = new double[_windowSize];
34+
_forceOverwrite = _windowSize;
35+
_currentReadingIdx = 0;
36+
_lastOutputValue = 0.0;
37+
}
38+
39+
/*!
40+
* @brief add a new ADC reading to the moving _window by replacing the olest one
41+
* but if the moving _window is empty or needs to be overwritten, force overwrite is executed
42+
*/
43+
void ScaleStabilizer::add(double reading) {
44+
if (_forceOverwrite > 0 || isBufferMonotone()) {
45+
int oldestReadingIdx = (_currentReadingIdx + 1) % _windowSize;
46+
_window[oldestReadingIdx] = reading;
47+
_currentReadingIdx = oldestReadingIdx;
48+
_forceOverwrite--;
49+
return;
50+
}
51+
52+
if (abs(reading - getAvg()) < _weightThreshold) {
53+
int oldestReadingIdx = (_currentReadingIdx + 1) % _windowSize;
54+
_window[oldestReadingIdx] = reading;
55+
_currentReadingIdx = oldestReadingIdx;
56+
return;
57+
}
58+
59+
// reading index just before the last one
60+
int nextToLastReadingIdx = _currentReadingIdx - 1 < 0 ? _windowSize : (_currentReadingIdx - 1) % _windowSize;
61+
62+
if (abs(_window[nextToLastReadingIdx] - getAvg()) > _weightThreshold) {
63+
// replace 75% of the data in the filter _window with fresh readings
64+
_forceOverwrite = _windowSize * 0.75;
65+
}
66+
67+
// everything else is probably just noise
68+
}
69+
70+
/*!
71+
* @brief returns the stabilized average reading from the moving _window
72+
*/
73+
double ScaleStabilizer::getStablilizedReading(double displayResolution, int decimalPlaces) {
74+
// find min and max values
75+
int minIdx = 0;
76+
int maxIdx = 0;
77+
for (int i = 0; i < _windowSize; i++) {
78+
if (_window[i] < minIdx) {
79+
minIdx = i;
80+
}
81+
if (_window[i] > maxIdx) {
82+
maxIdx = i;
83+
}
84+
}
85+
86+
// remove min and max from measurements
87+
double sum = 0;
88+
for (int i = 0; i < _windowSize; i++) {
89+
if (i == minIdx || i == maxIdx) {
90+
continue;
91+
}
92+
sum += _window[i];
93+
}
94+
95+
// calc cleaned average
96+
double cleanedAverage = sum / (_windowSize - 2);
97+
98+
// remove negative numbers and set to 0 if close to 0
99+
if (cleanedAverage < 0.5) {
100+
cleanedAverage = 0.0;
101+
}
102+
103+
// round to given decimal places
104+
float scale = pow(10, decimalPlaces);
105+
cleanedAverage = round(cleanedAverage * scale) / scale;
106+
107+
// perform the output flicker reduction
108+
if (_lastOutputValue == cleanedAverage) {
109+
return cleanedAverage;
110+
}
111+
112+
if(abs(cleanedAverage - _lastOutputValue) < displayResolution) {
113+
return _lastOutputValue; // probably was just noise - return the old measurement
114+
}
115+
116+
_lastOutputValue = cleanedAverage;
117+
return cleanedAverage;
118+
}

src/ScaleStabilizer.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#ifndef SCALESTABILIZER_H
2+
#define SCALESTABILIZER_H
3+
4+
#include "Arduino.h"
5+
6+
class ScaleStabilizer {
7+
private:
8+
double* _window;
9+
int _windowSize;
10+
double _weightThreshold;
11+
int _forceOverwrite;
12+
int _currentReadingIdx;
13+
double _lastOutputValue;
14+
15+
/*!
16+
* @brief Returns the average
17+
* @return Returns the average of the moving window
18+
*/
19+
double getAvg();
20+
21+
/*!
22+
* @brief Returns true if moving window contains monotone elements
23+
* @return True if all elements have the same value
24+
*/
25+
bool isBufferMonotone();
26+
27+
public:
28+
/*!
29+
* @brief ScaleStabilizer begin initializer
30+
* @param windowSize represents the size of the moving window
31+
* @param weightThreshold represents the weight/noise threshold - e.g. 0.1g
32+
*/
33+
void begin(int windowSize, double weightThreshold);
34+
35+
/*!
36+
* @brief Adds the given reading to the moving window
37+
* @param reading ADC value/reading
38+
*/
39+
void add(double reading);
40+
41+
/*!
42+
* @brief Returns the stabilized load cell reading
43+
* @param displayResolution represents the output resolution - e.g. 0.1g accuracy
44+
* @param decimalPlaces represents the decimal places present in the output
45+
*/
46+
double getStablilizedReading(double displayResolution = 0.1, int decimalPlaces = 1);
47+
};
48+
49+
#endif

0 commit comments

Comments
 (0)