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.

Wednesday, December 12, 2012

Time to code some autonomous operation


I will have to upload a video of the 'bot maneuvering as a very expensive remote control tracked vehicle but here is a picture that it took of me after a romp around the lounge.   The special effect is due to my telling it to start moving at which point it orients the sensor stalk forward.   This image just happened to be taken at that second.   It is pretty much where I want it to be at this stage of the project.
There are still a few small bugs, or areas for reconsideration, in the controlled operation but not serious enough to keep me from starting the next phase of the project...getting it to do something on it's own!

Friday, December 7, 2012

Following a compass bearing (or NOT!)

One of the things that I would like for my 'bot to be able to do is drive in a straight line.   Seems simple but unfortunately I seem to have one motor pulling slightly differently than the other.

My first try at correcting for this was to simply put in an adjustment factor for the motors.  This helped but to make things interesting it seems that the 'bot motors behave differently at different battery charge levels (and speeds).   So, I said to myself, why not write a routine that detects the drift of our heading and then tweaks the adjustment factor?   I then said to myself, it should probably be sensitive to the amount of variation and raise or lower the amount of each adjustment based on the deviation in our heading.   Finally, and this was turning into a long conversation with myself, I said to myself, you should probably put in a quiesce for a number of cycles to let the adjustment take effect before trying again, and, you should also make these different factors tunable as startup arguments.

So we (me, myself, and I) get all this coded and try it out.   Does not work.  Not even close.  It appears to be doing all the right things but the 'bot is veering radically to the left.   We put in all kinds of debug statements and can not figure out why it would be acting this way.

Finally it dawns on us.   In an earlier post I mentioned that we are renting a place (moving out in a couple of weeks now that we have finally bought a place) that sits just about underneath Brunei's famous Sounding Arches railroad bridge in Maidenhead.   This has to be one of the busiest train lines in the world as it is the major east west line into and out of the centre of London.   I knew that we get a lot of electro magnetic interference from the trains but thought that was only the occasional variation in bearing as a train passes (also plays havoc with TV reception via an ariel).   As you can see from the two compass readins we are getting a lot more than just an occasional glitch.   These two readings are taken long a five foot divider between our kitchen and lounge.   In that five feet we get a variation in bearing of almost 20 degrees!

It is NOT my code that has an issue here!  The 'bot is chasing a compass bearing that is far from constant to the magnetic north pole!

Tuesday, December 4, 2012

Imagine the look on my face...

...when my RPi would not boot right after I finished some power supply work on the 'Bot!?!?   I was so convinced that I had fried it that I was researching diagnostics to prove the point.   All I got on power on was a red light.   No green flashes.   Nary a one.

What I guess I did not realize is that a bad SD card will result in the same lack of green flashing.   That is good news.   Also on the good news front is that I have a backup of the boot partition and when I dd'ed it back onto the SD card everything in 'Botland was right again.   Err, well not quite.

Somehow, whatever took out the boot partition, also caused some pretty significant damage to the primary partition where everything else lives.   But not to worry we have a backup of that as well, right?  Err, well not quite.   You see, I give the advice, but I don't have to follow it!   The backup that I have is not exactly up to date.   I am not sure how up to date it is, or is not, so I am going to have to rebuild it.

-----UPDATE as of 5/12/2012 ----

It is the next day now and I am still recovering from the above fiasco...the part where my backup of the primary partition was not where I remembered putting it!   So I am re-creating the entire configuration, rationalizing that it is something I wanted to do anyway, and swearing that I will make good backups from now on!

Version control - for hobby 'Bot software?

You may not think that you need version control for a "hobby" project until you need it!   The code base for the 'Bot is getting pretty hefty and I have had a couple of times when I have implemented a series of changes and had some unexpected breakage.  I have implemented some pretty sophisticated version control as part of my Form Builder for PHP project (where all updates to test and production are done via diff files generated from development) but until this week had not been using any versioning for the 'Bot.

There are some simple ways to maintain versions of code.   If your operating system supports file versioning you can simply turn that on.   You can make periodic copies of your code directory.   If you are using a backup solution it likely maintains versions of current backups.   These all work but don't offer the additional functionality of a versioning tool like Apache Subversion combined with a front end like SmartSVN.

Below is the primary form from SmartSVN.  It shows the directory structure for your project and the files from the currently selected path.   Only files that you choose to be versioned will show in this list (in my case Python files).   If a file has been modified but not committed it will show as changed.


The bottom of the above form shows the latest revisions.   If you select a revision you can then see what changes were made as part of that commit.


You can, at this point if you realize where you have shot yourself in the foot, reverse those changes!

Sunday, December 2, 2012

Bright Idea re RPi GPIO - NOT!

So I had this bright idea that I could use the RPi's GPIO pins to offload some processing from the Arduino and save some latency in my command processing loop.   Got my ribbon connector all nice and sorted out, connected up the appropriate sensors to voltage dividers to get them down to 3.3v, and only then read the f-ing documentation.    The pins are binary!!!  Doop!

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.

Tuesday, October 30, 2012

Power Stability = RPi Stability

