Control of Walking Local control and real time systems

8 downloads 85 Views 9MB Size Report
May 1, 1984 ... Chapter 2 ...... nervous sys',cmresponse is composed of lwo parts: a portion associated with tt'.eswitching time of neurons and another p,,_tion ...
CMI'-CS-84-121

Control of Walking Local control and real time systems

Marc 1). Donner

Department

of(_"un_ptller Science

Carnegie-Mell(m Piltsburgh,

University

Pennsyl_ ania 15213

1 May 1984 Cop)right St_bmittcd t,:_Carncgic-Mcllon

(C) 1984 Marc Donner Uni_cr,,,it5 in partial

fulfillment

req_i: cmcnts fi_r the degrec of Doctor uf Ph itosophy.

of the

Ac knowledgements The number of people who have contributed to making this work possible or to my enjoyment of the process of doing it or both is truly stunning.

By tradition, only the author of a dissertation is honored

publicly; the rest of those who made it possible are repaid simply with private gratitude.

In token of my

gratitude, I mention here some of the people who have helped and hint at their contributions. The first five, Ivan Sutherland, Raj Reddy, Marc Raibert, Mary Shaw, and Rick Dill, served on my thesis committee. The rest are presented in no particular order at all. Ivan Sutherland designed and constructed the walking machine and offered me the opportunity to program it. He encouraged me when I decided to take a radical approach to the control problem.

He taught me the

meaning of courage and helped me rcfind it on the many occasions when I lost it. Raj Reddy opened my eyes to the idea that good scholarship need not be narrow, dry, or uncreative. Marc Raibert taught me that there are no boundaries or territories in science. When the interesting idea goes over there, follow it, even if you wander beyond the edges of your field. He also tried to instill a measure of scientific care and discipline in my work ... and almost succeeded, despite my best efforts. Mary Shaw spent a lot of her time discussing language design with me, patiently making the effort to understand the half-baked ideas I was scattering about and asking the carefifl questions that helped me understand what I was doing. Rick Dill taught me about intellectual hoqesty and good engineering. He has never failed to recognize and reward real achievement nor to ridicule silly pretension. James Gosling and I spent a lot of time eating and drinking and discussing IAfe, the Universe, and Everything.

Everything included my work, and James patiently suffered a great deal of earbending by me

about OWl_,and walking. Wes Clark took the effort to understand what I was doing and asked, in the most gentle manner imaginable, some of the hardest questions that I had ever avoided. He supervised the writing of the first walking program and provided the grapes that I consumed while doing so. Chris Stephenson provided intense intellectual challenges and a great deal of stimulating argument.

He

listened to me and made several important comments about the design of OWL. To Bill Wulf I owe my understanding of what a thesis is and, most importantly, the realization that OWL could be compiled instead of interpreted. Peter Capek, in addition to being one of the most flnpressive programmers of my acquaintance, provided challenge and inspiration and unfailing hospitality. A better fi'iend would be hard to come by. To the members of HA I owe lots of things, including many improvements in my programming style and quite a few enjoyable evenings spent reading code and drinking wine.

HA included Ed Smith, James

Gosling, Bob Sidebotham, Dave Rosenthal, lvor l)urham, Mike Kazar, Mahadev Satyanarayanan (Satya), David Nichols, and Larry Matthies, among others.

I must thank the house at 1014 [qemington for many hours of" diversion during the writing of my dissertation. When my brain began m overheat, I could always count on remodeling projects there to provide me with walls to tear down and other forms of useful destruction. Finally, special thanks go to Claude Shannon for the poem included as Appendix 4 and to Fred CaJ_Jsontbr the artwork from which the figure on the back of the title page is derived. Jim Kocher's help with videotaping was so important and so cheerful that it cannot be forgotten. The assistance that Jim McQuade provided with the 68000 C compiler was invaluable ... particularly the time he helped me patch a running program in order to salvage a day's worth of data. Mike Ullner wrote the 1/O roulincs that serviced the OWl. runtime system ... he provided some of the most reliable code I have ever dealt with.

l)avid Douglas kept the nmchine

functioning, bringing it back to life after broken legs a_d other disasters that I feared were terminal. _Iamaki kept the lab fiznctioning with a thousand difR-rent contributions.

Jenise

Sharon Burks, tlle CSD den

mother, was wonderful. Finally, my fi'iends who kept me happy and sane during my time in Pittsburgh:

Satish, Larry, James,

Robin, Bob, Dave, Satya, Jenise, Peg, Ed, Sarah, Carl, I.ynn, Ed, Nathaniel, Trina, and others. It wouldn't have been worth it without you.

Table of Contents

i

Table of Contents 1. Introduction

1

PART I: Machine and Animal Walking

5

2. Animal walking

7

2.1. Locality of control 2.1.1. The insect nervous system 2.1.2. lnscct experiments 2.1.3. The spinal cat 2.1.4. Reflexes versus patterns 2.2. Rear-to-front waves 2.3. Why insect gaits are not discrete 2.4. Summary 3. Other walking work

7 7 8 9 9 10 15 15 17

3.1. Static stability 3.2. I)ynamic stability 3.3. Summary 4. SSA walking machine 4.1. Mechanical overview 4.2. Valve settings 4.2.1. Hip control 4.2.2. Knee Control 4.2.3. Valve Switching time 4.3. Control computers 4.4. Hydraulic system 4.4.1. Pumps 4.4.2. Cylinders 4.4.3. Valves 4.5. Summary 5. Walking Program

18 20 21 23 23 26 27 29 30 30 31 31 32 33 36 37

5.1. 5.2. 5.3. 5.4.

Responsibilities of a walking program Inhibition and Excitation Walking program structure Row 5.4.1. Load 5.4.2. Recover 5.5. Service processes

37 38 41 41 42 43 45

ii

Control of Walking 5.5.1. Sensors 5.5.2. Trouble 5.5.3. Compensator monitor 5.5.4. Gather

PART 1I: Programming for Robotics and Control

46 48 49 50

51

6. Inadequacies of existing control structures

53

6.1. Concurrency 6.1.1. Time Slicing 6.1.2. Algorithmic languages 6.1.3. Production Systems 6.1.4. Concu rrent Programming I.anguages 6.2. Nondetenninacy 6.2.1. Concurrent programming languages revisited 6.2.2. Guarded Commands 6.3. The control of temporal behavior 6.3.1. Wait fi)r event 6.3.2. Complete task before event 6.3.3. The nature of loops 6.4. Real time performance 6.4.1. Pluribus "strips" 6.4.2. TOMAL 6.5. Summary 7. OWL language

54 54 54 55 57 58 59 59 60 60 62 63 63 63 64 65 67

7.1. OWL processes 7.2. Sequences 7.2.l. Asserting done and and alert 7.2.2. When and bothwhen 7.3. Concurrences 7.3.1. Handling of alert 7.3.2. Concurrent while 7.3.3. Synchronization and Mutual Exclusion 7.4. Named Processes 7.4.1. Scope and Parameter passing 7.5. Data 7.5.1. Data types 7.5.2. Declarations 7.6. Discussion 7.6.11.Sequences and loops 7.6.2. Concurrence and alternation 7.6.3. Distributed implementation 7.7. OWL Compiler and Runtime System 7.7.1. Compiler 7.7.2. Runtime system 7.8. Performance 7.9. OWL Syntax 7.9.1. Walking Machine primitives in OWL

69 70 7I 72 73 73 75 75 76 77 79 79 80 81 81 81 81 83 83 83 85 88 89

Table of Contents

PART 11I: Results and conclusions 8. Experimental Results 8.1. Local control 8.1.1. Walking 8.1.2. Five legged walking 8.2. Inhibition 8.3. Excitation 8.4. Comparison of OWL walking program with another walking program for the SSA machine 8.5. Summary 9. l)iscussion and Conclusions 9.1. Di,;tributed control 9.2. Scaling constraints on walking strategies 9.2.1. Why small things cannot balance 9.2.2. Why small animals don't have to balance 9.2.3. Prognosis for walking machines 9.3. Natural motions 9.4. Conclusions 9.5. Programming: real time and robotic systems 9.6. Directions for future research

iii

91 93 _ 93 94 94 96 99 99 102 103 103 104 104 105 106 106 108 108 109

Appendix A. Walking program code A.1. Overview A.2. walk.owl A.3. Load5.owl A.4. Drive7.owl A.5. Unload3.owl A.6. Recover6.owl A.7. waveinit.owl A.8. sensors.owl A.9. data.owl A.10. trouble.owl A.11. comps.owl Appendix B. Data

111 111 II 2 116 117 117 117 120 125 127 128 129 131

B.1. Description of data figures B.2. Data plots Appendix C. OWL Primitives

131 134 143

C.1. OWI, control primitives C.2. Compiler dircctives and declaration keywords C.3. Sensor primitives C.4. Valve command primitives C.5. 1/O primitives C.6. Misccllaneous primitives Appendix 1). The Trojan Cockroach

143 144 144 145 147 148 149

iv References

Control of Walking 151

Introduction

1 Welcome back my friends To the show that never ends. We're so glad you couM attend, Come inside, come inside. --- Emerson. Lake, and Palmer

Chapter 1 Introduction

Complex control tasks are best programmed by decomposition

into a number of asynchronous

communicating subtasks. Given such a decomposition, successft,1 implementation

depends on the

availability of a suitably expressive language. This thesis describes the results of research I conducted with the objective of designing and constructing control programs for the SSA1 six legged walking machine. This research makes two intimately interconnected contributions. The first is a decomposition of the walking task that exhibits a great deal of locality of control, relies on almost no global information, computation.

and requires little

The second is a programming language, OWl., specially designed to provide the real

time perfonnance and concurrency control needed to implement the walking program, qtle language made the walking strategy much easier to develop, and the strategy provided a guide for the design of the language.

Lift

_


.action pairs. The interpreter for a production system computes which of the Boolean conditions, or lefthand-sides, are true and then executes the associated actions, or right-hand-sides.

There is no

