1 Buzz: An Extensible Programming Language for Self-Organizing Heterogeneous Robot Swarms Carlo Pinciroli, Adam Lee-Brown, Giovanni Beltrame

Abstract—We present Buzz, a novel programming language In this paper, we argue that a DSL is an indispensable for heterogeneous robot swarms. Buzz advocates a compositional tool towards the deployment of real-world robot swarms. approach, offering primitives to define behaviors both The dynamics of robot swarms are made complex by the from the perspective of the single robot and of the overall swarm. Single-robot primitives include robot-specific instructions presence of both spatial aspects (body shape, sensing, actu- and manipulation of neighborhood data. Swarm-based primitives ation) and networks aspects (message loss, volatile topology). allow for the dynamic management of robot teams, and for Additionally, to render the production of large-scale swarms sharing information globally across the swarm. Self-organization affordable, the robots suffer from significant limitations in stems from the completely decentralized mechanisms upon which terms of computational power, especially when compared with the Buzz run-time platform is based. The language can be extended to add new primitives (thus supporting heterogeneous robots designed to act alone. Thus, a DSL for robot swarms robot swarms), and its run-time platform is designed to be has the potential to act as a platform that (i) Filters the low- laid on top of other frameworks, such as Robot Operating level details concerning space and networking, in an efficient, System. We showcase the capabilities of Buzz by providing resource-aware fashion; (ii) Offers a coherent abstraction of code examples, and analyze scalability and robustness of the the system; (iii) Acts as common platform for code reuse and run-time platform through realistic simulated experiments with representative swarm algorithms. benchmarking. In this paper, we present Buzz, a novel DSL for robot Index Terms—distributed robot systems, control architectures swarms. To drive the design of Buzz, we identified key and programming, , swarm engineering requirements a successful programming language for swarm robotics must meet. I.INTRODUCTION First, as mentioned, the language must allow the program- mer to work at a suitable level of abstraction. The complexity WARM robotics systems [1] are envisioned for large- of concentrating on individual robots and their interactions, S scale application scenarios that require reliable, scalable, i.e., a bottom-up approach, increases steeply with the size and autonomous behaviors. Among the many hurdles towards of the swarm. Conversely, a purely top-down approach, i.e., real-world deployment of swarm robotics systems, one of focused on the behaviour of the swarm as a whole, might the most important is the lack of dedicated tools, especially lack expressive power to fine-tune specific robot behaviors. We regarding software [2]. In particular, one problem that has believe that a language for robot swarms must combine both received little attention in the literature is programmability. bottom-up and top-down primitives, allowing the developer to The current practice of swarm behavior development typically pick the most comfortable level of abstraction to express a focuses on individual behaviors and low-level interactions [3]. swarm algorithm. This approach forces developers to constantly ‘reinvent the Second, the language must enable a compositional ap- wheel’ to fit well-known algorithms into new applications, proach, by providing predictable primitives that can be com- resulting in a slow and error-prone development process. bined intuitively into more complex algorithms and constructs. To promote code reuse, two general approaches are possible. arXiv:1507.05946v3 [cs.RO] 1 Aug 2015 Third, the language must prove generic enough to (i) express The first approach is the development of software libraries that the most common algorithms for swarm coordination, such as encapsulate certain algorithms. While this has the advantage of flocking, task allocation, and collective decision making; and leveraging pre-existing frameworks and tools, it falls short of (ii) support heterogeneous swarms. screening the user from unnecessary detail, such as non-trivial Fourth, the run-time platform of the language must ensure compilation configuration or language-specific boilerplate. acceptable levels of scalability (for increasing swarm sizes) The second approach is the creation of a domain-specific and robustness (in case of temporary issues). language (DSL) exposing only the relevant aspects of the Currently, the management of the low-level aspects and corner problem to solve. A well-designed DSL shapes the way a sys- cases concerning these issues constitutes a sizable portion of tem is conceived, by offering powerful abstractions expressed the development process of swarm behaviors. Alleviating this through concise constructs. burden with a scalable and robust run-time platform is crucial for real-world deployment of swarm behaviors. C. Pinciroli and G. Beltrame are with the Department of Computer and Software Engineering, Ecole´ Polytechnique de Montreal,´ PO Box The main contribution of this paper is the design and 6079, Succ. Centre-ville Montreal,´ Quebec,´ Canada H3C 3A7. E-mail: implementation of Buzz, a programming language that meets {carlo.pinciroli,giovanni.beltrame}@polymtl.ca the requirements discussed above. Buzz is released as open- A. Lee-Brown is with the School of Electrical and Electronic Engineering, Royal Melbourne Institute of Technology, 124 La Trobe St, Melbourne VIC source software under the MIT license. It can be downloaded 3000, Australia. E-mail: [email protected] at http://the.swarming.buzz/. 2

