cartographer/mapping/submaps.h

Overview

Submap classes represent local map regions as probabilistic grids. They are the fundamental building blocks of Cartographer’s mapping system. Separate implementations exist for 2D and 3D.

Class Hierarchy

Submap (abstract)
├── Submap2D
│   ├── ProbabilityGrid (grid_2d.h)
│   └── TSDF (tsdf_2d.h)  -- alternative representation
└── Submap3D
    └── HybridGrid (3d/hybrid_grid.h)

Class: cartographer::mapping::Submap

Interface

class Submap {
 public:
  explicit Submap(const transform::Rigid3d& local_pose);
  virtual ~Submap() {}

  const transform::Rigid3d& local_pose() const { return local_pose_; }
  int num_range_data() const { return num_range_data_; }
  bool insertion_finished() const { return insertion_finished_; }
  void set_insertion_finished() { insertion_finished_ = true; }

  // Subclasses implement grid access
  virtual std::unique_ptr<Submap> ToProto() const = 0;
  virtual void UpdateFromProto(const proto::Submap& proto) = 0;

 protected:
  const transform::Rigid3d local_pose_;
  int num_range_data_ = 0;
  bool insertion_finished_ = false;
};

Members

  • local_pose — Pose of submap origin in the local trajectory frame

  • num_range_data — Number of range data insertions into this submap

  • insertion_finished — True when submap has received all its range data

Class: cartographer::mapping::Submap2D

Located in 2d/submap_2d.h/.cc.

Grid Types

  1. ProbabilityGrid — Occupancy grid with log-odds representation (default)

  2. TSDF — Truncated Signed Distance Function grid (alternative)

Configuration

From trajectory_builder_2d.lua:

submaps = {
  num_range_data = 90,
  grid_options_2d = {
    grid_type = "PROBABILITY_GRID",  -- or "TSDF"
    resolution = 0.05,
  },
  range_data_inserter = {
    range_data_inserter_type = "PROBABILITY_GRID_INSERTER_2D",
    probability_grid_range_data_inserter = {
      insert_free_space = true,
      hit_probability = 0.55,
      miss_probability = 0.49,
    },
    tsdf_range_data_inserter = {
      truncation_distance = 0.3,
      maximum_weight = 10.,
      update_free_space = false,
      -- normal estimation options...
    },
  },
}

Probability Grid Inserter

Updates occupancy using log-odds:

  • Hit (return): log(hit_probability / (1 - hit_probability))

  • Miss (free space): log(miss_probability / (1 - miss_probability))

Default: hit=0.55, miss=0.49 → slight preference for free space.

TSDF Inserter

Stores truncated signed distance to surface. Supports:

  • Free space updates (optional)

  • Normal estimation for surface reconstruction

  • Weighted fusion of multiple scans

Class: cartographer::mapping::Submap3D

Located in 3d/submap_3d.h/.cc.

Hybrid Grid

3D submaps use a HybridGrid — a sparse 3D voxel grid implemented as a hash map (std::unordered_map<uint64_t, Cell>).

Structure

Each submap has two resolutions:

  • High resolution (e.g., 0.10m) — Near range, up to high_resolution_max_range (e.g., 20m)

  • Low resolution (e.g., 0.45m) — Far range, up to max_range (e.g., 60m)

Configuration

From trajectory_builder_3d.lua:

submaps = {
  high_resolution = 0.10,
  high_resolution_max_range = 20.,
  low_resolution = 0.45,
  num_range_data = 160,
  range_data_inserter = {
    hit_probability = 0.55,
    miss_probability = 0.49,
    num_free_space_voxels = 2,
    intensity_threshold = 40,
  },
}

Insertion

For each return point:

  1. Mark voxel as occupied (update hit probability)

  2. Mark num_free_space_voxels voxels along ray as free

  3. Optionally use intensity for weighting

Submap Lifecycle

1. Created by TrajectoryBuilder (AddSubmap)
2. Receives range data insertions (num_range_data times)
3. Marked insertion_finished = true
4. New submap created, previous becomes "finished"
5. After loop closure, may be trimmed (overlapping_submaps_trimmer_2d)

Serialization

Submaps are serialized as part of the pose graph state:

message Submap {
  SubmapId id;
  Rigid3d local_pose;
  int32 num_range_data;
  bool insertion_finished;
  // Grid data (ProbabilityGrid/TSDF/HybridGrid)
}

Usage

// Access submap data from pose graph
auto submap_data = pose_graph->GetSubmapData();
for (const auto& [submap_id, data] : submap_data) {
  // data.submap->local_pose() -- submap origin
  // data.submap->grid() -- access grid cells
}

// For 2D probability grid
auto* prob_grid = dynamic_cast<ProbabilityGrid*>(submap->grid());
for (const auto& cell : prob_grid->cells()) {
  float prob = prob_grid->GetProbability(cell.index);
}

See Also