requirement that the programmer specify an order of execution for the productions, in fact there is typically no mechanism for specifying order of execution simply. Production systems provide an attractive way to specify concurrency since a large number of independent conditions can be active at once. The drawback of using production system languages is that all of the productions in a program are active at once so that the difficulty of writing and understanding such programs is as bad as for

56

Control of Walking

ProcesslState : = hlA; Pmcess2State : = InD; While true Do Begin Case ProcesslState lnA: Begin if Xa then A else t'tvcesslState:= lnB; End; InB: Begin if Xb then B else l'rocesslState : = lnC; End; lnC: Begin if Xc then (" else l'rocesslState : = lnA; End; Esac; Case Process2State lnD: Begin if Xdthen D else Process2State : = lnF,; End; InE: Begin if Xe then E else t'tvcess2State : = InF; End; Inl:': Begin if )fthen/;else I'rocess2State : = lnE; End; Esae; End Fig.re 6-2: Code to implement the two concurrent processes illustrated in 6-1 by alternating between the two processes.

concurrent programs written in algorithmic languages, Production systems provide total concurrency but they surrender the ability m specify easily several independent

threads of time dependent-

behavior. Time threads can be inu'oduced by introducing explicit state variables, as illustrated in figure 6-3 which illustrates the implementation system language.

of the two processes of figure 6-1 in a production

The bookkeeping and overhead, however, are as bad as for the same task in an

algorithmic language. In addition to these software engineering concerns, most available production system languages are interpreters and so the real-time performance is rather limited. Production system languages provide, in a certain sense, too much concurrency.

The result is a

software engineering nightmare in which the experienced prognmamer must develop a collection of de_ices to impose serial behavior and program state on small sections of code. [!xisting production system languages lack any real procedure abstraction, though in the concurrent programming context it ought to be called a process abstraction. _Ilaus it is impossible to write a production system in one place and insert its function into another production system by simply putting an utterance of its name into the code. In a sense the OWl_, language, described in Chapter 7, could be considered to be the imposition of a procedure or process abstraction on a production system language.

Ben Hyde

drew my attention to this when he pointed out that it would not have been difficult to implement OWL as a compiler that produced production language code [25].

Inadequacies of existing control structures

(Statel (Statel (Statel (Statel (Statel (Slatel

= = = = = =

lnA) lnA) InB) InB) lnC) Ing)

(State2 (State2 (State2 (State2 (State2 (State2

= = = = = =

InD) & (Xd) -> D; htD) & ( not )(d ) -> State2 : = InE; hal:) & ( 2"e) -> E; InE) & ( not Xe) -> State2" = InF; Inl,) & (._f) -> F; 1_1_)& ( not Xf) -> State2 := InD;

57

& (Xa) -> A; & ( not Xa ) -> Statel : = InB; & ( Xb ) -> B; & ( not Xb ) -> Statel : = lnC; & ( Xc ) -> C; & ( not Xc ) -> Statel := InA;

Figure6-3: Productionsystemimplementation ofthetwoconcurrentprocessesfromfigure6-1.

6.1.4. Concurrent Programming Languages Several languages, both real and paper, have been designed with the intent of providing some amount of concurrent programming capability.

Languages like Concurrent Pascal [5], AL [42], and

Modula [62] provide control constructs for specification of concurrent programs. Path Expressions [6]provide a notation for specifying synchronization for concurrent programs. Concurrent Pascal provides the CoBegin and CoEnd syntax that is exhibited in figure 6-1. The semantics of"the language specify that all of the blocks defined within the CoBegin ... CoEnd pair are to execute concurrently, with the concurrent block passing control on to the succeeding statement or block after all of the processes within the concurrent block have terminated.

No mechanism is

provided to permit one process to affect the flow of control within another process. AL is a language that was designed for robotics research, with its primary focus on coordinate transformation and manipulation.

AL's concurrency control structures, CoBegin and CoEnd, are

similar to those of Concurrent Pascal, which simply provides syntax for specifying that several blocks of code are concurrent.

The example shown in figure 6-1 can be easily expressed in AL or

Concurrent Pascal languages. condition->action

AL also provides 'condition monitors' that are actually simplified

pairs. A condition monitor waits on some global relation involving force or time,

though it may wait on a variable that can be set and reset by program control in some other concurrent process.

58

Control of Walking

Modula [62] also has thcilities fi_rsetting up concurrent processes, but all of file processes must be statically defined. If several identical instances of a process are required, multiple copies of the code must be provided.

There are no facilities fi_r dynamically changing the set of active processes.

Modula provides even less ability to control concurrency than Concurrent Pascal and AL, because all of its concurrent processes are statically defined. None of these languages provide powerful facilities, like preemption, for controlling concurrency.

What I mean by control here is the ability of some

processes to affect the execution of other processes without special communication agreed upon in advance between the specific processes in question.

The section on nondeterminacy

contains a

discussion of this.

Path Expressions [6] arc a rathcr exciting notation for describing concurrent exccution of programs because they permit the direct expression of permitted concurrency and of required scquentiality. The expression of concurrency is achieved with simple syntactic marking.

A list of procedures

separated by semicolon are to be executed sequentially, whiie a list of procedures surrounded by curly braces { ... } may be executed concurrently. separating procedures in a list by commas.

In addition, exclusion may be specified by

Path expressions were designed for the purpose of

specifying synchronization for operating system design tools, but fl_ey suggested to me that I could design a notation for expression and control of concurrent real time programs that could easily be impiemcnted.

In many ways the OWl, language, described in detail in Ch_pter

7, provides

expressive powcr similar to that of path expressions, though with more computation power. Path expressions are similar in power to most of the other concurrent programming notations; both lack the ability for one process to easily affect the execution of others.

6.2. Nondeterminacy A system that lacks detailed information about the world around it must treat that world as unpredictable and nondetrenninistic. For example, a walking machine without a terrain map and without any ability to peer at the ground in front of it must locatc the ground by touch. When it tries to put a foot down on the ground, several things might happen. The ground might be fiat enough so that the machine finds support at about the same leg extension as the last time it picked that foot up. There might be a hole or ditch whose bottom is too deep for the foot to reach without overextending the leg. The program controlling the machine in this case cannot know in advance which of the two outcomes will happen; so it must be able to handle both. When the alternatives are very simplc or the action can be postponed until the decisions are made,

Inadequacies of existing control structures the task of handling the nondeterminacy is not difficult.

59

When the task involves several complex

concurrent subtasks, then h:mdling unpredictab}e interactions with the environment takes on some of the character of a search.

It is in situations of this sort that most of the existing systems for

programming concurrent control fail.

6.2.1. Concurrent programming languages revisited One of the most powerfi_l constructs for enabling a program, to deal with nondeterminacy is a grouping of concurrent activities each of which is intended to continue asynchronously as long as some condition remains true. common constructs

I call this construct the Concurrent While.

used in in the walking program

It is one of the most

for enabling the system to deal with

unpredictable events. The concurrent while is not easily achievable in Concurrent Pascal because the CoBegin ... CoEnd construct has no preemption and terminates only after all of its component subprocesses have terminated, which requires that the programmer include explicit tests of some global condition in each subprocess.

For an example of the value of this construct, consider the

recovery of a leg in the SSA walking machine. As long as the leg does not touch the ground the hip joint should move through the recovery motions and the knee jeint should concurrently move through its recovery motions.

If the leg contacts the ground, the other processes should be

terminated, regardless of _vhere they are in their ev_Hution. If the leg finishes recovering without touching the ground, then so much the better. A particular virtue of the concurrent while is the fact that the scope of the termination condition is expressed lexically; there is no need to pass process names around.

Process name bookkeeping is

usually unpleasant and prone to error. In addition, when process names are first class objects 3 the.job of ensuring that the set of processes active is in a consistent state becomes more difficult.. The synchronization and control solutions involved are well understood, but the constraints imposed make using them unattractive. 6.2.2. Guarded Commands Another language design that provides some of the right semantics for the implementation of robot tasks is Guarded Commands [9]. The language introduced two new control constructs, the do ... od and the if ... ft. Each of the statements inside of one of these constructs is a guard->action

pair,

where the guard is a Boolean condition like in a production system. When a do ... od is active,

3A first class object is one that can be created and assigned to.

60

Control of Walking

statements with true guards are selected nondeterministically one at a time and executed until no more true guards remain. When an if ... fi is active, one of the statements with a true guard is selected nondeterministically and executed after which the if ... fi construct terminates.

While the intent of

the language is to provide a total ordering on events, it is to be done without binding the order of execution of pieces of code until execution time. This delaying of the binding of execution order is very important to the handling of nondeterminacy with reasonably sized programs.

If this were

extended to it_clude cop.currency, the language might be appropriate for robotics progrtunming. Hoare's Communicating Sequential Processes [20] is such an extension and it might have served quite well. However, there were a lot of features of CSI', like the elaborate input and output facilities, that seemed too cumbersome to be implemented effectively in a real-time system and so we discarded them. Ada tasks [13] may prove this soeculation to be false, but in the absence of an implementation there was no opportunity to evaluate their performance.

6.3. The control of temporal behavior There are several ways to enable a computer system's behavior to be influenced by events that evolve in l_'al time. In dais section I will discuss them and contrast their merits and weaknesses. There are two ways to express the interaction of a program with time. The first is to enable the programmer to specify pauses in sequential p,ograms, to assert, in effect, 'wait here u_,til such-and-so happens.'

'[he other is to let the programme_ require that the program adhere to some external

schedule, to assert, 'get this done by the time such-and-so happeus.' In the rest of this section I will examine these two regimes and discuss some of the design choices available in each.

6.3.1. Wait for event There are four clearly identifiable ways to achieve the 'wait here until Boolean becomes true.' The four mechanisms range over a spectrum from minimum resource utilization and difficult design, for interrupts, to heavy resource utilization and simplified design, for busy waiting. The four choices are: • Interrupts * Prediction and anticipation • Priorities • Busy waiting In the case of hardware interrupts, the Booleans are wired into the hardware of the computer

Inadequacies of existing control structures

6l

system. This mechanism provides the smallest latency, but it requires the best understanding of the nature of the problem in order to provide the "right" l_ooleans. Traps, or software interrupts, are slightly more flexible, but they require some code to test the Booleans and assert the traps.

Both

implementation choices require substantial knowledge of the structure of the solution imbedded in the system supporting the implementation.

Systems with lots of knowledge are less flexible and

create software engineering problems. Prediction and anticipation is a technique, provided in TOMAI. [15], whereby the programmer can specify to the t_Jntime system some rules for predicting future events. This permits the runtime system to set a timer for the nearest future event and then ignore all predicted events until the timer interrupt arrives. This tcc:hnique can provide latmmies almost as good as those for interrupt based systems, but it does require substantial analysis of the system in order to make good predictions. Nondeterminacy is only weakly accommodated with this technique. The third choice, assignment of priorities, is a mechanism provided in many systems to achieve a rough bound on latency. Tasks are assigned to one of several priority levels with different quantities of system resources assigned to each priority.

Thus a bound on latency can be asserted for each

priorit_ level depending on both the resources and the load assigned to that level. Systems using interrupts often use priorities to further o,.ganize the behavier and guarantee different latency bounds for different devices. TOMAI. implemented a system ot' task priorities that assigned the CPU to the highest priority task currently waiting. Priorities require less analysis of the problem than interrupts or prediction, but they provide poorer bounds on latency as well. Finally, busy waiting is the simplest and most expensive way to achieve control of temporal behavior. The runtime system requires no knowledge of the system it is implementing to achieve its best latency bound, but that latency bound is worse than that for the other mechanisms. Of course, a properly designed concurrent programming system that used busy waiting would not hang the entire processor while waiting on a single test but would rather keep a list of the pending I_ooleans to be scanned repetitively.

This technique is only suitable when the processor resources available are

substantia! compared to the demands of the task, since it is wasteful of CPU time.

62

Control of Walking

6.3.2. Complete task before event The 'get this done before that event' strategy is necessary when the rcsources available are restricted enough that they must be well managed in order to achieve the real time performance goals of the systcm. This strategy requires somc capability for analysis of the code, either mechanical or manual, and for predictio_ of events so that the scl_eduling can be accomplished.

With a schedule of events

and of the times of sections of tasks, a set of constraints can be asserted from which a schedule can be derived.

In the case that the proccssor resources are more _an adequate, the constraints can be

trivially satisfied.

No schedule

works

Some schedule

I

" Quantity

Figure 6-4:

works

Any schedule

works

I of

CPU power--_

Scheduling regions for a given task as a function of the amount of CPU throughput, available. too limited, no strategy or plan will enable the schedule constraints to be met. If the CPU powerful,

almost any strategy will meet the schedule

and analysis might _tisfy

constraints

trivially.

In the intermediate

If the CPU is is sufficiently

region,

planning

the constraints.

The continuum of quantit._ of compute; resources, say throughput, ranging from none to a very large amount is broken up into three regions for every task. There is a quantity below which no schedule will permit the satisfaction of of the task scheduling constraints. There is a quantity above vH'dchalmost any reasonable scheduling strategy, for example round-robin, will work trivially. In the middle is a region in which the techniques of plan based scheduling will be effective in finding some schedule that will work. This is illustrated in figure 6-4. I believe that the region where planning works is usually quite small. Moreover, changes in the definition of a task that starts in the marginal region could easily make the task more difficult, perhaps moving it into the unachievable region. The walking machine control system fell well inside the region in which round.-robin scheduling worked, so there was no need to explore the more complex problems ot-'plan based scheduling. With the increasing power and decreasing cost of computers, the easy scheduling region should be accessible to most systems. Taking advantage of a multiprocessor to get into this region should be particularly effective because breaking a system into a large number of autonomous subprocesses will facilitate load balancing among the processors.

Inadequacies of cxisting control structures

63

6.3.3. The nature of loops There is a fundamental difference between the way that loops are used in robotics and control programming and the way that they are used in computational programming.

Stated concisely, inner

control loops do nothing, while inner computational loops do something. A tight loop in a control program is typically responsible for monitoring the evolution of some value, permitting the program to proceed only after a Boolean function of that value changes. On the other hand, a tight loop in an algorithmic program typically iterates across some data. sm.,cture, performing some computation as it goes. A tight loop in an algorithmic program should run as fast as possible so as to process the data structure in the minimum amount of time. This is best done by minimizing the amount of time spent on each iteration, including the control.

In the presence of several different computations ,this

minimum is achieved by interrupting the tight loop as rarely as possible. For a control problem, however, one wants the sharing of the processor to result in minimum latency.

6.4. Real time perfornnance The earlier sections of this chapter bear on the design issues for a language for programming real-time concurrent :;ystems. This section concerns some of the implementation

issues that are

important enough to affect the semantics of the language. Adequate real-time performance produces i,,tency small enough for the task at hand.

Latency is the amount of time that elapses between two

successive opportunities for any specific process to receive CPU cycles and affect the behavior of the system. This section discusses the "strips" programming discipline developed for the Pluribus project and the TOMAI_ language developed for real time programming.

Certain features of both systems

are incorporated in the implementation of the OWL languaged, described in Chapter 7.

6.4.1. Pluribus "strips" The aim of the Pluribus project at Bolt, Beranek, and Newman [14, 45, 28] was to provide an extremely reliable parallel processor and software to serve as the next generation of Arpanet Interface Message Processors (IMP). In the process of writing the software for the system the workers there developed a programming discipline, called strips, that was intended to provide good real time performance and system reliability. The basic idea behind strips is that every program is composed of a number of segments or strips of

64

Contn)l of Walking

code, each of which is somehow guaranteed to run to completion in less than some small amount of CPU time. The Pluribus runtime system includes a table containing the names of all those strips that are currently pending. looping.

A strip may put names into this table,

lnsc_'ting its own namc is a way of

Inserting a single different name is a way of proceeding in sequence.

Inserting several

names is a way of forking several processes. One very powerful property of the strips discipline is that it provides a bound on the latency of file system. The bound on individual strip latency was checked by hand in the Pluribus system.

In the OWI_ compiler strip latency was bounded by

requiring that each strip be a basic block, a non-looping, non-blocking stretch of inline code. Each strip is an uninterruptable piece of code, so critical sections can be implemented easily. The purpose of the strips discipline was to implement a highly reliable multiprocessor system, not specifically to provide concurrency, but the strip model was also one of the best ways to implement real or simulated concurrency.

The chief defect of strips was that it was implemented as a

programming discipline and the bookkeeping

was done by hand.

The difficulty of doing this

bookkceping was so severe that it influenced the success of the Pluribus project as a whole.

6.4.2. TOMAL TOMAL

[15, 16,17]isa ]anguagc thatprovides allthepowcrthatisneededforrcaltimerobotics,

havingbeendesigned forrealtimemultitasking systemson smallprocessors. Itcontrols processes, whichmustbcstatically dcfincd atcompilctimcina fashion similar toModula,by cxplicit signals fromprogramstotheruntimesystemactivating anddeactivating otherprocesses. Taskscanhave priorities andthescheduicr givestheprocessor tothosetasks withhigherprioritics inpreference to thosewithlowerpriorities. A taskthathastowaiton an eventcandeclare totheruntimesysteman estimate ofhow longitexpects towaitsothattheruntimesystemcancompletely deactivate the process until thattimehaselapsed.

The underlying implementation of TOMAL

[16]iscompiler-gcnel'ated code-strips which are

essentially thesameobjects asthestrips ofthePluribus system.Thesearealsomuch thesameasthe basic blocks oftheoptimizing compiler world.TOMAL

wasthefirst systembascdon thecodestrip

conceptthatincorporated a compilerto do the bookkeepingforthe strips.The TOMAL programmerwasstill responsible formanagingtheprocess structure ofhisprogram, butthetaskwas made considerably easier by bundlingup theimportant interactions betweena programand the scheduler intolanguageprimitivcs. Concernwithovcrhcadledtostrongrestrictions on process structure: eachprocess mustbe instantiated by itscode.Itisnotpossible inTOMAL process byhavingsomeotherprocess simplyuttcr a name.

tocreate a

Inadequacies of existing control structures

65

Tomal's model of processes is more primitive than is appealing to mc because it puts a substantial burden on the programmer.

Its limitations for the walking task come with its static task structure:

separate instances of otherwise identical tasks require explicit separate copies of the code. Its notions of priority and declaration of estimates of latency are quite in advance of any similar systems. The decision for static structure was a choice that was carefully and consciously taken in the interest of overhead control.

One reason that they made this decision is that the implementation of reentrant

modules was rather expensive on the machines for which TOMAL was designed: microprocessors like the lntel 8080.

6.5. Summary This chapter has illustrated some of the ways that existing prt_gramming tools and models are not adequate for the programming of robotics and control tasks. Algorithmic languages bind execution order far too early, while production system languages bind it too late. Many tasks, while they cannot be expressed as single sequential programs, can be expressed as the concurrent combination of a moderate number of small sequential programs.

While there are a lbw languages that provide the

ability to write concurrent programs, most of them lack one or more important features.

Most

concurrent langqages restrict the quantity of concurrency by requiring all processes to be statically defined at compile time. None of the available concurrent languages provides simple mechanisms for one process to affect the flow of control of other processes, whether by suspending or terminating them.

In view of all of this, I present here a list of features that I believe are necessary for a good robotics control language. It is also clear that a new view of objects is needed, as pointed out by Ossher and Reid in [46], but that issue is not addressed here. This list of requirements drove the design of the OWI. language, which is described in Chapter 7. o Real time performance guarantees through ways to assert bounds on latency. Performance guarantees are necessary for any program that is used to control a physical system. • Ability to control temporal behavior: for example, wait on a Boolean. This is important for handling asynchronous or nondeterministic behavior. • Concurrency with lexical scoping. Without lexical scoping, the problem of managing the code becomes much more difficult. • Process abstraction: the ability to create process instances by uttering their names. This frees the programmer from having to know how a function is implemented in order to use it.

66

Control of Walking • Preemption: the ability to affect the flow: of control in other processes, for example the Concurrent While. This fl'ees the programmer from a large body of complex synchronization bookkeeping.

OWL language

67 The Owl and the Puss)_Cat went to sea In a beautiful pea-green boat. --- Edward Lear

