Category: Node

Raspberry Pi Telepresence Robot

tele-robot

A telepresence robot allows users to interact with remote environments. You see what the robot see’s, hear what it hears, and you’re able to command it to move around and pick up objects. This project is a very simplified version of a telepresence robot. It includes the following features:

– live video streaming
– pan and tilt control
– motion sensor data display

Raspberry Pi + Arduino + Node = Home Automation

 

After figuring out how to set up the Raspberry Pi and how to communicate between a Raspberry Pi and an Arduino, I wanted to try a simple home-automation project that incorporated several really awesome and useful technologies:

Raspberry Pi
– Node
– Socket.IO
– Canvas with KineticJS
Arduino
– RGB LED Pixels

The following diagram shows how all this tech is arranged.  

Screen Shot 2013-02-05 at 10.29.26 PM

This is by no means the only way to do home-automation, but its a fun project if you don’t mind programming, and there are a lot of advantages to using these particular tools.  Having a browser based interface allows you to work the controls from virtually any computer or mobile device.  Canvas gives you the ability to create a rich interactive experience for the end-user.  KineticJS makes it incredibly easy to make canvas animations.  The Raspberry Pi gives you the benefit of a fully functional web server and allows the project to be portable.  Node makes developing that web server as well as serial communication with the Arduino quick and easy.  Websockets and Socket.IO allow the server to easily push updates to all clients in real time, so if I tweak a slider, everyone viewing the control panel sees me move it.  Finally the Arduino gives us an easy way to control the physical world and access to countless libraries including one that helps to work with the RGB LED Pixels .

Here is a video of the whole thing in action:

In my previous tests, Firmata was a great choice for integrating the Pi and Arduino since it simplified the code base – instead of writing a C program for the Arduino, the Arduino was controlled directly from my Node program.  In this case however, I opted to leverage this Adafruit Arduino library to work with the RGB LED Pixels.  So it made more sense to write a separate Arduino sketch which incorporates this lib and communicates with Node over serial.  Couple of things to note:

1. Arduino libraries go in this location:
    /usr/share/arduino/libraries/

2. Node serial communication can be done using this package
    sudo npm install -g serialport

3. Optional: Since the Arduino IDE is quite slow on the Pi, Ino is a great option for building and uploading arduino code from the command line.

IMG_20121223_032817
Here is our holiday tree outfitted with RGB LED Pixels from Adafruit.com

 

IMG_20121223_032021
From another angle you can see the attached Raspberry Pi and Arduino (in the dark)

 

IMG_20130105_142453
A clearer daytime pic of the setup. Breadboard with BBB Arduino Clone –> USB BUB –> male-to-male mini-A USB adapter –> Raspberry Pi

 

nodeOnPi
The Raspberry Pi is running a Node web server which communicates with clients using Socket.IO. Here it is in its entirety. For the canvas and arduino code, see the Github repo below.

 

ledMixer
When on the same network as the Pi, navigating a browser to http://raspberrypi:8080 brings up this canvas based control panel. I used KineticJS to make this happen faster

IMG_20121223_033341_1

Next, I’d like to take this project further by having a line of communication coming back from the Arduino to the canvas front-end.  When multiple clients are looking at the control panel and one user moves the sliders, everyone should see them move in close to real time.

In addition to my desktop browser, I tried this out from my Android device (LG Nexus 4 running Chromium).  I was disappointed to find that the animation is clunky and jumpy, and touch control is inaccurate.  I’ve heard that unless they’re very simple, canvas animations require extensive optimization to work in mobile browsers.  I have friends that are struggling with similar issues, so hopefully there will be some advancement in this area on mobile browsers to make canvas truly universal.

The source code for this project is available here on Github.

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...');
    });
});