动手学无人驾驶(5):多传感器数据融合

在这里插入图片描述

本系列的前4篇文章主要介绍了深度学习技术在无人驾驶环境感知中的应用,包括交通标志识别图像与点云3D目标检测。关于环境感知部分的介绍本系列暂且告一段落,后续如有需要再进行补充。
现在我们开启新的篇章,在本文中将会介绍无人驾驶的定位部分,我们将使用仿真的RadarLiDAR数据对自行车进行追踪。这里使用到了两种传感器数据,因此我们需要进行数据融合,同时由于两种传感器工作原理不同,我们需要分别应用卡尔曼滤波扩展卡尔曼滤波技术。
本文主要参考了Udacity《无人驾驶工程师》课程相关项目,同时也参考了知乎作者陈光的分享,在此一同表示感谢。

1. 毫米波雷达简介

毫米波雷达是自动驾驶汽车常用的传感器之一,目前市场上常用的毫米波雷达有大陆ARS408雷达,测距范围最远能达到250米。
在这里插入图片描述
毫米波雷达的工作原理是多普勒效应,输出值是极坐标下的测量结果。

如下图所示,毫米波雷达能够测量障碍物在极坐标下的距离 ρ \rho ρ方向夹角 φ \varphi φ,以及径向速度 ρ ˙ \dot{\rho} ρ˙
在这里插入图片描述


2. 激光雷达简介

激光雷达与毫米波雷达不同,它的测量原理是光沿直线传播

能直接获得障碍物在笛卡尔坐标系下 x x x方向、 y y y方向和 z z z方向上的距离。目前市场上常用的激光雷达有Velodyne激光雷达,国内有Robosense激光雷达以及大疆公司旗下的激光雷达。激光雷达根据线束的多少,分为16线,32线,64线,以及128线激光雷达。

在这里插入图片描述


3. 卡尔曼滤波直观理解

网上介绍卡尔曼滤波原理的书和资料有很多,这里从直观上来对其进行介绍,帮助大家理解,具体数学公式推导可查阅相关论文。

先一句话概括卡尔曼滤波的思想:根据上一时刻的状态 x t − 1 x_{t-1} xt1预测当前时刻的状态 x p r e x_{pre} xpre将预测的状态 x p r e x_{pre} xpre与当前时刻的测量值 z t z_t zt进行加权更新更新后的结果为最终的追踪结果 x t x_t xt

以一个常见的小车运动为例来介绍。如下图所示:有辆小车在道路上水平向右侧匀速运动,在左侧 o o o点安装了传感器,传感器每隔1秒测量一次小车的位置 s s s和运动速度 v v v

这里用向量 x t x_t xt来表示小车在 t t t时刻的运动状态,该向量 x t x_t xt也是最终的输出结果,被称作状态向量(state vector),则状态向量为:
x t = [ s t v t ] x_t=\begin{bmatrix}s_t \\ v_t\end{bmatrix} xt=[stvt]
在这里插入图片描述
由于传感器自身测量误差的存在,无法直接获取小车的真实位置,只能获取在真值附近的一个近似值,可以假设测量值在真值附近服从高斯分布,如下图所示,橙色部分为测量值。
在这里插入图片描述
在初始的时候,由于不存在上一时刻的状态,我们设初始的状态向量为测量值,因此有:

x 1 = z 1 = [ s 1 v 1 ] x_1=z_1=\begin{bmatrix}s_1 \\ v_1\end{bmatrix} x1=z1=[s1v1]


3.1 预测

卡尔曼滤波大致分为两步,第一步为状态预测(prediction)。现在我们已经有了小车第1秒的状态 x 1 x_1 x1,可以预测小车在第2秒的状态,小车所处位置假设如下图所示。
在这里插入图片描述
由于小车是做匀速运动,因此小车在第2秒时的预测状态为:
x p r e = [ s 1 + v 1 v 1 ] x_{pre}=\begin{bmatrix}s_1 + v_1\\ v_1\end{bmatrix} xpre=[s1+v1v1]


3.2 更新

现在我们已经预测了小车在第2秒的状态,同时传感器也测量出小车在第2秒时的位置,测量结果用 z 2 z_2 z2表示,则:
z 2 = [ s 2 v 2 ] z_2=\begin{bmatrix}s_2 \\ v_2\end{bmatrix} z2=[s2v2]
由于传感器本身存在着测量噪声,测量结果存在很大不确定性,将小车预测位置与测量值进行比较,如下图所示。

不难发现,小车的真实位置应该处于测量值与预测值之间。
在这里插入图片描述
对测量值与预测值进行加权,加权后的结果如下图所示,绿色部分即为小车真值分布区域。
在这里插入图片描述
这样,根据第2秒的预测值和测量值,我们就能得到第2秒的状态向量 x 2 x_2 x2。同理,按照上述预测、更新的过程,我们就能得到第3秒,第4秒…第n秒的状态向量 x n x_n xn

