Wednesday 24 November 2010

Behavioural Therapy

Starting up:
Participants: Johan & Jakob
Date: 18/11-2010
Duration: 6 Hours
Goal: Investigate how LeJOS NXJ implements a behaviour-based architecture with the subsumption API, with specific focus on the the interface lejos.subsumption.Behaviour and the class lejos.subsumption.Arbitrator.
Plan: This weeks programming exercise differs from the previous weeks, by having a very specific set of tasks.
We intend to solve these individual exercises and investigate further using a recent checkout of the LeJOS sourcecode.


Experiments:

Getting BumperCar running on the NXT was a trivial task and afterwards we were able to conduct the following experiments. 


Keeping the touch sensor held in:
When the touch sensor is pressed the DetectWall behaviour takes control and the robot turns to avoid the object. When the sensor button is kept down (or the sound sensor detects something close) the behaviours' takeControl() method continuously returns true thereby making the robot turn around itself over and over.
We must make note here that we were extremely confused at first at the robots behaviour, until we noted that the UltraSonic sensor was attached and had an influence on the actual behavior of the robot.


Properties of the Arbitrator regarding the running of takeControl() methods
As is seen in [2:line 121 through 129] the Arbitrator uses a for loop to select which behaviour will gain control by having its action() method called.
The arbitrator runs through its behaviour list from highest to lowest priority. When a behaviours' takeControl() method returns true, that behavior assumes control and the loop breaks. This means that as long as the DetectWall behaviours' takeControl() method returns true (meaning that the touch sensor is pressed or the SoundSensor detects an obstacle), the takeControl method of the behaviour DriveForward is never run.
This holds true for any ordering of any number of behaviours, the takeControl() methods of the lower priority behaviours will never be run when a higher priority behaviour becomes active.


Adding a behaviour to enable exit by keypress
In [1] we have added a behaviour called Exit that contains a takeControl() method that returns true on keypress and an action() method that exits the system.
This Behaviour can be seen below.



class Exit implements Behavior {
    public boolean takeControl() {
return Button.ESCAPE.isPressed();
    }
    public void suppress() {
//The behavior kills the program so if activated suppress wont matter.
    }
    public void action() {
System.exit(0);
    }
}

A suppress method is deemed unnecessary as the action method unconditionally terminates the program.
When the ESCAPE buttons pressed while the DriveForward behavior is active the program shuts down instantly due to the fact that the DriveForward behavior does not block the program. When the ESCAPE button is pressed the DriveForward behavior is suppressed and the Exit behavior kills the program. 


The DetectWall behavior is forced to block the program in order to assure that its motor rotation calls are not overwritten by the DriveForward behavior. This causes a delay when pressing the ESCAPE button, as the behavior guarantees a correct rotation before yielding control.


The Sound.pause(int x) call in the takeControl() method of the behavior DetectWall makes the entire behavior selection in the arbitrator slower by x-milliseconds because the loop cannot continue until the takeControl() method returns a boolean. This restricts the number of behavior changes possible each minute and makes the robot less responsive since the value the sensors return are only relevant immediately after the Sound.pause(int x) call. This also makes the Exit behavior less responsive since it has to wait for the next behavior selection loop before being able to execute. This can potentially also result in loss of input, for instance if the ESCAPE button is pressed while the takeControl() method of the behaviour DetectWall is running.
When the input of sound.pause() was increased to 2000 ms the robots behaviour became almost useless.
Each time the arbitrator tried to select an active thread there now was a blocking call lasting 2 seconds.
This of course results in a very unresponsive behaviour as the entire system is locked up while waiting for the loop to check for the data.


Using a local thread to avoid blocking call
We now implemented a thread in the behaviour detectWall to be able to continuously optain values from the sensor without blocking the system. This can be seen in [1].
This eliminated the need for the sound.pause(20) in the takeControl behaviour and should thusly make the Arbitrator run more smoothly. The 20 miliseconds is such a small value though, and we did not see any noticable effect from this change. 
Regarding this question we noticed something interesting, in [ref til bumpercar fra nyeste lejos checkout ), that is, the bumperCar example taken from the developer repository via svn, the call sound.pause(20) is commented out.
We also tried this approach and noted no difference in behaviour. Why the line is commented out rather than removed is anyones guess.


Backing up for a full second, before turning
For this rather uninspired exercise we utilized Sound.paused(1000) to wait a second while backing up before turning.


Interrupting a running behaviour
This part of the exercise regards restarting a running behaviour due to the same condition triggered, as caused the  action to run in the first place. This caused us quite a bit of trouble figuring this out, as the question asks us to implement the behaviour Detectwall in such a way that it can be interrupted and reset by the Arbitrator. This assumes that the Arbitrator runs the takeControl() method of the behaviour, get a true value as return value, and there suppresses the current Behaviour and calls the action() method of the new intended behaviour, but as can be seen in [2], the new behaviour only gets to run if it has a strictly higher priority than that of the active behaviour, and as such our Arbitrator model does not support the implementation of such a Behaviour.


Motivation functions:


First it must be noted that the behaviour framework as described in [4] is not suitable for this task, similarly to the last exercise, a behaviour based system is best geared towards an interaction model where you can interchange the different behaviours at any given time, disregarding the state the current behaviour is in at the time of switch.
Nothing more than the suppress call should be needed to make it possible for a smooth transition.


If the touch sensor is pressed again while turning it would still not make sense to reactivate the action. Since the rotation hasn't completed we do not know whether the direction the robot will be pointing after the turn is towards the object which it pressed against or if it is pointing in a completely different direction and therefore does not need further turning. Another action dictating backing off a little before completing the turn might be more suitable.


Let the integer range 0-100 define our motivation values where 0 is the least motivating and 100 the most motivating. We would obviously reserve the Exit behavior to be the most important and it is therefore the only behavior which is allowed to use motivation 100 (since we don't want to wait for our robot to exit.) If we then look at our takeControl methods we would then have them return an integer which represents the importance of the behavior based on the situation. Meaning that if our touch sensor registers an input it is important to start turning and if it doesn't it is very unimportant, returning a high and low motivation respectively. The driving forward behavior would then return an average integer, so it can both be overwritten and seize control easily.



Conclusions and further work:
From this labsession we have gotten the knowledge that Behaviour based models isn't fit for every task in robotics.
Some of the exercises left us trying to figure out how to make the screw work with the hammer, which wasn't an easy task.
In the future, more time could be spent actually trying to implement the integer returning takeControl() methods with a new Behaviour interface, and an Arbitrator that would be able to handle these return values.
This would allow for a significantly more dynamic Behaviour selection.

References:
  1. http://daimi.au.dk/~fx/dLego/BumperCar.java - The modified BumperCar.java
  2. http://daimi.au.dk/~fx/dLego/Arbitrator.java  - The Arbitrator.java from developer checkout of LeJOS source
  3. http://daimi.au.dk/~fx/dLego/Behaviour.java - The Behaviour.java from developer checkout of LeJOS source
  4. http://legolab.daimi.au.dk/DigitalControl.dir/Krink.pdf

No comments:

Post a Comment