Auteur/autrice : Seb

  • Pourquoi choisir l’AGPL ? Le cas RoadSimulator3



    Pourquoi choisir l’AGPL ? Le cas RoadSimulator3

    Le choix d’une licence open source n’est jamais neutre. Il conditionne la diffusion, l’adoption et la protection d’un projet logiciel. Pour RoadSimulator3 — simulateur inertiel multi-contexte conçu pour générer des trajectoires réalistes à 10 Hz avec inertie, gyroscope, topographie et météo — ce choix est particulièrement stratégique. Après analyse des différentes options (MIT, Apache, GPL, CeCILL…), nous avons retenu l’Affero General Public License (AGPL).

    Dans cet article, nous expliquons en détail pourquoi l’AGPL est le meilleur compromis entre ouverture scientifique, protection contre la captation industrielle, et alignement avec notre modèle économique.

    1. Contexte : pourquoi la licence compte pour RoadSimulator3 ?

    RoadSimulator3 n’est pas un simple script académique, mais une plateforme complète de simulation véhicule :

    • Trajectoires GPS réalistes via OSRM et OSM
    • Injection d’événements inertiels : freinages, accélérations, dos d’âne, nids de poule
    • Modélisation du gyroscope (gyro_x, gyro_y, gyro_z) et bruit stochastique
    • Prise en compte du relief (IGN RGE Alti®) et des conditions météo
    • Production de données à haute fréquence (10 Hz) pour IA, télématique et recherche

    La valeur de RoadSimulator3 repose donc autant sur le code source que sur l’approche scientifique et la création de jeux de données synthétiques. Sans licence claire, le risque est double :

    • Des acteurs commerciaux peuvent réutiliser le moteur dans leurs propres offres SaaS sans jamais contribuer en retour.
    • Les chercheurs n’ont aucune garantie que le code restera accessible ni que leurs améliorations seront reversées à la communauté.

    2. Comprendre la licence AGPL

    L’Affero GPL (AGPL v3) est une variante de la GPL conçue pour répondre au problème des logiciels utilisés via un réseau (par exemple dans le cloud ou en SaaS).

    2.1. Principe de base

    Comme la GPL, l’AGPL impose que tout dérivé du code reste open source. Mais elle ajoute une clause spécifique :

    « Si vous proposez ce logiciel comme service sur un réseau (SaaS, API), vous devez fournir le code source complet aux utilisateurs de ce service. »

    2.2. Conséquence

    Impossible donc de créer un SaaS fermé basé sur RoadSimulator3 sans reverser les améliorations à la communauté.

    3. Pourquoi l’AGPL protège RoadSimulator3

    3.1. Contre la captation industrielle

    Les acteurs de la mobilité connectée (constructeurs, assureurs, éditeurs télématiques) pourraient être tentés de forker RoadSimulator3 et de l’intégrer dans leur cloud. Avec une licence permissive (MIT, Apache), ils ne seraient pas obligés de partager leurs modifications. Avec l’AGPL, toute mise en production doit rester ouverte.

    3.2. Cohérence avec la recherche

    La science progresse par le partage. L’AGPL garantit que RoadSimulator3 restera disponible pour les chercheurs, et que toute amélioration significative sera partagée en retour. Cela aligne le projet avec les principes d’open science et de reproductibilité.

    3.3. Protection de l’écosystème

    RoadSimulator3 intègre des dépendances open source (OSM, OSRM, OpenWeatherMap). L’AGPL permet d’assurer que notre code reste dans le même esprit collaboratif et évite un « enclosure » du bien commun.

    4. Comparaison avec les autres licences

    Licence Avantages Inconvénients
    MIT / Apache 2.0 Adoption rapide, peu de contraintes Pas de protection contre l’appropriation commerciale
    GPL v3 Partage du code obligatoire pour redistributions Lacune pour les usages SaaS (cloud non couvert)
    CeCILL-C Lisibilité juridique en français, proche de la GPL Moins connu à l’international, même limite SaaS
    AGPL v3 Protection SaaS, open science, alignement avec recherche Peut freiner certains industriels qui veulent du code propriétaire

    5. Implications pour notre modèle économique

    Notre Business Model Canvas prévoit plusieurs sources de revenus :

    • Accès API payant (SaaS)
    • Consulting et formation
    • Jeux de données enrichis et premium

    L’AGPL ne bloque pas ces activités, car :

    • Nous pouvons proposer un SaaS officiel de RoadSimulator3 (les utilisateurs obtiennent le code, mais préfèrent payer pour l’hébergement, la maintenance et le support).
    • Nous pouvons publier le noyau sous AGPL, tout en réservant certaines extensions ou datasets sous licence commerciale.
    • Nous pouvons proposer une double licence : AGPL pour l’open science, et une licence propriétaire sur demande pour des industriels qui refusent l’AGPL.

    6. Exemple concret : scénario de simulation et diffusion

    Lors d’un run récent, RoadSimulator3 a généré un trajet avec injection d’événements :

    • 5 freinages
    • 5 accélérations
    • 5 dos d’âne
    • 5 nids de poule
    • 5 franchissements de trottoirs
    • 1672 arrêts temporaires (« wait »)

    Ces données sont précieuses pour entraîner des IA de détection d’événements ou tester des algorithmes embarqués. Grâce à l’AGPL :

    • Tout acteur qui réutilise ces scripts pour son propre simulateur doit publier son code dérivé.
    • Les chercheurs peuvent améliorer les modèles (bruit inertiel, gyro, typologie routière) et redistribuer librement leurs versions.

    7. Répondre aux critiques fréquentes sur l’AGPL

    7.1. « L’AGPL fait peur aux industriels »

    C’est vrai que certaines DSI rechignent à intégrer du code AGPL. Mais cela peut être transformé en opportunité : proposer un contrat de licence commerciale pour ces acteurs. C’est le principe de la dual licensing strategy adopté par MongoDB ou Elastic.

    7.2. « L’AGPL est trop contraignante »

    La contrainte est justement sa force : elle garantit que les améliorations restent dans l’écosystème. Pour un projet scientifique comme RoadSimulator3, c’est un avantage, pas un frein.

    7.3. « L’AGPL est peu utilisée »

    C’est vrai qu’elle est moins répandue que MIT ou Apache. Mais elle est adoptée par des projets majeurs comme GNU Affero, Moodle ou OpenERP/Odoo. Son adoption croît dans le contexte SaaS.

    8. Conclusion : un choix aligné avec notre vision

    En adoptant l’AGPL v3, RoadSimulator3 choisit :

    • La protection contre la privatisation de son code par des acteurs SaaS
    • La cohérence scientifique avec les principes d’open science
    • La possibilité d’un modèle économique hybride : open pour la recherche, commercial pour l’industrie

    Ce choix n’est pas seulement juridique : il incarne une philosophie. La simulation inertielle doit rester un bien commun, au service de la recherche, de l’innovation et de la mobilité durable.

    💡 Vous êtes chercheur, industriel ou étudiant ? Téléchargez RoadSimulator3 sous AGPL, testez-le, et contribuez à l’écosystème. Pour un partenariat, contactez-nous.

    Nous contacter

    © 2025 RoadSimulator3 — Article publié sous licence CC-BY 4.0.
  • 🧩 Simulation réaliste = bruit + inertie + logique

    🧩 Simulation inertielle réaliste : bruit, inertie & logique

    Une simulation inertielle réaliste ne se limite pas à dessiner une trace GPS. Pour être crédible
    et exploitable en télématique, IA embarquée ou assurance, elle doit combiner trois ingrédients :
    le bruit des capteurs, l’inertie du véhicule et la logique de conduite. Ce triptyque
    est au cœur de RoadSimulator3, qui génère des trajectoires enrichies à 10 Hz.

    Simulation inertielle réaliste : infographie Bruit, Inertie et Logique
    Le triptyque Bruit + Inertie + Logique structure toutes les sorties RS3.

    1) Pourquoi ajouter du bruit ?

    Les IMU/gyroscopes MEMS comportent du bruit et des dérives. Les ignorer crée une simulation
    « parfaite » mais inutilisable pour évaluer la robustesse d’algorithmes. RS3 reproduit des composantes
    réalistes (biais, marche aléatoire, variance d’Allan) pour confronter vos modèles à des conditions proches du terrain.

    2) L’inertie : la signature physique du véhicule

    Freinage, virage serré ou dos d’âne se traduisent par des motifs distincts dans
    acc_x, acc_y, acc_z et gyro_x, gyro_y, gyro_z. Quelques relations utiles :

    $$ a_{lat} = \frac{v^2}{r}, \qquad a_{long} = \frac{\Delta v}{\Delta t}, \qquad \omega_z = \frac{v}{r} $$

    La topographie agit aussi sur l’inertie : une pente p induit une composante longitudinale

    $$ a_{\text{pente}} = g\,\sin(p) $$

    3) La logique relie le signal au contexte

    • Décélération avant un feu / STOP, arrêt complet, redémarrage;
    • Vitesses et inerties adaptées à la typologie (urbain, voie rapide, zone d’activité);
    • Ronds-points : freinage progressif → lacet → ré-accélération mesurables.

    4) Comparatif : simulation simpliste vs simulation inertielle réaliste

    Dimension Simulation simpliste RS3 (réaliste)
    GPS Itinéraire 10 Hz (OSRM + OSMnx)
    Inertie ✔ Acc. tri-axes
    Gyroscope ✔ Lacet, roulis, tangage
    Bruit capteurs ✔ MEMS (Allan, biais, drift)
    Logique de conduite ✔ STOP, feux, rond-points
    Contexte ✔ Topographie IGN, météo

    5) Applications concrètes

    • Télématique : détection fiable de freinages/bruits de route (nid de poule, dos d’âne), scoring comportemental;
    • IA embarquée : entraînement robuste sur jeux synthétiques bruités et inertiels;
    • Smart City : analyse de zones à risques et aide à l’aménagement;
    • Assurance : indicateurs explicables fondés sur signaux physiques et contexte.


    Simulation inertielle réaliste : trajectoire véhicule 10 Hz avec inertie et gyroscope
    Exemple de trajectoire 10 Hz enrichie (accélérations & gyroscopes).

    Ressources & liens

    Conclusion

    La simulation inertielle réaliste repose sur bruit + inertie + logique. En combinant ces trois
    dimensions avec la topographie et la météo, RS3 livre des données prêtes pour la production
    et la recherche. Découvrez le moteur et demandez une démo.

  • 🔬 Gyroscope oublié = données amputées



    Gyroscope simulation inertielle véhicule : données amputées sans rotation

    Dans toute simulation inertielle véhicule, le gyroscope joue un rôle central.
    Sans lui, la trajectoire perd la cohérence des virages et rotations.
    Un gyroscope oublié équivaut à des données amputées, et cet article détaillé (≈3000 mots) montre pourquoi, en explorant la physique, les capteurs, les algorithmes et les usages industriels.

    1. Les limites des accélérations linéaires

    Un système inertiel embarqué repose d’abord sur les accéléromètres. Ces capteurs mesurent les accélérations dans trois axes : longitudinal (avant/arrière), latéral (gauche/droite) et vertical (haut/bas). Dans une simulation inertielle véhicule, ces données traduisent :

    • Accélération longitudinale : un freinage ou une accélération droite.
    • Accélération latérale : la force ressentie dans un virage.
    • Accélération verticale : bosses, nids de poule, dos d’âne.

    Par exemple, un freinage de -4 m/s² traduit un appui fort sur la pédale de frein.
    Une accélération latérale de 3 m/s² correspond à un virage serré pris à vitesse élevée.
    Mais ces informations restent ambigües : elles ne disent pas si le véhicule a changé d’orientation, ni à quelle vitesse il a pivoté.

    1.1 Exemple concret sans gyroscope

    Un véhicule peut perdre 20 km/h en 2 secondes. Deux scénarios sont possibles :

    • Un freinage sec en ligne droite.
    • Un virage serré où la perte de vitesse est due à la courbure.

    Les accéléromètres donneront une information similaire (décélération longitudinale), mais la dynamique réelle est totalement différente.
    Sans gyroscope, la simulation inertielle véhicule ne permet pas de trancher.

    2. Le rôle indispensable du gyroscope

    Le gyroscope mesure la vitesse angulaire : le taux de rotation du véhicule autour de ses trois axes (roulis, tangage, lacet).
    En clair, il capture « combien de degrés par seconde » le véhicule pivote.

    2.1 Axes de rotation

    • Roll (gyro_x) : inclinaison latérale (virage, dévers).
    • Pitch (gyro_y) : cabrage ou plongée (accélération ou freinage fort).
    • Yaw (gyro_z) : rotation horizontale (virages, rond-points).

    Dans une simulation inertielle véhicule, ignorer ces composantes revient à supprimer la mémoire du virage.
    On ne peut plus distinguer une trajectoire sinueuse d’une ligne droite ponctuée de freinages.

    2.2 Cas d’usage typiques

    • Virage avec freinage : seule la combinaison accélération longitudinale + vitesse angulaire révèle la manœuvre réelle.
    • Changement de voie subtil : l’accélération latérale est faible, mais le gyroscope montre une rotation caractéristique.
    • Rond-point : séquence continue de rotation en lacet, invisible sans gyroscope.

    3. Gyroscopes MEMS et réalités physiques

    La majorité des véhicules connectés et smartphones utilisent des gyroscopes MEMS (Micro Electro Mechanical Systems).
    Ces capteurs miniaturisés détectent la rotation par effet Coriolis. Leur avantage : faible coût, faible consommation, intégration facile.
    Leur inconvénient : bruit stochastique et dérive à long terme.

    3.1 Le bruit stochastique

    Le signal d’un gyroscope MEMS est toujours perturbé par des fluctuations aléatoires.
    Dans une simulation, il faut reproduire ce bruit pour coller à la réalité.
    Un gyroscope « parfait » serait irréaliste et tromperait les algorithmes de traitement.

    3.2 La dérive

    Avec le temps, un gyroscope MEMS accumule une erreur (bias drift).
    C’est pourquoi les systèmes embarqués utilisent souvent une fusion GNSS+IMU (GPS corrige la dérive du gyro, et le gyro comble les trous GPS).

    4. Simulation gyroscopique dans RoadSimulator3

    RoadSimulator3 intègre pleinement le gyroscope dans la simulation inertielle véhicule.
    Concrètement, cela signifie :

    • Production des signaux gyro_x, gyro_y, gyro_z sur toute la trajectoire.
    • Ajout d’un bruit stochastique calibré sur des publications scientifiques (Hemerly, 2017).
    • Possibilité d’activer une dérive gyroscopique pour tester la robustesse des algorithmes IA et télématiques.

    Ces données rendent possible :

    • La détection réaliste d’événements routiers (freinages, virages, dos d’âne).
    • La génération de datasets synthétiques utilisables par les chercheurs.
    • La validation de systèmes embarqués (ADAS, conduite autonome, télématique).

    4.1 Exemple visuel

    Voici une représentation schématique des trois cas typiques :

    Infographie gyroscope simulation inertielle véhicule RoadSimulator3

    5. Applications industrielles et scientifiques

    L’ajout du gyroscope dans une simulation inertielle véhicule ouvre de multiples cas d’usage :

    • Assurances et télématique : scoring conducteur fiable, différenciation freinage vs virage.
    • Constructeurs automobiles : validation des systèmes ADAS.
    • IA embarquée : datasets synthétiques réalistes pour apprentissage.
    • Recherche académique : étude des limites GNSS en milieu urbain, correction via inertiel.

    5.1 Exemple assurance

    Sans gyroscope, un freinage avant rond-point peut être noté comme « conduite brutale ».
    Avec gyroscope, le système sait qu’il s’agit d’une manœuvre normale et sécurisée.

    6. Comparaison avec d’autres simulateurs

    Simulateur Trajectoire GPS Inertie Topographie Météo Gyroscope
    RoadSimulator3
    SUMO
    CARLA Partiel

    7. Conclusion

    Un GPS seul donne la route. Un accéléromètre ajoute l’inertie.
    Mais c’est le gyroscope qui garantit la cohérence et la fidélité de la simulation inertielle véhicule.
    L’ignorer, c’est amputer la donnée et induire en erreur l’IA, la télématique et les chercheurs.

    Voir aussi :

    IEEE – Inertial Measurement and Gyroscope in Vehicle Simulation
    .

    Références

    • Hemerly, E.M. et al. (2017), Stochastic Modeling of MEMS IMU Errors
    • Harbers et al. (2023), Boundaries Enhancing Vehicle Simulation
    • IGN RGE Alti®, OSRM, OpenWeatherMap
    • Yurtsever et al. (2020), Survey Autonomous Driving
  • Pourquoi développer un provider PostgreSQL pour Jellyfin prépare le terrain à RoadSimulator3





    PostgreSQL Jellyfin RoadSimulator3 : pourquoi ce développement prépare RS3

    PostgreSQL Jellyfin RoadSimulator3 : pourquoi ce développement prépare RS3

    À première vue, travailler sur Jellyfin et RoadSimulator3 semble éloigné. Pourtant, PostgreSQL Jellyfin RoadSimulator3 est exactement le trio qui décrit mon actualité. Je développe un provider PostgreSQL pour Jellyfin afin d’éprouver les briques qui serviront directement à RoadSimulator3 (RS3).

    🎬 D’un côté, des films, des séries, des métadonnées.
    🚗 De l’autre, des trajectoires GPS, des accéléromètres et des millions de points collectés à 10 Hz.

    Pourquoi maintenant ? Parce que les deux mondes partagent la même colonne vertébrale – la donnée. Qu’il s’agisse de parcourir une médiathèque ou d’analyser une trajectoire, les défis sont identiques : structure, requêtes rapides, évolutivité sans perte d’historique. Bref : PostgreSQL Jellyfin RoadSimulator3 est un même problème vu sous deux angles.

    (suite…)

  • Ressusciter un iPhone 4S en 2025 : datalogger GPS + IMU 10 Hz (de l’idée à l’IPA)





    Ressusciter un iPhone 4S en 2025 : datalogger GPS + IMU 10 Hz (de l’idée à l’IPA)


    Ressusciter un iPhone 4S en 2025 : datalogger GPS + IMU 10 Hz (de l’idée à l’IPA)

    Oui, on peut encore donner une deuxième vie à un iPhone 4S (iOS 9.3.x, ARMv7) : un datalogger GPS + IMU qui enregistre à 10 Hz et exporte en CSV. Ce billet condense toutes les étapes, le code, et les pièges contournés.

    TL;DR

    • Compiler avec Xcode 13.2.1 sur macOS Monterey pour cibler armv7 et iOS 9.0.
    • App Objective-C (UIKit + CoreLocation + CoreMotion), sans dépendances Swift.
    • Échantillonnage 10 Hz via dispatch_source_t ; export CSV + UIFileSharingEnabled.
    • Installer sur 4S via Export Development/Ad Hoc ou IPA non signée + Sideloadly.
    • Bonus : commandes UTM/QEMU pour brancher l’iPhone en USB à une VM Windows/iTunes.

    1) Contexte & contrainte

    Les toolchains modernes ne supportent plus armv7/iOS 9. Xcode 13.2.1 est la dernière version confortable pour compiler et signer des apps 32 bits. On reste en Objective‑C pur.

    2) Préparer l’environnement

    Option A — macOS Monterey natif (recommandé)

    1. Télécharge Xcode 13.2.1 (More Downloads). Place Xcode.app dans /Applications.
    2. Sélectionne la version :
    sudo xcode-select -s /Applications/Xcode.app
    sudo xcodebuild -license accept

    Option B — VM UTM macOS 12 (si ton Mac hôte est trop récent)

    1. UTM → New → Virtualize → macOS.
    2. Fournis l’IPSW Monterey (dernière : UniversalMac_12.6.1_21G217_Restore.ipsw).
    3. 4 CPU / 8 Go RAM / 80 Go disque. Installe Xcode 13.2.1 dans la VM.

    3) Créer le projet (iOS 9, armv7)

    • App iOS Objective‑C, Single View App.
    • Deployment Target : 9.0
    • Architectures : armv7 (ou “Standard (armv7)” dans Xcode 13)
    • Enable Bitcode : NO
    • Signing automatique ; Bundle ID unique.

    Info.plist — clés utiles

    • NSLocationWhenInUseUsageDescription
    • NSLocationAlwaysUsageDescription (ou NSLocationAlwaysAndWhenInUseUsageDescription selon la version)
    • NSMotionUsageDescription
    • UIBackgroundModeslocation (si logging écran éteint)
    • UIFileSharingEnabledtrue (récupérer les CSV via Finder/iTunes)

    4) Code de l’app : UI minimaliste & CSV 10 Hz

    Deux boutons (Start/Stop, Share CSV) et un label de statut. Location en BestForNavigation, accéléro/gyro via Core Motion, timer 10 Hz.

    ViewController.m (complet)

    // ViewController.m
    #import "ViewController.h"
    #import <UIKit/UIKit.h>
    #import <CoreLocation/CoreLocation.h>
    #import <CoreMotion/CoreMotion.h>
    #import <TargetConditionals.h>
    #import <math.h>
    
    @interface ViewController () <CLLocationManagerDelegate>
    @property (nonatomic, strong) CLLocationManager *loc;
    @property (nonatomic, strong) CMMotionManager *mm;
    #if __has_feature(objc_arc)
    @property (atomic, strong) CLLocation *lastLoc;
    #else
    @property (atomic, retain) CLLocation *lastLoc;
    #endif
    @property (atomic) CMAcceleration  lastAccel;
    @property (atomic) CMRotationRate  lastGyro;
    #if __has_feature(objc_arc)
    @property (nonatomic, strong) NSFileHandle *fh;
    @property (nonatomic, strong) NSURL *fileURL;
    #else
    @property (nonatomic, retain) NSFileHandle *fh;
    @property (nonatomic, retain) NSURL *fileURL;
    #endif
    #if __has_feature(objc_arc)
    @property (nonatomic, strong) dispatch_source_t timer;
    #else
    @property (nonatomic, assign) dispatch_source_t timer;
    #endif
    @property (nonatomic) UIButton *toggleBtn;
    @property (nonatomic) UIButton *shareBtn;
    @property (nonatomic) UILabel  *statusLabel;
    @property (nonatomic) BOOL isLogging;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.view.backgroundColor = [UIColor whiteColor];
        [self buildUI];
        [self setupLocation];
        [self setupMotion];
        [self updateUIForState];
    }
    
    - (void)buildUI {
        UIFont *f = [UIFont boldSystemFontOfSize:16.0];
        self.toggleBtn = [UIButton buttonWithType:UIButtonTypeSystem];
        self.toggleBtn.frame = CGRectMake(20, 60, 120, 44);
        self.toggleBtn.titleLabel.font = f;
        [self.toggleBtn setTitle:@"Start" forState:UIControlStateNormal];
        [self.toggleBtn addTarget:self action:@selector(toggleLogging) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:self.toggleBtn];
    
        self.shareBtn = [UIButton buttonWithType:UIButtonTypeSystem];
        self.shareBtn.frame = CGRectMake(180, 60, 120, 44);
        self.shareBtn.titleLabel.font = f;
        [self.shareBtn setTitle:@"Share CSV" forState:UIControlStateNormal];
        [self.shareBtn addTarget:self action:@selector(shareCSV) forControlEvents:UIControlEventTouchUpInside];
        self.shareBtn.enabled = NO;
        [self.view addSubview:self.shareBtn];
    
        self.statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 120, 280, 200)];
        self.statusLabel.font = [UIFont systemFontOfSize:14.0];
        self.statusLabel.textColor = [UIColor darkGrayColor];
        self.statusLabel.numberOfLines = 0;
        self.statusLabel.text = @"Ready.";
        [self.view addSubview:self.statusLabel];
    }
    
    - (void)updateUIForState {
        [self.toggleBtn setTitle:(self.isLogging ? @"Stop" : @"Start") forState:UIControlStateNormal];
        self.shareBtn.enabled = (self.fileURL != nil);
        self.statusLabel.text = self.isLogging ? @"Logging @10Hz…" : @"Stopped.";
    }
    
    #pragma mark - Location & Motion
    - (void)setupLocation {
        self.loc = [CLLocationManager new];
        self.loc.delegate = self;
        self.loc.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
        self.loc.distanceFilter  = kCLDistanceFilterNone;
        if ([self.loc respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
            [self.loc requestWhenInUseAuthorization];
        }
        if ([self.loc respondsToSelector:@selector(requestAlwaysAuthorization)]) {
            [self.loc requestAlwaysAuthorization];
        }
        if ([self.loc respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {
            self.loc.allowsBackgroundLocationUpdates = YES;
        }
        [self.loc startUpdatingLocation];
        if ([self.loc respondsToSelector:@selector(startUpdatingHeading)]) {
            [self.loc startUpdatingHeading];
        }
    }
    
    - (void)setupMotion {
        self.mm = [CMMotionManager new];
        self.mm.accelerometerUpdateInterval = 1.0/100.0;
        self.mm.gyroUpdateInterval         = 1.0/100.0;
        NSOperationQueue *q = [NSOperationQueue new];
        if (self.mm.isAccelerometerAvailable) {
            [self.mm startAccelerometerUpdatesToQueue:q withHandler:^(CMAccelerometerData *data, NSError *error) {
                if (data) { self.lastAccel = data.acceleration; }
            }];
        }
        if (self.mm.isGyroAvailable) {
            [self.mm startGyroUpdatesToQueue:q withHandler:^(CMGyroData *data, NSError *error) {
                if (data) { self.lastGyro = data.rotationRate; }
            }];
        }
    }
    
    #pragma mark - Logging
    - (void)toggleLogging {
        if (self.isLogging) { [self stopLogging]; }
        else { [self startLogging]; }
        [self updateUIForState];
    }
    
    - (void)startLogging {
        if (self.fh) return;
        [self setupLoggingFile];
        [self startTenHzTimer];
        self.isLogging = YES;
        [self updateUIForState];
    }
    
    - (void)stopLogging {
        if (self.timer) {
            dispatch_source_cancel(self.timer);
    #if !__has_feature(objc_arc)
      #if !OS_OBJECT_USE_OBJC
            dispatch_release(self.timer);
      #endif
    #endif
            self.timer = nil;
        }
        if (self.fh) { [self.fh closeFile]; self.fh = nil; }
        self.isLogging = NO;
        [self updateUIForState];
    }
    
    - (void)setupLoggingFile {
        NSDateFormatter *fmt = [NSDateFormatter new];
        fmt.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
        fmt.dateFormat = @"yyyy-MM-dd_HH-mm-ss";
        NSString *fname = [NSString stringWithFormat:@"log_%@.csv", [fmt stringFromDate:[NSDate date]]];
        NSString *docs = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
        NSString *path = [docs stringByAppendingPathComponent:fname];
        self.fileURL = [NSURL fileURLWithPath:path];
        [[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil];
        NSError *err = nil;
        self.fh = [NSFileHandle fileHandleForWritingToURL:self.fileURL error:&err];
        if (!self.fh) {
            self.statusLabel.text = [NSString stringWithFormat:@"File open error: %@", err.localizedDescription ?: @"unknown"];
            return;
        }
        NSString *header = @"ts_ms,lat,lon,alt,acc_h,speed,course,ax,ay,az,gx,gy,gz\n";
        [self.fh writeData:[header dataUsingEncoding:NSUTF8StringEncoding]];
        self.shareBtn.enabled = YES;
    }
    
    - (void)startTenHzTimer {
        dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, q);
        uint64_t interval = (uint64_t)(0.1 * NSEC_PER_SEC);
        dispatch_source_set_timer(self.timer,
                                  dispatch_time(DISPATCH_TIME_NOW, 0),
                                  interval,
                                  (uint64_t)(0.02 * NSEC_PER_SEC));
    #if __has_feature(objc_arc)
        __weak typeof(self) wself = self;
    #else
        __unsafe_unretained typeof(self) wself = self;
    #endif
        dispatch_source_set_event_handler(self.timer, ^{ [wself tickAndWriteCSV]; });
        dispatch_resume(self.timer);
    }
    
    - (void)tickAndWriteCSV {
        if (!self.fh) return;
        NSTimeInterval t = [[NSDate date] timeIntervalSince1970];
        long long ms = (long long)llround(t * 1000.0);
        CLLocation *L = self.lastLoc;
        double lat=NAN, lon=NAN, alt=NAN, acc=NAN, speed=NAN, course=NAN;
        if (L) { lat=L.coordinate.latitude; lon=L.coordinate.longitude; alt=L.altitude; acc=L.horizontalAccuracy; speed=L.speed; course=L.course; }
        CMAcceleration a = self.lastAccel; CMRotationRate g = self.lastGyro;
        NSString *line = [NSString stringWithFormat:
            @"%lld,%.8f,%.8f,%.2f,%.2f,%.2f,%.2f,%.5f,%.5f,%.5f,%.5f,%.5f,%.5f\n",
            ms, lat, lon, alt, acc, speed, course, a.x, a.y, a.z, g.x, g.y, g.z];
        @synchronized (self) { [self.fh writeData:[line dataUsingEncoding:NSUTF8StringEncoding]]; }
    }
    
    #pragma mark - Partage (simulateur vs appareil)
    - (void)shareCSV {
        if (!self.fileURL) {
            UIAlertController *ac = [UIAlertController alertControllerWithTitle:@"Aucun fichier"
                message:@"Commence par Start pour créer un CSV."
                preferredStyle:UIAlertControllerStyleAlert];
            [ac addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
            [self presentViewController:ac animated:YES completion:nil];
            return;
        }
        if (self.timer) { dispatch_source_cancel(self.timer); self.timer=nil; self.isLogging = NO; [self updateUIForState]; }
        if (self.fh) { [self.fh synchronizeFile]; [self.fh closeFile]; self.fh=nil; }
    
    #if TARGET_OS_SIMULATOR
        // Simulateur: partager le TEXTE pour éviter -10814
        NSError *readErr=nil; NSString *contents=[NSString stringWithContentsOfURL:self.fileURL encoding:NSUTF8StringEncoding error:&readErr];
        NSArray *items = contents ? @[contents] : @[self.fileURL.path];
        UIActivityViewController *vc=[[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];
        [self presentViewController:vc animated:YES completion:nil];
    #else
        // Appareil: partager l’URL (copie dans /tmp pour éviter les locks)
        NSString *tmpPath=[NSTemporaryDirectory() stringByAppendingPathComponent:self.fileURL.lastPathComponent];
        [[NSFileManager defaultManager] removeItemAtPath:tmpPath error:NULL];
        NSError *copyErr=nil; if (![[NSFileManager defaultManager] copyItemAtPath:self.fileURL.path toPath:tmpPath error:&copyErr]) {
            UIAlertController *ac=[UIAlertController alertControllerWithTitle:@"Copie impossible" message:copyErr.localizedDescription?:@"Erreur inconnue" preferredStyle:UIAlertControllerStyleAlert];
            [ac addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
            [self presentViewController:ac animated:YES completion:nil];
            return;
        }
        NSURL *tmpURL=[NSURL fileURLWithPath:tmpPath];
        UIActivityViewController *vc=[[UIActivityViewController alloc] initWithActivityItems:@[tmpURL] applicationActivities:nil];
        [self presentViewController:vc animated:YES completion:nil];
    #endif
    }
    
    #pragma mark - CLLocationManagerDelegate
    - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
        CLLocation *last = [locations lastObject];
        if (last) {
    #if __has_feature(objc_arc)
            self.lastLoc = last;
    #else
            if (self.lastLoc != last) { [self.lastLoc release]; self.lastLoc = [last retain]; }
    #endif
            dispatch_async(dispatch_get_main_queue(), ^{
                self.statusLabel.text = [NSString stringWithFormat:@"GPS: %.5f, %.5f",
                                         last.coordinate.latitude, last.coordinate.longitude];
            });
        }
    }
    
    - (void)dealloc {
        if (self.timer) { dispatch_source_cancel(self.timer); self.timer=nil; }
        [self.mm stopAccelerometerUpdates]; [self.mm stopGyroUpdates]; [self.loc stopUpdatingLocation];
        if (self.fh) { [self.fh closeFile]; self.fh = nil; }
    #if !__has_feature(objc_arc)
        [self.loc release]; [self.mm release]; [self.fileURL release]; [self.lastLoc release]; [super dealloc];
    #endif
    }
    @end
    

    CSV : ts_ms,lat,lon,alt,acc_h,speed,course,ax,ay,az,gx,gy,gz


    5) Générer un .IPA armv7

    Depuis Xcode (GUI)

    1. Scheme : Generic iOS Device (ou iPhone 4S).
    2. Product → Archive → Organizer.
    3. Export… : Development (compte gratuit, appareil ajouté) ou Ad Hoc (compte payant + UDID).

    Ligne de commande

    xcodebuild -project GPSIMU10Hz.xcodeproj   -scheme GPSIMU10Hz -configuration Release   -sdk iphoneos -archivePath build/GPSIMU10Hz.xcarchive archive
    
    cat > build/exportOptions.plist <<'PLIST'
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0"><dict>
      <key>method</key><string>development</string>
      <key>compileBitcode</key><false/>
      <key>signingStyle</key><string>automatic</string>
      <key>stripSwiftSymbols</key><true/>
      <key>destination</key><string>export</string>
    </dict></plist>
    PLIST
    
    xcodebuild -exportArchive   -archivePath build/GPSIMU10Hz.xcarchive   -exportOptionsPlist build/exportOptions.plist   -exportPath build/export

    Plan B : IPA “crue” + Sideloadly

    # Depuis DerivedData/.../Build/Products/Release-iphoneos/
    mkdir -p Payload
    cp -R GPSIMU10Hz.app Payload/
    zip -r -y GPSIMU10Hz_unsigned.zip Payload
    mv GPSIMU10Hz_unsigned.zip GPSIMU10Hz_unsigned.ipa

    Installe l’IPA via Sideloadly (Windows). Avec Apple ID gratuit, la signature dure 7 jours.


    6) Bonus : brancher l’iPhone 4S à une VM Windows (UTM/QEMU)

    Pour utiliser de vieux iTunes : QEMU x86_64 en TCG (sur Mac ARM), UEFI OVMF, EHCI (USB 2.0), et capture du device Apple 05ac:12a0.

    qemu-system-x86_64   -machine q35,accel=tcg,thread=multi   -cpu qemu64 -smp 4 -m 4096   -drive if=pflash,format=raw,readonly=on,file=/opt/homebrew/share/qemu/edk2-x86_64-code.fd   -drive if=pflash,format=raw,file=$HOME/OVMF_VARS_WIN11.fd   -drive file=/chemin/win11.qcow2,if=virtio,format=qcow2   -vga virtio   -usb -device usb-ehci,id=ehci   -device usb-host,bus=ehci.0,vendorid=0x05ac,productid=0x12a0

    Astuce : ferme Photos/Finder/iTunes sur macOS avant de brancher l’iPhone ; branche après le boot de Windows.


    7) Dépannage express

    • EXC_BAD_ACCESS sur last.coordinate : la propriété lastLoc doit être strong/retain.
    • Simulateur : -10814 au partage : partager NSString (contenu) plutôt que l’URL de fichier.
    • Undefined symbol / link failed : si Quick Look utilisé, lier QuickLook.framework.
    • Syntaxe ObjC : [self updateUIForState] (pas [self.updateUIForState]).
    • QEMU : write lock : disque ouvert par UTM → quitter UTM.
    • QEMU : invalid accelerator hvf : utiliser -accel tcg,thread=multi.
    • UEFI Shell au boot : vérifier -drive (NVMe/SATA) + présence de Windows Boot Manager.

    Conclusion

    Avec Xcode 13.2.1, une app Objective‑C compacte et quelques contournements, on transforme un 4S en datalogger GPS/IMU 10 Hz fiable — prêt pour la route, la piste ou le labo.


  • Simulation inertielle de trajectoires de véhicules : définition et cas d’usage

    Simulation inertielle de trajectoires de véhicules

    La simulation inertielle de trajectoires de véhicules désigne l’ensemble des méthodes permettant de générer des données simulées (accélérations, gyroscope, vitesse) à haute fréquence (10 Hz), sans recourir à des mesures terrain réelles.

    Simulation inertielle de trajectoires de véhicules

    Définition

    Elle repose sur des équations du mouvement et des modèles de dynamique véhicule pour simuler les données que produiraient des capteurs embarqués type IMU (Unité de Mesure Inertielle). Cela permet d’émuler la vitesse, les accélérations longitudinales, latérales, verticales et les rotations (gyroscopiques) du véhicule.

    Donnée simulée IMU : acc_x, acc_y, acc_z (m/s²), gyro_x, gyro_y, gyro_z (rad/s), échantillonnées à 10 Hz sur une trajectoire GPS.

    Usages

    • Validation de modèles de fusion capteurs (IMU + GNSS, IMU + odométrie)
    • Simulation de trajets logistiques dans des flottes de véhicules
    • Détection d’événements de conduite simulés (freinage, choc, virage serré)
    • Entraînement de modèles IA ou vérification de cohérence inertielle

    Applications dans RoadSimulator3

    Le simulateur RoadSimulator3 permet de produire des trajectoires GPS/IMU réalistes à 10 Hz avec injection de bruit, simulation de capteurs MEMS, et reconstruction de données cinématiques à partir de points GPS issus d’OSRM ou OSMnx.

    Chaîne de génération :

    • Trajectoire GPS issue d’OSRM / OSMnx
    • Interpolation à 10 Hz
    • Simulation IMU (acc_x, acc_y, acc_z, gyro_x…)
    • Ajout de bruit réaliste MEMS
    • Injection d’événements inertiels (freinage, virage, etc.)

    Pour aller plus loin

    📖 Ce contenu est lié à l’article Wikipédia :

    Simulation inertielle de trajectoires de véhicules
    .

  • Données brutes 10 Hz inertie véhicule : analyse enrichie

    Données brutes inertie véhicule : pourquoi 10 Hz change tout

    Les données brutes inertie véhicule enregistrées à haute fréquence (10 Hz) permettent une analyse fine de la dynamique. Contrairement aux compteurs ABC (accélération, freinage, virage), elles offrent une vision continue et exploitable scientifiquement.

    Pourquoi les compteurs ABC ne suffisent plus

    Un compteur d’événement est un indicateur binaire : il signale qu’un seuil a été franchi, sans indiquer la valeur physique réelle, la durée ou la forme de l’événement. Par exemple :

    • Un freinage « compté » ne dit rien de son intensité réelle
    • Un virage « compté » ne permet pas d’analyser la trajectoire
    • Les seuils utilisés sont opaques et différents selon les véhicules

    Données brutes inertie véhicule : capter la réalité

    À 10 Hz, on enregistre acc_x, acc_y, acc_z, vitesse, gyro… Ce niveau de granularité révèle :

    • La dynamique complète d’un virage (via gyro_z)
    • L’intensité d’un dos d’âne ou d’un freinage brusque
    • Les oscillations ou pics dus à la chaussée

    Visualisation : 10 Hz vs compteurs

    L’image ci-dessous illustre la différence entre une mesure continue et un simple déclencheur :

    données brutes inertie véhicule comparées aux compteurs ABC

    Conclusion : pour une vraie science du mouvement

    Les données brutes inertie véhicule sont indispensables pour la recherche, la simulation et la validation comportementale. Elles captent la dynamique réelle du véhicule à chaque instant.

    🔗 Voir l’étude associée sur la détection d’événements IMU

    🔗 Lire la publication scientifique sur la fusion GPS-IMU

  • Détection de virages véhicule autonome : un indicateur clé du style de conduite

    Détection de virages véhicule autonome : un indicateur clé du style de conduite

    Dans l’analyse inertielle, la détection de virages véhicule autonome est bien plus qu’une question de géométrie. Elle permet de mieux comprendre le comportement d’un conducteur (humain ou logiciel), de détecter les changements d’environnement, et de qualifier la trajectoire d’un véhicule dans son contexte réel.

    Pourquoi détecter un virage ?

    Un virage n’est pas simplement un changement de direction. C’est un moment où le véhicule subit une accélération latérale (acc_y), un changement de cap (heading) et souvent une adaptation de la vitesse. Ces éléments traduisent des choix de conduite, une réactivité, ou même une contrainte de la route (rond-point, bretelle, croisement).

    Quels indicateurs inertiels apparaissent ?

    • Accélération latérale (acc_y) détectée via l’IMU
    • Variation de cap (delta heading) sur quelques secondes
    • Vitesse de rotation (gyro_z) indiquant le degré de courbure

    Ces indicateurs sont utilisés dans des fonctions de détection automatique, comme celles intégrées à RoadSimulator3.

    Applications pratiques

    La détection de virages véhicule autonome sert à :

    • Qualifier le style de conduite (agressif, prudent, fluide)
    • Identifier des événements dangereux (virages pris trop vite)
    • Valider une simulation inertielle (présence réaliste de virages)
    • Adapter dynamiquement la vitesse dans les courbes

    Conclusion

    Les virages sont des moments révélateurs dans une trajectoire. Leur détection permet non seulement de mieux simuler, mais aussi d’interpréter le comportement d’un véhicule autonome. Un simulateur comme RoadSimulator3 peut injecter, puis détecter ces signatures, garantissant ainsi la cohérence inertielle d’un trajet synthétique.

    détection de virages véhicule autonome avec acc_y et gyro_z
    Illustration de la détection inertielle d’un virage
  • Fusion GNSS LIDAR inertielle véhicule : vers une localisation plus robuste

    Fusion GNSS LIDAR inertielle véhicule : vers une localisation plus robuste

    La fusion GNSS LIDAR inertielle véhicule devient essentielle dans les systèmes de navigation de véhicules autonomes. Dans cet article, nous explorons une nouvelle méthode proposée par Cheng et al. (2025) combinant odométrie LIDAR, pré-intégration IMU et positionnement GNSS dans un cadre unifié, afin d’obtenir une localisation robuste même en milieu urbain dense ou à haute vitesse.

    Pourquoi fusionner GNSS, IMU et LIDAR ?

    Les approches LIDAR ou visuelles seules souffrent de dérives cumulées lors de longues trajectoires ou de pertes de signal. Le GNSS, bien qu’imparfait en ville, apporte une référence globale utile pour corriger ces dérives. En couplant les trois sources, on obtient une estimation de pose plus fiable et continue.

    Une architecture modulaire efficace

    • Odométrie GNSS : utilisée pour initialiser ou relocaliser rapidement le système.
    • Pré-intégration IMU : fournit une estimation rapide de mouvement entre deux mesures.
    • Odométrie LIDAR avec Dynamic-ICP : méthode de recalage pointcloud plus rapide et robuste.
    • Filtrage IKF contraint : améliore l’estimation des angles d’attitude avec les vitesses GNSS.

    Résultats expérimentaux

    Testée sur les jeux de données KITTI et HK UrbanNav, la méthode réduit l’erreur RMSE de plus de 50 % par rapport à LOAM ou NDT. La fusion adaptative (équation 18 du papier) ajuste dynamiquement la pondération GNSS selon la fiabilité estimée.

    Intégration dans RoadSimulator3

    Cette approche de fusion GNSS LIDAR inertielle véhicule peut enrichir RoadSimulator3, en simulant des conditions de relocalisation, de cartes préalables, ou des environnements dégradés. Une implémentation réaliste du Dynamic-ICP serait un excellent test pour valider des stratégies de fusion multi-capteurs.

    🔗 Lire l’article complet sur arXiv
    🔗 Voir la thèse RoadSimulator3

    fusion GNSS LIDAR inertielle véhicule – schéma du système de localisation
    Figure – Schéma de la fusion GNSS-LIDAR-IMU (source : Cheng et al., 2025)
  • Calibration extrinsèque LiDAR-GNSS : une méthode sans cible

    Calibration extrinsèque LiDAR-GNSS : une méthode sans cible

    calibration extrinsèque LiDAR-GNSS sans cible

    La calibration extrinsèque LiDAR-GNSS est une étape cruciale pour garantir la précision des systèmes multi-capteurs embarqués. Cet article explore une approche sans cible physique, directement applicable aux véhicules autonomes.

    Auteurs : Jeong et al. (2025)

    Référence : arXiv:2507.08349 — DOI : https://doi.org/10.48550/arXiv.2507.08349

    🔍 Résumé de l’étude

    Ce travail propose une approche d’optimisation conjointe pour calibrer plusieurs capteurs LiDAR et un système GNSS/INS sans recours à des cibles physiques. Cette méthode permet une calibration stable et précise, même dans des environnements sans marqueur visuel.

    🎯 Intérêt pour RoadSimulator3

    Une calibration extrinsèque fiable est essentielle pour générer des données simulées alignées entre IMU, LiDAR et GNSS. Cette méthode peut inspirer la fusion des trajectoires simulées avec des systèmes réels, en évitant les recalibrages manuels.

    🧩 Limites

    Le modèle repose sur des hypothèses de mouvement du véhicule qui peuvent ne pas être valides en conduite extrême. De plus, la généralisation à d’autres types de capteurs (caméras, radars) n’est pas traitée.

    🚀 Perspectives

    L’extension vers des calibrations multi-capteurs automatisées et la validation en environnement dégradé (GNSS partiel, LiDAR bruité) seraient des pistes clés.

    En intégrant cette méthode dans les simulateurs comme RoadSimulator3, on améliore la cohérence des données entre capteurs et on réduit les efforts manuels de recalibrage. Ce processus représente un gain considérable en précision et en reproductibilité pour les essais sur route.

    🔗 Liens utiles