Monthly Archives: December 2012

Complete on{X} script to control the Where Clock

After a lot of head scratching I’ve finished the on{X} script to control the Where Clock: making it turn  around when I enter or leave places. Here it is:

// add your locations to this list, use as many decimal places as possible, these are fake  :-) 
var locations = [
    {name: "home", lat: 50.9, lon: -1.3, rad: 1},
    {name: "pilates", lat: 51.9, lon: -1.3, rad: 1},
    {name: "pub", lat: 52.9, lon: -1.3, rad: 1}
    ];
var hostname = "your.hostname.here";
var port = "1234";  // your port here

function move(place) {
    console.log('Entered region: ' + place);
    device.ajax(
    {
      url: "http://" + hostname + ":" + port + "/move?l=" + place,
      type: 'GET',
      headers: {}
    },
    function onSuccess(body, textStatus, response) {
        var msg = device.notifications.createNotification('Clock is set to: ' + place);
        msg.show();
        console.log('Success: ' + textStatus);
    },
    function onError(textStatus, response) {
        var msg = device.notifications.createNotification('Failed to set clock to ' + place + '\n' + textStatus);
        msg.show();
        console.log('Error: ' + textStatus);
    });
}

function build_callback(place) {
    console.log("Building callback for " + place);
    return function() {
        move(place);
    };
}

for (i = 0; i < locations.length; i++) {
    var location = locations[i];
    var region = device.regions.createRegion({
        latitude: location.lat,
        longitude: location.lon,
        name: location.name,
        radius: location.rad
    });
    region.on('enter', build_callback(region.name));
    region.on('exit', build_callback("travelling"));
    device.regions.startMonitoring(region);
}
console.log("Script executed");

// test code follows
/*
var regions = device.regions.getAll();
console.log(regions.length);
for (i = 0; i < regions.length; i++) {
    r = regions[i];
    console.log(r.name + ":" + r.latitude + ':' + r.longitude + ':' + r.radius);
}
var locationSignal = { latitude: 50.919675, longitude: -1.377101 };
regions[0].emit('enter', locationSignal);
regions[0].emit('exit', locationSignal);
regions[1].emit('enter', locationSignal);
regions[1].emit('exit', locationSignal);
regions[2].emit('enter', locationSignal);
regions[2].emit('exit', locationSignal);
*/

The hardest part was the callback (line 45). I’m not that good at Javascript and I’m never sure if things are being passed by value or reference and when they are evaluated. You have to provide a function that will be called when a region is entered or exited. The API for regions shows a callback inline with a “signal” parameter passed to it. The tricky thing is, how to do that in a loop? I want to loop through all the locations defined at the top of the script and set all the entry and exit callbacks for them.

You can’t just do

region.on('enter', move(region.name))

because the “move(region.name)” gets evaluated (called) as the callback is defined so it sends instructions to move to all the places at the beginning (and probably not later). So we need some delay to the evaluation.

You also can’t just do

region.on('enter', function () { move(region.name); });

because all those anonymous callback functions get bound to the same instance of “region”: Javascript (unnecessarily) reuses the object each time it goes round the loop. When “region.name” is evaluated it ends up being whatever the last place you defined was. In this example I would always be at the pub…

(To be fair, the surprisingly good Javascript editor in the on{X} web page does warn you against creating functions in loops, presumably for this very reason.)

The solution is in the code above: set the callback to be the result of the “build_callback” function which returns a function that calls the “move” function with the place already evaluated and fixed.

You might have noticed that in the code above, the regions are defined to have a 1m radius.  I originally set them to be 10m which seems to make more sense. However, although this code seems to be correct now it doesn’t actually work very well.  I went to the shops today and it was only once I was about 3 miles away from home that the phone sent the “travelling” signal (because it realised I was outside the home region) and then it did send the “home” signal at some point when I got back but I missed it.

