Monday, 14 October 2013

Update on the pi bot simulator

It's been a little while and I've got a little further with my pi bot simulator. There's not a lot to describe on top my earlier plans. Basically I now have:
  • A unity program that runs a simulation of a robot
  • A unity plugin that runs a small tcp server. It stores some values such as 'motor speed', 'sensor value', 'servo position'.
  • A python script that connects to the server to set values that unity reads for controlling the robot, or to retrieve values that unity stores from the 'sensors'.
My simulated robot now has 2 motors, 2 neck servos, 2 eye servos, front, back, left, right and bottom range finders and a couple of eye cameras. 

The server code is a bit of bog standard c++ use of sockets. It reads in a 4 byte message length followed by a text based command, interprets it and sends a response. The code is longer than I'd like in true c++ style, but the nice python interpreter is much more precise:

import socket
import struct

print("Running inputtest.py")

HOST = 'localhost'    # The remote host
PORT = 5152              # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

#handy recvall function to block until a fixed number of bytes are read
def recvall(sock,requested_bytes):
    total_data=bytes(0)
    while len(total_data) < requested_bytes:
        data = sock.recv(requested_bytes-len(total_data))
        total_data = total_data + data
    return total_data

#Recv a block of text as a msg with 4 byte length header
def RecvText():
    lenbytes = struct.unpack("<i",recvall(s,4))[0]
    data = recvall(s,lenbytes);
    return data.decode()

print("Begin client loop")
while True:
    #read in a message to send
    val = input("Please input something\n")
    if(val == "q"): #bail out if quit requested
        break;
    
    #get the number of bytes
    lenbytes = struct.pack("<i",len(val))

    #send the bytes and print out the response
    s.sendall(lenbytes)
    s.sendall(val.encode())
    print(RecvText())

s.close();

Using this little script I can send commands such as:

set motor0 0.5

This results in:

  • The script posting the text "set motor0 0.5" to the server
  • The servo decoding this and assigning 0.5 to the variable RequestedMotorPower[0]
  • Unity querying the latest requested power for motor0 and assigning it to the motor joint in the simulation
Its the sort of thing that's much better described in video though, so here's a little demo:



Next up I'll getting those camera feeds through to python somehow, and get a slightly prettier python project going on with some proper modules to make the whole thing a bit more readable. In theory from there I should be able to run the very same scripts on the raspberry pi and have it controlling the simulation.

Tuesday, 17 September 2013

Pi Bot Simulator

I decided to begin a new robot recently, but first I've decided to simulate one. Why? Well a good few reasons....
  • It's going to take some serious coding, and I wanted to make sure I was up to the task before spending time and money building it
  • Making digital tweaks to the design is easier than making them once its built
  • Programming on my nice shiny lap top is much easier than writing code and distributing it out to multiple raspberry pis while plugged into a robot!


So this'll divide up into a few areas which I'll detail here.

The Architecture

I'm writing the simulation in unity. Basically it involves:
  • A basic physical model of the robot, in a simple physical world.
  • Scripts to replicate the behaviors of the various components of the physical robot (i.e. a servo script that feeds input into a unity hinge joint).
  • A central script that runs a tcp server, and takes commands from external programs to communicate with the robot components.
This basic model is designed to simulate how the raspberry pis work in the actual robot. Each Pi is an external program that communicates with a subset of the robot components (or other raspberry pis).




This diagram shows a simplified model of what I have in mind, with only the motor and central controllers (ignoring the vision and speech processors). Crucially, the controller programs will be cross platform applications that run the same code on pc or raspberry pi. The only exception will be that the communications layer on a raspberry pi will be talking to physical devices like an IO board, wheras on a pc it'll be sending commands over TCP to unity.

A unity example

This snippet from my code shows the servo logic. It has a current position and target position, and uses them to control a damped spring on a hinge joint. The result is similar to the real world servo scenario, in which you send it a signal to tell it which position to move to.

using UnityEngine;
using System.Collections;

public class Servo : MonoBehaviour {
    
    public float Position;
    public float TargetPosition;
    
    // Use this for initialization
    void Start () {
        Application.runInBackground = true;
    }
    
