Mit dem Modul HX711 (erhältlich um 2-3 Euro auf ebay) lässt sich in Kombination mit einem Biegebalken (engl. load cell) und dem Arduino sehr einfach eine Digitalwaage umsetzen. Bei Verwendung eines 100g-Biegebalkens liegt die Messgenauigkeit bei 0.01g. Möchte man die Messrate erhöhen, so muss man Pin 15 des HX711 mit Vcc verbinden. Dann beträgt diese 80 Hz. Eine Tara-Funktion habe ich mit einem Taster umgesetzt. Betätigt man diesen, so wird der aktuelle Messwert als offset eingelesen. Dies führt dazu, dass die Anzeige jederzeit auf 0 gestellt werden kann.
Variante 1:
Bei dieser einfachen Variante kommt ein 16×2 I2C display zum Einsatz.






Experiment zum Newtonmeter
Mit dem Newtonmeter lässt sich zum Beispiel die Abstandsabhängigkeit der Kraft zwischen zwei Magneten bestimmen. Dazu postiert man einen der beiden Magnete auf dem Biegebalken und diesem nähert man sich nun mit dem zweiten Magneten. Die Kraft F in Abhängigkeit von der Entfernung r wird dann notiert.









Wie findet man nun aber das Abstandsgesetz für die Magnetkraft? Bei punktförmigen elektrischen Ladungen gilt ja das bekannte Coulombgesetz mit seiner 1/r²-Abhängigkeit:

Kennen wir die Wertepaare F(r), so können wir daraus die Potenz der Abstandsabhängigkeit ermitteln. Dazu trägt man den ln(F) gegen den ln(r) auf. Es müsste sich eine fallende Gerade ergeben. Deren negative Steigung –n entspricht dann der Potenz 1/r^n der Kraft zwischen den beiden Magneten.


Im konkreten Fall beträgt die Steigung der Geraden –3.78. Daher gilt folgende Abstandsabhängigkeit der Magnetkraft:

Die Kraft nimmt also deutlich stärker als beim Coulombgesetz ab, wie man anhand des folgenden Graphen F(r) auch sehen kann:

Wie kann man sich diese ≈ 1/r ^ 4–Abhängigkeit erklären? Nun, Magnete liegen ja immer als Dipole vor, es kommt also immer ein Nordpol in Kombination mit einem Südpol vor. Nehmen wir an, wir hätten zwei Magnete/Dipole im Abstand x zueinander und die beiden jeweils gekoppelten Magnetpole besitzen den Abstand d:

Nehmen wir weiters an, die Kraft zwischen den einzelnen Polen nehme mit 1/x² ab, also gleich wie das Coulombgesetz. Dann lautet die Formel für die Kraft F(x):
F(x) = 1/(x – d)² – 2/x² + 1/(x + d)².
Nun ein wenig Mathematik:

Für große Abstände x im Verhältnis zu d nimmt also die Kraft mit der vierten Potenz von x ab. Diesen Umstand kann man auch in Excel herleiten, indem wir für obige Kraftformel F(x) den ln(F) gegen den ln(x) auftragen. Die Steigung der so erhaltenen Geraden entspricht dann wieder der Potenz, konkret also –4:



