Date: 2nd of May 2013
Participating group members: Kenneth Baagøe, Morten D. Bech and Thomas Winding
Activity duration: 5 hours
The goal of this lesson is to test the BumperCar example provided by lejOS according to the lesson plan. Furthermore the goal is also to expand upon the BumperCar example, also described in the lesson plan.
We will use the basic robot from the previous lesson and add an ultrasonic sensor and a touch sensor to it. We will then run the BumperCar example and observe how it functions and describe that. Afterwards we will modify the program according to modifications described in the lesson plan and observe how they work.
We added the ultrasonic sensor and the touch sensor to the robot and also added a bumper to increase the detection range of the touch sensor (pictured below).
Running the basic BumperCar example we saw that the robot would back off and turn a bit if the ultrasonic sensor was close to an obstacle and the same thing happened if the touch sensor was pressed. We also tried holding down the touch sensor and this resulted in the robot repeatedly backing off and turning slightly. The same behaviour was observed if we held an object close to the ultrasonic sensor. We did, however, have a slight problem with the ultrasonic sensor detecting even a very low obstacle, so to actually test the functionality of the touch sensor we had to temporarily remove the obstacle detection using the ultrasonic sensor.
Adding the Exit behavior
To add the Exit behavior, described in the lesson plan, we added an additional class in the BumperCar class, aptly named Exit, which, like the other classes, implemented the Behavior interface.
The implementation of the class looked like the following:
We also had to modify the DetectWall behavior as the suppress method was not implemented properly, it simply did nothing. We went about the basic idea of the suppression the same way that it was done in the DriveForward behavior: We added a _suppressed boolean and implemented the suppress() method to set this boolean to true. Furthermore the action() method of the DetectWall behavior did not properly check for suppression either. Thus we also modified the action() method to immediately return from both of the rotate() methods and added a loop that would yield its timeslices until either the rotation was completed or the behavior was suppressed.
Pressing the escape button seems to exit the program immediately, however from a previous lesson we are aware that the ultrasonic has a short delay of about 30ms when pinging, this will, of course, block the entire program and it is most likely because of the delay being relatively short that we are not able to observe it affecting the program.
Functionality of the Arbitrator class
When the triggering condition of the DetectWall behavior is true, the Arbitrator class does not call the takeControl method of the DriveForward behavior. This can be seen in the code snippet below from the Arbitrator class: It starts from the top priority, checking if the takeControl() method returns true, if it does not, it moves on to the second highest priority and so on. If the triggering condition, however, returns true, the method breaks out of the loop as there is no need to check for the lower priorities.
Sampling the ultrasonic sensor in an isolated thread
To alleviate the problem of the ultrasonic sensor delaying the program every time it is sampled, we added the sampling to a thread that would update a variable which the takeControl() method would then evaluate upon.
Further modifying the DetectWall behavior
To make the robot move backwards for one second before turning we employed the same basic principles as when we modified the DetectWall behavior to be able to be suppressed, as described above. We made the robot move backwards until either a second had passed or the behavior was suppressed by way of another loop, see the code below.
We were also asked to try to modify the code to make it possible to interrupt the DetectWall action if the touch sensor was pressed or the ultrasonic sensor detected an object. This interruption should then start the action of the behavior again. We were not able to make this part work, we tried adding a boolean to tell if the action was already running and if it was running, the program would stop the motors and start the action over. Unfortunately we couldn’t come up with a solution for this, however when we implemented motivation, which is described in the next section, the interruption worked without any problems. Again we were not exactly sure why.
To make the robot motivation based we used the Behavior and Arbitrator implementations provided by Ole Caprani. We then changed our modified BumperCar to return integers on the different takeControl() methods instead of booleans. DriveForward was given a low value as it is still a low priority behavior while Exit was given a high value as it should still take precedence over other behaviors. To make DetectWall return a somewhat lower value when it was already active, we added a boolean that was set to true when the action method was run and set to false when the method finished. Thus the takeControl method was able to differentiate between the two states.
We have followed the lesson plan almost to its full extend, the only catch was that we had trouble implementing the DetectWall behaviour so that it could be interrupted while turning if e.g. the touch sensor was activated. However the change to motivation based decision making fixed this problem as we were able to dynamically return higher values if some other action was in progress.