Maintenance rule: Any change to the project (new class, new module, new sensor, refactor, dependency change, etc.) must be reflected in this file to keep it accurate for future AI tools.
MultiVehicle Simulator (MVSim) is a lightweight, realistic 2.5D dynamics simulator for mobile robots and multi-agent research. It runs standalone, as a ROS 2 node, or embedded in C++/Python applications. Worlds are fully configured via XML files. Current version: 1.3.0.
- License: BSD 3-Clause
- Language: C++17 (minimum CMake 3.9)
- Repo: https://github.com/MRPT/mvsim
mvsim/
├── modules/ # Core C++ library
│ ├── simulator/ # Main simulation engine (libmvsim)
│ ├── comms/ # ZMQ/Protobuf pub-sub communications layer
│ └── msgs/ # Protobuf message definitions (.proto files)
├── mvsim_node_src/ # ROS 2 node wrapper
├── mvsim-cli/ # Command-line tool (mvsim launch/topic/node/server)
├── mvsim-pid-tuner/ # GUI tool for tuning PID controllers
├── mvsim_tutorial/ # Demo world XML files + launch files + RViz configs
├── definitions/ # Reusable vehicle and sensor XML definitions
├── examples_cpp/ # C++ subscriber and service-caller examples
├── examples_python/ # Python API examples
├── docs/ # Sphinx + RST documentation
├── cmake/ # CMake helpers and version template
├── .clang-format # Code style (Google base, Allman braces, 4-space indent, tabs)
└── .clang-tidy # Linter config (bugprone-*, selected cppcoreguidelines-*)
The simulation engine. Headers live in modules/simulator/include/mvsim/.
| Class | Header | Role |
|---|---|---|
World |
World.h |
Central simulation container. Owns all vehicles, blocks, world elements, Box2D physics world, GUI window, ZMQ comms client. Split across World.cpp, World_gui.cpp, World_load_xml.cpp, World_services.cpp, World_simul.cpp, World_walls.cpp. |
Simulable |
Simulable.h |
Base interface for anything that steps through simulation time. Provides simul_pre_timestep(), simul_post_timestep(), pose access with shared mutex. |
VisualObject |
VisualObject.h |
Base interface for anything renderable in the OpenGL GUI. |
VehicleBase |
VehicleBase.h |
Abstract vehicle. Inherits VisualObject and Simulable. Holds wheels, sensors, friction model, controller, CSV logger. Created via ClassFactory. |
Block |
Block.h |
Static or dynamic rigid-body obstacle/object in the world. |
HumanActor |
HumanActor.h |
Pedestrian/human agent with motion model. |
Wheel |
Wheel.h |
Per-wheel physical state (torque, slip, contact). |
SensorBase |
Sensors/SensorBase.h |
Base class for all sensors. |
WorldElementBase |
WorldElements/WorldElementBase.h |
Base class for ground plane, grids, elevation maps, etc. |
ControllerBase |
ControllerBase.h |
Abstract controller interface. |
FrictionBase |
FrictionModels/FrictionBase.h |
Abstract friction model. |
ClassFactory |
ClassFactory.h |
Template factory that maps XML type strings to C++ constructors. |
TParameterDefinitions |
TParameterDefinitions.h |
Declares XML-readable parameters with DECLARE_PARAMETER_* macros. |
Shape2p5 |
Shape2p5.h |
2.5D shape (2D footprint + height interval). |
RemoteResourcesManager |
RemoteResourcesManager.h |
Downloads and caches remote assets (maps, meshes). |
CsvLogger |
CsvLogger.h |
Per-vehicle time-series logging to CSV. |
PID_Controller |
PID_Controller.h |
Generic discrete PID used by controllers. |
CollisionShapeCache |
CollisionShapeCache.h |
Caches Box2D collision shapes for mesh reuse. |
| File | Vehicle type |
|---|---|
VehicleDifferential.cpp |
Differential drive (TurtleBot, Jackal style) |
VehicleAckermann.cpp |
Ackermann (car-like) with kinematic/dynamic control |
VehicleAckermann_Drivetrain.cpp |
Ackermann + realistic mechanical differentials (open/Torsen, 2WD/4WD) |
Each vehicle type has companion *_Controller*.cpp files for its controllers (Raw torque, Twist PID, Ideal twist, Front-steer PID).
| File | Sensor |
|---|---|
LaserScanner.cpp |
2D LiDAR (generic + RPLidar A2) |
Lidar3D.cpp |
3D LiDAR (Velodyne VLP-16, Ouster OS1, Hesai Helios-32) |
CameraSensor.cpp |
RGB pinhole camera |
DepthCameraSensor.cpp |
RGBD depth + color camera |
IMU.cpp / ImuNoiseModel.cpp |
IMU with Forster 2016 noise model |
GNSS.cpp |
GPS/GNSS with configurable noise |
OccupancyGridMap, ElevationMap, HorizontalPlane, VerticalPlane, GroundGrid, PointCloud, SkyBox, PropertyRegion (friction zones).
Default Coulomb, Ward-Iagnemma (off-road), Ellipse (slip angle + slip ratio).
Provides a language-agnostic pub-sub and service-call layer using ZeroMQ + Protobuf.
Key headers in modules/comms/include/mvsim/Comms/:
Server.h— runs insideWorld, accepts registrations and forwards messages.Client.h— used by external processes (Python, C++ tools, ROS node) to connect.common.h,ports.h— shared constants and port numbers.
.proto files under modules/msgs/proto/. Key messages:
RegisterNodeRequest/Answer— node registration handshakeAdvertiseTopicRequest/SubscribeRequest— pub-sub setupCallService/GenericAnswer— RPCObservationLidar2D/GenericObservation— sensor dataPose/TimeStampedPose— pose dataSrvGetPose/SrvSetPose/SrvSetControllerTwist/SrvShutdown— services
mvsim_node_main.cpp— entry pointmvsim_node.cpp—MvSimNodeclass wrappingWorld, publishing sensor observations as ROS topics, subscribing tocmd_vel, advertising TF transforms and ROS 2 parameters.mvsim_node_src/include/— node header
mvsim binary with subcommands:
launch <world.xml>— start simulator with GUIserver— start headless servertopic list/echo/pub— inspect/inject ZMQ topicsnode list— list connected nodes
Worlds are XML files. Root element: <mvsim_world>. Key child elements:
<element class="...">— world elements (occupancy grids, elevation maps, planes)<vehicle class="..." name="...">— vehicle instances; XML parsed byVehicleBase::factory()<block class="..." name="...">— rigid blocks<actor class="..." name="...">— actors (e.g., humans)<include>— file inclusion for reuse<variable>/<for>— flow-control / parameterization<if>/<verbatim>— conditional blocks
Sensor and vehicle definitions can be split into reusable files under definitions/.
Ready-to-include vehicle and sensor snippets:
- Vehicles:
jackal.vehicle.xml,turtlebot3_burger.vehicle.xml,ackermann.vehicle.xml,small_robot.vehicle.xml,pickup.vehicle.xml,scania_truck.vehicle.xml,agricobiot2.vehicle.xml,jackal-ellipse.vehicle.xml - Sensors:
velodyne-vlp16.sensor.xml,ouster-os1.sensor.xml,helios-32-FOV-{26,31,70}.sensor.xml,rplidar-a2.sensor.xml,camera.sensor.xml,rgbd_camera.sensor.xml,imu.sensor.xml,gnss.sensor.xml
demo_warehouse.world.xml, demo_2robots.world.xml, demo_greenhouse.world.xml, demo_elevation_map.world.xml, demo_road_circuit1.world.xml, demo_multistorey.world.xml, demo_logistics_center.world.xml, demo_articulated_vehicle.world.xml, demo_friction_zones.world.xml, demo_camera.world.xml, demo_depth_camera.world.xml, demo_jackal.world.xml, demo_many_robots.world.xml, demo_indoor_outdoor.world.xml, demo_outdoor.world.xml, demo_walls.world.xml, demo_turtlebot_world.world.xml, mvsim_slam.world.xml.
Uses ZMQ/Protobuf Client. Examples: subscriber-example.py, mvsim-teleop.py, simple-obstacle-avoidance.py, move-object-example.py, call-shutdown.py, plot-log-files-4-wheels.py.
| Library | Role |
|---|---|
| MRPT | Math, poses, observations, OpenGL GUI (mrpt/gui, mrpt/obs, mrpt/poses, mrpt/opengl) |
| Box2D | 2D rigid-body physics engine |
| ZeroMQ (optional) | Pub-sub communications |
| Protobuf (optional) | Message serialization |
| pybind11 (optional) | Python bindings |
| ROS 2 (optional) | ROS node wrapper |
| rapidxml | XML parsing (header-only, bundled) |
- CMake 3.9+, C++17.
- Detects ROS 2 via
$ROS_VERSIONenv var; builds the ROS node and usesament_cmakewhen present. - Standalone build:
cmake .. && make. - ROS 2 build:
colcon build. - Version is read from
package.xmland injected intomodules/simulator/include/mvsim/mvsim_version.hat configure time. cmake/mvsim_cmake_functions.cmakecontains helpers used across targets.- Optional features guarded by
MVSIM_HAS_ZMQandMVSIM_HAS_PROTOBUFcompile-time defines.
- clang-format: Google base style, Allman brace wrapping, 4-space indent width, tabs for indentation, column limit 100,
SortIncludes: true. Run viaformatter.shor.circleci/clang_format_codebase.sh. - clang-tidy:
bugprone-*, selectedcppcoreguidelines-*,readability-braces-around-statements,readability-else-after-return. Configured in.clang-tidy. - Always use braces for all control-flow statements (
if,else,for,while,do), even single-statement bodies. No brace-less single-line statements. This is enforced byreadability-braces-around-statementsin.clang-tidy. - CI enforces clang-format via the
check-clang-formatGitHub Actions workflow. - No trailing comments alignment (disabled in
.clang-format). - All new C++ code must pass both clang-format and clang-tidy without warnings.
- All simulator code lives in the
mvsimnamespace. - Protobuf messages are in the
mvsim_msgsnamespace. - Smart pointer alias
Ptr = std::shared_ptr<T>defined in every major class. - Factory-registered classes use
MVSIM_REGISTER_*macros. - XML-readable parameters declared with
DECLARE_PARAMETER_*macros fromTParameterDefinitions.h. - File naming:
CamelCase.h/CamelCase.cppfor classes;lowercase-hyphenated.cppfor CLI tool files. - Header guard style:
#pragma once.