上面是卡尔曼滤波的直观理解,下面给出其数学公式。这里留个伏笔,在下一节部分=结合代码再介绍其中每个字母的含义。
在这里插入图片描述


4. 传感器数据融合

不知道大家有没有想过这样一个问题?既然毫米波雷达与激光雷达都能测量障碍物的位置,为什么还需要对传感器数据进行融合操作呢。

这是因为在自动驾驶中,使用单一传感器进行障碍物跟踪,往往都有着很大的局限性。激光雷达测量更精准,但是其无法得到速度信息;毫米波雷达能够得到障碍物速度信息,但是其位置测量精度不如激光雷达。如果能将二者有效结合,就能精准得到障碍物位置和速度信息,因此数据融合技术孕育而生。

在毫米波雷达与激光雷达进行数据融合时,因为两个传感器工作原理的不同,其相应的技术处理细节也不同。激光雷达可直接使用线性卡尔曼来进行障碍物跟踪;而毫米波雷达则需要使用非线性卡尔曼来进行物体跟踪。

这里分为三个小节来实现,一是线性卡尔曼滤波的实现;二是非线性卡尔曼滤波的实现;三是对二者进行数据融合。


4.1 线性卡尔曼滤波实现

在正式写代码处理问题时,我们先熟悉下要处理的传感器数据,这里要处理的是激光雷达与毫米波雷达数据。

下面是激光雷达与毫米波雷达交替发出的前20行数据,其中L代表激光雷达,R代表毫米波雷达。

L	0	0	1477010443349642	0	0	0	0
R	0	0	0	1477010443349642	0	0	0	0
L	1.559445e+00	-1.385015e-01	1477010444349642	2.098967e+00	5.222280e-02	2.195949e+00	1.093391e-01
R	1.812711e+00	2.619727e-02	2.305732e+00	1477010444349642	2.098967e+00	5.222280e-02	2.195949e+00	1.093391e-01
L	3.890927e+00	-1.341657e-01	1477010445349642	4.291359e+00	2.153118e-01	2.284336e+00	2.263225e-01
R	4.200967e+00	5.202598e-02	2.418127e+00	1477010445349642	4.291359e+00	2.153118e-01	2.284336e+00	2.263225e-01
L	6.863517e+00	4.168175e-01	1477010446349642	6.569422e+00	4.960956e-01	2.363816e+00	3.488471e-01
R	6.456604e+00	7.330529e-02	2.438466e+00	1477010446349642	6.569422e+00	4.960956e-01	2.363816e+00	3.488471e-01
L	9.077331e+00	5.932112e-01	1477010447349642	8.924371e+00	8.992403e-01	2.433593e+00	4.745258e-01
R	8.941596e+00	9.936074e-02	2.529122e+00	1477010447349642	8.924371e+00	8.992403e-01	2.433593e+00	4.745258e-01
L	1.157555e+01	1.666900e+00	1477010448349642	1.134677e+01	1.426997e+00	2.493282e+00	6.007812e-01
R	1.153365e+01	1.242681e-01	2.500995e+00	1477010448349642	1.134677e+01	1.426997e+00	2.493282e+00	6.007812e-01
L	1.359209e+01	2.311915e+00	1477010449349642	1.382695e+01	2.079045e+00	2.542900e+00	7.249468e-01
R	1.380271e+01	1.453491e-01	2.539724e+00	1477010449349642	1.382695e+01	2.079045e+00	2.542900e+00	7.249468e-01
L	1.664559e+01	2.902999e+00	1477010450349642	1.635537e+01	2.852433e+00	2.582842e+00	8.443653e-01
R	1.652890e+01	1.730753e-01	2.728349e+00	1477010450349642	1.635537e+01	2.852433e+00	2.582842e+00	8.443653e-01
L	1.901058e+01	3.705553e+00	1477010451349642	1.892299e+01	3.741610e+00	2.613820e+00	9.564796e-01
R	1.974624e+01	1.973267e-01	2.502012e+00	1477010451349642	1.892299e+01	3.741610e+00	2.613820e+00	9.564796e-01
L	2.133124e+01	4.732053e+00	1477010452349642	2.152152e+01	4.738551e+00	2.636790e+00	1.058912e+00
R	2.213645e+01	2.161499e-01	2.798219e+00	1477010452349642	2.152152e+01	4.738551e+00	2.636790e+00	1.058912e+00

激光雷达每一帧有7个数据,依次是:

  • 障碍物在X方向上的测量值(单位:米);
  • Y方向上的测量值(单位:米);
  • 测量时刻的时间戳(单位:微秒);
  • 障碍物位置在X方向上的真值(单位:米);
  • 障碍物位置在Y方向上的真值(单位:米);
  • 障碍物速度在X方向上的真值(单位:米/秒);
  • 障碍物速度在Y方向上的真值(单位:米/秒)。