The text is organized as follows. In Sec. II, we present the operation of intersection, union, or difference between two design principles we followed. In Sec. III, we introduce the pre-existing swarms. Each swarm can be atomically assigned Buzz syntax. In Sec. IV we illustrate the run-time platform. operations to perform. Swarms can be employed to encode In Sec. V we report a number of scripts meant to showcase complex task coordination strategies. the capabilities of Buzz, in particular its conciseness and Situated communication. Each robot is assumed to be generality. In Sec. VI we analyze the scalability and robustness equipped with a device capable of situated communication [5]. of the Buzz run-time. In Sec. VII we discuss related work, Such device broadcasts messages within a limited range and outlining similarities and differences of Buzz with respect to receives messages from neighboring robots in direct, unob- existing languages and frameworks. Finally, in Sec. VIII we structed line-of-sight. Upon receipt of a message, a robot draw concluding remarks. also detects the relative distance and angle of the message sender. Situated communication has been used extensively in II.DESIGN PRINCIPLES swarm robotics to achieve global coordination in algorithms for, e.g., pattern formation [6], flocking [7], exploration [8], The design of Buzz was based on a set of high-level and task allocation [9]. This communication modality can be principles, that are described in the following. achieved on-hardware with robots such as the Kilobot [10], Discrete swarm, step-wise execution. A swarm is considered the e-puck [11], and the marXbot [12], although with lim- as a discrete collection of devices, each running the Buzz ited payload size, and a dedicated module for low-cost 3D virtual machine (BVM), and executing the same Buzz script. communication was proposed in [13]. Alternatively, situated Script execution proceeds independently on each robot in a communication can be satisfactorily realized through WiFi and step-wise fashion. Each time-step is divided in five phases: GPS (for outdoor scenarios) or tracking systems such as Vicon 1) Sensor readings are collected and stored in the BVM; (for indoor scenarios). 2) Incoming messages are collected and processed by the Information sharing. Buzz provides two ways for robots BVM; 3) A portion of the Buzz script is executed; 4) The to share information: virtual and neighbor queries. messages in the BVM output queue are sent (as many as Virtual stigmergy is a data structure that allows the robots in possible, according to the available payload size; see Sec. IV); a swarm to globally agree on the values of a set of variables. 5) Actuator values are collected from the BVM state and From an abstract point of view, virtual stigmergy is akin to applied. The length of a time-step is constant over the life- a distributed key-value storage. Among its many potential time of the script, although it does not need to be the same applications, this structure may be employed to coordinate for every robot. If the execution time of a step is shorter than task execution, e.g., mark the tasks that have already been the allotted time, the robot sleeps for a period. If the execution completed and/or share progress on the uncompleted ones. is longer, a warning message is printed on the screen and the Neighbor queries allow a robot to inquire its direct neighbors execution proceeds. on the value of a certain variable. Upon receiving a request, Predictable and composable syntax. Buzz employs a simple, the neighbors reply with the current value of the variable; imperative syntax inspired by languages such as Python, Lua, these replies are then collected into a list by the robot who and JavaScript. While this syntax ensures a short learning requested the data. Neighbor queries are useful when robots curve, it also allows for predictable and composable scripts. must perform local data aggregation, such as calculating By predictable, we mean that a programmer can easily infer averages [14] or constructing spatial gradients. the results of the execution of a program by reading its code. Composability refers to the ability to structure a complex III.LANGUAGE DEFINITION program into simpler elements, such as functions, classes, etc. A. Robot-wise operations and primitive types that can later be used as modules. The simplest operations available in Buzz are robot-wise Support for heterogeneous robots. Buzz is explicitly de- operations. These operations are executed by every robot signed to support heterogeneous robot swarms. To this aim, individually. Assignments, arithmetic operations, loops and extension language Buzz is conceived as an , that is, a lan- branches fall into this category. E.g.: guage that exports and enhances the capabilities of an already # Assignment and arithmetic operation existing system. This design choice allows one to stack the a=3+7 Buzz run-time on top of well-known single-robot frameworks # Loop 1 2 3 i = 0; while(i

s.leave() # Create an empty table # Check whethera robot belongs tos t = {} if(s.in()) { ... } # Index syntax, use as array t[6] = 5 # Dot syntax, use as dictionary Once a swarm is created, it is possible to assign tasks to it t.b=9 through the method exec(). This method accepts a closure # Index syntax, use as dictionary t["b"] = 10 as parameter. # Assigninga task toa swarm Buzz also supports functions as first-class objects, imple- s.exec(function() { ... }) mented as closures [16]. Two types of closures exist: native closures and C closures. Native closures refer to functions Internally, the closure is executed as a swarm function call. defined within a Buzz script, while C closures refer to C This call modality differs from normal closure calls in that functions registered into the BVM (see Sec. IV-F). the current swarm id is pushed onto a dedicated swarm stack. Upon return from a swarm function call, the swarm # Function definition function f(a){ return a} stack is popped. When the swarm stack is non-empty, the # Native closure assignment swarm.id() method is defined. If called without arguments, n=f # Function call usingf.x is set to9 it returns the swarm id at the top of the swarm stack (i.e., the x=f(9) current swarm id); if passed an integer argument n > 0, it # Function call usingn.x is set to5 x=n(5) returns the n-th element in the swarm stack. Besides making # Native closures can be defined anonymously(a.k.a. lambdas) the swarm.id() command possible, the swarm stack is l= function(a,b){ return a+b} x=l(2,3) #x is set to5 instrumental for neighbor operations (see Sec. IV-D). The programmer can create new swarms that result from The combination of tables and closures allows for the creation operations on pre-existing swarms. Four such operations are of class-like structures. Following the object-oriented program- available: intersection, union, difference, and negation. The ming jargon, we refer to functions assigned to table elements first three operations act on two swarms: as methods: #a,b are swarms defined earlier in the script # Create empty table # Create new swarm with robots belonging to botha andb t = {} # The first argument isa unique swarm identifier # Add attribute to table i= swarm.intersection(100,a,b) t.a=4 # Create new swarm with robots belonging toa orb # Add method to table u= swarm.union(101,a,b) #’self’ refers to the table owning the method # Create new swarm with robots belonging toa and not tob t.m= function(p){ return self.a+p} d= swarm.difference(102,a,b) # Method call x=t.m(6) #x is set to 10 The fourth operation, negation, is encoded in the others() method and it creates a new swarm that contains all the robots that do not belong to a given swarm: B. Swarm management # Createa new swarmn as the negation of swarms Buzz lets the programmer subdivide the robots into multiple n=s.others(103) teams. In Buzz parlance, each team is called a swarm. Buzz treats swarms as first-class objects. To create a swarm, the programmer must provide a unique identifier, which is known C. Neighbor operations and shared by all the robots in the created swarm. The returned Buzz offers a rich set of operations based on the neigh- value is a class-like structure of type swarm. borhood of a robot. These operations include both spatial and # Creation ofa swarm with identifier1 communication aspects. s= swarm.create(1) The neighbors structure. The entry point of all neighbor operations is the neighbors structure. For each robot, this Once a swarm is created, it is initially empty. To have robots structure stores spatial information on the neighbors within join a swarm, two methods are available: select() and communication range. The structure is updated at each time join(). With the former, the programmer can specify a step. It is internally organized as a dictionary, in which the condition, evaluated by each robot individually, for joining index is the id of the neighbor and the data entry is a tuple a swarm; with the latter, a robot joins a swarm uncondition- (distance, azimuth, elevation). ally. To leave a swarm, Buzz offers the analogous methods Iteration, transformation, reduction. The neighbors unselect() and leave(). A robot can check whether it structure admits three basic operations: iteration, transfor- belongs to a swarm through the method in(). mation, and reduction. Iteration, encoded in the method # Join the swarm if the robot identifier(id) is even foreach(), allows the programmer to apply a function #-’id’ is an internal symbol that refers to the # numeric id of the robot executing the script without return value to each neighbor. For instance, to print #-% is the modulo operator the data stored for each neighbor, one could write: s.select(id % 2 == 0) # Join the swarm unconditionally # Iteration example(rid is the neighbor’s id) s.join() neighbors.foreach( # Leave the swarm if the robot id is greater than5 function(rid, data){ s.unselect(id > 5) print("robot ", rid, ": ", # Leave the swarm unconditionally "distance = ", data.distance, ", " 4

