Skip to main content

Entity

In questa sezione, viene descritta la struttura e le funzionalità delle entità nel sistema di simulazione.

Entità

Entity

Il trait Entity modella un oggetto bidimensionale con:

  • id: UUID: identificativo univoco dell'entità;
  • position: Point2D: posizione cartesiana;
  • shape: ShapeType: forma geometrica;
  • orientation: Orientation: direzione espressa in gradi.

Costituisce l’interfaccia base comune per oggetti statici e dinamici.

Posizione

Point2D rappresenta un punto nel piano cartesiano (x: Double e y: Double) e fornisce primitive geometriche, quali:

  • somma/sottrazione vettoriale, moltiplicazione per scalare;
  • prodotto scalare, modulo, normalizzazione;
  • distanza euclidea.

Nota: queste operazioni sono la base per spostamenti, direzioni e collisioni.

Forma

ShapeType è un'enum con due varianti:

  • Circle(radius: Double): cerchio di raggio radius;
  • Rectangle(width: Double, height: Double): rettangolo con larghezza e altezza.

Nota: questo approccio consente una modellazione semplice ma estensibile delle dimensioni fisiche degli oggetti nello spazio simulato.

Orientamento

Orientation rappresenta l’angolo di rotazione rispetto a un riferimento fisso:

  • degrees: Double: gradi;
  • toRadians: Double: conversione in radianti per la trigonometria.

Nota: l’orientamento permette di rappresentare la direzione verso cui è rivolto un oggetto nello spazio, supportando il movimento direzionale e la rotazione.

Entità statiche e dinamiche

Entities

StaticEntity e DynamicEntity estendono Entity separando così le responsabilità.

DynamicEntity

DynamicEntity rappresenta un’entità che percepisce e agisce nel ciclo sense → plan → act:

  • sensors: Vector[Sensor[? <: DynamicEntity, ? <: Environment, ?]];
  • actuators: Seq[Actuator[? <: DynamicEntity]];
  • behavior: Policy.

I sensori raccolgono dati dall’ambiente; il behavior elabora le letture in base alla policy e seleziona un’azione; gli attuatori applicano l’azione all’entità. Questa struttura consente di modellare agenti robotici con ciclo sense–plan–act.

info

Progettazione del motore decisionale (Behavior) - regole, comportamenti, policy e DSL - nella pagina di design Behavior.

StaticEntity

StaticEntity modella entità non mobili che possono interagire passivamente con l'ambiente. Possono essere:

  • Obstacle / Boundary: rettangoli (orientabili) che occupano spazio e collidono;
  • Light: cerchi che emettono illuminazione (isotropica).

Nota: i boundary sono creati automaticamente durante la validazione dell’ambiente: sono rettangoli sottili posti sui bordi. Partecipano a collisioni e alla resistenza luminosa, e sono percepibili dai sensori di prossimità.

Ostacoli

Gli ostacoli (StaticEntity.Obstacle) sono “muri” rettangolari che bloccano il movimento e la luce, creando corridoi, stanze e scenari di navigazione.

Attributi principali:

  • id: UUID: identificativo univoco dell'entità;
  • position: Point2D: posizione del centro dell’ostacolo;
  • orientation: Orientation: angolo in gradi;
  • width: Double, height: Double: dimensioni;
  • shape: Rectangle(width, height): forma rettangolare.

La validazione include:

  • Dimensioni > 0;
  • Inclusione nei limiti dell’ambiente;
  • Assenza di sovrapposizioni con altre entità;

Nota: servono a costruire scenari realistici - dal corridoio stretto al piccolo labirinto - in cui i robot devono pianificare il movimento ed evitare collisioni.

Luce

Le luci (StaticEntity.Light) sono sorgenti radiali che forniscono un campo percettivo per i LightSensor e rendono osservabile lo stato luminoso (Environment.lightField).

Attributi:

  • id: UUID: identificativo univoco dell’entità;
  • position: Point2D: posizione del centro della luce;
  • orientation: Orientation: presente per uniformità di modello; impostato a Orientation(0.0); l’emissione è isotropica (non direzionale);
  • radius: Double: raggio geometrico usato per la shape (ShapeType.Circle(radius));
  • illuminationRadius: Double: portata luminosa efficace (raggio del contributo nel campo luce);
  • intensity: Double, attenuation: Double: livello e decadimento con la distanza;
  • shape: Circle(radius): forma circolare.

La validazione include:

  • parametri strettamente > 0;
  • inclusione nei limiti dell’ambiente;
  • assenza di sovrapposizioni con altre entità.

Nota: servono a creare zone buie/illuminate utili per testare policy di navigazione e priorità tra comportamenti.

Boundary

I boundary (StaticEntity.Boundary) definiscono i confini dell’ambiente. Sono creati automaticamente in validazione, in modo tale che l'utente non debba preoccuparsi di definirli esplicitamente. Simili agli ostacoli, ma con la differenza che hanno larghezza o altezza pari a zero. La creazione viene effettuata tramite la factory method nel companion object StaticEntity.Boundary.

Attributi principali:

  • id: UUID: identificativo univoco dell’entità;
  • position: Point2D: centro del lato;
  • orientation: Orientation: in factory impostato a Orientation(0.0);
  • shape: Rectangle(width, height) con uno dei due lati pari a zero.

La validazione include:

  • presenza su tutti i lati dell’ambiente;
  • dimensioni coerenti con i bordi (spessore zero consentito per i boundary);
  • nessuna sovrapposizione anomala con entità interne.

Nota: gli eventuali boundary definiti nel file YAML vengono ignorati: in validazione vengono sempre ricreati i 4 canonici. Questi elementi sono fondamentali per definire i limiti entro cui le entità possono muoversi e interagire.

Robot

Robot

