functional programming in spacerobotics.estec.esa.int/i-sairas/isairas2008... · functional...

6
Functional Programming in Space Andrew J. Harris 1 and Daniel Spoonhower 2 1 The Johns Hopkins University Applied Physics Laboratory 2 Carnegie Mellon University Abstract Embedded software systems form the backbone of cur- rent and future spacecraft designs. Developing robust software is critical to a successful mission. Advances in programming language research have provided soft- ware developers with sophisticated tools with which to build robust software. The long-term goal of our project is to demonstrate that these advances can be used to speed the development and improve the reliability of em- bedded space systems. We describe our efforts to build the infrastructure necessary to support high-level, func- tional programming for an embedded processor with a predefined path to space-qualified use. We demonstrate our present capability through development of a pro- totype power management system designed for use on autonomous mobile robot platforms. 1. Introduction Space systems are becoming increasing complex de- vices that make important mission-critical decisions and perform autonomous science. Thus not only is on-board software becoming more sophisticated, but successful missions are even more dependent on the software cor- rectness. High-level programming languages offer an opportunity to reduce the size of programs and to ease the verification of on-board software. In this work, we focus on functional programming languages, high-level languages with close ties to formal mathematics. We describe preliminary work on a compiler for a functional language, its associated runtime system, and example applications that target a stack-based proces- sor developed at the Johns Hopkins University Applied Physics Laboratory (JHU/APL). This stack-based pro- cessor, called SCIP, is specifically designed for use in spacecraft applications; the processor architecture was heavily influenced by both the FRISC processor, which flew on the Swedish Freja satellite as part of the Mag- netic Field Experiment, and by the Harris RTX2010 pro- cessor, which has flown on countless spacecraft includ- ing New Horizons, MESSENGER, ACE, and NEAR. The compiler, however, does not target this specialized processor exclusively; it also generates C source files that can be compiled with a standard C compiler. Our infrastructure supports a language based on Stan- dard ML [5, 7]. ML is a general-purpose programming language that promotes the construction of reusable and reliable software. Reuse is enabled through advanced language constructs such as parametrized types, partial evaluation, and higher-order functions. Reliability is enhanced through the nature of the programming lan- guage semantics: functional programming languages are closely related to a mathematical model of computation called the lambda calculus. One can therefore reason about programs in much the same way as one reasons about standard mathematics, and automated verification of functional programs is more tractable than verification of programs written in other (imperative) programming languages. Many embedded flight software systems have signifi- cant amounts of software without hard real-time bounds. This can include commanding software, autonomy soft- ware, and file management software. These domains are the focus of our current work. We believe that by programming this software in a high level functional programming language, we can build reliable, reusable software that also has reasonable performance on even the smallest embedded targets. To illustrate this, we discuss an embedded application developed using our tools that performs power management for a lunar rover prototype developed at Carnegie Mellon University. 2. Functional Programming In this section, we give a brief primer on ML. For a more complete description, see Ullman’s book [7]. The expression val x=y+3 defines x to be equivalent to y+3. Within the scope of this declaration, the value of x does not change; it is defined, not assigned.

Upload: others

Post on 23-May-2020

31 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Functional Programming in Spacerobotics.estec.esa.int/i-SAIRAS/isairas2008... · Functional programming languages allow software developers to develop software at a high level of

Functional Programming in Space

Andrew J. Harris1 and Daniel Spoonhower2

1The Johns Hopkins University Applied Physics Laboratory2Carnegie Mellon University

Abstract

Embedded software systems form the backbone of cur-rent and future spacecraft designs. Developing robustsoftware is critical to a successful mission. Advancesin programming language research have provided soft-ware developers with sophisticated tools with which tobuild robust software. The long-term goal of our projectis to demonstrate that these advances can be used tospeed the development and improve the reliability of em-bedded space systems. We describe our efforts to buildthe infrastructure necessary to support high-level, func-tional programming for an embedded processor with apredefined path to space-qualified use. We demonstrateour present capability through development of a pro-totype power management system designed for use onautonomous mobile robot platforms.

