ROSY: An elegant language to teach the pure reactive nature of robot programming

Hugo Pacheco Nuno Macedo Universidade do Minho & INESC TEC Universidade do Minho & INESC TEC Portugal Portugal Email: [email protected] Email: [email protected]

Abstract—Robotics is incredibly fun and is long recognized programming languages of the future [6]. It also carries a as a great way to teach programming, while drawing inspiring timely opportunity to transmit good design practices to new connections to other branches of engineering and science such as generations of programmers, that are receptive to novel lan- maths, physics or electronics. Although this symbiotic relation- ship between robotics and programming is perceived as largely guages as long as these allow to quickly build applications [7]. beneficial, educational approaches often feel the need to hide the As a step towards realising this vision, we advocate that underlying complexity of the robotic system, but as a result fail languages for teaching robotics to novice programmers shall: to transmit the reactive essence of robot programming to the • be compatible with standard robotic practices and seam- roboticists and programmers of the future. lessly connect to existing robotic infrastructures; This paper presents ROSY, a novel language for teaching novice programmers through robotics. Its functional style is both famil- • adopt a simple style and provide iar with a high-school algebra background and a materialization a pure cause-and-effect interface emphasizing the essence of the inherent reactive nature of robotic programming. Working of what it means to program a reactive system; at a higher-level of abstraction also teaches valuable design • rely on a general-purpose programming language with principles of decomposition of robotics software into collections of good tool support, so that advanced programming features interacting controllers. Despite its simplicity, ROSY is completely valid Haskell code compatible with theROS ecosystem. can be gradually introduced and acquired programming We make a convincing case for our language by demonstrating skills can naturally transfer to other domains. how non-trivial applications can be expressed with ease and In Section II, we argue that state-of-the-art languages fail, to clarity, exposing its sound foundations, and developing a web-enabled robot programming environment. some extent, to exhibit these characteristics. This justifies the proposal of ROSY, a simple yet powerful reactive program- I.INTRODUCTION ming language, presented in Section III. To ease adoption by novice programmers, ROSY is supported by a browser- Robotics, though a multi-disciplinary area of engineering based development environment, described in Section IV. As and science, shares a unique symbiotic relationship with an embedded domain-specific language, ROSY supports the computer science. As robots are increasingly put to solve more full power of higher-order functional programming offered by complex tasks, the more important it becomes to look carefully the host Haskell language, and is connected toROS, one of into the software that runs inside them, and in particular to the most popular robotic middlewares. The mechanics behind the programming languages that bring them to life. At the its implementation is presented in Section V. Section VI same time, programming a robot can grant computer science concludes the paper and leaves directions for future work. an often missing practical appeal, with a pedagogical potential

