Posts Tagged ‘bayes filter algorithm’

FNR – BubbleBoy Behaviour AI

Posted by Erin, the RobotGrrl on Monday, July 12th, 2010

This week and this Friday Night Robotics I was working on a behaviour AI for the newly refurbished BubbleBoy! It is much easier to design an AI that you know will be interactable with thew orld! Without the headbobbing capability of BubbleBoy, this effort would not be worth it.

BubbleBoy’s behaviour is primarily focused on food and water. BubbleBoy lives its anthropomorphized life just be be fed/watered! This means that BubbleBoy will want to know when it will expect to be fed, so that way it can headbob at the most optimal times. Being fed/watered is having a button pressed on BubbleBoy’s green stage area (the part with the blue and white LCD).

BubbleBoy will have three sensors, and a rudimentary measure time. The three sensors are the LDR, lid switch, and Xbee. All of these are onboard the robot (except for the Xbee which isn’t implemented yet).

Here’s a broad flowchart of the behaviour, which I will then explain below in detail.

BubbleBoy Behaviour AI Flowchart

  1. Creating the Expectation

  2. This is the observatory phase. BubbleBoy initially does not have any expectation of when to be fed, so it waits around. While it is waiting, its collecting data from all of the sensors and storing them to an array. There has to be 10 numbers in the array for each sensor before BubbleBoy can proceed to the next stage, pattern finding. Once this is fulfilled, and if BubbleBoy is fed/watered, then it goes on to find a pattern.

  3. Pattern Finding

  4. BubbleBoy is seen as a simple robot. Thereby, its pattern finding is relatively simple as well. The main idea is to check each sensor’s array and see if there is a pattern within the residuals. Meaning, if looking for a sequential pattern, the array would be iterated through (starting at i=0, stopping after i=8), and i+1 would be subtracted from i. An average of the residual change would be calculated at the same time. The array would be iterated through again, this time to count how many items are within +- 10% of the residual average. If the count is above 7, then it is said that there is a sequential pattern in there.

    The same process is done for a secondary pattern, and a ‘thirdary’ pattern. Meaning, every 2nd number and 3rd number is checked to see if there is a pattern. It also goes through and checks with offsets, just incase the pattern is “even/odd/whatever”.

    If there are no patterns, a random primary sensor is chosen for BubbleBoy to work with.

    A problem exists in determining which pattern for which sensor to trust the most. A thirdary pattern for a photosensor is less dependable than a sequential pattern for a lid switch. This is handled in the next step.

  5. Determining the Sensor to Use

  6. The sensor with whatever pattern to follow is chosen through a Bayes Filter. This allows for a simple specification of confidence levels for a given sense resulting in a particular state through a table where all rows add up to 1.0. The sense columns are the sensor and pattern type. Meaning, there’s three sensors for every sensor, giving 9 senses in total. The states are confidence intervals. Anything >= 85 would be considered the most confident.

    Bayes Filter AI Lookup Tables

    The numbers in bold are the ones that are more probable to be a result. A sensor in particular to look at is the Xbee for a thirdary pattern. The numbers are dispersed in such a way that it is almost a bimodal distribution. In order to understand why this is, imagine the scenario in real:

    Xbee modems can communicate for up to a few meters. If BubbleBoy only receives a message every 3rd instance, it could either be a clever pattern, or it could be a miscommunication.

    For this reason, the largest probability is given to the least confident state, and the second largest probability is given to the most confident state. It depends on the Bayes Filter and random roulette for what will actually be chosen.

    This is just for determining what sensor is the most confident, that will provide the best result. This can mean that the chosen sensor will be followed, but it also may not. This will be explained in the next step.

  7. Calculating the Cost Adjustment

  8. The adjusted cost is determined by using the result from the previous step, and multiplying the probability by the inverse of whatever column it was situated in. In simpler terms, if the result was found in the best confidence interval state, then it would be multiplied by 5. If it was in ( 85, 70 ], it would be multiplied by 4…

    This is then used as the sense for the next Bayes Filter. The state is how much of a cost to reduce the sense by.

    Bayes Filter AI Lookup Tables

    Once the cost adjustment amount is determined, it is then subtracted from the cost of the particular sense’s cell. All of the senses are in a grid, with the most “primary” being the closest to BubbleBoy. An A* search is then used to choose the closest and least cost sensor. Once this is done, BubbleBoy can get on to entertaining its audience while waiting for food/water!

  9. Following the Expectation

  10. This is the main loop of the program. It’s where BubbleBoy is thinking in the present time about if it will be fed or not! :)

    The key idea here is that BubbleBoy is thinking in the now. Meaning, it tracks the patterns differently than it does when it is reflecting back on them (in a “past” thought).

    Sensor data is retrieved and placed into an array of size 10. The data at i is checked wither it is within +- 10% of the average in the pattern. The threshold percentage amount differs for the type of pattern, where secondary would be +- 20%, and thirdary would be +- 30%. If the data fits in to the check, then a “yes” counter is incremented.

    Once the “yes” counter is >= 6, the food level will begin to decrease by (i/2)^2. At the same time, BubbleBoy will begin to show signs that he is excited to be fed/watered soon, by spinning its hat and bobbing its head.

    If the “no” counter is >= 6, then it means that the expectation isn’t really working in the present thought. A flag is set to redo the expectation once BubbleBoy receives food and water.

    i is then either incremented or reset to 0, depending if it hit 9 or not. (That’s a sort of obvious step)

  11. Real-World Behaviors

  12. When the time elapsed from not receiving food exceeds 150% of that of the observed elapsed time, BubbleBoy goes in to a “wallow” mode. When BubbleBoy is wallowing, it spins its hat slowly, and bobs rarely.

    If the time elapsed is ( 150%, 100% ], BubbleBoy is “angry” because it did not receive its food exactly before the time elapsed. The hat will not spin, and BubbleBoy will bob side to side, and once (quickly) in the opposite axis to simulate a sort of “twitching” to all this anger!

    If the time elapsed is ( 100%, 85% ], BubbleBoy is eager to please. Hat tricks will be common, same as delightful bobbing. Depending on how much food/water BubbleBoy has, it may also hoola hoop!

  13. Last part of Following the Expectation

  14. Depending on when BubbleBoy was fed, if it was in ( whatever, 100 ], the expectation will be done. Essentially, BubbleBoy is a positive/eager thinker that believes it should always be fed before the elapsed observed time. What an attitude!

    If it is in [ 85, 100 ), then the expectation will be kept.

    To reformulate the expectation, the previous steps are executed on the collected data. Then, everything repeats!

