Keywords

1 Introduction

Autonomous robots are software-intensive systems increasingly used in many different fields. Their software components interact in real-time with a highly dynamic and uncertain environment through sensors and actuators. To complete tasks that are beyond the capabilities of an individual autonomous robot, multiple robots are teamed together to form a Multi-Robot System (MRS). An MRS can take advantage of distributed sensing and action, and greater reliability. On the other hand, an MRS requires robots to cooperate and coordinate to achieve common goals.

The development of the software controlling a single autonomous robot is still a challenge [24, 31, 49]. This becomes even more arduous in the case of MRSs [14, 25], as it requires dealing with multiple cooperating tasks to drive the robots to work as a well-coordinated team. To meet this challenge, various software libraries, tools and middlewares have been proposed to assist and simplify the rapid prototyping of robotics applications. Among them, nowadays, a prominent solution is ROS (Robot Operating System [52]), a popular framework largely used in both industry and academia for writing robot software. On the one hand, ROS provides a layer to interact with a multitude of sensors and actuators, for a large variety of robots, while abstracting from the underlying hardware. On the other hand, programming with ROS still requires dealing with low-level implementation details; hence, robotics software development remains a complex and demanding activity for practitioners from the robotic domain. To face this issue, many researchers have proposed using higher-level abstractions to drive the software development process and then resorting to tools for the automated generation of executable code and system configuration files. Many proposals in the literature are surveyed in [11, 13, 49, 50].

Along this line of research, we introduced in [5] an approach for programming a single-robot system. Specifically, we propose using the language X-Klaim  [7] to program the components of a robot’s software. This choice is motivated by the fact that X-Klaim provides mechanisms, based on distributed tuple spaces, for coordinating the interactions between these software components at a high level of abstraction. The integration of X-Klaim with ROS permits the application of the approach in practice.

In this paper, we take a step forward in this direction by extending the approach in [5] to program MRSs. In fact, the X-Klaim ’s computation and communication model is particularly suitable for dealing both with (i) the distributed nature of the architecture of each robot belonging to an MRS, where the software components dealing with actuators and sensors execute concurrently, and (ii) the inherent distribution of the MRS, which is formed by multiple interacting robots. Notably, the same tuple-based mechanisms are used both for intra- and inter-robot communication. This simplifies the design and implementation of MRS’s software in terms of an X-Klaim application distributed across both multiple threads of execution and multiple hardware platforms, resulting in a better readable, maintainable, and reusable code.

Our framework can be thought of as a proof-of-concept implementation for experimenting with the applicability of the tuple space-based paradigm to MRS software development. To show the execution of the generated code, we use a simulator of robot behaviors in complex environments. To illustrate the proposed approach, we consider a warehouse scenario, where an MRS involving an arm robot and two delivery robots manages the movement of items.

The rest of the paper is organized as follows. In Sect. 2, we provide some background notions concerning the X-Klaim language, while in Sect. 3 we present our approach. In Sect. 4 we (partially) illustrate the implementation of a simple robotics scenario according to the proposed approach. In Sect. 5 we present a systematic analysis of the strictly related work, while in Sect. 6 we conclude and touch upon directions for future work.

2 The X-Klaim Language

This section briefly describes the key ingredient of the approach we propose: the programming language X-Klaim.Footnote 1 We refer the interested reader to the cited sources in the following for a complete account.

X-Klaim is based on Klaim (Kernel Language for Agents Interaction and Mobility, [15]), a formal language devised to design distributed applications consisting of (possibly mobile) software components deployed over the nodes of a network infrastructure. Klaim generalizes the notion of generative communication, introduced by the coordination language Linda [33], to multiple distributed tuple spaces. A tuple space is a shared data repository consisting of a multiset of tuples. Tuples are anonymous sequences of data items that are associatively retrieved from tuple spaces using a pattern-matching mechanism. Tuple spaces are identified through localities, which are symbolic addresses of network nodes where processes and tuples can be allocated.

