Skip to content

LOTUSim Architecture

estherRay edited this page Aug 17, 2026 · 3 revisions

1. Intro

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.

Contents


Key Concepts and Terminology

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.


High-Level System Diagram

Architecture 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.


Design Principles

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.


Component Architecture

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

ommunication Architecture

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

Working with the Core: Gazebo Plugins

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.


The lotus_param Block

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>

Time Management & Plugin Lifecycle

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.


World Plugins Reference

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>

Multi-Agent System

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 heading

sdf_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:

  • customUserPreUpdate
  • customUserPostUpdate
  • customUserAddEntity
  • customUserDeleteEntity

Renderer Backends

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.


User Application Interface (Web UI)

Lotusim UI Home

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 Lotusim UI Models

For the full walkthrough of using the Web UI to build a scenario, see Via the Web UI in the Tutorial.


Environment Variables, Debug Builds & Logging

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_build

Logging: 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.

Clone this wiki locally