Disponibile anche in inglese: English version.
I treni regionali in Lombardia sono un banco di prova severo per un’applicazione mobile. Il convoglio attraversa trincee e gallerie in cui il segnale GNSS e la connettività dati cellulare spariscono del tutto; il dispositivo aggancia e sgancia celle radio ogni pochi minuti, e molti passeggeri soffrono di cinetosi (il classico mal d’auto) quando provano a leggere a bordo.
Trenord Infotainment (repository GitHub(si apre in una nuova scheda)) è stato il nostro progetto conclusivo per l’insegnamento di Design and Implementation of Mobile Applications (DIMA) della laurea magistrale in Computer Science and Engineering al Politecnico di Milano. Lo abbiamo sviluppato in collaborazione con Trenord(si apre in una nuova scheda), la principale società ferroviaria regionale lombarda. Il team era composto da Tommaso Morganti, Luca Suzani e me. L’obiettivo: creare un’applicazione offline-first capace di mostrare la posizione del treno in ogni istante, mitigare la cinetosi e intrattenere i viaggiatori anche in totale assenza di rete.

I problemi da risolvere
La stragrande maggioranza delle app per smartphone dà per scontata una connettività continua. Su un treno regionale questa ipotesi viene smentita costantemente:
- Gallerie e zone d’ombra. Un’interfaccia che attende una risposta di rete prima di aggiornarsi si blocca non appena il convoglio entra in un tunnel.
- Cinetosi. L’orecchio interno percepisce le accelerazioni, le frenate e le oscillazioni della carrozza, mentre gli occhi fissano lo schermo immobile dello smartphone. Questo conflitto sensoriale provoca nausea e malessere.
- Informazioni frammentate. Ritardi, cambi di binario, meteo a destinazione e coincidenze sono distribuiti su portali diversi o annunci in stazione difficili da ascoltare.
- Fattori di forma eterogenei. I pendolari viaggiano con smartphone compatti, telefoni grandi e tablet appoggiati sul tavolino del sedile. Allungare una vista pensata per smartphone su uno schermo ampio spreca tutto lo spazio utile.
Abbiamo affrontato ogni criticità con soluzioni architetturali mirate: tutti i dati necessari al viaggio vengono scaricati e salvati in locale all’avvio, gli indicatori visivi di movimento girano sul thread nativo dell’interfaccia, e il layout si divide in due colonne su schermi larghi.
Iniziare un viaggio
Il passeggero può inquadrare il codice a barre 2D o il codice PNR presente sul biglietto, oppure digitare il numero del treno (ad esempio 24869).

L’applicazione interroga i servizi di orario di Trenord e scarica:
- la sequenza ordinata delle stazioni con orari previsti ed effettivi;
- i tempi di sosta, i binari assegnati e le coincidenze programmate;
- le coordinate geografiche del tracciato ferroviario per disegnare la linea sulla mappa.
L’app memorizza l’intero itinerario sul dispositivo. Se la connessione cade pochi secondi dopo, tutte le informazioni rimangono accessibili.
Tracciare la posizione del treno, anche in galleria
Quando il convoglio viaggia a cielo aperto, l’applicazione riceve aggiornamenti continui dal ricevitore satellitare dello smartphone.

Il segnale GPS all’interno di una carrozza ferroviaria è rumoroso: la schermatura metallica della struttura attenua il segnale e le onde rimbalzano sulle pareti. Per evitare che l’indicatore di velocità oscilli in modo anomalo, filtriamo ogni lettura con una media mobile esponenziale (EMA):
con .
Navigazione stimata (Dead Reckoning)
Nelle gallerie il segnale GNSS si interrompe bruscamente. Molte applicazioni di trasporto mostrano un cursore bloccato o un’icona di caricamento infinito. Noi abbiamo implementato una macchina a stati per la navigazione stimata:
- Rilevamento della perdita di segnale. Se non arrivano nuovi fix satellitari entro 5 secondi, l’app passa automaticamente dalla modalità GPS alla navigazione stimata.
- Stima basata sugli orari e sul percorso. L’applicazione combina i dati memorizzati dell’orario con il tempo trascorso dall’ultima stazione superata, posizionando il treno lungo la tratta corretta tra le due fermate.
- Riconnessione fluida. All’uscita dal tunnel, quando il segnale torna stabile, il cursore si riallinea alle coordinate satellitari con una transizione continua, senza scatti e senza resettare l’interfaccia.
Indicatori visivi contro il mal di movimento
In curva, l’apparato vestibolare percepisce l’inclinazione del vagone, ma la vista fissa uno schermo fermo tra le mani. Questo disallineamento è la causa principale della cinetosi.
Abbiamo inserito nell’interfaccia un sistema di indicatori di movimento (motion cues).