Processes can run concurrently, either at the same node or at different nodes, by executing actions to exchange tuples and to move processes. Action out (tuple)@nodeLocality adds the specified tuple to the tuple space of the target node identified by nodeLocality. A tuple is a sequence of actual fields, i.e., expressions, localities, or processes. Action in (template)@nodeLocality (resp., read (template)@nodeLocality) withdraws (resp., reads) tuples from the tuple space hosted at nodeLocality. The process is blocked until a matching tuple is found. Templates are sequences of actual and formal fields, where the latter are used to bind variables to values, localities, or processes. A template matches a tuple if both have the same number of fields and corresponding fields do match; two values/localities match only if they are identical, while formal fields match any value of the same type. Upon a successful matching, the template variables are replaced with the values of the corresponding actual fields of the accessed tuple. Action eval (Process)@nodeLocality sends Process for execution to nodeLocality. A process can use the reserved locality self to refer to its current hosting node.

The implementation of Klaim consists of the Java package Klava (Klaim in Java [4]), which provides the Klaim concepts in terms of Java classes and methods, and X-Klaim (eXtended Klaim  [7]), a Java-like programming language providing Klaim constructs besides the typical high-level programming constructs. X-Klaim is translated into Java code that uses the Java package Klava. An X-Klaim program can smoothly access any Java type and Java library available in the project’s classpath. X-Klaim comes with a complete IDE support based on Eclipse. The syntax of X-Klaim is similar to Java, thus it should be easily understood by Java programmers, but it removes much “syntactic noise” from Java.

3 The X-Klaim Approach to Multi-robot Programming

In this section, we provide an overview of our approach, and the resulting software framework, for programming MRS applications using ROS and X-Klaim.

A single autonomous robot has a distributed architecture, consisting of cooperating components, in particular sensors and actuators. Such cooperation is enabled and controlled by the ROS framework,Footnote 2 which provides tools and libraries for simplifying the development of complex controllers while abstracting from the underlying hardware. The core element of the ROS framework is the message-passing middleware, which enables hardware abstraction for a wide variety of robotic platforms. Although ROS supports different communication mechanisms, in this paper we only use the most common one: the anonymous and asynchronous publish/subscribe mechanism. For sending a message, a process has to publish it in a topic, which is a named and typed bus. A process that is interested in such message has to subscribe to the topic. Whenever a new message is published in the topic, the subscriber will be notified. Multiple publishers and subscribers for the same topic are allowed.

Fig. 1.
figure 1

Software architecture of an MRS in X-Klaim.

When passing from a single-robot system to an MRS, the distributed and heterogeneous nature of the overall system becomes even more evident. The software architecture for controlling an MRS reflects such a distribution: each robot is equipped with ROS, on top of which the controller software runs. This allows the robot to act independently and, when needed, to coordinate with the other robots of the system to work together coherently.

In X-Klaim the distributed architecture of the MRS’s software is naturally rendered as a network where the different parts are deployed. As shown in Fig. 1, we associate an X-Klaim node to each robot of the MRS. In its turn, the internal distribution of the software controller of each robot is managed by concurrent processes that synchronize their activities using local data, i.e., tuples stored in the robot’s tuple space. Inter-robot interactions rely on the same communication mechanism by specifying remote tuple spaces as targets of communication actions.

In practice, to program the behaviors of the robots forming an MRS, we enabled X-Klaim programs to interact with robots’ physical components by integrating the X-Klaim language with the ROS middleware. The communication infrastructure of the integrated framework is based on ROS Bridge. This is a server included in the ROS framework that provides a JSON API to ROS functionalities for external programs. This way, the ROS framework installed in a robot receives and executes commands on the physical components of the robot, and gives feedback and sensor data. The use of JSON enables the interoperability of ROS with most programming languages, including Java. As an example, we report in Fig. 2 a message pose in the JSON format published on the ROS topic /goal, providing information for navigating a delivery robot to a given goal position. In our example, the goal is the position \((-0.21,0.31)\), which is close to the position of the arm robot.

Fig. 2.
figure 2

Example of a JSON message for the /goal topic.

X-Klaim programs can indirectly interact with the ROS Bridge server, publishing and subscribing over ROS topics, via objects provided by the Java library java_rosbridge.Footnote 3 In its own turn, java_rosbridge communicates with the ROS Bridge server, via the WebSocket protocol, by means of the Jetty web server.Footnote 4

