occupancy grid mapping 占用栅格地图构建(三)
占用网格构图算法,主要是根据t时刻的有噪声的测量数据和机器人当前的位姿来生成连续地图。如下:

任何占用栅格建图的黄金法则都是给定数据计算地图的后验概率
我们可以发现,地图的构建就是寻找判断是否是障碍物,这样就把问题分解成为了一个二值概率的问题,讨论过这个问题的一个滤波器——二值贝叶斯滤波器binary Bayes filter。
occupancy grid mapping伪代码:

原理还是很简单的,就是遍历所有的网格,判断当前网格cell是否在传感器的扫描范围内,如果在的话,根据 和
来计算对数差异。
对数差异的逆模型的算法:

这样通过不断的获取扫描的传感器信息和机器人的位姿信息,就可以更新差异值。然后就可以计算 来获取最终的后验概率。
main.cpp
#include <iostream>
#include <math.h>
#include <vector>
using namespace std;
// Sensor characteristic: Min and Max ranges of the beams
double Zmax = 5000, Zmin = 170;
// Defining free cells(lfree), occupied cells(locc), unknown cells(l0) log odds values
double l0 = 0, locc = 0.4, lfree = -0.4;
// Grid dimensions
double gridWidth = 100, gridHeight = 100;
// Map dimensions
double mapWidth = 30000, mapHeight = 15000;
// Robot size with respect to the map
double robotXOffset = mapWidth / 5, robotYOffset = mapHeight / 3;
// Defining an l vector to store the log odds values of each cell
vector< vector<double> > l(mapWidth/gridWidth, vector<double>(mapHeight/gridHeight));
double inverseSensorModel(double x, double y, double theta, double xi, double yi, double sensorData[])
{
//******************Code the Inverse Sensor Model Algorithm**********************//
// Defining Sensor Characteristics
double Zk, thetaK, sensorTheta;
double minDelta = -1;
double alpha = 200, beta = 20;
//******************Compute r and phi**********************//
double r = sqrt(pow(xi - x, 2) + pow(yi - y, 2));
double phi = atan2(yi - y, xi - x) - theta;
//Scaling Measurement to [-90 -37.5 -22.5 -7.5 7.5 22.5 37.5 90]
for (int i = 0; i < 8; i++) {
if (i == 0) {
sensorTheta = -90 * (M_PI / 180);
}
else if (i == 1) {
sensorTheta = -37.5 * (M_PI / 180);
}
else if (i == 6) {
sensorTheta = 37.5 * (M_PI / 180);
}
else if (i == 7) {
sensorTheta = 90 * (M_PI / 180);
}
else {
sensorTheta = (-37.5 + (i - 1) * 15) * (M_PI / 180);
}
if (fabs(phi - sensorTheta) < minDelta || minDelta == -1) {
Zk = sensorData[i];
thetaK = sensorTheta;
minDelta = fabs(phi - sensorTheta);
}
}
//******************Evaluate the three cases**********************//
if (r > min((double)Zmax, Zk + alpha / 2) || fabs(phi - thetaK) > beta / 2 || Zk > Zmax || Zk < Zmin) {
return l0;
}
else if (Zk < Zmax && fabs(r - Zk) < alpha / 2) {
return locc;
}
else if (r <= Zk) {
return lfree;
}
}
void occupancyGridMapping(double Robotx, double Roboty, double Robottheta, double sensorData[])
{
for (int x = 0; x < mapWidth / gridWidth; x++) {
for (int y = 0; y < mapHeight / gridHeight; y++) {
double xi = x * gridWidth + gridWidth / 2 - robotXOffset;
double yi = -(y * gridHeight + gridHeight / 2) + robotYOffset;
if (sqrt(pow(xi - Robotx, 2) + pow(yi - Roboty, 2)) <= Zmax) {
l[x][y] = l[x][y] + inverseSensorModel(Robotx, Roboty, Robottheta, xi, yi, sensorData) - l0;
}
}
}
}
int main()
{
double timeStamp;
double measurementData[8];
double robotX, robotY, robotTheta;
FILE* posesFile = fopen("poses.txt", "r");
FILE* measurementFile = fopen("measurement.txt", "r");
// Scanning the files and retrieving measurement and poses at each timestamp
while (fscanf(posesFile, "%lf %lf %lf %lf", &timeStamp, &robotX, &robotY, &robotTheta) != EOF) {
fscanf(measurementFile, "%lf", &timeStamp);
for (int i = 0; i < 8; i++) {
fscanf(measurementFile, "%lf", &measurementData[i]);
}
occupancyGridMapping(robotX, robotY, (robotTheta / 10) * (M_PI / 180), measurementData);
}
// Displaying the map
for (int x = 0; x < mapWidth / gridWidth; x++) {
for (int y = 0; y < mapHeight / gridHeight; y++) {
cout << l[x][y] << " ";
}
}
return 0;
}
github:
https://github.com/horo2016/Occupancy-Grid-Mapping-Algorithm