毫米波雷达每一帧有8个数据,依次是:

  • 障碍物在极坐标系下的距离(单位:米);
  • 角度(单位:弧度) ;
  • 径向速度(单位:米/秒);
  • 测量时刻的时间戳(单位:微秒);
  • 障碍物位置在X方向上的真值(单位:米);
  • 障碍物位置在Y方向上的真值(单位:米);
  • 障碍物速度在X方向上的真值(单位:米/秒);
  • 障碍物速度在Y方向上的真值(单位:米/秒)。

对数据有了一定了解后,现在我们开始实现线性卡尔曼滤波。

(1)初始化

首先是初始化部分,在这里要初始化卡尔曼滤波的各个变量。

这里使用Eigen库进行初始化,这里我们定义了一个KalmanFilter类,表示为卡尔曼滤波追踪器,其成员函数包括初始化,预测,线性卡尔曼更新,扩展卡尔曼更新等,这在面向对象编程中是常使用的一种方法。

#ifndef KALMAN_FILTER_H_
#define KALMAN_FILTER_H_
#include "Eigen/Dense"

class KalmanFilter {
public:

	// state vector
	 Eigen::VectorXd x_;
	
	 // state covariance matrix
	 Eigen::MatrixXd P_;
	
	 // state transistion matrix
	 Eigen::MatrixXd F_;
	
	 // process covariance matrix
	 Eigen::MatrixXd Q_;
	
	 // measurement matrix
	 Eigen::MatrixXd H_;
	
	 // measurement covariance matrix
	 Eigen::MatrixXd R_;
	
	 /**
	  * Constructor
	  */
	 KalmanFilter();
	
	 /**
	  * Destructor
	  */
	 virtual ~KalmanFilter();
	
	 /**
	  * Init Initializes Kalman filter
	  * @param x_in Initial state
	  * @param P_in Initial state covariance
	  * @param F_in Transition matrix
	  * @param H_in Measurement matrix
	  * @param R_in Measurement covariance matrix
	  * @param Q_in Process covariance matrix
	  */
	 void Init(Eigen::VectorXd &x_in, Eigen::MatrixXd &P_in, Eigen::MatrixXd &F_in,
	     Eigen::MatrixXd &H_in, Eigen::MatrixXd &R_in, Eigen::MatrixXd &Q_in);
	
	 /**
	  * Prediction Predicts the state and the state covariance
	  * using the process model
	  * @param delta_T Time between k and k+1 in s
	  */
	 void Predict();
	
	 /**
	  * Updates the state by using standard Kalman Filter equations
	  * @param z The measurement at k+1
	  */
	 void Update(const Eigen::VectorXd &z);
	
	 /**
	  * Updates the state by using Extended Kalman Filter equations
	  * @param z The measurement at k+1
	  */
	 void UpdateEKF(const Eigen::VectorXd &z);
	
	 /**
	 * General kalman filter update operations
	 * @param y the update prediction error
	 */
	 void UpdateRoutine(const Eigen::VectorXd &y);

};

#endif /* KALMAN_FILTER_H_ */

初始化时,需要初始化状态向量 x x x,状态转移矩阵 F F F,状态协方差矩阵 P P P,测量矩阵 H H H,过程协方差矩阵 Q Q Q,测量协方差矩阵 R R R,代码如下:

void KalmanFilter::Init(VectorXd &x_in, MatrixXd &P_in, MatrixXd &F_in,
						MatrixXd &H_in, MatrixXd &R_in, MatrixXd &Q_in) {
	x_ = x_in;
	P_ = P_in;
	F_ = F_in;
	H_ = H_in;
	R_ = R_in;
	Q_ = Q_in;
}

(2)预测

然后是预测部分,根据卡尔曼滤波原理,预测公式为:
x ′ = F x + u x'=Fx+u x=Fx+u
这里的 x x x为状态向量,其乘以状态转移矩阵 F F F,再加上外部影响 u u u,即可得到预测状态向量 x ′ x' x

