Application de Splunk pour la sécurité... routière !

DamienLe 4 décembre 2024

Application de Splunk pour la sécurité… routière !


Introduction

Splunk est un logiciel de recherche, de suivi et d'analyse de données machines permettant d’aider les organisations à découvrir, extraire et exploiter tout le potentiel caché de leurs données. En tant que tel, ses champs d’application sont quasi-infinis dans la mesure où chacune de nos actions peut aujourd’hui générer une information à analyser.

Je propose donc de prouver cela par un exemple concret d'application de Splunk dans un domaine bien particulier : l’analyse de comportements humains.

Constat : Une rue à faible visibilité, d'une largeur insuffisante pour permettre à deux voitures de se croiser, sans aucun trottoir pour les résidents qui sortent de leur domicile, une vitesse limitée à 30 km/h, et pourtant de nombreux automobilistes roulent beaucoup trop vite et commettent à l'évidence des infractions à répétition.

Action : Demande faite à la commune pour mettre en œuvre les mesures de sécurité adéquates.

Résultats : Après plus d'un an, toujours aucune action mise en œuvre.

Idée : Si les personnes décisionnaires ne prennent aucune mesure correctrice, c'est qu'elles n'ont pas les éléments prouvant leur nécessité, et que rien ne les contraint à le faire ou à le traiter en priorité.

Pour faire avancer la situation, l'idéal serait donc que j'arrive à mesurer et analyser moi-même la situation pour l'exposer de manière plus factuelle qu'un simple constat du type « on trouve que les voitures roulent vite dans cette rue ».

La seule preuve concrète et respectueuse du règlement général sur la protection des données à caractère personnel serait de mesurer la vitesse des véhicules sans identification de ces derniers ni de leurs conducteur(rice)s pour quantifier et exposer de manière factuelle le comportement déviant de certains automobilistes.


Concept

L’objectif est le suivant : générer les données relatives à la vitesse des véhicules afin de pouvoir la collecter et l’exploiter dans Splunk. La condition sine qua non est donc d’arriver à la mesurer de façon simple, peu onéreuse, et sans avoir à disposition un radar des forces de l’ordre.

Comme chacun le sait, la vitesse est la grandeur définie par le temps mis à accomplir une action (dans le cas présent : parcourir une certaine distance). Par chance, j’ai à ma disposition un environnement idéal : deux fenêtres en rez-de-chaussée orientées dans le même sens, positionnées sur un même mur directement adjacent à la rue, à la même hauteur, et à une distance de plusieurs mètres l’une de l’autre.

  • Cette distance étant fixe et mesurable, il suffit donc de chronométrer le temps mis à la parcourir afin d’en déterminer la vitesse au même titre qu’un radar tronçon :