La case class Robot estende DynamicEntity e rappresenta un’entità autonoma in grado di muoversi e interagire con l’ambiente circostante nello spazio bidimensionale. Ogni robot è caratterizzato da un identificativo univoco (UUID), una posizione e un’orientazione nello spazio, nonché da una forma geometrica circolare (ShapeType.Circle).

Il robot è dotato di un insieme di attuatori (Seq[Actuator[Robot]]) e di una collezione di sensori (Vector[Sensor[Robot, Environment]]), che gli permettono di percepire e raccogliere informazioni sull’ambiente. Inoltre, possiede una strategia comportamentale (Policy) che definisce la logica decisionale del robot in base ai dati forniti dai sensori.

note

Vedere la sezione Action per i dettagli sull’algebra delle azioni e il pattern Tagless Final.

Attuatori

Actuator

Un attuatore è un componente in grado di modificare lo stato di un’entità dinamica (DynamicEntity). Il trait Actuator[E] definisce l’interfaccia generica, tramite il metodo act(dt, entity), che aggiorna l’entità dopo un intervallo temporale dt (delta time), restituendone una nuova istanza in un contesto monadico F[_].

Attuatori di movimento

Gli attuatori di movimento sono modellati tramite i motori differenziali. DifferentialWheelMotor estende Actuator[Robot] ed è costituito da due ruote (Wheel) – sinistra e destra – dotate di velocità lineare (speed) e una forma circolare (ShapeType.Circle). Il movimento del robot viene calcolato con un modello cinematico differenziale (DifferentialKinematics).

  • Velocità lineare (media delle velocità delle due ruote; ottenute moltiplicando la velocità (speed) per il raggio della ruota (radius)):
v=vleft+vright2v = \frac{v_{\text{left}} + v_{\text{right}}}{2}
  • Velocità angolare (proporzionale alla differenza tra le velocità delle ruote divisa per la distanza tra le ruote; si assume che la distanza tra le ruote sia pari al diametro del robot):
ω=vrightvleftdwheel\omega = \frac{v_{\text{right}} - v_{\text{left}}}{d_{\text{wheel}}}
  • Nuova posizione e orientazione del robot integrando le equazioni del moto su un intervallo di tempo dt:
x=x+vcos(θ)dtx' = x + v \cdot \cos(\theta) \cdot dt y=y+vsin(θ)dty' = y + v \cdot \sin(\theta) \cdot dt θ=θ+ωdt\theta' = \theta + \omega \cdot dt

Questa logica, incapsulata nel metodo act, consente di aggiornare lo stato del robot in modo funzionale e validato, rendendo il comportamento dell’attuatore modulare ed estendibile.

info

Per ulteriori dettagli sull’implementazione degli attuatori, vedere la sezione Attuatori.

Sensori

Sensor

I sensori sono componenti che permettono a un'entità dinamica di percepire l'ambiente circostante. Il trait Sensor[Entity, Environment] definisce un'interfaccia generica per i sensori. I sensori sono parametrizzati su tre tipi:

  • Entity: il tipo di entità che il sensore può percepire, sottotipo di DynamicEntity (ad esempio, Robot).
  • Environment: il tipo di ambiente in cui il sensore opera, sottotipo di Environment (ad esempio, Environment stesso).
  • Data: il tipo di dato restituito dal sensore.

Inoltre i sensori contengono un campo offset che rappresenta la posizione del sensore rispetto all'entità che lo possiede.

Infine, un metodo sense[F[_]](entity: Entity, env: Environment): F[Data] che permette di ottenere i dati di rilevamento dal sensore. Il tipo F[_] è un tipo di effetto generico (come IO, Id, Task, etc.) che permette:

  • astrazione rispetto al tipo di effetto utilizzato per l'esecuzione;
  • composizione funzionale con altre operazioni monadiche;
  • testabilità tramite interpreti fittizi o mock.

Il tipo SensorReading è un tipo di utilità che aiuta a rappresentare i dati letti da un sensore. Si tratta di un case class che contiene:

  • sensor: Sensor[?, ?]: il sensore che ha effettuato la lettura;
  • value: A: il valore letto dal sensore, parametrizzato su un tipo A.

Questo tipo consente di incapsulare le letture dei sensori in un formato coerente, facilitando la gestione e l'elaborazione dei dati raccolti.

SensorReadings è un tipo di utilità che rappresenta una raccolta di letture dei sensori.

info

I dettagli implementativi riguardanti i sensori sono disponibili nella sezione Implementazione dei sensori.

Sensori di prossimità

La case class ProximitySensor estende Sensor[Robot, Environment] e rappresenta un sensore di prossimità che rileva la presenza di altre entità nell'ambiente. Questo sensore dispone di un campo range che rappresenta il raggio di azione del sensore. I valori ritornati da questo sensore sono di tipo Double, e rappresentano la distanza alla quale si trova l'entità più vicina (normalizzata tra 0 e 1):

  • 0 indica che l'entità è molto vicina;
  • 1 indica che è molto lontana. Il metodo sense implementa la logica di rilevamento, tramite ray casting, che calcola la distanza tra il sensore e le entità nell'ambiente, restituendo il valore normalizzato.

Sensori di luce

La case class LightSensor estende Sensor[Robot, Environment] e rappresenta un sensore di luce, in grado di rilevare l'intensità luminosa in una determinata area. I valori restituiti dal sensore sono Double, e rappresentano l'intensità luminosa normalizzata tra 0 e 1, dove:

  • 0 indica assenza di luce;
  • 1 indica luce massima. La distribuzione della luce nell'ambiente è rappresentata da un campo lightField all'interno di Environment. Il metodo sense implementa la logica di rilevamento, utilizzando il lightField per ottenere i dati di intensità luminosa.