Skip to main content

Behavior

Il modulo Behavior è il motore decisionale di un'entità dinamica, progettato per operare all'interno del ciclo di simulazione sense → plan → act. La sua responsabilità è ricevere le letture sensoriali (SensorReadings) e produrre una intenzione, ossia l’ Action da eseguire, mantenendo una separazione netta tra la logica decisionale e l'esecuzione fisica dell'azione.

Posizionamento nel ciclo di simulazione

Il Behavior si inserisce nel ciclo di esecuzione di un'entità autonoma:

  1. Sense: l'entità acquisisce informazioni sull'ambiente tramite i suoi sensori, producendo un SensorReadings;
  2. Plan: il Behavior elabora il contesto e sceglie un’azione appropriata;
  3. Act: l’azione viene passata agli attuatori, che modificano lo stato dell'entità (es. velocità delle ruote).

Nota: il behavior è stateless (decisione cieca sul tick corrente).
Se servisse “memoria”, bisognerebbe estendere il contesto di input invece di introdurre mutazioni.

I/O e contratti

Il sistema opera su dati strutturati che incapsulano tutte le informazioni necessarie:

  • Input: BehaviorContext
    • sensorReadings: SensorReadings: le letture sensoriali correnti;
    • rng: RNG: un generatore di numeri pseudo-casuali per comportamenti stocastici e riproducibili.
  • Output una Decision[F] ossia una funzione totale BehaviorContext => (Action[F], RNG) (modellata come Kleisli).
    • Action[F]: l'azione da eseguire sull'entità;
    • RNG: lo stato aggiornato del generatore, per garantire che non venga perso il riferimento alla sequenza casuale.

Nota: un Behavior completo deve essere una funzione totale, ossia, dato un qualsiasi BehaviorContext valido, deve sempre produrre un'Action valida.

Pattern Kleisli

I comportamenti sono modellati come funzioni pure da un contesto a una decisione: Decision[F] = Kleisli[Id, BehaviorContext, (Action[F], RNG)]. Questo permette di avere:

  • accesso al contesto: Kleisli.ask fornisce accesso esplicito al contesto;
  • composizione: con Kleisli otteniamo combinatori (map/flatMap, andThen, local, ask) e un DSL pulito;
  • testabilità: si testa con decision.run(ctx) in modo deterministico;
  • astrazione degli effetti: attualmente utilizziamo Id, di conseguenza è una funziona pura; in futuro può sfruttareEither/IO senza cambiare le API del DSL.

Astrazione dei comportamenti

Il modello si basa su quattro livelli di astrazione:

  • Condition: predicati che valutano lo stato sensoriale (es. soglie/relazioni);
  • PartialBehavior: regole che possono proporre A (Some) o defers (None);
  • Behavior: composizione di regole con fallback garantito per assicurare totalità (sempre un’azione A);
  • Policy: strategie complete e riusabili per casi d'uso specifici (es. evita ostacoli, fototassi, ecc.).

Panoramica tra Policy e Behavior

Il diagramma seguente sintetizza le relazioni tra Policy, i Behavior concreti, Decision[F] e BehaviorContext.

Policy e Behaviors

DSL di composizione

Il modulo fornisce un linguaggio specifico di dominio per comporre comportamenti in modo dichiarativo:

Esempio: evitamento ostacoli con fallback
((front < 0.30) ==> turnRight[F]) |
((left < 0.25) ==> turnRight[F]) |
((right < 0.25) ==> turnLeft[F])
.default(moveForward[F])

Il DSL supporta:

  • composizione left-biased con priorità esplicite;
  • operatori logici per condizioni complesse;
  • fallback garantiti per totalità.

Politiche predefinite

Sono incluse un insieme di politiche standard che coprono i casi d'uso più comuni:

PolicyDescrizioneCaso d'uso
AlwaysForwardMovimento costante in avantiTesting, comportamento base
RandomWalkEsplorazione stocasticaCopertura spaziale
ObstacleAvoidanceEvitamento ostacoli multi-livelloNavigazione sicura
PhototaxisAttrazione verso sorgenti luminoseComportamento biologico
PrioritizedComposizione gerarchica di strategieComportamenti complessi
info

Per i dettagli tecnici di implementazione, consultare la sezione implementazione behavior.