lejos.robotics.subsumption.Arbitrator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lejos-ev3-api Show documentation
Show all versions of lejos-ev3-api Show documentation
leJOS (pronounced like the Spanish word "lejos" for "far") is a tiny Java Virtual Machine. In 2013 it was ported to the LEGO EV3 brick.
The newest version!
package lejos.robotics.subsumption;
/**
*An Arbitrator object manages a behavior control system by starting and stopping individual behaviors
*
by the calling the action()
and suppress()
methods on them.
*
These Behavior objects are stored in an array, in order of increasing priority.
*
Arbitrator has three major responsibilities:
* 1. Determine the highest priority behavior among those that returns true to takeControl()
.
* 2. Suppress the active behavior if its priority is less than highest
* priority. These two taska are performed the Arbitrator's internal Monitor thread.
* 3. When the action()
method exits, call action()
on the Behavior of highest priority.
* This task is performed by the Arbitrator main thread.
*
The Arbitrator assumes that a Behavior is no longer active when action()
exits,
*
therefore it will only call suppress()
on the active Behavior i.e. whose action()
method is running.
*
It can make consecutive calls of action()
on the same Behavior.
*
Requirements for a Behavior:
*
When suppress()
is called, terminate action()
immediately.
*
When action()
exits, the robot is in a safe state (e.g. motors stopped)
*
When the behavior should take control, the takeControl()
should continue to return true
*
until its action starts.
*
After your code instantiates the Arbitrator, it should call go()
to start it running.
*
* @see Behavior
* @author Roger Glassey
*/
public class Arbitrator
{
private final int NONE = -1;
private Behavior[] _behavior;
// highest priority behavior that wants control ; set by start() used by monitor
private int _highestPriority = NONE;
private int _active = NONE; // active behavior; set by monitor, used by start();
private boolean _returnWhenInactive;
public boolean keepRunning = true;
/**
* Monitor is an inner class. It polls the behavior array to find the behavior of hightst
* priority. If higher than the active behavior, it calls active.suppress()
*/
private Monitor monitor;
/**
* Allocates an Arbitrator object and initializes it with an array of
* Behavior objects. The index of a behavior in this array is its priority level, so
* the behavior of the largest index has the highest the priority level.
* The behaviors in an Arbitrator can not
* be changed once the arbitrator is initialized.
* NOTE: Once the Arbitrator is initialized, the method go() must be
* called to begin the arbitration.
* @param behaviorList an array of Behavior objects.
* @param returnWhenInactive if true, the go() method returns when no Behavior is active.
*/
public Arbitrator(Behavior[] behaviorList, boolean returnWhenInactive)
{
_behavior = behaviorList;
_returnWhenInactive = returnWhenInactive;
monitor = new Monitor();
monitor.setDaemon(true);
System.out.println("Arbitrator created");
}
/**
* Same as Arbitrator(behaviorList, false) Arbitrator start() never exits
* @param behaviorList An array of Behavior objects.
*/
public Arbitrator(Behavior[] behaviorList)
{
this(behaviorList, false);
}
/**
* This method starts the arbitration of Behaviors and runs an endless loop.
* Note: Arbitrator does not run in a separate thread. The go()
* method will not return unless
1. no action()
method is running and
*
2. no behavior takeControl()
returns true and
*
3. the returnWhenInacative flag is true,
*/
public void go()
{
monitor.start();
while (_highestPriority == NONE)
{
Thread.yield();//wait for some behavior to take control
}
while (true)
{
synchronized (monitor)
{
if (_highestPriority > NONE)
{
_active = _highestPriority;
}
else if (_returnWhenInactive)
{// no behavior wants to run
monitor.more = false;//9 shut down monitor thread
return;
}
}// monitor released before action is called
if (_active != NONE) //_highestPrioirty could be NONE
{
_behavior[_active].action();
_active = NONE; // no active behavior at the moment
}
Thread.yield();
}
}
public void stop() {
keepRunning = false;
}
/**
* Finds the highest priority behavior that returns true to takeControl()
;
* If this priority is higher than the active behavior, it calls active.suppress().
*/
private class Monitor extends Thread
{
boolean more = true;
int maxPriority = _behavior.length - 1;
public void run()
{
while (keepRunning)
{
//FIND HIGHEST PRIORITY BEHAVIOR THAT WANTS CONTROL
synchronized (this)
{
_highestPriority = NONE; // -1
for (int i = maxPriority; i > _active; i--) // only behaviors with higher priority are interesting
{
if (_behavior[i].takeControl())
{
_highestPriority = i;
break;
}
}
int active = _active; // local copy in case _active is set to NONE by the primary thread
if (_active != NONE && _highestPriority > _active)
{
_behavior[active].suppress();
}
}// end synchronize block - main thread can run now
Thread.yield();
}
}
}
}