对于激光雷达来说,其状态向量 x x x为4维向量, x , y x,y x,y方向上的位置和速度:
x = [ x y v x v y ] x=\begin{bmatrix}x\\ y\\v_x\\v_y\end{bmatrix} x= xyvxvy
假设障碍物做匀速运动,则在经过 δ t \delta{t} δt时间后,状态向量为:
x ′ = [ x + v x ∗ δ t y + v y ∗ δ t v x v y ] x'=\begin{bmatrix}{x+v_x*\delta{t}} \\ {y+v_y*\delta{t}}\\v_x\\v_y\end{bmatrix} x= x+vxδty+vyδtvxvy
如果用矩阵表示的话,则状态转移公式为:
[ x + v x ∗ δ t y + v y ∗ δ t v x v y ] = [ 1 0 δ t 0 0 1 0 δ t 0 0 1 0 0 0 0 1 ] ∗ [ x y v x v y ] \begin{bmatrix}{x+v_x*\delta{t}} \\ {y+v_y*\delta{t}}\\v_x\\v_y\end{bmatrix}=\begin{bmatrix}1&0&\delta{t}&0\\0&1&0&\delta{t}\\0&0&1&0\\0&0&0&1\end{bmatrix}*\begin{bmatrix}x \\ y \\ v_x \\v_y \end{bmatrix} x+vxδty+vyδtvxvy = 10000100δt0100δt01 xyvxvy
因此,状态转移矩阵为 ( 4 , 4 ) (4,4) (4,4)的矩阵,我们可以先将 δ t \delta{t} δt定义为1,计算时再根据实际情况修改:

  // Initial transition matrix F_
  ekf_.F_ = MatrixXd(4, 4);
  ekf_.F_ << 1, 0, 1, 0,
			 0, 1, 0, 1,
			 0, 0, 1, 0,
			 0, 0, 0, 1;

然后是预测部分的第二个公式:
P ′ = F P F T + Q P'=FPF^T+Q P=FPFT+Q
在公式中, P P P为状态协方差矩阵,表示系统的不确定性,开始时系统的不确定性会很大,但随着输入的数据越来越多,系统会趋于稳定。这里还用到了过程协方差矩阵 Q Q Q,这表示系统受外部环境影响的情况,如突然遇到爬坡或路面有凹坑的情况。

对于激光雷达来说,无法测量障碍物的速度,因此,测量位置的不确定性要小于速度不确定性。因此这里的 P P P可以初始化为:

// Initialize state covariance matrix P
  ekf_.P_ = MatrixXd(4, 4);
  ekf_.P_ << 1,	0,	0,	 0,
			 0,	1,	0,	 0,
			 0,	0, 1000, 0,
			 0,	0, 0,	1000;

Q Q Q代码如下,这里也是可以调整的。

 // Initialize process noise covariance matrix
  ekf_.Q_ = MatrixXd(4, 4); 
  ekf_.Q_ << 0, 0, 0, 0,
			 0, 0, 0, 0,
			 0, 0, 0, 0,
			 0, 0, 0, 0;

这样我们就完成了预测部分,最终我们写为一个函数Predict()代码如下:

void KalmanFilter::Predict() {

	// Predict the state
	x_ = F_ * x_;
	MatrixXd Ft = F_.transpose();
	P_ = F_ * P_ * Ft + Q_;
}

(3)更新

最后是卡尔曼滤波的更新部分,更新部分第一个公式为:
y = z − H x ′ y=z-Hx' y=zHx
上式计算了测量值 z z z与预测值 x ′ x' x之间的差值 y y y

由于激光雷达测量值为 ( x m , y m ) (x_m,y_m) (xmym),与状态向量维度不同。在与状态向量进行计算时,需要乘以一个测量矩阵 H H H变为同维的状态量,上式用矩阵表示为:
[ δ x δ y ] = [ x m y m ] − [ 1 0 0 0 0 1 0 0 ] ∗ [ x + v x ∗ δ t y + v y ∗ δ t v x v y ] \begin{bmatrix}{\delta{x}} \\ \delta{y}\end{bmatrix}=\begin{bmatrix}x_m\\y_m\end{bmatrix}-\begin{bmatrix}1&0&0&0 \\0&1&0&0 \end{bmatrix}*\begin{bmatrix} {x+v_x*\delta{t}} \\ {y+v_y*\delta{t}}\\v_x\\v_y\end{bmatrix} [δxδy]=[xmym][10010000] x+vxδty+vyδtvxvy
因此这里的测量矩阵 H H H为:

 // Lidar - measurement matrix
  H_laser_ = MatrixXd(2, 4);
  H_laser_ << 1, 0, 0, 0,
			  0, 1, 0, 0;

然后是下面两个公式:
S = H P ′ H T + R K = P ′ H T S − 1 S=HP'H^T+R\\K=P'H^TS^{-1} S=HPHT+RK=PHTS1
这两个公式是求卡尔曼增益 K K K,实际就是 y y y的权重。

最后还有两个公式:
x = x ′ + K y P = ( I − K H ) P ′ x=x'+Ky\\P=(I-KH)P' x=x+KyP=(IKH)P
这样就得到了当前帧的状态向量与状态协方差矩阵。然后根据新的状态向量 x x x和协方差矩阵 P P P可以计算下一帧的状态向量,如此反复。
这里定义测量协方差矩阵 R R R为:

 // Initialize measurement covariance matrix - laser
  R_laser_ = MatrixXd(2, 2);
  R_laser_ << 0.0225, 0,
			  0, 0.0225;

