-
Notifications
You must be signed in to change notification settings - Fork 15
LOTUSim Architecture
This document outlines LOTUSim's high-level software architecture, including its design principles, system structure, component interactions, and key architectural decisions.
It is not a replacement for implementation-level documentation; developers should refer to the wiki docs and source code for details.
This document covers core architectural details only. For full documentation, contact LOTUSim support email lotusim_support@naval-group.com.
- Key Concepts and Terminology
- High-Level System Diagram
- Design Principles
- Component Architecture
- Communication Architecture
- Working with the Core: Gazebo Plugins
- The
lotus_paramBlock - Time Management & Plugin Lifecycle
- World Plugins Reference
- Multi-Agent System
- Renderer Backends
- User Application Interface (Web UI)
- Environment Variables, Debug Builds & Logging
Click to expand
Entity: Any object within the simulation world (e.g. vessel, sensor, mesh). Managed by the Gazebo Simulation Core. Each entity is assigned a unique identifier by Gazebo and may include configuration in lotus_params. Not all entities are agents, an entity is only considered an agent if it has an associated external system that controls the entity.
Agent: An entity within the simulation that is controlled by an external system (autonomy stack, fleet management system...) via the defined ROS 2 interface. For example, a vessel whose navigation is driven by a Nav2 autonomy stack is an agent, whereas a static obstacle or environmental object in the simulation world is an entity but not an agent.
Multi-Agent Simulation: A simulation mode in which multiple agents operate simultaneously within the same environment, each controlled independently by its own external system.
Subsystem: A cohesive functional domain within LOTUSim that encapsulates a major simulation responsibility, such as physics, sensing, power, or rendering. A Subsystem is implemented as a Gazebo plugin and can be independently enabled or disabled without affecting other parts of the system.
Plugin: A software component that is dynamically loaded into LOTUSim Core to provide a Subsystem's functionality. Plugins can be added or removed without modifying the core system.
Component: A logical, replaceable unit of functionality within a Subsystem that implements a specific responsibility. Components are the individual functional models, such as a radar model, that can be independently swapped or reconfigured within a Subsystem.
Interface: C++ abstract base class provided by LOTUSim that defines the communication contract between a Subsystem and an external Engine. Multiple Interface instances can be active simultaneously within a single Subsystem.
User External Application: Any software system that runs outside of LOTUSim and interacts with the simulation through the defined ROS 2 interface. User External Applications are not part of the simulation core and do not participate in the simulation loop directly.
Engine: A user-operated external server that hosts mathematical models and performs computation on behalf of a LOTUSim Subsystem. The Engine receives simulation state from its corresponding Interface, executes the relevant models, and returns computed results. Engines are entirely external to LOTUSim, examples include a Physics Engine running hydrodynamic models.
Server: In the context of LOTUSim, servers refer to the processes hosting Engines or other external services. A single server may host one or more Engines, and multiple servers may be used in parallel to distribute computational load across a deployment.
Model: A computational representation of a physical system or behaviour within an Engine. Models define how a simulated entity responds to inputs, for example, a hydrodynamic model defines how a vessel's velocity and heading change in response to thruster forces and environmental conditions.
Simulation Time: Internal clock of the simulation, expressed in simulated seconds. Simulation time may run faster or slower than real time and can be paused or adjusted.
Deterministic Simulation: A simulation mode in which the same initial conditions always produce the same outputs across runs.
Stochastic Simulation: A simulation mode in which randomness is introduced, through noise models, randomness, or environmental disturbances, to better approximate real-world variability.
lotus_param: Custom LOTUSim XML configuration block embedded within a Gazebo SDF model definition. Each Subsystem plugin reads the relevant section of lotus_params on entity spawn to configure its behaviour and instantiate the appropriate Interface objects for that entity.
Operational Domain: The physical environment in which a simulated platform is operating. LOTUSim supports three operational domains: aerial (airborne), surface (on the water surface), and underwater (submerged). A platform may transition between domains during a simulation.
Actuator: A hardware component (thrusters, rudders…) on a simulated platform that produces physical force or motion. Actuator commands are sent to LOTUSim by User External Applications via ROS 2 and are processed by the Physics Subsystem.
Proprioceptive Sensor: A sensor that measures the internal state of the platform itself, such as its position, velocity, or orientation.
Exteroceptive Sensor: A sensor that measures the external environment or detects other entities. Examples include sonar and radar.
Renderer: A component generating the simulation's visual representation.
Real-time factor (RTF): Ratio of simulated time to wall-clock time.
Environment: The overall world setting the simulation takes place in.
Scene: A specific configuration of environment + entities for one simulation run.
Note: The gear icon indicates that these are under-development.
The LOTUSim Core Layer is built on Gazebo (made by OSRF), providing physics stepping, entity management, and the simulation loop. It includes six Subsystems: Physics, Sensor, Power, Rendering, Multi-agent, and Environment. Each is a Gazebo plugin operating alongside the Simulation core and interacting with it via a query-based update model.
The Internal Interface Layer provides the communication bridge between LOTUSim and external computation servers.
The Internal Computation Layer hosts user-operated Engines (Physics, Sensor, Power). Each Engine is a standalone server that receives state data from its corresponding Interface, executes the relevant mathematical models, and returns results. This layer is entirely external to LOTUSim and can be deployed on dedicated hardware or scaled across multiple machines as required.
The External Interface Layer manages communication between the LOTUSim Core and User External Applications. It comprises the ROS 2 Interface Layer, which uses DDS-based communication to expose simulation state and accept control inputs.
LOTUSim decentralises the computational load for large-scale simulation by distributing workloads across multiple servers using a client-server architecture, instead of relying on a single machine. This removes the single-machine bottleneck and allows the simulation to scale with available computing resources, supporting hundreds of simulated vessels distributed across environments.
Communication uses standardised mechanisms: ROS 2 with FastDDS for internal communication and user-implemented interfaces for external integration, enabling loosely coupled components to operate across network boundaries.
Subsystems, Interfaces, and Engines can each be independently enabled, disabled, or replaced without impacting the rest of the system.
LOTUSim Core Layer
| Element | Responsibility | Notes |
|---|---|---|
| Simulation Core (Gazebo) | Advances simulation time, manages entities,coordinates subsystem update loop | Built on Gazebo by OSRF. Planned replacement with internal library in future iteration |
| Multi-agent Subsystem | Coordinates agent registration, state tracking, and inter-agent events | Central registry for all simulated entities |
| Physics Subsystem | Manages physics computation and forwards state to Physics Interfaces. The implemented default is xdyn | Implemented as a Gazebo plugin; removable. Connects to user-operated Physics Engines |
| Waypoint Follower Subsystem | Provides lightweight kinematic motion for entities that do not require dynamic physics modeling | Implemented as a Gazebo plugin; removable. Operates entirely locally with no external Engine. Alternative to the Physics Subsystem for low-fidelity motion |
| Sensor Subsystem | Manages sensor simulation, forwards state to Sensor Interfaces | Optional. Connects to user-operated Sensor Engines. Architecture under review |
| Rendering Subsystem | Provides visual representation of the simulation world | Implemented as a Gazebo plugin; removable. Supports multiple renderers via Rendering Interface |
| Power Subsystem | Models energy generation, storage, and consumption per platform | Optional; per model. Connects to user-operated power providers and consummers types - see Power Providers Available |
| Environment Subsystem | Maintains and serves environment state variables | Under development. Publishes environment changes to ROS 2. Read by Physics, Sensor, and Rendering Subsystems |
Internal Interface Layer
| Element | Responsibility | Notes |
|---|---|---|
| Physics Interface | Forwards entity state to the Physics Engine, returns computed dynamics | Multiple instances per entity (one per domain). Instantiated via factory method |
| Sensor Interface | Forwards entity/environment state to the Sensor Engine, returns sensor outputs | Under development. Multiple instances per Sensor Subsystem |
| Power Interface | Forwards power draw/generation state to the Power Manager, returns updated power state | Multiple instances per Power Subsystem |
| Rendering Interface | Forwards simulation state to external rendering backends | Single instance per Rendering plugin. Connection defined at plugin level, not per entity |
Internal Computational Layer
| Element | Responsibility | Notes |
|---|---|---|
| Physics Engine | Runs hydrodynamic/physics models given state forwarded by the Physics Interface, returns computed dynamics | User-operated, external to LOTUSim. Default: xdyn |
| Sensor Engine | Runs sensor models given entity/environment state, returns sensor outputs | User-operated, external. Under development |
| Power Engine | Runs power provider/consumer models, returns updated power state | User-operated, external |
External Interface Layer
| Node | Direction | Responsibility |
|---|---|---|
| ROS 2 Interface Layer | Publishes simulation state, receives commands from external ROS 2 nodes | Primary integration mechanism. Uses FastDDS for distributed, peer-to-peer communication |
| WebSocket Interface | Lightweight access to selected simulation data | For dashboards, monitoring tools, browser-based clients |
| Rendering Interface | Forwards simulation state to external rendering backends | Single instance per Rendering plugin |
ROS2 Node Architecture
| Node | Direction | Responsibility |
|---|---|---|
| Multi-agent Subsystem node | Publisher & Action server | Publishes entity/simulation state. Action server for entity spawn/deletion commands |
| Physics Subsystem node | Subscriber | Subscribes to vessel actuator commands, forwards to the Physics Interface |
| Waypoint Follower node | Publisher / Subscriber / Service | Subscribes to waypoint topic, publishes status updates, provides a stop service |
| Sensor Subsystem node | Publisher & Subscriber | Publishes sensor outputs, subscribes to Environment Subsystem topic. Under development |
| Power Subsystem node | Publisher | Publishes power/energy state for all simulated platforms |
| Environment Subsystem node | Publisher & Server | Publishes environment state changes, provides a service for environment changes. Under development |
| Rendering Subsystem node | Subscriber | Subscribes to Environment Subsystem topic; talks to renderers only via the Rendering Interface |
| WebSocket Bridge node | Bridge | Subscribes to selected ROS 2 topics, forwards to connected WebSocket clients |
LOTUSim uses Gazebo as its core simulation framework to avoid reinventing common infrastructure (SDF/text parsing, time management, physics solvers), focusing development effort on simulation-specific functionality.
On top of Gazebo's core libraries, LOTUSim implements plugins invoked during each update loop. Each has a corresponding base class handling Gazebo update callbacks, abstracting Gazebo specifics and simplifying customization:
| Module | Base class(es) |
|---|---|
| Multi-agent system | EntityManager |
| Physics plugin |
PhysicsInterfacePlugin, PhysicsInterfaceBase
|
| Render plugin |
RenderPlugin, RenderInterfaceBase
|
| Sensor plugin |
LotusimSensorPlugin, CustomSensor
|
If you're extending or customising simulation behavior, the Doxygen docs for these base classes are the place to start. See also Extend with your components for hands-on sensor/plugin/model tutorials.
Models that interact with LOTUSim must include a lotus_param block in their SDF definition, modules only process models containing this block. you can see an example under LOTUSim/examples/python-scripts/controlling-ships.py
<lotus_param>
<render_interface>
<publish_render>true</publish_render>
<renderer_type_name>frigate</renderer_type_name>
</render_interface>
<physics_engine_interface>
<surface>
<connection_type>XDynWebSocket</connection_type>
<uri>ws://127.0.0.1:12345</uri>
<thrusters>
<thruster name="PSPropRudd"/>
<thruster name="SBPropRudd"/>
</thrusters>
</surface>
<init_state>Surface</init_state>
</physics_engine_interface>
</lotus_param>Simulation time follows Gazebo's discrete time-stepping model, controlled by two parameters in the world SDF's <physics> block:
| Parameter | Meaning | Default |
|---|---|---|
max_step_size |
Duration of each simulation step | 0.001 s |
real_time_factor |
Target ratio of simulation time to real time | 1.0 |
Every timestep, all registered plugins are invoked once, in this order: PreUpdate → Update → PostUpdate.
Each plugin implements up to four lifecycle methods:
| Method | Access | Purpose |
|---|---|---|
Configure |
- | Called once at plugin initialisation; receives the plugin's SDF configuration |
PreUpdate |
Read-write | Apply controls, sync external data, modify state before physics evaluation |
Update |
Read-write | Physics integration (force application, collision resolution) |
PostUpdate |
Read-only | Publish sensor data, log results, trigger post-physics logic |
For example, AISPlugin inherits the appropriate Gazebo system interfaces, with its Update method invoked once per step, behavior driven by its SDF configuration.
All these are declared in the world file's top level. See Your World File and Your Plugin for how world files and custom plugins work in general. This section is the reference for LOTUSim's own built-in plugins specifically.
Physics engine - connects models to external physics engines. Scans all models for physics_engine_interface in lotus_param, and initializes connections per the specified connection_type:
<plugin filename="physics_interface_plugin" name="lotusim::gazebo::PhysicsInterfacePlugin">
</plugin>Multi-agent system:
<plugin filename="multi_agent_system_plugin" name="lotusim::gazebo::MultiAgentSystem">
</plugin>Publishes entity poses to /poses, services the mas_cmd action interface - see Multi-Agent System below.
Rendering system - enables external rendering backends:
<plugin filename="render_plugin" name="lotusim::gazebo::RenderPlugin">
<connection_protocol>TCPUDP</connection_protocol>
<ip>127.0.0.1</ip>
<udp_port>23456</udp_port>
<tcp_port>23457</tcp_port>
</plugin>-
connection_protocol: protocol identifier (e.g.TCPUDP), mapped internally to a registered protocol handler - Remaining parameters are protocol-specific (ports, IP, serialization format)
Waypoint follower - see Via the Web UI in the Tutorial for the different trajectory modes (circle, line, waypoints) and how to configure them; the plugin itself is declared as:
<plugin filename="waypoint_plugin" name="lotusim::gazebo::WaypointFollowerPlugin">
</plugin>Manages all entities in the simulation: creation, deletion, state updates. Currently wraps Gazebo's internal entity system with ROS 2 DDS integration.
Simulation commands - two action interfaces, mas_cmd and mas_cmd_array, sharing this message definition:
# Built-in command types
int8 CREATE_CMD = 0
int8 DELETE_CMD = 1
int8 MOVE_CMD = 2
uint8 cmd_type
string sdf_string
string vessel_name
uint16 entity
geometry_msgs/Pose vessel_position
geographic_msgs/GeoPoint geo_point
float32 headingsdf_string carries a full SDF description of the model to instantiate - encoding it as a string allows runtime parameter modification without pre-registered templates. (This is exactly the mechanism used in the controlling_ships.py example - see Manually (script-based) in the Tutorial.)
Publishing positions: all active entity poses are published to /poses (geometry_msgs/PoseArray).
Custom behaviors: the MAS provides a base class for extension - inherit and override:
customUserPreUpdatecustomUserPostUpdatecustomUserAddEntitycustomUserDeleteEntity
LOTUSim supports modular renderer backends:
| Backend | Notes |
|---|---|
| Gazebo (default) | Uses Qt and the OGRE engine. Not recommended for high-fidelity visualization or large-scale environments |
| Unity | Left-handed coordinate system (Z forward, Y up), vs. Gazebo/most CAD tools' right-handed system (X forward, Z up) - LOTUSim applies a coordinate transform (Z → -Y) for consistency. Same convention note as individual vessel models - see Models Specifications |
The renderer plugin communicates via ROS 2 messages or TCP/UDP; custom protocols can be added via extension. See Renderer Backends above for the plugin declaration, and Extend with your components if you're implementing a custom renderer.

The LOTUSim Web UI assists in launching and managing simulations - React/Vite/Node.js frontend, accessible from any modern browser. All control requests go through a REST API; real-time position updates stream over WebSocket.
LOTUSim simulates hardware and environmental dynamics only - user applications (navigation algorithms, fleet coordinators) should run as external processes interfacing via ROS 2, mirroring real-world deployment architecture.
Features:
- Home - geographic world map for a large open operational area
- Models - add/remove/edit simulation models in the database (see below)
-
Scenarios - create scenarios and lists existing ones
For the full walkthrough of using the Web UI to build a scenario, see Via the Web UI in the Tutorial.
Environment variables: set up during installation, and used by LOTUSim to resolve directory paths. Use them (rather than hardcoded paths) when referencing files during development.
Debug build:
lotusim --debug clean_buildLogging: enabled automatically for all subsystems. Logs are written to the logs directory under the path specified by LOTUSIM_PATH.
This document will evolve as development progresses. For details not covered here - contact lotusim_support@naval-group.com.
↑ Back to Top ↑ | 🏠 Home | ❓ Support | Licensed under Eclipse Public License 2.0 | © 2025 Naval Group