ajfisher's doing space

From the Blog

Smart phones are becoming more sophisticated devices by the month it seems – you can even make phone calls with them I’m told. I’ve played around quite a bit with using bluetooth as a connection method between arduinos and mobile phones and whilst it works fairly well there’s a lot of overhead and your battery life is terrible for both phone and device.

One of the areas I’m looking into at the moment though is how mobile web browsers, particularly using the device APIs and web sockets can create interesting interaction points with nothing more than a browser on one side and then some interpretation of messages on the other.

Presently to achieve this I’m using Django Socket IO – a great little web sockets server and because it’s written in Python allows you full access to a serial connection to then talk to the arduino.

On the browser side it’s simply a case of hooking the relevant Device Event – devicemotion or deviceorientation then providing a call back to do something with it – in this case sending the data to a web socket connection.

// assumes some socketio code here to register to a room.
 
window.addEventListener("deviceorientation", update_gyro, true);
 
function update_gyro(e) {
	// gets the gyro position
    var x, y, z = 0;
    var o = deviceOrientation(e);
 
	update_text(o.gamma, o.beta, o.alpha);
    if ((new Date()).getTime() - last_sent > threshold) {
		socket.send({room: room, action: 'movement', x: o.gamma, y: o.beta, z: o.alpha, method: 'orientation'});
    }
}

After this we write a handler to take the data and do something with it. In this case a Django view that is a web socket message handler.

import serial
 
from django.shortcuts import get_object_or_404, render, redirect
from django_socketio import events
 
SERIAL_INTERFACE = "/dev/ttyUSB0"
SERIAL_BAUD = 115200
 
try:
    ser = serial.Serial(SERIAL_INTERFACE, SERIAL_BAUD, timeout=60)
except:
    print "Can't get a serial connection"
 
@events.on_message(channel="^light")
def message(request, socket, message):
    message = message[0]
    if message["action"] == "movement":
        socket.send({"action": "ack"})
 
        # pick up the values from the socket message
        x = int(message["x"])
        y = int(message["y"])
        z = int(message["z"])
 
        # now normalise the values as needed
        if message["method"] == "orientation":
            # put the vals back into +ive integer range as needed
            x += 90 #normalise 0-180
            y += 360 # normalise 0-360
 
        if x > 180:
            x = 180
        if y > 360:
            y = 360
        if z >= 360:
            z = 0
 
        # work out the y bytes
        # leaving this like this even though it's normalised back to 180 deg.
        # just in case there's any more changes to firefox.
        yh = y >> 8
        if y > 255:
            yl = y - 256
        else:
            yl = y
        # work out the z bytes
        zh = z >> 8
        if z > 255 :
            zl = z - 256
        else:
            zl = z
 
        #print "x: %s y: %s z: %s" % (x, y, z)
        try:
            ser.write("%s%s%s%s%s%s%s" % (chr(255), chr(255), chr(x), chr(yh), chr(yl), chr(zh), chr(zl)))
        except:
            #do  nothing - this is a good test anyway.
            print "Doing nothing as no serial"
 
    elif message["action"] == "test":
        # this is a test of the socket
        print "Test of the socket"
        socket.send({"action": "bcast", "message": "got a test"})

 

So this is really really early stage at this point and I’ve got a couple of demos that I’m building at the moment so will post them once they’ve solidified.

This little project started out really as a means of testing my Parallax Ping))) ultrasonic rangefinder that I got from Little Bird last week. As normal however a six year old wanted to understand what I was doing and how it all worked. So, what started as a test turned into something a little more fun in order to create an explanation for what was involved.

Materials:

  • A Parallax Ping))) range finder
  • Arduino (any type should work – I used a Freetronics Eleven)
  • An RGB LED (with relevant current limiting resistors – or you could use these cheap, fun DF Robot 7-LED SMD light discs). The code assumes a Common ANODE type LED.
  • A breadboard and some hookup or jumper wires