    // Update is called once per frame
    void Update () {
    
    }
    
    float ConvertToWithinPI(float angle)
    {
        while(angle < -180) angle += 360;
        while(angle > 180) angle -= 360;
        return angle;
    }
    
    void FixedUpdate()
    {    
        float a = ConvertToWithinPI(ConvertToWithinPI(TargetPosition) - ConvertToWithinPI(Position));
        if(a < -5) a = -5;
        if(a > 5) a = 5;
        Position += a;
        
        JointSpring spring = hingeJoint.spring;
        spring.targetPosition = Position;
        hingeJoint.spring = spring;
    }
}


I've written similar scripts for motors, and a central one to wire them all together in which I'll add the tcp communications layer.

It in action

So without further coding ado, here's a video of it in action:


This first version is just me tinkering with the numbers in the unity editor. Here you can see me fiddling with the eyes, neck joints and wheel motors.

Next Time...

Next up, I'll get it so that the inputs and outputs to the various simulated devices can be accessed via a network connection. Once I'm there I'll be in a position to write applications in any language I like to control the various aspects of the robot (probably python for the low power stuff, and c++ for things like image processing).


Sunday, 15 September 2013

Introducing PiBot

Well I'm coming to the end of a project at work, which means I'll finally have some of that free time stuff I've heard so much about, and will need a project at home to use it all up. And so, here's the beginnings of my thoughts on my next robot...

The basic idea is to build upon my prototypes made with MmBot back in the day, the objective being to create an AI driven 'cute' robot. My experience making games has taught me it's not about making something intelligent, it's about making something appear intelligent, and that will be the goal. Something that is cute looking and makes an apparent emotional connection to it's surroundings.

Before I get all AI on anybody though, we need a basic system design. The plan is to network together a set of raspberry Pi's, talking a common language to each other via a battery powered Ethernet hub. Initial layout is as follows:

Layout of processing units in Raspberry Pi

The arrows here indicate data flow, not necessarily physical connections, as the connections between the raspberry pis (in green) are all done across the network. So in reality, all the Pis are connected to a central Ethernet hub. I'll also have a port spare in the hub for a PC to connect to for development purposes.

Crucial to the design of the system is the extendability of it. I have no idea right now as to the exact processing power required to achieve my goals, but by designing the system as a set of CPUs running in parallel, communicating over a network, I can add new modules as required.

Vision

It's crucial that this robot has a good awareness of it's surroundings. In order to make any kind of emotive connection it'll need to be identify people and make eye contact with them, or wander around a room or building trying to 'make friends'. As such a full 3D representation of the scene will be necessary. This'll be obtained by:
  • 2 raspberry pi cameras
  • A raspberry pi for each camera, doing initial 2D vision processing. This will be conversion of the images into Sobel transforms, converting them to useful formats for 3D processing, and performing 2D feature detection.
  • The stereoscopic processor will receive data from the 2 vision processors, and combine it to form a 3D view of the scene, primarily through matching features from the 2 separate cameras and data from previous frames. It'll  also be responsible for feeding back requested eye movements to the central controller that are necessary to enhance knowledge of the scene layout.
It's my hope that these systems will provide the power needed to build and maintain an understanding of the environment the robot is in, however large parts of the image processing and stereoscopic work are parallelisable, so could be distributed across more machines if necessary. The raspberry pi has a tasty GPU though which could well be harnessed for this purpose.

For recognising things such as faces in the scene, I may offload additional work to an extra raspberry pi, to take data from the stereoscopic data and match it to historical records of people, or even image data retrieved from the internet!

Audio

This comes in 2 forms - input and output. I'd like the robot to be able to understand some very basic speech commands, but also respond to audio queues such as loud noises being scary. For feedback, I intend some sort of sim speak or emotive gobbledygook language (think R2D2), as you can achieve a lot with this kind of sound without it really having to make any sense!

Currently I'm expecting not to need too much power to achieve the audio goals, so 1 raspberry pi is reserved for both input and output. This could easily be farmed out to more CPUs if necessary though.

Additional IO

All extra IO will go via a raspberry pi 'Gert Board' - an extension available designed for driving motors and reading sensor input. 

