EU Horizon Europe · Grant #101070254

Deliverable D7.4
Inspection Testbed

Brownfield collective awareness in Aerostack2 for task allocation and collision avoidance in photovoltaic inspections

📄 Ref: CS-D7.4 v0.1 👤 Author: G. GP-Lenza (UPM) 📅 Date: 2026-04-28 🔓 Public
Funded by the European Union
🧭
Overview

What this deliverable implements and why it matters

The Core Idea

D7.4 implements the CORESENSE Collective Awareness Architecture (defined in D7.3) inside the Aerostack2 drone framework. A fleet of drones can now discover each other at runtime, distribute inspection targets via distributed auctions, and safely negotiate shared flight corridors — all without a central coordinator, and without modifying any existing Aerostack2 component.

as2_ca
📡

CA Middleware

CA Gateway node + CA Client library. Peer discovery, modelet routing, and behavior registration. The inter-agent communication backbone.

as2_core · as2_python_api
🧠

Knowledge Base Interface

C++ KBInterface and Python KBMonitorNode bridge behaviors and mission scripts to the CORESENSE knowledge_core RDF store.

as2_behaviors
🏷️

Auction Behavior

Implements the auctions collective model. Drones bid with distance costs; greedy-sequential convergence assigns targets identically on every drone.

as2_behaviors
🛡️

Collision Avoidance

Implements the consensus collective model. Pairwise path-lock arbitrates corridor access before motion begins.

Aerostack2 Behaviors as CORESENSE Cognitive Modules

📐
Models
The behavior class defines the mandatory coordination protocol — what must happen and in what order.
⚙️
Engines
Loadable plugins provide the how. Swapping greedy_sequential or pairwise_path_lock changes the algorithm, not the protocol.
📦
Modelets
Typed ROS 2 messages — Bid, CAPathLockRequest, CAPathLockGrant — exchanged between cognitive modules.

🏗️
System Architecture

D7.3 CA Module subsystems and their Aerostack2 implementations

Component map — two-drone fleet
Drone A Drone B CA Gateway as2_ca · Node CA Gateway as2_ca · Node network CA Client as2_ca · Library CA Client as2_ca · Library Auction Behavior greedy_sequential Collision Avoidance pairwise_path_lock Auction Behavior greedy_sequential Collision Avoidance pairwise_path_lock State Interface pose · twist · batt. KB Interface C++ KBInterface KB Monitor Python · as2_python_api State Interface pose · twist · batt. KB Interface C++ KBInterface KB Monitor Python · as2_python_api knowledge_core RDF triple store knowledge_core RDF triple store Behavior → CA Client Data bus (behaviors → knowledge) KB Interface → knowledge_core KB Monitor → knowledge_core CA Gateway ↔ network
D7.3 Subsystem

Communication Interface

CA Gateway + CA Client. Namespaced topics, automatic peer discovery, type-dispatched modelet routing.

D7.3 Subsystem

Agent Representation

StateInterface (self-model: pose, twist, battery) + behavior registration in CA Gateway (cognitive module catalog).

D7.3 Subsystem

Organisation Handling

CA Gateway peer discovery. 1-second timer scans for gateway_in topics — no fleet-size configuration needed.


📡
Collective Awareness Middleware

Package as2_ca — the inter-agent communication backbone

Participation Contract

Any drone that (1) deploys a CA Gateway node, (2) uses the CA Client API, and (3) exchanges only as2_msgs vocabulary is immediately interoperable with every conforming peer — the gateway enforces all three obligations at the transport, registry, and semantic levels.

A 1-second timer scans the live ROS 2 topic graph for topics ending in /gateway_in. Newly found topics become peer publishers; publishers whose topics disappear are pruned. No fleet-size configuration needed — satisfies IT-FR-028 (Swarm Size Awareness).

void CA_Gateway::check_peers()
{
  const std::string suffix = "/" + INCOMING_TOPIC_SUFFIX;
  auto topics = this->get_topic_names_and_types();
  for (auto & [name, types] : topics) {
    if (name ends with suffix && name != own_incoming_topic)
      if (not already known) create publisher to name;
  }
  prune peers with no subscribers;
}

Header-only (as2_ca/ca_gateway_client.hpp). Two operations mirror native ROS 2 pub-sub but work fleet-wide:

  • register_module<T> — like create_subscription but covers all current and future peers; delivers sender namespace as second argument
  • forward_IA_msg<T> — like publish but addressed by drone namespace names, not topic paths
// Register handler — covers ALL peers automatically:
client_.register_module<as2_msgs::msg::Bid>(
  "bid", "auction_behavior",
  [this](const as2_msgs::msg::Bid & msg, const std::string & sender) {
    auction_plugin_->on_bid_received(msg, sender);
  });

