Weight scale

Years ago I wanted a digital weight scale for more than 30kg. It took me 5 years to get almost there but the result is not a hello world and is more reliable than many commercial models (most are crap).

How do you make a digital weight scale? A single word will get you started: HX711. It's a load cell amplifier and 24-bits ADC. From wikipedia: « A load cell is force transducers. It converts a force such as tension, compression, pressure, or torque into an electrical signal that can be measured. ». Take a micro-controller, connect the HX711 to it, connect a load cell to the HX711 and use one of the existing libraries to read the data.

Unsurprisingly, it's not that simple. Or at least it's not that simple for my use case.

#Disclaimer: good off-the-shelf hardware exists

Sparkfun has built the OpenScale. It costs around 35 USD but includes everything. It's slightly expensive but probably a much better bargain than the bare HX711 basic breakout board sold by Sparkfun (11 USD while copycats on AE cost 5% of that and application note implementations even less).

They've produced some of the best documentation on the topic through their OpenScale tutorial. It covers wiring, Wheatstone bridges and the fact that temperature changes the readings (Wheatstone bridges are supposed to compensate for that though; I'm not sure how efficiently in the end).

#Making PCBs

Off-the-shelf HX711 module

It's not too big but there is a bit of wasted space, pins for both differential inputs and no way to connect all the wires involved in the Wheatstone bridge (i.e. the bridge has to be built on a separate board).

#First circuit board

I made a PCB early on by following the HX711 application note and another page on the Internet that mentioned errors in the application note. I think I don't have the KiCad project anymore due to SSD failures in series but it's not complicated at all.

My circuit board includes pads to solder the load cell wires. Manufactured by OSH Park (colours are way off on the picture, probably due to white balance).

There were up to three fragile wires to solder on the same pad. These pads were a mistake. Everything was too cramped, especially with the very fragile load cell wires. It worked though. Definitely not good enough for more than that.

Wires and pins are too cramped once soldered but it's good enough for a first version, and not for more than that.

#Second circuit board

Version 2 of the PCB: a lot cleaner with more room and a logical pad layout.

One side for the Wheatstone bridge and there is one pad per wire (arranged in a 3 by 4 setup, matching the 3 wires of each of the 4 load cells), labels are useful and properly placed.

I think I still used pads in order to save space but I could probably have arranged enough holes neatly on the board perimeter; nowadays I would probably attempt to use castellated holes to save some space. Vias in the middle of pins are a mistake: solder hates them.

#Using Linux when not appropriate

The original project included a fair bit of work besides weighing. Data would be stored in a time-series database, there might even be a dashboard available, and a few extra behaviours like toggling GPIOs could also be added.

I've long been annoyed by the difficulties to update embedded and especially IoT software. A full featured Linux distribution seemed better. Since there is an upstream kernel module for hx711, this seemed perfect.

I needed a distribution that supported Raspberry Pis: only very few do. Debian seemed to support everything I needed.

Unfortunately Debian didn't compile that module. That module is configured through device trees and the reasoning in Debian was that if you needed a device tree to use a module, it made little sense to include the module by default. That's very logical but it wasn't very good for me.

I think I discussed this on IRC and I think that's why the module is built by default now. Another thing that changed is the ability to use device tree overlays. It had been a thing for quite some time but actual usage in Debian was painful. Names were not kept so you had to use IDs in overlays but that's obviously difficult to write and maintain. I don't remember everything well: it's been around 4 years now. Fortunately the situation seems much better overall now.

Another issue was the use of a Raspberry Pi: too big, too slow to boot, too difficult to power well.

Overall an ESP32 makes much more sense: it's much tinier, less expensive and can be better integrated physically. Maybe there would be three ESP32s and one Raspberry Pi but integration and wiring would be so much simpler that the added cost would probably be recouped.

Still, I managed to get everything working but it wasn't production ready. Maintainability was poor due to the lack of easy integration. That isn't what I stopped with however: calibration was much more difficult, at least I thought so.

#ESP32 and esp-idf