So I think it’s all technically working now but that on{X} just isn’t up to the job.  I might try with tasker instead but I never got on with tasker’s UI.

Using on{X} to control the Where Clock

I want to be able to send GET requests to the web server on my Raspberry Pi from my phone so that I can have the hand of the Where Clock turn to point at where I am or what I’m doing.

Of course, I can fire up a web browser on my phone and type in the URL of the Pi’s web server but that’s a little inconvenient: it needs to be automatic, driven by my location or other events. That’s where an interesting project from Microsoft comes in: on{X}. You go to that site and sign in with Facebook, download an app to your Android phone and again associate it with Facebook and then, on the web site, you can write little scripts using JavaScript which get sent to your phone and run there.

The API for on{X} is designed so that you can perform actions when certain events happen (hence the name of the system: on{X}) and it’s very easy to use. Here’s my first attempt to get the Where Clock to move, it fires when my phone’s screen is unlocked:

device.screen.on("unlock", function(){
    console.log('Screen unlocked');
    device.ajax(
    {
        url: 'http://raspberry1.scphillips.com:8080/move?a=180',
        type: 'GET',
        headers: {}
    },
    function onSuccess(body, textStatus, response) {
        var msg = device.notifications.createNotification('Clock is set: ' + textStatus);
        msg.show();
        console.log('Success: ' + textStatus);
    },
    function onError(textStatus, response) {
        var msg = device.notifications.createNotification('Error: ' + textStatus);
        msg.show();
        console.log('Error: ' + textStatus);
    });
});

The notification messages pop up in the notification bar on the phone and the console messages go to a log that can be viewed in the on{X} app or on the on{X} website. All the script does is when the screen is unlocked it calls the Raspberry Pi’s web server (using the “ajax” method) and then depending on the response it receives reports success or the error. The move command sent to the server just sends it to 180 degrees so doing it a second time appears to have no effect on the clock.

It is surely just a small step from this to something that moves the hand based on location and anything else I can think of.

Moving the Where Clock from a web browser

Now I’ve got a web server and I’ve got code to control the stepper motor, let’s put them together and control the stepper motor from a web browser!  Here’s the new code: clockServer.py

#!/usr/bin/env python

# This code is written by Stephen C Phillips.
# It is in the public domain, so you can do what you like with it
# but a link to http://scphillips.com would be nice.

import socket
import re
import RPi.GPIO as GPIO
from move import Motor

# Set up stepper-motor:
GPIO.setmode(GPIO.BOARD)
motor = Motor([18,22,24,26])
motor.rpm = 5

# Standard socket stuff:
host = ''  # do we need socket.gethostname() ?
port = 8080
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((host, port))
sock.listen(1)  # don't queue up any requests

# Loop forever, listening for requests:
while True:
    print "Waiting..."
    csock, caddr = sock.accept()
    print "Connection from: " + `caddr`
    req = csock.recv(1024)  # get the request, 1kB max
    req = req.split("\n")[0]
    print "Request: " + req
    # Look in the first line of the request for a move command
    # A move command should be e.g. 'http://server/move?a=90'
    match = re.match('GET /move\?a=(\d+)\sHTTP/1', req)
    if match:
        angle = int(match.group(1))
        print "Angle: " + `angle`
        csock.sendall("HTTP/1.0 200 OK\r\n")
        print "Moving motor..."
        motor.move_to(angle)
    else:
        # If there was no recognised command then return a 404 (page not found)
        print "Returning 404"
        csock.sendall("HTTP/1.0 404 Not Found\r\n")
    csock.close()
    print "--------"

This is pretty much the same as the little web server from the last post, but this time instead of returning a web page when we’re asked to move the motor we just return a 200 code and actually move the motor (lines 36-40). This is very nearly all in place now – I just need to get the phone to call the web server at appropriate moments.

Till then, here’s a little video:

A simple Python webserver