Chapter 7 OWL language

OWL is a language designed as a solution to some of the inadequacies described in Chapter 6. [t was used to implement the walking program described in Chapter 5. This chapter contains a description of the language and of the compiler and runtime system that I designed and constructed to implement it. Before we dive into the details of the language, let's have a quick preview of the important features of the language. OWL programs are collections of processes appropriately decorated with markings that communicate the programmer's intentions about their order of execution. A process in OWl. may be any of four mings: a primitive statement defined in the language, a named process declared elsewhere by the programmer,

a sequence, or a conc¢_rrence. The two maj¢)r execution-order

abstractions in OWI. are sequences, lists of processes to be executed serially, and concurrences, lists &processes to be executed concurrently. The simplest kind of combination of OWL processes is the sequence.

A sequence is a list of

processes delimited by angle brackets ''. The processes in the list are to be executed in order, much as in traditional sequential programs. An OWL sequence is always an infinite loop. After the last process in the list has been executed, the head of the list is restarted.

Sequences are explicitly

terminated by execution of the done process, a primitive defined in the language. A sequence is a legitimate OWL process and may appear anywhere any other kind of process may appear. Figure 7-1 shows two OWL sequences.

< A; < B; C>; D> Figure 7-1: Two OWI_sequences. The first sequence is very simple, while the second one contains another sequence as a statement. An execution trace of the first sequence might look like A-B-C-A-B, while an execution trace of ',he second sequence might look like A-B-C-B-C-D.

