Sunday, September 30, 2012

Multiple Failures

The very first "on battery" run of the 'bot ended with multiple failures resulting in an upside down situation.   Don't you just hate it when that happens?   Proximity sensors did not stop the motors from trying to climb the cabinet.   Interestingly the 'bot had both the power and the traction to do so!   Latency killed the stop command that was sent from my control panel with the two adding up to the scene on the right!



Ultra-short Webcam Capture Script

I think that the below is the shortest possible Python script to capture and then save an image from a webcam:

    import cv
    capture = cv.CaptureFromCAM(-1)
    frame = cv.QueryFrame(capture)
    cv.SaveImage( "Test.png", frame)


The -1 on the second line works if you only have one webcam otherwise you will have to specify the one you want to capture from...and since they move around...you have to add logic for that as well.

This is the basics of what I need but I have been chasing a problem with the webcam on the RPi for a while.   Namely that the first image is exposed correctly and all subsequent images are extremely under exposed.   This persists until the RPi is rebooted or the webcam unplugged and plugged back in.

I have tried unbinding/rebinding the device drivers thinking this would accomplish the same thing as the unplug/replug but to no avail.  The webcam that I am using works on Ubuntu and another webcam that I borrowed from my wife works through multiple exposures on the RPi. 

Obviously I can get another webcam but I do have a problem that you can see to the right.   I seriously doubt that my wife will happily watch me disassemble her webcam for this project!

Saturday, September 29, 2012

Pan and Tilt

I added the optional Pan and Tilt Kit to give my range finder and webcam a place to live where the could be pointed on an arc covering the front of the 'bot.   The kit is designed as an accessory for the Explorer PCB and mounts nicely on it.   The pan and tilt mechanism is not a particularly highly engineered piece of gear but it works.   I had a little trouble assembling it as the tilt mechanism is somewhat fiddly. 

Wiring the servos is really pretty simple as the Explorer PCB has sockets for four servos on each side of the board.   Power to the appropriate pins on each of the sockets and the control pin back to the Arduino and we were done with the wiring.

The code is pretty simple but does need the servo library to make things happen.   

    #include <Servo.h>     // create servo object to control a servo     
    Servo myservo;         
    void setup()
    { 
        // attach servo on pin 24
        myservo.attach(24); 
    }
    void loop()
    { 
        // Move the servo to 10
        myservo.write(10);
        delay(1000);      
        // Move the servo to 120
        myservo.write(120);
        delay(10000);
    }

One of the challenges that I had was in getting the servos centered.   Make sure you have power them up and centered them BEFORE you mount them!   I also have a fair amount of servo chatter at various points on their arcs...a sign that I did not do a very good job of assembling the pan and tilt kit!

Proximity Detection

The Explorer PCB has an infrared proximity sensor at each of it's four corners.   This consists of three little LEDs (or LED like things).   Two of them are side by side hanging from under the board.   One of these is the IR emitter and the other is the reader.  On the top of the board is a little LED that lights when the IR emitter is active (since you can't see IR).





Power for these sensors is provided by the board so connecting them is a matter of four wires from the board to digital pins on the Arduino for triggering the IR and another four to analog input pins for reading the proximity.





 

The code below shows my test code reading the Right Front corner.   Note that this code is based on my Python to Arduino Interface but is 1-1 analogous to what you would code in Arduino directly.

    import time
    from Py2Ard import interfaceClass
 

    # Instantiate the interface class    
    my_board = interfaceClass('/dev/ttyUSB0')
     # Pin assignments for  operations 
    TriggerRF = 36 
    InputRF = 10 
    # Set the pin modes
    my_board.pinModeOutput(TriggerRF)
    my_board.pinModeInput(InputRF)
    while 1==1:
   
    # Turn on the infra red
   
    my_board.setHigh(TriggerRF)        

        # Take a reading
   
    my_board.analogRead(InputRF)
   
    reading = int(my_board.returnValue)
   
    # Turn off the infra red
   
    my_board.setLow(TriggerRF)
   
    # Take a reading (this will be the ambient light)
   
    my_board.analogRead(InputRF)
   
    ambient = int(my_board.returnValue)
   
    # Subtract ambient for your proximity reading
   
    print "RF = " + str(reading - ambient)
        
        time.sleep(1)
   

Propulsion (e.g. Making Motors Go)