The robot will be driven by 2 fairly powerful motors, each with a built in quadrature encoder (aka thing that measures how far the motors have turned), which will allow for precise control over its movement.

PiBot's head will be on a neck controlled by 3 servos to give a full range of motion, plus an additional servo to allow the eyes to move in unison (crucial for realistic and cute eye contact). I could see me needing additional servos for controlling eye brows or mounted sensors, but they aren't on the plan just yet.

I'll be adding various LEDs or light strips on PiBot to allow it communicate 'mood' with colour (think Ian M Banks culture robots), again as its simple to code but powerful in terms of emotive feedback. 

The only extra sensors I have planned are rangefinders (probably IR) mounted at various positions to give the robot some last minute warning systems against crashing into walls or rolling down stairs!

WiFi

I'd like the robot to be able to access the internet, to retrieve data from systems like face book in order to glean any extra info it can about the world around it or the people it's communicating with. In addition, a quick and easy way to connect to it with a PC will be handy so for this I'll be adding a WiFi network adapter connected to the central processor.

HDMI

Not sure what this is for yet, but I'm sure some kind of output to a display will be useful for debugging - or maybe playing back what it's been doing. Plug PiBot into the TV after its been wandering around for a day and see what it's been up to!

Summary

Well that's the basic plan - a set of networked raspberry pis all doing their own little jobs, with a central unit talking to them all to gather up sensor data and feedback to the output devices. Exciting stuff - just gotta ship Tearaway first!

Monday, 4 February 2013

PI Vision step 2 - to the metal!

In my last post I got a playstation eye camera working via ffmpeg, but even here I couldn't acheive a respectable frame rate at 640x480. Now perhaps I'm wrong, but it seems to me that the raspberry pi contains enough oomph (perhaps with the gpu involved) to happily decode a std definition web cam feed. The question for me is where is the slow down, why is it happening, and can I fix it?

My first port of call after digging around with ffmpeg was to go a step further back and take a look at using video4linux (aka the linux video capture system) directly. However after compiling a few demos I was unconvinced. I managed to get a lo res feed decoding, and the camera wouldn't even initialize at 640x480. Had I been certain it'd work eventually at a decent speed I might have been willing to put more time in, but the slow down could easily be in v4l.

So what now? Well, I've decided my next port of call is to try to talk to the camera directly. Unless the slow down is the usb communication (which is possible), this should get me close enough to the metal to get a high performance feed. It has the added advantage of letting me monkey around with the usb device directly as well, thus avoiding any nuances with picking up the video0 device (mentioned in earlier post).

Lib USB

A bit of research later, I discover libusb. This handy library lets you talk to the usb port directly, without having to monkey around with writing kernel code. Crossing my fingers, I take a guess at the package name and...

pi@raspberrypi ~ $ sudo apt-get install libusb-1.0

Bingo! I'm informed the library exists, but do I want to get the dev version (maybe this includes the header files). I say yes, it downloads, and there it is in /usr/include/libusb-1.0. Time for some c++. Incidentally, my current approach to coding on the pi is to setup a samba server so I can access the files from my windows PC, then use visual studio to edit. To compile, I currently log in via SSH and do so on the command prompt:



While this isn't exactly wonderful (debugging is reduced to printf), it is simple and efficient, and is serving me fairly well so far! With my main.cpp created, I can build and run it with:

pi@raspberrypi ~/libusbtest $ gcc main.cpp -o main
pi@raspberrypi ~/libusbtest $ ./main

So I'm all set. Lets see if I can use lib usb to find and chat to the ps eye...

After a bit of reading and fiddling, I end up with this simple program. It uses libusb to enumerate all the devices available, get some information on them, and print it out.

#include <stdio.h>
#include <iostream>
#include <libusb-1.0/libusb.h>

libusb_context* UsbContext;

using namespace std;

