ROS 2 API

This page reflects the topics and services that a MOLA system will expose when running a SLAM or LiDAR-odometry module. At present, this applies to:

https://mrpt.github.io/imgs/mola-lo-ros2-launch-demo-kitti.png


1. Nodes and launch files

1.1. ROS 2 node for Lidar Odometry (LO)

Note

It is recommended to start with the tutorial on how to build a map.

This launch file (view sources) runs MOLA-LO live on point clouds received from a ROS 2 topic, demonstrating a few features:

  • Launching and visualizing LO in both, mola_viz and RViz2 (or use FoxGlove if preferred).

  • How MOLA mola_lidar_odometry publishes the local map, the estimated trajectory, and /tf for the estimated odometry.

https://mrpt.github.io/imgs/mola-lo-ros2-launch-demo-live-forest.png
# Minimal use case (requires correct LiDAR sensor /tf):
ros2 launch mola_lidar_odometry ros2-lidar-odometry.launch.py \
   lidar_topic_name:=ouster/points

# Usage without sensor /tf:
ros2 launch mola_lidar_odometry ros2-lidar-odometry.launch.py \
   lidar_topic_name:=ouster/points \
   ignore_lidar_pose_from_tf:=True \
   publish_localization_following_rep105:=False

If your robot uses a ROS 2 namespace ROBOT_NS for all its sensor and tf topics, use:

# Minimal use case:
ros2 launch mola_lidar_odometry ros2-lidar-odometry.launch.py \
   lidar_topic_name:=ouster/points \
   use_namespace:=True \
   namespace:=ROBOT_NS

All launch arguments
$ ros2 launch mola_lidar_odometry ros2-lidar-odometry.launch.py --show-args
Arguments (pass arguments as '<name>:=<value>'):

  'namespace':
     Top-level namespace
     (default: '')

  'use_namespace':
     Whether to apply a namespace to the navigation stack
     (default: 'false')

  'lidar_topic_name':
     Topic name to listen for PointCloud2 input from the LiDAR (for example '/ouster/points')

  'ignore_lidar_pose_from_tf':
     If true, the LiDAR pose will be assumed to be at the origin (base_link). Set to false (default) if you want to read the actual sensor pose from /tf
     (default: 'false')

  'gnss_topic_name':
     Topic name to listen for NavSatFix input from a GNSS (for example '/gps')
     (default: 'gps')

  'imu_topic_name':
     Topic name to listen for Imu input (for example '/imu')
     (default: 'imu')

  'use_mola_gui':
     Whether to open MolaViz GUI interface for watching live mapping and control UI
     (default: 'True')

  'publish_localization_following_rep105':
     Whether to publish localization TFs in between map->odom (true) or directly map->base_link (false)
     (default: 'True')

  'start_mapping_enabled':
     Whether MOLA-LO should start with map update enabled (true), or in localization-only mode (false)
     (default: 'True')

  'start_active':
     Whether MOLA-LO should start active, that is, processing incoming sensor data (true), or ignoring them (false)
     (default: 'True')

  'mola_lo_reference_frame':
     The /tf frame name to be used for MOLA-LO localization updates
     (default: 'map')

  'mola_lo_pipeline':
     The LiDAR-Odometry pipeline configuration YAML file defining the LO system. Absolute path, or relative to 'mola-cli-launchs/lidar_odometry_ros2.yaml'. Default is the 'lidar3d-default.yaml' system described in the IJRR 2025 paper.
     (default: '../pipelines/lidar3d-default.yaml')

  'generate_simplemap':
     Whether to create a '.simplemap', useful for map post-processing. Refer to online tutorials.
     (default: 'False')

  'mola_initial_map_mm_file':
     Can be used to provide a metric map '.mm' file to be loaded as initial map. Refer to online tutorials.
     (default: '""')

  'mola_initial_map_sm_file':
     Can be used to provide a keyframes map '.simplemap' file to be loaded as initial map. Refer to online tutorials.
     (default: '""')

  'mola_footprint_to_base_link_tf':
     Can be used to define a custom transformation between base_footprint and base_link. The coordinates are [x, y, z, yaw_deg, pitch_deg, roll_deg].
     (default: '[0, 0, 0, 0, 0, 0]')

  'enforce_planar_motion':
     Whether to enforce z, pitch, and roll to be zero.
     (default: 'False')

  'forward_ros_tf_odom_to_mola':
     Whether to import an existing /tf 'odom'->'base_link' odometry into the MOLA subsystem.
     (default: 'False')

  'initial_localization_method':
     What method to use for initialization.  See https://docs.mola-slam.org/latest/ros2api.html#initial-localization
     (default: 'InitLocalization::FixedPose')

  'use_state_estimator':
     If false, the basic state estimator 'mola::state_estimation_simple::StateEstimationSimple' will be used. If true, 'mola::state_estimation_smoother::StateEstimationSmoother' is used instead.
     (default: 'False')

  'state_estimator_config_yaml':
     A YAML file with settings for the state estimator. Absolute path or relative to 'mola-cli-launchs/lidar_odometry_ros2.yaml'
     (default: PythonExpr(''../state-estimator-params/state-estimation-smoother.yaml' if ' + LaunchConfig('use_state_estimator') + ' else '../state-estimator-params/state-estimation-simple.yaml''))

  'mola_state_estimator_reference_frame':
     The /tf frame name to be used as reference for MOLA State Estimators to publish pose updates
     (default: 'map')

  'use_rviz':
     Whether to launch RViz2 with default lidar-odometry.rviz configuration
     (default: 'True')
