Evolution of a Blog

This blog has evolved as I have as a maker. It starts at the beginning of my journey where I began to re-tread my tires in the useful lore of micro electronics and the open-source software that can drive them. While building solutions around micro-electronics are still an occasional topic my more recent focus has been on the 3D Printing side of making.

Tuesday, November 27, 2012

Easy access for the Raspberry GPIO Bus

The Python code that drives the 'Bot functions around a processing loop that has to do a number of routine interactions with the 'Bot's physical contraptions.  This includes checking the bearing along with the 'Bot is traveling, proximity detection from both IR and Ultra Sonic detectors, current detection for stall warnings, and the check for commands from the web interface.

The interactions that go through the Arduino impart an obvious delay but the Arduino is necessary given the limited capacity of the RPi GPIO bus.   What I am doing, however, is offloading some of the above mentioned functions, though not all.   I am also using the GPIO bus to light up a RGB LED to visually show some status indications as the Python script runs.

All this means a number of wires connected to the GPIO bus.   Since it is critical that I be able easily remove the RPi from its resting place on the 'Bot to gain access to the Arduino and Explorer PCB I also needed some way to easily disconnect and then reconnect the GPIO bus.

My solution is shown by the photos to the right.

First I ordered a GPIO cable.  Since it only came with one connector I had to also order a 26 way IDC Ribbon Cable Connector that I attached to the end of the GPIO cable with the connector facing up.   

Next, I ordered a Right Angled IDC PCB Box Header to which I am able to connect my leads on the 'Bot side.   This connector allows me to easily mess with things during development and allows the RPi to be easily disconnected and reconnected as well.

I am not using power from the GPIO bus as everything is powered from the Explorer PCB.  I am using one of the GPIO 5v power pins to feed voltage readings to the Arduino.   The other 5v pin, and the 3.3v pin, are protected with a sawed off jumper connector to prevent any possible RPi frying short circuits.

Monday, November 26, 2012

Last of the hardware mods for the 'Bot

My wife and I just bought a new house so I have been, and/or will be, a little distracted over the coming weeks.   That said I am still making a little progress as shown by these pictures which represent what should be just about the final hardware configuration for the 'Bot.

First the an overall picture and then I will dive into some of the changes and why I have made them.
Some of the most major of the changes for this version of the 'Bot are the new RPi and case that FINALLY came after having ordered them in June.   The RPi case sits on a breadboarding platform above the Explorer PCB.   I expanded that platform a little to give some more room which pushes the RPi further to the stern of the 'Bot.   On top of the RPi is a new USB V2 Hub that seems to be helping with some of my USB issues (devices dropping offline).

 I have also made some power improvements by adding a Li-ion battery pack (2 x 3.7v 4000mAh cells) dedicated to the RPi with it's own power regulator and LED to indicate when it is on.

RPi Power Regulator
RPi Power Switch
RPi Batteries

Since I have decided to use the GPIO capabilities of the RPi to augment the Arduino (more elsewhere) I decided to bring the GPIO bus outside of the RPi and have connected it to a socket that allows me to plug and unplug the RPi when I need to lift the hood to get at the Arduino or the Explorer PCB (more on this here as well).




Finally, at the rear of the 'Bot I have added a little breadboard with an RGB LED (under the bottle cap) that I am using to signal status for the 'Bot (flashing green means all is well, a flash of blue when a command is received, SOS in red if all is not well...and of course solid on or off if the RPi has crashed).   The mini breadboard also has a reset switch for the Arduino since things have gotten croweded!

Friday, November 16, 2012

What to do with two RPis?

Earlier this year I had gotten frustrated with the ultra slow dispatching of my RPi from RS Components.   That and their great order status process (not).  So I did the obvious thing and ordered one from CPC Farnell.   Sure, I paid a little more, but I got it in two days and knew where it was that entire time.  

In any case my original order has finally shipped and while I was planning on selling one of these 'puters on eBay now I am thinking that having two might not be such a bad idea!  

What to do with the second one?

Simple motor stall detector

