Our goal is to allow vehicles to control movement (arcs, lines, and rotates) using data from a variety of sensors. A vehicle must be able to control the distance of travel and change in angle. There are two approaches to this:
There are a multitude of strategies that can be used for move-control feedback. This Wiki page attempts to examine some of these.
In applications using classes higher than just Pilot, the movement requests will always come directly from the PoseController. The PoseController, in turn, can receive paths from the [Path Planner], which is the ultimate builder of path data in our API. For this reason it is worth examining the data produced by a PathPlanner.
Imagine an application in which the user is on vacation in Florida and wants to look out the front window of their home back in Oregon. They have a map of their home (see image below) and are connected to a server via the Internet that controls the robot at home. In this scenario, some obstacles (red) are in the path between the starting pose and the desired final pose. When the vehicle is done moving, it must be facing the front window.
The PathPlanner comes up with a path tailored to different vehicle types. The PathPlanner consults the MoveController class (via the PoseController which has an instance of MoveController) to see which moves are available. The minimum turn radius the robot can achieve is important. The data it produces and passed to PoseController is a series of moves and waypoints that looks like this:
A steering vehicle does not have a tight enough turn a radius to go through the middle path, so the PathPlanner generates path data that looks like this:
The PathPlanner will want to allow for a margin of error so that inaccuracies with vehicle movement and sensors allow it to avoid walls/obstacles. This error should be gettable from sensors and actuators and propagate up the chain to the higher level classes to compute a margin of error to avoid solid objects.
Note: The PathPlanner will likely take a long time to do a space-search in order to find the most efficient path. This precludes it from computing new paths while a vehicle is on the move, unless the application decides to compute a path from some future point in a path that it is driving towards (in other words it won't reach that point before PathPlanner is able to compute that path). I don't think we want to attempt this until we are more comfortable with 1.0 functionality, so for now we should conclude PathPlanner is too slow.
Now that the PathPlanner has given a suggested path to the PoseController, its job is done and PoseController takes over (unless it finds itself in trouble - more on that in the ObstacleDetector section below).
PoseController has no access to Map data, just the proposed path from PathPlanner. It also has access to Pose data via a PoseProvider. It also has an instance of MoveController, which allows it to command the vehicle to make moves.
The basic problem is to allow the vehicle to steer through each of the discrete moves shown in the diagrams above, so that it gets from one point to the next and finally to the end pose. Specific move segments are marked on the diagram above at A and B:
Here are several scenarios for how these two classes (PoseController and MoveController) interact to provide move-feedback control.
With this scheme, the PoseProvider passes a whole move segment to the MoveController. The MoveController attempts to perform virtual line following with the move segment.
Data passed from PoseController to MoveController: current or proposed Move object
This scheme uses Pose-Based Move Control at the MoveController level. Basically the PoseController breaks up each move into a number of waypoints that are closer together. It then passes all these waypoints to the MoveController, and it attempts to steer towards each waypoint in the path. For this to method, the MoveController requires an instance of PoseProvider, which is a radical departure from our previous architecture.
Data passed from PoseController to MoveController: Pose objects (waypoints)
With this scheme the PoseController looks at the current Pose via its PoseProvider, then it looks at the next waypoint, and calculates the Move required to get approximately to the next waypoint. PoseController could update MoveController after an increment of distance (every 10 cm) or an increment of time (every second).
Data passed from PoseController to MoveController: current Move object
This scheme is based on the idea Roger had that path should be controlled only by direction, which in practical terms is dictated by the vehicles steering ratio. Both differential and steering vehicles can use steering ratio, and steering ratio can produce rotates on the spot for differential vehicles. The PoseController monitors Pose using PoseProvider, and as frequently as it can it updates the steering ratio to get it back on track towards the target, perhaps using PID control.
Data passed from PoseController to MoveController: steering ratio value
How does PathPlanner interact with ObstacleDetector? There could be two different actions taken, indicating a sort of yellow alert and red alert mode. PathPlanner passes the path once at the start with all the data to get to the destination (poses and moves). The vehicle starts following the path in green mode, until it encounters something unexpected that wasn't in the map data. Then it goes into yellow alert mode and does some sort of shallow-thinking low level attempt to get around the obstacle and rejoin the previous path. It could wall-follow the obstacle until it rejoins the path on the other side, at which point it goes back to green mode and continues on. If it fails to reconnect with the path and ends up wandering against a barrier in one direction for a long time, it realizes it is screwed and goes to red alert, which means it stops, tells the PathPlanner it needs a new path calculated from the current position (taking into account the previous barrier it encountered) and off it goes to try again.