// Forward to named peers — no topic paths needed:
client_.forward_IA_msg<as2_msgs::msg::Bid>(bid, "bid", bidders_);

Modelet Vocabulary (as2_msgs)

CA Gateway vs. Raw ROS 2 DDS

DimensionCA GatewayRaw ROS 2 DDS
Discovery overheadPeer registry resolved once at send timeGraph queried per message type at runtime
Naming couplingTyped registry — no topic names in behavior codePer-type topic names hard-coded
Transport flexibilityBackend swappable (DDS, Zenoh, MQTT)Tied to DDS
Fleet reconfigurationHandled automaticallyExplicit pub/sub rewiring required

🧠
Knowledge Base Interface

Connecting behaviors to the CORESENSE knowledge_core RDF triple store

C++ · as2_core

KBInterface

Synchronous-style API for asserting, retracting, and querying RDF facts. A dedicated background thread lets query_kb block safely from inside ROS 2 callbacks.

add_fact(subj, pred, obj)
remove_fact(subj, pred, obj)
query_kb(clauses, vars)   // first binding
query_kb_all(clauses, vars) // all bindings
register_event_handler(topic, cb)
Python · as2_python_api

KB Monitor Node

Event-driven mission layer. Declares RDF triple patterns; knowledge_core notifies on match. Mission scripts react without polling or direct call dependencies on behaviors.

Handler signature: handler(bindings, ctx) — plain Python function, no base class. ctx exposes query(), add_fact(), publish_mission_update(), pose, mission_status.

KB Monitor config (JSON — loaded at node startup)

{
  "kb_namespace": "kb",
  "handlers": [
    {
      "id": "assignment_done",
      "patterns": ["?drone is_assigned_to ?target"],
      "one_shot": false,
      "func": {
        "path": "/handlers.py",
        "func_name": "on_assignment"
      }
    }
  ]
}

Handler function (Python — invoked by knowledge_core on every pattern match)

def on_assignment(bindings, ctx):
    # bindings: list of dicts, one per matched triple set
    for b in bindings:
        msg = MissionUpdate()
        msg.drone_id = b['drone']
        msg.action   = MissionUpdate.RESUME
        msg.target   = b['target']
        ctx.publish_mission_update(msg)
    # ctx also exposes: ctx.query(), ctx.add_fact(), ctx.pose, ctx.mission_status

🏷️
Auction Behavior

Distributed task allocation via the auctions collective model

How it works

The auctioneer distributes inspection targets (items). All drones simultaneously compute distance-based costs (bids) and broadcast them via the CA Gateway. Each drone independently runs greedy_sequential — the same deterministic rule on the same bids produces the same assignment everywhere, with no central aggregator or extra communication rounds.

Auction message flow — interactive step-by-step
Press Next to walk through the auction protocol.
① Register ② Announce ③ Bid A→B ④ Bid B→A ⑤ Converge Auction Beh. A CA Client A CA Node A CA Node B CA Client B Auction Beh. B reg(StartAuction, cb) reg(Bid, cb) reg(StartAuction, cb) reg(Bid, cb) fwd(StartAuction) route(CAMsg) [ network ] dispatch(CAMsg) cb(StartAuction) fwd(Bid) [ network ] cb(Bid) fwd(Bid) [ network ] cb(Bid) CONVERGE CONVERGE knowledge_core add_fact(drone is_assigned_to target) add_fact(drone is_assigned_to target)

Plugin: greedy_sequential

Deterministic: assign each item to lowest-cost agent, break ties by namespace. Same rule + same bids = same assignment everywhere. No extra rounds.

Plugin: coordinate_item

Reads current pose from State Interface, computes Euclidean distance to a 3D target. Swappable without touching the behavior protocol.

KB Grounding

After convergence, asserts drone is_assigned_to target and auction_status done triples. KB Monitor triggers mission interpreter resumption for every drone.


🛡️
Collision Avoidance Behavior

Safe corridor arbitration via the consensus collective model

Core idea

Before any drone moves, it must acquire a distributed lock on its intended corridor. Peers grant the lock if their paths don't conflict. If two drones conflict simultaneously, the lexicographically smaller namespace wins. Consensus = receiving a grant from every known peer.

