robot_localization中EKF源码介绍

/** Copyright (c) 2014, 2015, 2016 Charles River Analytics, Inc.* Copyright (c) 2017, Locus Robotics, Inc.* All rights reserved.** Redistribution and use in source and binary forms, with or without* modification, are permitted provided that the following conditions* are met:** 1. Redistributions of source code must retain the above copyright* notice, this list of conditions and the following disclaimer.* 2. 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.* 3. Neither the name of the copyright holder 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 OR CONTRIBUTORS 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.*/
//其参考的导航坐标系为东北天坐标系
#include <robot_localization/ekf.hpp>
#include <robot_localization/filter_common.hpp>
#include <angles/angles.h>
#include <Eigen/Dense>
#include <rclcpp/duration.hpp>
#include <vector>namespace robot_localization
{
Ekf::Ekf()
: FilterBase()
{}Ekf::~Ekf() {}
//扩展卡尔曼滤波的量测更新
void Ekf::correct(const Measurement & measurement)
{FB_DEBUG("---------------------- Ekf::correct ----------------------\n" <<"State is:\n" <<state_ <<"\n""Topic is:\n" <<measurement.topic_name_ <<"\n""Measurement is:\n" <<measurement.measurement_ <<"\n""Measurement topic name is:\n" <<measurement.topic_name_ <<"\n\n""Measurement covariance is:\n" <<measurement.covariance_ << "\n");// We don't want to update everything, so we need to build matrices that only// update the measured parts of our state vector. Throughout prediction and// correction, we attempt to maximize efficiency in Eigen.// First, determine how many state vector values we're updatingstd::vector<size_t> update_indices;for (size_t i = 0; i < measurement.update_vector_.size(); ++i) {if (measurement.update_vector_[i]) {// Handle nan and inf values in measurementsif (std::isnan(measurement.measurement_(i))) {FB_DEBUG("Value at index " << i <<" was nan. Excluding from update.\n");} else if (std::isinf(measurement.measurement_(i))) {FB_DEBUG("Value at index " << i <<" was inf. Excluding from update.\n");} else {update_indices.push_back(i);}}}FB_DEBUG("Update indices are:\n" << update_indices << "\n");size_t update_size = update_indices.size();//设置状态量的向量和相关矩阵 Eigen::VectorXd是表示的是库Eigen的向量,而MatrixXd为其的矩阵// Now set up the relevant matricesEigen::VectorXd state_subset(update_size);       // x (in most literature)Eigen::VectorXd measurement_subset(update_size);  // zEigen::MatrixXd measurement_covariance_subset(update_size, update_size);  // REigen::MatrixXd state_to_measurement_subset(update_size, state_.rows());  // H 测量矩阵Eigen::MatrixXd kalman_gain_subset(state_.rows(), update_size);          // K Eigen::VectorXd innovation_subset(update_size);  // z - Hx 观测误差//将所有矩阵、向量初始化为0state_subset.setZero();measurement_subset.setZero();measurement_covariance_subset.setZero();state_to_measurement_subset.setZero();kalman_gain_subset.setZero();innovation_subset.setZero();// Now build the sub-matrices from the full-sized matricesfor (size_t i = 0; i < update_size; ++i) {measurement_subset(i) = measurement.measurement_(update_indices[i]);state_subset(i) = state_(update_indices[i]);for (size_t j = 0; j < update_size; ++j) {measurement_covariance_subset(i, j) =measurement.covariance_(update_indices[i], update_indices[j]);}// Handle negative (read: bad) covariances in the measurement. Rather// than exclude the measurement or make up a covariance, just take// the absolute value.//设置量测协方差矩阵//检查量测协方差矩阵是否为正,若不为正,则通过绝对值函数fabs将其改为正,防止矩阵奇异if (measurement_covariance_subset(i, i) < 0) {FB_DEBUG("WARNING: Negative covariance for index " <<i << " of measurement (value is" <<measurement_covariance_subset(i, i) <<"). Using absolute value...\n");measurement_covariance_subset(i, i) =::fabs(measurement_covariance_subset(i, i));}// If the measurement variance for a given variable is very// near 0 (as in e-50 or so) and the variance for that// variable in the covariance matrix is also near zero, then// the Kalman gain computation will blow up. Really, no// measurement can be completely without error, so add a small// amount in that case.if (measurement_covariance_subset(i, i) < 1e-9) {FB_DEBUG("WARNING: measurement had very small error covariance for index " <<update_indices[i] <<". Adding some noise to maintain filter stability.\n");measurement_covariance_subset(i, i) = 1e-9;}}// The state-to-measurement function, h, will now be a measurement_size x// full_state_size matrix, with ones in the (i, i) locations of the values to// be updated//设置量测矩阵H的值for (size_t i = 0; i < update_size; ++i) {state_to_measurement_subset(i, update_indices[i]) = 1;}FB_DEBUG("Current state subset is:\n" <<state_subset << "\nMeasurement subset is:\n" <<measurement_subset << "\nMeasurement covariance subset is:\n" <<measurement_covariance_subset <<"\nState-to-measurement subset is:\n" <<state_to_measurement_subset << "\n");// (1) Compute the Kalman gain: K = (PH') / (HPH' + R) 计算卡尔曼增益//transpose()转置函数 inverse()求逆函数 noalias()为防止左右赋值时出现混淆Eigen::MatrixXd pht =estimate_error_covariance_ * state_to_measurement_subset.transpose();Eigen::MatrixXd hphr_inverse =(state_to_measurement_subset * pht + measurement_covariance_subset).inverse();kalman_gain_subset.noalias() = pht * hphr_inverse;innovation_subset = (measurement_subset - state_subset);// Wrap angles in the innovationfor (size_t i = 0; i < update_size; ++i) {if (update_indices[i] == StateMemberRoll ||update_indices[i] == StateMemberPitch ||update_indices[i] == StateMemberYaw){innovation_subset(i) = ::angles::normalize_angle(innovation_subset(i));//调用ROS中angles的normalize_angle,将角度装为弧度范围为【-PI,PI】}}// (2) Check Mahalanobis distance between mapped measurement and state. 检查状态值与测量值之间的马氏距离:Mahalanobis距离是数据所在的空间的协方差的度量if (checkMahalanobisThreshold(innovation_subset, hphr_inverse,measurement.mahalanobis_thresh_)){// (3) Apply the gain to the difference between the state and measurement: x 利用当前观测与观测结果获得最终融合结果// x= x + K(z - Hx)state_.noalias() += kalman_gain_subset * innovation_subset;// (4) Update the estimate error covariance using the Joseph form: P=(I -KH)P(I - KH)' + KRK'//获得最终噪声的协方差矩阵Eigen::MatrixXd gain_residual = identity_;//单位矩阵gain_residual.noalias() -= kalman_gain_subset * state_to_measurement_subset;estimate_error_covariance_ =gain_residual * estimate_error_covariance_ * gain_residual.transpose();//(I -KH)P(I - KH)'estimate_error_covariance_.noalias() += kalman_gain_subset *measurement_covariance_subset *kalman_gain_subset.transpose();//(I -KH)P(I - KH)' + KRK'// Handle wrapping of angleswrapStateAngles();FB_DEBUG("Kalman gain subset is:\n" <<kalman_gain_subset << "\nInnovation is:\n" <<innovation_subset << "\nCorrected full state is:\n" <<state_ << "\nCorrected full estimate error covariance is:\n" <<estimate_error_covariance_ <<"\n\n---------------------- /Ekf::correct ----------------------\n");}
}
//下面是扩展卡尔曼滤波的时间更新
void Ekf::predict(const rclcpp::Time & reference_time,const rclcpp::Duration & delta)
{const double delta_sec = filter_utilities::toSec(delta);//设置离散时间间隔FB_DEBUG("---------------------- Ekf::predict ----------------------\n" <<"delta is " << filter_utilities::toSec(delta) << "\n" <<"state is " << state_ << "\n");double roll = state_(StateMemberRoll);double pitch = state_(StateMemberPitch);double yaw = state_(StateMemberYaw);double x_vel = state_(StateMemberVx);double y_vel = state_(StateMemberVy);double z_vel = state_(StateMemberVz);double pitch_vel = state_(StateMemberVpitch);double yaw_vel = state_(StateMemberVyaw);double x_acc = state_(StateMemberAx);double y_acc = state_(StateMemberAy);double z_acc = state_(StateMemberAz);// We'll need these trig calculations a lot.double sp = ::sin(pitch);double cp = ::cos(pitch);double cpi = 1.0 / cp;double tp = sp * cpi;double sr = ::sin(roll);double cr = ::cos(roll);double sy = ::sin(yaw);double cy = ::cos(yaw);prepareControl(reference_time, delta);//X是在世界坐标系下,X的一阶导和二阶导是在载体坐标系下,因此需要根据k-1时刻的姿态转换到世界坐标系下// Prepare the transfer functiontransfer_function_(StateMemberX, StateMemberVx) = cy * cp * delta_sec;transfer_function_(StateMemberX, StateMemberVy) =(cy * sp * sr - sy * cr) * delta_sec;transfer_function_(StateMemberX, StateMemberVz) =(cy * sp * cr + sy * sr) * delta_sec;transfer_function_(StateMemberX, StateMemberAx) =0.5 * transfer_function_(StateMemberX, StateMemberVx) * delta_sec;transfer_function_(StateMemberX, StateMemberAy) =0.5 * transfer_function_(StateMemberX, StateMemberVy) * delta_sec;transfer_function_(StateMemberX, StateMemberAz) =0.5 * transfer_function_(StateMemberX, StateMemberVz) * delta_sec;transfer_function_(StateMemberY, StateMemberVx) = sy * cp * delta_sec;transfer_function_(StateMemberY, StateMemberVy) =(sy * sp * sr + cy * cr) * delta_sec;transfer_function_(StateMemberY, StateMemberVz) =(sy * sp * cr - cy * sr) * delta_sec;transfer_function_(StateMemberY, StateMemberAx) =0.5 * transfer_function_(StateMemberY, StateMemberVx) * delta_sec;transfer_function_(StateMemberY, StateMemberAy) =0.5 * transfer_function_(StateMemberY, StateMemberVy) * delta_sec;transfer_function_(StateMemberY, StateMemberAz) =0.5 * transfer_function_(StateMemberY, StateMemberVz) * delta_sec;transfer_function_(StateMemberZ, StateMemberVx) = -sp * delta_sec;transfer_function_(StateMemberZ, StateMemberVy) = cp * sr * delta_sec;transfer_function_(StateMemberZ, StateMemberVz) = cp * cr * delta_sec;transfer_function_(StateMemberZ, StateMemberAx) =0.5 * transfer_function_(StateMemberZ, StateMemberVx) * delta_sec;transfer_function_(StateMemberZ, StateMemberAy) =0.5 * transfer_function_(StateMemberZ, StateMemberVy) * delta_sec;transfer_function_(StateMemberZ, StateMemberAz) =0.5 * transfer_function_(StateMemberZ, StateMemberVz) * delta_sec;transfer_function_(StateMemberRoll, StateMemberVroll) = delta_sec;transfer_function_(StateMemberRoll, StateMemberVpitch) = sr * tp * delta_sec;transfer_function_(StateMemberRoll, StateMemberVyaw) = cr * tp * delta_sec;transfer_function_(StateMemberPitch, StateMemberVpitch) = cr * delta_sec;transfer_function_(StateMemberPitch, StateMemberVyaw) = -sr * delta_sec;transfer_function_(StateMemberYaw, StateMemberVpitch) = sr * cpi * delta_sec;transfer_function_(StateMemberYaw, StateMemberVyaw) = cr * cpi * delta_sec;transfer_function_(StateMemberVx, StateMemberAx) = delta_sec;transfer_function_(StateMemberVy, StateMemberAy) = delta_sec;transfer_function_(StateMemberVz, StateMemberAz) = delta_sec;// Prepare the transfer function Jacobian. This function is analytically// derived from the transfer function.//求解雅克比矩阵double x_coeff = 0.0;double y_coeff = 0.0;double z_coeff = 0.0;double one_half_at_squared = 0.5 * delta_sec * delta_sec;y_coeff = cy * sp * cr + sy * sr;z_coeff = -cy * sp * sr + sy * cr;double dFx_dR = (y_coeff * y_vel + z_coeff * z_vel) * delta_sec +(y_coeff * y_acc + z_coeff * z_acc) * one_half_at_squared;double dFR_dR = 1.0 + (cr * tp * pitch_vel - sr * tp * yaw_vel) * delta_sec;x_coeff = -cy * sp;y_coeff = cy * cp * sr;z_coeff = cy * cp * cr;double dFx_dP =(x_coeff * x_vel + y_coeff * y_vel + z_coeff * z_vel) * delta_sec +(x_coeff * x_acc + y_coeff * y_acc + z_coeff * z_acc) *one_half_at_squared;double dFR_dP =(cpi * cpi * sr * pitch_vel + cpi * cpi * cr * yaw_vel) * delta_sec;x_coeff = -sy * cp;y_coeff = -sy * sp * sr - cy * cr;z_coeff = -sy * sp * cr + cy * sr;double dFx_dY =(x_coeff * x_vel + y_coeff * y_vel + z_coeff * z_vel) * delta_sec +(x_coeff * x_acc + y_coeff * y_acc + z_coeff * z_acc) *one_half_at_squared;y_coeff = sy * sp * cr - cy * sr;z_coeff = -sy * sp * sr - cy * cr;double dFy_dR = (y_coeff * y_vel + z_coeff * z_vel) * delta_sec +(y_coeff * y_acc + z_coeff * z_acc) * one_half_at_squared;double dFP_dR = (-sr * pitch_vel - cr * yaw_vel) * delta_sec;x_coeff = -sy * sp;y_coeff = sy * cp * sr;z_coeff = sy * cp * cr;double dFy_dP =(x_coeff * x_vel + y_coeff * y_vel + z_coeff * z_vel) * delta_sec +(x_coeff * x_acc + y_coeff * y_acc + z_coeff * z_acc) *one_half_at_squared;x_coeff = cy * cp;y_coeff = cy * sp * sr - sy * cr;z_coeff = cy * sp * cr + sy * sr;double dFy_dY =(x_coeff * x_vel + y_coeff * y_vel + z_coeff * z_vel) * delta_sec +(x_coeff * x_acc + y_coeff * y_acc + z_coeff * z_acc) *one_half_at_squared;y_coeff = cp * cr;z_coeff = -cp * sr;double dFz_dR = (y_coeff * y_vel + z_coeff * z_vel) * delta_sec +(y_coeff * y_acc + z_coeff * z_acc) * one_half_at_squared;double dFY_dR = (cr * cpi * pitch_vel - sr * cpi * yaw_vel) * delta_sec;x_coeff = -cp;y_coeff = -sp * sr;z_coeff = -sp * cr;double dFz_dP =(x_coeff * x_vel + y_coeff * y_vel + z_coeff * z_vel) * delta_sec +(x_coeff * x_acc + y_coeff * y_acc + z_coeff * z_acc) *one_half_at_squared;double dFY_dP =(sr * tp * cpi * pitch_vel + cr * tp * cpi * yaw_vel) * delta_sec;// Much of the transfer function Jacobian is identical to the transfer// function 计算雅克比矩阵,其为线性化的状态转移矩阵transfer_function_jacobian_ = transfer_function_;transfer_function_jacobian_(StateMemberX, StateMemberRoll) = dFx_dR;transfer_function_jacobian_(StateMemberX, StateMemberPitch) = dFx_dP;transfer_function_jacobian_(StateMemberX, StateMemberYaw) = dFx_dY;transfer_function_jacobian_(StateMemberY, StateMemberRoll) = dFy_dR;transfer_function_jacobian_(StateMemberY, StateMemberPitch) = dFy_dP;transfer_function_jacobian_(StateMemberY, StateMemberYaw) = dFy_dY;transfer_function_jacobian_(StateMemberZ, StateMemberRoll) = dFz_dR;transfer_function_jacobian_(StateMemberZ, StateMemberPitch) = dFz_dP;transfer_function_jacobian_(StateMemberRoll, StateMemberRoll) = dFR_dR;transfer_function_jacobian_(StateMemberRoll, StateMemberPitch) = dFR_dP;transfer_function_jacobian_(StateMemberPitch, StateMemberRoll) = dFP_dR;transfer_function_jacobian_(StateMemberYaw, StateMemberRoll) = dFY_dR;transfer_function_jacobian_(StateMemberYaw, StateMemberPitch) = dFY_dP;FB_DEBUG("Transfer function is:\n" <<transfer_function_ << "\nTransfer function Jacobian is:\n" <<transfer_function_jacobian_ << "\nProcess noise covariance is:\n" <<process_noise_covariance_ << "\nCurrent state is:\n" <<state_ << "\n");//过程噪声协方差矩阵Q位于filter_base.cppEigen::MatrixXd * process_noise_covariance = &process_noise_covariance_;if (use_dynamic_process_noise_covariance_) {computeDynamicProcessNoiseCovariance(state_);process_noise_covariance = &dynamic_process_noise_covariance_;}// (1) Apply control terms, which are actually accelerations预测状态向量的状态转移矩阵state_(StateMemberVroll) +=control_acceleration_(ControlMemberVroll) * delta_sec;state_(StateMemberVpitch) +=control_acceleration_(ControlMemberVpitch) * delta_sec;state_(StateMemberVyaw) +=control_acceleration_(ControlMemberVyaw) * delta_sec;state_(StateMemberAx) = (control_update_vector_[ControlMemberVx] ?control_acceleration_(ControlMemberVx) :state_(StateMemberAx));state_(StateMemberAy) = (control_update_vector_[ControlMemberVy] ?control_acceleration_(ControlMemberVy) :state_(StateMemberAy));state_(StateMemberAz) = (control_update_vector_[ControlMemberVz] ?control_acceleration_(ControlMemberVz) :state_(StateMemberAz));// (2) Project the state forward: x = Ax + Bu (really, x = f(x, u))state_ = transfer_function_ * state_;// Handle wrappingwrapStateAngles();FB_DEBUG("Predicted state is:\n" <<state_ << "\nCurrent estimate error covariance is:\n" <<estimate_error_covariance_ << "\n");// (3) Project the error forward: P = J * P * J' + Q 预测其噪声协方差矩阵estimate_error_covariance_ =(transfer_function_jacobian_ * estimate_error_covariance_ *transfer_function_jacobian_.transpose());estimate_error_covariance_.noalias() +=delta_sec * (*process_noise_covariance);FB_DEBUG("Predicted estimate error covariance is:\n" <<estimate_error_covariance_ <<"\n\n--------------------- /Ekf::predict ----------------------\n");
}}  // namespace robot_localization