ROS permits to check the execution of the code generated from an X-Klaim program by means of the GazeboFootnote 5 simulator. Gazebo [42] is an open-source simulator of robot behaviors in complex environments that is based on a robust physics engine and provides a high-quality 3D visualization of simulations. Gazebo is fully integrated in ROS; in fact, ROS can interact with the simulator via the publish-subscribe communication mechanism of the framework. The use of the simulator is not mandatory when ROS is deployed in real robots. However, even in such a case, the design activity of the MRS software may benefit from the use of a simulator, to save time and reduce the development cost.

Since the X-Klaim compiler generates plain Java code, which depends only on Klava and a few small libraries, deploying an X-Klaim application can be done by using standard Java tools and mechanisms. In the context of this paper, it is enough to create a jar with the generated Java code and its dependencies (Klava and java_rosbridge), that is, a so-called “fat-jar” or “uber-jar”, and deploy it to a physical robot where a Java virtual machine is already installed. Under that respect, X-Klaim provides standard Maven artifacts and a plugin to generate Java code outside Eclipse, e.g., in a Continuous Integration server. Moreover, the dependencies of an X-Klaim application, including java_rosbridge, are only a few megabytes, which makes X-Klaim applications suitable also for embedded devices like robots.

4 The X-Klaim Approach at Work on an MRS Scenario

To illustrate the proposed approach, in this section, we show and briefly comment on a few interesting parts of implementing a warehouse scenarioFootnote 6 involving an MRS that manages the movement of items. As shown in Fig. 3, the MRS is composed of an arm robot and two delivery robots, and the warehouse is divided into two sectors, each one served by a delivery robot. The arm robot, positioned in the center of the warehouse, picks up one item at a time from the ground, calls the delivery robot assigned to the item’s sector, and releases the item on top of the delivery robot. The latter delivers the item to the appropriate delivery area, which depends on the item’s color, and then becomes available for a new delivery.

Fig. 3.
figure 3

Warehouse scenario.

Fig. 4.
figure 4

The X-Klaim net of the warehouse scenario.

In Fig. 4 we show a part of the network for our implementation of the scenario. Each robot is rendered as an X-Klaim node, whose name represents its locality (see Sect. 2). We have one or several processes for each node implementing the robot’s main tasks. Each node creates processes locally and executes them concurrently using the X-Klaim operation eval. Processes are parametric concerning the URI of the ROS bridge WebSocket. As already discussed in Sect. 3, the execution of an X-Klaim robotics application requires the ROS Bridge server to run, providing a WebSocket connection at a given URI. In the code of our example application, we consider the ROS Bridge server running on the local machine (0.0.0.0) at port 9090. Similarly, to execute the code in a simulated environment and obtain a 3D visualization of the execution, the Gazebo simulator has to be launched with the corresponding robot description. At this point, our application can be executed by running the Java class Main, which the X-Klaim compiler has generated. A few processes require additional parameters like the robot and sector id and the locality of other nodes (e.g., the arm’s node locality in MoveToArm).

The code should be easily readable by a Java programmer. We mention a few additional X-Klaim syntax features to make the code more understandable. Such types as String and Double are Java types, since, as mentioned above, X-Klaim programs can refer directly to Java types. In the code snippets, we omitted the Java-like import statements. Variable declarations start with val or var, for final and non-final variables, respectively. The types of variables can be omitted if they can be inferred from the initialization expression. Here we also see the typical Klaim operations, read, in and out, acting on possibly distributed tuple spaces. Formal fields in a tuple are specified as variable declarations, since formal fields implicitly declare variables that are available in the code occurring after in and read operations (just like in Klaim).

In Fig. 4, the main processes of the nodes wait for specific matching tuples before starting a new loop. To make things simpler, the loop is infinite, but we could easily rely on a termination condition to stop the whole example’s net. The main idea behind the implementation of our example is that processes coordinate themselves through the X-Klaim tuple space-based communication. On the other hand, the processes still rely on the ROS bridge to coordinate the physical parts of the robots themselves. This approach can be seen in the code of two of the processes we comment on in this section.

Fig. 5.
figure 5

The X-Klaim Rotate process.

Fig. 6.
figure 6

The X-Klaim MoveToArm process.

