Our on-board computer runs Debian GNU/Linux. Onboard storage is all vibration resistant flash memory, decreasing power consumption and increasing speed.
The software architecture is built in three broad layers. The shared memory architecture based on existing Linux code stores all of the vehicle's status data (sensor readings, thruster commands, etc). The next layer of code interacts solely through this shared memory.
At the hardware end, serial drivers interact with the various peripheral electronics like sensors and thrusters. Data from these devices are written to shared memory, and outgoing commands to those devices are read from shared memory. This simple interface allows code reuse and simplifies the process of writing drivers.
Vehicle Abstraction Layer
The vehicle abstraction layer builds a Python language wrapper around all of the shared variables, creating an abstract ''Vehicle'' object in Python. This Vehicle not only has access to physical sensors which write data to shared memory, but can also create virtual hybrid sensors that combine data from multiple real or simulated sources. This feature allows us to create a new virtual sensor like ''water depth'' by combining data from the real depth and altitude sensor. It also allows mission code to be tested using data from a simulator which writes data to virtual sensors.
The vision system is written in C++ and uses the opencv vision processing library. The system is designed such that separate daemons are used for each of the mission tasks. The mission activates daemons when it needs data from them. The vision daemons first preprocess the images by color to highlight potential object and then use contour finding. The contour finding assigns a probability to be used by the mission.
The buoy finding code locates the center of mass of the orange pixels in frame. It keys off of size to determine when the vehicle has reached the buoy.
The bin finding algorithm preprocesses the image by looking for and isolating black areas. It then creates a contour of that area and compares the size, shape and aspect ratio to determine if the contour is indeed a bin.
Suits are recognized by first identifying red in the image. Contours are then created and run through a series of comparisons to see how well they match the suits. Contours that are too small or oddly shaped or intersect the edge are ignored.
The safe is found by looking for large areas of orange and then homing in on their center of mass.
Vents are found by locating the yellow bands around the front or back edge. Once the vehicle is inside the vent, it follows the yellow line down the center.
In order to identify pipelines along the bottom of the pool, an image is first segmented by orange and then eroded and dilated to remove small features. The processed images are then run through contour processing to determine if any of the collections of pixels resemble pipe by checking each contour for size, aspect ratio and rectangularity. If it finds something that might be a pipe, it records the heading and aspect ratio.
The mission planner is built upon two subsystems: a ‘planner’ and a ‘task’ subsystem. The planner schedules everything from ‘task’ blocks. Each task can encapsulate subtasks which must be completed for the objective to be complete. This structure allows for incredibly rich, dynamic missions to be written quickly, with the planner system taking care of many of the details that would have had to been encoded in a more procedural system. The mission planner is a tree-walking, multithreaded program, written in Python due to the complexity of the planner and ease of coding in Python. The planner instantiates each element of the user-given task list, allows the tasks to add sub-tasks, and executes these subtasks when their turn is up. The planner is always running in the background, ready to cull completed tasks and notify tasks further down the line that it’s their turn to run. The planner also makes sure ‘exclusive’ tasks, such as movement primitives, only run one-ata-time. Each task is allowed to give the planner a list of “dependencies”, which are simply aliases to shared variables. The planner monitors the requested lists of shared variables in separate threads, and notifies the tasks to run when their “dependencies” change.
For vehicle perspective videos of practice runs, vist our Underwater Video page.