event driven programming minus the gui plus a robot by charlie vick
TRANSCRIPT
Event Driven ProgrammingMinus the GUIPlus a RobotBy Charlie Vick
Why Event-Driven Robotics?
• This robot consists of sensors and motors.• Event driven programming decouples sensor
monitoring and motor controlling. Different classes specialize, compartmentalizing the hardware.
• Can more easily switch out sensors or motors, as long as everyone can use the same event system and events.
Robot Gear
• Hardware: Lego Mindstorm NXT - servos, sensors and an ARM processor
• Software: open-source 3rd party firmware called leJOS, which runs compiled Java bytecode
The old bot configuration
Current bot configuration
QuickTime™ and a decompressor
are needed to see this picture.
Architecture (part 1)
• Lejos library has a class, ‘SensorPort’• SensorPort.addSensorPortListener( Se
nsorPortListener aListener) is a public method
• SensorPortListener: Interface, has one method:void stateChanged(SensorPort source, int oldValue, int newValue)
This seemed a real coup
• leJOS looked to be designed for event-driven programming
• Wire up SensorPortListeners to a few sensors, have each steer in different ways when triggered
Problem
• API Documentation out of date. Forum search revealed SensorPortListener was deprecated for most sensors.
• Only works on one sensor I have, touch.
• Doesn’t actually work.
Program Architecture (part 2)
• Slightly more complex.
• One class, SensorReader, iterates through a couple of sensors. If certain values are hit, fire a certain event.
• Another class, EventHandler, receives these events and changes the motors accordingly.
How do these classes communicate?
• Each runs on its own thread. • They pass messages over a shared,
synchronized queue.• This means events are handled approximately
in the order created, barring synchronization issues
(Bonus: What is a better / more granular / more responsive data structure than a regular queue, given events with different priorities?)
DIAGRAM
QuickTime™ and a decompressor
are needed to see this picture.
public static void main (String[] aArg) { Robot robot = new Robot(); SensorPort.S1. addSensorPortListener(robot); robot.moveForward();}
In Robot:public void moveForward() { Motor.A.setSpeed(20); Motor.B.setSpeed(20); while (!ts.isPressed()) { //ts instanceof TouchSensor Motor.A.forward(); Motor.B.forward(); } } //bonus - what part is NOT very event-driven here?
Code sample from Architecture 1
Code sample from Architecture 1 public void stateChanged(SensorPort port, int oldValue, int newValue)
{ //replace with diff values checking in oldValue, newValue //otherwise not very event-driven if (oldValue < 500 && newValue < 500) { Motor.A.stop();
Motor.B.stop(); Motor.A.setSpeed(20); Motor.B.setSpeed(20); Motor.A.backward(); Motor.B.backward(); Thread.sleep(100); Motor.A.stop(); Motor.B.stop(); Motor.A.forward(); Motor.B.backward(); Thread.sleep(250); Motor.A.stop(); Motor.B.stop(); moveForward(); }
Architecture 2 Codepublic class SynchronizedQueue<E> {
private final ArrayList<E> queue;public void push(E o) {
synchronized(queue) {queue.add(o);queue.notify();
} }public E pop() {
synchronized(queue) {while (queue.isEmpty()) {
queue.wait(); } return queue.remove(0);
} }
}
public void run() {while (true) {
if(ts.isPressed()) {queue.push(new RobotEvent(
RobotEventInt.BACKUP));} else {
queue.push(new RobotEvent( RobotEventInt.FORWARD));
}
try {Thread.sleep(200);
} catch (InterruptedException e) {System.out.println("Sensor interrupted");
}}
}
public void run() {while(true) {
RobotEventInt curr = queue.pop();if (curr.getName().equals(
RobotEventInt.FORWARD)) {
leftMotor.forward();rightMotor.forward();
} else if (curr.getName().equals( RobotEventInt.BACKUP))
{if (!leftMotor.isStopped() &&
!rightMotor.isStopped()) {
leftMotor.stop();rightMotor.stop();
}leftMotor.backward();rightMotor.backward();Thread.sleep(40);
}}
}
Interface Runnable
• One method:
public void run() {}
Add a Runnable implementor to a Thread, run Thread.start(), and the code in run() executes asynchronously.
RobotEvent
• Implements RobotEventInt, a collection of static String values (RobotEventInt.BACKUP) and one method, getName(), which should always be one of RobotEventInt’s static String values.
Architecture 2 Working Yet?
• Still working at it. Robot throws an error that indicates not all classes loaded, which print statements don’t seem to verify. Runs fine until queue.pop() in EventResponder.
Lessons Learned
• If you learn about deprecated classes in a library from an online forum and NOT from the library’s API, try to switch libraries.
• (Also, if you shutdown and accidentally suspend an Ubuntu laptop and then power-cycle it, some perfect storm wipes out /sys and some of /sbin)
• (On a related note, Dropbox is great for backing up your work)