int main(int argc, const char* argv[])
{
    printf("Initializing lib usb\n");

    int res = libusb_init(&UsbContext);
    printf("libusb_init: %d\n", res);

    libusb_set_debug(UsbContext,3);

    libusb_device** devicelist;
    ssize_t num_devices = libusb_get_device_list(UsbContext, &devicelist);
    for(int i = 0; i < num_devices; i++)
    {
        int bus_number = libusb_get_bus_number(devicelist[i]);
        int device_address = libusb_get_device_address(devicelist[i]);
        int device_speed = libusb_get_device_speed(devicelist[i]);
        
        cout << "Device " << i << ": bus_number=" << bus_number << ", device_address=" << device_address << ", device_speed=" << device_speed << "\n";

        libusb_device_descriptor descriptor;
        libusb_get_device_descriptor(devicelist[i],&descriptor);

        cout << "  bLength=" << (int)descriptor.bLength;
        cout << ", bDescriptorType=" << (int)descriptor.bDescriptorType;
        cout << ", bcdUSB=" << (int)descriptor.bcdUSB;
        cout << ", bDeviceClass=" << (int)descriptor.bDeviceClass;
        cout << "\n  bDeviceSubClass=" << (int)descriptor.bDeviceSubClass;
        cout << ", bDeviceProtocol=" << (int)descriptor.bDeviceProtocol;
        cout << ", bMaxPacketSize0=" << (int)descriptor.bMaxPacketSize0;
        cout << ", idVendor=" << (int)descriptor.idVendor;
        cout << "\n  idProduct=" << (int)descriptor.idProduct;
        cout << ", bcdDevice=" << (int)descriptor.bcdDevice;
        cout << ", iManufacturer=" << (int)descriptor.iManufacturer;
        cout << ", iProduct=" << (int)descriptor.iProduct;
        cout << "\n  iSerialNumber=" << (int)descriptor.iSerialNumber;
        cout << ", bNumConfigurations=" << (int)descriptor.bNumConfigurations;
        cout << "\n";

        libusb_device_handle* devhandle;
        int openres = libusb_open(devicelist[i],&devhandle);
        if(openres == 0)
        {
            cout << "  Device opened\n";

            unsigned char buffer[1024];
            libusb_get_string_descriptor_ascii(devhandle,descriptor.iManufacturer,buffer,1024);
            cout << "  Manufacturer=" << (char*)buffer << "\n";
            libusb_get_string_descriptor_ascii(devhandle,descriptor.iProduct,buffer,1024);
            cout << "  Product=" << (char*)buffer << "\n";
            libusb_get_string_descriptor_ascii(devhandle,descriptor.iSerialNumber,buffer,1024);
            cout << "  SerialNumber=" << (char*)buffer << "\n";

            libusb_close(devhandle);
        }
        else
        {
            cout << "  Could not open device\n";
        }

        cout << "\n";
    }

    libusb_free_device_list(devicelist, 1);
    libusb_exit(UsbContext);
    return 0;
}

I discovered I had to run my application as a super user (i.e. use 'sudo') to access the usb ports, but other than that, success:


pi@raspberrypi ~/libusbtest $ gcc -o main main.cpp -lusb-1.0 -lstdc++
pi@raspberrypi ~/libusbtest $ sudo ./main
Initializing lib usb
libusb_init: 0
Device 0: bus_number=1, device_address=1, device_speed=3
  bLength=18, bDescriptorType=1, bcdUSB=512, bDeviceClass=9
  bDeviceSubClass=0, bDeviceProtocol=1, bMaxPacketSize0=64, idVendor=7531
  idProduct=2, bcdDevice=770, iManufacturer=3, iProduct=2
  iSerialNumber=1, bNumConfigurations=1
  Device opened
  Manufacturer=Linux 3.2.27+ dwc_otg_hcd
  Product=DWC OTG Controller
  SerialNumber=bcm2708_usb

<... bla bla bla more devices ...>


Device 4: bus_number=1, device_address=5, device_speed=3
  bLength=18, bDescriptorType=1, bcdUSB=512, bDeviceClass=9
  bDeviceSubClass=0, bDeviceProtocol=1, bMaxPacketSize0=64, idVendor=5141
  idProduct=16384, bcdDevice=1794, iManufacturer=10, iProduct=11
  iSerialNumber=0, bNumConfigurations=1
  Device opened
  Manufacturer=SONY
  Product=USB 2.0 HUB
  SerialNumber=USB 2.0 HUB

