Software for Humanoid Robots: The YARP Approach

Researchers in humanoid robotics find themselves with a complicated pile of hardware to control with an equally complicated pile of software. Achieving visual, auditory, and tactile perception while performing elaborate motor control in real-time requires a lot of processor cycles. The most practical way to get those cycles at the moment is to have a cluster of computers. Every year the capabilities of an individual machine grows, but so also do our demands; humanoid robots stretch the limits of current technology, and are likely to do so for the foreseeable future. Moreover, software easily becomes entangled with the hardware on which it runs and the devices that it controls. This limits modularity and code reuse which, in turn, complicates software development and maintainability. In the last few years we have been developing a software platform called YARP to ease these tasks and improve the software quality on our robot platforms. We want to reduce the effort devoted to infrastructure-level programming to increase the time spent doing research-level programming. At the same time, we would like to have stable robot platforms to work with. Today YARP is a platform for long-term software development for applications that are real-time, computation-intensive, and involve interfacing with diverse and changing hardware.

We summarize here some of the lessons we have learned over the years while working on various robots, some of which are software engineering commonplaces and some of which are more specific to long-term robotic research.

One processor is never enough.

Designing a robot control system as a set of processes running on a set of computers is a good way to work. It minimizes time spent wrestling with code optimization, rewriting other people's code, and maximizes time spent actually doing research. The heart of YARP is a communications mechanism to make writing and running such processes as easy as possible. Even where mobility is required this is not a limiting factor if tethers or wireless communication are acceptable.

Modularity.

Code is better maintained and reused if it is organized in small processes, each one performing a simple task. In a cluster of computers some processes are bound to specific machines (usually when they require a particular hardware device), and some can run on any of the available computers. With YARP it is easy to write processes that are location independent and that can run on different machines without code changes. This allows us to move processes across the cluster at runtime to redistribute the computational load on the CPUs, to recover from a hardware failure, or to follow a physical device that has been moved to another machine. YARP does not contain any means of automatically allocating processes as in some approaches like GRID. We deliberately assign this task to the developer. The rationale is that: i) the link between hardware and corresponding control software is subject to constraints understood by the developer but cumbersome to encode, particularly in a continually-changing research environment, and ii) in an heterogeneous network of processors, faster processors might need to be allocated differently from slower processors. The final behavior is that of a sort of ``soft real-time'' parallel computation cluster without the more demanding requirements of a real-time operating system.

Minimal interference.

As long as enough resources are available, the addition of new components should minimally interfere with existing processes. This is important, since often the actual performance of a robot controller depends on the timing of various signals. While this is not strictly guaranteed by the YARP infrastructure, the problem is in practice alleviated computationally by allowing the inclusion of more processors to the network, and from the communication point of view by the buffer policy.

Stopping hurts.

It is a commonplace that human cycles are much, much more expensive than machine cycles. In robotics, it turns out that the human cost of stopping and restarting a process can be very high. For example, that process may interface with some custom hardware which requires a physical reset. That reset many need to be carefully ordered with respect to when the process is stopped and started. There may be other dependent processes that need to be restarted in turn, and other dependent hardware. These ordering constraints are time-consuming to satisfy. YARP does its part to minimize dependencies between processes. Communication channels between processes can come and go without process restarts. A process that is killed or dies unexpectedly does not require processes to which it connects to be restarted. This also simplifies cooperation between people, as it minimizes the need to synchronize development on different parts of the system.

Humility helps.

Over time, software for a sophisticated robot needs to aggregate code written by many different people in many different contexts. Doubtless that code will have dependencies on various communication, image processing, and other libraries. Even the operating system on which the software is developed can pose similar constraints. This is especially true with code that relies heavily on the services offered by the operating system (such as communication, scheduling, synchronization primitives, and device driver interfaces). Any component that tries to place itself ``in control'' and has strong constraints on what dependencies are permissible will not be tolerated for long. It certainly cannot co-exist with another component with the same assumption of ``dominance''. Although YARP offers support for communication, image processing, interfacing to hardware etc., it is written with an {open world} mindset. We do not assume it will be the only library used, and endeavor to be as friendly to other libraries as possible. YARP allows interconnecting many modules seamlessly without subscribing to any specific programming style, language interface, or demanding specifications as for instance in CORBA or DCOM. Such systems, although far more powerful than YARP, require a much tighter link between the general algorithmic code and the communication layer. We have taken a more lightweight approach: YARP is a plain library linked to user-level code that can be used directly just by instantiating appropriate classes. Finally, other programming languages can access YARP as well, provided they can link and call C++ code.

Exploit diversity.

Different operating systems offer different features. Sometimes it is easier to write code to perform a given task on one OS as opposed to another. This can happen for example if device drivers for a given board are provided only on a specific platform or if an algorithm is available open source on another. We decided to reduce the dependencies with the operating system. For this we use ACE, an open source library providing a framework for concurrent programming across a very wide range of operating systems. YARP inherits the portability of ACE and has indeed been used and tested on Windows, Linux and (in some incarnations) QNX 6.

YARP's core communication model was the survivor from an early humanoid robot (called Kismet) controlled by a set of Motorola 68332 processors, an Apple Mac, and a loose network of PCs running QNX, Linux, and Microsoft Windows. Communication was a hodge-podge of dual-port RAM, QNX message passing, CORBA, and raw sockets. At one point, three incompatible communication protocols layered over QNX message passing were in use simultaneously. This variety was a consequence of organic growth, as developers added new modules to the robot. YARP began as one of the communication protocols built on QNX message passing. A key defining feature of YARP was that it was broad-minded: it was implemented in the form of a library which placed minimal constraints on user code; communication resources did not need to be allocated at any particular time or place in a program; reading messages could be blocking, polling, or callback based, etc. This meant it could be easily added without disturbing existing code, and communication could be moved across to the new protocol piece by piece.


Generated on Sun Jul 23 22:15:47 2006 by  doxygen 1.4.6