Executing a policy end to end
The planner could produce a branching policy and the builder could render one as a behavior tree, but until this work nothing had ever run one over a live ROS graph. Two end-to-end tests now do, and the package that turns a policy into a tree has the tests it never had.
Read the full report (PDF),
five pages, with the reasoning behind each fix and the execution logs.
What the tests run
Both missions bring up the whole graph in one process (domain expert,
problem expert, planner with the plansys2/EpistemicPlanSolver plugin,
executor with bt_builder_plugin: EpistemicBTBuilder and the epistemic node
library, the epistemic_state node loaded from the same grounded task, and
the fake action performers) and run the same mission twice with the world in
different states.
Test |
Mission |
What it proves |
|---|---|---|
|
One corridor of unknown state; a four-node policy that drives out, looks, and reports. |
One run executes |
|
Two corridors and three robots; a twelve-node policy with a switch nested inside another switch’s continuation. |
The two runs report the corridors in opposite states and share no leaf, so the second half of the mission is correct inside either branch of the first. |
|
Twelve unit tests of the plugin’s contract with |
Switch rendering and outcome order, flat rendering of unbranched plans,
refusal of a malformed policy, agreement with
|
Where the observation comes from
The epistemic state can name a sensing outcome by itself only when its model already designates one world. Both fleet fixtures designate several, which is what makes them worth testing with, and what means the observation has to come from whoever did the sensing.
The observation reaches the tree by one of two routes, and the tests cover one each.
ActionExecution carries an outcome alongside its status, so a performer
reports what it saw in the same message that reports completion. The packaged
action template binds ExecuteAction’s outcome port to
ApplyEpistemicUpdate’s observed. test_5 uses this route, running on
the executor’s defaults, with the fake inspect_corridor performer reporting
the corridor’s state.
test_6 binds the port explicitly, the approach required when the
observation originates elsewhere than the acting performer. It supplies its own
action template with the port wired to ObservedOutcome, a node that reads
action=outcome entries from a latched topic and reports the entry matching
its own action.
What the model then does is the point of the whole stack. From the depot run with north blocked and south clear:
[epistemic_state] applied inspect-north_r1 -> e-inspect-north-blocked: 4 worlds, 2 designated
[epistemic_state] applied inspect-south_r2 -> e-inspect-south-clear: 4 worlds, 1 designated
[epistemic_bt] [goal] (and (Kw r1 blocked-north) ... (Kw r3 blocked-south)) holds
Four candidate worlds at the start, two after the first sensing, one after the second, and the goal checked against the state that actually resulted rather than the one planning assumed.
Defects the end-to-end path exposed
None of these is visible to a unit test, and each is fatal to a real execution. All four are fixed; the report has the details.
# |
Defect |
Where |
|---|---|---|
1 |
A builder loaded by name was never initialized: |
|
2 |
With (1) fixed, the builder could be handed PlanSys2’s default action
template, which has no |
|
3 |
An empty policy, a goal that already holds, rendered a childless
|
|
4 |
|
|
Results
Verified in the ros:rolling container, the environment the rolling
workflow builds in.
Suite |
Tests |
Result |
Time |
|---|---|---|---|
|
12 |
pass |
0.16 s |
|
2 |
pass |
32.3 s |
|
2 |
pass |
56.6 s |
|
35 |
pass |
none |
|
165 |
pass |
3 min 18 s |
|
255 |
pass |
2 min 57 s |
plansys2_epistemic_bt_builder is also removed from the packages-ignore
list of the coverage step in rolling.yaml: that list is for packages
producing no .gcda at all, and with a test suite the builder now produces
one.
Known gaps
Todo
The negative case is not covered: an outcome the policy does not plan for,
where EpistemicSwitch must fail instead of guessing. It needs a performer
that reports something the model cannot account for.
ObservedOutcomeis a test’s stand-in for a sensor. A deployment still bindsobservedto its own performers, the one piece of wiring a domain supplies itself.The tests build against ROS 2 rolling only. The Humble job stops before
plansys2_executor, as it did before this work.The mission fixtures
robot-fleet.jsonandrobot-fleet-depot.json, with their action mappings, come from thefeature/epddl-front-endbranch.