"azimuth = ", data.azimuth, ", " D. Virtual stigmergy "elevation = ", data.elevation) }) Virtual stigmergy is a data structure that allows a swarm Transformation, encoded in the method map(), applies a of robots to share data globally. Essentially, virtual stig- function with return value to each neighbor. The return value is mergy works as a distributed tuple space analogous to the result of an operation on the data associated to a neighbor. Linda [17]. Three methods are available: create(), put(), The end result of mapping is a new neighbors structure, and get(). As the names suggest, create() is a method in which each neighbor id is associated to the transformed that creates a new virtual stigmergy structure, while put() data entries. For example, to transform the neighbor data into and get() access the structure, writing or reading (key, cartesian coordinates, one could proceed as follows: value) entries. # Createa new virtual stigmergy # Transformation example #A unique id (1 here) must be passed cart= neighbors.map( v= stigmergy.create(1) function(rid, data){ # Writea(key,value) entry into the structure var c = {} v.put("a", 6) c.x= data.distance * math.cos(data.elevation) * # Reada value from the structure math.cos(data.azimuth) x=v.get("a") c.y= data.distance * math.cos(data.elevation) * math.sin(data.azimuth) c.z= data.distance * math.sin(data.elevation) A virtual stigmergy structure can handle only a subset of return c}) the primitives types: integer, floating-point, string, and table. These types can be used either as keys or values. reduce() Reduction, encoded in the method , applies a The name virtual stigmergy derives from the indirect, function to each neighbor to produce a single result. For environment-mediated communication of nest-building insects instance, this code sums the cartesian vectors calculated in such as ants and termites [18]. The key idea in natural the previous example: stigmergy is that environmental modifications to organize the # Reduction example. accum isa table environment occur in a step-wise fashion, whereby a modifica- # with valuesx,y, andz, initialized to0 tion performed by an individual causes a behavioral response result= cart.reduce( function(rid, data, accum){ accum.x= accum.x+ data.x in another individual, without the two individuals ever directly accum.y= accum.y+ data.y interacting. From the point of view of the programmer, virtual accum.z= accum.z+ data.z return accum stigmergy works as a virtual shared environment: a robot }, {x=0,y=0,z=0}) modifies an entry, and this modification triggers a reaction in another robot without the two having to interact directly. Filtering. It is often useful to apply the presented operations As shown in Sec. V, virtual stigmergy is a powerful concept to a subset of neighbors. The filter() method allows that enables the implementation of a large class of swarm the programmer to apply a predicate to each neighbor. The behaviors. end result of the filter() method is a new neighbors structure storing the neighbors for which the predicate (a function) was true. For instance, to filter the neighbors whose IV. RUN-TIME PLATFORM distance is within 1 m from a robot, one could write: A. The Buzz virtual machine # Filtering example The run-time platform of Buzz is based on a custom, stack- onemeter= neighbors.filter(function(rid, data){ # We assume the distance is expressed in centimeters based virtual machine written entirely in C. The organization return data.distance < 100 }) of the modules composing the VM is depicted in Fig. 1. The implementation of a new VM is motivated by the design Another common necessity is filtering neighbors by their choices in Buzz. In particular, the integration of swarm man- membership to a swarm. The kin() method returns a agement and virtual stigmergy into a VM for a dynamically- neighbors structure that contains the robots that belong typed, extensible language forced us to find dedicated solutions to the same top-of-the-stack swarm as the current robot. The for data representation, stack/heap management, and byte code nonkin() method returns the complementary structure. An encoding. The specifics on these aspects are purely technical example application for these methods is offered in Sec. V. and go beyond the scope of this paper. A notable fact about the Communication. Another use for the neighbors structure BVM is its tiny size (12 KB) which fits most robots currently is to exchange and analyze local data. To make this possible, in use for swarm robotics research. Buzz offers two methods: broadcast() and listen(). At each time step, the BVM state is updated with the latest The former allows the robot to broadcast a (key, value) sensor readings. Sensor readings are typically stored in the pair across its neighborhood. The latter takes two inputs: heap as data structures (e.g., tables). Incoming messages are the key to listen to, and a listener function to execute then inserted in the BVM, which proceeds to unmarshal them upon receiving a value from a neighbor. The BVM executes and update the relevant modules. Subsequently, the interpreter the listener whenever data is received until the method is called to execute a portion of the script. At the end of this neighbors.ignore(key) is called. As an example, in phase, the updated actuator data is read from the BVM heap Sec. VI we report an experiment in which a robot swarm forms and part of the messages in the outbound queue are sent by a distance gradient from a robot acting as source. the underlying system. 5