Even with four corner IR obstacle detectors and the forward facing ultrasonic sensor there are still circumstances where the motors will be stalled and the 'bot should stop.  I did not want, or need, the complexity of an interrupt driven encoder routine so wrote the following simple code to detect a stalled situation:

First I needed to know if we are moving.  Obviously, as for other code posts, I am using my interface library to talk to the Arduino.   Note also that I am using a dictionary structure to pass context (like pin assignments) around the modules that comprise the 'bot.   Not great practice but easy for what I wanted to accomplish.

    def moving(self):
        """
        Returns the true if we are moving and false if not.   Checks changes

        in the encoders if no change is detected over 'n' iterations then
        no movement is indicated
        """
        try:
            self.movingIteration += 1
        except:
            self.movingIteration = 1          
            self.lastMovingIteration = 1
            self.notMoving = 0
            self.lastEnc1 = 0
            self.lastEnc2 = 0

        enc1 = int(self.utility.arduinoReturn(
            self.arduino.analogRead(self.intercom["pins"]["propulsionLeftEnc1"])))
        enc2 = int(self.utility.arduinoReturn(
            self.arduino.analogRead(self.intercom["pins"]["propulsionLeftEnc2"])))

        # Count the number of times the encoders have not shown a change
        if self.lastEnc1 == enc1 and self.lastEnc2 == enc2:
            if self.lastMovingIteration == self.movingIteration - 1:
                self.notMoving += 1
            else:
                self.notMoving = 0
  
        # Probability is pretty low that we would not encounter the same combination
        # of readings five times!
        if self.notMoving == 6:

             self.notMoving = 0
             return False
      
        self.lastEnc1 = enc1
        self.lastEnc2 = enc2
        self.lastMovingIteration = self.movingIteration

        return True


Obviously there is at least one issue with the approach that I am using...namely that I am only looking at one tread.   We could get ourselves into a predicament where the left tread is free wheeling but the right is stalled...!  Oh well.

Anyway, if we know that we are not moving we also need to know if we are supposed to be!  My test for this is to look for current flowing to the two motors:

    def currentLeft(self):
        """
        Returns the current for the left motor
        """
        self.leftCurrent =  int(self.utility.arduinoReturn
            (self.arduino.analogRead(self.intercom["pins"]

                ["propulsionLeftCur"])))
        return self.leftCurrent


Obviously there are two of these but I am only showing the one.

The test for a stalled condition is then a marriage of the above methods:

    def stalled(self):
        # Is current going to the motors?
        if self.currentLeft() > 25 or self.currentRight() > 25:
            # Are we moving?  Is this the second time in a row?   

            # If so we are stalled
            if not self.moving():
                return True
               
        return False


I use 25 rather than 0 as there appears to be some residual current flow for some amount of time after the motor is shut down.

Tuesday, November 13, 2012

Latest Robot Pictures

Here are some of the latest pictures of the 'bot.   We are getting close to the final state now where I can, and need to, focus on the software instead of messing with the hardware!

The white bottle cap is the RGB LED that blinks green for each command loop when we are healthy, once in blue when a command is received, and in red if we have lost the network.   Will also blink SOS if the 'bot software has crashed.


The only major change that I am entertaining at this point is to drive the servo stalk and ultrasonic range finder directly from the RPi GPIO instead of suffering the latency of going through the Arduino.

I would like to move the compass to a direct interface but am not sure about the I2C integration.

Option Parsing in Python

Another helpful Python module is "optparse" which provides a command line option parser.   It lets you define your command line options and then parses the command line for you.   It supports both dash and double-dash formats, logicals, defaults, and even sub options.

I used it for the script that I assembled when I was playing with the RPi GPIO functionality which accepted as options the message to be displayed, the color for the RGB LED, and the standard "interval" to use for signaling.   The definition code is shown below:

    # Get command line options    parser = OptionParser()    parser.add_option("-m", "--message", dest="message", default="SOS",
                  help="Message to blink out in morse code")
    parser.add_option("-r", "--red", dest="red", default=255,
                  help="Red component for blink")
    parser.add_option("-g", "--green", dest="green",  default=0,
                  help="Green component for blink")
    parser.add_option("-b", "--blue", dest="blue", default=0,
                  help="Blue component for blink")
    parser.add_option("-i", "--interval", dest="interval", default=200,
                  help="Length of standard interval in milliseconds")
    (options, args) = parser.parse_args()