The combination of the Rover 5 and the Explorer PCB make connection of the motors pretty easy.   The Rover 5 comes wired to plug into the bottom of the Explorer PCB and the PCB then provides connections for power, control, and feedback of current being drawn.   Power needs to be connected to the 5v supply provided by the Explorer PCB.

Speed is controlled by the PWM pin and takes a value of 0 to 255.   Direction is set by a digital high or low.   I have not gotten the current feedback to work yet but the documentation says it should be read on the processors "analog to digital (ADC) inputs".  I am not sure what exactly that means but I am not getting anything on the pins that I have tried to date though I am not losing sleep about it at the moment.

Code for running a test on the left motor is shown below.  Note that this code is based on my Python to Arduino Interface but the commands, less error handling, are 1-1 analogous to what you would code in Arduino directly.

    import time
    from Py2Ard import interfaceClass
   
    # Specify the port as an argument
    my_board = interfaceClass('/dev/ttyUSB0')
   
    leftMotorDir = 26
    leftMotorSpeed = 7
   
    print "Setting Pin Mode for Speed"
    if my_board.pinModeOutput(leftMotorSpeed) == -1:
        print "Error" + my_board.extraReturn
   
    print "Setting Pin Mode for Direction"
    if my_board.pinModeOutput(leftMotorDir) == -1:
        print "Error" + my_board.extraReturn
   
    print "Commanding Direction Forward"
    if my_board.setHigh(leftMotorDir) == -1:
        print "Error" + my_board.extraReturn
   
    print "Commanding Speed of 100"
    if my_board.pwmWrite(leftMotorSpeed, 100) == -1:
        print "Error" + my_board.extraReturn
    time.sleep(2)
   
    print "Commanding Direction Backward"
    if my_board.setLow(leftMotorDir) == -1:
        print "Error" + my_board.extraReturn
   
    print "Commanding Speed of 100"
    if my_board.pwmWrite(leftMotorSpeed, 100) == -1:
        print "Error" + my_board.extraReturn
    time.sleep(2)
   
    print "Commanding Stop"
    if my_board.pwmWrite(leftMotorSpeed, 0) == -1:
        print "Error" + my_board.extraReturn

Tuesday, September 25, 2012

Backing up the Raspberry Pi

The code base for the Robot lives upstream from the RPi and is downloaded on update but there is a fair amount of other configuration that goes into the Raspberry Pi that really needs backing up!   Having done a re-install once already...I know this!

The easy way to do a backup is to copy the entire SD card.  You can do this from the RPi if you have a second card reader but between the speed of the Raspberry and the speed of the cards this makes a slow process even slower.   I make my backups on my Ubuntu machine as follows.

Insert your SD card and find out what the two device names you need to backup:


First Way:  Use the 'dd' command to make a full backup from the SD card to your hard drive (this will take a while):



Second Way:  Instead of using dd you can just do a cp (it will actually be quicker than dd if your disk is less than full but slower if your disk is more full than empty).  In the example below I have positioned myself in a sub-directory within which I want my backup to reside:

    sudo cp /media/10b4c001-2137-4418-b29e-57b7d15a6cbc . -r

The problem with the second way is that everything comes across in a restore as being owned by root.   I think, but could be wrong, that dd preserves ownership?  In any case I only use the default user of 'pi' so fixing this is easy:

    sudo chown -R pi .

What I wonder about both of the above is...does it really yield a perfect replica if I had to do a restore?   I am not sure that it would given rights in the second case.

Friday, September 21, 2012

Wireless for the Raspberry Pi

Obviously my robot needs a wireless connection so I went to the Raspberry Pi Hardware Compatibility list to look for a small, cheap, compatible, wireless dongle.  I decided on the Belkin N150 and have been happy with it.   The RPi detects it on boot so all I needed to do was setup the network.

Edit the network interfaces file /etc/network/interfaces.   The file should look like the below once you have added the wlan0 interface for the Belkin N150 (highlighted):

    auto lo
    auto wlan0
    iface lo inet loopback
    iface eth0 inet dhcp

    iface wlan0 inet dhcp
    wpa-ssid YourNetworkSSID
    wpa-psk YourPassword



Tuesday, September 18, 2012

Raspberry Configuration

I have been spending a fair amount of time on my Ubuntu development environment and needed to get the Raspberry Pi configured to mirror the laptop: 

Get all the latest updates for packages that are installed as well as package indices: 

sudo apt-get updates
 
Install VNC server so that when I do need a graphical environment it is there for me:

sudo apt-get install tightvncserver
vncserver :1 -geometry 1024x728 -depth 24