68

Control of Walking

The concurrence is the only other kind of combination of OWI. processes. A concurrence is a list of processes delimited by square brackets '[' and ']'. The processes in the list arc to bc executed concurrently.

The concurrence terminates when all of the processes inside of it have terminated.

Concurrences are also legitimate processes and may appear in other sequences and concurrences. Figure 7-2 shows an example of a concurrence.

[ A; < B; C; D >; < E; F>

1 Figure 7.2: A concurrence with three subprocesses. A is a named process, while the other two are structural subprocesses, each a sequence.

A sequence or concurrence may be assigned a name and a list of formal and local parameters. Such a process, called a named process, may be invoked from sequences and concurrences in any place that other kinds of processes may appear. Except for side effects like time consumption, named processes and primitive statements provided by the language are indistinguishable. OWL provides a mccb.anism for preemptiorJ that permits processes to terminate competing concurrent processes.

Preemption is achieved only inside of concurrences.

Any subprocess of a

concurrence may request the termination of its siblings by signaling alert. Only one subprocess of a concurrence will have its alert request acknowledged and bc permitted to continue executing. All the other processes in the concurrence are terminated, including those requesting preemption but not receiving any acknowledgement.

A process is teraninated cleanly between statements when it is

preempted. In Chapter 4 I mention that the walking machine is big and powerful and dangerous. The primary reason for the inclusion of the alert mechanism was a desire fbr confidence in certain kinds of behavior of the walking program.

There are several hazards inherent in a walking strategy that

emphasizes a collection of independent

processes each controlling a single leg.

If some sort of

emergency arises that requires concerted behavior in order to prevent a disaster, it is desirable to ensure that no processes with conflicting goals remain active and capable of doing damage.

This

assurance requires more than cxclusion in the control of access to resources. It requires the ability to preemptively terminate competitors and take control of their resources, which is providcd by alert in OWL.

The facilities provided in OWI_ for control of concurrent

processes are necessary for

OWL language

69

implementing safe walking programs, but are not sufficient to make formal verification of safety feasible. They ease the task of designing, understanding, testing, and debugging programs. The alert mechanism makes it easier to say with some confidence that a program will never permit multiple processes to rnake conflicting operations on any actuator or other machine resource. That is not to say that any special protection is provided to ensure reasonable handling of resources, simply that it requires less bookkeeping by the programmer to develop some confidence in the behavior of the program.

7.1. OWL processes The fundamental control object in OWL is a process. OWL processes are not big expensive things like processes in traditional operating systems, they are simple inexpensive things that all live together in a single address space. Even primitive statements like assignments are processes in OWL, though of course there are optimizations in the compiler that take advantage of the simplicity of assignments and other such statements. Here is the syntax definition of all of the things that are processes: process :: = id[ id ( actuallist ) [ sequence [ concurrence]assignment An OWL process is one or more code strips, in the Pluribus or Tomal sense [45, 15], along with a small amount of state information.

The state associated with the process is any formal and local

parameters and the value of the alert attribute.

From the point of view of its control interactions an

OWL process is quite simple, having only three distinguished moments in time. One moment is initiation, when an instance of the process is created and becomes eligible to receive CPU time and other resources.

Another moment is termination, when the process decides that it is done and

announces that fact. Between initiation and telvaination comes the optional third moment when the process asserts its alert signal. The alert signal is a part of the handling of control of concurrency and will be described in greater detail in section 7.3. Figure 7-3 is an illustration of an OWL process. An OWL process may do things during its lifetime like make computations, send commands to actuators, or read sensors. As far as the process structure is concerned, these are side effects. A process may be a primitive, provided by the underlying runtime system, or it may be a composite, constructed from other OWL processes. OWL processes may be composed to make more complex processes in two ways: sequentially and concurrently. these work.

The next two sections describe how both of

70

Control of Walking

alert

/, initiate

I

"

done

Figure 7-3: An OWl, process Time increasesfrom left to fight. Between initiate and done the process is active. During its activetime it may assertits alelt attribute.

7.2. Sequences The simplest way of combining several OWL processes into a larger process is the sequence. An OWL sequence is the way that serial execution is specified. Here is the syntax for OWL sequences: sequence :: = < processlist > processlist :: = process ] processlist ; process Note that "" ave OWI_ syntax not BNF syntax here. An OWL sequence is a list of processes. The processes in the list are to be executed one at a time in the order of presentation in the text of the list, starting with the first one. Each process is activated when its predecessor tenninates.

The successor to the last process in the list is the first process; thus

each sequence is an infinite loop. Each sequence has a done attribute that may be set at any time by one of the subprocesses. The entire sequence terminates as soon as the subprocess that has set the sequence's done attribute terminates. Each sequence has an alert attribute as well. This attribute is unset when the sequence is first instantiated and may be set exactly once during the life of the sequence. Figure 7-4 illustrates the sequence whose code is < A; ,9; C >. The initiation of the composite process causes A, the first subprocess, to be initiated. The termination of A causes the initiation of B, and the termination of B causes the initiation of C. When C terminates it initiates A again. The entire composite process terminates when one of the subprocesses asserts the done attribute

for the

composite. In the figure this is illustrated by the dashed line from subprocess B to the done line of the composite.

OWl. language

Figure 7-4:

An illustration

ofa _quence.

71

The OWl, syntax for this process is < A; B; C>.

The alert signal for a sequence is asserted the first time any of the subprocesses asserts its own alert signal. Since the subprocesses of a sequence may repeatedly be terminating and being reinstantiated, the sequence could receive alert signals from its subprocesses many times. Only the first one is actually passed out as the parent's own alert signal. Explanation of the handling of th_ rest is best left for section 7.3. In essence, further alerts sent by subproccsses are ignored.

7.2.1. Asserting done and and alert Several special primitive processes are used to assert the done and alert attributes for a process. Each teixninates in the same activation that it is initiated, though it may delay the activation of its Successor.

• alert( Boolean ) - This primitive process evaluates the Boolean exprcssion passed as its argument. If the Boolean is true, then it asserts the alert signal for the parent process. If the Boolean is false, no signal is asserted. • done( Boolean ) - This primitive process evaluates its argument and asserts the termination of its parent process if the value is true. If the _alue is false, no signal is asserted. • both( Boolean ) - This primitive process asserts both done and alert for its parent process if the argument is true. Here are some examples of the use of these primitives in sequences. The first example, figure 7-5, shows a simple do-it-once process. The second example, figure 7-6, shows a simple loop, such as one might find in a computation. The first five instances of the done process terminate with no action. At the sixth instance the test ( i > 6 ) is true and the sequence is terminated.

72

Control of Walking

< A; B; C; done( true ) > Figure 7-5: A process that terminates after executing A followed by B followed by C exactly once.

6)>

Figure 7-6: A simple loop. Assuming that i is initialized elsewhere to 1, then this loop runs the process A six times.

7.2.2. _'hen and bothwhen In early walking programs the primary use of alert and both was from inside of simple wait loops. As a result, abbreviations for these common constructs were added as primitives.

Each of these

primitives is defined as being semantically identical to a piece of OWL code.

There is some

advantage to using the abbreviations because they permit the compiler to make optimizations and, in addition, t!-myare a bit easier to type. • _vhen( Boolean ) = = < done( Boolean ) >. This primitive waits until the boolean becomes true, at which poi_.t it terminates, thus permitting a sequence in which it might be embedded to proceed. It is important to remember that this process does not wait in a tight loop, but rather gets reactivated occasionally by the mn time system to recheck its Boolean This is true for all loops in OWL. ®bothwhen( Boolean ) = -= < both( Boolean ) >. This primitive waits until the Boolean becomes true and then asserts bolh alert and done, thus asserting the parent process's alert attribute and permitting the parent process to proceed. See section 7.3 for more about alert.

Figure 7-7 illustrates the use of the when primitive. In the exmnple the process A is initiated first. When A has tenninated, the process waits until the boolean Ready-to-proceed

becomes true, at

which point B is initiated. This kind of construct is suitable for the implementation of rendezvous and other synchroni:-ation operations.

< A; when( Ready-to-proceed); Figure7-7:

B; ... >

An example using the when primitive. Execution of the sequence Ready- to-proceed becomes u'ue, at which point it resumes with B.

pauses

until

the Boolean

OWL language

73

7.3. Concurrences Concurrences are the second and most important of the two ways of combining processes in OWL, the first being sequences. Concurrences provide the way to express asynchronous concurrent activity in OWL.

Here is the syntax for a concurrence: concurrence :: = [ processlist 1 processIist :: = process l processlist ; process When a concurrence is instantiated, each of the processes in the list is instantiated and proceeds asynchronously. Each subprocess of the concurrence may terminate itself, and the entire concurrence terminates after all of the subprocesses have terminated.

7.3.1. Handling of alert An arbiter associated with each concurrence mediates the preemption that is signaled by the alert attribute.

The arbiter is notified by each subprocess of the concurrence as soon as that subprocess

asserts its alert attribute.

The arbiter decides which subprocess asserted alert first and permits that

subprocess to proceed. All the other subprocesses in the concurrence are terminated. an illustration of a concurrent process.

Figure 7-8 is

The alert signal is not propagated up by concurrences,

contrary to the behavior of sequences. The rest of this section consists of some exmnples intended to illustrate the use of concurrences in OWL. These examples are important because normal alternation control structures like if ... then ... else and case are not provided in OWL. Figure 7-9 shows how a simple if-then-else alterqation can be achieved in OWI_. The C conditional expression (Boolean) ? exprtrue : exprraise is provided in OWL and was used occasionally in the walking program. Alternations of the forms shown in figure 7-9 were almost never needed. If OWL were to be developed into a production version, it is clear that an alternation construct :should provided. Figure 7-10 illustrates how one might implement a case statement in OWI_. Notice that the figure shows only the form that uses the alert signal to achieve the selection.

An analog to the second

example of figure 7-9 could be constructed, but in that style the test for each case would be of the

74

Control t)f Walking

/

C

Figure 7-8: Illustration of a concurrent process. Notice that it cannot signal alert. Its OWL syntax is [ A: B; C].

[ < botimhen( B ); Action - 1 >; < both_hen( not B ): Action- 2 >

1 { < done( not B ); Action- 1 >; < done( B ); Action-2 >

1 Figure 7-9: Two ways to implement if-then-else. The first relys on the arbitration provided by alert, though it is clearly not necessary for the Booleans shown in this illustration. The second relys on the fact that the loser of the two processes will ternainate itself, while the other will proceed to its action. Notice that there is a potential race cc,ndition with the second implementation. If the Boolean B becomes false, say, alter the sequence containing Action-2, then the sequence containing Action-1 might aiso be terminated, resulting in neither action being taken. "Ibis isn't a problem in the first implementation because even if both sequences tr)' to signal alert, the arbiter guarantees that only one will be permitted to proceed.

finTn done( Casel or Case2 or ... or CaseN ), rather ungainly to code and difficult to maintain. Case alternations of this form do appear in a few places in the OWL walking program.

Their primary

function is when "search" is necessary. Several processes are started up looking for various things and the first to find its condition satisfied signals alert, thus tmvninating all of its competitors, and proceeds with its action.

OWL language

75

[ < bothwhen( Casel ); Action- l >; < both_hen( Case2 ): Action - 2 >; < both_vhen( Case3 ); Action- 3 >; ..,

< bothwhen( CaseN ); Action- N >;

] Figure 7-10: An example of the implementation of a case construct in OWL.

7.3.2. Concurrent while The most common thing that the alert mechanism is used for in the walking program is a construct that is called the concurrent while in Chapter 6. It is a process that contains one or more active subprocesses plus a termination process. When the termination condition is satisfied, the termination process signals alert, terminating all of the active subprocesses, and then terminates itself. This construct is more attractive than a traditional while loop because each of the active subprocesses may involve waiting and other latency that should not be in series with the tcnnination

test. Figure

7-11 illustrates this usage. There are numerous other examples in the walking code contained in appendix A.

[ < both( Termination - test ) >; Activity- 1; Activity- 2; Activity- 3;

] l:igure 7-11: An example of the "concurrent while". The three busy subprocesses run concurrently until terminated by the alert a_sse:tedby the process that is watching Termination- test.

7.3.3. Synchronization and Mutual Exclusion The role of synchronization and mutual exclusion in robot control tasks is different from their role in operating system implementation

tasks, nonetheless, both can be achieved with OWL in a

reasonably straightforward manner. The way to protect a critical rcsource and ensure that only one process gets ownership at a time is to bundle the processes together in a concurrence and have each

76

Control of Walking

precede its entry to the critical section by an alert. The semantics of alert guarantee that only one process will bc permitted into the critical section. After that process has completed, it can terminate and the concurrence can bc rcinstantiatcd, thus again opening the resource for contention.

Notice

that this is not exactly right tbr operating system implementation, since it rcquires the termination and reinstantiation of all the contending processes.

It is also possible to create a monitor for a

resource by constructing a concurrence containing a subproccss for each potential contender and have the subprocess that receives the acknowledgement

to its 2dcrt then acknowledge the process

whose requests it is handling. If one were to use OWL for a lot of tasks of this sort, it might be better to add some facilitics to the language for that purpose.

7.4. Named Processes One of the most powerful features of OWL is the process abstraction capability. This enables the programmer to give a name to the code for a process and then to create instances of the process by simply putting inw)cations by name into other process code. Here is the syntax for process declaration: processdefinition :: = define idformals locals : action aclion :: = sequence Iconcurrence formals :: = (formallist ) I e formallist :: = formal Iformallist, formal formal :: = parmpassing id I parmpassing id [ literal ] parmpassing:: = var Ivarstar I val Ivaistar I e locals :: = , local ( locaIlist ) I e locallisl :: = local[ localtist , local local :: = idl id[ literaI] l id = actual A named process establishes a scope and permits the same code to bc instantiated in multiple processes. It is important to remember that these are not process identifiers in the traditional sense. A process identifier is a name by _hich you may refer to an existing process after you have created it, with operations like suspend, activate, abort and so on permitted on the process identifier.

Figure

7-12 illustrates the definition and use of a named process. Note that OWL named processes are

OWL language

77

definefoo( arg ), local( i ): { Here is the code for the process } < { It is a sequence } i = arg; {i is local to this process, arg is the parameter } > and here is an example of its use:

i = 17; { The canonical random number } foo( 3 * i ); { Of course, the i inside of foo is different } .,.

Figure 7-12: An example of the definition and use of a named process. In this example, the variable name i is defined both in the environment from whichfoo is called and inside offoo itself.

procedural, not functional, in nature.

An OWI_ process communicates

results to its invoking

environment with var parameters.

7.4.1. Scope and Parameter passing Scope

rules

and parameter

passing mechanisms

are

very

important

to a

language's

comprehensibility and usability. Scope rules determine what identifiers are nmaningful within any given procedure or process, while parameter passing rules govern how and when information is communicated between processes. Scope rules in OWL are simple and limited, similar to those in C or Fortran. The only identifiers visible within a named process are its formals and locals plus whatever globals have been declared. All processes that have been defined are considered to be globally visible, as there is no nesting of process definition. Parameter passing in OWL is quite a bit more complicated than for algorithmic languages because most interprocess communication is done through formal parameters.

There are four distinct

parameter passing mechanisms in OWL, two of which, value and value-result, are much like similarly named mechanisms for algorithmic languages.

The other two, called valstar and varstar, are

generalizations of the first two to the needs of concurrent processes in OWL. Note that the OWL syntax for designating value-result parameter passing is vat, different from conventional usage in which var is generally synonymous with passing by reference.

78

Control of Walking

The first and default parameter passing mechanism is by value, denoted val. The invoked process receives the value of the variable as seen by the invoking process at the instant of invocation.

No

subsequent change to the variable that was the source of the parameter is visible to the process, though it may alter its copy. The second mechanism is value-result parameter passing, available with the var parameter passing declarator. A formal passed in this manner has its value copied in at the time of instantiation of the process and copies the local value back to the original source variable after the process terminates successfully.

Note that if the process is terminated by the action of an alert asserted by some

concurrent sibling, it does not get a chance to write its var parameters out.

[ Watch( i ); < ...; i = ( Expression ); ... >

l Figure 7-13: An example of a concurrent while that cannot terminate if only value and value-result parameter passing are provided. Watch is a subprocess that signals alert when i indicates _at the concurrence should be terminated. Since the value of i is passed in at the instant of instantiation of Watch and never gets updated with later values from outside, Watch can never terminate the loop.

Passing by value and by value-result, while adequate for many algorithmic languages, are not sufficient for concurrent programming.

An example of the way in which these two mechanisms are

inadequate is provided in figure 7-13. This is a "concurrent while" in which the termination process is a named process and the variable being watched is passed in as a parameter.

Since the process sees

no changes to the external copy of i it cannot observe when the value that is being manipulated by the other process achieves a terminating value. Introduction of reference parameters could solve the invisibility problem described above, but it introduces several difficulties.

The first difficulty is that in a multiple processor environment with

message passing communication passing by reference is complex and expensive. This is because it requires that the address spaces be merged by hardware or software. The second difficulty is that reference parameters introduce accessing delays that are harmful to real time performance because each access requires a round trip communication.

It is often the case in control problems that it is

better to have a "pretty good" value right away rather than to pay the cost of going and getting the "best" or most up-to-date value.

OWL language

79

The first additional parameter passing mechanism that OWl, provides is called valstar. It is similar to wd except that each time a process or any of its structural subprocesses receives any CPU time, which I call being activated, copies are made of all valstar parameters fi'om their sources outside the process. The problem described earlier with the code in figure 7-13 is solved if the definition define Watch ( varstar arg ): ... is used, for then each time that the instance of Watch was activated, it would get the current value of its argument written into its local copy. The other additional parameter passing mechanism is called varstar and it is the analogous extension of var. Thus, each time a process or any of its structural subprocesses is activated the local copies are written from the source copies just before the code begins to execute and then the source copies are written with the local value at the end. These semantics guarantee that, in a concurrence, the subprocess that successfully preempts its siblings gets the privilege of making the final writes to any varstar parameters. Alert can also protect the final value of a vat parameter. The following table shows the complete set of possible choices for parameter passing mechanisms for OWL assuming that the only distinguishable instants in the life of an instance of a process are (1) initiation -

the first time it is activated, (2) the beginning and end of each activation, and (3)

termination - the end of the last time it is activated. Reads are done at the beginning of activations, Writes done at the ends of activations. Read Never At initiation Every activation Never At initiation Every activation Never At initiation Every activation

Write Never Never Never At termination At termination At termination Every activation Every activation Every activation

l)escrip tion l.ocal variable VAL parameter VALSTAR parameter (Function result- use VAR) VAR parameter (not provided in OWL) (Achieved with VARSTAR) (Achieved with VARSTAR) VARSTAR parameter

7.5. Data 7.5.1. Data types The only data types provided in OWL are integers and simple linear arrays of integers. important data structure design and implementation

The

issues in OWl, concern scope, parameter

passing, and how to keep shared data updated without relying unnecessarily on global variables.

80

Control of Walking The operations provided are assignment and expression evaluation, _'ith expression syntax taken

from the C progran3ming language

129]. Notice that square brackets 'T' and "]" arc merloaded in

OWl. because they are used for array indexes, as in C, and for concurrent groups of OWl_ processes. Similarly "" are merloaded,

being used to delimit sequences, much as in mathematical

notation, ancl in relational operators. The decision not to provide any tools for data abstraction was deliberate.

I felt that the control

strategies that were appropriate to the walking task did not require any more data structure power. In addition, since the concurrem processes require a runtime system data structure more complex than the simple stack that suffices for algorithmic languages, I was afraid that providing more complex data structures in the language might reduce the performance of the runtime system. 1 now believe that my concern was unfounded

and that more powerful data structures could be added without

serious real time performance penalty. 7.5.2. Declarations Data objects must be declared explicitly, either globally with a global statement or locally to a process with a local statement.

Formal parameters to processes arc equivalent to local declarations.

When an array is to be passed as a formal parmneter to a process, its size must be declared in the definition of the process. 4

J]ere is the syntax for global data declarations:

globaideclaralion :: = global ( globallist ) globallist :: = global[ gIoballist , global global :: = id] id[ literal]] id = literal The syntax for formal and local data declarations is included in the syntax specification exhibited in section on named processes. A global declaration makes a name visible throughout the entire collection of OWL processes. A local declaration is visible throughout the code of thc process to which it is attached. parameters obey the same scope rules as local parameters.