Options can be retrieved as shown here:

    # Execute!
    _execute(_compile(options.message), int(options.red), 

        int(options.green), int(options.blue))

I did not use this in the GPIO script but you can easily dump the contents of your options as shown here:

    logger.debug("Initiating startup with the following options:")
    for key, val in vars(options).iteritems():
        logger.debug("    " + key + " = '" + str(val) + "'")

Thursday, November 8, 2012

Python and Logging

Python features a pretty cool (IMHO) logging feature that I am using for my project.  It allows you to log messages with varying levels of severity from DEBUG, INFO, WARNING, ERROR, to CRITICAL.  The code that I am using is shown below.     A sample of output is shown at the bottom of this post.

First we setup a logger.  The name "Main" will be used to connect to this logger from other modules.

    # Setup my logger    logger = logging.getLogger("Main") 

I want my messages to be logged to a file as well so this is done here.   Formatting for messages going to the file include prefixes for the time, name of the module from where the message comes, and the severity level for the message.  

    # Send output to a file as well
    loggingFormat = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"         
    logging.basicConfig(filename='logs/Robot.log', level=logging.INFO, /
        format=loggingFormat)

Create the handler that will be used to log our messages. 

    # Create console handler and set level to debug     
    ch = logging.StreamHandler()
        

I have a command line option that specifies the level of messages to be displayed on the console.  The following dictionary expands the code that I use there.   The two eval statements then apply the selected level to the logging handler.   Obviously this could be hard coded to dispense with the "eval" statement.

    # Set appropriate logging level based on options
    loggingLevels = {"D" : "DEBUG",
                     "I" : "INFO",
                     "W" : "WARNING",
                     "E" : "ERROR",
                     "C" : "CRITICAL"
                    }
 
    eval("ch.setLevel(logging." + loggingLevels[options.loggingLevel] + ")") 
    eval("logger.setLevel(logging." + loggingLevels[options.loggingLevel] + ")")    

We want our messages to be preceded by the severity level so we build a formatter that will do that here.  There are a lot of formatting options but this is all I wanted for the console messages.

    # Create formatter     
    formatter = logging.Formatter("%(levelname)s - %(message)s")
    # Add formatter to ch         ch.setFormatter(formatter)

Finally we add the channel that we created above to our logger and we are ready to go.   My first message is at the debug level.

    # Add ch to logger    
    logger.addHandler(ch)    logger.debug("Initiating startup")

Modules within the robot use the same logger by connecting to it when they init:

    # Setup logging by connecting to our main logger
    self.logger = logging.getLogger('Main.' + __name__)


If I were going to be honest I would have to say that the above methods to get logging going are not all that straight forward!   It works but seems a bit convoluted to me.