Figure 1 : Principe d'un radar tronçon

  • Inconvénients :

    • Ce système ne permet que de calculer la vitesse moyenne sur cette portion. Cependant, elle peut être considérée comme étant quasi égale à la vitesse instantanée étant donné la faible distance parcourue.

    • RGPD oblige (pour mieux comprendre les principes de la protection des données personnelles, voici un autre article de notre blog : https://www.algosecure.fr/actualites/article/rgpd-conservation-donnees-personnelles), je ne pourrai pas non plus utiliser de caméras, donc je ne pourrai pas garantir à 100% que deux de détections correspondent bien à un même véhicule, ni même d’ailleurs que ce soit bien un véhicule.

    Acceptés : L’objectif n’est pas de fabriquer un radar parfait et homologué. La priorité est pour moi d’avoir de la donnée à exploiter rapidement et simplement, même si celle-ci est une estimation. La précision pourra toujours être améliorée dans un second temps si nécessaire.

  • Avantages :

    • Simple, sous réserve d’arriver à chronométrer le temps de parcours

    • En fonction de l’ordre chronologique des détections, je pourrai en déduire le sens de circulation afin de prendre en compte ce paramètre dans mes statistiques. L’une des hypothèses que je souhaiterais valider est la suivante : les véhicules roulent plus rapidement et commettent davantage d’excès de vitesse en entrant dans le village qu’en y sortant. Cela pour une raison simple : la topologie de la rue offre une meilleure et plus longue visibilité dans ce sens-là. Si je peux prouver qu’un sens particulier de circulation est plus sujette aux excès de vitesse qu’une autre, alors cela permettrait d’aider les personnes décisionnaires à faire des choix plus pertinents quant aux moyens à mettre en œuvre pour améliorer cette situation de manière plus efficace.

Pour mesurer le temps parcouru, il faudrait donc détecter de manière automatique lorsqu’un véhicule passe deux points de référence (ici mes deux fenêtres). Une solution offre pour cela un très bon compromis entre simplicité, coût et efficacité : les capteurs.

Aucun besoin de déporter le calcul ailleurs que dans Splunk : j’ai uniquement besoin que mes deux points de référence m’indiquent le moment exact auquel ils détectent un mouvement et que je récupère cette donnée.

  • Si je parviens à avoir ces valeurs de temps, alors je pourrais en déduire la durée.
  • Ayant déjà la distance qui est fixe, j’en déduirai la vitesse, dont l’unité de mesure la plus pertinente sera le nombre de mètres par seconde.
  • Il me suffira ensuite de la convertir en kilomètres par heure grâce au calcul suivant : il y a mille mètres dans un kilomètre et trois mille six cents secondes dans une heure donc $1$ m/s = $(1/1000) / (1/3600)$ = $3600 / 1000$ = $3,6$ km/h.
  • J’aurais alors l’heure et la vitesse des véhicules dans Splunk, et je n’aurai plus qu’à l’exploiter.


Le système de détection

Les contraintes

Il me faut gérer moi-même les détections et leurs envois vers Splunk en horodatant l’information transmise.

  • Ainsi, peu importe le temps que met cette donnée à être reçue : c’est l’heure indiquée au sein de l’information qui fera foi et non celle de réception de cette dernière.

Les deux points de mesure étant éloignés l’un de l’autre de plusieurs mètres, il me faut donc deux systèmes de détection indépendants et parvenir à ce qu’ils soient synchronisés au niveau temporel.

Enfin, je souhaite travailler sur une solution open-source pour des raisons de budget et pour donner à chacun la possibilité de reprendre et améliorer cette solution.

Le matériel

Mon serveur Splunk étant déjà en place, configuré, et en fonctionnement, ce point-là est déjà réglé et le choix du matériel va se porter uniquement sur le système de détection des véhicules.

Étant donné que j'ai décidé d'utiliser des capteurs, les composants open-source qui me permettront de les gérer en autonomie, de manière peu onéreuse, tout en me laissant une complète liberté au niveau du code exécuté sont les cartes Arduino.

  • L'objectif étant que la donnée soit collectée dans Splunk, il faut donc qu'elle transite sur le réseau jusqu'à mon serveur.
  • Bien qu'il soit possible d'utiliser une liaison filaire avec un câble RJ45 pour la communication depuis un Arduino via un composant spécifique (Shield Ethernet), je n'ai pas vraiment envie d'acheter et d'installer des mètres de câbles entre mes chambres et mon bureau.
  • Je vais par conséquent privilégier une connexion sans fil avec des cartes qui prendront en charge directement ce mode de communication : des Arduino R4 Wifi.

Figure 2 : Carte Arduino R4 Wifi

Au niveau de la connectique, je possède déjà des fils de connexion nécessaires pour pouvoir relier les capteurs aux cartes.

Figure 3 : Fils de connexion Arduino

Au niveau des capteurs, mon choix se porte sur le modèle infrarouge HC-SR501 :

Figure 4 : Capteur de mouvement HC-SR501

Principales caractéristiques :

  • Gamme de détection : 110 degrés
  • Détection de la distance : jusqu'à 7 mètres
  • Temps de blocage : 2,5s par défaut
  • Possibilité de réglage de la sensibilité et de la temporisation

Figure 5 : Broches capteur HC-SR501

Il suffit donc de connecter le capteur à la carte Arduino comme suit :

Broche capteur Broche Arduino
VCC 5V
OUT D2 (au choix)
GND GND

Figure 6 : Connexion du capteur HC-SR501 à l’Arduino

Le code Arduino

Contrainte n°1: le temps

La première chose essentielle qu'il a fallu déterminer est la manière de synchroniser les deux cartes Arduino au niveau temporel. En effet, de base les cartes n'ont aucune connaissance de l'heure qu'il est. La seule composante temporelle en leur possession est le nombre de millisecondes écoulées depuis qu’elles ont commencé à exécuter le programme en cours, qui est réinitialisé après environ 50 jours (cette valeur peut être récupérée via la fonction millis()).

Problème : il est impossible de faire démarrer les deux cartes en même temps à la milliseconde près donc cette valeur est inutilisable.

Solution : Les cartes étant connectées au réseau Wifi, elles peuvent donc avoir accès à Internet.

  • Il existe un protocole bien connu permettant de synchroniser l'horloge locale des machines via le réseau : le protocole NTP (Network Time Protocol).
  • Mes cartes pourront ainsi récupérer et transmettre cette heure qui sera toujours correcte, même si nous vivons dans un pays qui change d'heure deux fois par an.
  • Il me reste donc à trouver le moyen de faire interroger un même serveur NTP par mes cartes pour qu'elles se synchronisent avec celui-ci à la même heure.
  • Heureusement, les Arduino fonctionnant sous code open-source, des librairies existent généralement pour chaque besoin dont celui-ci avec la librairie ezTime.

Contrainte n°2 : l'envoi des données à Splunk

Les cartes Arduino ne possèdent pas de système d'exploitation et donc ne peuvent pas accueillir un agent Splunk déjà packagé.

  • Par chance, il existe de nombreuses autres méthodes de collecte dans Splunk.
  • L'une de ses méthodes déjà éprouvée dans mon contexte professionnel est l'utilisation du HEC (HTTP Event Collector), qui permet d’envoyer les données à une instance Splunk via le protocole HTTP/HTTPS.
  • Il me reste donc à trouver le moyen de faire envoyer par mes cartes les données reçues des capteurs dans des paquets HTTP à destination de mon serveur Splunk qui sera préalablement configuré pour les collecter et les indexer correctement.
  • Exceptionnellement, je ne sécuriserai pas le flux via HTTPS car je ne transmets aucune donnée sensible et je travaille dans un cadre personnel.

Contrainte n°3 : l'identification des capteurs

Afin de pouvoir analyser la durée et l'ordre des détections, il me faut identifier de manière fiable et unique le capteur qui communique ses données. Il est possible de spécifier manuellement la valeur de la métadonnée « host » identifiant la source de la donnée dans Splunk mais je souhaite avoir un code unique quel que soit mon capteur et utiliser une seule entrée de données pour toutes mes cartes Arduino.

  • La solution choisie consiste à utiliser le dernier octet de l'adresse IP retournée par mon serveur DHCP aux cartes.
  • Je sais en effet que mon réseau Wifi utilise un masque en /24 fournissant ainsi jusqu’à 254 IP potentielles disponibles entre les adresses X.X.X.1 et X.X.X.254. Le dernier octet sera donc toujours unique.
  • Il me suffit de faire attribuer une adresse statique à chacune de mes cartes par mon serveur DHCP pour garantir qu'elles ne changeront jamais même après redémarrage, puis de récupérer et d’utiliser le dernier octet attribué pour forger un nom unique à chaque carte.

Algorithmie et structure du code :

Toute création de code nécessite au préalable deux choses :

  1. Connaître la structure du programme pour le langage utilisé
  2. Réfléchir à l'algorithmie nécessaire pour répondre au besoin

La structure d’un code Arduino reprend beaucoup d'éléments communs à d'autres langages plus complexes :

  1. Importation des libraires (facultatif si non utilisées)
  2. Création des variables et constantes globales (facultatif)
  3. Fonctions (facultatif)
  4. Partie "Setup" :
    • Identifiée par la fonction setup()
    • Exécutée directement après le démarrage de la carte
    • Exécutée une seule et unique fois
    • Utilisée pour initialiser les variables, les modes des broches de la carte et commencer à utiliser les librairies
  5. Partie "Loop"
    • Identifiée par la fonction loop()
    • Exécutée directement après la partie setup()
    • Exécutée en boucle infinie
    • Utilisée pour réaliser les principales opérations de l'application

L'algorithmie envisagé pour mon besoin en fonction de cette structure sera donc le suivant :

  1. Importation des librairies nécessaires pour la connexion Wifi, la synchronisation NTP, et les envois HTTP

  2. Création des variables et constantes globales nécessaires

  3. Partie Setup avec :

    • Connexion à mon réseau Wifi
    • Récupération du dernier octet de l'adresse IP pour forger le nom de la carte
    • Initialisation de l'heure et de la fréquence de mise à jour NTP
    • Initialisation de la broche 2 de la carte pour lire les données du capteur
  4. Partie Loop avec :

    • Lecture des données du capteur
    • Si un mouvement est détecté : forger et envoyer la donnée à Splunk puis réinitialiser le capteur et attendre qu'il revienne à son état initial
    • Sinon ne rien faire

Voici donc le code finalement utilisé par chacune des cartes Arduino :

// Importation des librairies

// NTP
#include  <ezTime.h>

// Connexion Wifi
#include  <WiFi.h>

// Envoi des paquets HTTP
#include  <ArduinoHttpClient.h>  

// Fichier dédié contenant mes données sensibles (SSID, clé Wifi, adresse IP de mon serveur Splunk, et token d’authentification vers ce dernier)
#include  "arduino_secrets.h"

// Paramètres Wifi récupérés depuis le fichier arduino_secrets.h
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;

// Paramètres de connexion à Splunk récupérés depuis le fichier arduino_secrets.h
char splunkindexer[] = SPLUNK_IDX;
char collectorToken[] = SPLUNK_TOK;
int port = 8088;

// Initialisation des variables qui me seront nécessaires par la suite

// Pour la connexion Wifi
WiFiClient wifi;
int status = WL_IDLE_STATUS;

// Pour le NTP
Timezone France;
// Pour la connexion à Splunk
HttpClient client = HttpClient(wifi, splunkindexer, port);

// Pour la broche et les états du capteur
int sensorPin = 2;
int sensorState = LOW;
int sensorValue = 0;

// Pour les éléments à transmettre à Splunk
String date;
String eventData;
String host;

// Fonction utilisée pour les envois vers Splunk
void  splunkpost(String collectorToken,String PostData, String Host)
{
  // Affichage des données à envoyer
  Serial.println(PostData);

  // Inclusion des évènements à envoyer dans le paquet HTTP
  String postData = "{ \"event\": \"" + PostData + "\"}";

  // Authentification via token
  String tokenValue="Splunk " + collectorToken;

  // Initialisation du client
  client.beginRequest();

  // Définition de l’URL à contacter pour les envois en HTTP POST
  client.post("/services/collector/event");

  // Définition des différents en-têtes du paquet HTTP
  client.sendHeader("Content-Type", "application/application/json");
  client.sendHeader("Content-Length", postData.length());
  client.sendHeader("Host", Host);
  client.sendHeader("Authorization", tokenValue);

  // Inclusion des données
  client.beginBody();
  client.print(postData);

  // Fin de transmission de la requête
  client.endRequest();

  // Lecture et affichage du code retour et du corps de la réponse
  int statusCode = client.responseStatusCode();
  String response = client.responseBody();
  Serial.print("POST Status code: ");
  Serial.println(statusCode);
  Serial.print("POST Response: ");
  Serial.println(response);
}

// Partie setup
void  setup() {
  // Définition du débit de données en bits par seconde (baud) pour la transmission de données sur le moniteur série de la carte.
  Serial.begin(9600);

  // Connexion Wifi avec affichage des informations en série
  while  ( status != WL_CONNECTED)  {
    Serial.print("Attempting to connect to Network named: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);
  }

  // Récupération et affichage de l’adresse IP allouée
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // Utilisation du dernier octet pour paramétrer le nom d’host unique
  host="sensor"+String(ip[3]);

  // Paramétrage du serveur NTP à contacter, de la fréquence des synchronisation et affichage des évènements de synchronisations
  setServer("ntp.unice.fr");
  setInterval(60);
  waitForSync();
  setDebug(INFO);

  // Paramétrage de la timezone, essentielle pour avoir l’heure correcte
 France.setLocation("Europe/Paris");

  // Paramétrage de la broche du capteur en mode entrée et envoi des premières données à Splunk pour valider la communication initiale
  pinMode(sensorPin, INPUT);
  eventData="Initializing System...";
  splunkpost(collectorToken,eventData,host);

  // Pause de 5s pour laisser le temps au capteur de s’initialiser
  delay(5000);
}

// Partie loop
void  loop() {
  // Synchronisation NTP de manière récurrente à la fréquence définie
  events();

  // Lecture de la valeur du capteur
  sensorValue = digitalRead(sensorPin);

  // Si le capteur a détecté un mouvement
  if  (sensorValue == HIGH) {
    // Si le capteur n’avait rien détecté avant
    if  (sensorState == LOW) {
      // On forge la donnée à envoyer avec la date en millisecondes
      eventData=France.dateTime("d-m-Y H:i:s.v") + " - Motion detected !";
      // On transmet la donnée grâce à la fonction créée
      splunkpost(collectorToken,eventData,host);
      // On positionne l’état du capteur comme étant en détection
      sensorState = HIGH;
      // On attend 1s pour un début de temporisation
      delay(1000);
    }
  }

  // Si la variable d’état du capteur est en détection
  if  (sensorState == HIGH) {
    // On attend encore 1s
    delay(1000);
    // On positionne sont état en mode non-détection pour faire la lecture suivante
    sensorState = LOW;
  }
}


La collecte dans Splunk

L'ensemble de la configuration d'un serveur Splunk étant déjà documentée sur le site de l’éditeur, je me contenterai uniquement d'indiquer la configuration nécessaire à l'entrée des données de mes cartes Arduino :

  1. Un index pour réceptionner, compartimenter et stocker les données Arduino que je vais pouvoir interroger :

Figure 7 : Index Splunk

  1. Une entrée HTTP Event Collector avec un token d’authentification pour recevoir les données transmises par les Arduino sur un port bien spécifique (TCP 8088 par défaut) et les stocker dans l’index précédemment créé :

Figure 8 : Inputs HEC Splunk


Les résultats

Sur la carte

Une fois le code téléversé sur la carte, voici les données qui s’affiche sur le moniteur série (avec génération d’un mouvement devant le capteur) :

Figure 9 : Résultats en série sur l’Arduino

A chaque mouvement qui survient au niveau du capteur j'ai donc l'heure et la notification transmise à Splunk avec un code retour HTTP 200 (OK).

Dans Splunk

En cherchant dans l’index sur la période concernée, je retrouve bien les données de mes deux cartes identifiées de manière unique (les logs ci-dessous sont évidemment différents de ceux précédemment affichés sur le moniteur série de la carte Arduino) :

Figure 10 : Logs dans Splunk

J'ai donc bien les données générées par mes capteurs, transmises par mes cartes Arduino, reçues et stockées dans mon serveur Splunk. Il reste à les exploiter et les analyser mais avant cela, un problème doit au préalable être résolu.


Adaptations des capteurs

Les premiers tests réalisés étaient concluants en environnement intérieur mais en les réalisant en conditions réelles dans la rue, j'ai constaté un taux élevé de faux positifs avec des détections sans qu'aucun véhicule ne soit présent. La raison est la suivante : les capteurs de mouvements infrarouges fonctionnent avec un large faisceau de détection (110 degrés pour ce modèle de capteurs).

  • Dans mon salon, il n'y avait aucun mouvement autres que ceux que je déclenchais moi-même pour mes tests de fonctionnement.
  • Dans la rue, il en est tout autrement : le vent qui fait bouger les feuilles, un oiseau qui se pose sur un muret, un sac en plastique qui virevolte de manière poétique... Les mouvements sont divers et variés et chacun d'entre eux est détecté par mes capteurs.
  • Si je souhaite limiter ce phénomène pour me concentrer sur les mouvements qui m'intéressent alors il faut que je bride moi-même le faisceau de détection des capteurs, afin que seule une zone limitée soit surveillée.

Malheureusement, je ne peux pas réduire l'angle du faisceau au niveau du capteur comme la portée et la temporisation qui sont modifiables à l'aide d'un tournevis sur de petits potentiomètres.

  • Je vais donc devoir obstruer les capteurs assez finement pour limiter le faisceau dans une zone restreinte.
  • Contrainte : il faut que cette obstruction soit strictement identique entre mes deux capteurs pour éviter toute différence de comportement entre eux.

J'ai donc improvisé avec les éléments à ma disposition :

  • Deux petites boîtes de conserve vides et identiques
  • Des morceaux d'un même carton
  • Quatre trombones identiques
  • De la patafix
  • Un marteau et quelques clous

L'idée à partir de ces éléments :

  1. Enfermer mes capteurs au fond des boîtes de conserves
  2. Les fixer avec des trombones dépliés faisant office de fils de fer, en prévoyant également d'autres trous pour faire passer les fils de connectiques vers la carte Arduino
  3. Découper des cercles de cartons du même diamètre que les boîtes
  4. Les évider d'un petit trou
  5. Scotcher ces derniers pour obstruer les ouvertures

Le tout devant rester immobile, je complète avec deux petits couvercles d'emballages identiques pour servir de supports stables sur lesquels sont scotchées les boîtes.

Le résultat :

Figure 11 : Montage final du système de détection - recto

Figure 12 : Montage final du système de détection - verso

Merci à Angus de m’avoir appris qu’il existait toujours une solution étonnante pour résoudre un problème !

MacGyver

Après les avoir installés sur les bords de fenêtre, les détections ont directement été plus pertinentes : plus aucune détection de mouvements parasites et uniquement ceux d'objets qui passent exactement en face des capteurs (même si cela inclut d'autres éléments que les véhicules, par exemple les piétons, mais je traiterai ces faux-positifs dans mes calculs au sein de Splunk).


Exploitation des données

Une fois les données dans Splunk, et leurs champs extraits (même si dans le cas présent je n'ai pas eu à réaliser cette étape puisque seuls l'heure de l'évènement et l'identité de la carte source m'étaient nécessaires), elles peuvent être exploitées, manipulées, mises en forme, et enrichies grâce au langage de requêtage de Splunk : le SPL (Search Processing Language).

Ce langage étant documenté sur le site de l'éditeur, je me contenterai d'exposer progressivement l'élaboration de la requête pour illustrer comment, par différentes étapes successives, nous partons de données brutes pour arriver à des données mises en forme dans Splunk :

  1. J’interroge l’index concerné sur la période qui m’intéresse :

spl1

  1. Je m’occupe dès maintenant de définir quel capteur se trouve à quelle position :

spl2

result2

  1. Je regroupe les évènements par paquets de deux, en partant du principe :
    • Qu’il y a 2 secondes maximum de pause entre les passages de véhicules (car temporisation paramétrée dans le code des cartes Arduino entre chaque mesure)
    • Qu’il y a un délai de 1s maximum entre chaque évènement d’un même bloc (car si un élément met plus d’une seconde à parcourir la distance entre les deux fenêtres, cela correspond à une vitesse inférieure à 12km/h, ce qui est certainement un faux-positif car aucune voiture ne roule aussi lentement dans la rue)
    • Gros avantage de cette commande : elle calcule directement la durée entre l’évènement le plus ancien et le plus récent du bloc

spl3

result3

  1. Je ne conserve que les blocs avec deux capteurs différents au cas où :

spl4

  1. Je commence à générer un tableau avec les données qui m’intéressent :

spl5

result5

  1. Je renseigne la distance entre les capteurs, et je commence mes calculs : en fonction de l’ordre des capteurs, j’en déduis la direction, et en fonction de la durée, j’en déduis la vitesse en m/s que je convertis ensuite en km/h :

spl6

result6

  1. Je conserve les vitesses plausibles entre 15 et 75 km/h et retire 5 km/h à la valeur calculée pour inclure la même marge d’erreur que les radars homologués :

spl7

  1. Je me renseigne sur le site www.service-public.fr et identifie les éléments suivants en fonction du niveau d’infraction :

Figure 13 : Amendes et points en fonction des excès de vitesse

  • Je sais donc que dans mon contexte, les amendes seront uniquement de 135€ quel que soit le niveau d’infraction, et le nombre de points en fonction des différents seuils d’excès de vitesse
  • J’exclus le dernier cas de 50 km/h et plus car celui-ci ne fait pas partie des valeurs plausibles dans mon contexte
  1. Je paramètre donc ces éléments en fonction de la vitesse mesurée, en sachant que la limite est de 30 km/h :

spl8

result8

  1. Je ne conserve que les champs qui me sont utiles pour l’analyse :

spl9

result9

De plusieurs simples logs de détection de mouvement, nous nous retrouvons donc avec :

  • L'heure du passage devant les deux capteurs
  • La vitesse en km/h mesurée et abaissée pour concorder avec le fonctionnement des radars homologués
  • La direction de passage de l'objet
  • Le niveau d'infraction en cas de vitesse supérieure à 30 km/h
  • L'amende correspondant à l'infraction
  • Le nombre de points retirés correspondant à l'infraction
  • La suppression d'un maximum de faux-positifs en ne gardant que les vitesses plausibles et pouvant correspondre à celle d'un véhicule dans mon contexte

Il ne reste donc plus que la dernière étape de traitement, celle qui permet de mettre en évidence la valeur de la donnée et de la rendre accessible à tous : le dashboarding !


Dashboard et analyse

De la même manière que le langage SPL, l'idée n'est pas de montrer l'ensemble de la configuration d'un tableau de bord sur Splunk mais comment il est possible, à partir d'une donnée technique, d'arriver à un résultat beaucoup plus visuel, accessible et interprétable par tous.

Voici donc les différents éléments du dashboard créé, volontairement séparés pour une meilleure lisibilité, et sur une période d'analyse représentative de 24h consécutives :

dash1

dash2

Les données parlent d’elles-mêmes :

  • Un tiers d’excès de vitesse (malgré avoir retiré 5 km/h aux mesures)
  • Plus de 27 k€ d’amendes et presque 170 retraits de points sur cette journée
  • Les plus grandes infractions sont généralement commises dans la matinée, aux alentours de midi (pauses déjeuner), et en fin d’après-midi (retours du travail)

dash3

La majorité des infractions sont situées entre 5 et 19 km/h au-dessus de la vitesse autorisée (donc une vitesse entre 35 et 49 km/h).

dash4

La vitesse moyenne est proche de la limite autorisée.

Mais le 90ème percentile est plus de 10 km/h au-dessus, ce qui signifie qu’une personne sur dix roule à plus de 42 km/h.

L’écart type est de 11 km/h, ce qui correspond à la dispersion des données autour de la valeur moyenne : cela permet de mettre en évidence les différences de comportements entre les automobilistes. Un faible écart-type indiquerait qu’une grande partie roulent à une vitesse proche de la valeur moyenne (28 km/h pour cette journée). Plus l’écart-type augmente, plus les valeurs sont au contraire dispersées.

dash5

Il y a légèrement plus de sorties du village que d’entrées.

Le nombre d’entrées augmente brusquement en fin d’après-midi (certainement dû aux retours du travail) tandis que les sorties sont davantage étalées dans le temps.

dash6

Malgré le nombre de passages plus élevés en sortie du village, plus de 76% des infractions sont faites dans le sens inverse, et ce quelle que soit l’heure.

Les infractions en entrée du village sont à un niveau d’excès de vitesse largement supérieur à celui du sens inverse.

Cela confirme mon hypothèse concernant la topologie de la rue qui incite davantage à ces comportements déviants dans ce sens-là de circulation.


Conclusion

La création de ce projet m'a permis de valider plusieurs hypothèses concernant le comportement des automobilistes et leurs causes associées.

Les objectifs que je m’étais fixés étaient notamment :

  1. De parvenir, à mon niveau et avec les moyens à ma disposition, à répondre par moi-même à ce besoin d'analyse.
  2. De prouver qu'il n'y a que l'imagination qui bride les champs d'application de Splunk tant qu'il est possible de lui donner de la donnée à exploiter.

J’ai rempli le premier objectif, et j’ose espérer avoir également réussi à remplir le second pour celles et ceux qui auront eu le courage de me lire jusqu’ici 😊 !

Happy Splunking !


Axes d’amélioration

Comme tout projet, celui-ci n'est pas parfait... Pas au niveau de Splunk (évidemment), qui effectue très bien son travail de collecte et d'exploitation des données, mais au niveau du système de détection encore au stade de bricolage et qui comporte des défauts non négligeables :

La précision temporelle

Le plus important d'entre eux et la synchronisation du temps entre les cartes Arduino. En effet, malgré avoir tenté de résoudre cela au maximum, n'importe quelle machine se désynchronise perpétuellement de quelques millisecondes, même en interrogeant un serveur NTP toutes les minutes. Cela n'est d'ordinaire pas impactant, mais dans le cas présent, le moindre décalage a d'énormes impacts sur mes mesures.

Exemple :

A 50 km/h, qui correspond à 13,9 m/s, le temps de parcours de ma distance de 3,4m est de $3.4/13.9$ = environ $245$ ms.

  • Si mes cartes sont désynchronisées de 50 ms l'une de l'autre, je relèverai une durée pouvant être de $195$ms ou $295$ms en fonction du sens de désynchronisation.
  • A $195$ms, mon résultat de calcul de vitesse serait donc de $17,4$ m/s = $63$ km/h, contre $11,5$ m/s = environ $41$ km/h à $295$ms, les deux versus une vitesse réelle de 50 km/h.

Autant dire que je ne peux en l'état actuel malheureusement pas garantir la fiabilité de mes mesures car elles comportent une marge d'erreur beaucoup trop importante.

  • Elles reflètent tout au plus une tendance qui ne peut pas être interprétée comme des valeurs avérées d'un radar homologué.

Solutions :

  1. Diminuer les impacts de décalage du temps en augmentant la distance parcourue.

    • Mais cela ne résoudra pas le problème de désynchronisation des cartes, et en augmentant la distance, la vitesse moyenne sera de moins en moins proche de la vitesse instantanée
    • Dans tous les cas cette solution est impossible dans mon cas car mon environnement ne permet pas de disposer de davantage de distance
  2. Modifier le système en le rendant synchrone via deux capteurs reliés à une seule et même carte.

    • Meilleure solution car peu importe la désynchronisation de la carte avec le serveur NTP, les deux capteurs utiliseraient une seule et unique base temporelle pour leurs détections.
    • De plus, cela permettrait de déléguer tout le travail de calcul et de tri des faux-positifs à la carte Arduino au niveau de son propre code :
      • Si je vois une détection d'un capteur, alors j'attends le deuxième.
      • Si le deuxième ne voit rien, alors c'est un faux positif, j'ignore et je recommence.
      • Si le deuxième détecte aussi un mouvement je calcule la durée exacte entre les deux et je la transmets à Splunk, voire je vérifie si c'est une valeur plausible avant de l'envoyer.

    La donnée arriverait donc déjà épurée dans Splunk, et sa volumétrie serait divisée par deux étant donné qu'il ne recevrait plus que les durées déjà calculées et non les détections de mouvement de chaque capteur.

    • La distance étant variable en fonction de la manière dont sont positionnés les capteurs, elle resterait modifiable au sein de la requête Splunk pour s'adapter à chaque contexte sans avoir à changer systématiquement le code de l'Arduino.

    Malheureusement cette solution ne peut pas non plus être mise en œuvre en l'état dans mon contexte. J'ai en effet de nombreux murs et un couloir qui impliqueraient de tirer des mètres de fils électriques depuis mes capteurs pour pouvoir les relier à une même carte.

    • De plus, je ne peux pas non plus envisager de connecter mes capteurs à une carte positionnée entre les deux depuis l'extérieur car le tout serait à la vue de tous sans aucune protection et à la merci des intempéries.

    Si jamais je change d'environnement de mesure alors je pourrai envisager la mise en œuvre de cette version améliorée du système de détection.

La précision des capteurs

Utilisant des capteurs infrarouges que j'ai volontairement obstrués pour limiter la plage de détection, celle-ci est forcément imparfaite. J'ai notamment constaté que certains véhicules roulaient si rapidement que les capteurs n'avaient pas le temps de détecter leur passage.

De même, les capteurs possèdent une temporisation que j'ai limitée à 2 secondes entre chaque mesure, donc un mouvement survenant moins de 2 secondes après un autre ne sera pas détecté.

  • Les résultats ne sont donc pas complètement exhaustifs en termes de détections

Solution : Utiliser des capteurs beaucoup plus précis et réactifs, tels que des capteurs lasers avec réflecteurs.

  • Malheureusement impossible à mettre en œuvre dans mon environnement actuel.

La qualité du matériel

D'autres axes d'amélioration sont évidents au niveau de la finition du système de détection, qui reste fait de bric et de broc pour mes tests sans même avoir soudé les fils avec mes cartes Arduino.

Un produit propre, robuste et étanche serait tout de même plus présentable que des boîtes de conserves avec des fils reliés jusqu'à une carte elle-même branchée à une rallonge électrique...

Sources

Vous avez activé l'option "Do Not Track" dans votre navigateur, nous respectons ce choix et ne suivons pas votre visite.