robot_localization中EKF源码介绍相关推荐

  1. c语言复制粘贴源码,c语言函数memccpy()如何复制内存中的内容实例源码介绍

    c语言函数memccpy()如何复制内存中的内容实例源码介绍.引入的头文件:#include memccpy()函数定义:void * memccpy(void *dest, const void * ...

  2. 4- vue django restful framework 打造生鲜超市 -restful api 与前端源码介绍

    使用Python3.6与Django2.0.2(Django-rest-framework)以及前端vue开发的前后端分离的商城网站 项目支持支付宝支付(暂不支持微信支付),支持手机短信验证码注册, ...

  3. c语言 临时文件作用,c语言函数mktemp()产生唯一临时文件名实例源码介绍

    c语言函数mktemp()产生唯一临时文件名实例源码介绍.有关的函数:tmpfile引入的头文件:#include 定义函数mktemp():char * mktemp(char * template ...

  4. linux ssh rpm包,RHEL6(CentOS6)中使用源码包编译生成RPM的基本方法:升级OpenSSH篇

    RHEL6(CentOS6)中使用源码包编译生成RPM的基本方法:升级OpenSSH篇 具体过程请见代码~ # cp openssh-7.1p1.tar.gz /root/rpmbuild/SOURC ...

  5. linux部署3proxy源码,在CentOS 7系统中从源码安装RTPProxy的方法

    本文介绍在CentOS 7操作系统中从源码安装RTPProxy的方法,按照以下步骤操作即可成功. 在CentOS 7.x上安装RTPProxy 1.将目录更改为/usr/src: [root@kama ...

  6. Weka开发[8]-ID3源码介绍

    为什么80%的码农都做不了架构师?>>>    这次介绍一下Id3源码,这次用Weka的源码介绍一下.首先Id3是继承于Classifier的: public class Id3 e ...

  7. Linux 内核中RAID5源码详解之守护进程raid5d

    Linux 内核中RAID5源码详解之守护进程raid5d 对于一个人,大脑支配着他的一举一动:对于一支部队,指挥中心控制着它的所有活动:同样,对于内核中的RAID5,也需要一个像大脑一样的东西来支配 ...

  8. Live555源码阅读笔记(一):源码介绍文档 及 源码目录结构

    目录 一.Live555介绍 1.Live555项目介绍 2.官网及帮助文档介绍 二.源码目录结构 1.UsageEnvironment 2.BasicUsageEnvironment 3.group ...

  9. Fabric中PBFT源码解读——Checkpoint机制

    文章目录 1. 写在前面 1.1 前置阅读 1.2 对TestCheckpoint函数的测试 2. 对TestCheckpoint函数运行流程的解读 2.1 Checkpoint和Water mark ...

最新文章

  1. PHP文件和目录操作
  2. Android之assets资源
  3. 安装 linux kernel 3.12
  4. MVC 之 Partial View 用法
  5. 微软 SQL Server 2019 将免费支持 Java;Rancher Labs获2500万美元融资;腾讯云进军日本市场……...
  6. java反射学习笔记(常用的一些方法)
  7. android 6.0适应的机型,提升用户体验 可升Android 6.0机型盘点
  8. xlswriter-用于Excel 2007+XLSX文件中读取数据
  9. python全栈开发笔记---------数据类型-----集合set
  10. 机器学习之Adaboost (自适应增强)算法
  11. 2016年2月23日----Javascript全局变量和局部变量
  12. Eclipse 中 去掉控制台最大行数限制
  13. java 符_java运算符
  14. YUV格式讲解并使用ffmpeg生产YUV文件
  15. excel流程图分叉 合并_excel流程图怎么画
  16. 2022教培机构升级转型新模式
  17. Empty filename passed to function Cannot find proj.db
  18. 一个无经验的大学毕业生,可以转行做程序员吗?我的真实案例
  19. 【计算机系统】ICS大作业论文-程序人生-Hello’s P2P
  20. 蒙特卡洛(Monte Carlo)方法简介

热门文章

  1. 财务学python可以做什么-财务方面的学生如何学习python?
  2. BDW01手把手系列01:BDW01开发板基于TencentOS Tiny之helloworld!
  3. 雨听 | 英语学习笔记(十七)~作文范文:大学生的书单
  4. wget 下载失败,使用“--no-check-certificate”,/C=US/O=Let‘s Encrypt/CN=R3” 颁发的证书
  5. CSS设置超出几行显示省略号
  6. 七段数码管26字母对照表(附带映射表以及映射数组)
  7. win7 关机速度比较快
  8. 开启mybatis属性使用驼峰的命名
  9. 淘宝小程序体验优化:数据分析和优化实践
  10. java代码读取excel文件_Java 读取excel 文件流代码实例