arXiv:1911.03262v1 [cs.PL] 8 Nov 2019 long recognized by computer science educators [1]. II.THEPEDAGOGYOFROBOTPROGRAMMINGLANGUAGES Various studies corroborate that robotics can indeed mitigate Programming robots is a particularly complex task, where the abstract nature of programming [2] and provide a more cre- one has to deal not only with the continuous and real-time ative environment for teaching programming concepts focused aspects of the physical world, but also with heterogeneous on hands-on problem solving [3] and for coding rich behavior architectures and complex communication paradigms. To min- using basic code structures [4], while still requiring reason- imize frustration of novice programmers, several pedagogical ing about relevant computational concepts such as software languages and approaches have been proposed over the years. modularity and communication [5]. This section reviews and discusses such related work. Yet, the richness of robot programming is synonym of its real-world complexity, which renders standard robotic A. The Robot Operating System frameworks unfeasible for use in a pedagogical setting and Robotic middlewares have been developed to ease the pro- has been motivating the proposal of various educational robot gramming of robots, abstracting hardware and communication programming frameworks. As the synergy between robotics details and promoting modularity. The Robot Operating Sys- and programming deepens, education is the perfect place tem (ROS) [8] is one such middleware, possibly the most pop- to experiment novel approaches that can shape the robot ular, and defines an architecture through which components, called nodes inROS, can communicate with each other by publishing to or subscribing from data sources, called topics. Other than that, individual nodes are programmed in general- purpose languages, typically C++ or Python. The popularity ofROS is fueled by a very dynamic community and an open- source policy that encourages code re-use, and a large package Fig. 1: A simple that draws a square. ranging from educational to industrial applications. As a pedagogical example, consider the well-known Turtle- Bot2 robot, whose controller is programmed inROS-powered Aside from discussions on whether block-based approaches C++. A main node controls its Kobuki mobile base publishing constitute “real” programming or their programming expe- odometry information and data collected from a set of sensors rience transfers to “real” textual languages [15], [16], and (collision, cliff and wheel drop sensors, plus a few buttons), with due exceptions such as [14], the vast majority of block- and subscribing to commands that control its (linear and based robot programming approaches adopt an imperative angular) velocity and the color of a set of LEDs.ROS allows mindset: primitive blocks execute individual predefined tasks, the definition of custom message types, from which source such as moving forward during a certain period of time code is automatically generated, and Kobuki defines such or for a certain distance; and combining blocks amounts to message types for the relevant events. Below is a minimal performing sequences of tasks. For example, the TurtleBot3 example of aROS application that subscribes to bumper can be programmed via a block-based interface in which we events and plays an error sound when a bumper is pressed: can write a block similar to the one from Figure 1. Albeit Snippet 1 (Play a sound on collision). simple, this example block hides away the reactive nature of ros::Publisher pub; the robotic system – all the sensor and command behavior is encapsulated within the black-box primitive blocks. void cb (const kobuki_msgs::BumperEventConstPtr& b){ if (b->state==kobuki_msgs::BumperEvent::PRESSED){ C. Functional reactive programming languages kobuki_msgs::Sound s; s.value= kobuki_msgs::Sound::ERROR; Reactive programming [17] is a pub.publish(s); } } organised around information producers and consumers, that can naturally bring out the intrinsically reactive nature of int main(int argc, char** argv){ ros::init(argc, argv,"play"); cyber-physical systems. A particularly active line of research, ros::NodeHandle nh; known as functional reactive programming (FRP) [18], focuses ros::Subscriber sub= nh.subscribe( "/mobile_base/events/bumper", 10, cb); on streams of information as the central reactive abstraction, pub= nh.advertise< kobuki_msgs::Sound>( and advocates a declarative approach to manipulate streams at "/mobile_base/commands/sound", 10); a high-level of abstraction supported by the pure equational ros::spin(); return 0;} reasoning of functional languages such as Haskell. Functional languages, as a form of algebra, are a good fit Even this minimal snippet is clearly non-trivial for novice for introductory programming [7], and many pedagogical FRP programmers, obfuscating the truly reactive nature of the approaches have been proposed for programming interactive controller. Besides having to get around advanced linguistic games and animations [6], [19]–[21]. Much classical work has features such as pointers, namespaces or templates, to manip- also proposed FRP for programming robots [22]–[24]. ulate topics the programmer must first explicitly subscribe In FRP, time is typically explicit and conceptually con- to bumper events and advertise that sound commands will tinuous; the execution of the system is then carried out by be published, considering the buffer size for incoming and sampling all streams synchronously at the rate of an external outgoing messages. The programmer must also reason about and global clock. The ROSHASK [25] HaskellROS library how topics are processed, by registering a callback on the promotes the modularity and expressiveness of FRP, while ros::Subscriber that will publish an error sound command remaining faithful to the asynchronous nature ofROS, by if a bumper pressed event is read, and when topics are adopting a more pragmatic approach centered on manipulating processed, in this simplest case using theROS spin primitive asynchronous topics in their entirety. that periodically processes callbacks for the queued messages. D. Towards a pedagogical robot FRP language B. Visual robot programming languages Despite the declarative nature of functional programming To tame the complexity of programming robots in fully- and the focus on events of reactive programming, the com- fledged general-purpose programming languages, a myriad binatorial FRP style is not beginner friendly, as it tends to of frameworks aimed at novice robot programming using swallow entire programs and resorts to advanced higher-order visual programming languages have been proposed [9]. Many features to separate reactive code (referring to entire topics) of these follow a block-based approach [10]–[14], where from non-reactive code (referring to individual events). predefined blocks with varied colors and edges can be put In this paper, we advocate that a toned-down FRP language, together like pieces of a puzzle to define a robotic controller. focused on individual events, represents a sweet spot of introductory robot programming. Making time implicit is a accelerate :: Velocity -> Velocity big win, as it liberates novice programmers from specific FRP accelerate( Velocity vl va) = Velocity (vl+0.5) va syntax and invites them to simply write pure functions. To Note that the same Velocity type has different input and retain some of the expressiveness of FRP, these functions have output meanings. This second accelerate controller is a then an intuitive interpretation as operations on data streams. function that repeatedly asks the robot for its current linear III.THEROSYLANGUAGE velocity, and commands the robot to increase it by 0.5 m/s. As our robot is moving forward, what if it hits a wall? We The ROSY language presents itself as a natural dialect for can naturally express multiple ROSY controllers that react to bringing robots alive using nothing more than plain mathe- distinct events. For instance, we can make the robot play an matics, while promoting good software design practices. In error sound when one of its bumpers is pressed, what will this section, we make a case for how its declarative nature happen on contact with a wall: allows creating robotic controllers in an intuitive and painless way, and informally present its defining features through a Example 3 (Accelerate and play a sound on collision). collection of examples of increasing complexity that illustrate play :: Bumper -> Maybe Sound how to control a TurtleBot2 robot. The types and associated play( Bumper_ Pressed ) = Just ErrorSound play( Bumper_ Released ) = Nothing fields used in the examples will therefore spell the standard KobukiROS message types. The ROSY website1 offers a accelerateAndPlay = (accelerate,play) modern integrated development environment, including an editor, help guides, and executable versions of all the examples In this example, we define a composite accelerateAndPlay shown in this section and more. controller by simply pairing together accelerate and play. For readers not familiar with Haskell syntax, all the func- Note that these two functions are not required to execute at the tions and operators not defined in this paper are standard same time: accelerate runs on periodic robot information, and their definition can be found at https://hoogle.haskell.org. though play waits for Bumper events. The two controllers will The documentation for respectively colored ROSY-specific execute in parallel, effectively combining both behaviors. To Pressed functions and types is available at the ROSY website. be able to play a sound only when a bumper is , and not Released, the play function may or may not produce a A. A ROSY primer Sound command. The play ROSY controller displays the same In ROSY, we can control a robot by writing pure functions behavior as theROS one encoded in Snippet 1, but here its that receive sensor information from the robot and react by reactive nature is clear from the type declaration. sending commands back to the robot. To make a robot move Even though the controller from Example 3 detects when forward at a constant velocity of 0.5 m/s, we can simply write: the robot hits a wall, it will continue to push against the wall, likely reaching a deadlock. With controllers as pure Example 1 (Move forward). functions that react to events as they happen, there is no easy move :: Velocity move = Velocity 0.50 way to make a controller remember some event in the past. This contrasts with traditional imperative robot programming main = simulate move languages, where we could use a global variable to, e.g., mem- The move function models our controller (where the Velocity orize when the robot has hit a wall and, from then on, change of the robot is separated into its linear and angular com- its behavior. Like other pedagogical functional languages [19], Memory ponents), and the main function is ROSY-specific syntax we grant ROSY controllers a notion of , that can be used to simulate our controller (that will be elided from now on). to, e.g., remember the robot’s moving direction: Still, the astute reader may fittingly ask “for how long are we Example 4 (Accelerate forward and backwards on collision). telling the robot to move forward?” Being ROSY a reactive programming language, the answer is not “once” or “for a type Hit= Bool certain period of time”, but actually “forever”. The intuition reverseDir :: Bumper -> Memory Hit is that a controller is a function that unceasingly listens for reverseDir _= Memory True inputs, and for each received input produces an output, what grants ROSY programs an implicit notion of time. In this accelerate :: Memory Hit -> Velocity -> Velocity accelerate( Memory hit) (Velocity vl va) = if hit move Velocity case, since receives no inputs, it will produce then Velocity (vl-0.5) va outputs at a fixed rate. else Velocity (vl+0.5) va To make things a bit more interesting, imagine that we want the robot to accelerate forward with non-constant velocity. forwardBackward = (reverseDir,accelerate) We can achieve this behavior by making sure to increase the In the above example, the controller hands over its memory robot’s velocity at each point in time: to accelerate, that uses it to determine in which direction Example 2 (Accelerate forward). to move. To reconcile memory with pure functional program- ming, controllers that wish to change the memory are expected 1https://haskell.lsd.di.uminho.pt/rosy to return it explicitly as an output. The Hit boolean memory -> (Velocity,Memory Mode) spinm@( Memory Stop) _= (Velocity 00,m) spinm@( Memory (Turn dir t)) now|t> now = (Velocity 0 (dir*vel_ang),m) spinm _= (Velocity vel_lin0, Memory Go)