Configure sensor inputs for ROS 2 node and rosbag2 input

The following environment variables can be set to change the behavior of how BridgeROS2 handles input ROS 2 messages on sensor inputs. Please, refer to the actual mola-cli launch files where these variables are defined:

Environment variables:

  • MOLA_TF_BASE_LINK (Default: "base_link"): The robot reference frame id in /tf. Used to get sensor poses with respect to the vehicle.

  • MOLA_TF_FOOTPRINT_LINK (Default: base_footprint): If not empty, the node will broadcast a static /tf from base_footprint to base_link with the TF base_footprint_to_base_link_tf at start up.

  • MOLA_TF_FOOTPRINT_TO_BASE_LINK (Default: '[0, 0, 0, 0, 0, 0]'): [x, y, z, yaw_deg, pitch_deg, roll_deg].

  • MOLA_LIDAR_TOPIC (Default: '/ouster/points'): The sensor_msgs/PointCloud2 topic with raw LiDAR data (mandatory).

  • MOLA_USE_FIXED_LIDAR_POSE (Default: false): If false, sensor pose will be retrieved from /tf. You can also set it to true and then the sensor pose will be given by these env. variables:

    • LIDAR_POSE_X, LIDAR_POSE_Y, LIDAR_POSE_Z (in meters).

    • LIDAR_POSE_YAW, LIDAR_POSE_PITCH, LIDAR_POSE_ROLL (in degrees).

  • MOLA_GNSS_TOPIC (Default: '/gps'): The sensor_msgs/NavSatFix topic with GNSS data (optional).

  • MOLA_USE_FIXED_GNSS_POSE (Default: true): If false, sensor pose will be retrieved from /tf. You can also set it to true and then the sensor pose will be given by these env. variables:

    • GNSS_POSE_X, GNSS_POSE_Y, GNSS_POSE_Z (in meters).

    • GNSS_POSE_YAW, GNSS_POSE_PITCH, GNSS_POSE_ROLL (in degrees).

  • MOLA_IMU_TOPIC (Default: '/imu'): The sensor_msgs/Imu topic with IMU data (optional).

  • MOLA_USE_FIXED_IMU_POSE (Default: true): If false, sensor pose will be retrieved from /tf. You can also set it to true and then the sensor pose will be given by these env. variables:

    • IMU_POSE_X, IMU_POSE_Y, IMU_POSE_Z (in meters).

    • IMU_POSE_YAW, IMU_POSE_PITCH, IMU_POSE_ROLL (in degrees).