<... bla bla bla more devices ...>


Device 7: bus_number=1, device_address=8, device_speed=3
  bLength=18, bDescriptorType=1, bcdUSB=512, bDeviceClass=0
  bDeviceSubClass=0, bDeviceProtocol=0, bMaxPacketSize0=64, idVendor=5141
  idProduct=8192, bcdDevice=256, iManufacturer=1, iProduct=2
  iSerialNumber=0, bNumConfigurations=1
  Device opened
  Manufacturer=OmniVision Technologies, Inc.
  Product=USB Camera-B3.03.09.3
  SerialNumber=USB Camera-B3.03.09.3

2 interesting results there. The obvious end one - the OmniVision camera interface. I am however also intrigued by what claims to be a Sony USB HUB. Oh well - progress has been made. Next stop I'll focus on that 7th device and try to pull out some more information about it.


Digging Through Drivers

OK, I've spent the past few days digging through code and finding various bits and pieces. After some searching I went through the following process:

  • First step, this web site: http://nuigroup.com/forums/viewthread/2921/ in which the first windows drivers for the PS Eye were posted. Crucially, the post states that the play station eye uses the OV534-LB50 chip as its usb interface
  • After some scouring, I found the OV534 linux driver source here
  • While that source is rather long and contains lots of checks, it references this link - the original reverse engineering of the OV534 usb protocol

Conclusion

I'm now left with a few possible conclusions...
  1. The poor performance is due to the cost of getting data from the usb port and into memory. If this is the case, I'm ultimately screwed as I have no idea how to fix it (if it is even fixable!)
  2. It's down to slow OV534 drivers. I can potentially fix this, if I can proceed with my earlier plan of directly communicating with the chip via usb.
  3. The drivers are fine, but something in video 4 linux is slowing things down. Again, my earlier plan will solve this one - if I can make it work
  4. Aside from some oddities in functionality, video 4 linux is fine and it's the fact that everything converts from YUV to RGB on cpu that slows everything down. If that's all it is, just taking the raw video 4 linux data and converting it on gpu should do the job.
My gut right now says to spend a bit of time trying to bypass video 4 linux and go straight to usb as planned. If this turns out to be too tricky I'll give video 4 linux some more love and see if I can get it reading raw YUV data at 640x480 at a decent speed. 

I end this post with a final thought... YUV is 2 bytes per pixel. So for a 640x480 feed at 30fps you have:
     640*480*2*30 bytes per second = 18432000 bytes per second
Or roughly 17MB/s. Should a 600Mhz chip be able to get 17MB/s out of a USB port? I really don't know!


Sunday, 27 January 2013

PI Vision 1.0

My ultimate goal here is making a robot, and the main reason I wanted a raspberry pi (or multiple ones) is that they are powerful / flexible enough to read and process a web cam feed. This first short blog is my experience trying to get the Pi running a web cam.

I tried various tutorials, recommending various programs that detect motion, or stream video over IP. However often you end up limited to a very low frame rate. I wanted to strip out any excess stuff and start with just one objective - plug the pi into the tv, a web cam into the pi, and the video feed rendering on screen. After some research it turns out ffmpeg is a good way to go for this.

What you'll need

For this test I used:


Installing FFMpeg

First step, boot up your raspberry pi, make sure its hooked up to the internet and get ffmpeg installed. Some of the internet seems to think there's issues with the available version and suggest compiling yourself, however installing it as normal has worked fine for me thus far:

pi@raspberrypi ~ $ sudo apt-get install ffmpeg

Hook Up The Web Cam

The crucial point here is that you must be plugged in via a powered usb hub, as the Pi can't power much more than a keyboard/mouse. I randomly chose the Trust 10 port one listed above, and it seems to work, however the camera is a little unreliable - it virtually never shows up on boot, and I have to unplug/plug it in a few times to get it detected. The first thing to do (after plugging things in) is to list the usb devices with the command 'lsusb', which should give you something like this:

