Upload
others
View
10
Download
0
Embed Size (px)
Citation preview
Robo$cs & Autonomous Systems
A Prac'cal Introduc'on with NXT and JAVA
Threads and Behaviours
Michael Wooldridge (mjw @ liv.ac.uk)
Threads on NXT
• More or less impossible to do robot programming without making use of threads
• Threads typically used e.g., to monitor sensors and ensure reac<ve behaviour….
Using Threads: A Case Study
• We will use threads to build a class that con<nually monitors sensors and motors and displays their status on the LCD panel
• The thread to do this will run in the background, allowing us to focus on the main work we want to do
• Threads that run in the background in this way are called daemons
StandardRobot.java
• We first define a class to make our lives a liCle simpler as programmers
• We can reuse this class whenever we use the standard configura<on robot
import lejos.nxt.*;import lejos.nxt.addon.ColorSensorHT;public class StandardRobot { public static ColorSensorHT cs; public static TouchSensor ts; public static UltrasonicSensor us; public static NXTMotor ma, mb; public StandardRobot() {
// instantiate sensorsus = new UltrasonicSensor(SensorPort.S1);cs = new ColorSensorHT(SensorPort.S2);ts = new TouchSensor(SensorPort.S4);
// instantiate motorsma = new NXTMotor(MotorPort.A);
mb = new NXTMotor(MotorPort.B);
}}
Design Decisions
• What happens if we create more than one instance of this class?
• How can we design the code so that this is impossible?
• This is the interface to the robot, rather than a robot itself
• How can we design a StandardRobot class so that it has this code, and allows the user to add their own behaviour…?
RobotMonitor.java
• Now we create our RobotMonitor class
• This will be a daemon that sits in the background, periodically polling sensors & motors and displaying their state on the LCD panel
RobotMonitor.java (part 1) import java.lang.Thread;import java.lang.Boolean;import lejos.nxt.*;public class RobotMonitor extends Thread { private static int delay; private static StandardRobot me;
public RobotMonitor(StandardRobot r, int d) {
this.setDaemon(true); me = r;delay = d;
}
RobotMonitor.java (part 2) public void run() { while(true) { LCD.clear(); LCD.drawString("Color = "+me.cs.getColorID(),0,0); LCD.drawString("Ultra = "+me.us.getRange(), 0,1); LCD.drawString("Touch = "+me.ts.isPressed(), 0,2); LCD.drawString("MotorA = "+me.ma.getPower(), 0,3); LCD.drawString("MotorB = "+me.ma.getPower(), 0,4); try { this.sleep(delay); } catch (Exception e) { ; }
} // end while} // end run} // end class
ProgFive.java import lejos.nxt.*;public class ProgFive { public static void main(String [] args) throws Exception { StandardRobot me = new StandardRobot(); RobotMonitor rm = new RobotMonitor(me,400); me.ma.setPower(100); me.mb.setPower(100); rm.start(); // launch the monitor thread while(me.us.getRange() >= 30) { Thread.sleep(200); } // end while } // end main} // end ProgFive
What ProgFive does
• First creates an instance of StandardRobot, called “me”
• Then creates an instance of RobotMonitor, called “rm”
• Sets the motors running
• Invokes the start() method on the robot monitor
• Loops un<l range to closest object is < 30 cm
Behaviour-‐based Programming
• A standard programming methodology for robo<c applica<ons is behaviour-‐based programming
• Traces its origins to work by Rodney Brooks of MIT in the mid 1980s on subsump'on architecture
Behavior-‐based Programming Methodology
1. Programmer conceives all the task-‐accomplishing behaviors that they want the robot to exhibit
2. Behaviors are developed independently 3. Behaviors are then arranged into a hierarchy,
indica'ng precedence
4. At run-‐<me, behaviors “compete” for control of the robot
• Higher priority behaviors given precedence
Subsump$on Architecture Example: Trash-‐Collec$ng Robot
• Imagine a robot whose task is to travel around an office environment collec<ng and disposing of empty soda cans. Behaviors are:
• Avoid obstacles • Explore • Recognise trash • Pick up trash • Return to base • Empty trash can
Subsump$on Architecture Example: Trash-‐Collec$ng Robot
• At run <me, these behaviors will be interleaved:
• Explore • Explore • Avoid obstacle • Explore • Recognise trash • Pick up trash • …
Behaviors in LEJOS
• LEJOS provides a library to support behavior-‐based development
• Two key components:
• The Behavior interface • The Arbitrator class.
The Behavior Interface
• Each behavior is implemented in its own class, which must implement the Behavior interface • The Behavior interface requires a class to implement three methods:
• boolean takeControl()• void action()• void suppress()
boolean takeControl()
• This method should
• Return VERY QUICKLY – should not perform a <me-‐consuming computa<on
• Return true if the associated behavior should take control of the robot
void action()• This method encodes the actual ac<ons to be carried out if the behavior becomes ac<ve
• Must terminate quickly when the suppress() method is invoked on the behavior
• On termina<on, must leave the robot in a “clean” state
• Typical structure: public void action() { supressed = false; while(!suppressed) { // do something }}
suppressed is boolean variable set in suppress() method
void suppress()
• Should: • Terminate the code running in the action() method
• Terminate VERY quickly
• Typical structure: public void suppress() { suppressed = true;}
The action() method will quit when suppressed is set true
Arbitrators
• To select between behaviors, we use the Arbitrator class
• We pass the Arbitrator constructor an array of behaviors: lowest up to highest priority
• We then run the start() method on the arbitrator object we create
Prog06: Move Forward & Avoid
• Our program will have 2 behaviours, which will be interleaved:
• Forward just moves the robot forward
• Avoid will intervene when an obstacle is detected
Prog06.java
import lejos.nxt.*;import lejos.robotics.subsumption.*;public class Prog06 {
public static void main(String [] args) throws Exception { StandardRobot me = new StandardRobot(); RobotMonitor rm = new RobotMonitor(me,300); rm.start(); Behavior b1 = new ForwardBehavior(me); Behavior b2 = new AvoidBehavior(me); Behavior [] bArray = {b1, b2}; Arbitrator arb = new Arbitrator(bArray); arb.start();}
} // end Prog06
ForwardBehavior.java (part 1 of 2)
import lejos.robotics.subsumption.*;import lejos.nxt.*;public class ForwardBehavior implements Behavior {
public static boolean suppressed;
private static StandardRobot r;
public ForwardBehavior(StandardRobot r1) { r = r1; } public boolean takeControl() { return true; }
ForwardBehavior.java (part 2 of 2)
public void suppress() { suppressed = true; }
public void action() { suppressed = false; r.ma.forward(); r.mb.forward(); r.ma.setPower(100); r.mb.setPower(100); while(!suppressed) { try { Thread.sleep(200); } catch (Exception e) { ; } } }
} // end class
AvoidBehavior.java (part 1 of 2)
import lejos.robotics.subsumption.*;import lejos.nxt.*;public class AvoidBehavior implements Behavior {
public static boolean suppressed; private static StandardRobot r; public AvoidBehavior(StandardRobot r1) { r = r1; } public boolean takeControl() { return (r.ts.isPressed() || (r.us.getRange() < 10)); }