Now I can control the stepper-motor from Python I need to be able to tell the Raspberry Pi to move the motor from my phone so that, for instance, when I get to work it can tell the motor to move the indicator hand to point to “Work”.

To do this, the easiest way seem to me to be using a web server on the Pi.  I want to make it so that if you GET the URL http://<raspberry.server>:8080/move?a=90 then it will move the hand to 90 degrees. This normally requires a web server and a CGI script but it seemed overkill to install Apache or even something lighter-weight such as lighttpd or nginx for such a simple task so I’ve written my own: much more interesting!

#!/usr/bin/env python

# This code is written by Stephen C Phillips.
# It is in the public domain, so you can do what you like with it
# but a link to http://scphillips.com would be nice.

import socket
import re

# Standard socket stuff:
host = ''  # do we need socket.gethostname() ?
port = 8080
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((host, port))
sock.listen(1)  # don't queue up any requests

# Loop forever, listening for requests:
while True:
    csock, caddr = sock.accept()
    print "Connection from: " + `caddr`
    req = csock.recv(1024)  # get the request, 1kB max
    print req
    # Look in the first line of the request for a move command
    # A move command should be e.g. 'http://server/move?a=90'
    match = re.match('GET /move\?a=(\d+)\sHTTP/1', req)
    if match:
        angle = match.group(1)
        print "ANGLE: " + angle + "\n"
        csock.sendall("""HTTP/1.0 200 OK
Content-Type: text/html

<html>
<head>
<title>Success</title>
</head>
<body>
Boo!
</body>
</html>
""")
    else:
        # If there was no recognised command then return a 404 (page not found)
        print "Returning 404"
        csock.sendall("HTTP/1.0 404 Not Found\r\n")
    csock.close()

This is about as simple as a web server gets. It sets up a server socket to listen on using port 8080 and doesn’t queue up any requests (it’s not going to get many…).  When a connection is made from the client (e.g. a web browser) the “sock.accept()” line (19) creates a client socket to communicate with the client on.  We then just read at most 1kB of data from the client, which is the HTTP headers saying what the client wants and using a regular expression (line 25) we see if it is a “move” request and pull out the angle.  If it was a move request then we print the angle to the console and return a simple web page by using “csock.sendall” on line 29.  Otherwise we return a 404 error (line 45).  Finally we close the client socket and loop round to the top again to wait for another connection.

If I run this script (e.g. “python server.py”) and go to the URL “http://<server>:8080/move?a=20″ then I see this on the console of the Pi:

Connection from: ('192.168.1.129', 54340)
GET /move?a=20 HTTP/1.1
Host: raspberry1.scphillips.com:8080
Connection: keep-alive
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
DNT: 1
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

ANGLE: 20