Pairwise path-lock state machine
IDLE grants all requests REQUESTING awaiting grants HOLDING motion may begin RELEASING flush deferred_ When IDLE: Grants every incoming CAPathLockRequest immediately. No path held. Sends: CAPathLockGrant When REQUESTING: Sends CAPathLockRequest to all peers. Waits for N grants (one per peer). Applies lex tie-break on conflict. When HOLDING: Corridor locked. Drone executes navigation. New conflicts → deferred_ queue. Sends: CAPathLockGrant / defer When RELEASING: Path complete. Broadcasts CAPathLockRelease, then flushes deferred_ queue. Sends: CAPathLockRelease new goal all grants in path done CAPathLockRelease broadcast → back to IDLE Three lock-response cases — every peer applies this rule on each incoming CAPathLockRequest: ① No path conflict Grant immediately. Store peer path for future conflict checks. ② Conflict while HOLDING Defer — push to deferred_ queue. Flush all on RELEASING. ③ Conflict while REQUESTING Lex tie-break: smaller namespace wins; larger defers immediately.
Path-lock message flow — interactive step-by-step
Press Next to walk through the path-lock protocol.
① Configure ② Read pose ③ Lock request ④ Grant ⑤ Release CA Behavior A State Interface [ network ] CA Behavior B configure([pose_topic]) sub get_value<PoseStamped>() PoseStamped {x, y, z, …} prepend → locked_path_ fwd(CAPathLockRequest, locked_path_) cb(LockRequest) evaluate conflict fwd(CAPathLockGrant) cb(LockGrant) → HOLDING fwd(CAPathLockRelease) cb(LockRelease) deferred → proceed

Conflict detection: path_geometry::min_polyline_distance() checks all pairs of segments between two polylines. If result < safety_distance (default 1.5 m), paths conflict.

Three grant/defer cases

  • No conflict: grant immediately, store peer path for future checks.
  • Conflict while HOLDING: defer — push to deferred_ queue, flush when RELEASING.
  • Conflict while REQUESTING (simultaneous): lex tie-break — smaller namespace grants immediately, larger namespace defers.
bool should_grant = true;
if (state_ == HOLDING && conflicts(req.path, locked_path_))
    should_grant = false;
else if (state_ == REQUESTING && conflicts(req.path, locked_path_))
    should_grant = req.requester_id < own_id_;  // lex priority

if (should_grant) {
    send_grant(req.requester_id, req.req_id);
    peer_held_paths_[req.requester_id] = req.path;
} else {
    deferred_.push_back({req.requester_id, req.req_id, req.path});
}

🎬
Inspection Scenarios

How components combine to enable D7.1 use-case families

Normal Operation — Complete Inspection Loop

1
Mission Start
Script calls
drone.auction()
2
Bid Exchange
Distance costs broadcast via CA Gateway
3
Converge
greedy_sequential assigns targets; KB asserted
4
KB Reaction
Monitor detects is_assigned_to, resumes mission
5
Path Lock
CollisionAvoidance acquires corridor locks
6
Navigate
Drones fly; locks released on arrival
Normal Operation

Full Inspection Loop

  1. Auction distributes PV panel targets
  2. KB grounding resumes each drone's interpreter
  3. Path-lock consensus ensures safe concurrent navigation
CA GatewayAuction BehaviorKB InterfaceCollision AvoidanceState Interface
UC1 — Robot Failure

Battery Decay & Replanning

  1. State Interface caches battery; Power Management detects anomaly
  2. KB fact drone0 battery_status critical triggers landing
  3. KB Monitor removes drone from fleet
  4. New auction reallocates uncovered targets
State InterfaceKB InterfaceKB MonitorAuction Behavior
UC2 — Emergency Landing

Safe Emergency Landing

  1. Failing drone invokes CollisionAvoidance with emergency path
  2. HOLDING peers grant immediately; REQUESTING peers apply lex tie-break
  3. On landing, CAPathLockRelease unblocks all deferred peers
CA GatewayCollision Avoidancepairwise_path_lock

Requirements Coverage

D7.2 functional requirements satisfied by the implemented components

IDDescriptionImplemented byStatus
IT-FR-002Collaborative planningAuction Behavior (greedy_sequential)✔ Satisfied
IT-FR-003System replanning on failureAuction Behavior triggered by KB Monitor✔ Satisfied
IT-FR-016Failure resilienceKB Monitor + re-auction on UC1✔ Satisfied
IT-FR-027Information sharing between agentsKB Interface (shared RDF store)✔ Satisfied
IT-FR-028Swarm size awarenessCA Gateway peer discovery (dynamic)✔ Satisfied
IT-FR-031Trajectory collective-awarenessCollision Avoidance (path-lock broadcast)✔ Satisfied
IT-FR-032Security distance maintenanceCollision Avoidance (safety_distance)✔ Satisfied
7/7
D7.2 requirements satisfied
4
D7.1 use-case families enabled
0
existing components modified
2
plugin hierarchies (swappable)