Il Progetto

WasteService è un sistema software distribuito che implementa un servizio di smaltimento differenziato dei rifiuti. È costituito da diversi componenti applicativi, pensati per eseguire su nodi con architetture eterogenee: un dispositivo mobile (smartphone), un Raspberry Pi e dei dispositivi headless (server).

Ho sviluppato questo progetto assieme ai miei compagni di università TryKatChup e Raffaele Battipaglia, per il corso Ingegneria dei Sistemi Software M, seguendo i principi dello SCRUM Agile.

Obiettivo

L’obiettivo del corso era simulare la commissione di un sistema software per lo smaltimento di rifiuti, ad un team SCRUM Agile.

Il committente era il professore del corso, Antonio Natali, che ci ha fornito un documento con dei requisiti e gli strumenti di supporto da poter utilizzare/integrare nel progetto — e che ha interpretato la parte del cliente sul serio, sprint review dopo sprint review.

Requisiti

I requisiti possono essere riassunti come segue:

  • Il software WasteService deve predisporre delle zone con diverse funzionalità:
    • Un portellone Indoor, dove viene scaricato il materiale da smaltire.
    • Dei container per lo stoccaggio dei rifiuti di vetro e plastica, rispettivamente in GlassBox e PlasticBox, ciascuno con una capienza massima.
    • Una zona di riposo Home.
  • Un DDR robot che si occupa di prelevare i rifiuti e smaltirli, tornando alla zona Home quando non è attivo. Questo robot può essere virtuale o reale e deve poter svolgere le seguenti azioni:
    • Prelievo dei rifiuti da Indoor, da un Waste truck.
    • Spostamento presso il rispettivo container.
    • Deposito del materiale nel container.
  • Un software WasteServiceStatusGUI che deve poter permettere a un service manager umano di supervisionare lo stato del servizio: stato e posizione del DDR robot nella stanza, quantitativo di materiale contenuto nei container e stato del Led.
  • Dei componenti collegati a un Raspberry Pi, tra cui:
    • un Sonar (HC-SR04) usato come dispositivo di allarme, che ferma il DDR robot quando rileva una distanza sotto una certa soglia, e lo fa ripartire quando la distanza torna sopra;
    • un LED comune, usato per indicare lo stato del DDR robot (spento se è in Home, lampeggiante se si sta muovendo, acceso se è fermo a causa del Sonar).

QAK, il Linguaggio di Modellazione

L’intero sistema è modellato in QAK (QActor metamodel), il linguaggio progettato dal professore: un linguaggio di modellazione per applicazioni distribuite, ispirato all’actor model di Akka, dove la “k” sta per Kotlin, che è il linguaggio in cui il modello viene tradotto — senza però usare Akka.

I concetti sono pochi e si mappano bene su un sistema come questo:

  • un QActor è un’entità attiva che si comporta come una macchina a stati finiti;
  • ogni attore vive in un Context, cioè un nodo computazionale, dichiarato con host e porta;
  • gli attori interagiscono tramite messaggi (Dispatch unidirezionali, coppie Request/Reply) ed eventi, indirizzandosi per nome e non tramite riferimenti di basso livello. Fra nodi diversi, il runtime li trasporta su TCP, CoAP o MQTT.

Il che significa che l’interfaccia del sistema è un file di testo che elenca cosa ciascuno può dire agli altri:

// SmartDevice (truck) -> WasteService
Request storerequest:	storerequest(TYPE, LOAD)
// WasteService -> SmartDevice
Reply loadaccepted:		loadaccepted(_)
Reply loadrejected:		loadrejected(_)

// WasteService -> TransportTrolley
Request deposit:			deposit(TYPE, LOAD)
// TransportTrolley -> WasteService
Reply pickupcompleted:		pickupcompleted(_)
Dispatch depositcompleted:	depositcompleted(_)
Dispatch depositfailed:		depositfailed(REASON)

// Sonar -> AlarmController
Dispatch sonar_data:	sonar_data(DISTANCE)
// AlarmController -> PathExecutorBCR
Event stop:		stop(_)
Event resume:	resume(_)

// CONTEXES ===================================================================
Context ctx_wasteservice		ip [host="localhost" port=11800]
Context ctx_transporttrolley	ip [host="localhost" port=11801]
Context ctx_robot				ip [host="localhost" port=8020]
Context ctx_raspberrypi			ip [host="192.168.1.5" port=11802]

Si noti l’ultimo: il Raspberry Pi è semplicemente un altro context, a un altro indirizzo. Spostare il sottosistema di allarme su hardware reale ha voluto dire cambiare un indirizzo, non riscrivere l’interazione.

Architettura

Dal modello, la toolchain genera sia gli scheletri Kotlin sia il diagramma dell’architettura — il che rende l’immagine qui sotto un artefatto vero del progetto, e non un disegno fatto a posteriori per sembrare ordinati:


Architettura del sistema: context, attori e messaggi

Le responsabilità sono suddivise così:

  • ctx_wasteservice ospita wasteservice, l’attore che accetta o rifiuta le store request in base allo spazio libero nel container richiesto, typesprovider, che comunica agli smart device quali tipi di rifiuto sono accettati, e status_controller, che tiene aggiornata la GUI;
  • ctx_transporttrolley ospita transporttrolley, che esegue il deposito, pathexecutorbcr, che traduce un percorso in movimenti del robot e può essere fermato e fatto ripartire a metà strada, e trolleystateprovider, che pubblica lo stato del trolley;
  • ctx_raspberrypi ospita gli attori che incapsulano i dispositivi fisici: sonar, led, buzzer e display;
  • ctx_robot ospita basicrobot, l’attore fornito dal committente che pilota il robot.

Componenti

Smart Device — app mobile in Flutter, usata dall’autista del waste truck per inviare una StoreRequest, specificando quantità e tipo di rifiuto da depositare. È il punto d’ingresso dell’intero flusso.


Invio di una store request dallo Smart Device

Virtual Robot — applicazione web fornita dal committente, che simula il robot all’interno di una stanza rettangolare e accetta comandi di movimento via HTTP e WebSocket. È ciò che permette di sviluppare tutto il sistema senza avere il robot fisico sulla scrivania.

Mapper QAK22 — un altro strumento del committente: muove il robot per la stanza a passi e ne produce una rappresentazione a griglia.

Map Editor — applicazione desktop che abbiamo scritto in Java: carica quella griglia e permette di posizionare le zone (Home, Indoor, PlasticBox, GlassBox) col drag and drop, producendo il file di configurazione della mappa che il servizio carica all’avvio. Senza, configurare l’area significava scrivere coordinate a mano.


Posizionamento delle zone col Map Editor

Waste Service Core — il cuore del sistema: carica una configurazione della mappa, riceve le store request, decide se il carico ci sta e delega al transport trolley il prelievo e il deposito.

Waste Service RPi — il sottosistema di allarme e segnalazione. Gira su Raspberry Pi, con sonar, led, buzzer e display LCD pilotati da piccoli script Python incapsulati da attori Kotlin, e può girare anche in modalità simulata su un nodo desktop quando l’hardware non è a portata di mano.

Waste Service GUI — applicazione web Spring Boot che monitora il servizio: riceve gli aggiornamenti su WebSocket STOMP e disegna l’area, la posizione del trolley e il carico dei container.


La dashboard di monitoraggio

Gli Sprint

Il progetto è stato consegnato in quattro sprint, ciascuno chiuso da una review col committente:

SprintObiettivoReview
Sprint 0formalizzazione dei requisiti, system overview e modello08/09/22
Sprint 1core business del WasteService (requisiti 1 e 2)25/11/22
Sprint 2Raspberry Pi: sonar, led e allarme (requisito 4)14/04/23
Sprint 3monitoraggio: la status GUI (requisito 3)27/04/23

Ogni sprint segue lo stesso percorso nella repository: una problem analysis (il modello QAK del problema, coi relativi test) e poi un project (l’implementazione vera e propria), ciascuno con la propria pagina di documentazione.

La cosa che ho trovato più utile è stata proprio la forma: i requisiti erano volutamente incompleti, e il modo per colmare le lacune era chiedere al committente durante le review, esattamente come succede in un progetto reale. Scrivere il modello prima del codice — e far generare al modello gli scheletri e i diagrammi — faceva sì che quelle conversazioni riguardassero il comportamento del sistema, non i dettagli implementativi.

Esecuzione

La cartella di deployment contiene i pezzi pronti da avviare: l’SmartDevice.apk, i context compilati e uno script batch che lancia l’intero sistema, un context per processo:

cd ./VirtualRobot/
start run_VirtualRobot.bat

cd ../WasteService_Core/
start run_Ctx_Robot.bat
start run_Ctx_TransportTrolley.bat
start run_Ctx_WasteService.bat

cd ../WasteService_RPi/
start run_WasteService_RPi.bat

cd ../WasteService_GUI/
start run_WasteService_GUI.bat

Core e GUI hanno anche i rispettivi Dockerfile, per farli girare come container.

Demo

L’esecuzione completa — richiesta, prelievo, deposito, allarme e monitoraggio — è nel video dimostrativo:

Membri del Team

Raffaele Battipaglia
Karina Chichifoi
Michele Righi
Raffaele BattipagliaKarina ChichifoiMichele Righi