More LO parameters

The lidar3d-default.yaml pipeline file defines plenty of additional parameters and options that you can explore. See also the docs for the ROS 2 API and this tutorial on how to save and load a map using ROS 2 MOLA-LO nodes.



2. Map loading / saving

During a live SLAM run, BridgeROS2 will look for modules implementing MapServer and will expose these ROS 2 services to load or save the current map:

Example ROS 2 cli service calls

To save the current map:

ros2 service call /map_save mola_msgs/srv/MapSave "map_path: '/tmp/my_map_file_prefix'"

To load a map from disk:

ros2 service call /map_load mola_msgs/srv/MapLoad "map_path: '/tmp/my_map_file_prefix'"

Note that filename extension should not be given, since each service implementation may add a different extension, or even save several files that should all, together, be later on loaded as one to load the map again.

Alternatively, you can enable saving the map when mapping is ended by checking the corresponding checkbox in the MOLA-LO GUI (block “6” below):

imgs/gui_parts.png


3. Re-localization

There are two ROS services that can be used to enforce the MOLA subsystem to relocalize, for example, to address the problem of initial localization:

3.1. Specify the new localization and its initial uncertainty

The service /relocalize_near_pose (mola_msgs/srv/RelocalizeNearPose) can be used to directly request a relocalization in a given area (a pose with uncertainty):

ros2 service call /relocalize_near_pose mola_msgs/srv/RelocalizeNearPose "{
pose: {
   header: {
      stamp: {sec: 0, nanosec: 0},
      frame_id: 'map'
   },
   pose: {
      pose: {
      position: {x: 1.0, y: 2.0, z: 0.0},
      orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}
      },
      covariance: [1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                  0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
                  0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
                  0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
                  0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
                  0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
   }
}
}"

3.2. Request automatic relocalization from GNSS (GPS)

In geo-referenced maps, it is possible to request MOLA-LO to use incoming GPS readings to bootstrap LiDAR-based localization.

Note

This method requires the use of the smoother state estimator.

Request a relocalization now with:

ros2 service call /relocalize_from_state_estimator  mola_msgs/srv/RelocalizeFromStateEstimator "{}"

Depending on the parameters, it may take some time for the re-localization to take effect.



4. Published /tf frames

The frames of reference (`frame_id`s) at work when using MOLA depend on your system configuration:

  • Using just mola_lidar_odometry: Two situations here depending on the ROS launch argument publish_localization_following_rep105:

      1. Strictly following ROS REP-105 in systems with wheels (encoders-based) high-frequency odometry, or

      1. Not following REP-105 (e.g. if you do not have wheels odometry).

    1. Using state estimation data fusion (this case does not follow REP-105), and

And orthogonal to both above, whether the map is geo-referenced or not.

The diagrams below show the cases of following or not following ROS REP-105 for the different situations listed above:

For cases with ground robots with wheel-based odometry:

https://mrpt.github.io/imgs/mola_mrpt_ros_geo_referenced_utm_frames.png

This is who is responsible of publishing each transformation:

  • odom base_link: Wheel odometry module. High-frequency, relatively accurate in the short term, but drifts in the long term.

  • map odom: Localization module, which corrects the odometry drift.

  • enu {map, utm}: Published by mrpt_map_server (github) or mola_lidar_odometry map loading service if fed with a geo-referenced metric map (.mm) file.

When using just a LiDAR as single sensor.

https://mrpt.github.io/imgs/mola_mrpt_ros_frames_no_rep105.png

This is who is responsible of publishing each transformation:

  • map base_link: Localization module.

  • enu {map, utm}: Published by mrpt_map_server (github) or mola_lidar_odometry map loading service if fed with a geo-referenced metric map (.mm) file.

When using state estimation data fusion: applicable if having just one LiDAR sensor, or LiDAR + wheel odometry, or several odometry sources, optionally GNNS (GPS) and IMU, etc.

