Raspberry Pi + Arduino: Getting Started

 
IMG_20130105_155212The Raspberry Pi kind of looks like an Arduino replacement as far as it’s physical appearance.  At first glance, it’s specs are much more impressive for the same price point as an Arduino.  However, it is by no means an “Arduino killer”.  You could certainly swap out one for the other in some simple use cases.  However the two devices have very different capabilities, and I find that they actually complement each other quite well when combined.   
 
Pictured here left to right: Raspberry Pi, Arduino Mega, Arduino NG, Arduino Pro Mini
 
Here is one important reason the Arduino is still essential, from the author of Getting Started with Raspberry Pi:
 
When you have a problem that requires exact control in real time, such as a controller for a 3D printer.  Raspbian is not a Real Time operating system, and programs can’t necessarily depend on the same “instruction per clock cycles” rigor of a microcontroller.
 
Here are some other ways the Arduino has a leg up:
 
– Supports analog pins required for many types of sensors and actuators
– Supports a larger number of digital pins
– Includes PWM pins (pulse width modulation) used for some types of sensors and actuators
– Lower power consumption – Pi is about 7x the power consumption – ie, Arduino will last about 7x longer on battery
– Some Arduino clones are cheap as fudge
– Lots of parts made to integrate directly with Arduino, such as sheilds.
– Lots of code libraries exist for the Arduino
 
As for the Pi, the advantages are pretty obvious:
 
– Still the most processing power for your money
– Ability to easily program and drive graphics
– Integration with computer peripherals
– Access to tons of open source Linux and Python tools
– Easier to use for advanced network functionality (VNC on to it, run a websocket server, etc)
– Much more…
 

IMG_20130105_142231When connected to each other, the two devices can be use for the tasks they are best at. The Arduino for controlling hardware and the Pi for controlling software. There are a number of ways for them to communicate:

1.  They can have their own separate programs running and communicate over Serial, I2C, or SPI (only tried Serial so far)
 
2.  You can use something called “firmata” to control a connected Arduino directly from Node or Python on the Pi  (eg: Node Firmata)
 
The advantage of #1 is that you can still use libs written for Arduino to interface with hardware more efficiently.  The advantage of #2 is that you have just a single code base to maintain, without the need for context switching.  A HUGE plus with any method is that you can program your Arduino by VNC’ing into the Pi.  this is great if your setup is mounted somewhere inaccessible like on the ceiling or inside a casing.

IMG_20130105_142453

It’s hard to see what’s going on in the above images.  On the breadboard is an Arduino clone called the BBB from ModernDevice.com (white).  To cut it’s cost, it doesn’t have an on-board USB port, so to give it USB I use an component called a USB BUB (red).  Then there’s a male A to male mini-A USB adapter (black).  Finally I can connect the Raspberry Pi (green).

Install Arduino

Anyways, enough talking and more doing.  To get started, install the Arduino IDE on the Raspberry Pi:

sudo apt-get update
sudo apt-get install arduino

You’ll need to do this before running the Arduino IDE.

sudo usermod -a -G tty pi
sudo usermod -a -G dialout pi

Now you can launch Arduino IDE while running X11 by going to Start menu -> Programming -> Arduino IDE.  If your Pi is on WiFi, even better – VNC into it for remote and wireless control.  Keep in mind, you now have slightly more power consumption which may require you to use a power adapter with more amperage.  I was able to power a Pi, hooked up to an Arduino, hooked up to 25 addressable RGB LED pixels using a 5V 1.2A phone charger with no problem.

Install Node

I decided to start out programming on the Pi a little differently.  The more common way is to use Python which comes pre-installed.  I’ve recently been exploring Node.js and decided to see how it plays with the Pi.

Install Node.js with the following commands:

wget http://nodejs.org/dist/v0.8.17/node-v0.8.17.tar.gz
tar -zxf node-v0.8.17.tar.gz
cd node-v0.8.17
./configure
make
sudo make install

Next create a file as follows to test (must use 0.0.0.0 instead of 127.0.0.1):

1
2
3
4
5
6
var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
}).listen(8080, "0.0.0.0");
console.log('Server running at http://0.0.0.0:8080/');

To test, open up a browser on a computer which is on the same network as the Pi, and navigate to http://raspberrypi:8080 (or the IP address for example http://192.168.1.7:8080).  You should see “Hello World”.

Now that we have Arduino and Node working individually, lets get them working together.

Node + Arduino + Firmata

As mentioned above, Firmata is an interesting way to control the Arduino and get out of writing any C code. It wouldn’t be my preferred method since you lose out on some amazing open source Arduino libraries, but it’s a really easy way to control an Arduino on a very basic level.

1. Install Node and Arduino as explained above

2. Run Arduino IDE, open Examples->Firmata->StandardFirmata, and upload it to your Arduino board.

3. From terminal install the package firmata for Node:

sudo npm install -g firmata

4. Create a file called app.js containing the following code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
 * Sample script to blink LED 13
 */
 
console.log('blink start ...');
 
var ledPin = 13;
var firmata = require('/usr/local/lib/node_modules/firmata');
var board = new firmata.Board('/dev/ttyUSB0', function(err) {
    if (err) {
        console.log(err);
        return;
    }
    console.log('connected');
    console.log('Firmware: ' + board.firmware.name + '-' + board.firmware.version.major + '.' + board.firmware.version.minor);
 
    var ledOn = true;
    board.pinMode(ledPin, board.MODES.OUTPUT);
 
    setInterval(function(){
        if (ledOn) {
            console.log('+');
            board.digitalWrite(ledPin, board.HIGH);
        }
        else {
            console.log('-');
            board.digitalWrite(ledPin, board.LOW);
        }
        ledOn = !ledOn;
    },500)
 
});