The troubleshooting area of the Raspberry Pi forum uses the "check your power" a lot in answer to user problems with crashes and other bad behavior.   At first glance one would almost wonder if this is their version of either the reboot it stupid or RTFM.  In fact, the RPi is enormously, hugely, and frustratingly, sensitive to power issues.

Through the process of integrating my RPi with the robot it is meant to control I have learned more than I really expected about power.    Here are some of the problems that I have had that have tied back to "get your power sorted stupid"!
  1. RPi would not boot as input power was too low.   Would cycle through the color splash, get to the point where power was not adequate, and crash
  2. Wireless connection would drop.   Often occurred at a point where current draw from somewhere other than the RPi would draw down voltage and away goes wireless.
  3. RPi would crash when servos were activated to control the sensor pan and tilt stalk.
  4. Webcam would drop offline.   Finally determined that this was also power related and that it was dropping when power levels to the USB hub dropped.
I have not measured the various thresholds when bad stuff happens but after making the following changes, and running on reasonably fresh batteries, the 'bot is stable:
  1. The Rover 5 comes with a six AA cell battery pack that connects to the Explorer PCB where it is regulated down to a 5v and 3.3v supply.   I added a second six cell battery pack and upgraded the rechargeable batteries in these two packs to high end cells (1850mAh).
  2. To further sanitize the power going to the RPi I added a dedicated regulator that draws directly from the battery circuit and is dedicated to the RPi
  3. Somewhere along the line I read the Explorer PCB manual and realized that it provides three power outputs with one dedicated for servos.   Once I connected the servos to their own power source the servo induced crashes stopped.
I still have one more improvement pending and that will be to have two 3.7v 18560 Li-Ion cells (4000mAh) to drive the RPi with the a dedicated regulator from the main batteries powering the USB hub.

Addendum of 1/11/2012: In the days following this post I was also able to determine that problems with my compass were ALSO power related!

Structure of 'Bot in Python

The goal of the first phase of my 'Bot project is to have the entire platform integrated but operating under control of a web application.   The web application will pass commands to Python code running on the onboard RPi, which in turn will drive the Arduino to manage the 'Bot.  I am close to completing this first phase but for a fair amount of tuning...of the software, the hardware, and the integration of the two!  

The structure of things, however, is fairly well established so this post is intended to provide a high level overview of the python code running on the RPi.

Initialization, a dictionary used for a command and control structure, and the primary processing loop comprise the module Main.py.   The other modules of the 'Bot, mostly called from within the Main.py processing loop, are as follows:
  • Bridge.py - Not in use right now but anticipated to be the home of autonomous logic.
  • Control.py - Gets commands from the PHP web control script, via the ControlDaemon.py, and passes them on for execution.
  • Mapping.py - My thought was that this module would generate a map of a room using the rangefinder.   It currently does a scan but until I figure out how to accurately pin the robot position I am not sure how this will work.
  • Navigation.py - Not in use now but for returning a bearing.  Will ultimately keep track of exactly where the 'bot is and where it is going.
  • Propulsion.py - Controls the treads to move forward, backward, and to turn. 
  • Proximity.py - Detects objects using the four corner infra-red detectors and issues a stop order for propulsion.
  • Py2Ard.py - Called by any module needing to interface with the Arduino.   Discussed here in this blog.
  • Radar.py - Controls the ultrasonic sensors in a collision and speed governing mode while moving forward.  During mapping operations is driven by Mapping.py to scan an rangefind obstacles.
  • Sensor.py - Controls the two servo's that orient the pan and tilt sensor platform on which the radar (rangefinder) and webcam reside.
  • Utility.py - Home for a number of utility functions and supported by UtilityDaemon.py where lower priority processing is conducted.
As mentioned above a PHP script called Robot.php runs in the cloud and is used for manual control of the phase 1 robot.

Sunday, October 28, 2012

Continued Saga of Robot Power Issues

My legacy of power issues continues but I think I have solved at least one.  When the 'bot initializes it fires up the servos for the pan and tilt sensor stalk.   The current draw from this action has been causing the RPi to crash. 

Reading the documentation is probably a good thing. Turns out the Explorer PCB has a separate power supply for servos that delivers them their own 5v supply 'dioded' down from the batteries.  Go figure.  Unfortunately the first time I hooked it up I managed to make things smoke as I connected what I thought where "+" and "-" connections to the power rail for the servos.   The two pins were meant for a jumper so what I did was install a short.   Smoke is not good but nothing seems to have actually tipped over which is surprising at best (how does something smoke but still everything works?).   The servo's are now isolated from the RPi and that is a good thing.

I have still not received the new Lithium Ion batteries that I have ordered to power the RPi independent of the rest of the 'Bot.  I did, however, get a new power regulator and have installed that to further isolate the RPi from power glitches.   This seems to help but I need to complete my battery upgrades (still waiting for some new nicad rechargeable's as well) to be confident that my power issues are behind me.

Friday, October 26, 2012

Time for some Python

I have chosen to use Python as the development language for my 'bot.   One reason being that it seems to be the 'standard' higher level language for the Raspberry Pi and is a default on the Wheezy distribution of the O/S.   A second is that it is a cool language!  I grew up with interpreted languages and really like being able to prototype code at the command line.   More importantly it is also a good OO platform and has a large eco-system of extensions.  

In any case...I am using it and liking it as well.   One thing that I do find a little bizarro is the spacing sensitive syntax.   Instead of relying on something like "{" to group code Python relies on levels of indent.   Makes sense and also enforces neat code but is still strange!

From this point in the blog posts will start to mix between the hardware, which has consumed me to date, and the software that will be driving it.

Learning Python By Lutz, Mark (Google Affiliate Ad)

Wednesday, October 24, 2012

More Compass Shenanigans

My compass continues to be possessed by evil demons.  I am pretty confident that living in the shadow of Brunel's Sounding Arch bridge outside of Maidenhead, home of one of the worlds busiest train lines, is part of the problem.  The HMC5883L is supposed to be accurate within a couple of degrees but mine varies all over the map and is convinced that east and west are not 180 degrees apart.   I have not had a chance to prove this by testing somewhere else but will at some point.

I could live with this behavior for now assuming it were reasonably stable...which it has not been.   For example, I tell the 'bot to turn 10 degrees to the right and it went into an infinite loop chasing a bearing that it never attained.  This is not good!   It turns out that my own electric motors kick up enough magnetic disturbance to freak it out (maybe in tandem with the electric train lines near us)?   I had originally mounted the device on the bread board in the center of the Explorer PCB but moved it to the rear and mounted it on a little mast.   I have now raised that mast and it seems to have helped...with at least one aspect of it's behavior!

My original thought was that I could use the compass when doing mapping (a function that I envisioned for my 'bot).   At this point I am not convinced that I am going to be able to do this given the required accuracy.   This leaves me with the quandary of how to know the bot's position.   I was hoping to have a bearing and use the range finder for distance.   Hmmmm.

For an update on this issue see this post.

Monday, October 22, 2012

Crude FTP Update in Python

I have been keeping the code for my 'bot on my Ubuntu laptop, updating it from my iMac, and then running a Python script to FTP it to the RPi.   Once major problem with this is that sometimes I will make a change and forget to run the update and then wonder at the abstinence of the 'bot to have changed it's behavior!  

I could simply cron the script to run every how often but this didn't feel very eloquent especially as the copy includes everything whether it has changed or not.  So not that my solution is terribly eloquent but I decided to write a quick script to only move code that has been changed and then put this inside a 15 second iteration loop.

I have one big try statement as my assumption is that a failure means the RPi is not online and that I should try later.

Code for "Crude FTP Update"


Wednesday, October 17, 2012

Arduino - Voltmeter

The following code illustrates both the reading of a voltage with the Arduino and then adjusting it using the code from the Secret Arduino Voltmeter article by Scott Daniels:

Do some initialization stuff (obviously this is not Arduino code as I am using my interface library):

    import time
    from Py2Ard import interfaceClass
    my_board = interfaceClass('/dev/ttyACM0')


Get the reference voltage and use it to calculate an adjustment from 5 volts:

    if my_board.referenceVoltage() != 0:
        print "Error"
    else:
        print
        print "--------------------------------------"
        refVoltage = float(my_board.returnValue) / 1000
        print "Reference................. {0:.3f} volts".format(refVoltage)
       
        adjustToRef = 1 + (refVoltage - 5) / refVoltage
        print "Adjust to Reference....... {0:.3f}".format(adjustToRef)
        print "--------------------------------------"
       

Get the voltage we are trying to measure and adjust it using the above factor.  Note that the '* .0049' converts the analog return from reading the voltage to a five volt scale.  The '* 2' then doubles that value to compensate for the voltage divider factor of 50%:

    if my_board.pinModeInput(5) != 0:
        print "Error"
    if my_board.analogRead(5) != 0:
        print "Error"
    else:
        mainVoltage = float(my_board.returnValue) *.0049 * 2
        print "Input - As Read........... {0:.3f} volts".format(mainVoltage)
       
        mainVoltage = mainVoltage * adjustToRef
        print "Input - Adjusted.......... {0:.3f} volts".format(mainVoltage)
   
    
The actual voltage at this point in time is 7.82 as read from our meter so calculate an error percentage:
    
        actualVoltage = 7.82
        error = (actualVoltage - mainVoltage) / actualVoltage * 100
        print "Error from Actual......... {0:.1f}%".format(error)
        print "--------------------------------------"
        print
   
    
The output from the above script is shown below.   Note that I have also adjusted the Arduino referenceVoltage script provided by Scott Daniels as he suggests in his article (adjusting for the inaccuracy of the 1.1v reference by actually measuring the 5v Arduino output and adjusting for the difference).

    --------------------------------------
    Reference................. 4.910 volts 
    Adjust to Reference....... 0.982
    --------------------------------------
    Input - As Read........... 8.026 volts 
    Input - Adjusted.......... 7.879 volts
    Error from Actual......... -0.8% 
    --------------------------------------


Caveat comes here...it feels like I am double adjusting things to arrive at the answer that I want rather than the right answer...  I may post this on Scott's page and ask him if my not electronically oriented brain has miss interpreted things badly!