至此,卡尔曼滤波中五个重要矩阵 F , P , Q , H , R F,P,Q,H,R FPQHR就已经定义完了,更新部分代码为:

void KalmanFilter::Update(const VectorXd &z) {

	VectorXd z_pred = H_ * x_;
	VectorXd y = z - z_pred;

	UpdateRoutine(y);
}

void KalmanFilter::UpdateRoutine(const VectorXd &y) {

	MatrixXd Ht = H_.transpose();
	MatrixXd S = H_ * P_ * Ht + R_;
	MatrixXd Si = S.inverse();

	// Compute Kalman gain
	MatrixXd K = P_ * Ht * Si;

	// Update estimate
	x_ = x_ + K * y;
	long x_size = x_.size();
	MatrixXd I = MatrixXd::Identity(x_size, x_size);
	P_ = (I - K * H_) * P_;
}

至此,线性卡尔曼滤波部分就已经完成了,下一节我们实现非线性卡尔曼滤波。


4.2 非线性卡尔曼滤波实现

非线性卡尔曼滤波是用于解决非线性问题,与线性卡尔曼滤波相同,非线性卡尔曼滤波也分为初始化、预测、更新三部分。

初始化与线性卡尔曼滤波相似,我们仍然使用KalmanFilter类构造一个追踪器。

(1)预测

这里再回顾下卡尔曼滤波预测中的两个公式:
x ′ = F x + u P ′ = F P F T + Q x'=Fx+u\\P'=FPF^T+Q x=Fx+uP=FPFT+Q
这里仍然使用第一次测量值作为初始状态,状态转移矩阵为 F F F,状态协方差矩阵为 P P P,过程协方差矩阵为 Q Q Q,与上一节的初始化相同。


(2)更新

回顾上一节,更新部分第一个公式为:
y = z − H x ′ y=z-Hx' y=zHx
但是这里我们使用的是毫米波雷达数据,测量得到的数据为:距离 ρ \rho ρ方向夹角 φ \varphi φ,以及径向速度 ρ ˙ \dot{\rho} ρ˙

这里得到的信息为极坐标信息,需要转换为直角坐标距离。我们将上式写成矩阵形式为:
y = [ ρ φ ρ ˙ ] − [ ρ x 2 + ρ y 2 a r c t a n ( ρ y ρ x ) ρ x v x + ρ y v y ρ x 2 + ρ y 2 ] y=\begin{bmatrix}\rho\\\\\varphi\\\\\dot{\rho}\end{bmatrix}-\begin{bmatrix}\sqrt{\rho_x^2+\rho_y^2} \\\\arctan(\frac{\rho_y}{\rho_x})\\\\\frac{\rho_xv_x+\rho_yv_y}{\sqrt{\rho_x^2+\rho_y^2} } \end{bmatrix} y= ρφρ˙ ρx2+ρy2 arctan(ρxρy)ρx2+ρy2 ρxvx+ρyvy

其中, ρ x , ρ y \rho_x,\rho_y ρxρy为预测后的位置, v x , v y v_x,v_y vxvy为预测后的速度。这里的位置转换,速度转换为非线性转换

然后是卡尔曼滤波的后面两个公式:
S = H P ′ H T + R K = P ′ H T S − 1 S=HP'H^T+R\\K=P'H^TS^{-1} S=HPHT+RK=PHTS1

这里在求卡尔曼增益时,需要知道测量矩阵 H H H,因为我们测量数据为 ( 3 , 1 ) (3,1) (3,1)的列向量,而状态向量为 ( 4 , 1 ) (4,1) (4,1)的列向量。因此测量矩阵的维度为 ( 3 , 4 ) (3,4) (3,4)。我们可以写成下面这个形式:
H x ′ = [ ρ x 2 + ρ y 2 a r c t a n ( ρ y ρ x ) ρ x v x ρ y v y ρ x 2 + ρ y 2 ] = [ H 00 H 01 H 02 H 03 H 10 H 11 H 12 H 13 H 20 H 21 H 22 H 23 ] ∗ [ ρ x ρ y v x v y ] Hx'=\begin{bmatrix}\sqrt{\rho_x^2+\rho_y^2} \\\\arctan(\frac{\rho_y}{\rho_x})\\\\\frac{\rho_xv_x\rho_yv_y}{\sqrt{\rho_x^2+\rho_y^2} } \end{bmatrix}=\begin{bmatrix}H_{00}&H_{01}&H_{02}&H_{03}\\H_{10}&H_{11}&H_{12}&H_{13}\\H_{20}&H_{21}&H_{22}&H_{23}\end{bmatrix}*\begin{bmatrix}\rho_x\\\rho_y\\v_x\\v_y\end{bmatrix} Hx= ρx2+ρy2 arctan(ρxρy)ρx2+ρy2 ρxvxρyvy = H00H10H20H01H11H21H02H12H22H03H13H23 ρxρyvxvy
显然,上式两边转化为非线性转换,那么如何才能将非线性函数用近似线性函数表达呢?