Connection from: ('192.168.1.129', 54344)
GET /favicon.ico HTTP/1.1
Host: raspberry1.scphillips.com:8080
Connection: keep-alive
Accept: */*
DNT: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

Returning 404

So we first get a connection from IP address 192.168.1.129 (my address on my home network) asking for “/move?a=20″ using HTTP version 1.1.  It then says that it wants that “page” from “Host: raspberry1.scphillips.com:8080″.  This is in case my web browser is talking to a proxy – the proxy needs to know where to get the page from (however, in this case there is no proxy).  There are then a load of other headers that describe what the client is and how it would like information sent to it (language, character set, etc).

The web server ignores all but the first line of the headers, spots that it’s a move request and prints out the angle to the console.  Immediately we then get a second request from the web browser asking for the “favicon.ico” – this just happens automatically.  The favicon is the little icon you see in the address bar of most websites.  Web browsers request them a lot. Our little web server just ignores this request and sends a 404 (page not found) so the web browser is happy.

On the web browser we get a page that says “Boo!”.

Next, this needs linking up with the Motor class from the last post.

A Python class to move the stepper motor

To properly control the stepper motor from the Raspberry Pi we need a class to represent it. This is one of the most direct ways of understanding object oriented programming (OOP): from the class you make an “object” and the object represents and controls an object in the real world (the stepper motor).

The class lets us remember (and control) all the information we need:

  • the pins the motor is connected on;
  • the speed of the motor;
  • the angle the motor is currently pointing to.

The motor seems to have 4096 positions (steps) it can point to.  These don’t correspond exactly to degrees. The class takes an angle we want the motor to point to, converts that into a step position and works out how many steps to turn it by and in what direction to get there.

Actually, it doesn’t move to the step position that is closest to the angle, it chooses step positions that are divisible by 8 because the control sequence has 8 steps in it and I didn’t want to bother starting or stopping in the middle of the sequence.

#!/usr/bin/env python

# This code is written by Stephen C Phillips.
# It is in the public domain, so you can do what you like with it
# but a link to http://scphillips.com would be nice.

# It works on the Raspberry Pi computer with the standard Debian Wheezy OS and
# the 28BJY-48 stepper motor with ULN2003 control board.

from time import sleep
import RPi.GPIO as GPIO

class Motor(object):
    def __init__(self, pins):
        self.P1 = pins[0]
        self.P2 = pins[1]
        self.P3 = pins[2]
        self.P4 = pins[3]
        self.deg_per_step = 5.625 / 64
        self.steps_per_rev = int(360 / self.deg_per_step)  # 4096
        self.step_angle = 0  # Assume the way it is pointing is zero degrees
        for p in pins:
            GPIO.setup(p, GPIO.OUT)
            GPIO.output(p, 0)

    def _set_rpm(self, rpm):
        """Set the turn speed in RPM."""
        self._rpm = rpm
        # T is the amount of time to stop between signals
        self._T = (60.0 / rpm) / self.steps_per_rev

    # This means you can set "rpm" as if it is an attribute and
    # behind the scenes it sets the _T attribute
    rpm = property(lambda self: self._rpm, _set_rpm)

    def move_to(self, angle):
        """Take the shortest route to a particular angle (degrees)."""
        # Make sure there is a 1:1 mapping between angle and stepper angle
        target_step_angle = 8 * (int(angle / self.deg_per_step) / 8)
        steps = target_step_angle - self.step_angle
        steps = (steps % self.steps_per_rev)
        if steps > self.steps_per_rev / 2:
            steps -= self.steps_per_rev
            print "moving " + `steps` + " steps"
            self._move_acw(-steps / 8)
        else:
            print "moving " + `steps` + " steps"
            self._move_cw(steps / 8)
        self.step_angle = target_step_angle

    def _move_acw(self, big_steps):
        GPIO.output(self.P1, 0)
        GPIO.output(self.P2, 0)
        GPIO.output(self.P3, 0)
        GPIO.output(self.P4, 0)
        for i in range(big_steps):
            GPIO.output(self.P1, 0)
            sleep(self._T)
            GPIO.output(self.P3, 1)
            sleep(self._T)
            GPIO.output(self.P4, 0)
            sleep(self._T)
            GPIO.output(self.P2, 1)
            sleep(self._T)
            GPIO.output(self.P3, 0)
            sleep(self._T)
            GPIO.output(self.P1, 1)
            sleep(self._T)
            GPIO.output(self.P2, 0)
            sleep(self._T)
            GPIO.output(self.P4, 1)
            sleep(self._T)

    def _move_cw(self, big_steps):
        GPIO.output(self.P1, 0)
        GPIO.output(self.P2, 0)
        GPIO.output(self.P3, 0)
        GPIO.output(self.P4, 0)
        for i in range(big_steps):
            GPIO.output(self.P3, 0)
            sleep(self._T)
            GPIO.output(self.P1, 1)
            sleep(self._T)
            GPIO.output(self.P4, 0)
            sleep(self._T)
            GPIO.output(self.P2, 1)
            sleep(self._T)
            GPIO.output(self.P1, 0)
            sleep(self._T)
            GPIO.output(self.P3, 1)
            sleep(self._T)
            GPIO.output(self.P2, 0)
            sleep(self._T)
            GPIO.output(self.P4, 1)
            sleep(self._T)

if __name__ == "__main__":
    GPIO.setmode(GPIO.BOARD)
    m = Motor([18,22,24,26])
    m.rpm = 5
    print "Pause in seconds: " + `m._T`
    m.move_to(90)
    sleep(1)
    m.move_to(0)
    sleep(1)
    m.move_to(-90)
    sleep(1)
    m.move_to(-180)
    sleep(1)
    m.move_to(0)
    GPIO.cleanup()

If you save it as “move.py” you can run it using “sudo python move.py”. It will then move the motor round by 90 degrees, pause for 1 second, move it back again and so on according to the instructions at the end of the program. Alternatively, you can import the file and use the class from another program which is what I’ll be doing soon…

Wiring done right

With the new jumper leads from eBay I wired it all up again. For the power, the motor controller board has 4 pins and I don’t know why.  Two of them are bridged by a jumper and by the other two there is a “-” and a “+” and “5-12V” underneath.  I wired the 5V pin of the Pi (P2) to the one labelled “+” and the ground pin of the Pi (P1) to the “-”.  Seems to work, but I don’t know if I just got lucky or whether it doesn’t matter which way round you put them.

For the controller lines I wired P18, P22, P24 and P26 to IN1, IN2, IN3 and IN4 respectively. That done, I turned it on and tried some software.

I think I tried the Python code on Matt’s blog first but somehow it didn’t quite work – I don’t remember  now.  What was great though was that although the motor didn’t seem to turn the LEDs came on so I had got something happening! After a bit of puzzling I realised that the LEDs are wired to the four control lines of the motor so they are very useful in diagnosing what is happening and checking you’ve got the right control sequence.

I spent some time Googling (finding Patrick’s blog), trying to understand the motor’s datasheet, and combining Matt and Patrick’s Python code to make my own version that works for me:

#!/usr/bin/env python
# Based on http://patrickcambria.com/downloads/stepper.py

# This code is written by Stephen C Phillips.
# It is in the public domain, so you can do what you like with it
# but a link to http://scphillips.com would be nice.

from time import sleep
import RPi.GPIO as GPIO
import argparse

parser = argparse.ArgumentParser(description='Stepper motor arguments')
parser.add_argument('-rpm', action='store', dest='rpm', type=float)
parser.add_argument('-revs', action='store', dest='revs', type=int)
args = parser.parse_args()

step_angle = 5.625 / 64
steps_per_rev = int(360 / step_angle)
T = (60 / args.rpm) / steps_per_rev

print "Stepping @ " + `T` + " seconds per step"

GPIO.setmode(GPIO.BOARD)

Q1 = 18
Q2 = 22
Q3 = 24
Q4 = 26

GPIO.setup(Q1, GPIO.OUT)
GPIO.setup(Q2, GPIO.OUT)
GPIO.setup(Q3, GPIO.OUT)
GPIO.setup(Q4, GPIO.OUT)

GPIO.output(Q1,0)
GPIO.output(Q2,0)
GPIO.output(Q3,0)
GPIO.output(Q4,0)

# This makes it go anti-clockwise
for i in range(args.revs * steps_per_rev / 8):
    GPIO.output(Q1,0)
    sleep(T)
    GPIO.output(Q3,1)
    sleep(T)
    GPIO.output(Q4,0)
    sleep(T)
    GPIO.output(Q2,1)
    sleep(T)
    GPIO.output(Q3,0)
    sleep(T)
    GPIO.output(Q1,1)
    sleep(T)
    GPIO.output(Q2,0)
    sleep(T)
    GPIO.output(Q4,1)
    sleep(T)

GPIO.cleanup()

Lines 12-15 are just dealing with command line arguments: you can tell it how many times to turn round with “-revs” and how fast to go with “-rpm” (revolutions per minute).  I found that 10rpm was about as fast as it can go.

Lines 23-38 set the pins up using the pin numbers from the Raspberry Pi’s circuit board (starts 1 bottom left, 2 top left and goes up from there).  It sets them to be outputs and sets them to zero (0V I assume).

Lines 41-57 actually encode the sequence of ons and offs given in the motor’s datasheet and loops round it the right number of times.  Finally, it sets all the pins to zero again. I found it made the motor turn anti-clockwise, though the datasheet says the sequence is for clockwise rotation – perhaps it is because I plugged the 5V and ground pins in the wrong way round?

I called it “spin.py”.  To run it you have to type “sudo python spin.py” because you have to have root permissions to access the GPIO port.

Once this worked I started trying to do something more sophisticated but quickly realised that I needed to make a class to hold the state of the motor.  More on that next time…

Stepper motor

Two motors, just in caseTo make the Where Clock I need a stepper motors. I don’t know how stepper motors work but I know you can get them to turn around to point in a particular direction. Of course, I’m not the first person to think of this and after a bit of Googling I found a page about using stepper-motors from a Raspberry Pi.

That blog suggested a 28BJY-48 with ULN2003 control board which can be bought from eBay from “4tronix_uk” so I went ahead and bought 2 (just in case I needed another for something…). The motors arrived quickly and I took one, along with a Pi into Maplins to get some wires to join them together. Unfortunately, Maplins do not have the female to female jumper leads you need to connect the Pi directly to the controller board of the stepper motor. Instead I was sold some male-female leads and an IDE cable! The IDE cable fits onto the GPIO pins of the Pi (well, it hangs over the side) and we thought I could stick the male end of the jumpers into the other end of the IDE cable and then the female ends onto the motor’s board.

All wired up
Following the instructions about which GPIO pin is which on the same blog as before (mine is a revision 2 Pi), I cautiously wired it all up.  It was extra complicated because I had to also count along the holes in the IDE cable.  I then copied the code from the first post crossed my fingers and ran it.

Well, it didn’t work.  I got out the multimeter and checked there was the right voltage on the pins on the Pi (for instance, 5V between pins 2 and 6 and 3V between 2 and 1) but I could find no reading at the other end of the cabling.  I think perhaps that the male pins on the jumper leads weren’t quite long enough to connect to the IDE cable.

So, back to the drawing board, or rather eBay, where I purchased a bunch of female to female jumper leads from “phenoptix“.  They were listed as being for the arduino, but are just fine and arrived the next day…

The start of something

I’ve been thinking about having a blog for a long time as a place to put information that other people might find useful. Finally I’ve got one (it is very easy to set up thanks to my host, Webfaction). I suppose I finally thought I had something interesting enough to share.

I bought a couple of Raspberry Pi computers a few weeks back (from ModMyPi), not with any concrete plans as to what to do with them but I felt sure that they’d be useful for something (print server, file server, XBMC system for behind the telly, programming fun for the children, etc…). Well, somehow at work I got to reading about the Internet of Things (IoT) which is a buzz word these days. I think perhaps this page was linked to from the BBC R&D blog? Anyway it’s a great read and has a “Where Dial” mentioned as one of the interesting internet-connected “things” that are possible these days.  The Where Dial is inspired by the clock in the Weasley’s house in the Harry Potter books.  It doesn’t tell the time, but instead has a hand for each member of the family that moves round to point at various states such as “travelling”, “hospital” or “mortal peril”.

So, I thought I’ve got a Raspberry Pi, I’ve been wanting to hook it up to some hardware and I’ve also wanted to have a play with Android software, particularly an interesting event-driven system for Android called on{X} from (would you believe) Microsoft.

Why not make my own Where Dial, or as I am calling it, a “Where Clock”?  Perhaps the “mortal peril” state can be activated if the accelerometer goes above 1g?