1. IntroductionSpace systems are becoming increasing complex de-

vices that make important mission-critical decisions andperform autonomous science. Thus not only is on-boardsoftware becoming more sophisticated, but successfulmissions are even more dependent on the software cor-rectness. High-level programming languages offer anopportunity to reduce the size of programs and to easethe verification of on-board software. In this work, wefocus on functional programming languages, high-levellanguages with close ties to formal mathematics.

We describe preliminary work on a compiler for afunctional language, its associated runtime system, andexample applications that target a stack-based proces-sor developed at the Johns Hopkins University AppliedPhysics Laboratory (JHU/APL). This stack-based pro-cessor, called SCIP, is specifically designed for use inspacecraft applications; the processor architecture washeavily influenced by both the FRISC processor, whichflew on the Swedish Freja satellite as part of the Mag-netic Field Experiment, and by the Harris RTX2010 pro-cessor, which has flown on countless spacecraft includ-

ing New Horizons, MESSENGER, ACE, and NEAR.The compiler, however, does not target this specializedprocessor exclusively; it also generates C source filesthat can be compiled with a standard C compiler.

Our infrastructure supports a language based on Stan-dard ML [5, 7]. ML is a general-purpose programminglanguage that promotes the construction of reusable andreliable software. Reuse is enabled through advancedlanguage constructs such as parametrized types, partialevaluation, and higher-order functions. Reliability isenhanced through the nature of the programming lan-guage semantics: functional programming languages areclosely related to a mathematical model of computationcalled the lambda calculus. One can therefore reasonabout programs in much the same way as one reasonsabout standard mathematics, and automated verificationof functional programs is more tractable than verificationof programs written in other (imperative) programminglanguages.

Many embedded flight software systems have signifi-cant amounts of software without hard real-time bounds.This can include commanding software, autonomy soft-ware, and file management software. These domainsare the focus of our current work. We believe that byprogramming this software in a high level functionalprogramming language, we can build reliable, reusablesoftware that also has reasonable performance on eventhe smallest embedded targets. To illustrate this, wediscuss an embedded application developed using ourtools that performs power management for a lunar roverprototype developed at Carnegie Mellon University.

2. Functional ProgrammingIn this section, we give a brief primer on ML. For a

more complete description, see Ullman’s book [7].The expression

val x = y + 3

defines x to be equivalent to y + 3. Within the scopeof this declaration, the value of x does not change; it isdefined, not assigned.

Page 2: Functional Programming in Spacerobotics.estec.esa.int/i-SAIRAS/isairas2008... · Functional programming languages allow software developers to develop software at a high level of

Similarly, we may define a function

fun double z = z ∗ 2

that defines double to be a function of one argument (z)that multiplies that argument by two. Like all expres-sions in ML, these expressions have types associatedwith them. A type constrains where an expression canappear and prevents many programmer errors by catch-ing invalid uses during program compilation. A colon (:)asserts the type of an expression.

x : int

means x is an integer, and

double : int → int

means double is a function from integers to integers.In functional programming, a function call is called anapplication and is denoted by the juxtaposition of thefunction and its argument or arguments. This expressionapplies double to x.

val w = double x

Let us define two more useful functions, compose andapp.

fun compose f g x = f (g x)

fun app f xs =case xs of nil ⇒ ()

| x :: rest ⇒ (f x;app f rest)

The compose function takes three arguments f, g, andx. While the types of these arguments are not explicitin the source code, ML compilers include a powerfultype inference system that can determine the type of any(valid) expression. Here, f and g must be functions asboth are applied to an argument. The only constraintplaced on the type of x is that it must match the argumenttype of g. The compose function applies f to the resultof applying g to x.

The app function take a function f and a list xs andapplies the function f to every element in xs. (The emptylist is written nil and new elements are added to thebeginning of a list with ::. For example, a list with oneelement a is denoted a :: nil.) As compose and app areused quite frequently, both are defined in the standardlibrary for ML.