randomWalk = (bumper,cliff,wheel,chgdir,spin)

The randomWalk controller encodes each part of the above Fig. 2: The random walker application in ROSY. specification as a separate function, sharing a memory Mode that encodes the different robot states. TheROS-style compu- tation graph is illustrated in Fig. 2, where nodes amount to the will be false by default, and changed to true by reverseDir defined reactive functions, and topics are either user-defined when a bumper event occurs. events or those provided for the Kobuki controller. The bumper and cliff functions change the LED colors, and set in motion B. Revisiting ROS controllers a change in direction. For greater modularity, they both emit For a more complete and realistic example, we now encode a new event of type ChgDir. The wheel function also changes the popular Kobuki random walker controller in ROSY, while the LEDs’ colors and sets the memory mode to the Stop state. trying to stay faithful to the C++ROS implementation 2: The spin function reads the memory mode, sets the respective velocity depending on the mode, and returns an updated mode. • On a bumper or cliff event, the robot blinks one of its LEDs orange and decides to change its direction; It receives the current time in Seconds to determine if the estimated turning time has elapsed. • On a wheel drop event, the robot blinks both LEDs red and decides to stop moving while the wheel is in the air; The most complicated behavior is left to function chgdir, that resolves ChgDir events to concrete Turn actions. To • When changing direction, it randomly decides on an angle between 0◦ and 180◦ and on a left/right direction. implement random behavior, it resorts to a Haskell standard Depending on a fixed angular velocity, it estimates how randomness generator of type StdGen to generate a random many seconds it shall turn; direction and angle, and reads the current time to calculate the time limit for the Turn action. This is a good example of • A sequential loop routinely performs the adequate action depending on the state of the controller. It commands the how the power of the full Haskell language can be gradually robot to either: go forward, stop moving, or turn in a unleashed as students tackle more advanced problems. 3 given direction for a number of seconds. Another popular Kobuki controller is the safety controller , that imposes stricter conditions on dangerous events. Its C++ Example 5 (Random walker). ROS implementation can be encoded in ROSY as a single data Mode= Go | Stop | Turn Double Seconds controller that reacts to bumper, cliff or wheel drop events data ChgDir= ChgDir -- change direction and cautiously decides on a new velocity to escape danger: vel_lin = 0.5 vel_ang = 0.1 Example 6 (Safety controller). safetyControl :: Either (Either Bumper Cliff) Wheel bumper :: Bumper -> (Led1,Maybe ChgDir) -> Maybe Velocity bumper( Bumper_ st) = case st of safetyControl = ... Pressed -> (Led1 Orange,Just ChgDir) Released -> (Led1 Black,Nothing) The code for safetyControl is conceptually simple, yet ver- bose as it explores multiple combinations of sensor inputs. We cliff :: Cliff -> (Led2,Maybe ChgDir) cliff( Cliff_ st) = case st of omit it in the paper, but it can be found at the ROSY website. Hole -> (Led2 Orange,Just ChgDir) The safety controller does not do much by itself, and it is Floor -> (Led2 Black,Nothing) typically deployed together with the random walker to limit wheel :: Wheel -> (Led1,Led2,Memory Mode) its actions as the robot roams around. Since both controllers wheel( Wheel_ st) = case st of publish possibly conflicting Velocity commands to the robot, Air -> (Led1 Red,Led2 Red,Memory Stop) the traditionalROS solution is to use a multiplexer that remaps Ground -> (Led1 Black,Led2 Black,Memory Go) topics and allows one controller at a time to command the chgdir :: ChgDir -> StdGen -> Seconds robot, according to a fixed set of priorities. -> Memory Mode ROSY chgdir _ r now = Memory (Turn dir time) We can define a general multiplexer in as follows: where M1 M2 (b,r') = random r Example 7 (Binary multiplexer, with priority over ). (ang,_) = randomR (0,pi) r' dataM= Start | Ignore Seconds dir = if b then 1 else -1 data M1 a = M1 a time = now+ doubleToSeconds (ang/vel_ang) data M2 a = M2 a spin :: Memory Mode -> Seconds mux :: Seconds -> MemoryM

2https://github.com/yujinrobot/kobuki/tree/devel/kobuki random walker 3https://github.com/yujinrobot/kobuki/tree/devel/kobuki safety controller -> Either (M1 a) (M2 a) -> Maybe (a,MemoryM ) muxt _ (Left (M1 a)) = Just (a,Memory (Ignore(t+d))) muxt( Memory (Ignore s)) _ |s>t = Nothing muxt _ (Right (M2 a)) = Just (a,Memory Start)

This binary multiplexer reads the current time t in Seconds and reacts to events either marked as M1 or M2, giving higher priority to M1 events by setting a time interval starting at t and ending at t+d (for a fixed duration d) during which all M2 events are ignored. We can then instantiate a safe random walker by remapping output velocities of the safety and random walker controllers with M1 and M2 tags and running a multiplexer in parallel: Example 8 (Random walker with safety controller). Fig. 3: The CodeWorld-powered ROSY environment. safetyControl :: ... -> Maybe (M1 Velocity) spin :: ... -> (M2 Velocity,...) muxVel :: ... -> Either (M1 Velocity)(M2 Velocity) At initialization, the startTurn reads the robot’s Orientation -> Maybe (Velocity,...) from its odometry information, and writes the desired final safeRandomWalk = (randomWalk,safetyControl,muxVel) Orientation to memory by adding or subtracting the re- ceived angle to the current orientation. The runTurn controller The complete refactored code for the safeRandomWalk con- will rotate the robot towards the desired orientation until troller is available at the ROSY website. the desired and current orientations are equal with a small C. Revisiting block-based languages error margin err, signalling when it is Done. The Done type allow returning additional information on task termination. Because controllers in ROSY run forever, they do not directly Returning nothing is achieved with the empty type (). lend themselves to performing sequences of instructions. For A similar task makes the robot move a fixed distance: concreteness, imagine that we want to command the robot to draw a square on the floor with its movement. In a visual Example 10 (Task: Move forward or backwards). robot programming language, this can be done by assembling data Direction= Forward Centimeters | Backward Centimeters a block like the one from Fig. 1. Even though such a block can be expressed in ROSY as a multi-stage controller that explicitly move :: Direction -> Task () encodes a state machine and reacts differently depending on move = ... the state4, it is useful to lend more structure to the language Since tasks can end, in contrast to controllers, we can now as the complexity of the controller grows. mimic the block from Fig. 1 in ROSY by using Haskell’s Like other FRP languages [22], ROSY introduces the con- monadic notation to sequence tasks in an imperative style: cept of tasks, as a combination of an initialization step and a continuous controller. The initializer sets up the stage Example 11 (Task: Draw a square). drawSquare :: Task () for the controller, that runs continuously until a predefined drawSquare = replicateM_4$ do terminating event occurs. For example, we can make the robot move (Forward 2) turn sideways by a fixed amount of degrees by writing a task: turn (Left 90) Example 9 (Task: Turn left or right). IV. ENVIRONMENT type Side= Either Degrees Degrees As well as striving to allow students to learn a “real” turn :: Side -> Task () programming language while freeing them from inessential turns = task (startTurn s) runTurn technical language details outside of how to control a robot, ROSY comes with a fully integrated development environment. startTurn :: Side -> Orientation -> Memory Orientation To really allow students to concentrate on the meaning of their startTurnso = case s of programs, ignoring deployment details, the ROSY environment Left a -> Memory (o+degreesToOrientation a) runs as a web application inside any modern web browser. Right a -> Memory (o+degreesToOrientation a) Figure 3 shows the ROSY environment in action. It is pow- runTurn :: Memory Orientation -> Orientation ered by Codeworld [20], a modern educational environment -> Either (Velocity)(Done ()) for writing graphical Haskell programs such as games and runTurn( Memory to) from = if abs d <= err animations. CodeWorld has been used in K12 schools for then Right (Done ()) else Left (Velocity 0(orientation d)) years, and supports a code editor with features such as syntax where d = normOrientation (to-from) highlighting, improved on-the-fly compiler error messages, extensive documentation or easy sharing of projects. 4Classical FRP frameworks tackle this general problem by designing advanced higher-order switching combinators over reactive functions, that are Another vital component of the environment is a visualizer expressively powerful but even less novice-friendly. that simulates, directly in the browser, how the controller are modelled as infinite monadic streams [18], i.e., monadic actions that produce the next value and a new topic: newtype Topic m a = Topic (m (a,Topic m a)) The Node monad manages TCP connections and internal buffers of published and subscribed messages. The following example node subscribes to two sensors, fuses them using the bothNew combinator (subsampling the faster topic), maps an action act :: (Sense1,Sense2) -> Cmd over each pair of Fig. 4: The ROSY architecture. sensor values, and publishes the resulting commands: n1 = do t1 <- subscribe"sense1" t2 <- subscribe"sense2" programmed by the student interacts with a robot in a fictitious publish"cmd"$ fmap act$ t1 `bothNew` t2 2D world. At the moment, this is tailored for a TurtleBot2 Internally, the asynchronous ROSHASK behavior is imple- placed in a tiled world made of floor, walls and cliffs. In mented on top of Haskell user-space threads, that are managed ROSY training sessions for K12 students that we have hosted by the Haskell runtime and much more efficient than sys- at the University of Minho, students could also deploy their tem threads. For instance, a typical publish implementation same code to control a real robot and perceive the differences launches a thread that infinitely samples values from a topic between a simulated and a real world. Enabling students and communicates them to theROS master; similarly, merging to simultaneously test their examples in simulated and real two topics is done by launching two threads that independently scenarios played an important role in teaching them the consume each topic and write to a common channel. importance of these differences and their influence on the Nodes can also be easily composed, for instance, we can design of approximate, event-driven robotic controllers. simultaneously install a handler that listens to and prints the V. UNDERTHEHOOD published commands to the command line: n2 = subscribe"cmd" >>= runHandler putStrLn Despite their simplicity, ROSY programs are fully com- patible with theROS infrastructure. Under the hood, the In the style of publish, runHandler is a general combinator ROSY language is implemented as an embedded domain- that launches a thread that will consume values from a topic specific language that provides an additional abstraction layer and execute some user-defined IO action: over the existing HaskellROS library. The ROSY environment runHandler :: (a ->IO b) -> TopicIO a -> Node () is also implemented in Haskell, by extending and specially tai- The composite node n1 >> n2 will communicate the com- loring the CodeWorld [20] environment to the ROSY language. mands produced by n1 both via rostcp and locally to n2. This includes a custom prelude that is imported by default, a custom code pre-processor to automatically derive necessary Haskell type class instances, and a custom graphical simulation B. Architecture of the robot. All the development source code is open-source The ROSY web environment, depicted on left side of Fig. 4, and freely available5. is designed according to the common Model–View–Controller A. Haskell ROS library pattern, with components implemented as separate ROSHASK controllers that communicate locally and form The ROSHASK library [25] enablesROS programming a single ROSHASK node. The model controller (loosely) within the Haskell ecosystem by supporting the deployment simulates a standard kobuki_node6 in a simulated world, rostcp ofROS client nodes that are compatible with the the view controller implements a simple 2D animation of communications protocol. ROSHASK fades the architectural the robot within the world, and the user controller represents boundaries betweenROS system and software components, by the node specified by the programmer. To support web-based lifting topics to first-class values and designing a collection of simulation and loosen the dependency onROS, we have FRP-style combinators to split, fuse and generally manipulate adapted the ROSHASK library to run without aROS master topics in a more expressive, modular and compositional way. server. This way, all the Haskell code needed to perform At its core, the library provides functions for subscribing a simulation is compiled via GHCJS into a JavaScript and publishing topics: application that runs directly in the client browser. subscribe :: String -> Node (Topic m a) publish :: String -> Topic m a -> Node () Alternatively to web-based simulation, ROSY programs can also be executed on a local machine (right side of Fig. 4), by The type variable m is a monad for actions with effects, connecting to aROS master server and operate a more realistic typically IO for interacting with a non-pure outside world, Gazebo simulator or a real Kobuki robot. We have tested both and a is the type of the subscribed or published event derived scenarios on Ubuntu 14.04 withROS Indigo and a TurtleBot2. from standardROS message type definition files. Topics

5https://github.com/hpacheco/codeworld-rosy 6http://wiki.ros.org/kobuki node C. Implicit stream programming Multiple Controllers are executed in parallel threads, and can The greatest design decision of the ROSY language is that be composed in sequence: instance (Controller a,Controller b) controllers have an implicit notion of time. This favors a sim- => Controller (a,b) where pler declarative style focused on which commands are issued controller (a,b) = controllera >> controllerb when events happens, without specifying how often subscribers and publishers interact with theROS world, and freeing D. Supporting user-defined events and memory programmers from common robotic programming details such ROSY also allows the declaration of user-defined data types as clocks, sampling rates or synchronization. Therefore, unlike for more modular intra-node communication. Since these need ROSHASK, that exposes a full-fledged API to manipulate topics not be bound toROS namespaces, every newly declared user- as a whole, ROSY controllers are less expressive in that they defined data type is by default a Sensor and a Command. This only consider a single point in time. is supported by a new UserNode monad that extends Node In ROSY, events are identified by their type. We define two capabilities with local type-indexed event buffers for user- type classes that internally bind ROSY types andROS message defined data types. namespaces to streams of subscribed sensors or published Since ROSY programs are by design pure Haskell functions, commands: there is no native support for common robotics design patterns class Sensor a where that global memory. It is nonetheless possible to emulate sensor :: Node (TopicIO a) global variables by publishing an initial event, and on every class Command a where command :: TopicIO a -> Node () update subscribing to current event and re-publishing its For example, the same Velocity type can simultaneously updated value. Even so, this pattern can be error-prone as express the act of getting the current velocity from the robot’s the programmer needs to be cautious about subscribing and periodic odometry data and the act of setting the desired publishing the “variable” the right number of times in order velocity by sending a command to the robot’s base: to keep it alive. This may also be problematic if more than instance Sensor Velocity where one controller is manipulating the same “variable” in parallel. sensor = subscribe"odom" To avoid these caveats, ROSY supports node-specific mem- >>= return. fmap (_twist. _twist)) ory, distinguishable through a type-level tag: instance Command Velocity where command = publish data Memory a = Memory a "/mobile_base/commands/velocity" We implement memory by extending the UserNode monad The ROSY language currently supports a fixed set of events with a transactional memory store, holding a global value for offered by the kobuki_node API. Extending support for every distinct type a. other robots simply requires defining new boilerplate Sensor In order to support transactional controllers, or more specif- and Command instances, as ROSHASK already supports many ically, be able to execute each controller thread as a single standardROS message types and allows deriving Haskell transaction, we must generalize our sensor and command types from customROS message files. interfaces to produce and consume topics of transactions7: To conciliate whole topics with point-wise controllers, we sensor :: UserNode (TopicIO (STM a)) command :: TopicIO (STM (Maybe a)) define another type class that implicitly lifts a function on -> UserNode (TopicIO (STM ())) individual values to a controller on streams of values: Sensor (Memory a) class Controller a where A returns a topic that repeatedly controller :: a -> Node () reads from the memory variable of type a, while a The stream semantics of the lifted controller is then inferred Command (Memory a) appends memory writes to a topic of from the function’s type signature: inputs correspond to sub- transactions, returning a new topic. The greatest change oc- scribed sensors, and outputs to published commands, e.g.: curs on commands that, unlike before, must be published instance (Sensor a,Command b) synchronously within the same transaction, meaning we can => Controller (a -> b) where no longer fork a topic and publish each side independently. controllerf = sensor >>= command. fmap f We can execute a controller thread by installing a handler Instances for composite types perform implicit stream pro- that atomically executes each transaction as a side effect: gramming. For example, a Controller that receives an input instance (...) => Controller (a -> b) where pair is fusing data from two sensors: controllerf = sensor >>= command. fmap f instance (Sensor a,Sensor b) => Sensor (a,b) where >>= lift. runHandler atomically sensor = liftM2 bothNew sensor sensor E. Sequencing tasks As another example, a Controller that returns possibly dif- ferent commands is splitting the output stream (using the tee In ROSHASK and other FRP approaches, topics are modelled ROSHASK combinator that duplicates a topic), and processing as infinite streams and topic handlers are program-long threads each type of commands independently: continuously waiting on and reacting to events. The fact instance (Command a,Command b) that the data flow graph, inferred from the wiring of stream => Command (Either a b) where commandt = do (t1,t2) <- teet 7The STM monad stands for Haskell’s software transactional memory command$ lefts t1 library. The Maybe type is a technical requirement for filtering values inside command$ rights t2 a transaction, since instances must not change the periodicity of the topics. combinators, is typically known statically, allows ROSHASK to [3] A. Druin, J. A. Hendler, and J. Hendler, Robots for kids: Exploring new register all subscribers and publishers with theROS master at technologies for learning. Morgan Kaufmann, 2000. [4] E. A. Gandy, S. Bradley, D. Arnold-Brookes, and N. R. Allen, “The node initialization, before starting to actually process data. use of LEGO Mindstorms NXT robots in the teaching of introductory In ROSY, a task is defined as an initialization action, a Java programming to undergraduate students,” Innovation in Teaching continuous controller, and a terminating event: and Learning in Information and Computer Sciences, vol. 9, no. 1, pp. 2–9, 2010. :: Command Controller task ( init, ctrl) [5] P. B. Lawhead, M. E. Duncan, C. G. Bland, M. Goldweber, M. Schep, => -> -> Task init ctrl end D. J. Barnes, and R. G. Hollingsworth, “A road map for teaching A controller issues termination via a special event type: introductory programming using LEGO Mindstorms robots,” SIGCSE Bulletin data Done a = Done a , vol. 35, no. 2, pp. 191–201, 2003. [6] A. Cleary, L. Vandenbergh, and J. Peterson, “Reactive game engine We also make Task a monad, so that programmers can programming for STEM outreach,” in SIGCSE. ACM, 2015, pp. 628– use monadic notation to sequence tasks. For composing two 632. [7] M. Felleisen, R. B. Findler, M. Flatt, and S. Krishnamurthi, “The smaller tasks in into a composite task, where the output of the TeachScheme! project: Computing and programming for every student,” first is passed on to the second, we may write: Computer Science Education, vol. 14, no. 1, pp. 55–77, 2004. task12 = do end1 <- task init1 ctrl1 [8] M. Quigley, K. Conley, B. P. Gerkey, J. Faust, T. Foote, J. Leibs, task (init2 end) ctrl2 R. Wheeler, and A. Y. Ng, “ROS: An open-source Robot Operating System,” in ICRA Workshop on Open Source Software, 2009. In this scenario, controllers no longer run forever: when the [9] J. P. Diprose, B. A. MacDonald, and J. G. Hosking, “Ruru: A spatial first task ends, we must uninstall the controller ctrl1 and and interactive visual programming language for novice robot program- ming,” in VL/HCC. IEEE, 2011, pp. 25–32. install a new controller ctrl2 for the second task. We have [10] G. A. Casan,˜ E. Cervera, A. A. Moughlbay, J. Alemany, and P. Mar- extended ROSHASK to support dynamic node configuration: tinet, “ROS-based online robot programming for remote education and each task runs within its own UserNode; publishers and sub- training,” in ICRA. IEEE, 2015, pp. 6101–6106. [11] I. Angulo, J. Garc´ıa-Zub´ıa, U. Hernandez-Jayo,´ I. Uriarte, L. Rodr´ıguez- scribers are registered at declaration time; tasks keep a fine- Gil, P. Orduna,˜ and G. M. Pieper, “RoboBlock: A remote lab for robotics grained control of launched threads, and all children threads and visual programming,” in exp.at. IEEE, 2017, pp. 109–110. are killed when exiting the parent UserNode8. [12] M. H. Masum, T. S. Rifat, S. M. Tareeq, and H. Heickal, “A framework for developing graphically programmable low-cost robotics kit for classroom education,” in ICETC. ACM, 2018, pp. 22–26. VI.CONCLUSION [13] D. Weintrop, A. Afzal, J. Salac, P. Francis, B. Li, D. C. Shepherd, In this paper we have presented ROSY, a new pedagogical and D. Franklin, “Evaluating CoBlox: A comparative study of robotics programming environments for adult novices,” in CHI. ACM, 2018, robot programming language that advocates a sweet-spot be- pp. 366:1–366:12. tween the expressiveness of FRP and the needed simplicity of [14] D. Marghitu and S. Coy, “Robotics rule-based formalism to specify an educational setting. As part of a computing summer camp behaviors in a visual programming environment,” in B&B@VL/HCC. 9 IEEE, 2015, pp. 45–47. for held at the University of Minho , in July 2019, we have [15] D. Weintrop, “Block-based programming in computer science educa- taught a 4-hour training session for K12 students on hands- tion,” Commun. ACM, vol. 62, no. 8, pp. 22–25, 2019. on robot programming in ROSY, with only two prior sessions [16] Z. Xu, A. D. Ritzhaupt, F. Tian, and K. Umapathy, “Block-based versus text-based programming environments on novice student learning of general programming in Haskell. From our perceptions, outcomes: A meta-analysis study,” Computer Science Education, vol. 29, students were able to comprehend the concepts and quickly no. 2-3, pp. 177–204, 2019. start programming the robot to perform simple tasks. [17] E. Bainomugisha, A. L. Carreton, T. V. Cutsem, S. Mostinckx, and W. D. Meuter, “A survey on reactive programming,” ACM Comput. Surv., In the future, we plan to provide further ROSY training vol. 45, no. 4, pp. 52:1–52:34, 2013. sessions and undergo empirical studies that can corroborate [18] I. Perez, M. Barenz,¨ and H. Nilsson, “Functional reactive programming, its practical value for learning programming via robotics. We refactored,” in Haskell. ACM, 2016, pp. 33–44. [19] M. Felleisen, R. B. Findler, M. Flatt, and S. Krishnamurthi, “A functional plan to improve the ROSY environment with more advanced I/O system or, fun for freshman kids,” in ICFP. ACM, 2009, pp. 47–58. simulation scenarios using, e.g., the Gazebo web client10 or [20] J. Breitner and C. Smith, “Lock-step simulation is child’s play (experi- remoteROS support similar to [10]. We also plan to explore ence report),” PACMPL, vol. 1, no. ICFP, pp. 3:1–3:15, 2017. [21] J. B. Almeida, A. Cunha, N. Macedo, H. Pacheco, and J. Proenc¸a, the design of novel novice-friendly interfaces that blend textual “Teaching how to program using automated assessment and functional and visual representations, and graphically combine visual Glossy games (experience report),” PACMPL, vol. 2, no. ICFP, pp. 82:1– blocks typical of imperative robotic approaches with graphical 82:17, 2018. [22] J. Peterson, P. Hudak, and C. Elliott, “Lambda in motion: Controlling data flow diagrams typical of advanced FRP approaches. robots with haskell,” in PADL, ser. LNCS, vol. 1551. Springer, 1999, pp. 91–105. REFERENCES [23] P. Hudak, A. Courtney, H. Nilsson, and J. Peterson, “Arrows, robots, and functional reactive programming,” in Advanced Functional Program- [1] D. S. Blank, “Robots make computer science personal,” Commun. ACM, ming, ser. LNCS, vol. 2638. Springer, 2002, pp. 159–187. vol. 49, no. 12, pp. 25–27, 2006. [24] I. Pembeci, H. Nilsson, and G. D. Hager, “Functional reactive robotics: [2] A. Oddie, P. Hazlewood, S. Blakeway, and A. Whitfield, “Introduc- An exercise in principled integration of domain-specific languages,” in tory problem solving and programming: Robotics versus traditional PPDP. ACM, 2002, pp. 168–179. approaches,” Innovation in Teaching and Learning in Information and [25] A. Cowley and C. J. Taylor, “Stream-oriented robotics programming: Computer Sciences, vol. 9, no. 2, pp. 1–11, 2010. The design of roshask,” in IROS. IEEE, 2011, pp. 1048–1054.

8Note that messages are not lost when transitioning between tasks, since a Node keeps global buffers of published and subscribedROS topics. 9https://www.uminho.pt/veraonocampus 10http://gazebosim.org/gzweb.html