Demnach liege ich mit „meiner“ experimentellen Potenz von n = –3.78 gar nicht so verkehrt, Heureka 😉
Arduino-Code:
// ==================================================================================================
// Sensor HX711 zur Auwertung eines Waagesensors mit einer Auflösung von zumindest 0,01 g
// ==================================================================================================
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
// Anschlüsse:
// GND - GND
// VCC - 5V
// SDA - ANALOG Pin 4
// SCL - ANALOG pin 5
#include <HX711.h>
HX711 scale(A1, A0);
long Rohwert; // vom HX711 gelieferter Rohwert
long offset = -115920; // offset
float Scale = 6647.4; // scale
float Masse; // berechnete Masse in g
const int buttonPin = 2; // the number of the pushbutton pin
int buttonState = 0; // variable for reading the pushbutton status
// =====================
// ======= SETUP =======
// =====================
void setup()
{
Serial.begin(115200);
scale.set_gain(128); // A-Kanal: gain = 64 oder 128; B-Kanal: fix 32
pinMode(buttonPin, INPUT);
lcd.init(); // initialize the lcd
// Print a message to the LCD.
lcd.backlight();
lcd.setCursor(4,0);
lcd.print("mg-Waage");
delay(3000);
lcd.setCursor(4,0);
lcd.print(" ");
lcd.setCursor(0,0);
lcd.print("m = ");
}
// ============================
// ======= HAUPTSCHLEIFE ======
// ============================
void loop()
{
buttonState = digitalRead(buttonPin); // button for new tara (offset)
if (buttonState == HIGH)
{
offset = scale.read_average(20); // Einlesen von 20 Rohwerten zur Ermittlung des tara (offset)
}
Rohwert = scale.read_average(20); // Einlesen von 20 Rohwerten
Masse = (Rohwert - offset) / Scale; // Berechnung der Masse in g
/*
Serial.print("Wert = ");
Serial.println(Rohwert);
*/
Serial.print("Masse = ");
Serial.println(Masse,2);
lcd.setCursor(4,0);
lcd.print(" ");
lcd.setCursor(4,0);
lcd.print(Masse,2);
lcd.print(" g");
delay(50);
}
Variante 2:
Bei dieser Variante kommt anstelle des 16×2 displays ein 320 x 480 pixel display zum Einsatz. Dieses lässt sich über eine zweireihige Pinleiste problemlos mit dem Arduino Mega verbinden. Mit dem Display kann der zeitliche Kraftverlauf F(t) graphisch dargestellt werden. Erfasst werden bei meiner Variante rund 30 Sekunden. Der Messwert kann wieder jederzeit mittels Taster (offset button) auf 0 gesetzt werden. Mit einem weiteren Taster (start button) startet man die Aufzeichnung. Im Moment ist ein 1 kg–Biegebalken in Verwendung. Damit lassen sich Kräfte zwischen 0–10 N aufzeichnen. Bei Verwendung eines anderen Biegebalkens können natürlich auch andere Bereiche erfasst werden.




Mit diesem Newtonmeter kann man einige physikalische Experimente durchführen. Zum Beispiel die Bestimmung der Oberflächenspannung mittels Ringmethode oder die Bestimmung der Haft- und Gleitreibung. Hier erkennt man schön, dass etwa die Haftreibung größer als die Gleitreibung ist und beide von der Masse/Normalkraft des zu ziehenden Objekts abhängen.


Hier die Bestimmung der Oberflächenspannung von Wasser mit der Ringmethode. Es ist darauf zu achten, den doppelten Kreisumfang in die Formel für die Oberflächenspannung σ einzusetzen, da die Oberflächenhaut sowohl auf der Ringinnenseite, als auch auf der Ringaußenseite angreift!





Ein Vergleich mit Tabellenwerten zeigt die recht gute Übereinstimmung zwischen Theorie und Experiment:

Quelle: https://de.wikipedia.org/wiki/Oberflächenspannung
Arduino-Code:
#include <UTFT.h>
#include <Wire.h>
#include <HX711.h>
HX711 scale(A1, A0);
long Rohwert; // vom HX711 gelieferter Rohwert
long offset = 6475; // offset
float Scale = 90413; // scale: m = 17.4 g = 0.170694 N increase the value from 6475 to 21908 (difference = 15433). Therefore 1 N would increase the value by 90413 = scale
float Kraft_alt, Kraft_neu; // berechnete Kraft in N
float Kraft_max; // maximale Kraft
// Declare which fonts we will be using
extern uint8_t SmallFont[];
UTFT myGLCD(ILI9486,38,39,40,41);
int i, j; // Zählvariable
const int offsetPin = 2; // the number of the pushbutton pin
int offsetState = 0; // variable for reading the pushbutton status
const int startPin = 3; // the number of the switch pin
int startState = 0; // variable for reading the switch status
// ====================================
// === ===
// === SETUP ===
// === ===
// ====================================
void setup()
{
Serial.begin(9600);
// while(!Serial); // time to get serial running
pinMode(offsetPin, INPUT);
pinMode(startPin, INPUT);
// Setup the LCD
myGLCD.InitLCD();
myGLCD.setFont(SmallFont);
myGLCD.clrScr();
myGLCD.setColor(255, 255, 0);
myGLCD.fillRect(0, 0, 479, 13);
myGLCD.setColor(0, 0, 0);
myGLCD.setBackColor(255, 255, 0);
myGLCD.print("Newtonmeter - stoppi", CENTER, 1);
scale.set_gain(128); // A-Kanal: gain = 64 oder 128; B-Kanal: fix 32
Kraft_alt = 0.0;
}
// ====================================
// === ===
// === HAUPTSCHLEIFE ===
// === ===
// ====================================
void loop()
{
while(startState = digitalRead(startPin)) // Warten bis start-Taster betätigt wurde
{
/*
Rohwert = 0.0;
for(j = 1; j <= 100; j++)
{
Rohwert = Rohwert + scale.read(); // Einlesen eines Rohwerts
delay(10);
}
Rohwert = Rohwert / 100.0;
Serial.println(Rohwert);
delay(20);
*/
Rohwert = scale.read(); // Einlesen eines Rohwerts
Kraft_neu = (Rohwert - offset) / Scale; // Berechnung der Kraft in Newton
//Serial.println(Kraft_neu);
myGLCD.setColor(0, 255, 0);
myGLCD.setBackColor(0, 0, 0);
myGLCD.print(" ", 70, 18);
myGLCD.printNumF(Kraft_neu, 2, 70, 18);
offsetState = digitalRead(offsetPin); // button for new tara (offset)
if (offsetState == LOW)
{
offset = scale.read(); // Einlesen eines Rohwerts zur Ermittlung des offsets
}
delay(20);
}
Kraft_alt = 0.0;
Kraft_max = 0.0;
myGLCD.clrScr();
myGLCD.setColor(255, 255, 0);
myGLCD.fillRect(0, 0, 479, 13);
myGLCD.setColor(0, 0, 0);
myGLCD.setBackColor(255, 255, 0);
myGLCD.print("Newtonmeter - stoppi", CENTER, 1);
// Zeichnen der beiden Achsen
myGLCD.setColor(255, 255, 255);
myGLCD.drawLine(50,290,430,290);
myGLCD.drawLine(50,20,50,290);
myGLCD.setColor(255, 255, 255);
myGLCD.setBackColor(0, 0, 0);
myGLCD.print("F[N]", 5, 18);
myGLCD.setColor(255, 255, 255);
myGLCD.setBackColor(0, 0, 0);
myGLCD.print("t[sec]", 420, 300);
myGLCD.setColor(255, 255, 255);
myGLCD.drawLine(45,290,50,290);
myGLCD.drawLine(45,240,50,240);
myGLCD.drawLine(45,190,50,190);
myGLCD.drawLine(45,140,50,140);
myGLCD.drawLine(45,90,50,90);
myGLCD.drawLine(45,40,50,40);
myGLCD.drawLine(50,290,50,295);
myGLCD.drawLine(100,290,100,295);
myGLCD.drawLine(150,290,150,295);
myGLCD.drawLine(200,290,200,295);
myGLCD.drawLine(250,290,250,295);
myGLCD.drawLine(300,290,300,295);
myGLCD.drawLine(350,290,350,295);
myGLCD.drawLine(400,290,400,295);
myGLCD.setColor(255, 255, 255);
myGLCD.setBackColor(0, 0, 0);
myGLCD.printNumI(0,30,285);
myGLCD.printNumI(2,30,235);
myGLCD.printNumI(4,30,185);
myGLCD.printNumI(6,30,135);
myGLCD.printNumI(8,30,85);
myGLCD.printNumI(10,25,35);
myGLCD.printNumI(0,48,300);
myGLCD.printNumI(4,98,300);
myGLCD.printNumI(8,148,300);
myGLCD.printNumI(12,194,300);
myGLCD.printNumI(16,244,300);
myGLCD.printNumI(20,294,300);
myGLCD.printNumI(24,344,300);
myGLCD.printNumI(28,394,300);
// graues Gitternetz zeichnen
myGLCD.setColor(120, 120, 120);
myGLCD.drawLine(51,265,430,265);
myGLCD.drawLine(51,240,430,240);
myGLCD.drawLine(51,215,430,215);
myGLCD.drawLine(51,190,430,190);
myGLCD.drawLine(51,165,430,165);
myGLCD.drawLine(51,140,430,140);
myGLCD.drawLine(51,115,430,115);
myGLCD.drawLine(51,90,430,90);
myGLCD.drawLine(51,65,430,65);
myGLCD.drawLine(51,40,430,40);
myGLCD.drawLine(100,40,100,289);
myGLCD.drawLine(150,40,150,289);
myGLCD.drawLine(200,40,200,289);
myGLCD.drawLine(250,40,250,289);
myGLCD.drawLine(300,40,300,289);
myGLCD.drawLine(350,40,350,289);
myGLCD.drawLine(400,40,400,289);
myGLCD.setColor(0, 255, 0);
for(i = 1; i <= 380; i++)
{
offsetState = digitalRead(offsetPin); // button for new tara (offset)
if (offsetState == LOW)
{
offset = scale.read(); // Einlesen eines Rohwerts zur Ermittlung des offsets
Kraft_max = 0.0;
}
//Rohwert = scale.read_average(2); // Einlesen der gemittelten Rohwerten
Rohwert = scale.read(); // Einlesen eines Rohwerts
Kraft_neu = (Rohwert - offset) / Scale; // Berechnung der Kraft in Newton
if(Kraft_neu > Kraft_max)
{
Kraft_max = Kraft_neu;
myGLCD.setColor(255, 0, 0);
myGLCD.print(" ", 180, 18);
myGLCD.printNumF(Kraft_max, 3, 180, 18);
myGLCD.setColor(0, 255, 0);
}
//Serial.println(Rohwert);
myGLCD.print(" ", 70, 18);
myGLCD.printNumF(Kraft_neu, 2, 70, 18);
if(Kraft_neu >= 0 && Kraft_neu <= 10)
{
//myGLCD.drawPixel(50 + i, 290 - Kraft * 25);
myGLCD.drawLine(50 + (i - 1),290 - Kraft_alt * 25,50 + i,290 - Kraft_neu * 25);
Kraft_alt = Kraft_neu;
}
}
}
Variante 3:
Für die Erfassung des Schubs eines Raketentreibsatzes musste ich die Variante 2 ein wenig anpassen. Beim HX711-Modul habe ich nun den 80Hz Modus aktiviert und dafür die Zeitachse am Display auf ca. 0 – 8 Sekunden abgeändert.