2.1. Partial EvaluationThe compose function above requires three arguments,

and app requires two. Functional programming lan-guages permit programmers to apply a subset of thearguments to a function. Consider applying only twoarguments to the compose function:

val f2 then f1 = compose f1 f2

This new function, f2 then f1 is a partially evaluatedversion of compose. It represents a function that accepts

one argument and returns the value that compose wouldordinarily return if it were given all three arguments atonce.

Similarly for app, applying only one argument:

val double each = app double

results in a function that requires one more argument, alist. Once this argument is given, the function returnsthe value that app would return if it were given botharguments at once. We will use partial evaluation in thefollowing example that illustrates a list-based commandhandling system.

Let us assume that we have at our disposal two func-tions, insertHdr and sendCmd. The function insertHdrtakes a command as an argument and inserts a headeronto the command. The function sendCmd sends a com-mand through some implementation-dependent commu-nications channel.

We can partially evaluate compose using these twofunctions:

val cmdf = compose sendCmd insertHdr

This new function cmdf takes a command as an argumentand first inserts a header on it, then sends the commandover the communications channel.

In a similar fashion, we can partially evaluate app withthis function to create the command handling function:

val handleCmds = app cmdf

The function handleCmds is a partially evaluated appfunction with cmdf as defined above. The handleCmdsexpects a list of commands as an argument and willinsert headers on each of the individual commands andsend each to the communications channel.

In this example, we synthesize a complex functionusing readily available (and easily defined) functions.Partial application enables us to define each componentseparately (making each one available for reuse) andsuccinctly combine them.

2.2. Higher-Order FunctionsHigher-order functions are functions that take func-

tions as arguments or return functions as results. Bothcompose and app are examples of higher-order func-tions. The first two arguments of compose are bothfunctions, and when compose is partially evaluated, italso returns a function. When app is partially evaluatedwith a function, it returns a function that expects a singleargument in the form of a list.

2.3. Parametrized TypesIn the example above, we use compose and app in

specific ways to combine functions related to commands.However, the actual types of compose and app allowthem to be used more generally. Much like exam-ples using C++ templates or Java generics, composeis parametrized by the types of its function arguments,and app is parametrized by the type of elements the listpassed to it. The type given to compose is

Page 3: Functional Programming in Spacerobotics.estec.esa.int/i-SAIRAS/isairas2008... · Functional programming languages allow software developers to develop software at a high level of

compose : (b → c) → (a → b) → a → c

where a, b, and c are arbitrary types. This assertionstates:

• The first argument to compose is a function fromelements of type b to elements of type c. This isexpressed syntactically as b → c.

• The second argument is a function from elementsof type a to elements of type b. This is expressedas a → b.

• The third argument of an element of type a.

• compose returns an element of type c.

Any arguments to compose must satisfy these con-straints. Since the compose function doesn’t specifyconcrete types (such as int), and instead uses a, b, and c,which we call type variables, we say that compose has aparametrized type. Similarly, app has type

app : (a → unit) → a list → unit

This type expression states:

• The first argument to app is a function that takesas input elements of type a and returns nothing.(unit is the result type of functions that return no(interesting) results.)

• The second argument is a list of elements of type a.

• The app function returns nothing.

These two examples illustrate the concept ofparametrized types. The compose function will workwith any two functions where the domain of the firstfunction is the same as the range of the second. Theapp function will work for any function f and list xs aslong as the function operates on the type of elementscontained in the list.

2.4. Automated Memory ManagementFunctional programming languages automatically

manage all memory allocated and deallocated duringprogram execution. We see this as a definite advantage:developers don’t need to think about the details of mem-ory allocation. For example, map, a common and usefulfunction to generate a new list by applying a function fto each element of a pre-existing list l is defined as:

fun map f xs =case xs of

nil ⇒ ()| x :: rest ⇒ (f x) :: (map f rest)

Despite this function allocating a new list from one thatexists, there is no direct mention of a request to allo-cate memory for list cells; no linking list pointers. Thedeveloper is liberated from these details.

