This page describes a mechanism for passing Waypoint information from the PathPlanner to the PoseController queue. The description starts with the WaypointListener interface, then describes the methods needed to accept Waypoints into a PoseController queue, then an explanation for the internal code of PathPlanner and finally a code example of how this would look for the user application level. There are also many utility methods we could enhance these classes with.
The overall goal of this proposal is to make the PathPlanner less of a controller and more of a provider/reporter in a consultant role (similar to Google Maps), while still allowing the option of allowing the PathPlanner to take control of the PoseController (e.g. SLAM) and give it a limited number of moves at a time, and erase/retry a path if required (the queuing mechanism).
The methods for WaypointListener are:
Multiple listeners are allowed. In a typical example, the first listener is a PoseController which adds waypoints to its own queue. A second listener is a GUI that displays the path realtime as it becomes available.
Lawrie, Roger and Brian expressed a desire to retain the basic goTo(destination) functionality of PoseController which allows it to operate independent of a PathPlanner. However, is it okay if the PoseController API and internal code reference a PathPlanner object?
There is one basic method for the PathPlanner interface called addWaypointListener() to work with the listener interface. There can be two variations of this method in the API. Also I believe we should expand this (see Utility Methods below). For now, the variations of this method are:
Some implementations of PathPlanner, such as SLAM, will need to interact with the PoseController doing things such as clearing the queue and remaking paths, and interacting with ObstacleDetectors. The SLAMPathPlanner implementation will likely accept a PoseController in the constructor, but it will not require any special methods in the PathPlanner interface to deal with this (it is done internally). Most PathPlanners will only require Map data, a start pose, and a destination in the constructor.
With the two methods described above, when the PathPlanner is asked by the application to generate a path, and then before it completes it is asked to generate another path, it seems like it could get confused:
addWaypointListener(WaypointListener, start1, destination1); addWaypointListener(WaypointListener, start2, destination2);
How should it behave?
immediately stop generating the previous path and start working on the newest one
return false to indicate it is currently busy
* start a new thread each time and only send waypoints to the listener object provided by that particular method call (this makes it ambiguous which set of waypoints to send to listeners that don't specify a particular start and destination)
Or we could try an alternate API with these methods:
This is a style decision.
MoveController pilot = new DifferentialMoveController(..); PoseProvider locator = new MCLPoseProvider(..); PoseController navigator = new PoseController(pilot, locator); PathPlanner planner = new MapPathPlanner(..); navigator.goTo(destination, planner);
NOTE: We could add an alternate constructor in PoseController that accepts a PathPlanner, and then the PoseController is bound with it for all moves that are asked via PoseController.goTo(destination). This would eliminate the need for PoseController.goTo(destination, PathPlanner):
MoveController pilot = new DifferentialMoveController(..); PoseProvider locator = new MCLPoseProvider(..); PathPlanner planner = new MapPathPlanner(..); PoseController navigator = new PoseController(pilot, locator, planner); // Alternate constructor navigator.goTo(destination);
This is largely an API style decision.
Some of these utility methods will be needed, others are optional.
These helper methods allow users to use PathPlanner similar to Google maps (consultant only). This means applications can do things such as get the entire route, display it in a GUI, play around with the waypoints, then feed it to the PoseController:
MoveController pilot = new DifferentialMoveController(..); PoseProvider locator = new MCLPoseProvider(..); PoseController navigator = new PoseController(pilot, locator); PathPlanner planner = new MapPathPlanner(..); path = planner.getPath(start, destination) // Application displays waypoints on GUI: gui.drawWaypoints(path); // GUI allows user to tailor waypoints in path // When done user clicks "Go" button: path = gui.getPath(); navigator.addPath(path);
This is the basic outline of how this could work but it is not a complete or final architecture. All method and even class names are provisional, to be finalized later.
I'm a little worried this over-complicates the architecture. However, as the code above shows, the actual listener interface is not really used by users. Most of the complexity is on the developer end (us) and not the user end, which is a plus.