Event Driven Programming Minus the GUI Plus a Robot
200 likes | 422 Vues
Event Driven Programming Minus the GUI Plus a Robot. By 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.
Event Driven Programming Minus the GUI Plus a Robot
E N D
Presentation Transcript
Event Driven ProgrammingMinus the GUIPlus a Robot By 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
Architecture (part 1) • Lejos library has a class, ‘SensorPort’ • SensorPort.addSensorPortListener( SensorPortListener 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?)
Code sample from Architecture 1 publicstaticvoid main (String[] aArg) { Robot robot = new Robot(); SensorPort.S1. addSensorPortListener(robot); robot.moveForward(); } In Robot: publicvoid 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 publicvoid stateChanged(SensorPort port, int oldValue, int newValue) { //replace with diff values checking in oldValue, newValue//otherwise not very event-drivenif (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 Code public 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); } } }
Architecture 2 code: SensorReader(note: ‘ts’ is a TouchSensor instance) publicvoid 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"); } } }
Architecture 2 code: EventResponder’s run method. Both implement Runnable, an interface allowing them to run in separate Threads.Bonus: What is missing? publicvoid run() { while(true) { RobotEventInt curr = queue.pop(); if (curr.getName().equals( RobotEventInt.FORWARD)) { leftMotor.forward(); rightMotor.forward(); } elseif (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)