当前位置:   article > 正文

LIO_SAM程序实现原理学习笔记(三)--imuPreintergration.cpp_gtsam::vector(6) << 0.1, 0.1, 0.1, 0.1, 0.1, 0.1).

gtsam::vector(6) << 0.1, 0.1, 0.1, 0.1, 0.1, 0.1).finished()

        在文章开始先介绍一下预积分环节使用的GTSAM库,GTSAM是基于因子图的c++库,可以用于slam优化环节,因子图由因子和变量组成,变量表示待估计的变量,因子表示变量之间的约束。在slam问题中,变量一般表示位姿,因子表示位姿之间的约束,可能是帧间约束,闭环约束。

 

        对于它的使用,首先要构建因子图(包括构建因子图、添加先验位姿、里程计测量噪音、相邻位姿添加里程计因子、回环检测噪声、添加回环约束因子)、设置变量初值(变量初始化)、进行优化。

        在进入程序之前,先看一下文件内函数的相互关系,虽然vs code可以跳转,但是跳来跳去非常容易把结构搞乱,在这里贴上一张大体的结构图:

        在贴上程序注释前,把需要请提前注意的几个点放在前面,以便于读到这里时可以更有针对性的阅读。

        1、 首先是IMU与Lidar坐标系之间的变换问题,在头文件中定义了一个imuConverter函数,这个函数内只包含了旋转变化,将imu坐标系变换到了lidar坐标系。在本文件中,还包含了imu2lidar和lidar2imu两个变换(这里把to记作2哈哈哈学到了),乍一看这两个变换似乎是两个坐标系之间的转换矩阵。但事实是这两个变换只包含平移。流程是这样的,作者将imu通过旋转转至雷达坐标系下,但是两个坐标系之间缺一个平移。通过lidar2imu变换将两个坐标系对齐。最后通过imu2lidar将两个坐标系最终转至lidar系下。

        2、在储存imu数据的时候,有imuQueImu和imuQueOpt两个队列。这两个队列的作用是不同的,从结果来说imuQueImu是后面程序需要用到的数据,而imuQueOpt储存的是用于优化的缓存数据。从过程来说,每当lidar里程计新到一帧时,imuQueImu会删除此帧前的数据,只保留之后的数据用于两帧lidar里程计间发布imu增量式里程计;而imuQueOpt将此帧前的数据提取出来做积分,边用边删,数据用于后续优化过程。

        建议从main函数按程序运行顺序来看下面的注释:

  1. //imu预积分
  2. //下文中涉及到雷达里程计或者激光里程计的地方
  3. //其实两者指代同一内容(lidar)
  4. //因为注释时间不同注释的有所不同(不太想改了)
  5. #include "utility.h"
  6. #include <gtsam/geometry/Rot3.h>
  7. #include <gtsam/geometry/Pose3.h>
  8. #include <gtsam/slam/PriorFactor.h>
  9. #include <gtsam/slam/BetweenFactor.h>
  10. #include <gtsam/navigation/GPSFactor.h>
  11. #include <gtsam/navigation/ImuFactor.h>
  12. #include <gtsam/navigation/CombinedImuFactor.h>
  13. #include <gtsam/nonlinear/NonlinearFactorGraph.h>
  14. #include <gtsam/nonlinear/LevenbergMarquardtOptimizer.h>
  15. #include <gtsam/nonlinear/Marginals.h>
  16. #include <gtsam/nonlinear/Values.h>
  17. #include <gtsam/inference/Symbol.h>
  18. #include <gtsam/nonlinear/ISAM2.h>
  19. #include <gtsam_unstable/nonlinear/IncrementalFixedLagSmoother.h>
  20. using gtsam::symbol_shorthand::X; // Pose3 (x,y,z,r,p,y)
  21. using gtsam::symbol_shorthand::V; // Vel (xdot,ydot,zdot)
  22. using gtsam::symbol_shorthand::B; // Bias (ax,ay,az,gx,gy,gz)
  23. class TransformFusion : public ParamServer
  24. {
  25. public:
  26. std::mutex mtx;
  27. ros::Subscriber subImuOdometry;
  28. ros::Subscriber subLaserOdometry;
  29. ros::Publisher pubImuOdometry;
  30. ros::Publisher pubImuPath;
  31. Eigen::Affine3f lidarOdomAffine;
  32. Eigen::Affine3f imuOdomAffineFront;
  33. Eigen::Affine3f imuOdomAffineBack;
  34. tf::TransformListener tfListener;
  35. tf::StampedTransform lidar2Baselink;
  36. double lidarOdomTime = -1;
  37. deque<nav_msgs::Odometry> imuOdomQueue;
  38. TransformFusion()
  39. {
  40. //如果雷达系与载体系并不相同,需要执行下面代码
  41. if(lidarFrame != baselinkFrame)
  42. {
  43. //尝试获取雷达系到载体系的变换
  44. try
  45. {
  46. tfListener.waitForTransform(lidarFrame, baselinkFrame, ros::Time(0), ros::Duration(3.0));
  47. tfListener.lookupTransform(lidarFrame, baselinkFrame, ros::Time(0), lidar2Baselink);
  48. }
  49. //如果异常发生,捕获异常,输出报错信息
  50. catch (tf::TransformException ex)
  51. {
  52. ROS_ERROR("%s",ex.what());
  53. }
  54. }
  55. //订阅雷达里程计信息,来自mapOptmization.cpp
  56. subLaserOdometry = nh.subscribe<nav_msgs::Odometry>("lio_sam/mapping/odometry", 5, &TransformFusion::lidarOdometryHandler, this, ros::TransportHints().tcpNoDelay());
  57. //订阅IMU里程计信息,来自本文件中imuHandler结尾
  58. subImuOdometry = nh.subscribe<nav_msgs::Odometry>(odomTopic+"_incremental", 2000, &TransformFusion::imuOdometryHandler, this, ros::TransportHints().tcpNoDelay());
  59. //发布imu里程计信息以及imu轨迹
  60. //注意此处订阅的imu是用于rviz的,上面订阅代码为odomTopic+"_incremental"是增量式
  61. pubImuOdometry = nh.advertise<nav_msgs::Odometry>(odomTopic, 2000);
  62. pubImuPath = nh.advertise<nav_msgs::Path> ("lio_sam/imu/path", 1);
  63. }
  64. //里程计对应变换矩阵,在下面的雷达里程计回调函数中被调用
  65. Eigen::Affine3f odom2affine(nav_msgs::Odometry odom)
  66. {
  67. double x, y, z, roll, pitch, yaw;
  68. x = odom.pose.pose.position.x;
  69. y = odom.pose.pose.position.y;
  70. z = odom.pose.pose.position.z;
  71. tf::Quaternion orientation;
  72. tf::quaternionMsgToTF(odom.pose.pose.orientation, orientation);
  73. tf::Matrix3x3(orientation).getRPY(roll, pitch, yaw);
  74. return pcl::getTransformation(x, y, z, roll, pitch, yaw);
  75. }
  76. //雷达里程计回调函数,订阅的lio_sam/mapping/odometry将被传入此函数
  77. void lidarOdometryHandler(const nav_msgs::Odometry::ConstPtr& odomMsg)
  78. {
  79. //锁定线程
  80. std::lock_guard<std::mutex> lock(mtx);
  81. //接收odom2affine函数传入的tf信息
  82. lidarOdomAffine = odom2affine(*odomMsg);
  83. //获取时间戳
  84. lidarOdomTime = odomMsg->header.stamp.toSec();
  85. }
  86. //imu里程计回调函数,订阅的odomTopic+"_incremental"将被传入此函数处理
  87. void imuOdometryHandler(const nav_msgs::Odometry::ConstPtr& odomMsg)
  88. {
  89. // static tf
  90. //将tfmap转换到odom系下,发布tf
  91. static tf::TransformBroadcaster tfMap2Odom;
  92. static tf::Transform map_to_odom = tf::Transform(tf::createQuaternionFromRPY(0, 0, 0), tf::Vector3(0, 0, 0));
  93. tfMap2Odom.sendTransform(tf::StampedTransform(map_to_odom, odomMsg->header.stamp, mapFrame, odometryFrame));
  94. //锁线程
  95. std::lock_guard<std::mutex> lock(mtx);
  96. //将里程计信息添加到队列
  97. imuOdomQueue.push_back(*odomMsg);
  98. // get latest odometry (at current IMU stamp)
  99. //删除激光里程计前面的imu队列里的数据
  100. if (lidarOdomTime == -1)
  101. return;
  102. while (!imuOdomQueue.empty())
  103. {
  104. if (imuOdomQueue.front().header.stamp.toSec() <= lidarOdomTime)
  105. imuOdomQueue.pop_front();
  106. else
  107. break;
  108. }
  109. //与激光里程计最近的imu
  110. Eigen::Affine3f imuOdomAffineFront = odom2affine(imuOdomQueue.front());
  111. //当前最新
  112. Eigen::Affine3f imuOdomAffineBack = odom2affine(imuOdomQueue.back());
  113. //上述两状态的矩阵变换(好像是增量位姿变换?)
  114. Eigen::Affine3f imuOdomAffineIncre = imuOdomAffineFront.inverse() * imuOdomAffineBack;
  115. //当前imu位姿是激光里程计位姿乘imu位姿增量变化雷达
  116. Eigen::Affine3f imuOdomAffineLast = lidarOdomAffine * imuOdomAffineIncre;
  117. float x, y, z, roll, pitch, yaw;
  118. pcl::getTranslationAndEulerAngles(imuOdomAffineLast, x, y, z, roll, pitch, yaw);
  119. // publish latest odometry(发布最新的里程计)
  120. nav_msgs::Odometry laserOdometry = imuOdomQueue.back();
  121. laserOdometry.pose.pose.position.x = x;
  122. laserOdometry.pose.pose.position.y = y;
  123. laserOdometry.pose.pose.position.z = z;
  124. laserOdometry.pose.pose.orientation = tf::createQuaternionMsgFromRollPitchYaw(roll, pitch, yaw);
  125. pubImuOdometry.publish(laserOdometry);
  126. // publish tf发布tf,主要是lidarFrame与baselinkFrame变换关系
  127. static tf::TransformBroadcaster tfOdom2BaseLink;
  128. tf::Transform tCur;
  129. tf::poseMsgToTF(laserOdometry.pose.pose, tCur);
  130. if(lidarFrame != baselinkFrame)
  131. tCur = tCur * lidar2Baselink;
  132. tf::StampedTransform odom_2_baselink = tf::StampedTransform(tCur, odomMsg->header.stamp, odometryFrame, baselinkFrame);
  133. tfOdom2BaseLink.sendTransform(odom_2_baselink);
  134. // publish IMU path
  135. //主要是最近雷达里程计于当前时间的路径
  136. static nav_msgs::Path imuPath;
  137. static double last_path_time = -1;
  138. double imuTime = imuOdomQueue.back().header.stamp.toSec();
  139. //可以看出发布频率为0.1秒
  140. if (imuTime - last_path_time > 0.1)
  141. {
  142. last_path_time = imuTime;
  143. geometry_msgs::PoseStamped pose_stamped;
  144. pose_stamped.header.stamp = imuOdomQueue.back().header.stamp;
  145. pose_stamped.header.frame_id = odometryFrame;
  146. pose_stamped.pose = laserOdometry.pose.pose;
  147. imuPath.poses.push_back(pose_stamped);
  148. while(!imuPath.poses.empty() && imuPath.poses.front().header.stamp.toSec() < lidarOdomTime - 1.0)
  149. imuPath.poses.erase(imuPath.poses.begin());
  150. if (pubImuPath.getNumSubscribers() != 0)
  151. {
  152. imuPath.header.stamp = imuOdomQueue.back().header.stamp;
  153. imuPath.header.frame_id = odometryFrame;
  154. pubImuPath.publish(imuPath);
  155. }
  156. }
  157. }
  158. };
  159. class IMUPreintegration : public ParamServer
  160. {
  161. public:
  162. std::mutex mtx;
  163. ros::Subscriber subImu;
  164. ros::Subscriber subOdometry;
  165. ros::Publisher pubImuOdometry;
  166. bool systemInitialized = false;
  167. gtsam::noiseModel::Diagonal::shared_ptr priorPoseNoise;
  168. gtsam::noiseModel::Diagonal::shared_ptr priorVelNoise;
  169. gtsam::noiseModel::Diagonal::shared_ptr priorBiasNoise;
  170. gtsam::noiseModel::Diagonal::shared_ptr correctionNoise;
  171. gtsam::noiseModel::Diagonal::shared_ptr correctionNoise2;
  172. gtsam::Vector noiseModelBetweenBias;
  173. gtsam::PreintegratedImuMeasurements *imuIntegratorOpt_;
  174. gtsam::PreintegratedImuMeasurements *imuIntegratorImu_;
  175. std::deque<sensor_msgs::Imu> imuQueOpt;
  176. std::deque<sensor_msgs::Imu> imuQueImu;
  177. gtsam::Pose3 prevPose_;
  178. gtsam::Vector3 prevVel_;
  179. gtsam::NavState prevState_;
  180. gtsam::imuBias::ConstantBias prevBias_;
  181. gtsam::NavState prevStateOdom;
  182. gtsam::imuBias::ConstantBias prevBiasOdom;
  183. bool doneFirstOpt = false;
  184. double lastImuT_imu = -1;
  185. double lastImuT_opt = -1;
  186. gtsam::ISAM2 optimizer;
  187. gtsam::NonlinearFactorGraph graphFactors;
  188. gtsam::Values graphValues;
  189. const double delta_t = 0;
  190. int key = 1;
  191. //下面两处坐标变换只有平移部分
  192. // T_bl: tramsform points from lidar frame to imu frame
  193. gtsam::Pose3 imu2Lidar = gtsam::Pose3(gtsam::Rot3(1, 0, 0, 0), gtsam::Point3(-extTrans.x(), -extTrans.y(), -extTrans.z()));
  194. // T_lb: tramsform points from imu frame to lidar frame
  195. gtsam::Pose3 lidar2Imu = gtsam::Pose3(gtsam::Rot3(1, 0, 0, 0), gtsam::Point3(extTrans.x(), extTrans.y(), extTrans.z()));
  196. IMUPreintegration()
  197. {
  198. //订阅imu话题发送的原始消息,
  199. //队列长度2000,数据传入函数imuHandler处理,数据采取tcpNoDelay方式传递,该方式延迟较低
  200. subImu = nh.subscribe<sensor_msgs::Imu> (imuTopic, 2000, &IMUPreintegration::imuHandler, this, ros::TransportHints().tcpNoDelay());
  201. //订阅雷达里程计消息
  202. //队列长度为5,数据传入odometryHandler,同样采取tcpNoDelay方式传递
  203. subOdometry = nh.subscribe<nav_msgs::Odometry>("lio_sam/mapping/odometry_incremental", 5, &IMUPreintegration::odometryHandler, this, ros::TransportHints().tcpNoDelay());
  204. //发布增量IMU里程计信息
  205. pubImuOdometry = nh.advertise<nav_msgs::Odometry> (odomTopic+"_incremental", 2000);
  206. //关于噪声协方差部分
  207. //噪声参数已在params.yaml文件中填入,最后一行假设了初始bias为零
  208. boost::shared_ptr<gtsam::PreintegrationParams> p = gtsam::PreintegrationParams::MakeSharedU(imuGravity);
  209. p->accelerometerCovariance = gtsam::Matrix33::Identity(3,3) * pow(imuAccNoise, 2); // acc white noise in continuous
  210. p->gyroscopeCovariance = gtsam::Matrix33::Identity(3,3) * pow(imuGyrNoise, 2); // gyro white noise in continuous
  211. p->integrationCovariance = gtsam::Matrix33::Identity(3,3) * pow(1e-4, 2); // error committed in integrating position from velocities
  212. gtsam::imuBias::ConstantBias prior_imu_bias((gtsam::Vector(6) << 0, 0, 0, 0, 0, 0).finished());; // assume zero initial bias
  213. priorPoseNoise = gtsam::noiseModel::Diagonal::Sigmas((gtsam::Vector(6) << 1e-2, 1e-2, 1e-2, 1e-2, 1e-2, 1e-2).finished()); // rad,rad,rad,m, m, m
  214. priorVelNoise = gtsam::noiseModel::Isotropic::Sigma(3, 1e4); // m/s
  215. priorBiasNoise = gtsam::noiseModel::Isotropic::Sigma(6, 1e-3); // 1e-2 ~ 1e-3 seems to be good
  216. correctionNoise = gtsam::noiseModel::Diagonal::Sigmas((gtsam::Vector(6) << 0.05, 0.05, 0.05, 0.1, 0.1, 0.1).finished()); // rad,rad,rad,m, m, m
  217. correctionNoise2 = gtsam::noiseModel::Diagonal::Sigmas((gtsam::Vector(6) << 1, 1, 1, 1, 1, 1).finished()); // rad,rad,rad,m, m, m
  218. noiseModelBetweenBias = (gtsam::Vector(6) << imuAccBiasN, imuAccBiasN, imuAccBiasN, imuGyrBiasN, imuGyrBiasN, imuGyrBiasN).finished();
  219. imuIntegratorImu_ = new gtsam::PreintegratedImuMeasurements(p, prior_imu_bias); // setting up the IMU integration for IMU message thread
  220. imuIntegratorOpt_ = new gtsam::PreintegratedImuMeasurements(p, prior_imu_bias); // setting up the IMU integration for optimization
  221. }
  222. void resetOptimization()
  223. {
  224. gtsam::ISAM2Params optParameters;
  225. optParameters.relinearizeThreshold = 0.1;
  226. optParameters.relinearizeSkip = 1;
  227. optimizer = gtsam::ISAM2(optParameters);
  228. gtsam::NonlinearFactorGraph newGraphFactors;
  229. graphFactors = newGraphFactors;
  230. gtsam::Values NewGraphValues;
  231. graphValues = NewGraphValues;
  232. }
  233. void resetParams()
  234. {
  235. lastImuT_imu = -1;
  236. doneFirstOpt = false;
  237. systemInitialized = false;
  238. }
  239. void odometryHandler(const nav_msgs::Odometry::ConstPtr& odomMsg)
  240. {
  241. //锁定线程
  242. std::lock_guard<std::mutex> lock(mtx);
  243. //取出消息中的时间戳
  244. double currentCorrectionTime = ROS_TIME(odomMsg);
  245. // make sure we have imu data to integrate
  246. //保证有imu数据可以用来积分
  247. if (imuQueOpt.empty())
  248. return;
  249. //获取了位置和四元数信息
  250. float p_x = odomMsg->pose.pose.position.x;
  251. float p_y = odomMsg->pose.pose.position.y;
  252. float p_z = odomMsg->pose.pose.position.z;
  253. float r_x = odomMsg->pose.pose.orientation.x;
  254. float r_y = odomMsg->pose.pose.orientation.y;
  255. float r_z = odomMsg->pose.pose.orientation.z;
  256. float r_w = odomMsg->pose.pose.orientation.w;
  257. //用布尔变量接收判断pose.covariance[0] == 1的结果,true时雷达里程计有退化风险
  258. bool degenerate = (int)odomMsg->pose.covariance[0] == 1 ? true : false;
  259. //将位姿转化为gtsam的格式
  260. gtsam::Pose3 lidarPose = gtsam::Pose3(gtsam::Rot3::Quaternion(r_w, r_x, r_y, r_z), gtsam::Point3(p_x, p_y, p_z));
  261. // 0. initialize system系统初始化,只有在标识为为false时执行,通常仅执行一次
  262. if (systemInitialized == false)
  263. {
  264. //重置参数(isam2)
  265. resetOptimization();
  266. // pop old IMU message
  267. //丢弃掉雷达里程计之前的imu数据,imu频率是高于雷达里程计数据的
  268. while (!imuQueOpt.empty())
  269. {
  270. if (ROS_TIME(&imuQueOpt.front()) < currentCorrectionTime - delta_t)
  271. {
  272. lastImuT_opt = ROS_TIME(&imuQueOpt.front());
  273. imuQueOpt.pop_front();
  274. }
  275. else
  276. break;
  277. }
  278. //以下的结构类似,以第一组为例
  279. //首先用gtsam下的函数compose将雷达位姿转移至imu下,注意这个变化只有平移,在雷达与imu变换这块一定多看看防止着道
  280. //设置初始位姿与置信度
  281. //将其添加到因子图中
  282. // initial pose
  283. prevPose_ = lidarPose.compose(lidar2Imu);
  284. //gtsam::PriorFactor为先验因子,约束值不会离先验值太远
  285. //下面的X、V、B是定义在头文件下面的,分别表示六自由度的位姿、三坐标速度以及六噪声
  286. gtsam::PriorFactor<gtsam::Pose3> priorPose(X(0), prevPose_, priorPoseNoise);
  287. graphFactors.add(priorPose);
  288. // initial velocity
  289. prevVel_ = gtsam::Vector3(0, 0, 0);
  290. gtsam::PriorFactor<gtsam::Vector3> priorVel(V(0), prevVel_, priorVelNoise);
  291. graphFactors.add(priorVel);
  292. // initial bias
  293. prevBias_ = gtsam::imuBias::ConstantBias();
  294. gtsam::PriorFactor<gtsam::imuBias::ConstantBias> priorBias(B(0), prevBias_, priorBiasNoise);
  295. graphFactors.add(priorBias);
  296. // add values变量节点赋初值
  297. graphValues.insert(X(0), prevPose_);
  298. graphValues.insert(V(0), prevVel_);
  299. graphValues.insert(B(0), prevBias_);
  300. // optimize once
  301. //将参数传入isam优化器进行优化
  302. optimizer.update(graphFactors, graphValues);
  303. //下面将因子和图都清除了
  304. graphFactors.resize(0);
  305. graphValues.clear();
  306. //重置积分器
  307. imuIntegratorImu_->resetIntegrationAndSetBias(prevBias_);
  308. imuIntegratorOpt_->resetIntegrationAndSetBias(prevBias_);
  309. key = 1;
  310. systemInitialized = true;
  311. return;
  312. }
  313. // reset graph for speed
  314. //这里的key指的是激光里程计的帧,每100帧激光里程计数据就执行下面的函数
  315. if (key == 100)
  316. {
  317. // get updated noise before reset
  318. //储存一下上一帧的X、V、B噪声数据
  319. gtsam::noiseModel::Gaussian::shared_ptr updatedPoseNoise = gtsam::noiseModel::Gaussian::Covariance(optimizer.marginalCovariance(X(key-1)));
  320. gtsam::noiseModel::Gaussian::shared_ptr updatedVelNoise = gtsam::noiseModel::Gaussian::Covariance(optimizer.marginalCovariance(V(key-1)));
  321. gtsam::noiseModel::Gaussian::shared_ptr updatedBiasNoise = gtsam::noiseModel::Gaussian::Covariance(optimizer.marginalCovariance(B(key-1)));
  322. // reset graph
  323. //重置参数(isam2)
  324. //下面流程与初始化系统后半段内容差不多
  325. resetOptimization();
  326. // add pose
  327. gtsam::PriorFactor<gtsam::Pose3> priorPose(X(0), prevPose_, updatedPoseNoise);
  328. graphFactors.add(priorPose);
  329. // add velocity
  330. gtsam::PriorFactor<gtsam::Vector3> priorVel(V(0), prevVel_, updatedVelNoise);
  331. graphFactors.add(priorVel);
  332. // add bias
  333. gtsam::PriorFactor<gtsam::imuBias::ConstantBias> priorBias(B(0), prevBias_, updatedBiasNoise);
  334. graphFactors.add(priorBias);
  335. // add values
  336. graphValues.insert(X(0), prevPose_);
  337. graphValues.insert(V(0), prevVel_);
  338. graphValues.insert(B(0), prevBias_);
  339. // optimize once
  340. optimizer.update(graphFactors, graphValues);
  341. graphFactors.resize(0);
  342. graphValues.clear();
  343. key = 1;
  344. }
  345. // 1. integrate imu data and optimize(整合IMU数据并优化)
  346. while (!imuQueOpt.empty())
  347. {
  348. // pop and integrate imu data that is between two optimizations(弹出并整合两帧之间的imu数据)
  349. sensor_msgs::Imu *thisImu = &imuQueOpt.front();
  350. double imuTime = ROS_TIME(thisImu);
  351. //currentCorrectionTime是激光里程计时间数据,delta_t定义时赋值0,没找到修改此参数值的代码
  352. if (imuTime < currentCorrectionTime - delta_t)
  353. {
  354. //int c=a>b?a:b; //判断a和b的大小,如果a大于b为真,则把a的值赋予c,否则把b赋予c
  355. //判断lastImuT_opt < 0的是否成立,成立赋值dt为五百分之一,否则赋值imuTime - lastImuT_opt
  356. double dt = (lastImuT_opt < 0) ? (1.0 / 500.0) : (imuTime - lastImuT_opt);
  357. //预积分的数据输入,包含线加速度与角速度,以及上式中dt
  358. imuIntegratorOpt_->integrateMeasurement(
  359. gtsam::Vector3(thisImu->linear_acceleration.x, thisImu->linear_acceleration.y, thisImu->linear_acceleration.z),
  360. gtsam::Vector3(thisImu->angular_velocity.x, thisImu->angular_velocity.y, thisImu->angular_velocity.z), dt);
  361. //删除imu数据前记录下数据时间,然后将其删除
  362. lastImuT_opt = imuTime;
  363. imuQueOpt.pop_front();
  364. }
  365. else
  366. break;
  367. }
  368. // add imu factor to graph
  369. //imuIntegratorOpt_传入preint_imu。将前一帧的X、V、B与这一帧X、V与preint_imu导入因子图
  370. const gtsam::PreintegratedImuMeasurements& preint_imu = dynamic_cast<const gtsam::PreintegratedImuMeasurements&>(*imuIntegratorOpt_);
  371. gtsam::ImuFactor imu_factor(X(key - 1), V(key - 1), X(key), V(key), B(key - 1), preint_imu);
  372. graphFactors.add(imu_factor);
  373. // add imu bias between factor
  374. //添加了前一帧B、此帧B、观测偏差、协噪声方差
  375. graphFactors.add(gtsam::BetweenFactor<gtsam::imuBias::ConstantBias>(B(key - 1), B(key), gtsam::imuBias::ConstantBias(),
  376. gtsam::noiseModel::Diagonal::Sigmas(sqrt(imuIntegratorOpt_->deltaTij()) * noiseModelBetweenBias)));
  377. // add pose factor
  378. gtsam::Pose3 curPose = lidarPose.compose(lidar2Imu);
  379. gtsam::PriorFactor<gtsam::Pose3> pose_factor(X(key), curPose, degenerate ? correctionNoise2 : correctionNoise);
  380. graphFactors.add(pose_factor);
  381. // insert predicted values
  382. gtsam::NavState propState_ = imuIntegratorOpt_->predict(prevState_, prevBias_);
  383. graphValues.insert(X(key), propState_.pose());
  384. graphValues.insert(V(key), propState_.v());
  385. graphValues.insert(B(key), prevBias_);
  386. // optimize
  387. optimizer.update(graphFactors, graphValues);
  388. optimizer.update();
  389. graphFactors.resize(0);
  390. graphValues.clear();
  391. // Overwrite the beginning of the preintegration for the next step.
  392. //下一轮预积分值复写,优化结果、位姿、速度、当前帧状态以及偏置
  393. gtsam::Values result = optimizer.calculateEstimate();
  394. prevPose_ = result.at<gtsam::Pose3>(X(key));
  395. prevVel_ = result.at<gtsam::Vector3>(V(key));
  396. prevState_ = gtsam::NavState(prevPose_, prevVel_);
  397. prevBias_ = result.at<gtsam::imuBias::ConstantBias>(B(key));
  398. // Reset the optimization preintegration object.
  399. //重置预积分优化对象
  400. imuIntegratorOpt_->resetIntegrationAndSetBias(prevBias_);
  401. // check optimization
  402. //检查因子图优化结果,通过failureDetection函数返回if判断true或者false
  403. if (failureDetection(prevVel_, prevBias_))
  404. {
  405. resetParams();
  406. return;
  407. }
  408. // 2. after optiization, re-propagate imu odometry preintegration
  409. //优化之后,重新传播imu里程计预积分
  410. prevStateOdom = prevState_;
  411. prevBiasOdom = prevBias_;
  412. // first pop imu message older than current correction data
  413. //移除激光里程计帧当前时间之前的imu数据
  414. double lastImuQT = -1;
  415. while (!imuQueImu.empty() && ROS_TIME(&imuQueImu.front()) < currentCorrectionTime - delta_t)
  416. {
  417. lastImuQT = ROS_TIME(&imuQueImu.front());
  418. imuQueImu.pop_front();
  419. }
  420. // repropogate
  421. if (!imuQueImu.empty())
  422. {
  423. // reset bias use the newly optimized bias
  424. //使用最新的优化后的偏置设置bias
  425. imuIntegratorImu_->resetIntegrationAndSetBias(prevBiasOdom);
  426. // integrate imu message from the beginning of this optimization
  427. //使用imuQueImu队列的数据进行预积分,bias采用的处理过的最新数据
  428. for (int i = 0; i < (int)imuQueImu.size(); ++i)
  429. {
  430. sensor_msgs::Imu *thisImu = &imuQueImu[i];
  431. double imuTime = ROS_TIME(thisImu);
  432. double dt = (lastImuQT < 0) ? (1.0 / 500.0) :(imuTime - lastImuQT);
  433. imuIntegratorImu_->integrateMeasurement(gtsam::Vector3(thisImu->linear_acceleration.x, thisImu->linear_acceleration.y, thisImu->linear_acceleration.z),
  434. gtsam::Vector3(thisImu->angular_velocity.x, thisImu->angular_velocity.y, thisImu->angular_velocity.z), dt);
  435. lastImuQT = imuTime;
  436. }
  437. }
  438. ++key;
  439. //使imuHandler函数可以运行通过if判断
  440. doneFirstOpt = true;
  441. }
  442. //integrate imu data and optimize(整合IMU数据并优化)环节末尾判断优化结果函数
  443. bool failureDetection(const gtsam::Vector3& velCur, const gtsam::imuBias::ConstantBias& biasCur)
  444. {
  445. //速度过大错误
  446. Eigen::Vector3f vel(velCur.x(), velCur.y(), velCur.z());
  447. if (vel.norm() > 30)
  448. {
  449. ROS_WARN("Large velocity, reset IMU-preintegration!");
  450. return true;
  451. }
  452. //偏置过大错误
  453. Eigen::Vector3f ba(biasCur.accelerometer().x(), biasCur.accelerometer().y(), biasCur.accelerometer().z());
  454. Eigen::Vector3f bg(biasCur.gyroscope().x(), biasCur.gyroscope().y(), biasCur.gyroscope().z());
  455. if (ba.norm() > 1.0 || bg.norm() > 1.0)
  456. {
  457. ROS_WARN("Large bias, reset IMU-preintegration!");
  458. return true;
  459. }
  460. return false;
  461. }
  462. void imuHandler(const sensor_msgs::Imu::ConstPtr& imu_raw)
  463. {
  464. //锁定线程,防止后进入队列干扰
  465. std::lock_guard<std::mutex> lock(mtx);
  466. //使用在头文件中定义的函数imuConverter处理原始imu数据
  467. //该函数将imu转移至雷达坐标系,注意只进行了旋转,没有进行平移
  468. sensor_msgs::Imu thisImu = imuConverter(*imu_raw);
  469. //将转换完的数据传入两个队列
  470. imuQueOpt.push_back(thisImu);
  471. imuQueImu.push_back(thisImu);
  472. //如果没有发生位姿变换的优化,return
  473. //doneFirstOpt默认置false,odometryHandler函数完成置为true
  474. if (doneFirstOpt == false)
  475. return;
  476. double imuTime = ROS_TIME(&thisImu);
  477. double dt = (lastImuT_imu < 0) ? (1.0 / 500.0) : (imuTime - lastImuT_imu);
  478. lastImuT_imu = imuTime;
  479. // integrate this single imu message(添加单帧)
  480. imuIntegratorImu_->integrateMeasurement(gtsam::Vector3(thisImu.linear_acceleration.x, thisImu.linear_acceleration.y, thisImu.linear_acceleration.z),
  481. gtsam::Vector3(thisImu.angular_velocity.x, thisImu.angular_velocity.y, thisImu.angular_velocity.z), dt);
  482. // predict odometry(预计从上一激光里程计到这一时刻的状态)
  483. gtsam::NavState currentState = imuIntegratorImu_->predict(prevStateOdom, prevBiasOdom);
  484. // publish odometry
  485. nav_msgs::Odometry odometry;
  486. odometry.header.stamp = thisImu.header.stamp;
  487. odometry.header.frame_id = odometryFrame;
  488. odometry.child_frame_id = "odom_imu";
  489. // transform imu pose to ldiar(将imu里程计转移至雷达里程计,只有平移变换)
  490. gtsam::Pose3 imuPose = gtsam::Pose3(currentState.quaternion(), currentState.position());
  491. gtsam::Pose3 lidarPose = imuPose.compose(imu2Lidar);
  492. odometry.pose.pose.position.x = lidarPose.translation().x();
  493. odometry.pose.pose.position.y = lidarPose.translation().y();
  494. odometry.pose.pose.position.z = lidarPose.translation().z();
  495. odometry.pose.pose.orientation.x = lidarPose.rotation().toQuaternion().x();
  496. odometry.pose.pose.orientation.y = lidarPose.rotation().toQuaternion().y();
  497. odometry.pose.pose.orientation.z = lidarPose.rotation().toQuaternion().z();
  498. odometry.pose.pose.orientation.w = lidarPose.rotation().toQuaternion().w();
  499. odometry.twist.twist.linear.x = currentState.velocity().x();
  500. odometry.twist.twist.linear.y = currentState.velocity().y();
  501. odometry.twist.twist.linear.z = currentState.velocity().z();
  502. odometry.twist.twist.angular.x = thisImu.angular_velocity.x + prevBiasOdom.gyroscope().x();
  503. odometry.twist.twist.angular.y = thisImu.angular_velocity.y + prevBiasOdom.gyroscope().y();
  504. odometry.twist.twist.angular.z = thisImu.angular_velocity.z + prevBiasOdom.gyroscope().z();
  505. pubImuOdometry.publish(odometry);
  506. }
  507. };
  508. int main(int argc, char** argv)
  509. {
  510. //节点初始化
  511. ros::init(argc, argv, "roboat_loam");
  512. //类的实例:IMUPreintegration
  513. IMUPreintegration ImuP;
  514. //类的实例:TransformFusion
  515. TransformFusion TF;
  516. //打印消息,说明该节点已经开始工作
  517. ROS_INFO("\033[1;32m----> IMU Preintegration Started.\033[0m");
  518. //开了四个线程
  519. ros::MultiThreadedSpinner spinner(4);
  520. spinner.spin();
  521. return 0;
  522. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/102966
推荐阅读
相关标签
  

闽ICP备14008679号