Parameters

The supported bring-up uses two YAML files:

  1. Core parameters (map resolution/size, kernels, services, toggles)

  2. A robot/setup file (subscribers + publishers)

Core Parameters

/elevation_mapping_node:
  ros__parameters:
    #### Basic parameters ########
    drift_compensation_variance_inlier: 0.1
    checker_layer: 'elevation'                # layer name for checking the validity of the cell.
    initialized_variance: 10.0                     # initial variance for each cell.    
    resolution: 0.1                                # resolution in m.  
    map_length: 20.0                                 # map's size in m.
    sensor_noise_factor: 0.05                       # point noise ~ sensor_noise_factor * range^2 in the sensor frame (range^2 = x^2+y^2+z^2).
    mahalanobis_thresh: 2.0                         # points outside this distance is outlier.
    outlier_variance: 0.01                          # if point is outlier, add this value to the cell.
    max_drift: 0.1                                  # drift compensation happens only the drift is smaller than this value (for safety)
    drift_compensation_alpha: 0.1                   # drift compensation alpha for smoother update of drift compensation
    time_variance: 0.0001                           # add this value when update_variance is called.
    max_variance: 100.0                             # maximum variance for each cell.
    initial_variance: 1000.0                        # initial variance for each cell.
    traversability_inlier: 0.9                      # cells with higher traversability are used for drift compensation.
    dilation_size: 3                                # dilation filter size before traversability filter.
    wall_num_thresh: 20                             # if there are more points than this value, only higher points than the current height are used to make the wall more sharp.
    min_height_drift_cnt: 100                       # drift compensation only happens if the valid cells are more than this number.
    position_noise_thresh: 0.01                     # if the position change is bigger than this value, the drift compensation happens.
    orientation_noise_thresh: 0.01                  # if the orientation change is bigger than this value, the drift compensation happens.
    position_lowpass_alpha: 0.2                     # lowpass filter alpha used for detecting movements.
    orientation_lowpass_alpha: 0.2                  # lowpass filter alpha used for detecting movements.
    min_valid_distance: 0.1                         # points with shorter distance will be filtered out.
    max_height_range: 10.5                          # points higher than this value from sensor will be filtered out to disable ceiling.
    ramped_height_range_a: 0.3                      # if z > max(d - ramped_height_range_b, 0) * ramped_height_range_a + ramped_height_range_c, reject.
    ramped_height_range_b: 1.0                      # if z > max(d - ramped_height_range_b, 0) * ramped_height_range_a + ramped_height_range_c, reject.
    ramped_height_range_c: 0.2                      # if z > max(d - ramped_height_range_b, 0) * ramped_height_range_a + ramped_height_range_c, reject.
    update_variance_fps: 5.0                        # fps for updating variance.
    update_pose_fps: 10.0                           # fps for updating pose and shift the center of map.
    time_interval: 0.1                              # Time layer is updated with this interval.
    map_acquire_fps: 5.0                            # Raw map is fetched from GPU memory in this fps.
    publish_statistics_fps: 1.0                     # Publish statistics topic in this fps.
    recordable_fps: 3.0                           # Recordable fps for pointcloud.
    enable_normal_arrow_publishing: false

    masked_replace_service_mask_layer_name: 'mask'
    save_map_default_topic: 'elevation_map'
    save_map_storage_id: 'mcap'
    service_namespace: '/elevation_mapping_cupy'

    max_ray_length: 10.0                            # maximum length for ray tracing.
    cleanup_step: 0.1                               # subtitute this value from validity layer at visibiltiy cleanup.
    cleanup_cos_thresh: 0.1                         # subtitute this value from validity layer at visibiltiy cleanup.

    safe_thresh: 0.7                                # if traversability is smaller, it is counted as unsafe cell.
    safe_min_thresh: 0.4                            # polygon is unsafe if there exists lower traversability than this.
    max_unsafe_n: 10                                # if the number of cells under safe_thresh exceeds this value, polygon is unsafe.

    overlap_clear_range_xy: 4.0                     # xy range [m] for clearing overlapped area. this defines the valid area for overlap clearance. (used for multi floor setting)
    overlap_clear_range_z: 2.0                      # z range [m] for clearing overlapped area. cells outside this range will be cleared. (used for multi floor setting)
    
    # Default frame configuration (can be overridden in robot-specific configs)
    map_frame: 'odom'                               # The map frame where the odometry source uses.
    base_frame: 'base_link'                    # The robot's base frame. This frame will be a center of the map.
    corrected_map_frame: 'odom'

    #### Feature toggles ########
    enable_edge_sharpen: true
    enable_visibility_cleanup: true
    enable_drift_compensation: true
    enable_overlap_clearance: true
    enable_pointcloud_publishing: false
    enable_drift_corrected_TF_publishing: false
    #### Traversability filter ########
    use_chainer: false                              # If false, uses the PyTorch backend (GPU).

    #### Upper bound ########
    use_only_above_for_upper_bound: false

    #### Initializer ########
    initialize_method: 'linear'                                         # Choose one from 'nearest', 'linear', 'cubic'
    initialize_frame_id: ['base_link']   # One tf (like ['footprint'] ) initializes a square around it.
    initialize_tf_offset: [0.0]                                         # Optional z-offset(s) for initializer (same length as initialize_frame_id).
    dilation_size_initialize: 2                                         # dilation size after the init.
    initialize_tf_grid_size: 1.0                                        # This is not used if number of tf is more than 3.
    use_initializer_at_start: true                                      # Use initializer when the node starts.

    #### Default Plugins ########
    # plugin_config_file is resolved internally (package share) by the node.

