机器人地图的分类
尺度地图(Metric Map)
机器人领域中常见的尺度地图有栅格地图和点云地图。它的好处是可以用一个唯一的坐标描述一个具体的位置。
拓扑地图(Topological Map)
拓扑地图用节点表示每一个位置,位置与位置连接的线就是可以通行的路。拓扑地图一般用于大地图,比如国家公路网和城市地图路线图等等。
语义地图(Semantic Map)
语义地图会用标签来描述地点。如手机里的地图APP。
覆盖栅格建图算法
特点
- 把环境分解成一个一个的小栅格。常用0.05m的正方形栅格
- 每个栅格有两种状态:占用(Occupied)或者空闲(free)
- 非参模型
- 随着地图的增大,内存需求急剧增加
- 天然区分可通行区域,适合进行轨迹规划
数学描述
给定机器人的位姿和传感器的观测数据(主要指激光雷达)。
dat a = { x 1 , z 1 , x 2 , z 2 , ⋯ x n , z n } a=\left\{x_{1}, z_{1}, x_{2}, z_{2}, \cdots x_{n}, z_{n}\right\} a={x1,z1,x2,z2,⋯xn,zn}
估计出最可能的地图
m ∗ = arg max m P ( m ∣ d a t a ) m^{*}=\arg \max _{m} P(m | d a t a) m∗=argmaxmP(m∣data)
m ∗ = arg max m P ( m ∣ x 1 : t , z 1 : t ) m^{*}=\arg \max _{m} P\left(m | x_{1: t}, z_{1: t}\right) m∗=argmaxmP(m∣x1:t,z1:t)
假设
- 栅格地图中的栅格是一个二元随机变量,只能取两个值:占用(Occupied)或者空闲(Free)
- 𝑝 𝑚𝑖 = 1表示被占用, 𝑝 𝑚𝑖 = 0表示空闲, 𝑝 𝑚𝑖 = 0.5表示不知道(Unknown)
- 在建图的过程中,环境不会发生改变
- 地图中的每一个栅格都是独立的,因此数学表达式可以表示为:
p ( m ) = ∏ p ( m i ) \mathrm{p}(m)=\prod p\left(m_{i}\right) p(m)=∏p(mi)
- 地图估计问题表示为:
p ( m ∣ x 1 : t , z 1 : t ) = ∏ p ( m i ∣ x 1 : t , z 1 : t ) \mathrm{p}\left(m | x_{1: t}, z_{1: t}\right)=\prod p\left(m_{i} | x_{1: t}, z_{1: t}\right) p(m∣x1:t,z1:t)=∏p(mi∣x1:t,z1:t)
由上可知,估计环境的地图只需要对每一个独立的栅格进行估计即可。
公式推导
m i m_i mi是一个二元随机变量,因此:
p ( m i ∣ x 1 : t , z 1 : t ) = p ( z t ∣ m i , z 1 : t − 1 , x 1 : t ) p ( m i ∣ z 1 : t − 1 , x 1 : t ) p ( z t ∣ z 1 : t − 1 , x 1 : t ) = p ( z t ∣ m i , x t ) p ( m i ∣ z 1 : t − 1 , x 1 : t − 1 ) p ( z t ∣ z 1 : t − 1 , x 1 : t ) \begin{aligned} \mathrm{p}\left(m_{i} | x_{1: t}, z_{1: t}\right) &=\frac{p\left(z_{t} | m_{i}, z_{1: t-1}, x_{1: t}\right) p\left(m_{i} | z_{1: t-1}, x_{1: t}\right)}{p\left(z_{t} | z_{1: t-1}, x_{1: t}\right)} \\ &=\frac{p\left(z_{t} | m_{i}, x_{t}\right) p\left(m_{i} | z_{1: t-1}, x_{1: t-1}\right)}{p\left(z_{t} | z_{1: t-1}, x_{1: t}\right)} \end{aligned} p(mi∣x1:t,z1:t)=p(zt∣z1:t−1,x1:t)p(zt∣mi,z1:t−1,x1:t)p(mi∣z1:t−1,x1:t)=p(zt∣z1:t−1,x1:t)p(zt∣mi,xt)p(mi∣z1:t−1,x1:t−1)
m
i
m_{i}
mi表示第
i
i
i个栅格的状态
z
1
:
t
z_{1: t}
z1:t表示
1
:
t
1: t
1:t时刻的激光数据
x
1
:
t
x_{1: t}
x1:t表示
1
:
t
1: t
1:t时刻的机器人位姿
上面的公式其实就是贝叶斯公式。将 z 1 : t z_{1: t} z1:t分成了 z 1 : t − 1 z_{1: t-1} z1:t−1和 z t z_{t} zt。因为每帧激光数据都是独立的,所以 p ( z 1 : t − 1 ) p(z_{1: t-1}) p(z1:t−1)和 p ( z t ) p(z_{t}) p(zt)是互不影响的。根据Markov, z t z_{t} zt只与当前机器人位姿有关,跟之前的位姿无光。则上面可以有 p ( z t ∣ m i , z 1 : t − 1 , x 1 : t ) = p ( z t ∣ m i , x t ) p(z_{t} | m_{i}, z_{1: t-1}, x_{1: t})=p(z_{t} | m_{i}, x_{ t}) p(zt∣mi,z1:t−1,x1:t)=p(zt∣mi,xt)。同理可得, p ( m i ∣ z 1 : t − 1 , x 1 : t ) = p ( m i ∣ z 1 : t − 1 , x t − 1 ) p(m_{i} | z_{1: t-1}, x_{1: t})=p(m_{i} | z_{1: t-1}, x_{ t-1}) p(mi∣z1:t−1,x1:t)=p(mi∣z1:t−1,xt−1)。
其中
p ( z t ∣ m i , x t ) = p ( m i ∣ z t , x t ) p ( z t ∣ x t ) p ( m i ∣ x t ) \mathrm{p}\left(z_{t} | m_{i}, x_{t}\right)=\frac{p\left(m_{i} | z_{t}, x_{t}\right) p\left(z_{t} | x_{t}\right)}{p\left(m_{i} | x_{t}\right)} p(zt∣mi,xt)=p(mi∣xt)p(mi∣zt,xt)p(zt∣xt)
m i m_i mi是一个二元随机变量,因此:
p ( m i ∣ x 1 : t , z 1 : t ) = p ( m i ∣ z t , x t ) p ( z t ∣ x t ) p ( m i ∣ x t ) p ( m i ∣ z 1 : t − 1 , x 1 : t − 1 ) p ( z t ∣ z 1 : t − 1 , x 1 : t ) = p ( m i ∣ z t , x t ) p ( z t ∣ x t ) p ( m i ) p ( m i ∣ z 1 : t − 1 , x 1 : t − 1 ) p ( z t ∣ z 1 : t − 1 , x 1 : t ) \begin{aligned} \mathrm{p}\left(m_{i} | x_{1: t}, z_{1: t}\right) &=\frac{p\left(m_{i} | z_{t}, x_{t}\right) p\left(z_{t} | x_{t}\right)}{p\left(m_{i} | x_{t}\right)} \frac{p\left(m_{i} | z_{1: t-1}, x_{1: t-1}\right)}{p\left(z_{t} | z_{1: t-1}, x_{1: t}\right)} \\ &=\frac{p\left(m_{i} | z_{t}, x_{t}\right) p\left(z_{t} | x_{t}\right)}{p\left(m_{i}\right)} \frac{p\left(m_{i} | z_{1: t-1}, x_{1: t-1}\right)}{p\left(z_{t} | z_{1: t-1}, x_{1: t}\right)} \end{aligned} p(mi∣x1:t,z1:t)=p(mi∣xt)p(mi∣zt,xt)p(zt∣xt)p(zt∣z1:t−1,x1:t)p(mi∣z1:t−1,x1:t−1)=p(mi)p(mi∣zt,xt)p(zt∣xt)p(zt∣z1:t−1,x1:t)p(mi∣z1:t−1,x1:t−1)
上式中 m i m_i mi和 x t x_t xt是相互独立的。所以有 p ( m i ∣ x t ) = p ( m i ) p(m_{i} | x_t)=p( m_{i}) p(mi∣xt)=p(mi)。
同理,对于 ¬ m i \neg m_{i} ¬mi:
p ( ¬ m i ∣ x 1 : t , z 1 : t ) = p ( ¬ m i ∣ z t , x t ) p ( z t ∣ x t ) p ( ¬ m i ∣ x t ) p ( ¬ m i ∣ z 1 : t − 1 , x 1 : t − 1 ) p ( z t ∣ z 1 : t − 1 , x 1 : t ) = p ( ¬ m i ∣ z t , x t ) p ( z t ∣ x t ) p ( ¬ m i ) p ( ¬ m i ∣ z 1 : t − 1 , x 1 : t − 1 ) p ( z t ∣ z 1 : t − 1 , x 1 : t ) \begin{aligned} \mathrm{p}\left(\neg m_{i} | x_{1: t}, z_{1: t}\right) &=\frac{p\left(\neg m_{i} | z_{t}, x_{t}\right) p\left(z_{t} | x_{t}\right)}{p\left(\neg m_{i} | x_{t}\right)} \frac{p\left(\neg m_{i} | z_{1: t-1}, x_{1: t-1}\right)}{p\left(z_{t} | z_{1: t-1}, x_{1: t}\right)} \\ &=\frac{p\left(\neg m_{i} | z_{t}, x_{t}\right) p\left(z_{t} | x_{t}\right)}{p\left(\neg m_{i}\right)} \frac{p\left(\neg m_{i} | z_{1: t-1}, x_{1: t-1}\right)}{p\left(z_{t} | z_{1: t-1}, x_{1: t}\right)} \end{aligned} p(¬mi∣x1:t,z1:t)=p(¬mi∣xt)p(¬mi∣zt,xt)p(zt∣xt)p(zt∣z1:t−1,x1:t)p(¬mi∣z1:t−1,x1:t−1)=p(¬mi)p(¬mi∣zt,xt)p(zt∣xt)p(zt∣z1:t−1,x1:t)p(¬mi∣z1:t−1,x1:t−1)
两者之比
p ( m i ∣ x 1 : t , z 1 : t ) p ( ¬ m i ∣ x 1 : t , z 1 : t ) = p ( m i ∣ z t , x t ) p ( m i ) p ( m i ∣ z 1 : t − 1 , x 1 : t − 1 ) p ( ¬ m i ) p ( ¬ m i ∣ z t , x t ) p ( ¬ m i ∣ z 1 : t − 1 , x 1 : t − 1 ) = p ( m i ∣ z t , x t ) p ( ¬ m i ∣ z t , x t ) p ( m i ∣ z 1 : t − 1 , x 1 : t − 1 ) p ( ¬ m i ∣ z 1 : t − 1 , x 1 : t − 1 ) p ( ¬ m i ) p ( m i ) \begin{aligned} \frac{\mathrm{p}\left(m_{i} | x_{1: t}, z_{1: t}\right)}{\mathrm{p}\left(\neg m_{i} | x_{1: t}, z_{1: t}\right)} &=\frac{p\left(m_{i} | z_{t}, x_{t}\right)}{p\left(m_{i}\right)} \frac{p\left(m_{i} | z_{1: t-1}, x_{1: t-1}\right) p\left(\neg m_{i}\right)}{p\left(\neg m_{i} | z_{t}, x_{t}\right) p\left(\neg m_{i} | z_{1: t-1}, x_{1: t-1}\right)} \\ &=\frac{p\left(m_{i} | z_{t}, x_{t}\right)}{p\left(\neg m_{i} | z_{t}, x_{t}\right)} \frac{p\left(m_{i} | z_{1: t-1}, x_{1: t-1}\right)}{p\left(\neg m_{i} | z_{1: t-1}, x_{1: t-1}\right)} \frac{p\left(\neg m_{i}\right)}{p\left(m_{i}\right)} \end{aligned} p(¬mi∣x1:t,z1:t)p(mi∣x1:t,z1:t)=p(mi)p(mi∣zt,xt)p(¬mi∣zt,xt)p(¬mi∣z1:t−1,x1:t−1)p(mi∣z1:t−1,x1:t−1)p(¬mi)=p(¬mi∣zt,xt)p(mi∣zt,xt)p(¬mi∣z1:t−1,x1:t−1)p(mi∣z1:t−1,x1:t−1)p(mi)p(¬mi)
对于二元随机变量:
p ( m i ∣ x 1 : t , z 1 : t ) p ( ¬ m i ∣ x 1 : t , z 1 : t ) = p ( m i ∣ z t , x t ) 1 − p ( m i ∣ z t , x t ) p ( m i ∣ z 1 : t − 1 , x 1 : t − 1 ) 1 − p ( m i ∣ z 1 : t − 1 , x 1 : t − 1 ) 1 − p ( m i ) p ( m i ) \frac{\mathrm{p}\left(m_{i} | x_{1: t}, z_{1: t}\right)}{\mathrm{p}\left(\neg m_{i} | x_{1: t}, z_{1: t}\right)}=\frac{p\left(m_{i} | z_{t}, x_{t}\right)}{1-p\left(m_{i} | z_{t}, x_{t}\right)} \frac{p\left(m_{i} | z_{1: t-1}, x_{1: t-1}\right)}{1-p\left(m_{i} | z_{1: t-1}, x_{1: t-1}\right)} \frac{1-p\left(m_{i}\right)}{p\left(m_{i}\right)} p(¬mi∣x1:t,z1:t)p(mi∣x1:t,z1:t)=1−p(mi∣zt,xt)p(mi∣zt,xt)1−p(mi∣z1:t−1,x1:t−1)p(mi∣z1:t−1,x1:t−1)p(mi)1−p(mi)
对于p(x),定义对应的Log-Odd项:
l ( x ) = log p ( x ) 1 − p ( x ) l(x)=\log \frac{p(x)}{1-p(x)} l(x)=log1−p(x)p(x)
则:
p ( x ) = 1 − 1 1 + exp ( l ( x ) ) \mathrm{p}(x)=1-\frac{1}{1+\exp (l(x))} p(x)=1−1+exp(l(x))1
等式两边取 l o g log log,则变成:
l ( m i ∣ x 1 : t , z 1 : t ) = l ( m i ∣ x t , z t ) + l ( m i ∣ x 1 : t − 1 , z 1 : t − 1 ) − l ( m i ) l\left(m_{i} | x_{1: t}, z_{1: t}\right)=l\left(m_{i} | x_{t}, z_{t}\right)+l\left(m_{i} | x_{1: t-1}, z_{1: t-1}\right)-l\left(m_{i}\right) l(mi∣x1:t,z1:t)=l(mi∣xt,zt)+l(mi∣x1:t−1,z1:t−1)−l(mi)
其中:
l ( m i ∣ x t , z t ) l\left(m_{i} | x_{t}, z_{t}\right) l(mi∣xt,zt)表示激光雷达的逆观测模型(inverse measurement Model)
l ( m i ∣ x 1 : t − 1 , z 1 : t − 1 ) l\left(m_{i} | x_{1: t-1}, z_{1: t-1}\right) l(mi∣x1:t−1,z1:t−1)表示栅格𝑚𝑖在t-1时刻的状态
l ( m i ) l(m_{i} ) l(mi)表示栅格 m i m_{i} mi的先验值,该值对所有栅格都相同
算法流程
- 该算法对某一个栅格进行操作的时候,只有加法操作,因此具有非常高的更新速度。
- 更新的时候,需要知道传感器的逆测量模型。
示例代码
在hector-slam包中包含了覆盖栅格地图更新栅格概率的代码。文件为GridMapLogOdds.h。
//=================================================================================================
// Copyright (c) 2011, Stefan Kohlbrecher, TU Darmstadt
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the Simulation, Systems Optimization and Robotics
// group, TU Darmstadt nor the names of its contributors may be used to
// endorse or promote products derived from this software without
// specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//=================================================================================================
#ifndef __GridMapLogOdds_h_
#define __GridMapLogOdds_h_
#include <cmath>
/**
* Provides a log odds of occupancy probability representation for cells in a occupancy grid map.
*/
class LogOddsCell
{
public:
/*
void setOccupied()
{
logOddsVal += 0.7f;
};
void setFree()
{
logOddsVal -= 0.4f;
};
*/
/**
* Sets the cell value to val.
* @param val The log odds value.
*/
void set(float val)
{
logOddsVal = val;
}
/**
* Returns the value of the cell.
* @return The log odds value.
*/
float getValue() const
{
return logOddsVal;
}
/**
* Returns wether the cell is occupied.
* @return Cell is occupied
*/
bool isOccupied() const
{
return logOddsVal > 0.0f;
}
bool isFree() const
{
return logOddsVal < 0.0f;
}
/**
* Reset Cell to prior probability.
*/
void resetGridCell()
{
logOddsVal = 0.0f;
updateIndex = -1;
}
//protected:
public:
float logOddsVal; ///< The log odds representation of occupancy probability.
int updateIndex;
};
/**
* Provides functions related to a log odds of occupancy probability respresentation for cells in a occupancy grid map.
*/
class GridMapLogOddsFunctions
{
public:
/**
* Constructor, sets parameters like free and occupied log odds ratios.
*/
GridMapLogOddsFunctions()
{
this->setUpdateFreeFactor(0.4f);
this->setUpdateOccupiedFactor(0.6f);
/*
//float probOccupied = 0.6f;
float probOccupied = 0.9f;
float oddsOccupied = probOccupied / (1.0f - probOccupied);
logOddsOccupied = log(oddsOccupied);
float probFree = 0.4f;
float oddsFree = probFree / (1.0f - probFree);
logOddsFree = log(oddsFree);
*/
}
/**
* Update cell as occupied
* @param cell The cell.
*/
void updateSetOccupied(LogOddsCell& cell) const
{
if (cell.logOddsVal < 50.0f){
cell.logOddsVal += logOddsOccupied;
}
}
/**
* Update cell as free
* @param cell The cell.
*/
void updateSetFree(LogOddsCell& cell) const
{
cell.logOddsVal += logOddsFree;
}
void updateUnsetFree(LogOddsCell& cell) const
{
cell.logOddsVal -= logOddsFree;
}
/**
* Get the probability value represented by the grid cell.
* @param cell The cell.
* @return The probability
*/
float getGridProbability(const LogOddsCell& cell) const
{
float odds = exp(cell.logOddsVal);
return odds / (odds + 1.0f);
/*
float val = cell.logOddsVal;
//prevent #IND when doing exp(large number).
if (val > 50.0f) {
return 1.0f;
} else {
float odds = exp(val);
return odds / (odds + 1.0f);
}
*/
//return 0.5f;
}
//void getGridValueMap( const LogOddsCell& cell) const{};
//void isOccupied(LogOddsCell& cell) {};
//void resetGridCell() {};
void setUpdateFreeFactor(float factor)
{
logOddsFree = probToLogOdds(factor);
}
void setUpdateOccupiedFactor(float factor)
{
logOddsOccupied = probToLogOdds(factor);
}
protected:
float probToLogOdds(float prob)
{
float odds = prob / (1.0f - prob);
return log(odds);
}
float logOddsOccupied; /// < The log odds representation of probability used for updating cells as occupied
float logOddsFree; /// < The log odds representation of probability used for updating cells as free
};
#endif
参考网址:
占据栅格地图(Occupancy Grid Map)
占用栅格地图构建
计数建图算法
概念
- 对于每一个栅格统计两个量:𝑚𝑖𝑠𝑠𝑒𝑠(𝑖)和ℎ𝑖𝑡𝑠(𝑖)
- 𝑚𝑖𝑠𝑠𝑒𝑠(𝑖)表示栅格𝑖被激光束通过的次数,即被标为free的次数
- ℎ𝑖𝑡𝑠(𝑖)表示栅格𝑖被激光束击中的次数,即被标为occupied的次数
- 当ℎ𝑖𝑡𝑠(𝑖) / (𝑚𝑖𝑠𝑠𝑒𝑑(𝑖) + ℎ𝑖𝑡𝑠(𝑖))超过阈值则认为该栅格为Occupied,否则认为栅格是Free的。
- 𝐻𝑖𝑡𝑠(𝑖)/(𝑚𝑖𝑠𝑠𝑒𝑠(𝑖) + ℎ𝑖𝑡𝑠(𝑖))表示栅格𝑖的极大似然估计
观测模型
其中:
- t t t时刻的机器人位姿为 x t x_t xt
- t t t时刻的激光雷达数据为 z t z_t zt,第 n n n个激光束为 z t , n z_t,_n zt,n
- c t , n c_t,_n ct,n表示t时刻的第 n n n个激光束是否为击中障碍物。 c t , n = 1 c_t,_n=1 ct,n=1表示最大值,即没有击中任何障碍物, c t , n = 0 c_t,_n=0 ct,n=0表示正常值。
- f ( x t , n , z t , n ) f(x_t,n,z_t,n) f(xt,n,zt,n)表示 t t t时刻第 n n n个激光束击中的栅格的下标, m f ( x t , n , z t , n ) m_f(x_t,n,z_t,n) mf(xt,n,zt,n)表示对应的栅格的占用概率。
地图的极大似然估计为:
等价于:
则函数可简化为:
显然是关于
m
j
m_j
mj的函数,其极值可直接求其对于
m
j
m_j
mj的导数,令其等于0即可:
化解可得:
最终得到的就是上面提到的结论。
TSDF建图算法
基本思路
- 充分考虑传感器测量的不确定性,利用多次测量数据来实现更精确的表面重构,从而得到更精确、更细、更薄的地图。
用多次激光测量数据更新同一个栅格的TSDF值。线性插值得到TSDF值为0的栅格就是被占用的栅格。理论上可以只用一个栅格的厚度表示环境曲面。 - 为障碍物表面建立Signed Distance Function。
根据该方程更新每个栅格的TSDF值。 - 距离表面较远的点忽略不计,因为不会影响到表面重构。
由于截止距离的设置,大于截止距离的点不会用于曲面重建。
数学描述
s
d
f
i
(
x
)
=
l
a
s
e
r
i
(
x
)
−
d
i
s
t
i
(
x
)
sdf_{i}(x)=laser_{i}(x) - dist_{i}(x)
sdfi(x)=laseri(x)−disti(x)
l a s e r i ( x ) laser_{i}(x) laseri(x)表示激光测量距离
d i s t i ( x ) dist_{i}(x) disti(x)表示栅格离传感器原点的距离
t s d f ( x ) tsdf(x) tsdf(x)的定义
t s d f ( x ) = m a x ( − 1 , m i n ( 1 , s d f i ( x ) / t ) ) tsdf(x)=max(-1,min(1,sdf_{i}(x)/t)) tsdf(x)=max(−1,min(1,sdfi(x)/t))
t t t为设定的截止距离。
多次观测的融合更新方程:
通常
w
i
w_{i}
wi设置为1。每个栅格初始状态时,
T
S
D
F
0
(
x
)
=
0
TSDF_{0}(x)=0
TSDF0(x)=0,
W
0
=
0
W_{0}=0
W0=0。每次有观测数据(即激光击中或扫过)都按照上面的方程更新栅格的TSDF值。该方程实际上就是更新每个栅格的TSDF平均值。而环境曲面的重建就是寻找TSDF值正负交替的栅格。该栅格就是被占用的栅格。
上图展示了使用上述方程得到的TSDF场。在TSDF场中,符号进行变化的栅格就是曲面的所在。通过在两个栅格之间进行插值可以得到TSDF值为0的栅格坐标,而该坐标就是曲面的精确位置。由于可以得到精确的栅格坐标,其构建的地图通常只有一个栅格的厚度。
论文:Truncated Signed Distance Function-Experiments on Voxel Size
总结
针对Occupancy Grid和Count Model
优势:这两种算法计算量比较小,实现也较为简单。Occupancy Grid只需对Grid Log Likelihood进行加法更新;Count Model只需对Grid Hit/Miss计数进行加法更新。之后便可通过公式获取每个栅格的占用概率,进而构建整张地图。
劣势:这两个算法对测量噪声较为敏感,得到的障碍物可能占用多个栅格,无法获取环境曲面的精确位置。
针对TSDF
优势:TSDF方法通过加权线性最小二乘,使用多帧观测值进行平均计算来融合,能够有效减小测量噪声的影响。同时可以通过线性插值得到TSDF的零点位置来获取环境曲面的精确位置。最终得到障碍物仅会占用一个栅格。
劣势:计算复杂,实时性较差。需要更多的工程优化(如并行计算)来保证建图效率。
关注公众号《首飞》回复“机器人”获取精心推荐的C/C++,Python,Docker,Qt,ROS1/2,机器人学等机器人行业常用技术资料。