这里我们使用泰勒公式来近似,近似后的泰勒公式为:
h ( x ) ≈ h ( x 0 ) + ∂ h ( x 0 ) ∂ x ( x − x 0 ) h(x)\approx h(x_0)+\frac{\partial h(x_0)}{\partial x}(x-x_0) h(x)h(x0)+xh(x0)(xx0)
这里忽略了二次以上的高阶项。对 x x x求导后的项为雅克比公式。这里,雅克比公式就是我们的测量矩阵 H H H

最终测量矩阵为:
H = [ p x ρ x 2 + ρ y 2 p y ρ x 2 + ρ y 2 0 0 − p y ρ x 2 + ρ y 2 − p x ρ x 2 + ρ y 2 0 0 p y ( v x ρ y − v y ρ x ) ( ρ x 2 + ρ y 2 ) 3 / 2 p x ( v y ρ x − v x ρ y ) ( ρ x 2 + ρ y 2 ) 3 / 2 p x ρ x 2 + ρ y 2 p y ρ x 2 + ρ y 2 ] H = \begin{bmatrix} \frac{p_x}{\sqrt{\rho_x^2+\rho_y^2}} & \frac{p_y}{\sqrt{\rho_x^2+\rho_y^2}} & 0& 0 \\\\ \frac{-p_y}{\rho_x^2+\rho_y^2} & \frac{-p_x}{\rho_x^2+\rho_y^2} & 0& 0 \\\\ \frac{p_y(v_x\rho_y-v_y\rho_x)}{(\rho_x^2+\rho_y^2)^{3/2}} & \frac{p_x(v_y\rho_x-v_x\rho_y)}{(\rho_x^2+\rho_y^2)^{3/2}} & \frac{p_x}{\sqrt{\rho_x^2+\rho_y^2}} & \frac{p_y}{\sqrt{\rho_x^2+\rho_y^2}} \end{bmatrix} H= ρx2+ρy2 pxρx2+ρy2py(ρx2+ρy2)3/2py(vxρyvyρx)ρx2+ρy2 pyρx2+ρy2px(ρx2+ρy2)3/2px(vyρxvxρy)00ρx2+ρy2 px00ρx2+ρy2 py
这里对测量矩阵进行初始化 H H H

  // Radar - jacobian matrix
  Hj_ = MatrixXd(3, 4);
  Hj_ << 0, 0, 0, 0,
	     0, 0, 0, 0,
		 0, 0, 0, 0;

测量噪声协方差矩阵 R R R为:

  //measurement covariance matrix - radar
  R_radar_ = MatrixXd(3, 3);
  R_radar_ << 0.09,	0,		0,
			  0,	0.0009, 0,
			  0,	0,		0.09;

下面是雅克比公式计算函数:

MatrixXd Tools::CalculateJacobian(const VectorXd& x_state) {

	MatrixXd Hj(3, 4);
	
	// Unroll state parameters
	float px = x_state(0);
	float py = x_state(1);
	float vx = x_state(2);
	float vy = x_state(3);
	
	// Pre-compute some term which recur in the Jacobian
	float c1 = px * px + py * py;
	float c2 = sqrt(c1);
	float c3 = c1 * c2;
	
	// Sanity check to avoid division by zero
	if (std::abs(c1) < 0.0001) {
		std::cout << "Error in CalculateJacobian. Division by zero." << std::endl;
		return Hj;
	}
	
	// Actually compute Jacobian matrix
	Hj << (px / c2),				(py / c2),					0,			0,
		-(py / c1),					(px / c1),					0,			0,
		py * (vx*py - vy*px) / c3,	px * (vy*px - vx*py) / c3,	px / c2,	py / c2;
	
	return Hj;

}

最后还有两个公式:
x = x ′ + K y P = ( I − K H ) P ′ x=x'+Ky\\P=(I-KH)P' x=x+KyP=(IKH)P
最终得到更新后的状态向量 x x x,以及新的状态协方差矩阵 P P P

至此,非线性卡尔曼滤波部分就已经完成了,重点是测量矩阵H的计算。


4.3 数据融合

完成了毫米波雷达与激光雷达的预测与更新,现在是对二者进行融合。

下图所示为毫米波雷达与激光雷达数据融合的整体框架。
在这里插入图片描述首先是读入传感器数据,选择第一帧作为初始值。对于之后的帧,进行状态预测,然后根据传感器类型进行更新,最后得到跟踪后的状态向量。

这里定义了一个数据融合类FusionEKF

class FusionEKF {

public:

	/* Constructor. */
	 FusionEKF();
	
	 /* Destructor. */
	 virtual ~FusionEKF();
	