In Fig. 5 we show the code of the process Rotate, executed in the node Arm. All the processes of this example start by waiting for a specific tuple before executing the main body. This way, the processes that execute in parallel (see the eval in Fig. 4) can coordinate themselves: a process will effectively begin its task only after the previous process terminated its task. Then, the process creates the ROS bridge and initializes a publisher for the topic related to the control of the arm movements. After creating the joint positions for the arm movement, the process publishes the trajectory to rotate the arm. The process also inserts a tuple, consisting of an identifier string and the sector, in its local tuple space. The presence of this tuple triggers the call for a delivery robot. In fact, as shown later in Fig. 6, such a tuple is consumed by the MoveToArm process, which is executed by the delivery robots. This form of tuple-based interaction between the two kinds of robots allows the arm’s code not to depend on the number, the status, and the identities of the delivery robots. This way, the introduction of new delivery robots in the scenario would not affect the code of the arm robot.

The process then uses the Java API provided by java_rosbridge for subscribing to a specific topic (we refer to java_rosbridge documentation for the used API). The last argument is a lambda expression (i.e., an anonymous function). In X-Klaim, lambda expressions have the shape [ param1, param2, ... | body ], where the types of the parameters can be omitted if they can be inferred from the context. The lambda will be executed when an event for the subscribed topic is received. In particular, the lambda reads some data from the event (in JSON format) concerning the “positions”. ROS dictates the JSON message format. To access the contents, we use the standard Java API (data is of type JsonNode, from the jackson-databind library). The lambda calculates the delta between the actual joint positions and the destination positions to measure the arm movement’s completeness. The if determines when the arm has completed the rotation movement, according to a specific tolerance. When that happens, the lambda activates the process responsible for raising the object (GetUp in our example, see Fig. 4). This is achieved, once again, by inserting a specific tuple in the local tuple space. Finally, we can unsubscribe from the topic so that this process will receive no further notifications from the ROS bridge.

Fig. 7.
figure 7

Execution of an X-Klaim robotics application.

In Fig. 6 we show the code of the process MoveToArm, executed in the node DeliveryRobot1. This process is responsible for moving the delivery robot to the arm to get the item deposited on the robot by the arm. The structure of this process is similar to the previous one. Since the arm robot has a fixed position in our scenario, the coordinates x and y are defined as constants. As anticipated above, this process first waits for a tuple deposited by the Rotate process (Fig. 5). Recall that the Rotate process deposits such a tuple at its locality, so the process MoveToArm retrieves a matching tuple at the locality of the node of the arm (passed as a parameter to the process). The process then publishes the destination position on the ROS bridge and waits until the destination is reached by subscribing to a specific topic. As before, we specify a lambda that decides when the destination has been reached. Also in this case, we use the published information as JSON messages. Once the lambda establishes that the delivery robot arrived at the arm robot’s desired position, it stops the wheels (by publishing a Twist message). Then, it notifies the arm robot that the delivery robot is ready to receive the item (that is, the arm can drop the item), again, by inserting a tuple at the arm locality. The other tuple inserted in the local tuple space will be retrieved by the DeliverItem process, not shown here. As usual, the lambda takes care of unsubscribing from the ROS bridge once done.

The screenshot in Fig. 7 shows our X-Klaim robotics application in execution. On the left, the Eclipse IDE with our X-Klaim code is shown (see the logged messages on the Console). On the right, the Gazebo simulator is shown, which visualizes on the center the arm ready to drop the item on top of the delivery robot’s white plate.

5 Discussion and Related Work

Over the last years, researchers have attempted to define notations closer to the robotics domain to raise the abstraction level for enabling automated code generation, behavior analysis and property verification (e.g., safety and performance). In this section, we review several high-level languages and frameworks for modeling, designing and verifying ROS-based applications and some languages for coordinating collaborative MRSs. We summarize in Table 1 our considerations and comparison with the languages more strictly related to ours.

Table 1. Features comparison of the related works.

High-Level Languages and Frameworks. Many DSLs for component-based modeling of robotic systems are based on UML and target mostly the architectural aspect of robotic applications, e.g., RobotML [24], V\(^3\)CMM [3], BRICS [9], RoboChart [48], and SafeRobots [53]. Some of them can be used to build ROS-based systems by either supporting a direct translation, e.g., Hyperflex [8], or serving as a base for other platforms. For example, in BRIDE [10], which relies on BRICS, the components are modeled using UML and converted to ROS meta-models to generate runnable ROS C++ code. Additional meta-models (i.e., deployment meta-model and experiment meta-model) for rapid prototyping component-based systems are provided in [43]. UML has also been used to model and design robotic tasks and missions, e.g., Art2ool [28] supports the development cycle of robotic arm tasks in which atomic tasks are abstracted with UML class diagrams. Textual languages, e.g., CommonLang [54], are another type of language used to model robotic systems. For example, in [2], a DSL based on the Python language is presented that can be used interactively, through the Python command-line interface, to create brand new ROS nodes and to reshape existing ROS nodes by wrapping their communication interfaces.

