SmartSoft is a service-oriented component-based approach for robotics software based on communication patterns as core of a robotics component model. The framework assists the component developer, the application builder and the end user in building and using distributed components in such a way that the semantics of the interface of components is predefined by the communication patterns, irrespective of where they are applied. Dynamic wiring of components at run-time is explicitly supported by the wiring pattern which makes the major difference to other approaches. This allows to implement loosely coupled and distributed systems based on standardized components whose interaction can be adjusted according to the current context and requirements.
The SmartSoft MDSD Toolchain is an Integrated Development Environment (IDE) for robotics software development that supports the separation of roles. The toolchain covers the development process of modeling communication objects, components and systems.
To get started with SmartSoft, please see collected material at Quick Start.
Screenshot of the SmartMDSD Toolchain while modeling a component.
The SmartSoft Approach
Vital functions of robots are provided by software and software dominance is still growing. Mastering the software complexity is not only a demanding but also indispensable task towards an operational robot. Component based software approaches provide suitable means to master the complexity issue. Nevertheless shareable, distributable and reusable off-the-shelf software components for robotics are still a great dream. One of the reasons is the lack of a software component model taking into account robotics needs. The challenge of component based software approaches for robotic systems is to assist in building a system and to provide a software architecture without enforcing a particular robot architecture.
SmartSoft is a component based software framework to implement sensorimotor systems based on communication patterns as central mean to achieve decoupling at various levels. Decoupling is the key to master the overall complexity of software of sensorimotor systems.
SmartSoft has been developed in the domain of sensorimotor systems but is not restricted to applications in that domain. The general approach is also useful in other domains.
SmartSoft addresses the complexity issue by providing templates for standardized communication patterns. These provide a clear semantic of services and enforce consistent component interfaces.
Component interfaces based on predefined communication patterns allow a clear distinction between the external behavior of a component and its internal implementation. This is of vital importance for complex systems consisting of many components which are developed concurrently and even at different sites. It is also the key to component reuse avoiding starting from scratch again and again.
For a long time integration has been considered to require only a minor effort once the needed algorithms are all available. The difficulties to overcome have been vastly underestimated.
An important step from laboratory prototypes towards everyday robots is increased reliability and robustness. This requires to master the inherent complexity of robotic systems. Component based approaches address the complexity issue by splitting a complex system into several independent units with well-formed interfaces. Fitting of components is ensured by standards for their external behavior. This allows to compose systems of approved components and to focus on a single component when going into details without bothering with internals of other components.
A component based approach is not only useful for robotics hardware but is also advantageous at the software level. This is in particular true with regard to the still growing dominance of software in robotics. So far, there is hardly a chance to share software components between labs or reuse them on another platform even for the most often needed skills. The lack of standard specifications for robotic software requires error-prone and tedious reimplementations wasting valuable resources.
Several categories of users are distinguished which all put a different focus on complexity management for integration in robotics.
End users operate an application based on the provided user interface. They focus on the functionality of their application and use a readily provided system with a given functionality to fulfill the required tasks. They do not care on how the application has been built by the application builder and mainly expect reliable operation.
Application builders assemble applications based on suitable and reusable components. They customize them by adjusting parameters and sometimes even fill in application dependent parts called hot spots. They expect the framework to ensure clearly structured and consistent component interfaces for easy assembling of approved off-the-shelf components.
Component builders focus on the specification and implementation of a single component. They expect the framework to provide the infrastructure which supports their implementation effort in such a way that it is compatible with other components without being restricted too much with regard to component internals. They want to focus on algorithms and component functionality without bothering with integration issues.
Framework builders design and implement the framework such that it matches the manifold requirements at its best and that the above types of users can focus on their role.
Important features required in the robotics domain which go beyond standard component based software are the following ones:
Dynamic wiring can be considered as the pattern of robotics. The dynamic wiring pattern allows dynamic configuration of connections between services of components at runtime. Making both the control flow and the data flow configurable from outside a component is for example the key to situated skill compositions and is required in nearly any robotic architecture. The dynamic wiring pattern tightly interacts with the communication primitives and makes one of the major differences to other approaches.
Asynchronicity is a powerful concept to decouple activities and to reduce latencies by exploiting concurrency as far as possible. Decoupling is in particular important at the component level to avoid passing on tight timing dependencies between components. A robotics framework has to exploit asynchronicity whereever possible without involving the framework user.
Component internal structures can follow completely different designs and component builders therefore ask for as less restrictions as possible. A framework therefore has to allow for different component internal architectures. It however has to ensure interoperability by assisting in structuring and implementing a component.
Easy usage allows focusing on robotics and makes up-to-date software technology available without requiring a robotics expert to become a software engineering expert. Challenging topics which have to be addressed are for example location transparency of components and their services and concepts of concurrency including synchronization and thread safety.
Mastering the intercomponent communication is considered as key to master component dependencies and to ensure uniform component interfaces. The developed approach therefore selects intercomponent communication as a suitable starting point. The basic idea is to provide a small set of communication patterns which can transmit objects between components and then squeeze every component interaction into those predefined patterns. As shown in figure 1, components interact solely via those patterns.
The internal realization of the SmartMDSD Toolchain. The figure shows artifacts of the toolchain (models and
code), their relationships and their handover (red arrows) through the workflow.
Components are technically implemented as processes. A component can contain several threads and interacts with other components via predefined communication patterns. Components can be wired dynamically at runtime.
Communication Patterns assist the component builder and the application builder in building and using distributed components in such a way that the semantics of the interface is predefined by the patterns, irrespective of where they are applied. A communication pattern defines the communication mode, provides predefined access methods and hides all the communication and synchronization issues. It always consists of two complementary parts named service requestor and service provider representing a client/server, master/slave or publisher/subscriber relationship.
Communication Objects parameterize the communication pattern templates. They represent the content to be transmitted via a communication pattern. They are always transmitted by value to avoid fine grained intercomponent communication when accessing an attribute. Furthermore, object responsibilities are much simpler with locally maintained objects than with remote objects. Communication objects are ordinary objects decorated with additional member functions for use by the framework.
Service Each instantiation of a communication pattern provides a service. A service comprises the communication mode as defined by the communication pattern and the content as defined by the communication objects.
|push newest||publisher/subscriber||1-to-n distribution|
|push timed||publisher/subscriber||1-to-n distribution|
|state||master/slave||state management (utility)|
The set of communication patterns is summarized in table 1. The communication patterns make several communication modes explicit like oneway or request/response interaction. Push services are provided by the push newest and the push timed pattern. Whereas the push newest can be used to irregularly distribute data to subscribed clients whenever updates are available, the latter triggers calculation and distribution of updates on a regularly basis. The event pattern is used for asynchronous notification if an event condition becomes true under the activation parameters. The wiring pattern covers dynamic wiring of components and is described in more detail in the following sections.
The state pattern provides a very basic mechanism for state based activity coordination including cancelling of blocking calls of communication patterns if a state change is enforced. The state pattern is only one possible mechanism and already belongs to the set of patterns working on top of the basic primitives.
The set of communication patterns is not the smallest possible one since a oneway communication is already sufficient to implement any other communication mode. It however is a reasonable trade-off between usability and minimality.
Predefined member functions of the patterns provide access modes like synchronous and asynchronous service invocation or provide a handler based request handling. This no longer leaves it to the component builder to decide on whether to invoke a remote service synchronously or asynchronously but already defines an easy to use and fixed set of access modes with every communication pattern. In particular this provides the opportunity to fully handle concurrency and asynchronicity inside the communication patterns hidden from the user instead of dealing with those issues again and again in every single user defined object visible at a component interface. Communication patterns hide the underlying middleware and do not expect the framework user to for example deal with CORBA details like AMI and valuetypes. Compared to distributed objects, one can neither expose arbitrary member functions as component interface nor can one dilute the precise interface semantic. Both avoids puzzling over the semantic of component interfaces. Individual access methods are moved from the externally visible component interface to communication objects. Since communication objects are always transmitted by communication patterns and since member functions of communication objects are not exposed outside a component, usage of communication objects and implementing user member functions is completely free from cumbersome and demanding details of intercomponent communication and distributed object mechanisms. Communication patterns ensure decoupling of components since both parts always interact asynchronously irrespective of the access mode used by the user. Arbitrary communication objects provide diversity and ensure genericity even with a very small set of communication patterns. Figure 2 illustrates the key concept.
The User API
The service requestor always provides several constructors including immediate wiring with a service provider and exposing the service requestor as port wireable from outside. Connections can always be changed using the connect/disconnect methods. A service requestor can decide on being wireable from outside the component using the add/remove methods. These constructors and member functions are part of all service requestors listed in table 1 except the wiring pattern.
Client side management of blocking calls decouples blocking access modes from the service provider and supports client side canceling of blocking member functions calls. The blocking member function sets whether blocking is allowed or not. This feature is for example needed by the state pattern to rush through blocking calls to reach a forced state as fast as possible and still in an ordered way. Setting blocking to false aborts all blocking member function calls with an appropriate return code as well as new blocking method invocations.
The component developer implements and uses the components’ services. Based on the modeled component, the SmartMDSD Toolchain generates the component hull and provides empty functions for the user to fill in source-code.
Using communication patterns as core of a component approach ensures clearly structured component interfaces ad avoids dubious interface behaviors while still not restricting the component internal architecture. Moving access modes from the user domain into the communication patterns ensures decoupling of components by only using asynchronous interactions at the intercomponent level inside the patterns. Communication objects prevent the component from being poluted with middleware data types. Standard communication objects for maps, laser range scans, ultrasonic sensor values etc. support uniform representations at the component level. Using inheritance one can individually extend a communication object with individual member functions without affecting other components. Applying the communication patterns does not require additional software expertise beyong the standard knowledge. Due to its simple usage, it might boost the component based development of robotics software.