	 /* Run the whole flow of the Kalman Filter from here. */
	 void ProcessMeasurement(const MeasurementPackage &measurement_pack);
	
	 /* Kalman Filter update and prediction math lives in here. */
	 KalmanFilter ekf_;

private:

	// check whether the tracking toolbox was initialized or not (first measurement)
	 bool is_initialized_;
	
	 // previous timestamp
	 long long previous_timestamp_;
	
	 // tool object used to compute Jacobian and RMSE
	 Tools tools;
	
	 Eigen::MatrixXd R_laser_;
	 Eigen::MatrixXd R_radar_;
	 Eigen::MatrixXd H_laser_;
	 Eigen::MatrixXd Hj_;
	
	 float noise_ax;
	 float noise_ay;
};

上面有一个很重要的处理函数ProcessMeasurement(),是对上图数据融合的代码实现。

void FusionEKF::ProcessMeasurement(const MeasurementPackage &measurement_pack) {

	 /*****************************************************************************
	  *  Initialization
	  ****************************************************************************/
	 if (!is_initialized_){
	 	if (measurement_pack.sensor_type_ == MeasurementPackage::RADAR) {
			// Extract values from measurement
			float rho		= measurement_pack.raw_measurements_(0);
			float phi		= measurement_pack.raw_measurements_(1);
			float rho_dot	= measurement_pack.raw_measurements_(2);
			// Convert from polar to cartesian coordinates
			float px = rho * cos(phi);
			float py = rho * sin(phi);
			float vx = rho_dot * cos(phi);
			float vy = rho_dot * sin(phi);
	
			// Initialize state
			ekf_.x_ << px, py, vx, vy;
	   	}
	   	else if (measurement_pack.sensor_type_ == MeasurementPackage::LASER) {
	
			// Extract values from measurement
			float px = measurement_pack.raw_measurements_(0);
			float py = measurement_pack.raw_measurements_(1);
	
			// Initialize state
			ekf_.x_ << px, py, 0.0, 0.0;
	   	}
	
		// Update last measurement
		previous_timestamp_ = measurement_pack.timestamp_;
	
		// Done initializing, no need to predict or update
	    is_initialized_ = true;
	   return;
	 }
	
	 /*****************************************************************************
	  *  Prediction
	  ****************************************************************************/
	
	 // Compute elapsed time from last measurement
	 float dt = (measurement_pack.timestamp_ - previous_timestamp_) / 1000000.0;
	
	 // Update last measurement
	 previous_timestamp_ = measurement_pack.timestamp_;
	
	 // Update state transition matrix F (according to elapsed time dt)
	 ekf_.F_(0, 2) = dt;
	 ekf_.F_(1, 3) = dt;
	
	 // Compute process noise covariance matrix
	 float dt_2 = dt * dt;
	 float dt_3 = dt_2 * dt;
	 float dt_4 = dt_3 * dt;
	
	 ekf_.Q_	<<	dt_4 / 4 * noise_ax,	0,						dt_3 / 2 * noise_ax,	0,
				0,						dt_4 / 4 * noise_ay,	0,						dt_3 / 2 * noise_ay,
				dt_3 / 2 * noise_ax,	0,						dt_2 * noise_ax,		0,
				0,						dt_3 / 2 * noise_ay,	0,						dt_2 * noise_ay;
	
	 ekf_.Predict();
	
	 /*****************************************************************************
	  *  Update
	  ****************************************************************************/
	
	 if (measurement_pack.sensor_type_ == MeasurementPackage::RADAR) {
	 	// Radar updates
	    ekf_.R_ = R_radar_;
	    ekf_.H_ = tools.CalculateJacobian(ekf_.x_);
	    ekf_.UpdateEKF(measurement_pack.raw_measurements_);
	 } else {
	    // Laser updates
	    ekf_.R_ = R_laser_;
	    ekf_.H_ = H_laser_;
	    ekf_.Update(measurement_pack.raw_measurements_);
	 }
	
	 // print the output
	 cout << "x_ = " << ekf_.x_ << endl;
	 cout << "P_ = " << ekf_.P_ << endl;
}

至此,激光雷达与毫米波雷达融合部分就已经完成了。

而在实际开发时,一辆ADAS汽车通常会安装多个毫米波雷达,包括前雷达,后雷达,角雷达;有的还会装有激光雷达;本文没有考虑相机,而相机是ADAS汽车最常使用的传感器。在对这些传感器进行数据融合时还需要考虑时间同步空间同步问题。