Setup VNC to start on boot:

This last command is what starts VNC automatically...
sudo update-rc.d tightvncserver defaults

Start manually
sudo /etc/init.d/tightvncserver start

Install an FTP client and server (note that the FTP server will be installed to start automagically):

sudo apt-get install ftp
sudo apt-get install proftpd

Setup Python with the add-ons that I need for my Robot:

sudo apt-get install python-serial
sudo apt-get install python-opencv
sudo apt-get install python-imaging

Install the Arduino environment (won’t need it often but thought it should be there):

sudo apt-get install arduino
 
Install compass library (I had to copy this from development for latest version as I am not sure where I got it!)

Install beanstalkd (and all of the rest just to get a Python interface library) for inter-process queue management:

apt-get install beanstalkd
PIP (all the rest is to get support for Python)
sudo apt-get install python-pip python-dev build-essential
sudo pip install --upgrade pip
sudo pip install --upgrade virtualenv
sudo apt-get build-dep python-yaml
sudo pip install PyYAML
beanstalkc
sudo pip install beanstalkc

With all of the above done my RPi was acting exactly as my development environment running Ubuntu on an Intel based laptop.   The RPi is, obviously, quite a bit slower but this is still an impressive feat!

Monday, September 17, 2012

Frustrated by the RPi Wait - Ordered Another!

I finally got frustrated by the wait for my Raspberry from Allied Electronics and RS Components so I ordered on from CPC in Farnell.   It was a little more expensive but they had one in stock.   A little case from eBay and I am good to go.   Someday when I get the original Raspberry that I ordered you will find one of them on eBay.   I do wonder a little about AE and RSC.   Why not add a quid or even two to the price and offer some customer service?????

Anyway, having an RPi in hand I connected a mouse and keyboard dongle, attached it to my TV, and gave it some power.   It booted up as advertized with the raspi-config menu displayed from whence I:
  • Expanded the root so that my entire 16gb card would be utilized,
  • Set the timezone to London, and
  • Rebooted the device.
This first reboot after expanding the root will take some time so I needed to be patient.

Working on a 42 inch TV was a little awkward so I connected the Rpi to an AP that I have for just such purposes and continued with some initial configuration via an SSH session:
  • Restarted raspi-config and asked it to update itself now that we were on the network.
  • Once the above was done the menu option for overclocking turned up so I set it to the medium setting.
  • As I am working almost exclusively from the command prompt I also set the video memory to the minimum setting.
In my next post I will describe the configuration of the RPi to match the development environment that I have been using on my Ubuntu Laptop.


The velcro dots are part of my sophisticated mounting system for the USB hub that will ride on top of the RPi.   To the rear you can see the three leads for the serial console connection that I will talk about later.  Power is coming from the left and the AP for wireless connectivity is coming in from the right.

Sunday, September 16, 2012

Range Finding


The URM37 V3.2 Ultrasonic Sensor was the first thing that I connected to my Arduino.   It is a cool little piece of kit.   It is actually a sonar device in that it bounces ultrasonic beams off of things to measure their distance from the sensor by timing the echo.

Note that the product to the right is NOT precisely the same device as I am using but does offer most of the same features.

In any case, the one that I amusing can be connected either via PWM or serial (TTL or RS232) and if you use the serial interface you can also measure the temperature.   I just wanted simple range finding on command so I used the PWM input.   The user manual covers a lot more of the capabilities than I need!

As you can see from the picture it takes four wires to connect the sensor if you are using PWM.  Two power, the PWM output, and a trigger input.

Below is the Arduino code to read from the sensor.   This presumes you have already set the pins to output and input respectively and declared their variables!

    digitalWrite(triggerPin, LOW);
    digitalWrite(triggerPin, HIGH);
    range = pulseIn(inputPin, LOW);
    rangeCM = range / 50;


The only issue that I have had with this sensor has been one related to power.   If you don't give it good power it will limit the range of the sensor.   Drove me nuts.

Specification
  • Power: +5V
  • Current: <20mA
  • Working temperature: -10 ~ +70 C
  • Detecting range: 4cm-3m (3-5m is possible, but depending on situations)
  • Resolution: 1cm
  • Interface: PWM, RS232 or TTL (via Jumper)
  • Servo control: One servo control output
  • Operating Mode: Serial (PWM) passive control mode; Autonomous Mode; On/OFF Mode
  • Temperature sensor: 12 bits reading from serial port
  • Size: 22mm × 51 mm
  • Weight: 30g