Sample output from the startup of the 'bot, showing all messages, is below:

    pi@raspberrypi ~ $ sudo ./xxr  -lD  --disableStream
    DEBUG - Initiating startup with the following options:
    DEBUG -     map = ''
    DEBUG -     testBed = 'None'
    DEBUG -     disableStream = 'True'
    DEBUG -     auto = 'M'
    DEBUG -     disablePropulsion = 'None'
    DEBUG -     serialPort = 'ttyUSB0'
    DEBUG -     commandStart = 'True'
    DEBUG -     shutdown = 'None'
    DEBUG -     loggingLevel = 'D'
    DEBUG -     voltageCheck = 'None'
    DEBUG - Starting hardware interface and utilities
    DEBUG - Initialized utility
    DEBUG - Hardware interface has started
    DEBUG - Reference voltage at 4.8 volts
    DEBUG - Reference adjustment 0.965
    DEBUG - RPi Main voltage at 6.547 volts
    DEBUG - RPi voltage at 4.243 volts
    DEBUG - Main voltage at 7.881 volts
    DEBUG - 5v Bus voltage at 4.839 volts
    DEBUG - Starting daemon communication queues
    DEBUG - Killing old daemons
    DEBUG - Restarting daemons
    DEBUG - Disable stream command queued for action
    DEBUG - Starting robot classes
    DEBUG - Initialized control
    DEBUG - Initialized bridge
    DEBUG - Sensor at 0h and 0v
    DEBUG - Initialized sensor
    DEBUG - Initialized radar
    DEBUG - Initialized navigation
    DEBUG - Current bearing 220.0
    DEBUG - Initialized propulsion
    DEBUG - Initialized mapping
    DEBUG - Initialized proximity
    DEBUG - Robot is waiting for commands
    DEBUG - ----------------------------------
    DEBUG - RPi Main voltage at 6.490 volts
    DEBUG - RPi voltage at 4.196 volts
    DEBUG - Main voltage at 7.881 volts
    DEBUG - 5v Bus voltage at 4.839 volts
    DEBUG - Current range from sensor is 21.07421875
    DEBUG - Message queues are empty
    DEBUG - Current sensor (and robot) bearing 220.0
    INFO - Telemetry uploaded
    DEBUG - ----------------------------------

Wednesday, November 7, 2012

Raspberry Pi and Basic GPIO

Might be a bit silly but I decided that my 'bot needs some way to signal a status...for example...that the network has dropped but the RPi is still there.   I got myself an RGB LED and am thinking that a green strobe actuated at the end of each process loop will mean that all is well.   If the network drops the color will change to orange or yellow.  If the whole lot of code running the 'bot fails a watchdog daemon will flash an "SOS" across the LED.
It turns out that working with GPIO on the RPi is simple.  As you can see in the photo to the right I don't have the ribbon cable adapter for the RPi so I used five jumper cables.   Three of them are for the pins that I will use for driving the LED colors (red, green, and orange = blue since I didn't have a blue cable).   The ground is the black jumper.   The extra red jumper is used to measure the power on the RPi 5v bus (more here).

For now I only have this setup for testing.   I am going to put the LED inside a ping pong ball and stick it on a mast on the stern of the 'bot across from the compass, ideally with a reset switch for the Arduino as things are getting crowded.



The code to drive this RGB LED as a Morse Code signaler is here.  I don't anticipate sending any other message other than SOS but I got carried away.   This sample code also illustrates the use of option parsing in Python but I will talk to that later.  Some of the key snippets from this code are here:

    # Initialize the GPIO module and our three pins     
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(GREEN, GPIO.OUT)
    GPIO.setup(RED, GPIO.OUT)
    GPIO.setup(BLUE, GPIO.OUT)
 

    # Do the actual blinking 
    def blink(r, g, b, duration):
   
    global RED, GREEN, BLUE
   
    GPIO.output(RED, r)
   
    GPIO.output(GREEN, g)
   
    GPIO.output(BLUE, b)
   
    time.sleep(duration)
   
    GPIO.output(RED, 0)
   
    GPIO.output(GREEN, 0)
   
    GPIO.output(BLUE, 0)
   
    time.sleep(INTERVAL)
 

    # Reset the pins we used
    GPIO.cleanup()


Obviously this is the most simple example possible but it shows the initialization, writing to a pin, and the all important cleanup.  

BTW, you need to run this under sudo to access the GPIO.  There is a discussion of alternatives here.

Almost all the code related to the Morse Code functionality came from a post created by Stephen Chappell on Thu, 12 Jan 2012 (MIT)

Monday, November 5, 2012

Required Reading for 'Bot Builders

I have been spending a little time on the Raspberry Pi Forum and have found it to be very useful for troubleshooting assistance.   One of my posts elicited a response from Dave that pointed me to the following two articles, that while I have not yet finished reading, are clearly of interest to a 'bot builder:
In particular they address the issue of 'how will my robot find it's way home' or maybe even just how it will find it's way around things!?!?

The first of the two is brief and practical.  The second is much, much, longer, and more comprehensive but possibly less practical for my needs!

Sunday, November 4, 2012