以上只是对汽车外部的障碍物进行定位,而如果汽车想对自身进行定位的话,通常需要安装惯性测量单元IMU和GPS传感器,在下一篇博客中将会进行介绍。

  • 17
    点赞
  • 164
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
### 回答1: 无人驾驶算法中的多传感器融合MSF算法是一种将多个传感器数据进行融合的方法。传感器无人驾驶系统中获取环境信息的重要组成部分,包括相机、激光雷达、毫米波雷达等。这些传感器各自具有不同的特性和数据输出,通过将它们数据融合,可以提高无人驾驶系统的环境感知和决策能力。 MSF算法主要由以下步骤组成: 1. 数据预处理:对不同传感器收集到的原始数据进行预处理,包括去除噪声、校准等。 2. 数据对齐:将不同传感器收集到的数据进行时间和空间上的对齐,确保数据在同一时刻和坐标系下进行融合。 3. 特征提取:从每个传感器数据中提取特征信息,用于后续的数据融合和决策过程。 4. 数据融合:将不同传感器提取到的特征信息进行融合,可以采用概率统计方法、滤波方法等,得到更准确和可靠的环境感知结果。 5. 决策与控制:根据融合后的环境感知结果,进行路径规划、障碍物避障等决策与控制操作。 多传感器融合MSF算法具有以下优点: 1. 提高环境感知能力:通过融合多个传感器数据,可以获取更全面和准确的环境信息,提高无人驾驶系统对车辆、行人、障碍物等的感知能力。 2. 提高决策精度:融合多个传感器数据可以减少单一传感器的局限性和误差,提高决策的准确性和可靠性。 3. 增强鲁棒性:多传感器融合可以减少特定环境条件下的干扰,提高系统的鲁棒性和稳定性。 4. 提高安全性:多传感器融合可以增加对潜在危险情况的检测和预警能力,提升无人驾驶系统的安全性。 因此,多传感器融合MSF算法在无人驾驶算法中起着重要的作用,它的应用将进一步推动无人驾驶技术的发展和应用。 ### 回答2: 无人驾驶算法的多传感器融合是指通过将多个不同类型的传感器数据进行融合和协同处理,来提升无人驾驶系统的感知和决策能力的一种技术手段。其中,多传感器融合msf算法是一种常用的传感器数据融合算法。 多传感器融合msf算法的核心思想是通过将不同传感器所获取的信息进行整合,从而达到对环境的更全面、更准确的感知,并进一步实现智能的决策和规划。该算法主要包括三个关键步骤:传感器数据预处理、数据融合和对象跟踪与预测。 首先,在传感器数据预处理阶段,不同传感器的原始数据需要进行校准、滤波和对齐等处理,以确保数据的准确性和一致性。其次,在数据融合过程中,需要将来自不同传感器的信息进行融合,利用机器习和统计方法来估计和推理目标物体的状态和属性。最后,在对象跟踪与预测阶段,算法通过对目标物体的运动轨迹进行建模和预测,实现对目标物体的准确跟踪和预测。 多传感器融合msf算法在无人驾驶领域具有重要的应用价值。通过融合多种传感器的信息,可以提高无人驾驶车辆对复杂道路和复杂交通环境的感知能力,进而实现更精准和安全的驾驶决策。此外,多传感器融合msf算法还可以提高无人驾驶系统的鲁棒性和可靠性,降低传感器误判和漏检的概率,提高系统的可用性和稳定性。 总之,无人驾驶算法的多传感器融合msf算法通过整合多种传感器的信息来提升无人驾驶系统的感知和决策能力。该算法具有广泛的应用前景,可以为无人驾驶技术的发展和推广提供重要的支持。 ### 回答3: 无人驾驶算法中的多传感器融合算法MSF(Multi-Sensor Fusion)是一种通过结合多种传感器的信息来提高无人驾驶系统感知能力的算法。传统的无人驾驶系统通常会使用多种传感器,例如摄像头、激光雷达、毫米波雷达等,来感知周围环境和障碍物。 MSF算法的核心思想是将不同传感器数据进行融合,以获得更全面、准确的环境感知结果。一般而言,不同传感器所感知到的信息具有互补性,通过综合利用它们的优势可以提高无人驾驶系统对环境的理解和对障碍物的识别能力。 MSF算法的实现需要解决多个关键问题。首先,需要进行传感器数据的校准和配准,确保不同传感器数据具有一致性。其次,需要进行数据融合,将不同传感器的信息进行合并,得到更全面的环境模型。在融合过程中,还需要考虑各个传感器的精度、置信度等因素,以权衡不同传感器数据的重要性。最后,需要对融合后的数据进行处理和分析,提取出对无人驾驶决策和控制具有重要意义的信息。 通过使用MSF算法,无人驾驶系统可以获得更准确的环境感知结果,提高系统对路况和障碍物的识别能力,从而更好地做出决策和规划路径。然而,MSF算法的实现需要考虑传感器的数量、类型和布局,以及数据的同步和处理等技术细节。因此,对于无人驾驶算法研究人员来说,研究和改进MSF算法是提高无人驾驶系统性能和可靠性的重要课题之一。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值