Main Page | Modules | Namespace List | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

Introduction and Philosophy

The goal of the ModUtils package is to ease development and maximize code reuse in robotic software systems. ModUtils is not an architecture, i.e., it is not a particular specification of data flows and protocols that solves a particular set of robotic tasks, but rather it is a meta-architectural toolkit. It contains utilities for building almost any particular architecture, but, more importantly, these utilities encapsulate a methodology for building many different kinds of robotic architectures while supporting the straightforward reuse of code between these diverse architectures. In addition, the utilities have been tweaked and tuned over a long period of time to address the real world problems involved in building, running, debugging, and maintaining real world, real-time robotic systems.

What is an architecture?

Since the ModUtils package is a "meta-architectural" toolkit, a key question that must be answered is "what is an architecture?" Unfortunately, for a word that is used so commonly, it means different things to different people. There is a sense in which the definition of architecture is the same as the definition of pornography: "I know one when I see it."

Architectures as Blueprints

One use of the word architecture is as the software blueprint for the system. All the relevant robotic experts, sponsors, and customers sit down in a room, determine the task requirements and work plans. We all work hard drawing multiple diagrams with bubbles and arrows showing all of the modules and their gozintas and their gozoutas. We then plan to use this as a framework for collaboration for the next 5 years.

In this usage, a software architecture is directly analogous to the blueprint of a house. Unfortunately, robotic system development is not house building.

A Short Parable.

We all get together and define the blue print of our house:

Back To Reality.

We find when we actually build robot systems that,

Architectures as Grand Ontologies

Another approach to architectures is the establishment of a grand classification system or ontology under a single unifying philosophy. The goal is to decompose all possible problems in robotics into a consistent classification framework. The idea is that if we know all the slots in our ontological system, and we know which slots all modules go into, we should be able to standardize and formalize the relationships between modules in such a way as to make developing and integrating new robotic systems fairly straightforward.

A tendency in this approach is to overreach, i.e., to assume that "my architecture is the architecture for robotics" when in fact it turns out that "my architecture is the approach for the type of robots I want to build".

This reflects a tension in any of these "grand theory" approaches to robot architectures between specificity and efficacy. The more general a grand theory is, the less useful it tends to be in building any particular robot. In general, the narrower the class of tasks that the architecture addresses, the more useful the architecture is within that domain.

Inevitably, algorithm developers find they must move their code from one grand architecture to another for any of a variety of reasons ranging from the inadequacy of the grand architecture for a specific task or simply the funding agent demands it. The toolkits used by any grand architecture are designed to be used pervasively under the assumption that no other architecture exists, and thus it can be somewhat difficult to move just an algorithm from one grand architecture to another.

Holy Grail: Standards

All approaches to architectures have as their holy grail the idea of establishing long lasting, pervasive standards as the underlying mechanism for allowing massive code reuse. Blueprint architectures attempt to standardize over the life span of a project, while grand unified theory architectures attempt to establish standards over the whole space of robotic tasks.

So far, this has not panned out in robotics. Robotic modules and architectures are in serious flux as research is continually done on them, and the range of tasks that robots are given, from bumbling about in beige corridors at 1 mph to ripping along cross country trails at 50 mph, is so wide that it has been extremely difficult to come up with a standard set of components, infrastructure, or data flow that is widely applicable or accepted. Thus robotic systems have tended to be one-off productions, or, at best, productions where code reuse is limited to within the group doing the work. As the field of robotics matures, the hope is that we will have a stable, tested set of components and architectures (not just one grand architecture) that will span the useful set of robotic tasks and allow some amount of code reuse between people developing real robots in the field, but this hope is currently far from reality.

Reconfigurable Interfaces

Even without a standard set of components or standard architecture, there are some things that, from observation, do stay standard in most robot development projects: The decomposition of the personell and the development model. Many of the mobile robot systems are composed of loosely coupled modules, where each module may execute a particular perception, arbitration, control, or planning algorithm. Typically, each module is one person's reponsibility, and they are typically focused on a particular algorithm which they will be using to System integration is then done by a different, although possibly overlapping, set of people. Module developers concentrate on their algorithms, and in an academic setting, use them to produce papers and obtain doctorates. System integrators need to combine the modules to demonstrate system capabilities.

The problem in most robotic system development efforts is that in order to develop a module, most module developers are forced to learn about a particular system architecture that is specific to the current system being built. If they ignore this, it becomes very difficult for them to get the results they need. In addition, the system integrators typically have to learn a large amount about the individual modules in order to help the module developers integrate their modules into a coherent system. Usually, the system integrators have to take a version of the module and modify it for the current system needs. This blurring of roles locks the system into a particular architectural approach, as changing the system architecture means retraining everyone and rewriting everything involved in the system. Thus, mistakes made early in a project tend to be essentially uncorrectable later in the project developement without a huge investment of resources.