pi@raspberrypi / $ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp.
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 004: ID 05e3:0608 Genesys Logic, Inc. USB-2.0 4-Port HUB
Bus 001 Device 005: ID 1415:4000 Nam Tai E&E Products Ltd. or OmniVision Technologies, Inc.
Bus 001 Device 006: ID 05e3:0608 Genesys Logic, Inc. USB-2.0 4-Port HUB
Bus 001 Device 007: ID 05e3:0608 Genesys Logic, Inc. USB-2.0 4-Port HUB
Bus 001 Device 008: ID 1415:2000 Nam Tai E&E Products Ltd. or OmniVision Technologies, Inc. Sony Playstation Eye


As you can see, the PS Eye has shown up in the list. Now while that seems to always work for me, what doesn't always happen is the camera actually being picked up as a video input device. To check if this has worked, switch to the devices folder and list them:

pi@raspberrypi / $ cd /dev
pi@raspberrypi /dev $ ls

If you're not used to linux, the 'dev' folder is a special one, that contains a 'file' for each device on the system. If a camera is present, you should see 'video0'. If you're like me, the odds are it won't be there. Unplug the camera and plug it back in, then type 'ls' to see if it appears. So far this has worked for me every time, but I need to work out why its happening at some point, and whether it can be remedied.

Anyhoo, after a bit of plugging in, that 'ls' command should show you something like this:



Once that 'video0' appears you're all set!

Getting it running

Up until now I've been working over SSH via putty, as this means I can work via my pc using a nice screen etc, however it's time to get the web cam stream and for that we'll need to plug the Pi into a tv. Plug it in, reboot, and make sure the video0 device is present using the steps above. Now we can use the supplied ffmpeg player application to get the feed. Using a tweaked version of the example from this ffmpeg documentation, I come up with the command:

pi@raspberrypi /dev $ ffplay -f video4linux2 -framerate 15 -video_size 320x240 /dev/video0

In english this means:

  • Run the ffplay test application that comes with ffmpeg
  • Use the 'video4linux2' mode (video4linux2 is the video capture system that linux uses)
  • Request a frame rate of 15fps
  • Request a video size of 320x240
  • Use the device '/dev/video0'
Here's a video to show it working!




Conclusion / Future plans

After some experimenting I've found that you can't really push the above tests past 320x240. At 640x480 (the native ps eye resolution) you can't get past 2 or 3 fps, and on a higher resolution camera this'll just get worse. While it performs much better than some more complex examples, I'm looking for high performance, so the next stage will be to do this via code, using ffmpeg to pull out a stream and the pi gpu to render it. Hopefully then I can work out where the slow down is and whether it's feasible to use the gpu to speed things up. Maybe I'll have to skip ffmpeg altogether and go straight to video4linux, but I'd rather not!

On top of the decoding side, I also have the issue of the usb unplugging. If anyone has any thoughts on this I'd be interested. I've seen there's code out there to reset the usb device, which I'll try. Worst case though I'll use the gpio pins and a transistor to cut the power to the camera via code!





Sunday, 20 January 2013

Raspberry Pi chats to Arduino

Well I got the Pi working, so what next? After a tiny amount of pondering I decided to get it chatting to an Arduino using the serial interface. I'll try and note down everything relevant so this'll be as much a guide to doing it as a recording of what I did!



Before proceeding If you have a Pi, you might ask why on earth I'd do this - surely the Raspberry Pi is so awesome, the Arduino is just wasting space? The answer is that while technically you probably could get it to do everything, that doesn't mean you should. The Pi is a high level computer, with lots of stuff happening in the background (like an operating system!) and isn't well suited to things like sending precisely timed intervals to a servo, or reading times in between pulses from sensors. Admittedly where there's a will there's a way, but I prefer the ways that require as little will as possible, so my robots down the line will generally feature 1 or more Pi's as the 'brains', with Arduinos doing the grunt work!

Overview

So, onto the actual job. The basic bits that needed doing were:
  • Connect the raspberry pi serial pins to the arduino serial pins via a logic level converter. We need the converter as the raspberry pi pins work at 3.3V, but the the Arduino works at 5V. Without it, dead Pi!
  • Disable some default settings that the raspberry pi has so that we can gain read/write access to the serial port, then use the 'minicom' app to interact with it
  • Write a little program on the Arduino to read serial data from the PI and echo it to the PC, and visa-versa