Some other contributions, to some extent, allow for the verification of ROS-based systems. ROSGen [47] takes a specification of a ROS system architecture as an input and generates a ROS node as an output. Using the theorem prover Coq, the generation process is amenable to formal verification. DeROS [1] permits describing a robot’s safety rules (and their related corrective actions) and automatically generating a ROS safety monitoring node by integrating these rules with a run-time monitor. Another framework for run-time verification of ROS-based systems is described in [41], which allows generating C++ code for a monitoring node from user-defined properties specified in terms of event sequences. In [56], robot systems are modeled as a network of timed automata that, after verification in Uppaal, are automatically translated into executable C++ code satisfying the same temporal logic properties as the model. Finally, RSSM [30] permits to model the activities of multi-agent robot systems using Hierarchical Petri Nets and, once deadlock absence has been checked on this model, to generate C++ code for ROS packages automatically.

The approaches mentioned above have not been applied to such complex systems as MRSs, and some of them are not even suitable for such systems. Very few high-level languages for MRSs have been proposed. For example, FLYAQ [12] is a set of DSLs based on UML to specify the civilian missions for unmanned aerial vehicles. This work is extended in [26] for enabling the use of a declarative specification style, but it only supports homogeneous robots. ATLAS [39], which also provides a simulator-based analysis, takes a step further towards coordination of MRSs, but it only supports centralized coordination. PROMISE [32] allows specifying the missions of MRSs using Linear Temporal Logic operators for composing robotic mission patterns. Finally, RMoM [40] allows first using a high-level language for specifying various constraints and properties of ROS-based robot swarms with temporal and timed requirements and then automatically generating distributed monitors for their run-time verification.

Languages for Coordination. Coordination for MRSs has been investigated from several diverse perspectives, and nowadays there is a wide range of techniques that can be used to orchestrate the actions and movements of robots operating in the same environment [25, 57]. Designing fully-automated and robust MRSs requires strong coordination of the involved robots for autonomous decision-making and mission continuity in the presence of communication failures [29]. Several studies recommend using indirect communication to cut implementation and design costs usually caused by direct communication. Indirect communication occurs through a shared communication structure that each robot can access in a distributed concurrent fashion. Some languages providing communication and coordination primitives suitable for designing robust MRSs are reviewed in [14]. In ISPL [44], communication is obtained as an indirect result of synchronization of multiple labeled transition systems on a specific action. In SCEL [21], a formal language for the description and verification of collective adaptive systems, communication is related to the concept of knowledge repositories, represented by tuple spaces. In Buzz [51], a language for programming heterogeneous robot swarms, communication is implemented as a distributed key-value store. For this latter language, integration with the standard environment of ROS has also been developed, which is named Rosbuzz [55]. Differently from X-Klaim, however, Rosbuzz does not provide high-level coordination primitives, robots’ distribution is not explicit, and permits less heterogeneity. Drona [23] is a framework for distributed drones where communication is somehow similar to the one used in ISPL. Koord [34] is a language for programming and verifying distributed robotic applications where communication occurs through a distributed shared memory. Differently from X-Klaim, however, robots distribution is not explicit, and open-endedness is not supported. Finally, in [46] a programming model and a typing discipline for complex multi-robot coordination are presented. The programming model uses choreographies to compositionally specify and statically verify both message-based communications and jointly executed motion between robotics components in the physical space. Well-typed programs, which are terms of a process calculus, are then compiled into programs in the ROS framework.

6 Concluding Remarks and Future Work

In this paper, we have presented an approach for programming robotics applications based on the language X-Klaim and the ROS framework. We have extended the approach introduced in [5] from single robot scenarios to MRS ones. X-Klaim has proved expressive enough to smoothly implement MRSs’ behaviors, and its integration with Java allowed us to seamlessly use the java_rosbridge API directly in the X-Klaim code to access the publish/subscribe communication infrastructure of ROS.

