Connecting a Load Cell to the Web

loadcell
iot
ruby
json
electricimp

#1

Neo asks:

We are trying to design a project for university where you can place a food item on the load sensor and use the Arduino or any device and connect to Internet. So if any one is away from home, they can connect by Internet either by website or application (we are still deciding on how to do this) to the the Arduino and load sensor and find out the weight of the food item in percentage. We want to know the initial weight of the item and find out how much is left.

Thanks for your question Neo!

I should first say there are commercial products that can do this. At Little Bird use digital scales, a laptop running OS X and PrintNode’s Scale API to do just this every day.

If you want to make something more DIY. I’d recommend looking at a Load Cell.

Per Wikipedia:

A load cell is a transducer that is used to create an electrical signal whose magnitude is directly proportional to the force being measured.

An example of a load cell is the Load Cell - 10kg, Wide Bar (TAL201)

Load Cell - 10kg, Wide Bar (TAL201)

This part can translate up to 10kg of pressure (force) into an electrical signal.

The load cells from SparkFun Little Bird carriers are “bar strain gauge load cells”.

They work by having a metal bar with strain gauges attached. When weight is applied to the bar it flexes, and strains the strain gauges. When this happens the resistance of the strain gauges changes a very tiny amount (for a 120Ω gauge, this is a change of only 0.12Ω.).

Because the change in resistance is so small you’ll need an amplifier such as the Load Cell Amplifier - HX711.

SparkFun Load Cell Amplifier - HX711

A guide on hooking up this part to an Arduino is available on SparkFun’s learn website.

Some example code is below:

/*
 Example using the SparkFun HX711 breakout board with a scale
 By: Nathan Seidle
 SparkFun Electronics
 Date: November 19th, 2014
 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: https://github.com/bogde/HX711
 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.
 
*/

#include "HX711.h"

#define calibration_factor -7050.0 //This value is obtained using the SparkFun_HX711_Calibration sketch

#define DOUT  3
#define CLK  2

HX711 scale(DOUT, CLK);

void setup() {
  Serial.begin(9600);
  Serial.println("HX711 scale demo");

  scale.set_scale(calibration_factor); //This value is obtained by using the SparkFun_HX711_Calibration sketch
  scale.tare();	//Assuming there is no weight on the scale at start up, reset the scale to 0

  Serial.println("Readings:");
}

void loop() {
  Serial.print("Reading: ");
  Serial.print(scale.get_units(), 1); //scale.get_units() returns a float
  Serial.print(" lbs"); //You can change this to kg but you'll need to refactor the calibration_factor
  Serial.println();
}

Electric Imp:

Electric Imp

For getting your data out onto the web I recommend the Electric Imp.

I know what you’re thinking, “What’s the big deal? Looks like an SD card…” Well this is no SD card! The Electric Imp is a WiFi enabled development platform powered by a Cortex-M3 processor core. “Really?” Yup.

In essence, the Imp provides an easy, integrated way to connect almost any hardware device both to other devices and to internet services. It’s more than just a WiFi card, or even a WiFi module with processing built in - it’s an integrated platform that deals with the drudgery of connectivity, allowing you to concentrate on the application instead of the mechanics.

It does this by integrating an 802.11b/g/n WiFi transceiver, a great antenna, a Cortex-M3 core and lots of flexible I/O in a tiny package. But the hardware is only part of what makes the Electric Imp an innovative platform. The development environment and workflow is totally cloud-based and in-browser! Simply program the Imp with your WiFi Network information using your iOS or Android smartphone (Optically! No special hardware required!) then log on to the Electric Imp developer website and program your module over-the-air!

Development is done in-browser and in a language called “Squirrel,” which is a C-like language with extensions to communicate with the hardware interfaces and the service. Thanks to cloud-power, you get many big system benefits like buffered I/O and crash recovery - plus you can push updates to devices in the field with a few clicks. There’s even a Planner tool that makes it easy to design interactivity between your Imps.

Note: Although, the Electric Imp comes in an SD form factor, it isn’t compatible with standard SD devices. Development boards are available, though, in the related items below!

Electric Imp Shield

To connect your Electric Imp to your Arduino you’ll need the Electric Imp Shield.

SparkFun Electric Imp Shield

Unfortunately the Imp shield doesn’t come with header pins soldered so we’ll have to solder some on.

Soldering on the Header Pins

We’re going to solder onto the shield some “Arduino Headers” from the Arduino Stackable Header Kit.

Arduino Stackable Header Kit - R3

Prepare your soldering iron

  1. Place the soldering iron in its stand and plug it in.
  2. Wait for the soldering iron to heat up.
  3. Moisten the sponge.
  4. Wipe the tip of the iron on the damp sponge.
  5. Melt a little solder on the tip of the iron.
  6. The tip of the soldering iron should be a shiny silver color.