5. Run the app as sudo:

sudo node app.js

Integrate Socket.io

So far, we’ve created a simple Node server script that controls the Arduino. How about giving it a front-end? That way you can interact with your Arduino using a web browser. Just for kicks, why not use websockets since that’s a nice and easy-to-work-with feature Node offers. Socket.io makes it even easier. Simply install Socket.io using the following command:

    sudo npm install -g socket.io

This is what I used for index.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<html>
    <head>
        <title>web led switch</title>
    </head>
    <body>
        <div>
            <p>
                <button id="switchButton">turn on</button>
            </p>
        </div>    
        <div>
            <ul id="messages">
            </ul>
        </div>
        <script src="socket.io/socket.io.js"></script>
        <script src="http://code.jquery.com/jquery-1.8.0.min.js"></script>
 
        <script>
            $(function(){
                var socket = io.connect('http://raspberrypi:8080');
 
                socket.on('connect', function() {
                    $('#messages').append('<li>Connected to the server.</li>');            
                });
 
                socket.on('message', function(message) {    
                    $('#messages').append('<li>' + message + '</li>');
                });
 
                socket.on('disconnect', function() {
                    $('#messages').append('<li>Disconnected from the server.</li>');            
                });
 
                $('#switchButton').bind('click', function() {
                    var message = $('#switchButton').text();
                    socket.send(message);
                    $('#messages').append('<li>me: ' + message + '</li>');
 
                    if (message == 'turn on')
                        $('#switchButton').text('turn off');
                    else 
                        $('#switchButton').text('turn on');
                });    
            });
        </script>
    </body>
</html>

This is app.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
var app = require('http').createServer(handler), 
    io = require('/usr/local/lib/node_modules/socket.io').listen(app), 
    fs = require('fs'),
    firmata = require('/usr/local/lib/node_modules/firmata'),
    board = new firmata.Board('/dev/ttyUSB0', arduinoReady);
 
var ledPin = 13;
 
function arduinoReady(err) {
    if (err) {
        console.log(err);
        return;
    }
    console.log('Firmware: ' + board.firmware.name 
      + '-' + board.firmware.version.major 
      + '.' + board.firmware.version.minor);
 
    var ledOn = true;
    board.pinMode(ledPin, board.MODES.OUTPUT);
}
 
app.listen(8080);
console.log("Listening on http://raspberrypi:8080...");
 
// directs page requests to html files
 
function handler (req, res) {
  fs.readFile(__dirname + '/index.html',
  function (err, data) {
    if (err) {
      res.writeHead(500);
      return res.end('Error loading index.html');
    }
 
    res.writeHead(200);
    res.end(data);
  });
}
 
// this handles socket.io comm from html files
 
io.sockets.on('connection', function(socket) {
    socket.send('connected...');
 
    socket.on('message', function(data) {
        if (data == 'turn on') {
            console.log('+');
            board.digitalWrite(ledPin, board.HIGH);
            socket.broadcast.send("let there be light!");
        }
        if (data == 'turn off') {
            console.log('-');
            board.digitalWrite(ledPin, board.LOW);
            socket.broadcast.send("who turned out the light?");
        }
        return;
    });
 
    socket.on('disconnect', function() {
        socket.send('disconnected...');
    });
});

8 comments

  1. Pingback: Creative Technologists of Toronto | Some Tutorials for Raspberry Pi and Inputs | Create, innovate, and have some beer!
  2. Pingback: Control an #Arduino from a #RaspberryPi using Node.js | Raspberry PiPod
  3. Pingback: Raspberry Pi + Arduino + Tornado
  4. Thomas

    Something is not working correctly.
    I think there is a fault in the HTML code.

    this is what is see when opening index.html:


    Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â
    Â Â Â Â Â Â Â Â Â Â Â Â
                    turn on            Â

    Â Â Â Â Â Â Â Â
    Â Â Â Â Â Â Â Â Â Â Â Â
    Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â
    Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â

    also, the app.js is only executed for a few seconds

    • Thomas

      this error i got when executing app.js:

      TypeError: Property ’64’ of object # is not a function
      at SerialPort.board.once.board.versionReceived (/usr/local/lib/node_modules/firmata/lib/firmata.js:337:43)
      at SerialPort.EventEmitter.emit (events.js:96:17)
      at Object.parsers.raw [as parser] (/usr/local/lib/node_modules/firmata/node_modules/serialport/serialport.js:23:13)
      at options.dataCallback (/usr/local/lib/node_modules/firmata/node_modules/serialport/serialport.js:90:13)
      at EventEmitter.emit (events.js:96:17)
      at ReadStream._emitData (fs.js:1368:10)
      at afterRead (fs.js:1350:10)
      at Object.wrapper [as oncomplete] (fs.js:362:17)

  5. Christian

    I got it working from my ubuntu laptop, running the source code from eclipse. It works from the local browser on both http://192.168.1.136:8080 / localhost:8080. But from an iOS device with both Chrome and Safari, it loads the page, but don’t connect to the server?

    Thank you for a great tutorial!

    • Christian

      Foolish me, I figured it out. Made a change in app.js line 22 to: app.listen(8080, “192.168.1.136”); and then it worked. Remember to change index.html correspondingly…

      Man, this is awesome!

  6. mahendra

    hi..niltoid.
    I am Mahendra from India.
    your blog is really awesome..
    it is really very very useful.
    i was googling for the project to send and receive data from raspberyy pi to arduino in realtime from web. and i found your blog.
    but I just want to confirm that which is best way (fastest, reliable) to do this project. ???
    tornado or jode.js or anyother..
    thanx in advance..
    I will really appreciate your help..

Post a comment

You may use the following HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>