PROJECT · 02/08 · cohoma ← cd ..

// challenge ministère des armées · juin 2025

COHOMA.

Transmission de cartes 3D voxelisées depuis un drone vers un serveur central, en environnement contraint.

C++ · ASIOROS 2OctoMap PostgreSQLzlibDockerUDP
server_udp ↗ pointcloudCOMPLET ↗ drone_middleware ↗ pointCloudV2 ↗

// Contexte

Le Challenge COHOMA (Collaborative Human/Robot Machine Awareness) est organisé par le Ministère des Armées. L'objectif : transmettre des cartes 3D de l'environnement depuis un drone vers un serveur central en temps réel, via des réseaux contraints (Wi-Fi dégradé, UDP). Le projet couvre toute la chaîne : génération OctoMap, compression, transmission, réassemblage et stockage.

// Server UDP · C++ / ASIO

Serveur C++ utilisant Boost.ASIO pour recevoir des cartes OctoMap fragmentées via UDP. Pipeline : réception → réassemblage → décompression zlib → extraction des voxels → insertion PostgreSQL.

flowchart LR
  D["Drone (ROS 2)"] --> OM["OctoMap Server\npointcloud → octomap binaire"]
  OM --> MW["Middleware C++\ncompression zlib, envoi UDP"]
  MW --> NG["Net Guard\ncontrôle RSSI Wi-Fi\n(suspend si signal < seuil)"]
  NG -->|UDP fragments| SV["server_udp (C++ / ASIO)"]
  SV --> RE["Réassemblage blobs"]
  RE --> DC["Décompression zlib"]
  DC --> PV["Parsing voxels"]
  PV --> PG["INSERT PostgreSQL\nON CONFLICT UPDATE"]
        

// Middleware · ROS 2 + C++

Le middleware embarqué écoute le topic ROS 2 /octomap_binary, compresse l'OctoMap avec zlib et l'envoie en UDP. Un système de Net Guard surveille le RSSI Wi-Fi et suspend l'envoi si le signal est trop faible.

// Topics ROS 2

  • /depth/points → PointCloud2
  • /octomap_binary → Octomap

// Variables d'env

  • DRONE_ID (ex: DT1)
  • TRANSPORT_URL (udp://...)
  • RSSI_MIN (ex: -75 dBm)
  • WIFI_IFACE (ex: wlan0)

// Schéma DB

CREATE TABLE spatial_points (
  x INT, y INT, z INT,
  color_r SMALLINT, color_g SMALLINT,
  color_b SMALLINT, color_a SMALLINT,
  timestamp BIGINT,
  nb_records INT,
  PRIMARY KEY (x, y, z)
);

CREATE INDEX sp_xyz_gist
  ON spatial_points USING gist (point(x, y, z));

// INSERT ... ON CONFLICT ... UPDATE pour les mises à jour de voxels existants

// Refonte Python → C++

La version précédente (Python, stage IG4) était monolithique : middleware ROS 2 et insertion BDD dans le même nœud, sans séparation des responsabilités. Elle présentait des latences importantes (complexité O(n²) sur >10k voxels) et aucune logique réseau.

La refonte en C++17 + ASIO sépare middleware embarqué et serveur, avec thread-pool natif, zéro dépendance ROS côté serveur, et une fragmentation MTU-aware avec protocole d'entête binaire structuré (16 octets).

// Entête UDP — 16 octets (packé, little-endian)
struct UdpHeader {
  uint32_t seq;        // ID snapshot (drone_id + seq)
  uint32_t total_size; // Taille totale du blob compressé
  uint32_t offset;     // Offset du fragment courant
  uint16_t payload_len;// Longueur utile du fragment
  uint8_t  flags;      // Flags (START, END...)
  uint8_t  drone_id;   // Identifiant numérique du drone
};

// Points techniques

// Réseau contraint

UDP pour le temps réel, fragmentation des OctoMap, Net Guard avec contrôle RSSI.

// Multithreading

Serveur ASIO multithreadé : paquets en parallèle du réassemblage et de l'insertion DB.

// Compression

zlib niveau 1 pour réduire la taille des OctoMap avant transmission UDP.

// Index spatial

Index GiST sur point(x,y,z) pour des requêtes spatiales rapides sur les voxels 3D.