Formal

Separate instances of the same process

have independent instances of all locals and formals. A spcckd globai arra_, n_m; < bothwhen( ( state[ leg ] = = 'R' ) ); recoverknee( leg, recover-x-target ); done( true ) >; < when( ( kneevalve[ leg ]! = 'H' ) ); khold( leg ) > l; done( true ) > ] >; { Keep the hydraulic system flags up to date } to,draulic( leg ); { Show what's happening on the console } monitor( leg ); { Main sequence in the row process } < state[ leg ] = 'L'; load leg ); excite[ leg ] = 0; excite[ afmeighbor[ leg l] = excite[ aftneighbor[ leg] ] + excitation; inhibit[ crossneighbor[ leg] ] = inhibit[ crossneighbol[ leg]]" #zhibition; inhibit[ qftneighbod leg ] ] = inhibit[ aftneighbol[ leg ] 1- inhibition; inhibit[fi)reneighbor[ leg ] ] = ipd_ibit[jbreneighbo_[leg ] ]- inhibition; state[ leg I = 'D'; drive( leg, drive--y-target[ leg 1,drive-x-target ); inhibit[ crossneighbot[ leg ] ] -- iuhibi;[ crossneighbot[ leg I ] + inhibition; inhibit[ aftneighbot[ leg ] ] = inhibill @neighbor[ leg ] ] + inhibition; inhibit[foreneighbor[ leg ] ] = i_thibit[foreneighbor[ leg ] ] + inhibition; state[ Dg ] = 'U'; unload( leg, unloaded); state[/eg ] = 'R'; recovel( leg, recover-y-target[ leg ], recover-z-target, recover-x-target )>

1

113

114

Control of Walking

define holdall: { Put all valves in hold } < hhold( l ); hhold( 2 ); hhold( 3 ); hhold( 4 ); hhold( 5 ); hhold( 6 ); khold( 1 ); khold( 2 ): khold( 3 ); khold( 4 ); khold( 5 ); khold( 6 ); sendvalvccommands; { This makes holdall an immediate command. } done( true ) > define nzain, local( i = 1, spins = O, tl, t2, ttot = 0 ): < initrow; { Initialize the walking parameters } inittrouble; { lqitialize the trouble flags } holdall: { Make sure everything is stopped } hzittrace; { Initialize the table Ibr data taking } snapsensors; { initial set of sensor data } startclock; { Make sure the real timc clock is running } beep; { Ring the console bell } [ { The main concurrence } < sendvalvecommands >; { Keep sending new commands to I/O processor } sensors; { Keep the sensor values up to date } < { Report selected sensor valucs when requested } when( ( dial = = 10 ) ); i=1; < printf( "\r\nI,eg%d: Y:%6d Z:%6d H:%c K:%c FZ:%6d I:%6d", i,)_ i ], z[ i ], hipvalve[ i 1, kneevalve[ i ],fz[ i ], inhibit[ i ] ); i= i+ 1; done((i>6)) >; _hen( ( dial != 10 ) ) >; < { Report the states of all six legs when requested } _hen( ( dial = = 7 ) ); i= 1; printf( "" ); when( ( dial != 7 ) ) >; < { Keep measures of run time performance } time( tl ); suspend; time( t2 ); ttot = trot -F t2- ll; spins = spins-F 1 ); troubleserver, { Keep anytrouble up to date } compserver; { Mother to service the compensator }

