1 / 82

Flight Controller

Flight Controller. James A. Rome Tennessee Governors Academy August 2010. The Goal is to simulate a sector. We will do it in 2-D Unclear if it is easier or harder in 3-D More room versus more computation We will make it as automatic as possible, and then see if we can do as good a job.

liesel
Télécharger la présentation

Flight Controller

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Flight Controller James A. Rome Tennessee Governors Academy August 2010

  2. The Goal is to simulate a sector • We will do it in 2-D • Unclear if it is easier or harder in 3-D • More room versus more computation • We will make it as automatic as possible, and then see if we can do as good a job. • Tasks:

  3. Proposed GUI – My vision Destination Current location Flight trail (Other flights drawn also) Other flights in range Current direction Destination direction

  4. Geometry of collision avoidance • This is the conceptually most difficult part of the problem, so don't let me snow you. • "You" are the red plane trying to see which direction you could go in without interfering with any other flight. • You must check at each future time up to the "look ahead" time, say 10 minutes. • The blue plane is in a hockey puck of 5 nm radius that you cannot enter. • You assume that both planes keep their current speed • The red plane must be somewhere on the concentric circles at each increment of time. • The blue plane moves along the gray path. • So what directions can red go in?

  5. Geometry of collision avoidance For each time, we can project the intersections on the cylinder at the look-ahead time (t = 7).

  6. Geometry of collision avoidance This calculation is complicated, (even for me), so let's go over it slowly. It is really important to draw good pictures to get everything clear in my (your) mind. P2 next slide If d > r0 + r1, no interaction

  7. Vector subtraction Coordinate system origin, x=0, y=0

  8. Use similar triangles to find P3 • Quadrants (wrt North): • 0° ≤ θ < 90° • x3 ≥ x0; y3 > y0 • 90° ≤ θ < 180° • x3 ≥ x0; y3 < y0 • –90° ≤ θ < 0° • x3 ≤ x0; y3 ≥ y0 • –180°< θ < –90° • x3 ≤ x0; y3 < y0 • And also, must keep track • of the part of the arc that is between the P3 points North

  9. What is the result? • The red plane will see all the angles that would hit every other "blue" plane at all times up to the look-ahead time. • Red picks the closest unblocked angle to the straight line to its destination. • At each time step, red can try to get a direction closer to a straight line to its destination. • This method is "failsafe" — If the system dies, it can go for the look-ahead time and be guaranteed of not hitting anyone.

  10. Think about how to compute this • The blue plane always must follow its current path in calculations done by other planes. • Lots of these calculations, so we should calculate, update, and save future points on the current course in Flight • The red plane (figuring out where to go) must do the collision calculation against every other plane, out to the look-ahead time. It automatically does it for all possible directions because it intersects the look-ahead circle with the other plane's course. • Probably do this work in Sector?

  11. There are some gotchas • Time synchronization • You must be sure that you compare two flights at the same time • (I put in some print statements to check and found errors) • The discontinuity in angles looking South • The angle jumps from +180 to -180 • Of course the planes do not see any discontinuity here • I spent a week tracking down a problem with the course panel calculation • All of your comparison methods must work while going across this boundary

  12. Programming uses a lot of recipes • It is like cooking—you know how to make standard parts and put the canned parts together to make a meal • Part of the pleasure/pain is figuring out how to do these things • But you have to always think about whether your basic part really fits the current problem

  13. Now we must implement this model • Need at least 2 classes: • Flight contains information about each flight • Identifier (we will use Color) • Destination on the border • Speed (assumed constant) • Current location • Previous n locations (trail) • Flight needs methods too: • To "self control" • Create a new instance • Calculate a new position • Give heading to destination • Sector contains • List of all flights • Values of metrics • Sector needs methods to • Know when to create a new Flight, # Flights, sector size. • To calculate the best course for each Flight • To provide information to the flight for self control (and to receive back its answer) • To calculate metrics (# collisions, flight density,…)

  14. Start a new FlightController project • Use c:\nbprojects\ as the location for your project • NetBeans creates a fully-functional GUI for you. • It does not do much, but you can run it by clicking the right-facing green arrow. • We will design the GUI later . . .

  15. Get rid of the Progress Bar • We will not need the Progress Bar at the bottom-right of the GUI. • Click it and delete it • In Code view: • Delete the associated code in the Constructor FlightControllerView after the call to initComponents() • Delete the associated variables at the bottom of the class—all that are not in gray except the aboutBox

  16. Java Swing GUI issues • NetBeans lets you design a GUI by using drag-and-drop. • You can drag the components onto their desired locations, and even pin them to other components • But when the user resizes the window, havoc will reign • (Windows dialogs generally do not resize!) • Instead, Java uses Layout Managers • They handle the job of making sure that the components behave properly upon resize

  17. Panels in panels in panels Title Border Except for the controlPanel, ctrPanel, and the neswPanel, these all use a BorderLayout. North West Center East South Notice that sectorPanel and coursePanel are not in the Swing widget list. We make them.

  18. CoursePanel (a JavaBean) • public class CoursePanel extends JPanel { • Sector sec = null; • public CoursePanel (Sector sec) { //the real constructor super(); // This does whatever JPanel does. Must be first this.sec = sec; // We will need to know the Sector } • // To make a Bean, you need a no-argument constructor • public CoursePanel() { super();} • @Override // This allows us to draw in the panel • public void paintComponent(Graphics g) { • super.paintComponent(); • // more to come later • }} We will draw a conflict map in this JPanel

  19. SectorPanel (a JavaBean) • public class SectorPanel extends JPanel { • public SectorPanel() { • super(); • } • @Override // This tells compiler that I am overriding • public void paintComponent(Graphics g) { • super.paintComponent(g); • // Lots more to come … } • } We will draw the flight courses in this JPanel

  20. Now we can add these components • Do this for CoursePanel and SectorPanel: • Right-click the Panel source file, and select Tools, Add to Palette. • Put it into Swing Containers.

  21. Adding new Swing Components • The new components are now in your palette, ready to use just like any other components!

  22. Grid Layout • A Grid Layout splits the container into rows and columns to make equal-size grid cells. • It is just the thing for making the lower N, E, S, W labels • A label can be Left, Right, or Center justified, both horizontally and vertically • The goal is to get the NESW labels equally spaced • 5 Columns works, but 7 might be better • And this scheme will resize automatically as the GUI is resized!

  23. Now try and create the GUI • Open FlightControllerView in Design Mode and start with the outermost containers first. • Rename every component from its default to a name that describes it rather than using a generic name. Right-click it in the Navigator and select Change Variable Name… • If a panel has nothing in it, it can shrink to a line, so drag-and-drop does not work. In that case, add it using the method at top-left. • Right-click containers in the Navigator to set its Layout Manager. • For components inside a container with a Layout Manager, select its location as shown at bottom-left for the East Label.

  24. Run the code • Try running your GUI. Make sure it resizes properly. • Minimize it, maximize it, cover and uncover it.

  25. The problem with graphics . . . • In a Swing application, the event queue is in the GUI part of the code, listening for the user or the OS to make changes • User resizing window, changing a textField, pressing button, clicking mouse • The OS covering, uncovering, minimizing the window • If you do number crunching in the event loop, the GUI will be unresponsive or freeze — a bad user experience • So, we will put all the flight calculations into a separate worker Thread (that can even run on a second CPU of you have one) • How do you communicate the results to the GUI, or get input from the GUI? You cannot call any of the methods in FlightControllerView directly from the worker Thread! • We will need to plot all the flights, their positions and goals, and a depiction of the look-ahead collision algorithm. You cannot be changing these data values while they are being plotted! • We will clone the data and send them to the two paintComponent() methods

  26. Thinking required! (Philosophy) • Programming is like juggling a dozen balls: • In advance you need to decide what each one is • Know when to “throw” and “catch” them • I break the problem into many smaller challenges that I can solve separately. • Despite what some Computer Science departments say (write a test program first), for real problems, you cannot always tell whether the answer will be right. • The challenge is that you have to write a lot of code before it can be fully tested, which means a lot of debugging. • Better thinking = less debugging • If I have a problem, I lie down and think. 5 AM is when my subconscious finds many problems

  27. Class diagram in UML (Useful??)

  28. FlightPosition class • It is useful to create Classes to combine pieces of data that belong together, in analogy to a TZ message: • position, speed, altitude, time • Java has a Point2D,Double class to hold an x,y pair Clone makes a copy of this class NetBeans generates these for you!

  29. FlightPositionComparator • Must tell Java how to order FlightPositions • Will put FlightPositions into TreeSets which are ordered (so we can plot the courses) • Want them ordered by their time • So override the compare() • Extract the two times • Return • <0 if t1 < t2 • 0 if t1 = t2 • > 0 if t1 > t2 • package flightcontroller;import java.util.Comparator; • public class FlightPositionComparator implements Comparator { • /*** Implement compare* @param o1 The first FlightPosition* @param o2 The Second Flight Position* @return*/ • public int compare(Object o1, Object o2) { • int t1 = ((FlightPosition)o1).getSecs(); int t2 = ((FlightPosition)o2).getSecs(); • // <0 if t1 < t2, >0 if t1 > t2 • return t1 - t2; • } • } We did this before in the ZOB48 code

  30. Create the getters and setters • NetBeans does the work for you: • Right-click the Class in the Project Panel • Choose Refactor, and then Encapsulate Fields • Check Select All, and then Refactor • NetBeans creates a public class that gives access to each of the data pieces in our FlightPosition Class • These methods follow the Java Beans naming convention

  31. Flight needs to do a lot • How do we do each of these? • Make a new flight with random start and destination (on different sides of sector) and with random Color • Keep track of its past positions (for plotting) in a TreeSet • Look ahead and store its future course (a TreeSet) because the future track is used by every other flight in the collision algorithm • Keep track of the current time • Calculate the bearing to its goal • Clone itself (for plotting) • TreeSet is a Collection that orders its elements • TreeSet<FlightPosition> ts = new TreeSet<FlightPosition>(FlightPositionComparator); • ts.add(flightPosition); // add element • Iterator<FlightPosition> it = ts.iterator(); // get contents while(it.hasNext()) { // Get FPs in order FlightPosition fp = itr.next();// do stuff with fp. // Remove it if necessary it.remove(); } • ts.descendingIterator(); // reverses order • clone() will have to copy the TreeSets and will have to call clone() for each FlightPosition

  32. The Flight Class Add getters for positions, fltID, goal, speed, course, NewFlight,oldBearing and a setter for fltID and newFlight via Refactor, Encapsulate Fields random goes from 0 to 1 try to save old data

  33. Flight class (continued) Note: Must get a newiterator after removals Check for time sync Add getters and setters for newFlight, fltId;Add getters for speed, positions, goal, course, oldBearing

  34. Flights stored by Sector in HashMap • HashMap must be extended to support clone(); • HashMaps have Keys and Values, for us, Colors and Flights • They are fast ways of retrieving specific data from a large set. • Each Flight has a unique color, so Color is a good Key (must be an Object) • To iterate over the whole set, you retrieve a Set of Keys and iterate • put(K key, V value) Associates the specified value with the specified key and inserts it into this map. • Vget(Object key) Returns the value to which the specified key is mapped • package flightcontroller;// imports go here • public class FlightMap extends HashMap<Color, Flight> { • public FlightMap() {super();} • @Overridepublic FlightMap clone() { FlightMap fm = new FlightMap); Set<Color> keys = this.keySet(); Iterator<Color> itr = keys.iterator(); • while (itr.hasNext()) { Color fid = itr.next(); flightcontroller.Flight flt = (flightcontroller.Flight) this.get(fid); Flight fc = null; fc =(Flight)flt.clone(); fm.put(fid, fc); } return (FlightMap) fm; }}

  35. Sector models & controls everything • Stores and maintains flight list • Listens to user input from the GUI • Stores and maintains the state:initial, running, paused, resume, stop • Determines when Flight exits sector • Determines when Flights collide. • Replaces the expired Flights • Maintains statistics: simulation time, # collisions, average distance from the goal • Controls the Flights a step at a time • Calculates the interference map for each flight at each step • Determines the “best” next direction • Updates the GUI sectorPanel and coursePanel with current data using cloned data, but how? • // Update GUI, but keep goingEventQueue.invokeLater(new Runnable() { public void run() {// Make any calls to FCV fcv.updateMisses(avgMiles); }}); • // Notify GUI of update. // Stop until it is donetry {EventQueue.invokeAndWait(new Runnable() { public void run() {// Make any calls to FCV fcv.updateTime(hms); sectorPanel.recalc(fmMap); }});} catch (InterruptedException ex) {}catch (InvocationTargetException ex) {} • This is why Sector implements Runnable

  36. Sector is a Thread, implements run() • public class Sector extends Thread implements Runnable { • // Constructor goes here • // run keeps looping and does // different things, depending on// stepState, which is updated from// FlightControllerView • public void run() { time = 0; while(true) { switch(stepState) { • case 0: // initialize • stepState = 1; • controlFlights(); • break; • case 1: // run • controlFlights(); • break; • case 2: // Pause • try { // pause while user stares • sleep(1000); // method of Thread • } catch (InterruptedException ex) {;} • break; • case 3: //resume • stepState = 1; • controlFlights(); • break; • case 4: //stop • return; // thread dies upon return • } // End of switch • try { // slow down to see results • Sector.sleep(100); • } catch (InterruptedException ex) { ;} • } // end of while(true) • }

  37. Back to FlightControllerView (FCV) • We need FCV to do something!Right-click the Go button and add an ActionPerformed • private void goButtonActionPerformed(java.awt.event.ActionEvent evt) { • // create the sector. Read and check user input • int nflights = Integer.parseInt(nFlightsTextField.getText()); if(nflights <= 0) nflights = 10; • int size = Integer.parseInt(milesTextField.getText()); • if(size < 50) size = 50; • int lookahead = Integer.parseInt(lookAheadTextField.getText()); • if(currentState == 0) { // Not from pause • sector = new Sector((double)size, nflights, lookahead, sectorPanel, coursePanel, this); • sector.setStepState(1); • sectorPanel.setS(sector); • Thread t = new Thread(sector); • t.start();// start the thread. Calls run() • sector.setStepState(1); • currentState = 1; • } • else { // Resume from a pause sector.setStepState(3); currentState = 1; • } • } • // Add at bottom of class • privateSector sector; • private int currentState = 0;

  38. Add actions for pause and exit • private void exitButtonActionPerformed(java.awt.event.ActionEvent evt) { • sector.setStepState(4); this.getFrame().setVisible(false); • System.exit(0); • } • private void pauseButtonActionPerformed(java.awt.event.ActionEvent evt) { • // resume from pause • if(currentState == 2) { • goButtonActionPerformed(evt); • return; • } • // start a pause sector.setStepState(2); currentState = 2; • } • Other methods to be called by Sector to update the information boxes. Call repaint() to get the GUI to update them (when it gets around to it). • public void updateTime(String time) { • timeTextField.setText(time); • timeTextField.repaint(); • } • public void updateHits(String hits) { • collisionsTextField.setText(hits); • collisionsTextField.repaint(); • } • public void updateMisses(String misses) { • missTextField.setText(misses); • missTextField.repaint(); • } FCV is done!

  39. Trig functions have sheets • Angles goes continuously from –∞ to +∞ • But our headings go from –180º to +180º, about North • The inverse trig functions in Java are defined on a sheet, say – to + • We must always check that we are operating on the correct sheet, and fix this if necessary • Simple testing algorithms can fail N +180 -180 occlusionangle To other plane

  40. Sector.flightInterferences(Flight f) This implements our avoidance algorithm

  41. Sector.flightInterferences(Flight f) • Note how I calculate in angle and use the bin() function to map the angle to the hitAngles array • Start from psideg and work outward • hitAngles goes from 0 (-180) to NANGLES (<+180) • After each loop, the plus angle is increased and the minus angle is decreased, and we check for crossing the cut at 180 • We check for the loop angle being in the same bin as the limit angles, and then stop • (Note: I had screwed this up!)

  42. Sector.flightStep(Flight f) Calls flightInterferences to get hitAngles[ ]. Given hitAngles[ ], what heading to pick? (1-degree resolution only—is that enough?)

  43. Sector.controlFlights() • Loop through the flights • Step each one • Check for exited sector or collided • Add any new flights • Update the SectorPanel using a clone FlightMap

  44. Sector headers and constructors

  45. Sector utility methods Note: It can hang here if youuse too many flights Plus encapsulate fields to create getters for size, fltMap, lookAheadTime, and setters for size, lookAheadTime

  46. FlightInfo combines course plot data • We need to pass information about the current flight to CoursePanel • Most convenient to just make a Class to package them all together Plus, encapsulate all of the 4 fields with getters and setters

  47. Drawing in Java • Java’s draws in pixels with the origin at the top-left. • We draw in real units with the origin at the bottom-left. • We must transformint scalex(double x) { return (int)(x * width/xmax);}int scaley(double y) { return (int)(height – y * height/ymax)} ymax Java x width = panel.getWidth() 0 width Java y JPanel height = panel.getHeight() Real y 0 Real x height xmax Easy checks for a linear transformation • Plug in the extreme values of x and y and see if you get the right answer

  48. CoursePanel methods A Semaphore can be used to adjudicate access to a resource. Here we do not want to change info when the CoursePanel is being repainted, and vice-versa. The code waits until the Semaphore is available. void acquire()  Acquires a permit from this semaphore, blocking until one is available, or the thread is interrupted.

  49. SectorPanel Methods Do not want plotting occurring while the FlightMapis being updated, so use a Semaphore.

  50. The controller works … • In our 2-D space, with fixed speeds, there is not a lot of freedom • We do not want jerky paths or loop-de-loops • We do not want any collisions • How many planes can our Sector handle? What is the best look-ahead time? • But actually, it is amazing that we can control this many flights under so may constraints. Probably better than the real ZOB48 in some ways.

More Related