The challenge is to build a high-precision scale and to process its data so that it can be consumed in real-time by online apps. The actual implementation was built with a kitchen scale attached to a signal amplifier (the HX711 used for high-precision readings), an Arduino microcontroller and a RaspberryPi microcomputer.

The Implementation

Load sensors are very tricky. Usually, standard sensors exposes an easy-to-develop interface as their output is just an analog value ranging from 0 to 1023 (1024 values/bytes in total). This is true for photosensors, thermometers etc… Load sensors or strain gauges — on the other hand — are different: depending on the actual device, their signal needs to be amplified and processed. Amplifiers like the cheap and handy HX711 takes the usual 4 inputs from the sensor and outputs 2 channels: one is a stream of data and the other is a clock input. The clock is a signal that needs to be sent from the microcontroller to the amplifier. The amplifier has an internal clock too but that kicks in when you connect the clock pin to the ground, but its output is tricky to implement and there are no ready-to-use libraries for it.

First Iteration

The first architecture design involved a RaspBerryPi directly connected to the load sensor: a Python script was designed to read the data and write it to a file. A NodeJS server with Express and Socket.io was supposed to tail the file and share its data over the internet. Unfortunately, the RaspBerryPi doesn’t have an analog reader and although I could simulate one using software, the best way to have reliable readings is to connect an AD/C device or by using a microcontroller with analog reading built-in to the device.

Pivoting to the final Iteration

After several iterations the following structure was chosen (different parameters were taken into consideration like cost, reliability, precision, community support and available libraries): a kitchen scale with a high-precision load sensor was connected to the signal amplifier (HX711). The amplifier was then connected to the Arduino with the embedded calibration logic: the actual data was then printed to Serial. The RaspBerryPi, connected to the Arduino with a USB cable, will then read from Serial using NodeJS and share the data using Express and Socket.io.

Material

1x soldering Iron and soldering material

several jumper cables (male-to-male and female-to-male)

1x prototyping breadboard

several 1mm and 3mm heat-shrinking tubes

1x HX711 amplifier and AD/C converter

1x Arduino microcontroller (the one used is the Genuino Uno R3)

1x RaspBerryPi (the one used is the model 3)

1x kitchen scale — as a rule of thumbs, a cheap one: they are much more easy to disassemble

screwdriver(s)

1x multimiter for continuity tests

Building the scale

Remove the plastic shield from the scale: you should clearly see 4 wires than run from the load sensor to the on-board microcontroller (they are usually white, red, green and black).

Disconnect the wires from the on-board microcontroller (cut them loose)

Remove the male part from 4 jumper-cables (I’ve done the contrary but I feel it was a mistake)

Expose the copper of the cables and twist them toghether with the load sensor cables.

Using a soldering iron you have to solder toghether the wires

Using the heath-shirking cables, cover the exposed part in order to prevent short-circuits and magnetic interferences. This part is very delicate: if you don’t have previous experience with soldering, I recommend that you first experiment with spare cables and perform continuity test with a Multimiter.

Connect the load sensor cables to the HX711

Connect the HX711 to the Arduino

Connect the Arduino to the RaspBerryPi using a USB cable

Scale code

Now we will put some logic in our scale. Using the Arduino IDE, install this library: https://github.com/bogde/HX711 and upload the following code:

/*

Example using the SparkFun HX711 breakout board with a scale

By: Nathan Seidle SparkFun Electronics

Edited by: Edoardo Paolo Scalafiotti



This is the calibration sketch. Use it to determine the calibration_factor that the main example uses. It also

outputs the zero_factor useful for projects that have a permanent mass on the scale in between power cycles.



Setup your scale and start the sketch WITHOUT a weight on the scale

Once readings are displayed place the weight on the scale

Press +/- or a/z to adjust the calibration_factor until the output readings match the known weight

Use this calibration_factor on the example sketch



This example assumes pounds (lbs). If you prefer kilograms, change the Serial.print(“ lbs”); line to kg. The

calibration factor will be significantly different but it will be linearly related to lbs (1 lbs = 0.453592 kg).



Your calibration factor may be very positive or very negative. It all depends on the setup of your scale system

and the direction the sensors deflect from zero state

This example code uses bogde’s excellent library:

bogde’s library is released under a GNU GENERAL PUBLIC LICENSE

Arduino pin 2 -> HX711 CLK

3 -> DOUT

5V -> VCC

GND -> GND



Most any pin on the Arduino Uno will be compatible with DOUT/CLK.



The HX711 board can be powered from 2.7V to 5V so the Arduino 5V power should be fine.



*/ License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).This is the calibration sketch. Use it to determine the calibration_factor that the main example uses. It alsooutputs the zero_factor useful for projects that have a permanent mass on the scale in between power cycles.Setup your scale and start the sketch WITHOUT a weight on the scaleOnce readings are displayed place the weight on the scalePress +/- or a/z to adjust the calibration_factor until the output readings match the known weightUse this calibration_factor on the example sketchThis example assumes pounds (lbs). If you prefer kilograms, change the Serial.print(“ lbs”); line to kg. Thecalibration factor will be significantly different but it will be linearly related to lbs (1 lbs = 0.453592 kg).Your calibration factor may be very positive or very negative. It all depends on the setup of your scale systemand the direction the sensors deflect from zero stateThis example code uses bogde’s excellent library: https://github.com/bogde/HX711 bogde’s library is released under a GNU GENERAL PUBLIC LICENSEArduino pin 2 -> HX711 CLK3 -> DOUT5V -> VCCGND -> GNDMost any pin on the Arduino Uno will be compatible with DOUT/CLK.The HX711 board can be powered from 2.7V to 5V so the Arduino 5V power should be fine.*/ #include “HX711.h” #define DOUT A1