What will be super interesting to see, in my opinion, will be when the discrepancies occur from past thought to present thought. It will be interesting to see which sensors fare better through that transformation.

It will also be interesting to see if this actually can work on an Arduino, and not in simulation. I created a simulated version of BubbleBoy in Processing earlier in the week.

Screen shot 2010-07-04 at 2.56.16 PM

I’ll do the initial coding and testing through this simulation, mainly because I already coded the Bayes Filter Algorithm (with random roulette) in Processing from 2009 Honors Summer Research. :D Plus, in Processing it is very simple to communicate to an Arduino through Firmata. I can read in the data from BubbleBoy through there.

Hopefully next Friday I will have devised a test sequence to test the soon-to-be-coded AI on. This will of course be Open Source, under the Attribution-NonCommercial-ShareAlike 3.0 Unported License (BY-NC-SA).

Let me know what you think of this AI in the comment section below! (And yes I know it is very linear, but BubbleBoy doesn’t have enough DOF in the real world to spend the effort making the AI more nonlinear, since the observed result will essentially be the same!)

Posted in: Programming, Projects, Robot.

Expelliarmus = Bayes Filter Algorithm

Posted by Erin, the RobotGrrl on Saturday, June 20th, 2009

In the final Harry Potter book, it is mentioned quite often that HP depends on this simple yet extremely functional spell called ‘Expelliarmus’.

I often find myself comparing Expelliarmus in the wizarding world to the Bayes Filter Algorithm in my world. It is such a simple method to give your program a little AI.

Before I go on any further, I just want to say that I didn’t invent the Bayes Filter Algorithm, I found it in this book. It is also said in this powerpoint. Additionally, for good measure, here’s a citation:
The Bayes Filter Algorithm I am using is based on the one in the book Probablistic Robotics. (Thrun, Sebastien, Wolfram Burgard, and Dieter Fox. Probablistic Robotics. Cambridge: The MIT Press, 2006.)
OK, now I think I have all of my bases covered.