Memory allocation details are encapsulated in a run-time engine that is output as a product during the com-pilation phase as will be described later. The run timeengine is always the same. In a system where memory isdynamically managed, this approach can greatly increasethe robustness of the software. In a typical developmentenvironment without this technology, developers are incharge of managing details of memory allocation anddeallocation. Regardless of the skill and experience ofthe developers involved, it is possible for errors or in-consistencies to be introduced in the management ofdynamic memory. Automated memory managementprevents these types of problems.

3. The Compiler TechnologyFunctional programming languages allow software

developers to develop software at a high level of ab-straction. The environment distances developers fromworries pertaining to memory management and enforcesstrict type constraints on functions and expressions.

To use functional programming techniques in embed-ded software, a compiler is needed than can translatefunctional programs into code suitable for execution onan embedded target computer. Our work extends previ-ous work on an ML compiler [6] with two new backendsthat target SCIP and generic embedded platforms thatsupport the C programming language. An ML programcan be targeted to either of these platforms with identicalresults (barring, of course, performance differences be-tween the target architectures). We also include severalnew primitives specific to the instrument control domain.

3.1. A Sequence of TransformationsThe compiler performs a sequence of transformations

of the original source program. During the first phase,the source program is parsed and type-checked. Thetype-checking phase ensures that all expressions andfunctions satisfy the constraints expressed by their types.

After this first phase, the program is converted to aseries of intermediate languages. At each stage, complexoperations (e.g., function calls) are broken down into sim-pler operations and implicit steps (e.g., allocation of in-termediate results) are made explicit. Optimizations areperformed at each stage to improve the performance ofthe original program or to eliminate redundancies intro-duced by conversion from one intermediate language toanother. These optimizations are platform-independentand are carried over from previous work [6]. For thesake of simplicity, each conversion or optimization isimplemented as a separate pass over the program text.Our compiler currently includes 14 such passes. Despitethis, the power management application described inSection 4 can be compiled in less than a few seconds(including all library code used in the application) on acommodity desktop computer.

The penultimate phase of compilation is the trans-formation of the program into the continuation-passingstyle (CPS) language [1]. While a full description of thislanguage is beyond the scope of the current work, two

Page 4: Functional Programming in Spacerobotics.estec.esa.int/i-SAIRAS/isairas2008... · Functional programming languages allow software developers to develop software at a high level of

features the CPS language make it suitable to translationto platform-specific code. First, compound expressions(those requiring more than one primitive operation) arebroken down into simple statements and each interme-diate result is given a unique name. Second, the mecha-nisms required to implement control flow such as condi-tional branches, loops, and function calls are unified in asingle control construct.

During the CPS transformation, each program is con-verted into a set of basic blocks. Each basic block con-sists of a sequence of program statements with no inter-vening control flow: a basic block is always executedstarting with the first statement and ending with the last.Control never jumps to the middle of a block, nor doesit leave before executing the final statement.

This sequence of transformations is illustrated in Fig-ure 1.

3.2. C Language BackendWhen the C language backend is used, the source

program (in CPS form) is transformed into a set of Cprogram files, including one C file containing the run-time system. This set of C files can be compiled by atraditional C compiler into the native binary format ofthe target platform.

This notion of generating C code as output from thecompiler is not novel. Many current functional program-ming language compilers also use C code as an inter-mediate format. The advantage of the work describedin this paper is that the compiler toolchain is small andthe generated C code has no dependencies on librariesthat would be difficult to provide on an embedded targetcomputer. For example, the runtime system, which in-cludes the garbage collector, is comprised of only 400lines of C code.

3.3. SCIP BackendWhen the SCIP backend is used, the source program

(in CPS form) is converted into a Forth program. Thisprogram is then transmitted to the SCIP processor whereit is assembled into the native binary format of the SCIPplatform before execution. This backend is used forthe power management system application described inSection 4.