https://mrpt.github.io/imgs/mola_mrpt_ros_frames_fusion.png

This is who is responsible of publishing each transformation:

  • odom_{i} base_link: One or more odometry sources.

  • map base_link: Published by state estimation data fusion.

  • enu {map, utm}: Published by mrpt_map_server (github) or mola_lidar_odometry map loading service if fed with a geo-referenced metric map (.mm) file.

Note

For non geo-referenced maps, all frames remain the same but utm and enu will not exist.

Definition of the frames above:

  • base_link: The robot reference frame. For ground vehicles, normally placed at the center of the rear axle.

  • base_footprint (optional): The projection of base_link on the ground plane. In MOLA, this frame is published by BridgeROS2 as a child of base_link.

  • odom, odom_1,… odom_n: The arbitrary origin for odometry measurements. There may be different odometry sources: wheels, LiDAR odometry, visual odometry, etc.

  • map: The origin of the reference metric map used for localization.

  • enu: For geo-referenced maps, the North (y axis), East (x axis), Up (z axis) frame for which we have reference geodetic coordinates (latitude and longitude). Different maps built in the same zone will surely have different enu frames, since it is defined by collected GNSS measurements.

  • utm: The origin of the UTM zone in which enu falls. Unlike enu, it is independent of the trajectory followed while building the map.




5. Published topics

Write me!




6. Map publishing

There are three ways of publishing maps to ROS:

  1. Using mrpt_map_server (github): the recommended way for static, previously-built maps, if you are not using MOLA for localization but want the map published for localization using the particle filter method or for your own purposes, e.g. for visualization in RViz, processing in a custom node, etc. In this case, one ROS topic will be published for each map layer, as described in the package documentation. See also this tutorial.

  2. During a live map building process (e.g. MOLA-LO).

Topics

Using the default MOLA LiDAR odometry pipeline, only one map topic will be generated during live mapping:

  • Name: /lidar_odometry/localmap_points

  • Type: sensor_msgs/PointCloud2

  1. If using MOLA-LO for localization-only, it will send out the loaded map. In this case, there will be as many topics as map layers in the *.mm file. See also this tutorial.

In cases (2)-(3), BridgeROS2 will look for modules implementing MapSourceBase and will publish one topic named <METHOD>/<LAYER_NAME> for each map layer. The metric map layer C++ class will determine the ROS topic type to use. Map topics are “latched” (so that new subscribers will receive the last published map immediately after subscribing), and will be re-published only if mapping is enabled and the map has changed since the last publication.




7. Runtime dynamic reconfiguration

MOLA modules may expose a subset of their parameters through an interface that allows runtime reconfiguration via ROS 2 service requests:

7.1. Runtime parameters for mola_lidar_odometry

List all existing parameters:

ros2 service call /mola_runtime_param_get mola_msgs/srv/MolaRuntimeParamGet
Example output
requester: making request: mola_msgs.srv.MolaRuntimeParamGet_Request()

response:
mola_msgs.srv.MolaRuntimeParamGet_Response(parameters='mola::LidarOdometry:lidar_odom:\n  active: true\n  generate_simplemap: false\n  mapping_enabled: true\n')

Returned parameters as YAML:

mola::LidarOdometry:lidar_odom:
  active: true
  generate_simplemap: false
  mapping_enabled: true

Documented parameters:

  • active: Whether MOLA-LO should process incoming sensor data (active: true) or ignore them (active: false).

Copy & paste commands for active
# active: true
ros2 service call /mola_runtime_param_set mola_msgs/srv/MolaRuntimeParamSet \
   "{parameters: \"mola::LidarOdometry:lidar_odom:\n  active: true\n\"}"
# active: false
ros2 service call /mola_runtime_param_set mola_msgs/srv/MolaRuntimeParamSet \
   "{parameters: \"mola::LidarOdometry:lidar_odom:\n  active: false\n\"}"
  • mapping_enabled: Whether MOLA-LO should update the localmap (true) or just use it in localization-only mode (false).

