cartographer/mapping/2d/probability_grid.h¶
Overview¶
ProbabilityGrid is a 2D occupancy grid using log-odds representation. Each cell stores the log-odds of occupancy, allowing efficient Bayesian updates during range data insertion.
Class: cartographer::mapping::ProbabilityGrid¶
Inheritance¶
Grid2D (abstract)
└── ProbabilityGrid
Grid2D Interface¶
class Grid2D {
public:
virtual ~Grid2D() {}
virtual const MapLimits& limits() const = 0;
virtual float GetProbability(const Eigen::Array2i& cell_index) const = 0;
virtual bool IsKnown(const Eigen::Array2i& cell_index) const = 0;
virtual void SetProbability(const Eigen::Array2i& cell_index,
float probability) = 0;
};
ProbabilityGrid Methods¶
Construction¶
explicit ProbabilityGrid(const MapLimits& limits);
ProbabilityGrid(const proto::ProbabilityGrid2D& proto,
const MapLimits& limits);
Grid Access¶
const MapLimits& limits() const override;
float GetProbability(const Eigen::Array2i& cell_index) const override;
bool IsKnown(const Eigen::Array2i& cell_index) const override;
void SetProbability(const Eigen::Array2i& cell_index,
float probability) override;
Iteration¶
void ApplyToCells(const std::function<void(const Eigen::Array2i&)>& function) const;
Calls function for every known cell.
Serialization¶
proto::ProbabilityGrid2D ToProto() const;
void ToProto(proto::ProbabilityGrid2D* proto) const;
Log-Odds Representation¶
Internally stores log-odds (logit) values:
log_odds = log(p / (1 - p))
Where p is the occupancy probability.
Advantages:
Bayesian updates become addition:
log_odds_new = log_odds_prior + log_odds_measurementNo division or clamping during updates
Efficient incremental updates
Constants¶
constexpr int16 kMaxCorrespondenceCost = 32767;
constexpr int16 kMinCorrespondenceCost = 0;
constexpr int16 kUnknownCorrespondenceCost = 32767;
Correspondence cost maps to probability:
0→ probability 1.0 (occupied)32767→ probability 0.0 (free) or unknown
Correspondence Cost¶
Used for scan matching cost computation:
int GetCorrespondenceCost(const Eigen::Array2i& cell_index) const;
Returns cost in [0, 32767] where lower = more likely occupied.
Conversion Functions¶
static float ProbabilityToCorrespondenceCost(float probability);
static float CorrespondenceCostToProbability(int correspondence_cost);
MapLimits¶
Defines the grid bounds and resolution:
struct MapLimits {
double resolution; // Meters per cell
Eigen::Vector2d max; // Max x, y in grid frame
Eigen::Array2i cell_limits; // Number of cells (x, y)
Eigen::Array2i GetCellIndex(const Eigen::Vector2f& point) const;
Eigen::Vector2f GetCellCenter(const Eigen::Array2i& cell_index) const;
bool Contains(const Eigen::Array2i& cell_index) const;
};
ProbabilityGridRangeDataInserter2D¶
Located in probability_grid_range_data_inserter_2d.h/.cc.
Insertion Algorithm¶
For each range data insertion:
Hit cells (returns) → Increase occupancy probability
Miss cells (free space along rays) → Decrease occupancy probability
struct Options {
bool insert_free_space = true;
float hit_probability = 0.55;
float miss_probability = 0.49;
};
Update equations:
Hit:
log_odds += log(hit_prob / (1 - hit_prob))Miss:
log_odds += log(miss_prob / (1 - miss_prob))
With defaults: hit adds ~0.2, miss adds ~-0.04 (slight free space bias).
Ray Casting¶
Uses Bresenham’s algorithm to trace rays from origin to returns/misses.
Usage¶
// Create grid
MapLimits limits(0.05, Eigen::Vector2d(50, 50), Eigen::Array2i(1000, 1000));
ProbabilityGrid grid(limits);
// Insert range data
ProbabilityGridRangeDataInserter2D inserter(options);
inserter.Insert(range_data, &grid);
// Query probability
Eigen::Array2i cell = limits.GetCellIndex(Eigen::Vector2f(1.0, 2.0));
float prob = grid.GetProbability(cell);
// For scan matching: get correspondence cost
int cost = grid.GetCorrespondenceCost(cell);
Configuration¶
From trajectory_builder_2d.lua:
range_data_inserter = {
probability_grid_range_data_inserter = {
insert_free_space = true,
hit_probability = 0.55,
miss_probability = 0.49,
},
}