dependability. To address this issue, we run the control
loop anyways at very low frequency, typically in the range
of a few Hz. If such executions compute new actuator settings, the drone most likely applies some significant correction to the flight operation that causes reactive control
to be triggered immediately after. If logistic regression
originally indicated that the current changes in sensor
readings did not demand to run the control logic, the current iteration is considered a false negative and feed back
to the data set used for tuning the regression parameters.
The next time the least square estimation executes, as
explained above, these false negatives are also taken into
account.
c requires an explicit assignment following the changes
in a or b. It becomes an issue to determine where to place
such an assignment without knowing when a or b might
change.
Using RP, one declaratively describes the data dependencies between variables a, b, and c. As variables a and b
change, the value of c is constantly kept up-to-date. Then,
variable c may be input to the computation of further state
variables. The data dependencies thus take the form of an
(acylic) graph, where the nodes represent individual values,
and edges represent input/output relations.
Note that the techniques hitherto described do not
require one to alter the control logic itself; they solely
drive its execution differently over time. The single iteration remains essentially the same as in a traditional time-triggered implementation. This means reactive control
does not require to conceive a new control logic; the existing ones can be re-used provided an efficient implementation of such asynchronous processing is possible, as we
discuss next.
The RP run-time support traverses the data dependency graph every time a data change occurs, stopping
whenever a variable does not change its value as a result
of changes in its inputs. Any further processing would be
unnecessary because the other values in the graph would
remain the same. This is precisely what we need to efficiently implement reactive control; however, RP is rarely
employed in embedded computing because of resource
constraints.
3. 3. Implementation
Problem. The control logic is implemented as multiple processing steps arranged in a complex multi-branch pipeline.
Moreover, each such processing step may—in addition to
producing an output immediately useful to take control decisions—update global state used at a different iteration elsewhere in the control pipeline.
RP-Embedded. We rely on a few key characteristics
of reactive control to realize a highly efficient RP implementation. First, the data dependency graph encodes the
control logic; therefore, its layout is known at compile-time. Second, the sensors we wish to use as initial inputs
are only a handful. Finally, the highest frequency of data
changes is known; for each sensors, we are aware or can
safely approximate the highest sampling frequency.
Using reactive control, depending on what sensor indicates the need to execute the control loop, different slices
of the code may need to run while other parts may not. The
parts of the control pipeline that do not run at a given iteration, however, may need to run later because of new updates
to global state. Thus, any arbitrary processing step—not
just those directly connected to the sensors’ inputs—might
potentially need to execute upon recognizing a significant
change in given sensor inputs.
Employing standard programming techniques in these
circumstances quickly turns implementations into a “
call-back hell”. 10 This fragments the program’s control flow
across numerous syntactically-independent fragments of
code, hampering compile-time optimizations. We experimentally found that this causes an overhead that limits the
benefits of reactive control. 7
Based on these, we design and implement RP-Embedded: a C++ library to support RP on embedded resource-constrained hardware. RP-Embedded trades generality for
efficiency, both in terms of memory consumption and processing speed, which are limited on our target platforms.
We achieve this by relying heavily on statically-allocated
compact data structures to encode the data dependency
graph. These reduce memory occupation compared with
container classes of the STD library used in many existing
C++ RP implementations, and improve processing speed
by sparing pointer dereferences and indirection operation during the traversal. This comes at the cost of
reduced flexibility: at run-time, the data dependency graph
can only change within strict bounds determined at
compile-time.
Approach. We tackle this issue using RP. 3 RP is increas-
ingly employed in applications where it is generally impos-
sible to predict when interesting events arrive. 3 It provides
abstractions to automatically manage data dependencies in
programs where updates to variables happen unpredictably.
Consider for example:
In addition, RP-Embedded provides custom time
semantics to handle the issues described in Section 3. 2.
The traditional RP semantics would trigger a traversal of
the data dependency graph for any change of the inputs.
With reactive control, however, the traversal caused by
changes in a high-frequency sensor may be immedi-
ately superseded by the traversal caused by changes in
another sensor within the same hyperperiod. The out-
put that matters, however, is only the one produced by
the second traversal.
a= 2;
b= 3;
c= a + b;
In sequential programming, variable c retains the value 5
regardless of any future update to variable a or b. Updating
To avoid unnecessary processing, RP-Embedded allows
one to characterize the inputs to the data dependency
graph with their maximum rate of change. This informa-
tion is used to compute the system’s hyperperiod. Every
time a value is updated in the data dependency graph,
RP-Embedded waits for the completion of the current