So, the Bayes Filter algorithm uses Bayes Law, some initial and conditional probabilities, and the actual probabilities, to give you the final probability.

The first thing that happens is that the prior belief is calculated by adding up the multiplication of the conditional probability table and the initial beliefs.

After that, you add up the multiplication of the probability table and the prior belief.

You then find the normalizer by taking that summation and inversing it.

FINALLY, you can get the final belief when you multiply the normalizer and the number where you multiplied the probability table and the prior belief.

If you want, you can even take it a step further by putting log odds to it based on the final belief and the prior belief.

Here is a class I created in Java (in Processing) that is the Bayes Filter Algorithm:

  1. class BFA {
  2.  
  3.   public int numberOfStates;
  4.   public int numberOfSenses;
  5.   public float[][] probabilityTable;
  6.   public float[] initialBels;
  7.   public float[][][] conditionalProbabilityTable;
  8.  
  9.   BFA(int theNumberOfStates, int theNumberOfSenses, float[][] theProbabilityTable, float[] theInitialBels, float[][][] theConditionalProbabilityTable) {
  10.     numberOfStates = theNumberOfStates;
  11.     numberOfSenses = theNumberOfSenses;
  12.     probabilityTable = theProbabilityTable;
  13.     initialBels = theInitialBels;
  14.     conditionalProbabilityTable = theConditionalProbabilityTable;
  15.   }
  16.  
  17.   public void printProbabilityTable() {
  18.    for(int j=0; j<numberOfSenses; j++) {
  19.     for(int i=0; i<numberOfStates; i++) {
  20.      print("     " + probabilityTable[j][i] + "     ");
  21.     }
  22.     println(" ");
  23.    }
  24.    
  25.    println("\n");
  26.    
  27.    for(int j=0; j<numberOfStates; j++) {
  28.     print("   " + initialBels[j] + "   ");
  29.    }
  30.    
  31.    println("\n");
  32.    
  33.    for(int j=0; j<numberOfStates; j++) {
  34.     for(int i=0; i<numberOfStates; i++) {
  35.      print("     " + conditionalProbabilityTable[0][j][i] + "     ");
  36.     }
  37.     println(" ");
  38.    }
  39.    
  40.    println("\n");
  41.    
  42.   }
  43.  
  44. public float calculateProbability(int theStateQuestioned, int sensorData, boolean logOdds, boolean logData, boolean printThem) {
  45.    
  46.     float priorbel[] = new float[this.numberOfStates+1];
  47.     float multiplier[][] = new float[this.numberOfSenses+1][this.numberOfStates+1];
  48.  
  49.     float tempResult = 0.0;
  50.     float normalizer = 0;
  51.     float summation = 0;
  52.     float logOddsResult;
  53.    
  54.     if(logData) output.println(getTime() + "Entering Bayes Filter Algorithm");
  55.    
  56.     for(int i=0; i<numberOfStates; i++) {
  57.      for(int j=0; j<numberOfStates; j++) {
  58.       tempResult += (conditionalProbabilityTable[0][i][j]*initialBels[j]);
  59.      }
  60.      priorbel[i] = tempResult;
  61.      if(logData) output.println(getTime() + "Prior belief calculated. priorbel[" + i + "]: " + priorbel[i]);
  62.      if(printThem) println("Prior bel[" + i + "]: " + priorbel[i] + " Temp result: " + tempResult);
  63.      tempResult = 0.0;
  64.     }
  65.  
  66.    for(int i=0; i<numberOfStates; i++) {
  67.     multiplier[sensorData][i] = probabilityTable[sensorData][i]*priorbel[i];
  68.     summation += multiplier[sensorData][i];
  69.     if(logData) output.println(getTime() + "Summation and multiplier calculated. Summation: " + summation + " Multiplier: " + multiplier[sensorData][i]);
  70.     if(printThem) println("Summation: " + summation + " Multiplier: " + multiplier[sensorData][i]);
  71.    }
  72.    
  73.    normalizer = pow(summation, -1);
  74.    if(logData) output.println(getTime() + "Normalizer and multiplied together calculated. Normalizer: " + normalizer + " Multiplied together: " + summation*normalizer);
  75.    if(printThem) println("Normalizer: " + normalizer);
  76.    if(printThem) println("Multiplied together: " + summation*normalizer);
  77.    
  78.    float finalProbability = normalizer*multiplier[sensorData][theStateQuestioned];
  79.    float priorProbability = priorbel[theStateQuestioned];
  80.    
  81.    if(logData) output.println(getTime() + "Prior probability calculated. Prior probability: " + priorProbability);
  82.    if(logData) output.println(getTime() + "Final probability calculated. Final probability: " + finalProbability);
  83.    if(printThem) println("Final probability: " + finalProbability);
  84.  
  85.     if(logOdds) {
  86.      logOddsResult = log(finalProbability/(1-finalProbability))-log(priorProbability/(1-priorProbability));
  87.      if(logData) output.println(getTime() + "Log odds probability calculated. Log odds: " + logOddsResult);
  88.      if(logData) output.println(getTime() + "Bayes filter algorithm complete.");
  89.      return logOddsResult; // log base e
  90.     } else {
  91.      if(logData) output.println(getTime() + "Bayes filter algorithm complete.");
  92.      return finalProbability;
  93.     }
  94.    
  95.   }
  96.  
  97.   public void setNumberOfStates(int theNumber) {
  98.    numberOfStates = theNumber;
  99.   }
  100.  
  101.   public int getNumberOfStates() {
  102.    return numberOfStates;
  103.   }
  104.  
  105. }

