Layers#
Every cycle the agent asks its layers for a step in descending priority; the first layer whose
planPath() succeeds wins. Layers explains the arbitration and the two shipped layers.
-
class Layer : public open_apero::Plugin#
- #include <open_apero_core/plugin/layer/layer.h>
Abstract planner layer that keeps its own view of the current state and offers steps.
Owned by Agent. A Layer is a Plugin; the default setup composes a generator, an evaluator and a path planner created through the agent’s factory, which a layer may replace with its own (BacktrackingLayer). RobotState is the cross-layer currency.
Subclassed by open_apero::layer::BacktrackingLayer, open_apero::layer::PlanningLayer
Public Functions
-
inline bool computeCost(Edge *edge)#
Compute the cost of
edgeusing the agent’s cost computer.- Parameters:
edge – The edge whose cost is set.
- Throws:
std::runtime_error – if the agent has no cost computer.
- Returns:
The cost computer’s result: true if the cost was computed.
-
inline int configuredPriority() const#
The static priority loaded from YAML (before any state-dependent promotion in getPriority()). Used for diagnostics such as the agent’s startup stack summary.
-
inline virtual std::string cycleSummary() const#
Human-readable one-line summary of this layer’s last planning cycle.
Default is empty; the agent prints any non-empty summary in verbose mode.
-
inline virtual int defaultPriority() const#
Baseline priority used when YAML does not specify “priority”. Subclasses override to give themselves a sensible default (e.g. BacktrackingLayer returns a very low number so it is the fallback).
-
virtual void expand() = 0#
Grow the layer’s candidate set: sample new candidates, connect and evaluate them.
Called every iteration after update(), from the layer’s own current-node view. How many candidates one call adds is the layer’s choice (PlanningLayer runs max_expansions rounds).
-
inline CostComputer *getCostComputer() const#
The agent’s cost computer, shared by every layer.
-
inline Evaluator &getEvaluator()#
The evaluator child; precondition: hasEvaluator() (see getGenerator()).
-
inline Generator &getGenerator()#
The generator child created by Layer::setupFromParamMap().
Precondition: hasGenerator(). A layer that replaces that setup (e.g. BacktrackingLayer) has no children, and this and the two accessors below then dereference a null pointer.
-
inline LayerMetrics &getLayerMetrics()#
This layer’s metrics; subclasses install a derived LayerMetrics in their constructor.
-
inline const LayerMetrics &getLayerMetrics() const#
-
inline PathPlanner &getPathPlanner()#
The path-planner child; precondition: hasPathPlanner() (see getGenerator()).
-
inline virtual void getPathVisualization(Node *selected_node, VisualizationMarkers *markers)#
Append markers describing the path this layer just offered, for a topic of its own.
Default no-op.
- Parameters:
selected_node – The next node selected by the agent this tick, or nullptr when this layer offered no step; a layer that lost has no path to describe.
markers – Output marker container.
-
inline virtual int getPriority(const RobotState&) const#
Per-tick priority; higher values are consulted first.
The default returns the configured priority. State-dependent overrides must list every value they can return in possiblePriorities().
-
inline virtual void getVisualization(Node *selected_node, VisualizationMarkers *markers)#
Append per-layer visualization markers for the current planning state.
Default no-op. Layers with persistent geometry (graph, KD-tree, synthetic targets) override to render it.
- Parameters:
selected_node – The next node selected by the agent this tick (may be nullptr if no step was selected).
markers – Output marker container.
-
inline bool hasCostComputer() const#
Whether the agent has a cost computer; Agent always configures one.
-
inline bool hasEvaluator() const#
Whether the layer owns an evaluator child.
-
inline bool hasGenerator() const#
Whether the layer owns a generator child.
-
inline bool hasPathPlanner() const#
Whether the layer owns a path-planner child.
-
inline std::string instanceName() const#
Runtime instance identity: the “layers” dictionary key this layer was configured under.
Falls back to layerName() for layers created outside that path (tests).
-
inline explicit Layer(AgentInterface &agent)#
-
virtual std::string layerName() const = 0#
The layer’s semantic kind, fixed per concrete class (e.g. “planning”, “backtracking”).
Not the class name or the registered type string. Runtime identity (CSV column prefix, visualization topic, logs) comes from instanceName().
-
inline virtual void onEpisodeStart(const RobotState&)#
Initialize per-episode state from the robot’s starting pose.
Called once per episode before the first onStateReached. Default is a no-op; layers that need to seed an internal structure (e.g. PlanningLayer rooting its graph at
init_state) override this.
-
inline virtual void onSelectedAsWinner()#
Called by Agent after this layer’s planPath proposal was accepted.
Overrides must call Layer::onSelectedAsWinner() to keep the common metrics accurate.
-
virtual void onStateReached(const RobotState &state, const Edge *executed_edge, Node *active_node) = 0#
Update the layer’s private current-state view.
Called once per tick before update/expand/planPath.
active_nodeis planned_path[1] of the step last executed, from whichever layer produced it; a layer that does not own that node adoptsstateits own way. Layers that record executed edges consumeexecuted_edgehere.- Parameters:
state – Latest robot state.
executed_edge – The edge the agent just finished executing (nullptr on the first tick before any edge has run).
active_node – Destination of the executed edge (nullptr if none).
-
virtual bool planPath(const RobotState ¤t_state, Map *map, RobotModel *robot, std::vector<Node*> *planned_path, std::vector<Edge*> *planned_edges) = 0#
Try to produce a planned path/edge handoff for execution.
Returns false when the layer has nothing to offer; Agent then consults the next layer. On success planned_path[0] is the layer’s current node, planned_path[1] the destination and planned_edges[0] the edge to execute; every edge has >= 2 states and starts at time 0.
- Parameters:
current_state – Latest robot state (used by free-space planners).
map – The shared agent map.
robot – The shared robot model.
planned_path – Out: planned nodes, starting at the layer’s current node.
planned_edges – Out: edges between consecutive
planned_pathnodes.
- Returns:
True if the layer offers a step.
-
inline virtual std::vector<int> possiblePriorities() const#
Every priority this layer can possibly report from getPriority().
The agent rejects overlapping sets at startup, so a layer with state-dependent priority must override this.
-
inline virtual std::optional<double> realAccumulatedGain() const#
The gain this layer has really collected this episode, for episode_summary.yaml.
The default returns std::nullopt: the layer reports no gain.
-
inline virtual void resetEpisode() override#
Reset per-episode state.
Default resets this layer’s own children; the agent’s cost computer is reset by Agent::clearEpisodeState. Subclasses that override must call Layer::resetEpisode().
-
inline void setInstanceName(const std::string &instance_name)#
Set the runtime instance name (see instanceName()).
-
virtual void setupFromParamMap(Configurable::ParamMap *param_map) override#
Loads the layer’s params and creates the generator, evaluator and path_planner children.
Edge costs come from the agent’s cost computer (see computeCost), not a child. Layers with extra params call this from their override; layers without the three-plugin composition (e.g. BacktrackingLayer) replace it, and must then read “priority” themselves (default defaultPriority()).
-
inline virtual bool splitActiveEdge(Node *active_node, Edge *edge, int waypoint_idx, Node **intermediate_out, Edge **finished_edge_out)#
Split the active edge at
waypoint_idxinto a new intermediate node and the leading half.Hook for agent subclasses that recover a partially executed edge (e.g. after a collision); nothing in the core calls it. The default returns false: splitting unsupported, which a caller with no other recovery treats as fatal.
- Parameters:
active_node – Destination node of the active edge.
edge – The active edge being split.
waypoint_idx – Trajectory index at which to split.
intermediate_out – Out: new intermediate node inserted at the split.
finished_edge_out – Out: leading half of the split edge.
- Returns:
True if the edge was split and both outputs are set.
-
inline virtual void update()#
Re-evaluate existing candidate nodes after map updates.
Called every iteration after onStateReached and before expand(). Default is a no-op.
-
inline virtual void warmUp()#
Optional one-shot lazy-init pass triggered when the agent is configured with build_plugins_on_init. Default is a no-op.
-
~Layer() override = default#
Protected Attributes
-
std::unique_ptr<LayerMetrics> metrics_#
Per-layer metrics; a plain LayerMetrics unless a subclass installs a derived type.
-
int p_priority_ = 0#
Baseline priority loaded from YAML in setupFromParamMap. Layers may override getPriority() to make it state-dependent.
-
std::unique_ptr<PathPlanner> path_planner_#
-
inline bool computeCost(Edge *edge)#
-
class PlanningLayer : public open_apero::Layer#
- #include <open_apero_core/plugin/layer/planning_layer.h>
Graph-based planning layer: a GraphGenerator samples and connects viewpoints, an Evaluator scores them, and a PathPlanner picks the next-best path.
Public Functions
-
virtual std::string cycleSummary() const override#
One-line summary of the graph-size evolution during the last cycle: the node count after the start-node update, the net change from update and expansion, and the count at selection.
-
virtual void expand() override#
Run max_expansions rounds, each sampling one viewpoint cluster, connecting it into the graph, evaluating its gain and computing its edge costs; then connect current_node_ if it has no outgoing edge.
-
inline Node *getCurrentNode() const#
Current vertex in the planning graph representing the robot’s state: the generator’s start node.
-
inline PlanningLayerMetrics &getMetrics()#
Typed accessor for the layer’s own metrics. The base Layer::getLayerMetrics() returns the same object as LayerMetrics&.
-
inline const PlanningLayerMetrics &getMetrics() const#
-
int getNodeCount() const#
Number of nodes in the layer’s graph or tree; used for planner metrics.
-
virtual void getPathVisualization(Node *selected_node, VisualizationMarkers *markers) override#
Hands the evaluator the path just selected, for its own visualization topic.
-
virtual void getVisualization(Node *selected_node, VisualizationMarkers *markers) override#
Append graph + per-node gain visualization markers. With
selected_node, also the evaluator’s markers for the selected path’s first evaluated node past current_node_, else forselected_node.
-
inline virtual std::string layerName() const override#
The layer’s semantic kind, fixed per concrete class (e.g. “planning”, “backtracking”).
Not the class name or the registered type string. Runtime identity (CSV column prefix, visualization topic, logs) comes from instanceName().
-
virtual void onEpisodeStart(const RobotState &init_state) override#
Initialize the planning graph at
init_state. Wraps the generator’s generateInitNode and makes its node the layer’s current_node_.
-
virtual void onStateReached(const RobotState &state, const Edge *executed_edge, Node *active_node) override#
Advance current_node_ to
active_nodewhen it is a vertex of this layer’s graph, else insert an intermediate vertex at the end ofexecuted_edge; with neither it stays where it is. Also records the evaluator’s accumulated gain and moves the generator’s start node (setNewStartNode).
-
PlanningLayer &operator=(const PlanningLayer&) = delete#
-
explicit PlanningLayer(AgentInterface &agent)#
-
PlanningLayer(const PlanningLayer&) = delete#
-
virtual bool planPath(const RobotState ¤t_state, Map *map, RobotModel *robot, std::vector<Node*> *planned_path, std::vector<Edge*> *planned_edges) override#
Run the configured PathPlanner over the graph and finalize the winning edge for execution (refinement, intermediate-node insertion for replan_num_steps, cost recompute). Returns false when the planning graph has no traversable outgoing step.
-
virtual std::optional<double> realAccumulatedGain() const override#
The evaluator’s real accumulated gain; std::nullopt without an evaluator.
-
virtual void resetEpisode() override#
Reset per-episode state.
Default resets this layer’s own children; the agent’s cost computer is reset by Agent::clearEpisodeState. Subclasses that override must call Layer::resetEpisode().
-
virtual void setupFromParamMap(Configurable::ParamMap *param_map) override#
Loads the layer’s params and creates the generator, evaluator and path_planner children.
Edge costs come from the agent’s cost computer (see computeCost), not a child. Layers with extra params call this from their override; layers without the three-plugin composition (e.g. BacktrackingLayer) replace it, and must then read “priority” themselves (default defaultPriority()).
-
virtual bool splitActiveEdge(Node *active_node, Edge *edge, int waypoint_idx, Node **intermediate_out, Edge **finished_edge_out) override#
Split the active edge at
waypoint_idxvia the layer’s GraphGenerator, using current_node_ as the source vertex.
-
virtual void update() override#
Prune untraversable nodes/edges, regenerate edges near current_node_, and re-evaluate gains across all clusters.
-
virtual void warmUp() override#
Force one pass through every owned plugin to trigger any lazy init. Called by Agent::setupFromParamMap when build_plugins_on_init is true. The path planner searches the graph only when current_node_ has an outgoing edge, as in planPath(). Precondition: onEpisodeStart() has set current_node_.
-
~PlanningLayer() override = default#
Protected Attributes
-
Node *current_node_ = nullptr#
Current vertex in graph_ representing the robot’s state; the generator calls it the start node.
-
GraphType *graph_ = nullptr#
Raw pointer to the graph owned by generator_; refreshed by onEpisodeStart. nullptr with a tree generator.
-
int p_max_expansions_ = 50#
Number of expansion rounds run per replan cycle (each round samples, connects, evaluates and prices one node cluster).
-
int p_replan_num_steps_ = std::numeric_limits<int>::max()#
How many trajectory points before inserting an intermediate node into a selected edge so we can replan early. INT_MAX disables splitting.
-
std::vector<Node*> selected_path_#
The path planPath() last offered, for visualization only.
Valid only while this layer’s step was just taken (a non-null selected node); read nowhere else.
-
virtual std::string cycleSummary() const override#
-
class BacktrackingLayer : public open_apero::Layer#
- #include <open_apero_core/plugin/layer/backtracking_layer.h>
Layer wrapping a Backtracker plugin. Owns its own two-node-one-edge recovery state; never reaches into another layer’s storage.
Public Functions
-
explicit BacktrackingLayer(AgentInterface &agent)#
-
BacktrackingLayer(const BacktrackingLayer&) = delete#
-
inline virtual void expand() override#
No graph to extend — no-op.
-
inline Backtracker &getBacktracker()#
Accessor for the owned backtracker (used by tests / debug).
-
inline BacktrackingLayerMetrics &getMetrics()#
This layer’s metrics, already downcast. The constructor installs a BacktrackingLayerMetrics, so the cast always holds; Layer::getLayerMetrics() returns the same object as LayerMetrics&.
-
inline const BacktrackingLayerMetrics &getMetrics() const#
-
virtual int getPriority(const RobotState &state) const override#
Returns promoted_priority while the backtracker’s initial sweep runs or
stateis untraversable, the configured baseline otherwise.
-
virtual void getVisualization(Node *selected_node, VisualizationMarkers *markers) override#
Forward debug markers from the owned backtracker.
-
virtual void onStateReached(const RobotState &state, const Edge *executed_edge, Node *active_node) override#
Caches the latest robot state and lets the backtracker record non-recovery executed edges (so e.g. Reverse can queue forward segments).
-
BacktrackingLayer &operator=(const BacktrackingLayer&) = delete#
-
virtual bool planPath(const RobotState ¤t_state, Map *map, RobotModel *robot, std::vector<Node*> *planned_path, std::vector<Edge*> *planned_edges) override#
Ask the backtracker for a recovery trajectory and wrap it as a step. Returns false if the strategy declines.
-
inline virtual std::vector<int> possiblePriorities() const override#
Configured baseline plus the promoted priority (initial sweep running or untraversable state).
-
virtual void resetEpisode() override#
Forwards to the owned Backtracker’s resetEpisode.
-
virtual void setupFromParamMap(Configurable::ParamMap *param_map) override#
Construct the owned Backtracker from YAML and hand it to the metrics, so its columns join the layer’s. Does NOT call Layer::setupFromParamMap: the backtracker is the only child (edge costs come from the agent’s cost computer).
-
virtual bool splitActiveEdge(Node *active_node, Edge *edge, int waypoint_idx, Node **intermediate_out, Edge **finished_edge_out) override#
Truncate the active recovery edge to its executed prefix [0, waypoint_idx] and return it as the finished edge, with a new recovery_node_ at its end as the intermediate. Fails only on invalid arguments.
-
inline virtual void update() override#
No state to re-evaluate — no-op.
-
~BacktrackingLayer() override = default#
-
explicit BacktrackingLayer(AgentInterface &agent)#