Soldering the joint

  1. Apply a very small amount of solder to the tip of the iron. This helps conduct the heat to the component and board, but it is not the solder that will make up the joint.
  2. Lay the tip of the iron so that it rests against both the header pin and the board.
  3. Heat both the header and the board, otherwise the solder will simply pool and refuse to stick the pin.
  4. The small amount of solder you applied to the tip before heating the joint will help make contact between the board and the header. It normally takes a second or two to get the joint hot enough to solder.

Sign up for a free Electric Imp account

The first step to getting your imp online is to create a Developer Account. This is free and gives you access to the Electric Imp IDE, which you’ll explore in the next section and use to develop the code your imp will run.

You only need create a Developer Account once. You can add as many imps as you like to your account, and program and monitor them all through the IDE.

Create your Account now: visit the registration page (above) and fill in your details. Once you’ve done so, you’ll receive a confirmation email asking you to verify your email address. When you do so, you can return to the IDE and sign in.

Download the Electric Imp App

The free Electric Imp app is the tool you’ll use to configure your imp using your phone or tablet.

You can download their app from the Apple App Store, or the Google Play store.

Once you’ve downloaded the app, fire it up and enter the Wi-Fi credentials for your network.

The imp is capable of determining what kind of security – WEP, WPA, WPA2, etc – your network uses, so all you need to do is enter your WiFi password. If you are connecting to an unsecured network, leave the password field blank.

The imp’s progress as it tries to go online is indicated by its LED. If the process went smoothly, you’ll see the imp LED flash green after a second or so – it’s connected and ready to use.

Sending Data to the Web

I’ve previously written some code to send Temperature and Humidity Data to the web. It shouldn’t be that hard for you to swap out the Temperature and Humidity readings for the reading from the stain gauge.

Arduino Code

// HIH_6130_1  - Arduino
// 
// Arduino                HIH-6130
// SCL (Analog 5) ------- SCL (term 3)
// SDA (Analog 4) ------- SDA (term 4)
//
// Note 2.2K pullups to 5 VDC on both SDA and SCL
//
// Pin4 ----------------- Vdd (term 8) 
//
// Illustrates how to measure relative humidity and temperature.
//
// copyright, Peter H Anderson, Baltimore, MD, Nov, '11
// You may use it, but please give credit.  
    
#include <Wire.h> //I2C library
#include <SoftwareSerial.h>
byte fetch_humidity_temperature(unsigned int *p_Humidity, unsigned int *p_Temperature);
void print_float(float f, int num_digits);

#define TRUE 1
#define FALSE 0
SoftwareSerial mySerial(8, 9);
void setup(void)
{
   mySerial.begin(9600);     // Configure serial
   Serial.begin(9600);
   Wire.begin();
   pinMode(4, OUTPUT);
   digitalWrite(4, HIGH); // this turns on the HIH3610
   delay(5000);
   Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>");  // just to be sure things are working
}
    
void loop(void)
{
   byte _status;
   unsigned int H_dat, T_dat;
   float RH, T_C;
   
   while(1)
   {
      _status = fetch_humidity_temperature(&H_dat, &T_dat);
      
      switch(_status)
      {
          case 0:  Serial.println("Normal.");
                   break;
          case 1:  Serial.println("Stale Data.");
                   break;
          case 2:  Serial.println("In command mode.");
                   break;
          default: Serial.println("Diagnostic."); 
                   break; 
      }       
    
      RH = (float) H_dat * 6.10e-3;
      T_C = (float) T_dat * 1.007e-2 - 40.0;

      print_float(RH, 1);
      Serial.print("  ");
      print_float(T_C, 2);
      //Serial.println("{t:" + T_C + ",h:" + RH +"}");
      mySerial.println(T_C);
      Serial.println();
      delay(1000);
   }
}

byte fetch_humidity_temperature(unsigned int *p_H_dat, unsigned int *p_T_dat)
{
      byte address, Hum_H, Hum_L, Temp_H, Temp_L, _status;
      unsigned int H_dat, T_dat;
      address = 0x27;;
      Wire.beginTransmission(address); 
      Wire.endTransmission();
      delay(100);
      
      Wire.requestFrom((int)address, (int) 4);
      Hum_H = Wire.read();
      Hum_L = Wire.read();
      Temp_H = Wire.read();
      Temp_L = Wire.read();
      Wire.endTransmission();
      
      _status = (Hum_H >> 6) & 0x03;
      Hum_H = Hum_H & 0x3f;
      H_dat = (((unsigned int)Hum_H) << 8) | Hum_L;
      T_dat = (((unsigned int)Temp_H) << 8) | Temp_L;
      T_dat = T_dat / 4;
      *p_H_dat = H_dat;
      *p_T_dat = T_dat;
      return(_status);
}
   