When I started working on this project again, I started with an ESP32. As outline above, a Raspberry Pi or anything running Linux was not going to work out unless I customised the hardware and the software a lot. ESP32s are cheap, fast and versatile. I went with a DevKitC-v4 which I had lying around; its main issue is that it's slightly too large to be breadboard-friendly.

The software is based on esp-idf, Espressif's SDK, which I find really good overall. Arduino can be used too but I really don't appreciate it.

Not all pins are the same on ESP32. A lot of the pins on devboards are actually borderline unusable (the strapping pins plus the internal flash ones). I thought I had avoided the bad ones but I kept hitting issues with SPI until I switched to the "default" pins for it. I hadn't used them before because of the aforementioned breadboard-unfriendliness but it's definitely better to use safe pins, write the software and only then find better pins.

#Libraries

Using esp-idf instead of Arduino means you are not able to use the vast majority of the libraries that have been written in that space. Fortunately it is still possible to find appropriate and even very good ones. For this project, esp-idf-lib has been perfect. I have used it for HX711, MAX7219 and BME280 (before switching to only a thermistor).

#Battery power

Not done yet. I'm still using a powerbank.

Interesting stuff on that page.

#Calibration

Load cells for weight scales are not engineered for precision. This task is delegated to software instead and requires calibration. Since I went with cheap load cells on Aliexpress, I couldn't rely on manufacturer data and checked everything from scratch.

Calibration was a topic in itself. I started doing it but it seemed there was no linear relation between readings and weights. That made calibration a difficult topic: it would have to be done piecewise and using extrapolations. I devised a way to do it with several objects (including myself) of unknown weight. It seemed that while the relationship wasn't linear, its derivative might be. I would use objects of unknown weight plus objects of known weight to determine local relations, extrapolate and then use piecewise integration and extrapolate again if needed). That required time, a clean setup, and ... a flat floor.

The flat floor was a real issue back then and greatly contributed to prevent me from meeting my deadline. The integration with a Raspberry Pi was also poor. It was quite bulky and horrible to power properly (that's probably Raspberry Pis' biggest issue). The project also included other components and they weren't ready at all. I kept the setup around and switched.

And then I had to translate ADC readings into a weight. For that I either needed a flat surface to put the scale on, or an actual scale object which could compensate for some lack of flatness. That's where I stopped during a few years. My need for the scale mostly went away quickly after that, just like my time available.

More recently I had both a need and some time. That's a rare combination. And a desk that was actually flat enough.

Software-wise, I wanted to avoid Arduino which doesn't really fit my mental model, habits (its IDE was basically mandatory until recently) and which I don't really enjoy. Everything would run on an ESP32. Libraries for esp-idf are far less common and active than Arduino ones; like ten times less. Fortunately there are a few high-qualiry repositories, among which esp-idf-lib (TODO: link).

Libraries give readings but help very little when it comes to calibration, even documentation is very scarce.

Value varies with temperature with only a small time difference

Value as a function of temperature is very noisy but a very rough linear approximation (i.e. straight line) could halve error.

TBH I don't remember what this shows. It's been three years.

Calibration ended up being a fairly long but simple process. I started with temperature. I first checked if the heating the HX711 with my hand changed the values; it didn't or was negligible. I then output on the UART both the temperature and the ADC reading during several days. The temperature sensor reacts much much faster than the load cells but that doesn't matter on average. The result was noisy but fairly clear. I could get better values but on first approximation, I concluded that the change in readings was +1000/°C with a gain of 64. It's actually huge at 0.1kg per °C! Imagine a personal weight scale which reports you 1kg lighter if you've opened the window.

Weight calibration was much easier than I had thought during all these years. The reason is that the relationship between readings and weight is actually clearly linear unlike what I had believed after my first experiments back then. Moreover I have a fairly large pot now and I was able to reach 16kg with steps of 0.6kg. I got a good number of data points, evenly spaced, a good range, and a very linear relationship (deviation was under 0.1%).

While calibrating, I paused to eat. Since I knew temperature affected readings, I measured again before continuing to increase the load. The value had indeed shifted. Correcting for this was the only thing I had to do and all subsequent measurements were coherent.

#Updates

#Reports

#Notes