The core of the ModUtils package is to recognize this division of labor and first and foremost formalize the relationship between module developers and system integrators. We give module developers a common framework for module developement and utilities to support the standalone development of algorithms within modules, such as standard mechanisms for logging and replaying data, accessing parameters, and dealing with time when playing back data. The module developers view the rest of the system through what we call "reconfigurable interface." These reconfigurable interfaces are simply abstract C++ classes which cover adapters that can integrate the module into a particular system architecture. Behind the reconfigurable interfaces we provide communications toolkits that let system integrators connect the various modules together through their interfaces within a particular infrastructure. The goal is to allow system integrators to change almost anything about the integrated architecture without that change being visible to the module developers. Thus, we allow module developers to work on what they are experts in: algorithm development, while allowing system integrators to work on what they are experts in: building systems.

For example, we can look an an obstacle detection module. This module takes input from three laser scanners, so it uses three LaserScanner reconfigurable interfaces and needs to know the pose of the vehicle, so it uses a VehicleState reconfigurable interface. It needs to know what parameters to use for its algorithm, so it reads them from a ConfigurationSource. It creates a map of the obstacles and outputs through a CostMap reconfigurable interface. The ObstacleDetector algorithm cannot tell what is on the other side of these interfaces, it is almost completely isolated from the architecture in which it resides.


The reconfigurable interfaces for an obstacle detection module

The vast majority of the time in this module's life cycle will be spent with the module developer running in a "stand-alone" architecture. In this "architecture" we only run one process: the obstacle detector. The parameters are read in from a file, and the various data sources are read in from files using reconfigurable interfaces implemented with the underlying ModUtils data and parameter reading tools. The CostMap output can be a dummy, in which case the ObstacleDetector module is usually configured to run with a private development GUI, or, in some cases, the CostMap can cover another GUI which shows the output before we do the system integration. No other architectureal support processes need to be run, thus vastly simplifying the debugging of this one algorithm.


The module developer architecture

As the module matures, the system integrator will start moving into the larger, integrated architecture. To do this, the integrator will first reconfigure the module's configuration source to read its parameters from a central database via TCP/IP sockets instead of reading from a local file, and then will reconfigure the other data sources and outputs to use the shared memory based communications to talk with the rest of the system. The integrator does not have to change, or even recompile or relink, the obstacle detector module in order to do this. When bugs are found in the integrated system and isolated to this module, the system integrator can reconfigure the necessary interfaces to log data to disk, and can then hand off the data to the module developer to test and fix with in the predictable, canned data-based "stand-alone" architecture.


The integrated architecture

Reconfigurable interfaces are not rocket science. Actually, good module developers have always done something equivalent in order to protect themselves from the realities of system integration. The problem is that different module developers use different methods with differing degrees of rigor, some use #ifdef's to reconfigure at compile time, some use conditional statements to reconfigure at run time, and some use libraries with API's to reconfigure at link time. Some reconfigure based on the command line, some based on a configuration file (of some arbitrary syntax). In a large system, it can get very difficult for a system integrator to keep track of exactly how to configure each module. Reconfigurable interfaces simply represent a consistent, run-time changeable, means of isolating the modules from the architectures in which they reside.

In essense, a reconfigurable interface is an abstract API represented by an abstract C++ class definition. Then there is a suite of interface instances available at runtime. The particular interface instance is chosen and parameterized by a specification string. Once an interface is chosen and instantiated, the user simply invokes the top level, abstract methods without regard for the underlying implementation, i.e., whether the methods resolve to looking up data in files, fetching data across a network, or talking directly to a physical sensor or actuator.

The Goal

The goal of the ModUtils toolkit is to address the realities of developing robotic systems, where both the components and the architectures are subjects of research. The ModUtils toolkit provides the structure for reconfigurable interfaces, which allow the movement of modules from architecture to architecture, most importantly including smooth movement back and forth between a stand-alone development architecture and an integrated system architecture. The ModUtils package also includes many of the features necessary to implement and support typical stand-alone module development and a wide variety of system architectures.

The hope is to allow module developers the freedom to achieve algorithmic breakthroughs while giving system integrators the freedom to change the system as the real requirements of the task and capabilities of the modules become evident. Robot systems need to be in a constant prototype/evaluate cycle, and the ModUtils toolkit is there to support development and change in both algorithm and architecture while providing a consistent framework and nexus of communication for both algorithm and system developers.

Generated on Fri Jun 16 13:21:26 2006 for ModUtils by  doxygen 1.4.4