Reid Carlberg

Connected Devices, salesforce.com & Other Adventures

Control an Arduino with a Raspberry Pi Using Node.js and I2C

8

You might also find this post helpful: Read Data from Multiple Arduinos with a Raspberry Pi B+ using I2C and Node.js

As a software developer, I usually stay away from lower level communication protocols. My logic has historically been: they’re a lot of work, and my time is better spent higher up the stack.

A couple of weeks ago, after suffering through a variety of failures and uncertainty higher up the stack, I decided the only way out was to go at least a little deeper. So I bit the bullet and connected a Raspberry Pi to an Arduino using the I2C protocol, and then was able to control the Arduino using Node.js. This post covers how I did it.

Raspberry-Pi-Wild-Thumper.jpg

My use case was fairly simple.  I decided to drive a Wild Thumper using the Salesforce1 mobile app.  The Wild Thumper is controlled by an Arduino compatible board, aptly named the “Wild Thumper Controller“.  You might remember I had a couple of these with me at the Connected Device Lab this Dreamforce.  In order to communicate with Salesforce, it needs to have some kind of a gateway that can talk to the Internet using HTTPS, which is where the Raspberry Pi comes in.  If you have a different flavor or Arduino sitting around this should still work.

There are a lot of really great technical introductions to I2C (including — gasp — one from 2001), but you don’t really need them to get started.  Keep these two basic ideas in mind:

  • You’re going to work in a Master-Slave configuration.
  • You need to connect three pins.  SDA, SCL and Ground.

That’s it.

Step 1: Slave Configuration on the Arduino compatible Wild Thumper Board is pretty easy.  In fact, you can simply use the “Wire > Slave Receiver” sample code included with the IDE to get started (below). Load this in the Arduino IDE as is, send to your device and then start the serial monitor.  Put it aside.

// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this
// Created 29 March 2006
// This example code is in the public domain.
#include <Wire.h>

void setup()
{
  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
}

void loop()
{
  delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
  while(1 < Wire.available()) // loop through all but the last
  {
    char c = Wire.read(); // receive byte as a character
    Serial.print(c);         // print the character
  }
  int x = Wire.read();    // receive byte as an integer
  Serial.println(x);         // print the integer
}

Step 2: Setting up the Raspberry Pi is a little more difficult, but it’s well documented.  If you are using a standard Raspbian distro, the I2C port is not yet enabled.  Adafruit has an excellent post on enabling the I2C port.  Follow those instructions, then c’mon back.

Step 3: Wire your Raspberry Pi and your Arduino together and make sure the RPi can see the Arduino.  Pinouts on the RPi are a little irritating.  I use the Pi Cobbler.  It gives you a handy, easy to read guide to which pins are where.  If you are connecting directly to the GPIO pins, be sure to consult a pinout digram.

Before you connect everything, your RPi should produce this when you use the i2cdetect command.

Raspberry-Pi-Before-Arduino.png

The basic configuration is really simple.  Master SDA pin to Slave SDA, Master SCL pin to Slave SCL, Master GND pin to Slave GND.  On the Wild Thumper Controller, SDA is A4, SCL is A5 and GND is any pin on the outside edge of the board.  And an Arduino Uno R3, there are special pins for I2C, above the AREF pin, clearly labeled on the back side of the board. In my case, the result looks like this (that’s the Wild Thumper Controller on the right, Pi Cobbler on the left):

Raspberry-Pi-Arduino-I2C-Wiring.jpg

After connected, your RPi should produce this (note that there is now a device on 4).

Raspberry-Pi-Arduino-After-I2C.png

Step 4: Install Node.js on to your Raspberry Pi using this simple link.  If you prefer to be a bit more hands on, you can follow these instructions.  If you prefer to be really hands on, you can install it by compiling from the source, but it will probably take > 2 hours and so far in my experience it’s no different.

Step 5: Install something that lets Node.js talk to the Raspberry Pi’s I2C system.  You should use the I2C library.  There are a couple of others out there, but this is easy and popular.  Now you should be able to do something like this:

var i2c = require('i2c');
var device1 = new i2c(0x18, {device: '/dev/i2c-1', debug: false});
device1.setAddress(0x4);
device1.writeByte(0x2, function(err) { console.log("error"); console.log(err); });

And see a “2” in the Arduino serial port monitor (like so).

Arduino-Serial-Monitor.png

There you have it — the basics of controlling an Arduino using a Raspberry Pi with Node.js and I2C. My original goal was to control the Wild Thumper via the Salesforce1 app.  I was able to accomplish that pretty easily.  Here’s my basic controller for the Thumper, and here’s the Node.js app running on the RPi.  I created a simple UI on the Salesforce1 mobile app (below)  that sends commands to the Thumper using the Streaming API and connects to Salesforce using the excellent nforce.

Salesforce1-Arduino.png

8 thoughts on “Control an Arduino with a Raspberry Pi Using Node.js and I2C

  1. Reid Carlberg Post author

    I’m a little light on that side, but IIRC you set the value on the Arduino and the Raspberry Pi reads it. Googling around it looks like there’s several examples. Have you found one that works?

    1. Evertith

      Yeah, I finally figured it out. I had to setup a arduino.readBytes function in Node.JS and provide a length (in my case 24) of the incoming data. Then, on the Arduino side, I had to setup an onRequest callback, and within there, I created my string of data and converted it to bytes and then sent the bytes using Wire.write.

      Based on my research, you can only send up to 32 bytes per I2C message, so I’m limited on how much data I can send. Right now, it works good for what I’m trying to accomplish.

      1. beber

        Hi, I use the same configuration as this article and I tried the readBytes function as you suggested but it triggers the onReceive function on the arduino instead of the onRequest. I can’t figure out what the readBytes COMMAND parameter is meant for and so i might misuse it. Any help here?

  2. Pingback: Read Data from Multiple Arduinos with a Raspberry Pi B+ using I2C and Node.js | Reid Carlberg

  3. César

    Hello, Is it not true that i2c protocol needs an electronics interface between arduino and PI? Pi manages 3.3V and Arduino 5V and different currents so, could happen that PI device suffer a damage. Thanks in advance!

  4. Chintan Pathak

    Hey,
    Nice post, and maybe I should get I2C working with node-js after this. While comparing your code against the original here on: https://github.com/kelly/node-i2c , I notice the use of address: 0x18, which is a bit puzzling. Would you mind explaining, what address is this in your code ? The arduino, I believe has an address of 0x04 as shown by i2cdetect, then what is the **other** address?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: