Sunday, September 15, 2013

Symphony in C

One of the challenges with a custom language like Spin is that a lot of the support mechanisms available to standard languages are not available.  

The great news is that Parallax has released a C/C++ compiler and IDE for the Propeller chip!    A set of libraries is under development by Parallax to provide support for many of the sensors, servos and accessories where there are Spin libraries.  

Here is a link to the main Parallax page for using C with propeller.

Going forward any code that I create for Boe-bot will be developed in C.  

Thursday, September 5, 2013

Really simple Artificial Intelligence (Part 2)

This is part two of really simple AI for Boe-bot in Spin.  In this example, Boe-bot is setup with a speaker (Pin 3) and two contact whiskers (Pins 6 and 9).

The code below gives boe-bot the goal of moving forward and several pre-programmed choices for dealing with obstacles.  Boe-bot tries different maneuvers when it encounters an obstacle until a maneuver is successful in navigating the obstacle.    

A few basic programming hygiene comments about the code:

  • Name variables and constants.  Without names the code is less maintainable.  For example, WhiskerContact = 0 and NoWhiskerContact =1.  Without these names it would be very easy to reverse which value meant what!  To improve the below code, the values 0 and 255, which represent the minimum and maximum values that can be stored in a byte should be replaced with constants that reflect their purpose.
  • Even better, give clear meaningful names.  Take constants C6, C7 and G6.  As the author I know that they correspond to musical note frequencies.  Unfortunately, that required context and increases the learning curve for others.  Better names would be noteC6, noteC7 and noteG6.
  • Split code into small logical units.  This may seem obvious but is important as your program gets larger.  As a general rule, a function should be about 20 lines of code.  It will also help with reuse of code, as larger units of code are less likely to be reusable and much smaller units will not be too simple to capture meaningful functionality.    

Future ideas for this code.  While this code is functional, there are ways it could be enhanced.

  • The PickManeuver function has simple logic, selecting the highest value.  Using a statistical model could improve the learning process.  This would also be useful if Boe-bot was in a changing environment and a previously successful maneuver was no longer successful.  
  • Generate obstacle avoidance maneuvers at run time.  Currently these are hard coded to be successful options.   


OBJ

 system : "Propeller Board of Education"
 speaker : "PropBOE Square Wave"
 drive : "PropBOE-Bot Servo Drive"
 pst    : "Parallax Serial Terminal Plus"
 pin    : "Input Output Pins"   
 time : "Timing"  

CON
  C6 = 1046
  C7 = 2093
  G6 = 1568
  SpeakerPin = 3
  LeftWhisker = 6
  RightWhisker = 9
  LeftServoPin = 14
  RightServoPin = 15
  WhiskerContact = 0
  NoWhiskerContact = 1

DAT
  '                   left   right    time
  forward      long    100,    100,   1000
  backward     long   -100,   -100,    500
  pivot_R_45   long    100,   -100,    370   
  pivot_L_45   long   -100,    100,    370
  stop         long      0,      0,    500
  backupLeftLeft  long @backupLeftLeft, @backward, @pivot_L_45, @pivot_L_45, @stop, -1
  Right     long @Right, @pivot_R_45, @stop, -1
  Left      long @Left, @pivot_L_45, @stop, -1

VAR

  byte maneuverSuccessL_CntList[3]
  byte maneuverSuccessR_CntList[3]
  byte maneuverSuccessB_CntList[3]
  
PUB Main
  Startup
  LearnNavigation
  
PUB StartUp

  system.Clock(80_000_000)

  speaker.Out(SpeakerPin, 300, G6)
  speaker.Out(SpeakerPin, 300, G6)
  speaker.Out(SpeakerPin, 300, C6)

PUB LearnNavigation | maneuver, i
  pst.Str(String("Starting learn navigation program"))
  pst.NewLine

  bytefill(@maneuverSuccessL_CntList, 128, 3)
  bytefill(@maneuverSuccessR_CntList, 128, 3)
  bytefill(@maneuverSuccessB_CntList, 128, 3)
             
  repeat                                                                
      time.Pause(20)
      if pin.In(LeftWhisker) == WhiskerContact and pin.In(RightWhisker) == WhiskerContact
          maneuver := PickManeuver(@maneuverSuccessB_CntList)
          ExecManeuver(maneuver)
          if pin.In(LeftWhisker) == WhiskerContact and pin.In(RightWhisker) == WhiskerContact
            if(maneuverSuccessB_CntList[maneuver] > 0)
               maneuverSuccessB_CntList[maneuver]--
          else
            if(maneuverSuccessB_CntList[maneuver] < 255)
               maneuverSuccessB_CntList[maneuver]++
      elseif pin.In(LeftWhisker) == WhiskerContact
          maneuver := PickManeuver(@maneuverSuccessL_CntList)
          ExecManeuver(maneuver)
          if pin.In(LeftWhisker) == WhiskerContact
            if(maneuverSuccessL_CntList[maneuver] > 0)
               maneuverSuccessL_CntList[maneuver]--
          else
            if(maneuverSuccessL_CntList[maneuver] < 255)
               maneuverSuccessL_CntList[maneuver]++
      elseif pin.In(RightWhisker) == WhiskerContact
          maneuver := PickManeuver(@maneuverSuccessR_CntList)
          ExecManeuver(maneuver)
          if pin.In(RightWhisker) == WhiskerContact 
            if(maneuverSuccessR_CntList[maneuver] > 0)  
               maneuverSuccessR_CntList[maneuver]--
          else
            if(maneuverSuccessR_CntList[maneuver] < 255)
               maneuverSuccessR_CntList[maneuver]++
      else
        drive.wheels(100,100)  

PUB PickManeuver(maneuverSuccessList) : highScoreIndex | highScore, i          

        highScore := 0
        highScoreIndex := 0
        'use highest ranked option
        
        repeat i from 0 to 2
          if((byte[maneuverSuccessList][i]) > highScore)
              highScore := byte[maneuverSuccessList][i]
              highScoreIndex := i

        return highScoreIndex  

PUB ExecManeuver(maneuver)
  case maneuver
    0: drive.Sequence(@Left)
    1: drive.Sequence(@Right) 
    2: drive.Sequence(@backupLeftLeft)
              

Wednesday, September 4, 2013

Really simple Artificial Intelligence

Artificial Intelligence (AI) is a very broad field.  I could not possible do the entire topic justice in a blog post but at least I can give a brief introduction to the field and break down what I see as the most common misconception.  

The field of AI seeks to create systems that find solutions were previously unknown to the program creator (not take over the world and use us as batteries).  One branch of AI is machine learning, where programs learn based on inputs and then can act on future inputs to achieve a goal.  

Today, we are going to break down the misconception that artificial intelligence programming has to be very complex.  The diagram below illustrates a conceptual goal based navigation for Boe-bot that I created.  The goal we've given Boe-bot is to go forward.  That is it!  

This wouldn't be much of a goal if Boe-bot were in an environment with no walls, like on a treadmill or an infinitely large surface.   Since there are walls in Boe-bot's actual environment, it needs to know it has driven into a wall and take a corrective action in order to meet its goal (of driving forward).  To help with this, Boe-bot has two inputs -whiskers that are attached to switches.  When a switch is closed, we know Boe-bot is touching a wall or obstacle.  

In this first code iteration, Boe-bot has been armed with three action choices, turn left, turn right or backup and turn right.  We want Boe-bot to learn which action will allow Boe-bot to accomplish the goal of driving forward.  Initially, Boe-bot gives each action an equal likelihood of success for the three combinations of input stimuli (left whisker touching, right whisker touching or both).  Through trial and error Boe-bot will learn which actions are more success at responding to certain input stimuli.

For example, if the left whisker is touching a wall, it is unlikely that turning left will free Boe-bot from the wall.  Using the algorithm outlined in the diagram, if Boe-bot initially did select turn left in this example, the result would be to reduce the success rating for this action choice.  When Boe-bot chooses an action the second time, it will choose a different action.  Assuming that action is successful, Boe-bot will increase the success factor for this action stimuli pair.   


In part two of this article, I'll share my code that implements the above algorithm and perhaps also share a video of Boe-bot learning in action!  

In future articles, I'll explore how we can make this more interesting, through a richer selection algorithm and have Boe-bot generate actions.

Monday, September 2, 2013

What good is a robotics blog, without some robots?


I’ve been using the Parallax Boe-Bot platform with a Propeller microprocessor on a Propeller Board of Education.  My initial impressions of both the chassis and electronics are positive:

Chassis
This platform is relatively low cost (bare chassis can be had for around $80 USD), its compact size and lots of attachment points.  Mostly metal, it can take the beating that figuring out how to detect the edge of a table can dish out!  One wish I do have is that it doesn’t have wheel encoders, so accurate navigation can be a real challenge. 

Propulsion comes from two servo motors, so it simplifies the overall electronic complexity.  This also has the added benefit of making the robot move at a reasonable speed, so that head on collisions don't inflict any damage (except for my ego - where did my obstacle avoidance design go wrong)! 

Propeller and Board of Education

Multicore, check.  SD card interface, check.  Breadboard, check.  The propeller microcontroller and board of education offer a lot of expansion options, so you won’t quickly run out room to experiment.  Parallax provides robust documentation for propeller and a free IDE.  The IDE supports two languages, Spin a high level language and assembly language for those times when speed matters.

The 64K of onboard RAM may sound like nothing compared to the gigabytes on most computers.  For me it has been a huge adjustment.  With that little space, things that you rarely had to consider in software development become much more important.  For example, not only do programs have to be shorter, the variables in them also occupy that same 64K.  It is like asking J R R Martin to write a haiku.  

Boe-bot with whiskers





Welcome

Robots have been around for a long time, probably longer than most people realize!  

Some sources trace mechanical robots back over 2,000 years.  These early mechanical robots, often built to look like a person, were very simple by modern standards yet touch on a very human desire to create life in many ways.  It was not the advent of the transistor and integrated circuits that robots began to move from novelty into a serious field of research that yielded practical applications. 

In the last 50 years robots have proliferated in both number and design.  From factory assembly lines, children’s toys and Mars robots have not just made us more productive but expanded the boundaries of our knowledge of the universe.

As a child of the 80s, I couldn’t help but be fascinated by robots and credit a few pop-culture robotic icons (Johnny 5 from Short Circuit and Batteries NotIncluded to name a few) with first getting me started in programming.  I imagined what it would be like if advanced robots with emotions and social connections really existed.  It would take more than just circuits and hardware to imbue robots with the capacity to learn, problem solve and think; the real challenge would be software. 

The purpose of this blog is to explore areas of interest (mine and yours) related robotics and software engineering.  I hope to make this blog accessible to a wide range of readers, so look for a range of articles from basic programming and electronics to cutting edge topics such as artificial intelligence, robot swarms, communications and navigation. 


What other robotics related topics would you like to see discussed?