Remote Control Web Interface for 'Bot

The first phase of my project was to assemble the 'bot, integrate all of it's moving parts with the Arduino, and then with the RPi via my interface library, and control it all with a web based control panel.   In the next phase I will tackle some autonomous tasking but the first phase has been quite the challenge as it stands.   I am nearly there now and have one of the most expensive, yet clunky, remote control 'bots around.

Anyway, here is a screen shot of the web control panel for the 'bot.   I really should have developed this in something like Python and gotten rid of the latency that a web application entails but I did have a rationale.   Namely that as part of my technical education I developed a forms building environment for PHP and that allows me to very easily and quickly deploy a web based application.   So here it is.


Under control of this application my 'bot can now do the following things (though still with a couple areas of improvement):
  1. Move forward or backward at various speeds using the compass to maintain a straight course (tracks do not always pull uniformly).
  2. Throttle forward speed based on nearness to an object being approached as detected by the ultrasonic range finder.
  3. Detect obstacles using the four corner IR sensors and stop the 'bot.
  4. Reverse direction, change course, or stop under command from the web application.
  5. Pan and tilt the sensor stalk at the front of the robot on which the range finder and webcam reside.
  6. Use the range finder to scan the area within the pan range of the sensor stalk.
While doing the above the 'bot will upload images from the webcam, will upload an image created from the scan done with the range finder, all while uploading various status messages and telemetry.   The 'bot will also respond to shutdown and restart commands (the python code runs within a looping shell script that either repeats itself for a restart or exits on shutdown).

My first incarnation of the interface between the 'bot and this web application was to have the 'bot interact using a simple command/response dialog via HTTP.   This doubled the latency for dealing between the controlling app and the 'bot so I implemented a socket based stream for communications.   You still have the latency between wet ware and the web application but commands from the web app, and telemetry back, are done in real time.  This is described here.

The below screen shots show the result of the ultrasonic scan that matches the photo from the screen shot above.  The 'bot is in blue, the darker a return the more confident we are in it's location, and red indicates infinity.    This is a very first attempt at this and has much work to do including accounting for the "cone" of coverage the sensor provides.






A third and final screenshot shows the status log display.


Saturday, November 3, 2012

Python to Arduino Interface - Part 3 - Version 2

This is an update to the posts that described my original Python to Arduino Interface.  I upgraded the interface to add an option for generating exceptions on error and to return values directly from a read function.

The download includes a script named zzTestVoltage.py that illustrates the use of exceptions for error processing:

    print
    print "Throw error exception test"
    print
    my_board.setExceptionOn()
    try:
        testVoltage = float(my_board.analogRead(999)) * .0049
    except interfaceError as err:
        print err.message


The other change implemented in this version is to return values from functions such as analogRead directly rather than as an attribute to the class.   This is illustrated above as well. 

If you would rather not throw exceptions you will need to check the value of the returnStatus attribute to ensure there has not been an error:

    testVoltage = float(my_board.analogRead(5)) * .0049
    if my_board.returnStatus != 0:
        print "Error on analogRead = " + my_board.returnDebug



Python to Arduino Library Download - Version 2

Download the Py2Ard Interface Library - Version 2.  There are four files in this archive:
  • Py2Ard.ino - The sketch that provides the Arduino side of the interface.
  • Py2Ard.py - Python code that provides the host side of the interface - in my case running on a Raspberry Pi.
  • zzTestVoltage.py - Script that shows a voltage check and the throwing of an exception on error.
  • zzTestLib.py - LED blink test also showing the use of Debug and Trace functions.
Please leave a comment below and I will let you know when a new version is available.

The above library is described in three posts, Part 1, Part 2, and Part 3 - Version 2.

Thursday, November 1, 2012

Power Issues = Compass Issues

In a previous post I complained about some compass issues that I have now attributed to, guess what, power!   Having sorted out my other power issues I came back to work on the compass a little and found that it was now reading accurately (e.g. agreed with a regular compass).    It still delivers the occasional errant reading when a train goes by but I have written some code to tune those out.   I now have a compass that is stable within what looks like about a degree.