Implementing the SCIP backend presented severalchallenges. For example, Forth does not provide a nativejump instruction. Instead, it includes more structuredprogramming constructs such as conditional expressionsor iteration primitives. While we agree that program-mers should use these more structured control constructs,our compiler has already translated the structured con-structs of ML into a single unstructured construct: jump.To perform an operation similar to a jump, we use theForth execute word (a Forth “word” is a function). Atarget address is placed on the Forth data stack and theexecute word executes a procedure call (a fast operationin Forth) to that address. execute adds a return addressto the Forth control stack, so our compiler inserts thenecessary instructions to remove this return address after

each jump. (Due to the structure of the CPS code, thisreturn address will never be used.) This sequence ofoperations simulates a native jump instruction.

User-defined words in Forth may only refer to wordsthat have been previously defined. This is a problemsince basic blocks need to refer to each other, sometimesin a mutually dependent way. We remedy this by pairingeach basic block definition with a variable that containsthe address of the basic block. We dereference thisvariable when a basic block needs to refer to anotherbasic block.

3.4. The Runtime SystemAfter the compiler generates the target language out-

put, the runtime system is joined to the output. This rela-tively small segment of code contains memory allocationroutines and a stop-and-copy garbage collector [4]. Thistype of garbage collector has several useful attributes.First, it is a compacting collector. Requesting and releas-ing arbitrary amounts of memory will generally causememory fragmentation in embedded systems. This col-lector eliminates memory fragmentation by performing acompaction step during the collection phase. In addition,this type of collector can identify cyclic garbage. Othercollectors, notably some reference-counting approaches,cannot reclaim cyclic data structures.

It is important to note that the garbage collector is amodular component. The compiler generates code thatmerely requests memory; neither the compiler nor thecompiled code care how the garbage collector is imple-mented. Different garbage collectors can be substitutedinto the implementation if the need arises. The only con-straint on the collector implementation is the physicallayout of heap elements: the garbage collector must beaware of this structure to guarantee that memory is notprematurely reclaimed.

4. Application – Power ManagementTo demonstrate the feasibility of writing embedded

software in a functional programming language, we havedeveloped an embedded power management system foruse by mobile robots.

This power management system is designed to be con-tinuously powered, and during its operation, the powermanagement system provides measurements of powerconsumption for all attached electrical loads and sup-ports powering these loads on and off.

The power management system must be reliable: inmany cases it is the only device powered on (for example,during overnight hibernation). This need for reliabilityis well served by the particular set of hardware and soft-ware tools described in this paper. In this section webriefly describe the hardware platform and the softwareapplication that implements the main control softwarefor this power management system.

4.1. Power Management HardwareThe main computer running the software for the power

management system incorporates a SCIP processor as

Page 5: Functional Programming in Spacerobotics.estec.esa.int/i-SAIRAS/isairas2008... · Functional programming languages allow software developers to develop software at a high level of

Figure 1. A Sequence of Transformations

described earlier. The SCIP processor is implementedin VHDL and is amenable to insertion into current gen-eration space-qualified FPGA devices. We do not usespace qualified components for the implementation ofthe demonstration power management system describedhere, but instead use a readily available Xilinx-Spartan3E development board. This development board, calledthe “SCIP development board” for the remainder of thispaper, is clocked at 18 MHz and provides 512KB ofSRAM and several digital output pins and status LEDs.The prototype power management system in a test envi-ronment can be seen in Figure 2.

In addition to the SCIP development board, there arenumerous other components necessary to implementthe power management system. F.T. Bell NT-5 currentsensors are used to provide current consumption mea-surements, and an Atmel ATmega128 microcontrolleris used to read from the current sensors and write to thedigital output pins that control powering on and off theattached devices. The ATmega128 microcontroller alongwith the F.T. Bell current sensors and digital outputs aregrouped together and termed a “switching board”. TheSCIP development board is connected to the switchingboard through an RS-485 multidrop serial network.

The demonstration version of the power managementsystem has a single switching board, allowing it to mea-sure and control up to eight attached devices. However,the architecture of the power management system pro-vides the potential for multiple switching boards to beconnected to the RS-485 network, resulting in the abilityto monitor more attached devices. This is illustrated inFigure 3.