I used these web sites to gain enough info to do it:

In addition to a raspberry pi and an Arduino Uno, I also had a few wires, some jumper cables and crucially this logic level converter: https://www.sparkfun.com/products/8745. (although being in the uk I got mine from coolcomponents.co.uk).

The Circuit

This is the circuit I built in photo form - very simple really. It's ultimatley just connecting the raspberry pi serial Rx/Tx to 2 pins on the arduino, however to avoid circuit damage there's a logic level converter in the middle.


I'll upload a circuit diagram if I manage to get visio up and running again!

Note: In case you didn't know, with basic communications stuff,  'Tx' means 'transmit' and 'Rx' means 'receive'. The idea is to connect the 'Tx' of one device into the 'Rx' of another and visa versa so they can chat!

The Pi on the right looks slightly more complex than it needs to as I didn't have any single wire jumper cables. So while I've connected 9 actual pins to the breadboard, I'm really only using:
  • Pin 1: 3.3V, connects to LV (low voltage) on the level converter
  • Pin 6: 0V, connects to GND on level converter
  • Pin 8: UART Tx, connects to Tx1 on level converter
  • Pin 10: UART Rx, connects to Rx0 on level converter
The Arduino is very similar:
  • 5V goes to HV (high voltage) on the level converter
  • GND goes to GND on level converter
  • Pin 11 (using for software serial Tx) connects to Rx1 on level converter
  • Pin 10 (using for software serial Rx) connects to Tx0 on level converter
I highly recommend testing the circuit with a voltmeter as you go. I verified the raspberry pi 0V/3.3V signals with a multimeter, and as you can see here, used an oscilliscope to check the serial port output was happening:


I won't declare that's necessary, but it helps to be sure. You can test all points of your circuit with it, and check that 3.3V is what will be pumped into your Raspberry Pi before actually making the final connections.

Arduino Program

This is the very basic program used on the Arduino. It's just checking for data from either the PC (on hardware serial port) or Raspberry Pi (on the software serial port via pins 10 and 11).

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX


void setup() {
  // initialize hardware serial (arduino<->pc) and softare serial (arduino<->pi)
  Serial.begin(57600); //pc at 57600
  mySerial.begin(115200); //pi at 115200
}

void loop() {
  //check for data from pi
  if (mySerial.available())
  {
    unsigned char val = mySerial.read(); //read pi data
    Serial.write(val);    //send pi data to the pc
    mySerial.write(val);  //also echo it back to the pi, so it shows up as you type it
  }
  //check for data from pc
  if(Serial.available())
  {
    mySerial.write(Serial.read()); //send pc data to the pi
  }
}

The only slight oddity here is that I echo any data from the pi right back at it (in addition to forwarding it to pc). This is just so I can conveniently view it on the raspberry pi console and verify things are working even without the PC itself connected.

Preparing The Pi

I'm literally just repeating what I found on this very useful page: http://www.irrational.net/2012/04/19/using-the-raspberry-pis-serial-port/ in this section. Basically, bits of the default Pi setup reserve the serial port for stuff like kernel debugging and console output. We just need to disable those and restart it.

First up, I log into the Pi over SSH (search the web for how to do this - its very easy), as this gives me access to it from my PC, rather than having to actually hook it up to a tv/keyboard.


Now backup the old command line file in case I want it back!
sudo cp /boot/cmdline.txt /boot/cmdline_backup.txt

Edit the command line file:
sudo nano /boot/cmdline.txt

Remove the references to ttyAMA0. In my case this left me with:
dwc_otg.lpm_enable=0 rpitestmode=1 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait

Now edit the inittab file
sudo nano /etc/inittab

And comment out this:
2:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

Then finally, reboot:
sudo reboot

After rebooting I installed 'minicom' - a handy serial port utility:
sudo apt-get install minicom

And run it connecting to the serial port:
minicom -b 115200 -o -D /dev/ttyAMA0

Testing It

