Détecter un bouchon sur une bretelle : de la caméra au panneau
Sur une route nationale, une bretelle de sortie qui se remplit finit par déborder sur la voie principale. Pour un gestionnaire de réseau, savoir tôt que la file se forme vaut mieux que le constater ensuite. Nous avons développé DAB (Détection Automatique de Bouchons) pour fournir cette information sous la forme la plus simple possible : un état binaire par bretelle surveillée, fiable et lisible par le superviseur qui pilote le panneau d’alerte.
Le besoin
Une caméra dotée d’une analyse vidéo embarquée sait compter les véhicules à l’arrêt dans une zone qu’on lui définit. Mais un compte de véhicules n’est pas un signal d’exploitation : MiVisu, le superviseur qui pilote le panneau d’alerte, attend un état net et stable, dans un protocole industriel. DAB fait ce travail de traduction : il reçoit les détections de la caméra, décide s’il y a bouchon, et expose le résultat en Modbus TCP.
DAB ne traite aucune image. Toute l’intelligence de détection reste dans la caméra ; DAB ne gère que la décision, l’historique et l’exposition.
La détection, dans la caméra
La règle de détection se programme directement dans l’interface d’analyse de la caméra, une SWISSTRAFFIC AI. On y dessine sur l’image la zone à surveiller, puis on assemble des opérateurs sous forme de graphe : la zone alimente un filtre de catégorie de véhicule, puis un opérateur de durée d’arrêt. Un véhicule qui reste immobile dans la zone plus longtemps que la durée programmée, 5 secondes dans cette configuration, déclenche une détection. C’est ce nombre de véhicules détectés que la caméra remonte à DAB.
Architecture
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#eef0ff','primaryTextColor':'#27262b','primaryBorderColor':'#5c5adc','lineColor':'#8a8da8','secondaryColor':'#f4f5ff','tertiaryColor':'#f4f5ff','edgeLabelBackground':'#eef0ff','clusterBkg':'#f4f5ff','clusterBorder':'#5c5adc'}}}%%
flowchart TB
CAM["Caméra SWISSTRAFFIC AI<br/>zone de détection<br/>véhicule à l'arrêt > durée programmée"] -->|"HTTP POST JSON<br/>(webhook)"| WEB
subgraph SRV["Serveur DAB · Debian"]
WEB["nginx + PHP-FPM<br/>logique de décision"] -->|"écriture"| DB[("SQLite<br/>mode WAL")]
DB -->|"lecture toutes les secondes"| MB["dab-modbus<br/>serveur Modbus C · libmodbus"]
UI["Interface web<br/>supervision · historique<br/>forçage · rôles"] <--> DB
end
MB -->|"Modbus TCP · fonction 2<br/>1 bit par site"| MIV["MiVisu<br/>superviseur · LABOCOM"]
MIV -->|"LCR"| PAN["Panneau de police dynamique<br/>pictogramme BOUCHON"]
Côté DAB, la chaîne tient en quatre maillons :
- La caméra notifie DAB par un message JSON qui porte l’identifiant du site et le nombre de véhicules détectés.
- L’ingestion est assurée par nginx (POST uniquement, taille des requêtes bornée) puis PHP-FPM. Un identifiant de site inconnu est rejeté : seuls les sites déclarés dans l’interface sont acceptés.
- L’état est stocké dans SQLite en mode WAL, partagé entre PHP et le serveur Modbus : une ligne par site pour l’état courant, une table d’historique à part.
- L’exposition est confiée à un logiciel dédié, écrit en C, qui lit l’état et le publie sur le port Modbus.
Une décision asymétrique
La règle de décision tient en deux phrases : dès qu’au moins un véhicule à l’arrêt est détecté, le site passe en BOUCHON immédiatement ; il ne retombe en LIBRE qu’après un délai sans aucune détection, de l’ordre de la minute et réglable dans l’interface.
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#eef0ff','primaryTextColor':'#27262b','primaryBorderColor':'#5c5adc','lineColor':'#8a8da8','secondaryColor':'#f4f5ff','tertiaryColor':'#f4f5ff','edgeLabelBackground':'#eef0ff','clusterBkg':'#f4f5ff','clusterBorder':'#5c5adc'}}}%%
flowchart LR
LIBRE(["LIBRE"]) -->|"véhicule à l'arrêt détecté<br/>(immédiat)"| BOUCHON(["BOUCHON"])
BOUCHON -->|"nouvelle détection :<br/>le délai repart à zéro"| BOUCHON
BOUCHON -->|"aucune détection pendant<br/>le délai d'hystérésis"| LIBRE
style LIBRE fill:#e3f5ea,stroke:#2fb37a,color:#27262b
style BOUCHON fill:#fde8e8,stroke:#e5484d,color:#27262b
L’hystérésis ne porte donc que sur la retombée. Sans elle, un véhicule qui redémarre, une occultation passagère ou une mesure à zéro entre deux voitures ferait osciller le bit, et donc l’affichage du panneau. Avec elle, DAB ne retarde jamais l’alerte, et seul le retour à la normale est lissé.
Trois détails de conception comptent :
- Le retour à LIBRE est géré côté serveur. En plus de la logique du webhook, le serveur Modbus vérifie lui-même chaque seconde si le délai d’hystérésis est écoulé : un site ne reste donc pas bloqué en BOUCHON si la caméra cesse d’émettre.
- La vie de la caméra est suivie, à titre informatif. Chaque trame reçue, y compris une simple trame de vie sans comptage de véhicules, rafraîchit l’horodate du site. L’interface en déduit un état (en ligne, silencieuse, hors ligne) d’après l’âge de la dernière trame, visible dans la surveillance et dans la table de correspondance Modbus. Cet indicateur alerte l’exploitant mais n’agit pas sur le bit exposé, qui ne dépend que des détections et du forçage.
- Seules les transitions sont journalisées, pas chaque mesure. L’historique reste compact et chaque ligne correspond à un événement qu’un exploitant peut lire.
- Un forçage manuel par site (automatique, libre ou bouchon) prend le pas sur la détection, y compris sur le bit exposé en Modbus. Il est réservé au rôle administrateur, protégé contre le CSRF, et tout changement d’état qu’il provoque est tracé dans l’historique. Il permet par exemple de tester la chaîne de bout en bout avec le superviseur sans attendre un vrai bouchon, ou de neutraliser un site le temps d’une intervention.
Le serveur Modbus en C
Modbus TCP demande un serveur à l’écoute en permanence sur le port 502, avec des connexions persistantes : ce n’est pas le métier de PHP-FPM. D’où un logiciel dédié, écrit en C et construit sur libmodbus.
Il tient une boucle select() qui sert plusieurs clients simultanés, relit la base chaque seconde, et alimente deux tables en mémoire : les Discrete Inputs (fonction 2), un bit par site à l’adresse choisie dans l’interface, et un miroir en Holding Registers (fonction 3) pour tolérer un client Modbus mal configuré qui interrogerait en lecture de registres. Voici l’échange pour huit sites, où seul le site d’adresse 0 est en BOUCHON (unit id 1 à titre d’exemple) :
Requête 00 01 00 00 00 06 01 02 00 00 00 08 lecture de 8 entrées à partir de l'adresse 0
Réponse 00 01 00 00 00 04 01 02 01 01 1 octet de données : bit 0 à 1
Quelques choix d’exploitation :
- Le statut du serveur (PID, durée de fonctionnement, dernière lecture de la base, nombre de sites) est écrit dans un fichier JSON de façon atomique, par écriture dans un fichier temporaire puis renommage, pour que l’interface web ne lise jamais un fichier à moitié écrit.
- Il s’arrête proprement sur SIGTERM et ignore SIGPIPE, pour qu’une déconnexion brutale d’un client ne le fasse pas tomber.
- L’unité systemd est durcie : utilisateur non privilégié,
NoNewPrivileges,PrivateTmp, système de fichiers en lecture seule hors des deux répertoires de travail, et la capacitéCAP_NET_BIND_SERVICEpour écouter sur le port 502 sans être root.
En aval : MiVisu et le panneau
DAB ne pilote aucun panneau : il ne connaît ni l’équipement ni son protocole. C’est le superviseur MiVisu, édité par la société LABOCOM, qui s’en charge. MiVisu scrute l’état de chaque site de détection en Modbus TCP auprès de DAB, puis commande en LCR un panneau de police dynamique. Quand un site passe en BOUCHON, le panneau affiche à l’attention des usagers un pictogramme de danger représentant une file de véhicules, avec la mention BOUCHON.
Cette séparation garde DAB indépendant du panneau : changer d’afficheur n’oblige pas à toucher à la détection.
L’interface d’exploitation
L’interface web, en PHP, couvre l’ensemble de la vie du système :
- un tableau de bord : sites surveillés, bouchons actifs, voies libres, état du serveur Modbus ;
- une surveillance en temps réel, rafraîchie toutes les 5 secondes, avec l’état de chaque caméra ;
- un historique des transitions avec graphiques ;
- une page Interface Modbus : paramètres d’écoute et table de correspondance entre chaque adresse et l’état du site, avec la valeur réellement exposée ;
- la configuration des sites (identifiant de la caméra, nom, adresse Modbus, unique par site) et le réglage de l’hystérésis ;
- la gestion des utilisateurs avec trois rôles : administrateur, opérateur, lecteur.
Côté réseau, nginx limite le débit des tentatives de connexion et des appels d’API, applique HSTS, et refuse l’accès direct à la configuration et aux fichiers cachés.
Technologies
Analyse vidéo embarquée (caméra SWISSTRAFFIC AI), HTTP (webhook JSON), Modbus TCP (fonctions 2 et 3), LCR (panneau, via MiVisu), nginx, PHP-FPM, SQLite (WAL), C (libmodbus), systemd, Debian.