#define CLK A0 HX711 scale(DOUT, CLK); float calibration_factor = -47000; //-47000 worked for my 3kg max scale setup void setup() {

Serial.begin(9600);

Serial.println("HX711 calibration sketch");

Serial.println("Remove all weight from scale");

Serial.println("After readings begin, place known weight on scale");

Serial.println("Press + or a to increase calibration factor");

Serial.println("Press — or z to decrease calibration factor"); scale.set_scale();

scale.tare(); //Reset the scale to 0 long zero_factor = scale.read_average(); //Get a baseline reading

Serial.print("Zero factor: "); //This can be used to remove the need to tare the scale. Useful in permanent scale projects.

Serial.println(zero_factor);

} void loop() { scale.set_scale(calibration_factor); //Adjust to this calibration factor Serial.print("Reading: ");

Serial.print(scale.get_units(), 1);

Serial.print(" kg"); //Change this to lbs if are insane

Serial.print(" calibration_factor: ");

Serial.print(calibration_factor);

Serial.println(); if(Serial.available())

{

char temp = Serial.read();

if(temp == '+' || temp == 'a')

calibration_factor += 10000;

else if(temp == '-' || temp == 'z')

calibration_factor -= 10000;

}

}

Adjust your calibration factor: for a 3kg scale I’ve used -470000 but milage may vary depending on your load sensor. Once you’ve found your calibration factor, upload the following code:



Example using the HX711 breakout board with a scale

By: Nathan Seidle SparkFun Electronics

Edited by: Edoardo Paolo Scalafiotti

License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).



This example demonstrates basic scale output. See the calibration sketch to get the calibration_factor for your

specific load cell setup.



This example code uses bogde’s excellent library:

bogde’s library is released under a GNU GENERAL PUBLIC LICENSE



The HX711 does one thing well: read load cells. The breakout board is compatible with any wheat-stone bridge

based load cell which should allow a user to measure everything from a few grams to tens of tons.

Arduino pin 2 -> HX711 CLK

3 -> DAT

5V -> VCC

GND -> GND



The HX711 board can be powered from 2.7V to 5V so the Arduino 5V power should be fine.



*/ /*Example using the HX711 breakout board with a scaleBy: Nathan Seidle SparkFun ElectronicsEdited by: Edoardo Paolo ScalafiottiLicense: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).This example demonstrates basic scale output. See the calibration sketch to get the calibration_factor for yourspecific load cell setup.This example code uses bogde’s excellent library: https://github.com/bogde/HX711 bogde’s library is released under a GNU GENERAL PUBLIC LICENSEThe HX711 does one thing well: read load cells. The breakout board is compatible with any wheat-stone bridgebased load cell which should allow a user to measure everything from a few grams to tens of tons.Arduino pin 2 -> HX711 CLK3 -> DAT5V -> VCCGND -> GNDThe HX711 board can be powered from 2.7V to 5V so the Arduino 5V power should be fine.*/ #include <HX711.h> #define calibration_factor -470000 //This value is obtained using the calibration sketch #define DOUT A1

#define CLK A0 HX711 scale(DOUT, CLK); void setup() {

Serial.begin(9600);

while (!Serial) {

// wait serial port initialization

}

scale.set_scale(calibration_factor); //This value is obtained by using the calibration sketch

scale.tare(); //Assuming there is no weight on the scale at start up, reset the scale to 0

} void loop() {

Serial.print(scale.get_units(), 4); //scale.get_units() returns a float

Serial.println();

}

If everything is ok, you should now see the scale values popping on the Serial Terminal. You can augment the precision of the scale by augmenting the float precision. I’ve tested several weights and seen that it was also detecting me blowing on it. Nice.

The Server

We are almost there. We just need the final code: read from the serial port and transmit the code over. As the scale will broadcast live data, we will use Socket.io . On the RaspBerry Pi, install the following dependencies:

npm install express npm install serialport npm install socket.io

Then, copy and paste the following code in a file called index.js:

var serialPort = require(‘serialport’),

arduinoPort = ‘/dev/cu.usbmodem41’, //replace this with the address of your serialPort

app = require(‘express’)(),

http = require(‘http’).Server(app),

ioServer = require(‘socket.io’)(http); // Setup the serialPort

var port = new serialPort.SerialPort(arduinoPort, {

baudrate: 9600,

parser: serialPort.parsers.readline(‘

’)

}); // Setup express

app.get(‘/’, function(req, res) {

res.send(‘<h1>Nothing here, move along</h1>’);

}); port.on(‘open’, function() {

console.log(‘Port opened.’);

}); var nsp = ioServer.of(‘/consumption’);

nsp.on(‘connection’, function(socket) {

console.log(“A client is connected.”);

}); port.on(‘data’, function(data) {

var val, dataObj;

val = data > 0 ? parseFloat(data) : 0;

dataObj = {

timestamp: new Date(),

val: parseFloat(val)

};

nsp.emit(‘live reading’, dataObj);

console.log(‘reading: ‘, dataObj);

}); // open errors will be emitted as an error event

port.on(‘error’, function(err) {

console.log(‘Error: ‘, err.message);

}); http.listen(3000, function(){

console.log(‘listening on *:3000’);

});

And that’s it. You can run the script:

node index.js

and check the console: you should see the values coming from the serialPort of Arduino. The very same values are now being sent over the specified port using websocket, ready to be consumed by a browser or client app.