LMICSE: Lego Mindstorms in Computer Science Education

Site Map | Contact Us
Project Overview | Staff | Grant Information
Short Workshops | Primary Workshops
CS 1 | Data Str. & Algo. | Prog. Languages | Architecture | Intelligent Sys. | Operating Sys. | Net-centric
Ada | C | C++ | Java | Lisp

Subsumption Architecture

small logo

Defining and Using Behaviors and an Arbitrator

Subsumption architecture is a form of robot control in which the control is divided into layers corresponding to levels of behavior. The idea of subsumption is that not only do more complex layers depend on lower, more reactive levels, but that they could also influence their behavior.

Within subsumption architecture, the controlling structure is an arbitrator. The arbitrator looks through a list of behaviors, and depending on the current conditions, will fire off a certain behavior.

Behavior generally refers to the actions or reactions of an object or organism, usually in relation to the environment or surrounding world of stimuli. In our case, we are going to want to have behaviors that fire depending on information that we receive in from our sensors. Therefore, we can brake down our behaviors into two parts, the conditions that determine whether or not to fire a certain behavior, and the actions to take if those conditions are satisfied.

Prerequisite Knowledge

How to manipulate the robot and how to program it using Java.

Materials

The robot, but it should be rebuilt so that the center of gravity is as much over the center of the axle as possible. You will also want to install both bump sensors, as well as the light sensor on your bot. For optimum performance, try and install your light sensor so that it is as close to the center of rotation on the bot as possible.

Arbitrator

You need to create a class called Arbitrator with a constructor and a method. The first method, a constructor, should receive in and initialize an array of behaviors. The second method, a run method, should repeatedly cycle through the array of behaviors, checking each behavior to see if it should fire.

Declaring and Defining Behaviors - Wander

Now lets start to build some behaviors that we want our bot to perform. Your behaviors should include two methods, one that checks some conditions to see if this behavior should fire, and one that performs the desired actions for that behavior. We'll provide you with a behavior interface so that all you have to do is copy the file into your project folder, and then create classes which implement this interface. We'll also provide you with a skeleton behavior class called wander where all you have to do is write the code so that the bot will wander aimlessly about in its environment. This means that it should move about and at random points in time, it will perform random turns. You should notice in the takeControl() method in our wander behavior that it is set to return true every time. We want to return true every time we get to the wander behavior because it is the default behavior, this is the behavior that we want to fire off if no other behaviors are fired.

When creating your behaviors, keep in mind that it is important to make our actions consume as little time as possible. The more time that our action methods take, the more we're absent from our arbitrator. If we keep our actions short and quick, then we can get back to the arbitrator quickly and start checking our environment conditions again. However, if our actions take a relatively long amount of time to complete, then in the time that it takes to complete our actions, our conditions may change in that they require a different behavior to fire off, but because we're still performing our current behavior, the next behavior may be delayed or not fire at all.

So we've got an arbitrator and a behavior, we can now run our bot. All we have left to do is initialize our behavior, build an array of behaviors (right now we only have one behavior, but you'll need to put it into an array so that we can pass it to our arbitrator), initialize our arbitrator, and then tell our arbitrator to run.

Hint: To make the bot perform random turns at random times, you could create some random number with a limit and then check that random number to some number with in the limit. If they are the same then make the bot turn, otherwise turn the motors on forward. By wandering through this process, our bot's actions are truly random. As a suggestion, you may want to make the limit of your random number fairly high because the arbitrator will be cycling through the behaviors very quickly.

Behaviors - Avoid

Ok, so our bot isn't all that exciting right now, it basically just runs around like a chicken with its head cut off, completely ignoring the world around it. So lets implement an avoid behavior that looks at the bump sensors. If either bump sensor is pressed, the bot will back up and turn away from the obstacle. This means that the takeControl() method for our avoid behavior will check the sensors, and our action() method will adjust the bot according to which bump sensor was hit.

With multiple behaviors, it is now important that we order them correctly in our behavior array. For example, we do not want to check the conditions for our default behavior first, because it always returns true (always fires). Therefore, we'll want to order our behavior array so that the behaviors with the highest priority are first, and lower priority behaviors follow (our default behavior). This way, when our arbitrator cycles through our behaviors, checking each one if the conditions are right for it to fire, it checks those behaviors which are least likely to fire first. Keep this in mind as we add more behaviors.

Behaviors - Feed

Next, lets take our bot one step further; lets make it seem a bit more intelligent than something that just runs around and bumps off walls. Lets design a behavior that uses the light sensor to check and see if our bot is over a food source (a spot in our environment). Once it finds a food source, our bot should stop and 'feed' for 3 seconds, and then continue on its merry way. However, once our bot is back on its way, it should ignore all other food sources that it encounters until at least 5 seconds after the last time that it 'ate.'

Although this behavior seems easy to implement, it is actually fairly tricky. In this behavior, we have to initialize and activate the light sensor (so we'll need a constructor). We also have to keep some sort of time. This entails keeping a global variable within the class that contains some number (the time when we either started eating, or the last time we finished eating). You will also want to use a 'flag' (boolean) that corresponds to whether or not the bot is currently feeding.

Some Additional Problems

Experiment with building other behaviors such as:

  • a behavior that keeps track of locations where the bot has found food and goes directly to the nearest food source if it hasn't eaten in a while
  • any other behaviors that you can think of that may make our bot seem more 'intelligent'

Conclusion

In this lab, you learned the following:

  • How to implement interfaces.
  • How to use the light sensor.
  • How to build a structure which continuously checks the environment and responds accordingly.