Vehicle Platooning Simulations with Functional Reactive Programming
Bernd Finkbeiner, Felix Klein, Ruzica Piskac, Mark Santolucito
VVehicle Platooning Simulations with Functional ReactiveProgramming
Bernd Finkbeiner
Saarland UniversityGermany
Felix Klein
Saarland UniversityGermany
Ruzica Piskac
Yale UniversityCT, USA
Mark Santolucito
Yale UniversityCT, USA
ABSTRACT
Functional languages have provided major benefits to the verifica-tion community. Although features such as purity, a strong typesystem, and computational abstractions can help guide program-mers away from costly errors, these can present challenges whenused in a reactive system. Functional Reactive Programming is aparadigm that allows users the benefits of functional languages andan easy interface to a reactive environment. We present a tool forbuilding autonomous vehicle controllers in FRP using Haskell.
CCS CONCEPTS • Computer systems organization → Embedded and cyber-physical systems; • Software and its engineering → Embeddedsoftware; Real-time systems software;
KEYWORDS
FRP, Autonomous Vehicles
ACM Reference format:
Bernd Finkbeiner, Felix Klein, Ruzica Piskac, and Mark Santolucito. 2016.Vehicle Platooning Simulations with Functional Reactive Programming. In
Proceedings of 2017 1st International Workshop on Safe Control of Connectedand Autonomous Vehicles (SCAV 2017), Pittsburgh, PA USA, April 2017 (SCAV2017),
Autonomous vehicles are considered to be one of the most challeng-ing types of reactive systems currently under development [ ? ? ? ].They need to interact reliably with a highly reactive environmentand crashes cannot be tolerated. Life critical decisions have to bemade instantaneously and need to be executed at the right point intime.The development of autonomous vehicles and other cyberphys-ical systems is supported by a wide spectrum of programmingand modeling methodologies, including synchronous programming
Permission to make digital or hard copies of all or part of this work for personal orclassroom use is granted without fee provided that copies are not made or distributedfor profit or commercial advantage and that copies bear this notice and the full citationon the first page. Copyrights for components of this work owned by others than ACMmust be honored. Abstracting with credit is permitted. To copy otherwise, or republish,to post on servers or to redistribute to lists, requires prior specific permission and/or afee. Request permissions from [email protected].
SCAV 2017, Pittsburgh, PA USA © 2017 ACM. 978-1-4503-4976-5/17/04...$15.00DOI: http://dx.doi.org/10.1145/3055378.3055385 languages like Lustre [ ? ] and Esterelle [ ? ], hardware-orientedversions of imperative programming languages like SystemC [ ? ],and visual languages like MSCs and Stateflow-charts [ ? ? ]. Thequestion of which programming paradigm is best-suited to writeeasy-to-understand, bug-free code is still largely unresolved.In the development of other forms of critical software, outsidethe embedded domain, developers increasingly turn to functionalprogramming (cf. [ ? ]). The strong type system in functional lan-guages largely eliminates runtime errors [ ? ]. Higher-order func-tions like map often eliminate the need for explicit index counters,and, hence, the risk of “index out of bounds” errors. Functionalpurity reduces the possibility of malformed state that can causeunexpected behavior.While mathematical models of embedded and cyberphysical sys-tems often rely on functional notions such as stream-processingfunctions [ ? ? ], the application of functional programming in thepractical development of such systems has, so far, been limited.One of the most advanced programming language in this direc-tion is Ivory, which was used in the development of autonomousvehicles [ ? ]. Ivory is a restricted version of the C programminglanguage, embedded in Haskell. It provides access to the low leveloperations necessary for embedded system programming, but stillenforces good programming practice, such as disallowing pointerarithmetic, with a rich type system.Ivory does not, however, have an explicit notion of time. Itcannot deal directly with the integration of continuous and discretetime, which is fundamental for the development of a cyberphysicalsystem. For example, in a car, continuous signals, such as thevelocity or acceleration, mix with the discrete steps of the digitalcontroller.In this paper, we investigate the use of functional programmingin a domain where the interaction between continuous and discretesignals is of fundamental importance. We build a vehicle controllercapable of both autonomous vehicle control and multi-vehicle com-munication, such as the coordination in platooning situations.Our approach is based on Functional Reactive Programming(FRP) [ ? ? ]. The fundamental idea of FRP is to extend the classicbuilding blocks of functional programming ( e.g. monads, arrows, ap-plicatives) with the abstraction of a signal to describe time-varyingvalues. FRP programs can be exceptionally efficient. For example, anetwork controller recently implemented as an FRP program on amulticore processor outperforms any other such controller existingtoday [ ? ]. a r X i v : . [ c s . P L ] M a r CAV 2017, April 2017, Pittsburgh, PA USA Bernd Finkbeiner, Felix Klein, Ruzica Piskac, and Mark Santolucito
Figure 1: A screenshot of Haskell controlling the au-tonomous vehicle in the TORCS simulator.
We have built a library, Haskell-TORCS, to use FRP to controla vehicle inside a simulation. The library interfaces Haskell FRPprograms to TORCS, The Open Racing Car Simulator, an open-source vehicle simulator [ ? ]. TORCS has been used in the Simu-lated Car Racing Championship competition [ ? ], as well as otherautonomous vehicle research projects [ ? ? ? ? ]. Through Haskell-TORCS, the Haskell program has access to the sensors and actuatorsof the car, as well as communication channels between differentvehicles. Such a simulator is a critical component of modern au-tonomous vehicle research, especially towards the goal of safeplatooning algorithms [ ? ].We report on our experience with two case studies, one in whichwe implement a controller for a solo car, and another for multi-vehicle platooning using a communication channel between thecars. Our controller successfully navigates the TORCS preloadedtracks with reasonable speed and finesse while avoiding collisions(see Fig. 1). Furthermore, the case study illustrates that the func-tional approach indeed leads to elegant, easily understandable, andsafe code. The ability to run full simulations for solo and platooningvehicles is a critical piece to advancing the state of the art in usingFRP for autonomous vehicle control. The most common solution for the construction of reactive systemsin an imperative setting are call-back frameworks, embedded into aloop. The call-backs are either used to query the state of variables,or to change them. This imperative approach is well suited for rapidprototyping of small systems. However, tracing behaviors over timequickly becomes unmanageably complex for larger systems.Functional Reactive Programming instead introduces a concreteabstraction of time that allows the programmer to safely manipu-late time-varying values. The key abstraction is given by a signal ,providing the programmer with a simple type interface: type Signal a = Time → a For example, the type
Signal Image represents a video, while
Signal Steer captures a steering wheel operated over time. Tobetter understand how our library works, we now introduce thebasic concepts and terminology from FRP.
Listing 1: Basic Arrowized FRP syntax myDriver :: SF Image SteermyDriver = proc image → dobasicSteer <- turn -< imageadjustedSteer <- arr avoid -< (image , basicSteer)returnA -< adjustedSteer There are many types of FRP based on different abstractions fromtype theory. Expressive abstractions, such as monads, allow forcomplex manipulation of signal flows [ ? ]. However, for mostapplications they are far too expressive. We instead focus on anFRP library, Yampa, which uses the arrow abstraction, or so calledArrowized FRP [ ? ]. Arrows generally run faster and with little needfor manual optimization [ ? ], but are fundamentally less expressivethan a monadic FRP [ ? ]. This more restrictive language is in fact abenefit, as it makes it harder for the programmer to introduce errors.As we will see in the sequel, Yampa is still powerful enough to writecomplex controllers to drive an autonomous vehicle, or even tocommunicate with other vehicles. At the same time, the syntax isclear and accessible enough to make for an easy introduction to theFRP paradigm.Along with signals, Yampa also introduces the abstraction of a signal function (SF) . This is a transformer from one signal to another. type SF a b = Signal a → Signal b
Using the previous signals, imagine a type for a steering function,which operates based on a video stream, such as turn :: SF Image Steer
This function processes video and uses it to decide how to steer. Weomit an implementation, as the details of the data transformationare not relevant to the structure of the FRP code.Haskell provides special syntax for Arrowized FRP, which mimicsthe structure of control flow charts. The syntax provides a com-position environment, in which the programmer just manages thecomposition of arrow functions. Inputs are read in from the righthand side, and piped to the left hand side ( output <- function-< input ). A demonstration is given in Listing 1.The example introduces avoid :: (Image , Steer) → Steer a pure function that adjusts the basic steering plan based on theimage to avoid any obstacles. In Listing 1, this avoid function islifted to the signal level using: arr :: (a → b) → SF a b
The function turn is already on the signal level (has an SF type).Hence, we do not need to lift it.
To avoid obstacles on the road, we might write an avoid2 functionas shown in Listing 2, which requires two images to calculate theadjusted steering command. For this, we need a mechanism tomaintain state between each processing step. Two images would benecessary to filter noise in the image, or calculates the velocity of anapproaching obstacle. To implement it, we use an abstraction called
ArrowLoop to save the previous state of the image for the next ehicle Platooning Simulations with Functional Reactive Programming SCAV 2017, April 2017, Pittsburgh, PA USA
Listing 2: Using ArrowLoop to send feedback myDriver :: SF Image SteermyDriver = proc image → dorecoldI <- iPre null -< imagebasicSteer <- turn -< imageadjustedSteer <- arr avoid2 -< (image , oldI ,basicSteer)returnA -< adjustedSteer processing step. The syntax is presented in Listing 2. Intuitively, ArrowLoop gives us a recursive computation, as also indicated bythe rec keyword .The predefined function iPre takes an initial state, in our casean empty image, and saves images for one time step, each time it isprocessed. This way, we create a feedback loop that is then used inthe updated avoid function. At the same time, the rec keyword isused to denote a section of arrow code with mutual dependencies . TORCS, The Open Racing Car Simulator, is an existing open sourcevehicle simulator [ ? ] that has bindings for various languages [ ? ].We provide the first bindings for Haskell, and further extend thisinto a full library for multi-vehicle simulations. The library is anopen source library, called Haskell-TORCS, and publicly availableat https://hackage.haskell.org/package/TORCS. We now explainthe functionality provided by our library, and highlight the abilityof FRP to create modular and flexible controllers with clean codefor autonomous vehicles. To interface with Haskell-TORCS, a user must implement a con-troller that will process the
CarState , which contains all the dataavailable from the sensors. The controller should then output a
DriveState , which contains all the data for controlling the vehicle.This transformation is succinctly described as the now familiar signal function . The core functionality of Haskell-TORCS is cap-tured in the function startDriver , which launches a controller inthe simulator. This function automatically connects a
Driver toTORCS, which results in continuous
IO() actions, the output typeof this function. type Driver = SF CarState DriveStatestartDriver :: Driver → IO ()
The sensor and output data structures contain all the typical dataavailable in an autonomously controlled vehicle.
CarState includesfields like rpm to monitor the engine, or track to simulate an arrayof LiDAR sensors oriented to the front of the vehicle.
DriveState includes fields like accel to control the gas pedal, or steering to control the angle of the steering wheel. A full description ofthe interface is available in the Simulated Car Racing CompetitionManual [ ? ]. We elide the technical details for the purposes of this presentation and refer theinterested reader to [ ? ]. Without the keyword, there is an unresolvable dependency loop.
Listing 3: A complete basic controller in Yampa {- → dorecoldG <- iPre 0 -< gg <- arr shifting -< (rpm , oldG)s <- arr steering -< (angle , trackPos)a <- arr gas -< (speedX , s)returnA -< defaultDriveState{ accel = a, gear = g, steer = s }shifting :: (Double , Int) → Intshifting (rpm , g) = if| rpm > 6000 → min 6 (g + 1)| rpm < 3000 → max 1 (g - 1)| otherwise → gsteering :: (Double , Double) → Doublesteering (spd , trackPos) = letturns = spd * 14 / picentering = turns - (trackPos * 0.1)clip x = max (-1) (min x 1)inclip centeringgas :: (Double , Double) → Doublegas (speed , steer) =if speed < (100 - (steer * 50)) then 1 else 0
As a demonstration of the Haskell-TORCS library in use, we im-plemented a simple controller, shown in Listing 3. The code iscomplete and immediately executable as-is together with an instal-lation of TORCS. Our controller successfully navigates, with somespeed and finesse, a vehicle on track, as shown in Fig. 1 along witha video demonstration . The controller uses ArrowLoop to keeptrack of the current gear of the car. Although the gear is availableas sensor data, it is illustrative to keep track locally of this state.In general, the
ArrowLoop can be used to maintain any state thatmay be of interest in a future processing step. Additionally, noticeall of the data manipulation functions are pure, and lifted via thepredefined function arr .One major advantage of FRP is this separation of dependencyflow and data level manipulation. This abstraction makes it possibleto easily reason about each of the components without worryingabout confounding factors from the other. For example, if a pro-grammer wants to verify that the steering control is correct, itis semantically guaranteed that the only function that must bechecked is steering . Because of Haskell’s purity, this is the onlyplace where the steering value is changed. This significantly re-duces the complexity of verification or bug tracking in case of anerror. CAV 2017, April 2017, Pittsburgh, PA USA Bernd Finkbeiner, Felix Klein, Ruzica Piskac, and Mark Santolucito
Listing 4: Communicating between controllers request :: Double → Messagerequest dist =if dist < 3 then "faster" else ""adjustSpeed :: (Communications , Double) → DoubleadjustSpeed (comms , oldSpeed) =if any (map (== "faster") comms) then s + 10 else s
Thanks to functional languages’ exceptional support for paral-lelism, controlling multiple vehicles in a multi-threaded environ-ment is exceedingly simple. In our library API, the user simplyuses startDrivers rather than startDriver , and passes a list of
Driver signal functions “driving” together. In this way, we easilylet various implementations race against each other, or build a vehi-cle platooning controller. In the latter, the user can even extend theimplementation to simulate communication between the vehicles.Our library already provides a simple interface for simulatingcommunication between vehicles. In order to broadcast a messageto the other vehicles in the simulation, the controller simply writesa message to the broadcast field of
DriveState . That message isthen sent to all other vehicles as soon as possible, and received inthe communication field of the input
CarState .A fragment of communication code is given in Listing 4, to passmessages between vehicles. In this fragment, a vehicle checks ifa collision is imminent, and can request for the other cars in theplatoon to go faster and move out of the way. Every vehicle alsochecks if any other car has requested for the platoon to speed up,and will adjust its own speed accordingly. These functions can beadded to a controller, like the one in Listing 3, with little effort.We allow all vehicles in the simulation to communicate irrespec-tive of distance and with zero packet loss. However, users are freeto implement and simulate unreliable communications, or distanceconstraints.
Haskell-TORCS uses Yampa [ ? ] as the core FRP library, though itsstructure can easily be adapted to any other Haskell FRP library.TORCS uses a specialized physics engine for vehicle simulations,that includes levels of detail as fine grained as tire temperatureseffect on traction. When TORCS is used in the Simulated Car Rac-ing Championship competition [ ? ], each car is controlled via asocket that sends the sensor data from the vehicle and receives andprocesses the driving commands. So too, Haskell-TORCS commu-nicates over these sockets to control vehicles inside the TORCSsimulations.In addition to the core controller functionality, we have alsoaugmented Haskell-TORCS with the ability to test vehicle pla-tooning algorithms that utilize cross-vehicle communication. Thecommunication channels are realized via a hash map, using the Data.Hashmap interface, from vehicle identifiers to messages. Eachvehicle is given write permissions to their unique channel, whereall other vehicles have read-only permissions. The access is mutu-ally exclusive, which is ensured by Haskell’s
MVar implementation,a threadsafe shared memory library. This ensures that there willnever be packet loss in the communication.
TORCS has been proven to provide an expressive framework forthe research community [ ? ? ? ]. Notably, it has even been usedfor formal verification of platoons [ ? ? ]. None of these works haveused FRP as the language for the controller. With the assistance ofFRP, we build vehicle controllers in a principled way that allowsusers to manipulate sensor data in a transparent and well structuredenvironment.To the best of our knowledge this is the first FRP-based vehiclesimulator. Although there are many bindings to various vehiclesimulators, these tend to use imperative languages. For instance,TORCS allows users to directly edit the source code and add a newcar in C ++ . There are also TORCS bindings for Python, Java, andMatlab, which have been used in the SCRC competition [ ? ].FRP specifically has been proposed as a tool for vehicle control [ ?? ], where FRP was extended to prioritize functions for timingconstraints. However, due to the lack of a compatible simulator,the vehicle simulation never was implemented. FRP has also beenused for embedded systems [ ? ] and networking [ ? ]. The FRPnetworking library took advantage of Haskell’s multicore supportand significantly outperformed competing tools written in C ++ andJava.The videogame Grand Theft Auto (GTA) [ ? ] has also been usedto train image recognition software for autonomous vehicles [ ? ].While GTA is a professionally produced game with more attractivegraphics, it is proprietary software not designed for autonomousvehicle research. The only available sensor data are gameplayimages, which are a limited model for autonomous vehicles. UsingGTA as a meaningful control simulator would still be a valuabletool, but we leave this to future work. We have presented a library to write autonomous vehicle controllersin FRP that supports cross-vehicle communication. This work opensthe door for further research in using the powerful FRP paradigmfor building safer, more reliable controllers for one of the mostcritical applications in reactive systems.