swarm to 1 and queues a message . Analogously, when a robot Activation Swarm Stack leaves a swarm, the BVM sets the corresponding flag to Record Stack 0 and queues a message . Because leaving and joining swarms is not a particularly frequent operation, and motion constantly Interpreter changes the neighborhood of a robot, it is likely for a Virtual robot to encounter a neighbor for which no information is Stigmergy available. To maintain everybody’s information up-to-date, the BVM periodically queues a message containing the complete Output Input Message Heap list of swarms to which the robot belongs. The frequency of FIFO Message FIFO this message is chosen by the developer when configuring the BVM installed on a robot. Sensor data Actuator data Neighbor swarm data. The BVM stores the information in a hash map indexed by robot id. Each element of the hash map is Fig. 1. The structure of the Buzz virtual machine. a (swarm_id_list, age) pair where swarm_id_list corresponds the list of swarms of which the robot is a member, and age is a counter of the time steps since the last reception B. Code Compilation of a swarm update. Upon receipt of a swarm-related message The compilation of a Buzz script involves two tools: a com- (i.e., SWARM_JOIN, SWARM_LEAVE, SWARM_LIST), the piler called buzzc and an assembler/linker called buzzasm. BVM updates the information on a robot accordingly and The former is a classical recursive descent parser that generates zeroes the age of the entry. This counter is employed to an annotated object file in a single pass. The latter parses the forget information on robots from which no message has been object file, performs the linking phase, and generates the byte received in a predefined period. When the counter exceeds a code. The compilation process is typically performed on the threshold decided when configuring the BVM, the information programmer’s machine, and the generated byte code is then on the corresponding robot is removed from the structure. uploaded on the robots. This simple mechanism allows the robots to commit memory Because Buzz is an extension language, it is likely for the storage on active, nearby robots while avoiding waste of compiler to encounter unknown symbols. This typically occurs resources on unnecessary robots, such as out-of-range or dam- when robots with different capabilities are employed. For in- aged robots. In addition, this mechanism prevents excessive stance, flying robots may provide a fly_to() command for memory usage when the swarm size increases. motion, while wheeled robots may provide a set_wheels() Message queue optimizations. To minimize the bandwidth command (see also Sec. IV-F). required for swarm management, the BVM performs a number By default, the compiler treats unknown symbols as global of optimizations on the queue of swarm-related outbound symbols. Only at run-time, when a symbol is accessed, its messages. actual value is retrieved. In case the symbol is unknown at • If a SWARM_LIST message is queued, the information nil run-time, its value is set to . This mechanism provides contained in the message is more up-to-date than any a flexible way to write scripts that can work on robots with other message in the queue. Thus, all the queued mes- diverse capabilities. As a simple example, to create a swarm sages are removed and only the latest SWARM_LIST that contains all the flying robots, it is enough to write: message is kept. aerial= swarm.create(1) • If a SWARM_JOIN message is queued, three situations aerial.select(fly_to) can occur:4 (i) The queue does not contain any message regarding the same swarm id; (ii) The queue contains an SWARM_LIST C. Swarm management older message; or (iii) The queue contains an older SWARM_LEAVE message for the same swarm id. The management of swarm information is performed trans- In the first case, the SWARM_JOIN message is kept in the parently by the BVM. Essentially, each robot maintains two queue. In the second case, the SWARM_JOIN message data structures about swarms: the first structure concerns the is dropped, the SWARM_LIST message is kept in the swarms of which the robot is a member; the second stores data queue, and the swarm id of the SWARM_JOIN message regarding neighboring robots. The membership management is added to the list if not already present. In the third mechanisms are loosely inspired by CYCLON [19]. case, the SWARM_LEAVE message is dropped and the Membership management. Every time a SWARM_JOIN message is kept in the queue. swarm.create() command is executed, the BVM • If a SWARM_LEAVE message is queued, three situations stores the identifier of the created swarm into a dedicated can occur: (i) The queue does not contain any message hash table, along with a flag encoding whether the robot is a member of the swarm (1) or not (0). Upon joining 4If an older SWARM_JOIN message for the same swarm id is present, the a swarm, the BVM sets the flag corresponding to the new message is discarded. 6