We believe that the X-Klaim computation and communication model is particularly suitable for programming MRSs’ behavior. On the one hand, X-Klaim natively supports concurrent programming, which is required by the distributed nature of robots’ software. On the other hand, the organization of an X-Klaim application in terms of a network of nodes interacting via multiple distributed tuple spaces, where communicating processes are decoupled both in space and time, naturally reflects the distributed structure of an MRS. In addition, X-Klaim tuples permit to model both raw data produced by sensors and aggregated information obtained from such data; this allows programmers to specify the robot’s behavior at different levels of granularity. Moreover, the form of communication offered by tuple spaces, supported by X-Klaim, benefits the scalability of MRSs in terms of the number of components and robots that can be dynamically added. This would also permit to meet the open-endedness requirement (i.e., robots can dynamically enter or leave the system), which is crucial in MRSs.

Our long-term goal is to design a domain-specific language for the robotics domain that, besides being used for automatically generating executable code, is integrated with tools supporting formal verification and analysis techniques. These tools are indeed highly desirable for such complex and often safety-critical systems as autonomous robots [45]. The tools already developed for Klaim, e.g., type systems [16, 17, 37, 38], behavioral equivalences [18], flow logic [22], and model checking [19, 20, 27], could be a valuable starting point. A first attempt to define a formal verification approach for the design of MRSs using the Klaim stochastic extension StoKlaim and the relative stochastic logic MoSL [19] has been presented in [36].

Runtime adaptation is another important capability of MRSs. In [35], we have shown that adaptive behaviors can be smoothly rendered in Klaim by exploiting tuple-based higher-order communication to exchange code and possibly execute it. We plan to investigate to what extent we can benefit from this mechanism to achieve adaptive behaviors in robotics applications. For example, an X-Klaim process (a controller or an actuator) could dynamically receive code from other possibly distributed processes containing the logic to continue the execution.

X-Klaim has several other features that we did not use in this work. We list here the most interesting ones, which could be useful for future work in the field of MRSs. Non-blocking versions of in and read are available: in_nb and read_nb, respectively. These are useful to check the presence of a matching tuple without being blocked indefinitely. Under that respect, X-Klaim also provides “timed” versions of these operations: as an additional argument, they take a timeout, which specifies how long the process executing such action is willing to wait for a matching tuple. If a matching tuple is not found within the specified timeout these operations return false, and the programmer can adopt countermeasures. In the example of this paper, we used the simplest way of specifying a flat and closed network in X-Klaim. However, X-Klaim also implements the hierarchical version of the Klaim model as presented in [6], which allows nodes and processes to be dynamically added to existing networks so that modular programming can be achieved and open-ended scenarios can be implemented.

It is worth noticing that in this work we exploit both the tuple-based communication model, which X-Klaim inherits from Klaim, and the publish/subscribe one, supported by ROS and enabled in X-Klaim by the java_rosbridge library. The former communication model is used to coordinate both the execution of concurrent processes running in a robot and the inter-robot interactions. The latter model, instead, is used to send/receive messages for given topics to/from the ROS framework installed in a single robot. In principle, the former model can be used to express the latter. However, this would require introducing intermediary processes that consume tuples and publish their data on the related topics and, vice-versa, generate a tuple each time an event for a subscribed topic is received. This would introduce significant overhead in the communication with the ROS framework, especially for what concerns the handling of the subscriptions (as topics related to sensors usually produce message streams). Nevertheless, we plan to investigate the definition of a programming framework to make transparent the use of the publish/subscribe mechanism as mentioned above, overcoming the performance issue by elevating the level of abstraction. The idea is not only to replace topics with tuples, but to provide ready-to-use processes acting as building blocks for creating robotics applications. The API for interacting with these processes will be tuples with given structures. These processes will hide the interactions with the ROS framework to the programmer, and produce tuples only when events relevant to the coordination of the MRS behavior occur (e.g., a robot reached a given position or a requested movement has been completed).

Finally, in this work we have used the version 1 of ROS as a reference middleware for the proposed approach, because currently this seems to be most adopted in practice. We plan anyway to investigate the possibility of extending our approach to the version 2 of ROS, which features a more sophisticated publish/subscribe system based on the OMG DDS standard.