SLAM system YAML configuration file format
Refer to demos for real examples to launch and run SLAM systems.
File structure
A SLAM system is defined via a YAML configuration file, comprising a top-level
modules entry, with one or more children elements with the following
required fields:
# my-slam-system.yml
modules:
- type: CLASS_NAME1 # mandatory
name: INSTANCE_NAME1 # mandatory
execution_rate: 20 # Hz (optional)
verbosity_level: INFO # DEBUG|INFO|WARN|ERROR
params: # Other module-specific parameters
var1: value1
var2: value2
# ...
- type: CLASS_NAME2
name: INSTANCE_NAME2
# ...
Notes:
CLASS_NAME1: The C++ class name of one of the modules registered in the MOLA system.INSTANCE_NAME1: Arbitrary name of this instance of the module. All names must be unique in a SLAM system.
YAML pre-processing
Before being parsed as standard YAML, every configuration file loaded by MOLA
is run through a lightweight pre-processor that expands special $-prefixed
expressions. The three expansion passes are always applied in the following
fixed order:
Include other files: $include{path} —
$include{path}Run an external command: $(command) —
$(command)Variables and environment: ${VAR} / ${VAR|default} —
${VAR}/${VAR|default}
This ordering means that:
$include{}can pull in files whose paths are themselves built with$()or${}tokens.$()command output can reference environment variables already present in the environment at parse time.${}variable expansion sees the fully assembled text — including the content of all included files — and can therefore reference variables that are defined in those files.
Comments are never expanded. Any $include{}, $(), or ${}
token that appears after a # comment marker on the same line is left
completely unchanged. This applies to both inline comments and full-line
comments:
v: 1 # $(echo this-is-never-run) ${ALSO_NEVER_EXPANDED}
# ${THIS_IS_ALSO_SAFE}
Include other files: $include{path}
A YAML scalar whose value matches the pattern $include{/path/to/file.yaml}
is replaced by the full contents of the referenced file.
Paths may be absolute or relative. A relative path is resolved against the directory of the file that contains the
$include{}directive. Includes within the included file are in turn resolved relative to that file’s own directory, so any depth of nesting works correctly.The path expression inside
$include{}is itself pre-processed by the$()and${}passes before the file is opened, so the path may be constructed dynamically.Circular includes are detected. If a file attempts to include itself (directly or transitively), a clear error is raised rather than looping indefinitely.
modules:
- type: CLASS_NAME1
params:
# Include a file whose path is built from an environment variable:
$include{${MY_CONFIG_DIR}/sensor_params.yaml}
config:
# Include a file relative to this file's own directory:
$include{params/lidar_odometry.yaml}
# Include a file whose path comes from a shell command
# (e.g. a ROS 2 package share directory):
$include{$(ros2 pkg prefix mola_lidar_odometry)/share/mola_lidar_odometry/config/lo_default.yaml}
Note
The $include{} directive replaces the entire scalar node it appears
in. The typical usage is therefore as the sole value of a map key (params:,
config:, etc.), where the included file provides the child map:
params:
$include{my_params.yaml} # ← my_params.yaml contributes all keys here
Run an external command: $(command)
The pattern $(command arg1 arg2 ...) is replaced by the standard output
of the command, with leading and trailing whitespace stripped. Multi-line
output is preserved; only the boundary whitespace is removed.
A non-zero exit code causes a fatal error.
This is most commonly used together with $include{} to locate files inside
a ROS 2 package:
params:
$include{$(ros2 pkg prefix my_package)/share/my_package/config/default.yaml}
It can also set scalar values directly:
hostname: $(hostname)
git_sha: $(git -C ${MY_SRC_DIR} rev-parse --short HEAD)
Warning
Shell commands are executed at parse time, with the same privileges as
the process loading the YAML file. Only use $() with commands whose
output you trust.
Variables and environment: ${VAR} / ${VAR|default}
The pattern ${NAME} is replaced by a value looked up in the following
order (first match wins):
Environment variable — the current value of
getenv("NAME").Built-in token
CURRENT_YAML_FILE_PATH— expands to the directory of the file currently being parsed (or the value ofYAMLParseOptions::includesBasePathwhen called programmatically).Caller-supplied variables — entries in the
YAMLParseOptions::variablesmap, which allows C++ code to inject arbitrary name/value pairs at load time.Inline default — if the token has the form
${NAME|default_value}, the literal text after|is used as a fallback. The default may be empty (${NAME|}resolves to an empty string).Error — if none of the above matched, a fatal error is raised.
# Expand an environment variable (fatal if MY_ROBOT is unset):
robot_name: ${MY_ROBOT}
# Use a default value when the variable is not set:
log_dir: ${LOG_DIR|/tmp/mola_logs}
# Empty-string default — never raises an error:
optional_suffix: ${SUFFIX|}
# Refer to the directory of this file (useful for sibling-relative paths):
calibration_file: ${CURRENT_YAML_FILE_PATH}/calib/lidar.yaml
# The same variable may appear multiple times in one scalar:
topic: /${ROBOT_NS}/sensors/${SENSOR_NAME}/points
Note
Substituted values are not re-expanded. If an environment variable
itself contains a ${...} or $(...) token, that token is emitted
verbatim and not processed a second time. This prevents accidental
double-expansion and avoids infinite loops.
Tip
You can combine all three mechanisms. For example, the following snippet locates a calibration file in a ROS 2 package, using an environment variable to choose the robot variant, with a safe default:
calibration:
$include{$(ros2 pkg prefix my_robot_config)/share/my_robot_config/calib/${ROBOT_VARIANT|default}/lidar.yaml}
Mathematical formulas: $f{expr}
The pattern $f{expr} evaluates a mathematical expression using the
ExprTk library (via
mrpt-expr).
Refer to the ExprTk documentation for the full list of built-in functions and
operators. User-defined variables may be available depending on the context in
which the YAML file is parsed.
half_fov_rad: $f{deg2rad(45.0)}
diagonal: $f{sqrt(3.0^2 + 4.0^2)}
Processing order summary
The table below summarises which pass handles each token, and what happens when a token falls inside a comment:
Token |
Replaced with |
Pass |
In a |
|---|---|---|---|
|
Contents of |
1st |
Left verbatim |
|
stdout of |
2nd |
Left verbatim (command not run) |
|
Value of |
3rd |
Left verbatim |
|
Value of |
3rd |
Left verbatim |
|
Result of mathematical expression |
Context-dependent |
Left verbatim |
Debugging pre-processing
Set the environment variable VERBOSE=1 before launching any MOLA
executable to print each $include{} directive as it is resolved:
VERBOSE=1 ros2 launch my_slam_system slam.launch.py
Each include prints a line of the form:
[mola::parse_yaml] $include{ "/absolute/path/to/file.yaml" }
[mola::parse_yaml] $include done: "/absolute/path/to/file.yaml"