void print_float(float f, int num_digits)
{
    int f_int;
    int pows_of_ten[4] = {1, 10, 100, 1000};
    int multiplier, whole, fract, d, n;

    multiplier = pows_of_ten[num_digits];
    if (f < 0.0)
    {
        f = -f;
        Serial.print("-");
    }
    whole = (int) f;
    fract = (int) (multiplier * (f - (float)whole));

    Serial.print(whole);
    Serial.print(".");

    for (n=num_digits-1; n>=0; n--) // print each digit with no leading zero suppression
    {
         d = fract / pows_of_ten[n];
         Serial.print(d);
         fract = fract % pows_of_ten[n];
    }
}     

Electric Imp Cloud Agent Code

// Set up outgoing request object

const RUBYURL = "http://107.170.218.10/temperature"

function log(logMessage) 
{    
  // Prepare the request with a JSON payload
  
  local body = http.jsonencode({ temperature = logMessage })
  local extraHeaders = { "Content-Type" : "application/json" }
  local request = http.post(RUBYURL, extraHeaders, body)
    
  local incomingDataTable = request.sendsync()
  
  // Display the received data
  
  server.log("Code: " + incomingDataTable.statuscode + ". Message: " + incomingDataTable.body)
}

// Log a string with Loggly


function cb(){
    
}

device.on("temperature", log)

Electric Imp Device Code

server.log("Device Started");
arduino <- hardware.uart57;
input_string <- "";

function arduinoData() 
{
    // Read the UART for data sent by Arduino to indicate
    // the state of its LED.
    
    local b = arduino.readstring(4);
    server.log(b);
   while(b != -1) 
   {
       // As long as UART read value is not -1, we're getting data
       
       local state = "Unknown";
       //if (b == 0x10) state = "Off";
       //if (b == 0x11) state = "On"
       server.log("LED: " + b);
       b = arduino.read();
   }
}



function readback()
{
    // Function triggered by receipt of a byte from the connected computer
	// Adds the input byte as an alphanumeric character to a buffer string
	// which is displayed in the log when the remote user hits Enter
    
	local byte = arduino.read()
    
	// Ignore initial input
    
	if (byte == -1) return
    
	if (byte == 13)
	{

		server.log("Temperature: " + input_string)
		agent.send("temperature", input_string)
		input_string = ""
	}
	else
	{
		// Add the input character to the buffer
        
		input_string = input_string + chr(byte)
	}
}

function chr(asciiValue)
{
	// Convert passed integer value Ascii code into a character string
    
	if (asciiValue < 32) return ""
    	return format("%c", asciiValue)
}



// Alias UART to which Arduino is connected

arduino.configure(9600, 8, PARITY_NONE, 1, NO_CTSRTS, readback);

Web App

In the example above we’re sending data from our Agent to our Website in a format called JSON. JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML.

JSON is built on two structures:

  • A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.
  • An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.

Here is an example of JSON data:

{
     "firstName": "John",
     "lastName": "Smith",
     "address": {
         "streetAddress": "21 2nd Street",
         "city": "New York",
         "state": "NY",
         "postalCode": 10021
     },
     "phoneNumbers": [
         "212 555-1234",
         "646 555-4567"
     ]
 }

In the example above I send a ver simple string of JSON:

{"temperature":15.00}

You can of course change this to weight.

I run a basic Ruby web framework called Sinatra on a Linux server.

To get it up and running I install the following Ruby Libraries with:

sudo gem install sinatra;

To make things easier to read we’re going to install the colorize gem.

sudo gem install colorize;

The Web App Code i as follows:

#!/usr/bin/env ruby

require 'rubygems'
require 'sinatra'
require 'json'
require 'colorize'

GlobalState = {}
GlobalState[:temperature] = 0

set :port, 80
set :bind, '0.0.0.0'

post '/temperature' do
   puts params.inspect
   request.body.rewind
   result = JSON.parse request.body.read
   GlobalState[:temperature] = result["temperature"]
   puts "The temperature is #{result["temperature"].green}"
  "ok"
end

get '/' do
  "The temperature is #{GlobalState[:temperature]}"
end

To run the code type:

  • save the above code in a file called app.rb
  • run the code with sudo ruby ./app.rb

The above code accepts a POST request (containing the JSON) from the Electric Imp Agent and will respond with the reading on the IP address over the sever that’s running the code.


#2

I’ve got a beehive scale which uses 4 load cells hooked up in parallel via a Sparkfun loadcell amplifier to an arduino (Sodaq). Sends via GPRS to the ThingSpeak using HTTPGet. Working well.