Golden-Path Setup (Synthetic Demo)

/elevation_mapping_node:
  ros__parameters:
    # Frames (must match the synthetic publisher)
    map_frame: "map"
    base_frame: "base_link"
    corrected_map_frame: "map"

    # One deterministic pointcloud input (no image/semantic fusion in the supported surface).
    subscribers:
      depth:
        topic_name: "/camera/depth/points"
        data_type: "pointcloud"

    # Single output topic for RViz + tests.
    publishers:
      elevation_map:
        layers: ["elevation", "variance", "traversability"]
        basic_layers: ["elevation"]
        fps: 10.0

Example Robot Setup (Menzi)

/elevation_mapping_node:
  ros__parameters:
    subscribers:
      front_cam:
        topic_name: '/ouster_points_self_filtered'
        data_type: pointcloud

    publishers:
      elevation_map_raw:
        layers: ['elevation', 'traversability', 'variance']
        basic_layers: ['elevation']
        fps: 5.0
      elevation_map_filter:
        layers: ['min_filter', 'smooth', 'near_base_filtered', 'despiked', 'inpaint', 'elevation']
        basic_layers: ['min_filter', 'smooth', 'near_base_filtered', 'despiked', 'inpaint']
        fps: 3.0

Plugin Configuration

# min_filter fills in minimum value around the invalid cell.
min_filter:                                   
  enable: True                                # weather to load this plugin
  fill_nan: False                             # Fill nans to invalid cells of elevation layer.
  is_height_layer: True                       # If this is a height layer (such as elevation) or not (such as traversability)
  layer_name: "min_filter"                    # The layer name.
  extra_params:                               # This params are passed to the plugin class on initialization.
    dilation_size: 1                         # The patch size to apply
    iteration_n: 30                           # The number of iterations
# Apply smoothing.
smooth_filter:
  enable: True
  fill_nan: False
  is_height_layer: True
  layer_name: "smooth"
  extra_params:
    input_layer_name: "min_filter"
# Reject close-range above-base returns before despiking. This is meant for
# BASE-centered digging maps where weather/dust can create floating points that
# block later ground observations.
near_base_height_filter:
  enable: True
  fill_nan: False
  is_height_layer: True
  layer_name: "near_base_filtered"
  extra_params:
    input_layer_name: "elevation"
    radius_m: 4.0
    max_allowed_height_m: 0.5
# Remove isolated positive spikes before inpainting. This is intentionally
# asymmetric: upward one/few-cell towers are clipped, trench drops are kept.
positive_spike_filter:
  enable: True
  fill_nan: False
  is_height_layer: True
  layer_name: "despiked_coarse"
  extra_params:
    input_layer_name: "near_base_filtered"
    median_filter_size: 5
    spike_height_diff_m: 0.35
    support_height_tolerance_m: 0.12
    max_support_neighbor_count: 1
    max_component_cells: 4
# A second narrower cleanup pass catches the smaller shovel-local residual bumps
# that survive the coarse tower filter while still preserving supported walls.
positive_spike_filter_cleanup:
  type: "positive_spike_filter"
  enable: True
  fill_nan: False
  is_height_layer: True
  layer_name: "despiked"
  extra_params:
    input_layer_name: "despiked_coarse"
    median_filter_size: 3
    spike_height_diff_m: 0.08
    support_height_tolerance_m: 0.02
    max_support_neighbor_count: 1
    max_component_cells: 2
    edge_invalid_neighbor_count_min: 3
    edge_peak_diff_m: 0.12
    edge_similarity_tolerance_m: 0.05
    edge_max_similar_neighbor_count: 1
# Inpaint the cleaned surface so downstream digging keeps hole filling without
# reintroducing the rejected spikes.
inpainting:
  enable: True
  fill_nan: False
  is_height_layer: True
  layer_name: "inpaint"
  extra_params:
    method: "telea"                           # telea or ns
    input_layer_name: "despiked"
    max_hole_area: 25                         # 5x5 cells at 0.1m resolution
    fill_border_holes: False                  # boundary-connected invalid regions stay unknown
erosion:
  enable: True
  fill_nan: False
  is_height_layer: False
  layer_name: "erosion"
  extra_params:
    input_layer_name: "traversability"
    dilation_size: 3
    iteration_n: 20
    reverse: True