Entity
In questa sezione, viene descritta la struttura e le funzionalità delle entità nel sistema di simulazione.
Entità
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 raggioradius
;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
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.
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 aOrientation(0.0)
; l’emissione è isotropica (non direzionale);radius: Double
: raggio geometrico usato per lashape
(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 aOrientation(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
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.
Vedere la sezione Action per i dettagli sull’algebra delle azioni e il pattern Tagless Final.
Attuatori
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
)):
- 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):
- Nuova posizione e orientazione del robot integrando le equazioni del moto su un intervallo di tempo
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.
Per ulteriori dettagli sull’implementazione degli attuatori, vedere la sezione Attuatori.
Sensori
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 diDynamicEntity
(ad esempio,Robot
).Environment
: il tipo di ambiente in cui il sensore opera, sottotipo diEnvironment
(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 tipoA
.
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.
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 diEnvironment
. Il metodosense
implementa la logica di rilevamento, utilizzando illightField
per ottenere i dati di intensità luminosa.