Copy & paste commands for mapping_enabled
# mapping_enabled: true
ros2 service call /mola_runtime_param_set mola_msgs/srv/MolaRuntimeParamSet \
   "{parameters: \"mola::LidarOdometry:lidar_odom:\n  mapping_enabled: true\n\"}"
# mapping_enabled: false
ros2 service call /mola_runtime_param_set mola_msgs/srv/MolaRuntimeParamSet \
   "{parameters: \"mola::LidarOdometry:lidar_odom:\n  mapping_enabled: false\n\"}"
  • generate_simplemap: Whether MOLA-LO should build the keyframes-based map (apart of the local metric map), so you end up with a *.simplemap file.

Copy & paste commands for generate_simplemap
# generate_simplemap: true
ros2 service call /mola_runtime_param_set mola_msgs/srv/MolaRuntimeParamSet \
   "{parameters: \"mola::LidarOdometry:lidar_odom:\n  generate_simplemap: true\n\"}"
# generate_simplemap: false
ros2 service call /mola_runtime_param_set mola_msgs/srv/MolaRuntimeParamSet \
   "{parameters: \"mola::LidarOdometry:lidar_odom:\n  generate_simplemap: false\n\"}"
  • reset_state: This is actually not a real state variable, but a trigger to request MOLA-LO to reset its state, effectively restarting mapping from scratch. It resets the internal local map, the simplemap (keyframe map). The state estimator, since it is in a different independent module, is not affected.

Copy & paste commands to reset map
ros2 service call /mola_runtime_param_set mola_msgs/srv/MolaRuntimeParamSet \
   "{parameters: \"mola::LidarOdometry:lidar_odom:\n  reset_state: true\n\"}"

8. Initial localization

8.1. Lidar-Odometry (LO)

When the LO system is started, there are different situations:

  1. The system is started without any former map. Here, the default is starting at the identity SE(3) pose, that is, at the origin (0,0,0), and that should be enough in most common cases.

  2. The system is started with a former known map. Here, correctly localizing within that map before trying to update it is critical to avoid ruining the map. Also, finding the correct initial pose is a non trivial problem and requires specific methods.

For the latter case, it is important to disable mapping at start up (see the start_mapping_enabled:=False launch argument above) and only enable mapping once the system is correctly localized, and if the user really wants to update the map. Keeping mapping disabled for the whole run is actually desired for robots operating in a known, pre-mapped environment.

Then, the user can choose between:

  • Requesting re-localization in a given area or from GNSS readings, as described in this section above.

  • Selecting one of the available initial localization methods directly set in the pipeline configuration file, or via a ROS2 launch argument, so that method is used straight away at startup.

These are the available initial localization methods, that can be used in the launch argument initial_localization_method:=xxxx launch argument (listed above):

How to select initial localization without ROS API

If LO is launched independently of a ROS2 system, e.g. using the command-line or GUI LO tools, the initial localization method can be set via the environment variable MOLA_LO_INITIAL_LOCALIZATION_METHOD which should be set to any of the options listed below. For example, to set the initial localization method to FromStateEstimator:

MOLA_LO_INITIAL_LOCALIZATION_METHOD="InitLocalization::FromStateEstimator" \
mola_lidar_odometry_cli ... \ # the rest as usual
  • InitLocalization::FixedPose: Initializes around a given SE(3) pose with covariance.

  • InitLocalization::FromStateEstimator: In combination with the smoother state estimator, can be used to initialize based on accumulated evidence of geo-referenced positioning based on low-cost GNSS readings, wheels odometry, IMU, or any sensible combination of sensors. See smoother state estimator.

  • InitLocalization::PitchAndRollFromIMU: Without using the external state estimator, this method uses the IMU to estimate the pitch and roll angles of the robot, and then initializes the localization system with that information assuming sensor is roughly stationary at startup. This is useful for systems that are not perfectly level, such as hand-held devices, drones, etc. since it will remove the apparent tilt of the ground plane.