So, we now have:
  • An Arduino with my program on, connected to the pc with the serial monitor open
  • A Raspberry Pi running minicom (in my case connected to pc via SSH for ease of use)
  • A circuit that connects, via logic level converter the serial Rx/Tx of Raspberry Pi with pins 11/10 of Arduino
In theory, if you type in minicom, it should appear in the Arduino output, and visa versa! Here's a video to prove it - hope I didn't miss anything!


Thursday, 17 January 2013

Pi Time!

Well, it's been a while since I updated this blog, but I'm sick, the house is a mess, the washing needs hanging up and my fingers are sore from playing the guitar. So it's obviously time to set up my Raspberry Pi. I'm writing this as I go, so I may get half way through and realise it's broke. Lets hope I get all the way through.

Here's the bits - an sd card, an hdmi cable, a power lead and of course the Pi itself.

The basic bits for the Pi - hdmi cable, power, sd card and the board itself

USB keyboard/mouse is recommended, but all I have on hand is wireless ones so lets hope they still do the job. I'll face that when I come to it though - even if we just get things booting up it'll be a win!

First up, pick an OS from the raspberry pi site - I'm going for the Linux Debian release, named Raspbian. Downloading...

In the mean time, lets find out how to set it up from here. Note - respect to the authors here - both links are not broken, despite being from a 6 month old piece of paper.

Apparently the easiest way to do it, having acquired the disk image from the earlier link is to grab win32diskimage from here and use it to write the image to an SD card (which is plugged into my lap top):

Disk imager - used to create initialize the sd card ready for the PI
You gotta love a nice simple program for a simple task! With the imager running, SD card in and image at 50% it's time for some tea.

OK, tea made, image downloaded. Hitting run.... percentages clicking up.. 25% and still going.... Done.

Boot time. OK, my monitor doesn't have hdmi input. Guess we're going with tv for now.

And incorrect plug type. Thanks RS electronics. Fortunately I am the sort of person with many an adapter lying around the house...

Everything wired up and ready to go
Doesn't work. Fiddle with plug.... and Houston we have Pi!

Hurray! It begins to boot. Lots of text, no scary error messages.
Looks like wireless keyboard works, but only if I plug in the adapter post boot, or maybe in a specific socket. Not worked that out yet. Oh well, time to fiddle. Looks like there's a handy config tool that boots up first, so I'l click on all the options to see what they do.

The first interactive screen - a friendly config tool


  • Expanding partition to fill the whole card worked fine.
  • Setting the keyboard was a little ropey, but I've ended up with a working UK setup. 
  • Presented with a vast list of locales to generate, and seem to have chosen none of them. It's generated the en-GB one though so hopefully that'll do for now.
  • Time zone nice and simple if you know your own address. I do.
  • Memory split seems to be how much memory to give the GPU. Default is 64MB which will do for now.
  • Lets not overclock it thankyou very much.
  • SSH enabled as I'm sure I'll need it at some point
  • Yes we'll boot straight to desktop please.

And lastly, given it ain't online yet, I don't see much point in clicking update, so I'm going for Finish! Reboot complete and...

Booted up after initial config, works first time. We have a desk top.
Well bugger me it works. With wireless mouse/keyboard as well (that's the logitech K520 wireless keyboard, and M310 mouse it comes with). That was easier than opening a document in the latest version of MS Office. OK so most things are easier than opening a document in the latest version of office, but this was still really easy.

Next up - the interweb. My knowledge of Linux is around about 0, so this'll be a test of the OS as much as it is the Pi. The obvious first step is to plug it into my router though...

Turns out plugging it in was also the last step. No other steps needed. And there you have it - a preview of this blog post (before even being posted) on the Raspberry Pi. Very chicken/egg ish.

Raspberry Pi connected to the interweb and previewing this blog

Well, that was the easiest bit of setting something up that might turn out complex I've done in a long a time. One might even say it was easy as Pi (boom boom). I guess there'll be some updating to be done, but I've heard Linux is good at that.

Well done Rasperry Pi team. You truly are the kings of small $30 computers.

Now I just need to decide what to do with it - probably next post will involve web cams - hopefully 2 of them! Or an Arduino. Who knows.

-Chris