L’overlay renderizza 40 punti lungo i margini dello schermo. Quando il convoglio oscilla, accelera o curva, i punti si muovono nella direzione opposta all’accelerazione inerziale. La visione periferica registra così il movimento fisico avvertito dal corpo, funzionando come un orizzonte artificiale.
Esecuzione sul thread UI
Eseguire questi calcoli fisici sul thread JavaScript provocherebbe cali di frame rate. Il calcolo delle traiettorie viene eseguito direttamente sul thread nativo dell’interfaccia tramite worklet di React Native Reanimated:

useAnimatedSensor(SensorType.ACCELEROMETER)campiona l’accelerometro alla frequenza di aggiornamento dello schermo (60 Hz o 120 Hz).- Un filtro passa-basso () separa la componente gravitazionale () dall’accelerazione lineare del treno.
- L’accelerazione dinamica sposta le particelle, che scorrono lungo i bordi e svaniscono in profondità.
- Il worklet non tocca mai l’event loop di JavaScript, mantenendo l’animazione stabilmente a 60 FPS.
Abbiamo aggiunto anche la funzione shake to report. Se il telefono rileva uno scuotimento marcato o una decelerazione improvvisa (, ), l’app apre una scheda di segnalazione immediata per permettere al passeggero di comunicare ritardi, guasti a bordo o emergenze sanitarie.
Giochi e contenuti multimediali completamente offline
Guardare video in streaming tramite il Wi-Fi di bordo o con una connessione mobile discontinua è frustrante. Tutta la sezione di intrattenimento dell’app è progettata per funzionare offline.

L’hub multimediale include notizie, approfondimenti sul territorio e passatempi:
- Riproduzione audio in background basata su
expo-audio, con controlli nella schermata di blocco (MediaSession), velocità da 1x a 2x e navigazione per capitoli che prosegue anche passando ad altre app. - Commuter Sudoku, una griglia 9x9 con vari livelli di difficoltà, note a matita, evidenziazione degli errori, cronometro e salvataggio automatico dello stato.
- Trenord Hop, un gioco arcade in pixel art a 60 FPS: si attraversano binari, si raccolgono monete e ogni impatto viene restituito con feedback aptico via
expo-haptics.

Entrambi i giochi girano localmente sul telefono senza richiedere alcuna connessione di rete.
Arrivo a destinazione
Verso la conclusione del viaggio, l’app presenta una panoramica utile sulla città di arrivo:

- Meteo e qualità dell’aria: temperatura, previsioni di pioggia e indice europeo AQI (da 1 a 500).
- Punti di interesse: mappa con monumenti, musei ed edifici storici raggiungibili a piedi dalla stazione.
- Notizie locali: articoli e aggiornamenti culturali sul comune e sulla provincia di arrivo.
- Avvisi: notifiche per le coincidenze successive, cambiamenti di binario e conto alla rovescia per l’arrivo.

Ottimizzazione per tablet
Molti pendolari utilizzano un tablet durante il viaggio. Invece di allungare elenchi verticali su display ampi o duplicare il codice, il layout si riorganizza a livello di rendering:

Quando la larghezza della finestra supera i :
- La schermata del viaggio si sdoppia in due colonne: la mappa con il percorso OpenStreetMap a sinistra, e l’elenco delle fermate con ritardi e affluenza delle carrozze a destra.
- La schermata principale affianca gli indicatori telemetrici e i caroselli di scoperta.
- Le finestre di dialogo hanno una larghezza massima di , mantenendo le righe di testo leggibili e i pulsanti facilmente raggiungibili.

A cambiare è unicamente il layout visivo: lo stato dell’app, la riproduzione audio e i giochi in corso non vengono interrotti quando si ruota il dispositivo o si ridimensiona l’area visibile.
Architettura del sistema e collaudo
L’applicazione è strutturata nei container descritti in questo diagramma C4:

- Navigazione: Expo Router v5 con rotte basate su file system. Delle guardie di navigazione proteggono le schermate di viaggio finché non viene caricato un titolo di viaggio valido.
- Stato applicativo: 11 store Zustand 5, suddivisi per dominio (viaggio, meteo, notizie, contenuti, audio, giochi, impostazioni), persistiti in formato JSON su AsyncStorage.
- Chiusura del viaggio: un’azione unificata
rootResetazzera gli store al termine della corsa, eliminando i dati di viaggio ma conservando tema e preferenze dell’utente. - Sicurezza: un proxy edge inoltra le richieste esclusivamente a host autorizzati in allowlist per prevenire vulnerabilità SSRF. Le chiamate alle API B2B di Trenord sono autenticate con token JWT firmati con chiave privata RS256 e tolleranza al disallineamento d’orologio.
Tecnologie adottate
| Area | Tecnologia | Scopo |
|---|---|---|
| Runtime | React Native 0.83.10 / Expo SDK 55 | Esecuzione sulla New Architecture di React Native |
| Linguaggio | TypeScript 5.9 | Tipizzazione statica rigorosa per modelli, payload API, store e proprietà dei componenti |
| Stato | Zustand 5 + AsyncStorage | 11 store di dominio persistiti su disco e azzerati al termine del viaggio |
| Navigazione | Expo Router v5 | Routing basato su file, tab bar e pannelli modali |
| Animazioni | React Native Reanimated 3 | Gestione degli indicatori visivi di movimento sul thread UI a 60 FPS |
| Sensori | expo-sensors + expo-location | Lettura dell’accelerometro a 3 assi e fix GPS ad alta frequenza per il tachimetro |
| Audio | expo-audio | Riproduzione in background con controlli nativi su schermata di blocco |
| Funzionalità native | expo-camera, expo-haptics, expo-notifications | Scansione biglietti, feedback con vibrazione e notifiche sull’arrivo |
| Testing | Jest 29 + React Native Testing Library + fast-check | 142 suite, 921 test, test property-based per i filtri EMA e verifiche di accessibilità |
| API esterne | Proxy edge + OAuth 2.0 (JWT RS256) | Trenord B2B, percorsi OpenStreetMap, Open-Meteo, CurrentsAPI e Listen Notes |
| Localizzazione | react-i18next | Tutte le stringhe disponibili in italiano e inglese |
Test automatizzati
La codebase è protetta da 142 suite di test con 921 unit test:


La copertura include:
- Modelli matematici: test basati su proprietà con
fast-checkper verificare la convergenza dei filtri EMA e assicurare che le coordinate cicliche delle particelle non sforino mai dallo schermo. - Transizioni di stato: la macchina a stati del dead reckoning, il ciclo di vita dell’audio e le guardie di accesso con biglietto.
- Accessibilità: React Native Testing Library verifica la presenza di etichette per gli screen reader e il rispetto dell’area minima di tocco di 44px per tutti i pulsanti.
Conclusioni e lezioni apprese
La collaborazione con Trenord ci ha permesso di lavorare con vincoli e dati operativi reali. Questo ha spinto il progetto ben oltre una tipica applicazione mobile: abbiamo dovuto gestire l’instabilità dei sensori, le perdite di segnale, i consumi energetici e il malessere dei passeggeri in viaggio.
Su un treno la connessione non è una certezza, ma un valore aggiunto occasionale. Mantenere le informazioni critiche sul dispositivo, delegare le animazioni al thread nativo e adattare l’interfaccia a qualunque schermo sono state le scelte decisive per rendere l’app affidabile perfino nel cuore di una galleria alpina.
Un ringraziamento sincero ai compagni di squadra Tommaso Morganti e Luca Suzani, al team ingegneristico di Trenord per il supporto e il tempo dedicato, e a tutti i docenti del corso DIMA del Politecnico di Milano.
Il codice sorgente e la documentazione tecnica sono interamente open source su GitHub(si apre in una nuova scheda).