Walking program code { The main walking control processes. Six leg rowers plus the } { two cross excitation processes } ro_( 1 ); { Row leg 1} row( 2 ); row( 3 ); < { Excitation to leg 3 fi'om leg 4 } when( ( excite[ 3 ] = = 0 ) && ( state[ 3 ] = = 'D' ) && ( )'f 3 ] < = ( recover-y-target[ 3 ] + drive-y-target[ 3 ] ) / 2 ) )[I ( ( state[ 4 ] = = 'l)') && ( trouble[ 4 ]! = 0 ) ) ) ); excite[ 4 ] = excite[ 4 ] + crossexcita/ion; when( ( excite[ 4 ] - = 0 ) ) >; < { Excitation to leg 4 from leg 3 } when( ( excite[ 4 ] = = 0 ) && ( state[ 4 ] = = 'D' ) && ( y[ 4 ] ( = ( recover-y-target[ 4 ] + drive-y-target[ 4 ] ) / 2 ) )I[ ( ( state[ 3 ] = = 'l-Y ) && ( trouble[ 3 ] != 0 ) ) ) ); excite[ 3 ] = excite[ 3 ] + crossexcitation; when(( excite[ 3 ] = = 0)) ); row 4 ); { Row leg 4 }

row(5 ); row( 6 ); { More service routines } < { Report on the trouble flags when requested } when( ( dial = = 11 ) ); printf( "\r\nTrouble: %d = %d %d %d %d %d %d %d %d", an.vtrouble, trouble[ 1 ], troub/e[ 2 ], trouble[ 3 ], trouble[ 4 ], troubie[ 5 ], trouble[ 6 ], trouUc[ 7 ], trouble[ 8 ] ); printf'( "\r\nI.l= %d I_LI:%d PL: %d PU: %d", llJlag, luflag, pIflag, puflag ); printf( "\r\nairmode%d", airmode ); when( ( dial != 11 ) ) ); < { Toggle the airmode flag } when( ( dial = = 9 ) ); airmode = ( airmode != 0 ) ? 0 : 1; inittrouble; printf( "airmode->%d", aitmode); when( ( dial!= 9 ) )>; < { Start data taking } when( ( thumb!= 0 ) ); when( ( thumb = = 0 ) ); inittrace; [ < bothwhen( ( thumb != 0 )II ( indx >= tmcesize- 100 ) ); { Quit data taking } printf( "\r\ngather done: %d", imtx / 11 ); when( ( thumb = = 0 ) ); done( true ) >; < printf( "gathering" ); gather; { Actually take data } both( true ) > ] >; { In case we run out of data space }

115

116

Control of Walking
; deadman { The deadman switch watcher } 1; { The main concurrence ends here } { Now wrap up, upload any data, and exit. } printt'( "%d points taken.", indx / 11 ); printf( "\r\nUpload trace dam to the vax?" ); printf( "\r\nThumb to upload, hat to quit." ); [ { Clean up, upload data, etc } sensors; { Need 1/0 fi'om tile keypad and joystick } < when( ( cooleehat != 0 ) ); printR "Done." ); bothwhen( ( cooleehat = = 0 )); quit; done( true ) >; < both_vhen( ( thumb!= 0 ) ); printf( "Sending data to the vax." ); quit; tovax; done( true ) > ]; report( 8, 10 ); printf( "\r\n%d spins were timed, total time was: %d", spins, trot ); done( true ) > end

A.3. Load5.owl define load( leg): < when( ( plflag = = 0 ) II( dial = = leg ) ); { OK to load or else override } [ < both( ( (fz[ leg]> = loadtop ) II{ Max good force } ( z[ leg ] < = stancebottom )II { Too far down } { spring region } (J_[/eg ] >= ( ( ( z[ leg]- stancebottom ) * stancefactor) + !oadbottom ) ) 1[ ( ( ( el[ leg ] >= toolong ) II( dl[ leg ] > = toolong ) ) && (fz[ leg ] > = lightly ) ) II ( ( z[ leg ] < = stancetop ) && ( ainnode != 0 ) ) I[{ Test mode } ( dial = = leg ) ) ) >; { Bypass } < when( ( ( hipvalve[ leg ] != 'P' ) && ( trouble[ 7 ] = = 0 ) ) ); hplace(leg) > 1; hhold( leg ); when( ( dial!= leg) ); done( true ) > end

Walking program code

A.4. Drive7.owl define drive( leg, ytarget, xtarget ): < when( ( ato,trouble = : 0 ) [[( dial = = leg ) ); henergize( leg ); [ _, both( ( dial = = leg )0[ ( (fz[ leg ] ( = ( safeload- inhibit[ leg ] + excite[ leg ] ) ) && ( ( ){ leg ] = xtarget ) [[( x[ leg ] (: - xtarget ) ) ) )>; < when( ( ( ( e4 leg ]4: tooshort )[[( d/[ #g] >= too/ong) [I ( 3{#g ] < = ),target ) ) && ( ato,trouble = = 0 ) ) ); trouble[ leg ] = true; printf( "%dX", leg); Mwn( ( ( e,1leg ] > tooshort ) && ( dll leg ] ),target ) && ( x[ leg ] < xtarget ) && ( x[ leg ] >- xtarget ) ) ); trouble[ leg] = false; printf( "%all)", leg ) >; < when( ( ( hipvalve[ leg ] != 'E' ) && ( anytrouble = = 0 ) ) ); henergize(leg) > ]; when( ( dial!= leg ) ); trouble[ leg] - false; done( true ) > end

A.5. Unload3.owl define unload( leg, unloaded): < when( ( lujiag-- : 0 )II( dial = = leg) ); [ < both( (J_[ leg ] < = unloaded ) [I( dial = = leg ) ) >; < _hen( ( ( hipvalve[ leg ] != 'L' ) && ( trouble[ 7 ] = = 0 ) ) ); hlift(/eg ) > ]; hhold( leg ); when( ( dial!= leg) ); done( true ) > end

A.6. Recover6.owl

117

118

Control of Walking

define reco:,erknee( leg, target ): [ ( bothwhen( ( .x[leg ] >= target- 3000 ) && ( x[ leg ] ; < bother'hen( ( )_[leg ] < = target- 3000 ) ); [ ( when( ( ( kneevah, e[ leg ]! = 'R' ) ) ); kright( leg ) >; < bothwhen( ( x[ leg ] > = target- 3000 ) ); khold( leg ); done( true ) ) ]; done( true ) >; < both,_hen( ( x[ #g ]) target + 3000 ) ); [ < when( ( ( kneevalw_[leg ] !: 'L' ) ) ); kleft( #g ) ); < both_'hen( ( x[/eg ]

l

Walking program code

119

define recoveff Leg, yt, zt, kt ), local( ct, dr, tO,tl ): < et = yt - zt: { Target cylinder position } dt = - yt - zt; { Target other cylinder position } [ < both(( dial = = leg)[I { Manual bypass } ( ( el[ leg ] > = et ) && ( d/[/eg ] < =dt ) ) I[ { Overshot a bit, ok to quit } ( ( et < = el[ leg ] + fi_zz ) && ( el[ leg ] < = et + fuzz ) && { On ... } ( dt < = dl[ leg l + fuzz ) && ( dl[ leg,] ; { ... target } < when( ( hipvalve[/eg ] = = 'D' ) ); time( tO); < time( tl ); { Delay 250 milliseconds } dane((tl>tO+ 25)) ); both_hen( (J2[ leg ] >: lightly ) ); { Stop if we hit the ground } done( true ) >; < [ < bothwhen( ( ( el[ leg] >= et ) && ( dl[ leg ] >= dt ) && ( llflag = = 0 ) ) ); { We are in the lift region ... both cylinders are too long } [ < when( ( ( hipvalve[ leg ]! = 'L' ) && ( trouble[ 7 ] = = 0 ) ) );

hlift(leg)>;
= dt ) ); hhold( leg ); done( true ) > ]; done( true ) >; bothwhen( ( ( c/[ leg ] = dt ) && ( llflag = = 0 ) ) ); { We are in the t:p-d,)wn region } [ < when( ( ( hipvalve[ leg ] l= 'U' ) && ( trouble[ 7 ] = = 0 ) )); hup( leg ) >; < both( ( dl[ leg ] < = art,+ fuzz ) ) > ]; hhold( leg ); when( (plflag = = 0 ) ); [ < when( ( ( hipvah,e[ leg ] [= 'D' ) && ( trouble[ 7 ] = : 0 ) ) ); hd_wn(leg) >; < both( ( el[ leg ] )= et- fuzz ) ) > ]; done( true ) > ] > ];

hhold( leg); _hen( ( dial!-: leg) ); done( true ) > end

120

Control of Walking

A.7. waveinit.owi global ( recover-y-target[ 6 ], recover-z-target, recover-x-target, drive-y-target[ 6 ], drive-x-target, engine-drive, engine-recover, middle-drive, middle-recover, driver-drive, driver-mcovel; airmode, safeload, unloaded, lightly, loadtop, loadbottom, stancetop, stancebottom, stanc_fTctor, toolong, tooshort, inhibit[ 7 ], excite[ 7 ], inhibition, excitation, crossexcitation, chr, #_pt, afmeighbor[ 6 ], foreneighbot[ 6 ], crossneighbor[ 6 ], fuzz, minrise, state)[6 ]

{ fore-aft target fi)r hip } { up-down target for hip } { in-out target for knee } {Encrgize direction target } { Crab dircction target } { l.cgs 3 & 4 l)rive target } { I.eg:_3 & 4 P,ecover target } { legs 2 & 5 l)rive target } { legs 2 & 5 Recover target } { l_egs 1& 6 Drive target } { l.egs 1& 6 Recover target } { Testing in air flag } { I.eg with this much won't let machine fall } { l.ess force than this means leg is unloaded } { Just touching the ground } { Maximum recommended load for a leg } { Bottom load for good stance } { Top position for good stance } { Bottom position for good stance } { Slope of load/position curve } { Maximum extension of a cylinder } { Minimum extension of a cylinder } { The seventh position is for 1 and 6, which have no } { fore/aft neig:hbors to inhibit or excite. } { llasic inhibition amount } { Basic excitation amount } { I.eg 3 - [.cg 4 excitation } { Place for console character input } { Place for console integer input } { Leg number of aft neighbor } { l.eg number of fore neighbor } { l.eg number of crosswise neighbor } { Error tolerance } { Minimum amount to raise leg during unload } { States for all six legs }

) define watch( varstar parm, string, row, col ), local( last = -99999 ): { Redisplay any parameters that change. For menu system. } < when( ( last != parm ) ); last = parm; cursor( row, col); printf( string, parm ) >

Walking program code define update( var pann, dig, row,col ): { Update selected parameter. For menu system. } ( bothwhen( ( chr = = dig ) ); cursor( row, col); getline( row, col); geti( parm ); beep; cursor( row, col); printf( .... ); done( true ) > define customize: { Present menu for user to modify walking parameters. } < clearscreen; cursor( 24, 5 ): printf( "Type 'q" to continue. Single character to select parameter to modify" ); [ watch( engine-recover, "1 Engine Y Recover: %8d", 1, 5 ); watch( middle-recover, "2 Middle Y Recover: %8d", 2, 5 ); watch( driver-recover, "3 Driver Y Recover: %8d", 3, 5 ); watch( recover-z-target, "4 Recover Z target: %8d", 4, 5 ); watch( recover-x-target, "5 Recover X target: %8d", 5, 5 ); watch( engine-drive, "6 Engine Y Drive: %8d", 6, 5 ); watch( middle-drive, "7 Middle Y I)rive: %8d", 7, 5 ); watch( driver-drive. "8 Driver Y Drive: %8d", 8, 5 ); watch( drivc_x-target, "9 Drive X target: %8d", 9, 5 ); watch( unloaded. "a Unloaded threshold: %8d", 10, 5 ); walch( minrise, "b Minimum rise: %8d", 11, 5 ); watch( loadtop, "c l_oad Top: %8d", 12, 5 ); watct_(loadbottom, "d Load Bottom: %8d", 13, 5 ); watch( stancetop, '% Stance Top: %8d", 14, 5 ); watch( stancebottom, "fStance Bottom: %8d", 15, 5 ); watch( safeIoad, "g Sate l.oad: %8d", 16, 5 ); watch( inhibition, "h Inhibition: %8d", 17, 5 ); watch( excitation, "i Excitation: %8d", 18, 5 ); watch( crossexcitation, "j Cross Excitation: %8d", 19, 5 ); watch(fi_zz, "k Fuzz: %8d", 20, 5 ); watch( toolong, "1Too Long: %8d", 21, 5 ); watch( tooshort, "m Too Short: %8d", 22, 5 ); watch( lightly, "n Light I.oad: %8d", 23, 5 );

121

122

Control of Walking
", i/11 ) >; < upprintf( "%d %d %d %d %d %d %c %d %d %d %d\n", trace[ i], trace[ i + 1 ], trace[ i + 2 ], trace[ i + 3 ], trace[ i + 4 ], trace[ i + 5 ], trace[ i + 6 ], trace[ i + 7 ], trace[ i + 8 ], trace[ i + 9 ], trace[ i + 10 ] ); i = i + 11; both( ( i >= indx ) ) > ]; upflush; { [:lush the transmitter buffer } upprintff "%c", '\004' ); { send atD to close the file } done( true ) > define snapshot( leg ): < time( trace[ indx ] ); trace[ indx + 1] = leg; trace[ indx + 2] = y[ leg ]; t.:ace[indx + 3 ] = z[ leg ]; trace[ indx + 4 ] = fz[ leg ]; trace[ indx + 5 ] = fy[ leg 1; trace[ indx + 6 ] = hipvalve[ leg ]; trace[ indx + 7 ] = ( leg < 4 ) ? d123 : d456; trace[ indx + 8] = rcv; trace[ indx + 9] = inhibit[ leg ]; trace[ indx + 10] = excite[ leg ]; indx = indx + 11; done( true ) > end

128

Control of Walking

A.10. trouble.owl global ( trouble[ 8 1, apo,trouble, p/[ 8 ], ptflag, pu[ 8 ], puflag, ll[ 8 ], ltfiag, lu[ 8 ], luflag

{ Trouble flag array ... 7 is compensator } { 8 is operator override } { Overall trouble flag } { l.oaded and in Place or Down } { Unloaded and in Place or Down } { Eoaded and in Lift or Up } { Unloaded and in Lift or Up }

) define troubleserver:. < anytrouble = trouble[ 1 ] + trouble[ 2 ] + trouble[ 3 ] + trouble[ 4 ] + trouble[ 5 ] + trouble[ 6 ] + trouble[ 8 ]; plfiag = i'/[ ] ] + p/[ 2 ] + p/[ 3 ] + p/[4 ] + p/[ 5 ] + p/[ 6]; puJlag = pu[1] + pu[ 2 ] + pu[ 3 ] + pu[ 4 ] + pu[ 5 ] + pu[ 6 ]; lljlag = 11ll]+ l/[2] + I/[31+ ]_4] + I/[5] + i/[6]; lujlag = lu[ l ] + lu[ 2 ] + h,[ 3 ] + h,,[4 ] + lu[ 5 ] + Is,[6] > define &a&nan: < ;vhen( ( trigger = = 0 ) ); trouble[ 8 ] = true; when( ( trigger!= 0 ) ); trouble[ 8 ] = false > define inittrouble, local( i = 1 ): < < trouble[ i] = 0; p/[ i l = 0; pu[i] = 0;

till] =0; lu[ i] = 0; i= i+ 1; done( ( i> 8 ) ) >; anytrouble = 0; plflag = 0; puflag = 0; IIflag = 0; luflag = 0; done( true ) >

Walking program code define hydraulic( leg ), local( Ic, ht): < when( ( hipvah,e[ leg 1! = &)ll ( ( M = = 1) && (fz[ leg ] 4,= lightly ) ) [I ( ( Id = = 0 ) && ( fz[ leg ] ) lightly ) ) ); lc = hipvalve[ leg ]; ld = ( fz[ leg ] >= lightly ) ? 1 : O;

ll[legl =(((#=='l.')ll(Ic=-'U'))&&(Id== 1))?1:0; l.[ leg] -=(((to= ='i.' )11(le= ='U' ))&&( ld = = 0))? 1 : O; p/[ leg] = (((/c= -'P' ) II( Ic- -'I)" ))&&( ld = = 1)) ? 1:0; pu[leg] = ((( le= ='t" ) II( Ic= = 'D' ))&&( IN= = 0 ))? 1:0 > end

A.I 1. comps.owl define compserver: [ < when( ( comp >= 9000 ) ); trouble[ 7 ] = true; lengthencomp; ,_lien( ( comp = 0 )); relcasecomp; trouble[ 7 ] = false >

1 end

129

130

Control of Walking

Data

131 1 am not arguing with you - I am telling you. ---J. et McNeil Whistler

Appendix B Data

This appendix contains selected plots of data taken from the walking machine sensors and internal state during various walking experiments. They are presented in chronological order. Discussion of these data is contained in Chapter 8. • w830728 - July 28 90 seconds of walking. Excitation and Inhibition on. S turn. • w830731 - July 31 160 seconds of walking. Excitation and Inhibition on. An attempt at a straight walk, but 123 side was driving a bit faster than 456 due to a problem with the drive pumps, so it curved a bit. • _830808a - August 8 130 seconds of walking. Excitation off, Inhibition oil. Relatively straight walk. • _v830809- First run Augus', 9 160 seconds of walking. Straight walk.

Excitation off, Inhibition on.

• ,_'830809a - Second run August 9 300 seconds of walking. Excitation and Inhibition both on.

• g830816 - August 16 160 seconds of walking. Excitation off. This walking was done with "gimpy", a copy of walk.owl with leg 5's instance of the Row process commented out. I=ivelegged walking.

B.I. Descril;tion of data figures This section describes the data plots contained in t_hisappendix. The record of each "run" consists of three plots derived from the data taken during the run. The first plot, a sample of which is figure B-l, is a time history of all six legs. There is an independent

trace for each leg that shows when the leg was recovering and when it was driving.

When the trace is "down", the leg was on the ground. When the trace is "up", the leg was recovering. The horizontal axis is the time scale.

The excitation system was on and triplets of rear-to-front

recoveries are visible. Notice that the machine's walking doesn't always exhibit these rear-to-front

132

Control of Walking

triplets; when conditions change the legs may choose to vary from the perfect rear-to-front sequencing.

__FLI--1 ,FE_F_ ,F-1 r--1 I--] left rear

left middle

LJ

,n

!-1

Fl

1

H

n

Legs recovering, from w830728.data

M I-1 [--[ F-1 [--I I--1 1 FE F_ .N n _ .,_, r-1 Jo 71 _o ' F1, 40 .do l-qdo I-1 _o 1-71 ao _;o time (seconds)

right rear

r_=gt_t middle

Figure B-I:

Sample plot of recovery values estimated from inhibition data taken during experiment run July 28, 1983.

The second plot of each set, figure B-2, shows an estimate of the forward progress of each side of the machine. This estimate is computed by integ,'ating the horizontal joint motion of all legs that are on the ground on each side and then taking a linear combination.

In this sample you can see that

there was no forward progress on the 123 side between 35 and 50 seconds into the run while there was progress on the 456 side during that time thus indicating that the machine turned during that time. Between 55 and 70 seconds it turned back the other way and it ended up pointing in the same direction as when it started, as you can see by the fact that the progress lines converge at about 85 seconds. Of course, if the machine made a complete circle, it could end up pointing in the same direction while the progress lines would not have converged at all. 7'he third plot is the six load traces for the run. Figure B-3 shows the load plot for the same run exhibited in the other samples in this section.

Comparison of this plot with figure B-1 can show

things like legs entering drive but remaining unloaded, or becoming unloaded during drive, and so on. It also illustrates some of the effect_sof the machine's lack of mechanical compliance.

Data

133

._ 6.0 L,,

• 5.5 ¢_ ¢_

_.o

. "'// /

Forward progress from w830728.data

4.5

...... "

123 progress

_ 4.0

."

........ 4_6proQre_

3.0 3.5

.... .......'

.___:

°

2.5

.'_:-_:

1.5

,'*

o

_

._

2.0

1.0

[

/ •

_o

_

Jo

_o

_o

;o

do

.... 73

60

- 70

do

time (seconds)

._o

Figure B-2: Sample of progress estimates tor file two sides of the machine.

I500 pounds

...... rig

f/On ^^

Leg forces, from w830728.data

20

Figure B-3: Sample ofall six load traces.

30

^" 40

50

-dO 90 time (seconds)

134

Control of Walking

B.2. Data plots

_£2_J_1 left rear

left' niiddle left front

,[--_F-1 I-1 ,,F_

[___I--]

I-1 I-i

r-]

l---i

F-1 F1

__r---]

F-]_I---I

__z___ ,_,r-_ _ _ Legs recovering,

_ ,I

from w830728.data

.....',7:1:i_] 7-l_1-1 r--t_,r--I t--1 - ['ight 7¢nt 2o _o ,_o

1 i--LJ

FI I-i 1-1 i--ido i-i70 I-:1 do 8o

_o

time (seconds)

-, 6.0

• ,_.5

..F Forward progress from w830728.data

5.0 4.5

..... .

._

123progress

OCl,4.03.5

.......

456 progress

,--,'" ,"'.......

fJ

3.0

f

2.5 2.0 1.5 1.0 .5

o

,o

20

30

_o

do

do

_o

do time (seconds)

_o

OW I_Primitives

500 pounds

135

Leg forces, from w830728.data

t'rear

A.. 20

4e_mid_e

J-L_]

30 " _- 40

50

__V-__N.

--_e_t f]7.ron, FL__H

FL

.r_

60

right ,rondo

40

q_]q._[---]

90

p-___ [_]_______ji]__]

nFI__ n F]__J] n n dO

80

time (seconds)

__H

Legs rec°verin _31"dath

!_!e_ _ffii"'

- fo

80

[--]__]--]

I

[] n ,r:-i ,is

I-I rl 1_i0 .....

120

140

i 60

time (seconds)

136

Control of Walking

_11 10

_ 9

/---

tb

6

f

J

_._

...

j

5

°

f Forward, Dro._ess from w830731 .data

4

.....

lz3p_-_ress 45616rogress

........

.... " ....

.'""

.- ..... " .....

• . o..o., ..

1

o

20

I500 pounds

,_o

_o

_o ' _bo

,_o

,:_o

Leg forces, from w830731 .data

..... ___ ..... _,_ .....___._..... _,.___._, rightfronL_0

,_o

time (seconds)

40

60

80

100

120

140 160 time (seconds)

OW !. Primitives

137

___£},,_a, n r-Lr-L_S7 _m H_M_r__r7 left middle

N

I-I.... J-l__Fi_l-l__l-IFl_rl

--£7,oot J_--LrT__m_mn

,rl

m_n r

,oO rTove,l w O OI-1a. a,a FI sm I-

r--I

I"°"tri_,r7r_n H,nn, right front 20

40

60

n , nn, 80

100

,

120 (seconds)140 time

6.5 o_6.0

J"

E_5.5 Forward progress from w830808a.data

o 4.5

......

el. _ 5.0

456 progress 123progress

3.15 4,0

".......

.... .......

""

_-----_

2.5

f

2.0 1.5

¢_o

.-

..........

3.0

1.0

.,"

f.--

_

.;o

,70

do

_o

_bo

_o

,

_4o

time (seconds)

138

Control of Walking

I left front

500 pounds

0

Leg forces, from w830808a.data

rightfront 20

40

60

-]_l__e ]__Ft_J]___I]rl left front

__H_I_

80

100

rLrl_rl

FLFL_I-LrU-I_FLZ-t._II_IIJ

120 1'40 time (.seconds)

rl_lt__l

Legs recovering, from w830809.data

rLmLrL mrmLm I],.rl,.Ilrl ,"_

Suggest Documents