This document describes the high-level architecture and design of YARS (Yet Another Robot Simulator).
YARS is a modular robot simulation platform consisting of several interconnected subsystems:
┌─────────────────────────────────────────────────────────────────┐
│ YARS Application │
├─────────────────────────────────────────────────────────────────┤
│ YarsMainControl │
│ (Application Lifecycle) │
├────────────────┬────────────────┬────────────────┬──────────────┤
│ Configuration │ Physics │ Visualization │ Logging │
│ (XML/XSD) │ (Bullet) │ (OGRE 14) │ (Multi-out) │
├────────────────┼────────────────┼────────────────┼──────────────┤
│ Data │ Robot │ SceneGraph │ File │
│ Models │ Controllers │ Views │ CSV │
│ Parsers │ Actuators │ Overlays │ Blender │
│ Schemas │ Sensors │ SDL2 Input │ Console │
└────────────────┴────────────────┴────────────────┴──────────────┘
The application entry point and lifecycle manager.
Key Classes:
YarsMainControl- Central coordinator for simulation lifecycle- Handles initialization, simulation loop, and shutdown
- Manages communication between subsystems
Flow:
main() → YarsMainControl::init() → loadConfiguration() → startSimulation()
↓
YarsMainControl::step()
↓
┌───────────────┼───────────────┐
↓ ↓ ↓
Physics::step() View::step() Logging::step()
XML-based configuration with XSD schema validation.
Components:
YarsConfiguration- Central configuration managerdata/- Data model classes for all configuration elements- XSD schema defines valid simulation configurations
Configuration Hierarchy:
<rosiml>
├── <simulator> # Simulation parameters
├── <macros> # Reusable definitions
├── <screens> # Visualization settings
├── <environment> # World setup (ground, walls, etc.)
└── <robots> # Robot definitions
└── <robot>
├── <body> # Physical components
├── <sensors> # Sensor definitions
├── <actuators> # Motor/joint definitions
└── <controller> # Control logic
Bullet Physics integration for rigid body dynamics.
Key Classes:
Robot- Physical robot representationBody- Rigid body wrapperJoint- Constraint/joint handlingSensor/Actuator- Physics-aware I/O
Physics Loop:
PhysicsEngine::step()
→ updateActuators() # Apply motor forces
→ bulletWorld.step() # Bullet simulation
→ updateSensors() # Read sensor values
→ updateBodies() # Sync transforms
OGRE 14-based 3D rendering with SDL2 window management.
GUI Components (view/gui/):
OgreHandler- OGRE initialization and resource managementSdlWindow- SDL2 window + OGRE viewport integrationSceneGraph- Scene node hierarchyTextOverlay- On-screen display (OSD)CameraMan- Camera control and following modes
Rendering Pipeline:
OgreHandler::setupSceneManager()
→ RTSS initialization (shader generation)
→ Resource loading (materials, meshes, fonts)
→ SceneGraph creation
SdlWindow::step()
→ Handle input events
→ Update camera
→ OgreHandler::step() → root->renderOneFrame()
OGRE 14 Specifics:
- Uses GL3Plus render system (OpenGL 3.3+)
- RTSS (Runtime Shader System) for material shaders
- No fixed-function pipeline (all materials need shaders)
- Cameras and lights attached to SceneNodes
Multi-target logging framework.
Available Loggers:
FileLogger- Text file outputCSVLogger- Structured CSV exportConsoleLogger- Terminal outputBlenderLogger- Blender animation exportSelforgLogger- Self-organization metrics
Logger Configuration:
<logging>
<csv filename="data.csv" precision="6">
<sensor name="sensor1"/>
<actuator name="motor1"/>
</csv>
</logging>Plugin-based robot controller system.
Controller Types:
- Built-in: Braitenberg vehicles, constant value, sine wave
- External: TCP/IP, Named Pipe communication
- Custom: Dynamically loaded
.so/.dylibplugins
Controller Interface:
class Controller {
virtual void init();
virtual void update(double dt);
virtual void close();
};1. Input Phase
└── SDL2 events → Camera/UI updates
2. Control Phase
└── Controllers read sensors → compute outputs → set actuators
3. Physics Phase
└── Bullet applies forces → steps simulation → updates transforms
4. Render Phase
└── SceneGraph sync → OGRE renders frame
5. Logging Phase
└── Loggers capture state → write outputs
XML File → SAX Parser → Data Models → Runtime Objects
↓
Validation (XSD)
↓
Configuration Events
↓
Subsystem Initialization
Used for event notification between components.
ObservableMessage- Event base class- Components register for events they care about
Used for global managers:
OgreHandler::instance()Data::instance()(configuration data)
Used for creating configurable objects:
- Sensor factories
- Actuator factories
- Controller factories
Robot composition:
- Robots contain Bodies, Sensors, Actuators
- Each component handles its own physics/rendering
src/yars/
├── configuration/
│ ├── data/ # Data model classes
│ ├── xsd/ # Schema definitions
│ └── container/ # Generic containers
├── defines/ # Constants, version info
├── logging/ # Logger implementations
├── main/ # Application control
├── physics/ # Bullet integration
├── types/ # Math types, matrices
├── util/ # Utilities (CircularBuffer, StringTokeniser, etc.)
└── view/
├── console/ # Text-mode view
└── gui/ # OGRE visualization
- Create controller class in
contrib/controller/ - Implement
Controllerinterface - Register in CMakeLists.txt
- Reference in XML configuration
- Define data model in
configuration/data/ - Implement physics behavior in
physics/ - Add visualization in
view/gui/ - Update XSD schema
- Implement logger class in
logging/ - Add factory method
- Update configuration parser
- Update XSD schema
YARS uses a single-threaded main loop:
Main Thread:
└── Simulation Loop
├── Input handling
├── Physics step
├── Rendering
└── Logging
Background (if enabled):
└── Video capture encoding
Thread safety considerations:
- Physics and rendering are synchronized
- Logging may buffer for async writes
- Controller callbacks run on main thread
- OGRE resources managed by ResourceManager
- Bullet physics objects owned by physics world
- Configuration data uses shared pointers
- Scene graph uses OGRE's node ownership
- Physics step rate configurable (default: 100 Hz)
- Rendering rate tied to vsync or uncapped
- Large scenes benefit from spatial partitioning
- Shader compilation cached by RTSS
- Hot path: Physics raycast for sensors (~69% of CPU time)
- See
PROFILING.mdfor detailed performance analysis
YARS uses Catch2 for unit and integration testing.
Test Structure:
tests/
├── unit/ # Fast, isolated unit tests
│ ├── test_p3d.cpp
│ ├── test_quaternion.cpp
│ ├── test_matrix.cpp
│ ├── test_circular_buffer.cpp
│ ├── test_string_tokeniser.cpp
│ └── test_colour.cpp
└── integration/ # Tests requiring full subsystems
├── test_configuration.cpp
└── test_simulation.cpp
Running Tests:
cmake .. -DYARS_BUILD_TESTS=ON
make
ctest --output-on-failure| Library | Purpose | Notes |
|---|---|---|
| Bullet Physics 3 | Rigid body dynamics | System library |
| OGRE 14 | 3D rendering | Git submodule, macOS frameworks |
| SDL2 | Window/input | System library |
| Xerces-C | XML parsing | System library |
| CLI11 | Command-line parsing | Header-only, replaced Boost.ProgramOptions |
| Catch2 3 | Unit testing | Optional, system library |
Note: YARS uses C++17 standard library features (<filesystem>, <optional>) instead of Boost equivalents.