regarding the same swarm id; (ii) The queue contains an a message . Nearby robots, upon receipt of an older SWARM_JOIN message for the same swarm id. the message, check whether its timestamp is higher than the In the first case, the SWARM_LEAVE message is kept locally known one. If this is the case, the robots propagate the in the queue. In the second case, the SWARM_LEAVE message. Otherwise, they ignore it. It might happen that two message is dropped, the SWARM_LIST message is kept robots advertise an update on the same key with the same in the queue, and the swarm id of the SWARM_LEAVE timestamp. When this happens, a user-defined conflict- message is removed from the list if present. In the third solver function is called. This function is given the conflicting case, the SWARM_JOIN message is dropped and the entries as parameters, and must return an entry as result. The SWARM_LEAVE message is kept in the queue. resulting entry can be either picked as-is from the input ones, or be a newly created one. To help resolve conflicts, each D. Neighbor operations input entry also contains a robot_id field storing the robot id that generated the entry. If no conflict solver is specified by Neighbor operations involve the collection and manipulation the user, the entry with the highest robot id is propagated. A of data about nearby robots. further user-defined function is executed by the robot that lost Neighbor data handling. Neighbor information is stored in the conflict. By default, this function does nothing; however, a sparse array indexed by the robot id of a neighbor. Each in some applications a robot might need to react, e.g. retry entry is a tuple containing the id of the neighbor, its distance, sending its update. An example usage of these functions is azimuth, and elevation angles expressed with respect to the reported in Sec. V-B. robot’s frame of reference. Reading from a virtual stigmergy structure. When a robot Neighbor data collection. Data collection involves the use of R1 reads a value from a virtual stigmergy structure, the situated communication devices, as discussed in Sec. II. At locally known value is returned by the BVM. Subsequently, each time step, a robot broadcasts a message . the BVM queues a message to inquire situated communication devices to detect the distance, azimuth nearby robots on whether the local entry is up-to-date or and elevation of the sending robot. The neighbors structure not. Upon receiving this message, a robot R2 checks its is cleared and reconstructed at each time step, to ensure internal data structure. If R2 knows more up-to-date informa- that the data is constantly up-to-date. This operation is not tion, it replies with a message contain- robot is lower than 10. ing its local version of the entry. If, instead, R2 possesses Neighbor queries. Neighbor queries allow robots older information, its BVM updates the entry and then to inquire and share information on the value of a broadcasts a message . This mechanism neighbors.listen(key, listener), the BVM allows robots to automatically update information after tem- stores the passed listener in a map indexed by key. porary disconnections or when random message loss occurs. Whenever the robot processes a message identified by key, the Message queue optimizations. The fact that messages are sent BVM executes the corresponding listener. The command only when an entry is written or read ensures that maximum neighbors.ignore(key) removes listener from resources are concentrated on ‘hot’ data. This allows the robots the map. The method neighbors.broadcast(key, to avoid expensive updates of the entire tuple space. In this value) queues a message . If a message way, a virtual stigmergy structure can grow in size if necessary, with the same key is already present in the output queue, knowing that minimal overhead is necessary to keep ‘hot’ data the BVM keeps the most recent one. up-to-date. However, the fact that each access to a virtual stigmergy structure entails the production of a message can E. Virtual stigmergy quickly fill the message queue. To avoid this problem, when a Virtual stigmergy structures are stored by the BVM in a message is queued, the BVM checks for existing messages in sparse array indexed by the id provided in the Buzz script. the outbound queue that refer to the same entry in the same Each entry of the sparse array is a separate virtual stig- virtual stigmergy structure, and only keeps the most up-to-date mergy structure. Internally, a virtual stigmergy structure is a message. hash map that stores tuples (key, value, timestamp, robot_id) where key is a Buzz primitive type that iden- tifies the entry, value is a primitive type that contains the F. Integrating and Extending Buzz value of the entry, timestamp is a Lamport clock [20] As an extension language, Buzz provides the necessary used to impose a temporal ordering on the entry updates, and mechanisms to add new commands and add data structures robot_id is the id of the robot that last changed the entry. that export parts of an underlying system (e.g. ROS [21]). Writing into a virtual stigmergy structure. When a Adding new data structures. Sensor readings are a common robot writes a new value into a virtual stigmergy struc- aspect that must be integrated with Buzz. Typically, this is ture, the BVM first creates or updates the local en- realized by adding dedicated data structures (e.g., tables) to the try in the hash map. Subsequently, the BVM queues BVM. For instance, the e-puck is equipped with 8 proximity 7 sensors placed in a ring around the robot body. The C code to V. EXAMPLES create a Buzz table that contains these values is as follows: The objective of this section is to showcase Buzz, by /* The Buzz virtual machine, assumed already initialized */ buzzvm_t vm; providing examples of common swarm algorithms for motion /* The proximity readings, assumed already filled */ and task coordination. These examples show how to build int prox[8]; complex swarm behaviors starting from simpler primitives, /* Createa new Buzz table for the proximity readings */ buzzvm_pusht(vm); and demonstrate the generality and composability of Buzz. The buzzobj_t pt= buzzvm_stack_at(vm, 1); buzzvm_pop(vm); examples are also designed to suggest how a library of reusable /* Store the proximity readings in the table */ swarm behaviors could be constructed using Buzz. The scripts for(int i = 0;i < 8; ++i){ were tested with ARGoS [22], an accurate, physics-based buzzvm_push(pt); /* push table */ 5 buzzvm_pushi(vm,i); /* push table index */ simulator that includes models for Spiri , a commercial quad- buzzvm_pushi(vm, prox[i]); /* push prox reading */ rotor robot. buzzvm_tput(vm); /* store in table */ } /* Store the table as the global symbol"prox" */ buzzvm_pushs(vm, buzzvm_string_register(vm, "prox")); A. Motion and Spatial Coordination buzzvm_push(pt); buzzvm_gstore(pt); In heterogeneous swarms, the presence of robots with In Buzz, one could then write the following: diverse motion means can enhance the capabilities of the swarm [23]. Buzz does not offer native motion primitives, if(prox[0] > 100 or prox[7] > 100) { # obstacle in front, turn around leaving the designer with the freedom to set ones that are most } suitable for each robot. In this section, we assume that every Adding new commands. Adding new commands allows a robot is endowed with a primitive goto(), which takes a 2D programmer to extend Buzz with new capabilities. External C direction as input in the form of a table {x,y}. The direction functions are integrated with Buzz as C closures. For instance, is then transformed into low-level actuation accordingly to the the code to integrate a function that sets the e-puck wheel specific motion means of a robot (e.g., wheels, propellers). speeds is as follows (error checking is omitted for brevity): Pattern formation [6] is a basic swarm behavior that has int set_wheels(buzzvm_t vm){ been employed in several applications including flocking [7] /* Read arguments */ and area coverage [8]. One of the most common approaches, buzzvm_lload(vm, 1); buzzvm_lload(vm, 2); and the one we show here, is to implement pattern formation int leftwheel= buzzvm_stack_at(vm, 2); through virtual physics [6]. Essentially, every robot is consid- int rightwheel= buzzvm_stack_at(vm, 1); ered as a charged particle immersed in a potential field, which /* Set wheel speed using low-levele-puck library */ ... is ‘virtual’ because it is calculated from neighbor positioning /* Return no value to Buzz */ return buzzvm_ret0(vm); data. The direction vector of each robot is calculated as } the weighted sum of the virtual forces that derive from the /* Register function as global symbol */ buzzvm_pushs(vm, buzzvm_string_register(vm, "set_wheels")); interaction of a robot with its neighbors. We employ the buzzvm_pushcc(vm, buzzvm_function_register(vm, set_wheels)); following formula [6] to calculate the magnitude of the virtual buzzvm_gstore(vm); force fn due to a neighbor n: As a result, in Buzz one could write: !   δ 4  δ 2 # Sete-puck wheel speeds |fn| = − − , set_wheels(10.0, 5.0) dn dn dn

Calling Buzz functions from C. It is sometimes necessary where dn is the current distance between the robot and its to call a (native or C) closure from C code. This happens, for neighbor n, δ is the target distance, and  is a gain. The instance, when the execution loop is managed outside Buzz. In direction vector a robot must follow is calculated as the this case, a Buzz script is typically organized in functions such average of the vectors of the virtual forces fn: as init(), step(), and destroy(). These functions are N called by the underlying system when necessary. As a simple 1 X f = f . example, let us take the increment function: N n n=1 # Buzz function that acceptsa single argument function inc(x){ return x+1} The neighbors structure provides a natural way to im- plement this behavior. First, one must implement the function To call it from C code, one needs to push its argument on the that calculates |f |: stack (an integer, in this example) and then call the function n buzzvm_function_call(): # Virtual force parameters(manually fitted) DELTA = 50. /* Push the function argument on the stack */ EPSILON = 2700. buzzvm_pushi(vm, 5); # Virtual force magnitude /* Call the function with: function force_mag(dist, delta, epsilon){ * 1. TheVM data return -(epsilon/ dist) * * 2. The function name ((delta/ dist)ˆ4 - (delta/ dist)ˆ2) * 3. The number of parameters passed } */ buzzvm_function_call(vm, "inc", 1); 5http://www.pleiades.ca 8

(a) Hexagonal pattern formation. (b) Segregation. Fig. 2. ARGoS screenshots of the swarm behaviors presented in Sec. V-A.

Next, we need a function to calculate fn from the positional BARRIER_VSTIG=1 # Function to marka robot ready information of a neighbor. This function is then used in function barrier_set() { neighbor.reduce() to calculate f: # Createa vstig barrier= stigmergy.create(BARRIER_VSTIG) # Virtual force accumulator } function force_sum(rid, data, accum){ # Function to marka robot ready var fm= force_mag(data.distance, DELTA, EPSILON) function barrier_ready() { accum.x= accum.x+ fm * math.cos(data.azimuth) barrier.put(id, 1) accum.y= accum.y+ fm * math.sin(data.azimuth) } return accum # Function to wait for everybody to be ready } function barrier_wait(threshold){ # Calculates the direction vector while(barrier.size() < threshold) barrier.get(id); function direction() { } var dir= neighbors.reduce(force_sum,{x=0,y=0}) dir.x= dir.x/ neighbors.count() dir.y= dir.y/ neighbors.count() An example usage of the barrier is presented in Sec. V-C. return dir } # Executed at each step C. Separation into Multiple Swarms # The loop is assumed managed outside Buzz function step() { Segregation is a basic motion behavior whereby a group of goto(direction()) } robots divides into two or more subgroups. A possible way to implement this behavior in Buzz consists of defining two Fig. 2a reports an ARGoS screenshot depicting the structure swarms, and use pattern formation to impose a short distance achieved by the robots after 30 seconds of simulated time. between kin robots, and a long one between non-kin ones. The following modifications to the pattern formation algorithm in B. Collective Decision-Making Sec. V-A capture the interaction among the different swarms: Collective decision-making is an important aspect in multi- # Virtual force parameters(manually fitted) DELTA_KIN = 50. robot coordination. In this section, we concentrate on one EPSILON_KIN = 2700. of the simplest and widespread behaviors in this class—the DELTA_NONKIN = 150. EPSILON_NONKIN = 8000. barrier. A barrier is a synchronization mechanism that allows # Virtual force accumulator for kin robots a swarm to wait until a sufficient number of robots are ready # Same as force_sum, with _KIN constants function force_sum_kin(rid, data, accum) { ... } to proceed. Quorum sensing has been proposed as a way # Virtual force accumulator for non-kin robots to achieve this behavior [24]. Quorum sensing refers to the # Same as force_sum, with _NONKIN constants function force_sum_nonkin(rid, data, accum) { ... } progressive build-up of a chemical in cell colonies. When the # Calculates the direction vector cells detect that the concentration of such chemical exceeds a function direction() { var dir threshold, a new behavior is triggered. dir= neighbors.kin().reduce(force_sum_kin,{x=0,y=0}) Virtual stigmergy offers a mean to implement quorum sens- dir= neighbors.nonkin().reduce(force_sum_nonkin, dir) dir.x= dir.x/ neighbors.count() ing. Every time a robot wants to mark itself as ready, it puts a dir.y= dir.y/ neighbors.count() pair (id, 1) in the virtual stigmergy structure, where id is return dir } a robot’s numeric id. The size() method returns the number of tuples in the virtual stigmergy, which here corresponds to The decision on which group a robot belongs to depends on the count of ready robots. When this count reaches the swarm the application. In the following, we concentrate on the case size (or another application-dependent threshold value), the in which two different targets are present in the environment. robots collectively trigger the next phase. Each target is marked by a colored light—one red, one blue. #A numeric id for the barrier virtual stigmergy The Spiri is equipped with a frontal camera that can detect 9 a target and its color. We assume that not all of the robots Experimental setup. Our experimental setup consists of a are capable of detecting the target, due to obstructions or square arena of side L in which N robots are scattered. The sensor range limitations. The uninformed robots must rely coordinates (x, y) of each robot are chosen uniformly from on the information shared by the informed robots to pick the U(−L/2, L/2).6 We define the robot density D as the ratio closest target. A possible solution to achieve this is employing between the area occupied by all the robots and the total area a virtual stigmergy structure, in which each robot advertises of the arena. To ensure comparable conditions across different its distance to the closest target and its color: choices of N, we keep the density constant (D = 0.1) and NUM_ROBOTS = 10 calculate L with: MAX_DISTANCE = 10000 # 100 meters r TARGET_VSTIG=2 NπR2 NπR2 # Create virtual stigmergy D = ⇒ L = , targetvstig= stigmergy.create(TARGET_VSTIG) L2 D # Get target data var mytargetdata = {} where R = 8.5 cm is the radius of a marXbot. We focus our if(camera.targetdata) # Can see the target directly analysis on two parameters that directly affect the properties mytargetdata= camera.targetdata that we intend to analyze: (i) The number of robots N, which targetvstig.put(id, mytargetdata) targetfound=1 impacts scalability; and (ii) The message dropping probability else { P , which affects robustness and accounts for an important, # Can’t see the target directly mytargetdata.dist= MAX_DISTANCE unavoidable phenomenon that influences the efficiency of mytargetdata.color= nil current devices for situated communication. For N, we chose mytargetdata.closest= nil targetfound= nil {10, 100, 1000}; for P , we chose {0, 0.25, 0.5, 0.75, 0.95}. } Each experimental configuration hN,P i was tested 100 times. # Keep monitoring neighbors until everybody # advertisesa distance Virtual stigmergy. To analyze the efficiency of virtual stig- while(not targetfound){ mergy, we devised an experiment in which the robots must targetfound=1 mytargetdata= neighbors.reduce( agree on the highest robot id across the swarm. This experi- function(rid, rdata, accum){ ment is representative of a wide class of situations in which a var d= targetvstig.get(rid) if(d != nil){ robot swarm must agree on the maximum or minimum value if(d.dist< DISTANCE_MAX){ of a quantity (e.g., sensor reading). As performance measure, if(accum.dist> rdata.distance+d.dist){ accum.dist= rdata.distance+d.dist we employed the number of time steps necessary to reach accum.closest= rid global consensus. We report in Fig. 3 the script we executed accum.color=d.color } and the data distribution we obtained. Our results indicate that, } up to P = 0.75, the number of time steps necessary to reach else targetfound= nil } consensus is affected weakly by N, and practically unaffected else targetfound= nil by P . Interestingly, for hN = 1000,P = 0.75i, consensus is return accum }, mytargetdata) reached in at most 15 time steps (a time step corresponds to # Advertise choice 0.1 s in our simulations). This positive result can be explained targetvstig.put(id, mytargetdata) # Neighbors done? by noting that, with P = 0.75, 3 messages out of 4 are lost; if(targetfound) barrier_ready() however, the uniform distribution of the robots ensures that, on } # Wait for others to finish average, each robot has more than 3 neighbors. Thus, messages barrier_wait(NUM_ROBOTS); can still flow throughout the network. The effect of packet # When we get here, everybody has pickeda target dropping is apparent for very pessimistic values (P = 0.95). Once the choice is done and the barrier is overcome, the Neighbor queries. To analyze the performance of neighbor robots form two swarms and move accordingly: queries, we devised an experiment in which the robots must sred= swarm.create(COLOR_RED) construct a distance gradient from a robot acting as source. sred.select(mytargetdata.color == COLOR_RED) This experiment is representative because the formation of sblue= swarm.create(COLOR_BLUE) sblue.select(mytargetdata.color == COLOR_BLUE) gradients is a fundamental coordination mechanism in swarm while(1) { behaviors. As performance measure, we employ the time sred.exec(function() { goto(direction()) }) sblue.exec(function() { goto(direction()) }) necessary for every robot to estimate its distance to the source. } The script and the data plot are reported in Fig. 4. The dynamics are analogous to virtual stigmergy: convergence Fig. 2b reports an ARGoS screenshot depicting the structure time depends weakly on N and is unaffected by P up to achieved by the robots after 2 minutes of simulated time. P = 0.75; for hN = 1000,P = 0.75i convergence is reached in a maximum of 13 time steps; for P = 0.95, convergence VI.EXPERIMENTAL EVALUATION times increase sensibly. Again, this is arguably due to the In this section, we analyze the scalability and robust- dense distribution of robots, which facilitates the circulation ness of the Buzz run-time. We focus our analysis on two of messages across the swarm, thus mitigating the effects of subsystems, virtual stigmergy and neighbor queries, because message dropping. of their key role in swarm coordination. The evaluation is conducted through simulations in ARGoS with the ground- 6When a coordinate choice causes physical overlap with already placed based marXbot robot [12]. robots, a new coordinate is picked until no overlap occurs. 10

Virtual stigmergy convergence times Neighbor query convergence times 60 40 10 Robots 10 Robots 35 50 100 Robots 100 Robots 1000 Robots 30 1000 Robots 40 25

30 20

Time steps Time steps 15 20 10 10 5

0 0 0.00 0.25 0.50 0.75 0.95 0.00 0.25 0.50 0.75 0.95 Packet drop probability Packet drop probability

# Executed at init time # Constant for infinite distance (500m) function init() { DISTANCE_INF = 50000. # Createa vstig VSKEY=1 # Executed at init time vs= stigmergy.create(1) function init() { # Set onconflict manager if(id == 0) vs.onconflict(function(k,l,r){ # Source robot # Return local value if mydist = 0. #- Remote value is smaller than local,OR else { #- Values are equal, robot of remote record is # Other robots # smaller than local one mydist= DISTANCE_INF if(r.data

[16] P. J. Landin, “The mechanical evaluation of expressions,” The Computer Journal, vol. 6, no. 4, pp. 308–320, 1964. [17] D. Gelernter, “Generative communication in Linda,” ACM Transactions on Programming Languages and Systems (TOPLAS), vol. 7, no. 1, pp. 80–112, 1985. [18] P. Grasse,´ “La reconstruction du nid et les coordinations inter- individuelles chez bellicositermes natalensis et cubitermes sp. la theorie´ de la stigmergie: Essai d’interpretation´ des termites constructeurs.” Insects Sociaux, vol. 6, pp. 41–83, 1959. [19] S. Voulgaris, D. Gavidia, and M. Van Steen, “CYCLON: Inexpensive membership management for unstructured P2P overlays,” Journal of Network and Systems Management, vol. 13, no. 2, pp. 197–216, 2005. [20] L. Lamport, “Time, clocks, and the ordering of events in a distributed system,” of the ACM, vol. 21, no. 7, pp. 558–565, Jul. 1978. [21] M. Quigley, K. Conley, B. P. Gerkey, J. Faust, T. Foote, J. Leibs, R. Wheeler, and A. Y. Ng, “ROS: an open-source Robot Operating System,” in ICRA workshop on open source software, 2009, p. 5. [22] C. Pinciroli, V. Trianni, R. O’Grady, G. Pini, A. Brutschy, M. Brambilla, N. Mathews, E. Ferrante, G. Di Caro, F. Ducatelle, M. Birattari, L. M. Gambardella, and M. Dorigo, “ARGoS: a modular, parallel, multi-engine simulator for multi-robot systems,” Swarm Intelligence, vol. 6, no. 4, pp. 271–295, 2012. [23] M. Dorigo, D. Floreano, L. Gambardella, F. Mondada, S. Nolfi, T. Baaboura, M. Birattari, M. Bonani, M. Brambilla, A. Brutschy, D. Burnier, A. Campo, A. Christensen, A. Decugniere,` G. Di Caro, F. Ducatelle, E. Ferrante, A. Forster,¨ J. Guzzi, V. Longchamp, S. Magne- nat, J. Martinez Gonzales, N. Mathews, M. Montes de Oca, R. O’Grady, C. Pinciroli, G. Pini, P. Retornaz,´ J. Roberts, V. Sperati, T. Stirling, A. Stranieri, T. Stutzle,¨ V. Trianni, E. Tuci, A. Turgut, and F. Vaussard, “Swarmanoid: a novel concept for the study of heterogeneous robotic swarms,” IEEE Robotics & Automation Magazine, vol. 20, no. 4, pp. 60–71, 2013. [24] R. Nagpal, “A Catalog of Biologically-Inspired Primitives for Engineer- ing Self-Organization,” in Engineering Self-Organising Systems, G. Di Marzo Serugendo, A. Karageorgos, O. F. Rana, and F. Zambonelli, Eds. Springer Berlin Heidelberg, 2004, pp. 53–62. [25] J.-C. Baillie, “URBI: towards a universal robotic low-level programming language,” in 2005 IEEE/RSJ International Conference on Intelligent Robots and Systems. IEEE Press, Piscataway, NJ, 2005, pp. 820–825. [26] R. O’Grady, A. L. Christensen, and M. Dorigo, “SWARMORPH: Mor- phogenesis with Self-Assembling Robots,” in Morphogenetic Engineer- ing: Toward Programmable Complex Systems, R. Doursat, H. Sayama, and O. Michel, Eds. Springer Berlin Heidelberg, 2012, ch. 2, pp. 27–60. [27] L. Mottola and G. P. Picco, “Programming wireless sensor networks: Fundamental concepts and state of the art,” ACM Computing Surveys (CSUR), vol. 43, no. 3, p. Paper ID 19, 2011. [28] R. Nagpal, “Programmable self-assembly using biologically-inspired multiagent control,” in Proceedings of the first international joint con- ference on Autonomous agents and multiagent systems part 1 - AAMAS ’02. New York, New York, USA: ACM Press, 2002, pp. 418–425. [29] K. Dantu, B. Kate, J. Waterman, P. Bailis, and M. Welsh, “Programming micro-aerial vehicle swarms with Karma,” in Proceedings of the 9th ACM Conference on Embedded Networked Sensor Systems - SenSys ’11. New York, New York, USA: ACM Press, 2011, pp. 121–134. [30] J. Bachrach, J. Beal, and J. McLurkin, “Composable continuous-space programs for robotic swarms,” Neural Computing and Applications, vol. 19, no. 6, pp. 825–847, May 2010. [31] M. Viroli, D. Pianini, and J. Beal, “Linda in Space-Time: An Adaptive Coordination Model for Mobile Ad-Hoc Environments,” Coordination 2012, LNCS 7274, pp. 212–229, 2012. [32] M. P. Ashley-Rollman, P. Lee, S. C. Goldstein, P. Pillai, and J. D. Campbell, “A language for large ensembles of independently executing nodes,” in Logic Programming, ser. LNCS 5649, P. M. Hill and D. S. Warren, Eds., vol. 5649 LNCS. Springer Berlin Heidelberg, 2009, pp. 265–280. [33] L. Mottola, M. Moretta, K. Whitehouse, and C. Ghezzi, “Team-level Programming of Drone Sensor Networks,” in SenSys ’14 Proceedings of the 12th ACM Conference on Embedded Network Sensor SystemsSys- tems. ACM New York, NY, 2014, pp. 177–190. [34] K. Birman and T. Joseph, “Exploiting virtual synchrony in distributed systems,” in Proceedings of the eleventh ACM Symposium on Operating systems principles (SOSP ’87), vol. 21, no. 5. ACM New York, 1987, pp. 123–138. [35] E. Gamma, R. Helm, R. Johnson, and J. Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 1995.