Category: Robotics

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