Directions:

Plug the ping))) in to +5v and GND and connect the signal pin to digital pin 7 on the arduino (this uses the same set up as the ping))) arduino example).

Connect your RGB LED to +5v and then connect your Red leg to Pin 9, Green leg to Pin 10 and Blue leg to pin 11. This is where your breadboard comes in handy because you can put your LEDs and sensor on the board then jumper everything to the arduino (see photo below for my set up).

* note that I haven’t

Wiring photos

 

Code:

Load the following code onto your Arduino (can also be downloaded from the gist here):

/*
  WARMER COOLER GAME
 
  Use a ping sensor to determine distance and then depending on the distance,
  show warmer or cooler colours.
 
  Built using a ping))) Sensor and connected to a RGB display.
 
  Uses the ping))) example in the base Arduino install,
  written by David Mellis & Tom Igoe
  http://www.arduino.cc/en/Tutorial/Ping
 
 */
 
#define PING_PIN 7
#define RED 9
#define GREEN 10
#define BLUE 11
 
#define BLUE_LONG 400
#define BLUE_SHORT 175
#define GREEN_LONG 225
#define GREEN_SHORT 75
#define RED_LONG 125
#define RED_SHORT 0
 
void setup() {
  // initialize serial communication:
  Serial.begin(9600);
 
  // set the LED off
  pinMode(RED, OUTPUT);
  pinMode(GREEN, OUTPUT);
  pinMode(BLUE, OUTPUT);
 
  // uses a common anode RGB LED (so +5v turns them off)
  digitalWrite(RED, HIGH);
  digitalWrite(GREEN, HIGH);
  digitalWrite(BLUE, HIGH);
}
 
void loop()
{
 
  long distance;
  distance = ping();
 
  // now depending on the distances we map the colours on the LED.
  // BLUE will be bright at about 350 cm fading out to 175cm
  // GREEN will be bright about 225cm fading out to about 75cm
  // RED will be faded at about 125cm getting bright to 0cm
 
  if (distance > RED_LONG) {
    digitalWrite(RED, HIGH);
  } else {
    analogWrite(RED, map(distance, RED_LONG, RED_SHORT, 255, 0));
  }
  if ((distance > GREEN_LONG) || (distance < GREEN_SHORT)) {
        digitalWrite(GREEN, HIGH);
  } else {
        analogWrite(GREEN, map(distance, GREEN_LONG, GREEN_SHORT, 255, 0));
    }
  if ((distance > BLUE_LONG) || (distance < BLUE_SHORT)) {
      digitalWrite(BLUE, HIGH);
  } else {
      analogWrite(BLUE, map(distance, BLUE_LONG, BLUE_SHORT, 255, 0));
  }
 
  Serial.print(distance);
  Serial.print("cm");
  Serial.println();
 
  delay(100);
}
 
long ping() {
  // returns the distance to the nearest object.
  // establish variables for duration of the ping,
  // and the distance result in inches and centimeters:
  long duration, cm;
 
  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(PING_PIN, OUTPUT);
  digitalWrite(PING_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(PING_PIN, HIGH);
  delayMicroseconds(5);
  digitalWrite(PING_PIN, LOW);
 
  // The same pin is used to read the signal from the PING))): a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(PING_PIN, INPUT);
  duration = pulseIn(PING_PIN, HIGH);
 
  // convert the time into a distance
  return (microsecondsToCentimeters(duration));
 
}
 
long microsecondsToCentimeters(long microseconds)
{
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return microseconds / 29 / 2;
}

The code is pretty straight forward – get the distance on the range finder using the ping() function then use that distance to determine which coloured LEDs should be switched on. Note that there is some overlaps between the ranges so you get a transition from blue to green and then from green to red.

Given the rangefinder’s view is narrow and 6-year olds tend to be small and unable to stand still for long periods of time, the game then turned into how long you could keep the LEDs solid green.