The Bayes Filter Algorithm is super handy because you can check it by hand. There are no ambiguities introduced into the algorithm. Some of the algorithms, like the Kalman Filter, use covariance in the algorithm to adjust the final belief. This is great, but definitely more tricky to calculate by hand.

I favour the Bayes Filter Algorithm right now because of its ease of use, and it gives me what I want. However, for more interesting results, the Kalman Filter would be a better way to go. If I have time at the end of this project, I’ll probably implement the Kalman Filter and use it instead of the Bayes Filter Algorithm. :D

Posted in: Programming, Projects.

Super Sanguino!

Posted by Erin, the RobotGrrl on Wednesday, December 17th, 2008

I got my Sanguino yesterday night, so it was time to finally delve in and make one of these awesomeness things! PLUS, I get to do a nice blog post about it. :D

I’m happy that I got super shipping… I don’t think I would have received it in time otherwise!

See:


It even comes with bubble wrap! ^_^


Let’s get started :D


The board is really shiny, but it is more of an orangey-red than a red-red. However, it is really catchy. Too bad in the end it is covered by all the components though!


See, look how giant the chip is! Sweet!


It’s time to solder. This is the cleanest the soldering iron has been in a few weeks :D


The SANGUINO silkscreen is easily covered by the DIP…


These capacitors remind me of balloons hehe :D


It doesn’t have a chip on its shoulder… yet (get it? the 648P isn’t in yet hahaha)


This part was sooo confusing. The instructions said… “Insert the LED on the flat side of the board” or something like that. Flat side? I never knew that there was a non-flat side… BAHA!


If the red LED is not entered correctly, nothing will work…


The proper way to insert the LEDs is… negative, positive and negative, positive. It clearly didn’t say that on my silkscreen >_> At least I only got one of them wrong :D


Sooo, after cleaning that LED up… it works! YAY! :D


The software was aggravating to get working, but I did manage to get it to work in the end. I’ll post up my version of the Arduino 12 IDE for Sanguino tomorrow, or something. :)

The number of outputs and inputs is so astonishing! It even has two TX/RX ports. I’ll probably finish off MANOI and Snowplow robot tomorrow, and think of a way to use the Sanguino in MANOI!

It would be cool to have an IR sensor right now for MANOI, so I could mount it on its stick, but instead I may try two LDRs with LEDs. I have the supplies for that, so I can easily implement a Bayes Filter algorithm to determine if the ball is there or not.

The Bayes Filter algorithm is a form of AI. I’ve been working on a tutorial about the BFA for uCHobby.com for a very long time. (TeX takes a long time to type).

Swweeeet!!!!

Posted in: Projects, Robot.