4.2. Power Management SoftwareAll of the software running on the SCIP development

board is written in a functional programming language.This software is compiled using the tools described inthis paper and is downloaded to the master controllerover a serial connection.

The software is composed of several parts:

• An implementation of the ROBIN packet-basedprotocol [2] for RS-485 networks.

Figure 3. Power Management Hardware Architec-ture

• Software for decoding packets received from theswitching board microcontroller. These packetsinclude the current consumption measurements andstates of the digital outputs.

• A time based action system that allows the powermanagement system to perform actions such aspowering on and off loads at specific times.

• A console interface to allow operators to interactwith the power management system.

4.3. General Purpose Software Components

In addition to the power management specific soft-ware, we have implemented several additional softwaremodules that assist in the construction of embedded ap-plications.

The first of these is a cooperative multithreading li-brary. New threads may be created using a functioncalled fork. Threads can relinquish the processor via ayield function.

The second of these is a FIFO queue library [3]. Mes-sage queueing systems are a powerful way to connectmultiple threads together to form a processing architec-ture where messages are passed between threads andeach thread performs a specific function upon receipt ofthe message.

Page 6: Functional Programming in Spacerobotics.estec.esa.int/i-SAIRAS/isairas2008... · Functional programming languages allow software developers to develop software at a high level of

Figure 2. Power Management System Prototype

Figure 4. Tasks and Software Libraries

We bind these libraries together with another librarythat supports the generation of tasks. Tasks are threadsthat wait on a message from a message queue and apply afunction to that message. Using this task library, one maycreate a task that waits on a message queue inboundPktQand calls function processFn on each received messageby writing the following:

taskCreate inboundPktQ processFn

The layering of these libraries is illustrated in Figure 4.

5. ConclusionFunctional programming languages provide powerful

tools that developers can use to create reliable, reusablesoftware. These languages liberate developers from deal-ing with details of memory management and enforcestrict constraints on functions and expressions as speci-fied by their types.

We have extended an existing compiler to allow em-bedded software to be written in a functional program-ming language. This compiler translates source code intoa suitable representation for execution on an embeddedtarget platform.

As a demonstration of the capabilities of our infras-tructure, we have developed a prototype power man-agement system for use on autonomous mobile robots,including a lunar rover prototype developed at CarnegieMellon University. The power management system isbased around a stack-based microprocessor developed

at The Johns Hopkins University Applied Physics Labo-ratory. This VHDL-based processor architecture has aclear transition path to insertion into radiation hardenedFPGA components.

As stated previously, the long-term goal of our projectis to demonstrate that advances in programming lan-guages, and functional programming languages in partic-ular, can be used to speed the development and improvethe reliability of embedded space systems. Future workincludes further development of libraries relevant to em-bedded software for highly autonomous space robots.

AcknowledgmentsThe authors would like to thank John Hayes, David

Kohanbash, John Kua, Jim Teza, Prasanna Velagapudi,and David Wettergreen for their advice and assistance.Tom Murphy VII helped with the extensions of the Hem-lock compiler described in this work.

References1. Andrew W. Appel. Compiling With Continuations.

Cambridge, 1991.

2. Brian Dean. ROBIN – ROBot Independent Network.http://www.bdmicro.com/code/robin/.

3. Rachel Harrison. Abstract Data Types in StandardML. Wiley, 1993.

4. Richard Jones and Rafael Lins. Garbage collection:algorithms for automatic dynamic memory manage-ment. John Wiley & Sons, Inc., New York, NY, USA,1996.

5. Robin Milner, Mads Tofte, Robert Harper, and DavidMacQueen. The Definition of Standard ML (Revised).MIT Press, 1997.

6. Tom Murphy, VII. Grid ML programming with Con-Cert. In ML Workshop 2006, September 2006.

7. Jeffrey D. Ullman. Elements of ML Programming.Prentice Hall, 1998.