Die Treibsätze gibt es bei der Firma Klima in Deutschland, wobei ich mich für den Typ C2-P entschieden habe. Dieser hat eine Schubkraft von ca. 2 N und eine Schubdauer von rund 5 Sekunden.



Der Treibsatz wird über Metallwinkel an die Wägezelle gekoppelt:



Da mir der Versuch in der Wohnung doch zu „brand“gefährlich erschien, ging ich zur Durchführung in den Hof. Beim ersten Durchgang kippte mir die Halterung aufgrund des doch recht beachtlichen Schubs um. Beim zweiten Versuch klappte dann alles wie gewünscht…




Hier der erhaltene Kraftverlauf, welcher sich sehr gut mit den Angaben des Herstellers deckt, Heureka 😉 Die anfängliche Spitzenkraft erreichte rund 6 N, danach betrug die Kraft für ca. 5 Sekunden 2 N…


Das Youtube-Video:
Der leicht abgeänderte Arduino-Code:
#include <UTFT.h>
#include <Wire.h>
#include <HX711.h>
HX711 scale(A1, A0);
long Rohwert; // vom HX711 gelieferter Rohwert
long offset = 6475; // offset
float Scale = 198388; // scale: m = 17.4 g = 0.170694 N increase the value from 6475 to 21908 (difference = 15433). Therefore 1 N would increase the value by 90413 = scale
float Kraft_alt, Kraft_neu; // berechnete Kraft in N
float Kraft_max; // maximale Kraft
// Declare which fonts we will be using
extern uint8_t SmallFont[];
UTFT myGLCD(ILI9486,38,39,40,41);
int i, j; // Zählvariable
const int offsetPin = 2; // the number of the pushbutton pin
int offsetState = 0; // variable for reading the pushbutton status
const int startPin = 3; // the number of the switch pin
int startState = 0; // variable for reading the switch status
// ====================================
// === ===
// === SETUP ===
// === ===
// ====================================
void setup()
{
Serial.begin(9600);
// while(!Serial); // time to get serial running
pinMode(offsetPin, INPUT);
pinMode(startPin, INPUT);
// Setup the LCD
myGLCD.InitLCD();
myGLCD.setFont(SmallFont);
myGLCD.clrScr();
myGLCD.setColor(255, 255, 0);
myGLCD.fillRect(0, 0, 479, 13);
myGLCD.setColor(0, 0, 0);
myGLCD.setBackColor(255, 255, 0);
myGLCD.print("Raketenschub - stoppi", CENTER, 1);
scale.set_gain(128); // A-Kanal: gain = 64 oder 128; B-Kanal: fix 32
Kraft_alt = 0.0;
}
// ====================================
// === ===
// === HAUPTSCHLEIFE ===
// === ===
// ====================================
void loop()
{
Kraft_neu = 0.0;
while(Kraft_neu < 0.2) // Warten bis die Kraft >= 0.2 N beträgt
{
/*
Rohwert = 0.0;
for(j = 1; j <= 100; j++)
{
Rohwert = Rohwert + scale.read(); // Einlesen eines Rohwerts
delay(10);
}
Rohwert = Rohwert / 100.0;
Serial.println(Rohwert);
delay(20);
*/
Rohwert = scale.read(); // Einlesen eines Rohwerts
Kraft_neu = (Rohwert - offset) / Scale; // Berechnung der Kraft in Newton
//Serial.println(Kraft_neu);
myGLCD.setColor(0, 255, 0);
myGLCD.setBackColor(0, 0, 0);
myGLCD.print(" ", 70, 18);
myGLCD.printNumF(Kraft_neu, 2, 70, 18);
offsetState = digitalRead(offsetPin); // button for new tara (offset)
if (offsetState == LOW)
{
offset = scale.read(); // Einlesen eines Rohwerts zur Ermittlung des offsets
}
delay(20);
}
Kraft_alt = 0.0;
Kraft_max = 0.0;
myGLCD.clrScr();
myGLCD.setColor(255, 255, 0);
myGLCD.fillRect(0, 0, 479, 13);
myGLCD.setColor(0, 0, 0);
myGLCD.setBackColor(255, 255, 0);
myGLCD.print("Raketenschub - stoppi", CENTER, 1);
// Zeichnen der beiden Achsen
myGLCD.setColor(255, 255, 255);
myGLCD.drawLine(50,290,430,290);
myGLCD.drawLine(50,20,50,290);
myGLCD.setColor(255, 255, 255);
myGLCD.setBackColor(0, 0, 0);
myGLCD.print("F[N]", 5, 18);
myGLCD.setColor(255, 255, 255);
myGLCD.setBackColor(0, 0, 0);
myGLCD.print("t[sec]", 420, 300);
myGLCD.setColor(255, 255, 255);
myGLCD.drawLine(45,290,50,290);
myGLCD.drawLine(45,240,50,240);
myGLCD.drawLine(45,190,50,190);
myGLCD.drawLine(45,140,50,140);
myGLCD.drawLine(45,90,50,90);
myGLCD.drawLine(45,40,50,40);
myGLCD.drawLine(50,290,50,295);
myGLCD.drawLine(95,290,95,295);
myGLCD.drawLine(140,290,140,295);
myGLCD.drawLine(185,290,185,295);
myGLCD.drawLine(230,290,230,295);
myGLCD.drawLine(275,290,275,295);
myGLCD.drawLine(320,290,320,295);
myGLCD.drawLine(365,290,365,295);
myGLCD.drawLine(410,290,410,295);
myGLCD.setColor(255, 255, 255);
myGLCD.setBackColor(0, 0, 0);
myGLCD.printNumI(0,30,285);
myGLCD.printNumI(2,30,235);
myGLCD.printNumI(4,30,185);
myGLCD.printNumI(6,30,135);
myGLCD.printNumI(8,30,85);
myGLCD.printNumI(10,25,35);
myGLCD.printNumI(0,48,300);
myGLCD.printNumI(1,93,300);
myGLCD.printNumI(2,138,300);
myGLCD.printNumI(3,183,300);
myGLCD.printNumI(4,228,300);
myGLCD.printNumI(5,273,300);
myGLCD.printNumI(6,318,300);
myGLCD.printNumI(7,363,300);
myGLCD.printNumI(8,408,300);
// graues Gitternetz zeichnen
myGLCD.setColor(120, 120, 120);
myGLCD.drawLine(51,265,430,265);
myGLCD.drawLine(51,240,430,240);
myGLCD.drawLine(51,215,430,215);
myGLCD.drawLine(51,190,430,190);
myGLCD.drawLine(51,165,430,165);
myGLCD.drawLine(51,140,430,140);
myGLCD.drawLine(51,115,430,115);
myGLCD.drawLine(51,90,430,90);
myGLCD.drawLine(51,65,430,65);
myGLCD.drawLine(51,40,430,40);
myGLCD.drawLine(95,40,95,289);
myGLCD.drawLine(140,40,140,289);
myGLCD.drawLine(185,40,185,289);
myGLCD.drawLine(230,40,230,289);
myGLCD.drawLine(275,40,275,289);
myGLCD.drawLine(320,40,320,289);
myGLCD.drawLine(365,40,365,289);
myGLCD.drawLine(410,40,410,289);
myGLCD.setColor(0, 255, 0);
for(i = 1; i <= 380; i++)
{
offsetState = digitalRead(offsetPin); // button for new tara (offset)
if (offsetState == LOW)
{
offset = scale.read(); // Einlesen eines Rohwerts zur Ermittlung des offsets
Kraft_max = 0.0;
}
//Rohwert = scale.read_average(2); // Einlesen der gemittelten Rohwerten
Rohwert = scale.read(); // Einlesen eines Rohwerts
Kraft_neu = (Rohwert - offset) / Scale; // Berechnung der Kraft in Newton
if(Kraft_neu > Kraft_max)
{
Kraft_max = Kraft_neu;
myGLCD.setColor(255, 0, 0);
myGLCD.print(" ", 180, 18);
myGLCD.printNumF(Kraft_max, 3, 180, 18);
myGLCD.setColor(0, 255, 0);
}
//Serial.println(Rohwert);
myGLCD.print(" ", 70, 18);
myGLCD.printNumF(Kraft_neu, 2, 70, 18);
if(Kraft_neu >= 0 && Kraft_neu <= 10)
{
//myGLCD.drawPixel(50 + i, 290 - Kraft * 25);
myGLCD.drawLine(50 + (i - 1),290 - Kraft_alt * 25,50 + i,290 - Kraft_neu * 25);
Kraft_alt = Kraft_neu;
}
}
while(startState = digitalRead(startPin)) // Warten bis start-Taster betätigt wurde
{
}
}
