fiesta论文翻译和代码

2023-05-16

论文

体素信息结构(VIS):

Namemean符号
position体素坐标pos
occupancy占用概率occ
ESDF到最近障碍物的欧几里得距离dis
Closest Obstacle Coordinate最近障碍物的体素坐标coc
observed是否曾经观察到这种体素obs
prev, next, headDLL用过prev, next, head
Doubly Linked List(DLL)最近障碍物是该体素的所有体素dll
Neighhoods该体素的所有观察到的Neighhood(如26连接)nbrs

索引数据结构

该数据结构用来将体素坐标映射到VIS的索引中,可以使用数组的方式或者哈希表的方式。

数组方式:当通过其坐标查询体素时,我们只需要计算其在该数组内的索引,然后返回VIS的相应指针即可。缺点:地图大占内存。

哈希表方式:使用哈希表将体素坐标转换为其相应的VIS指针。缺点:查找操作数量众多,性能差。

我们:将(块大小)3个体素,作为一块,哈希表仅用于管理块,在根据体素坐标计算块坐标之后,该哈希表将用于查找对应的块。该块中所有体素的VIS的所有指针都存储在相对于该块的数组中。

双向链表(DLLs)

使用DLLs可以在体素从占有变为空闲的时候,高效地更新ESDF地图。一个体素vox所对应的dll存放了所有最近障碍物是vox的体素。它是个双向链表,能够快速的遍历。

对于障碍物vox,DLL存储了所有最近障碍物是vox的体素。

在这里插入图片描述

过程

在此过程中,所有更改其占用状态的体素均被添加到分别名为insertQueue和deleteQueue的两个队列中。之后,将这两个队列合并为一个名为updateQueue的队列,并使用基于BFS的ESDF更新算法来更新ESDF可能更改的所有体素。

我们使用光线追踪法来将新的占有信息叠加到占有栅格地图中。所有占有状态发生变化的体素会被添加到insertQueue或deleteQueue中。

  • 情况1:假设添加为“占据”的体素,对地图进行更新:

    仅有insertQueue, deleteQueue 为空

    对于每个被更新过的点cur,处理更新它的临近点nbr,如果临近点nbr之前的esdf 小于 其到cur的最近障碍物的距离,那esdf就更新为其到cur的最近障碍物的距离,把nbr也放到更新过的点里。

大致如图,当某个点占据情况发生变化时,搜索它的邻居,如果这个邻居离该点的距离 比之前的最近距离(esdf)近,就更新成本次距离,并把该邻居也作为生长点,搜索它的邻居进行比较。
在这里插入图片描述

  • 情况2:既添加又删除

    添加时,该点的 d i s = 0 dis=0 dis=0,然后执行上一步的更新操作

    删除时,该点的 d i s = ∞ dis=∞ dis=,查找所有以被删除点cur为最近障碍物的点vox,查找vox的nbr的最近障碍物,最近的那个作为vox的最近障碍物。
    在这里插入图片描述

  • 情况3:补丁
    bug:当观察到范围外的点,t0时观察到0,t1时观察到1~3。按步骤1的话,t0时刻不会更新体素1~3,因为他们属于为探测区域;t1时刻,体素3为占据,以它为中心更新它的邻居,第1个体素以为最近的是3。(因为0没发生变化,没再更新障碍0)
    补丁:添加内容->当体素cur到其邻居的最近障碍物的距离,比他自身的近,就换成其邻居的最近障碍物
    在这里插入图片描述

存在的误差:

假设A要被更新,因为 n b r . d i s ← D I S T ( c u r . c o c , n b r . p o s ) nbr.dis ← DIST(cur.coc, nbr.pos) nbr.disDIST(cur.coc,nbr.pos),考虑AC, 其中A是nbr,c是cur。在红蓝之间,离A更近,但离C原,所以A的最近点也会被更新为B。

在这里插入图片描述

代码

test_fiesta.cpp:
从test_fiesta.cpp进入,就实例化了一个模板类fiesta,具体实现都在类的构造函数中。
这里可以修改类的输入类型,点云格式:点云还是深度图,位姿格式:path还是odom等。支持的类型回调中可以看到:

int main(int argc, char **argv) 
    fiesta::Fiesta<sensor_msgs::PointCloud2::ConstPtr, geometry_msgs::TransformStamped::ConstPtr> esdf_map(node);

Fiesta.h:

构造函数:

esdf_map_->SetParameters()//读入参数
//订阅者,见1、2、
transform_sub_ = node.subscribe("transform", 10, &Fiesta::PoseCallback, this);\
depth_sub_ = node.subscribe("depth", 10, &Fiesta::DepthCallback, this);
//发布者
pass
//定时器,每隔一定时间进入一次回调,见3、
update_mesh_timer_ = node.createTimer(ros::Duration(time), &Fiesta::UpdateEsdfEvent, this);

1、PoseCallback:

//对于不同的输入格式,位姿(平移和旋转)提取出来放到pos、q
if constexpr(std::is_same<PoseMsgType, geometry_msgs::PoseStamped::ConstPtr>::value) 
          pos = Eigen::Vector3d(msg->pose.position.x, msg->pose.position.y, msg->pose.position.z);
          q = Eigen::Quaterniond(msg->pose.orientation.w, msg->pose.orientation.x, msg->pose.orientation.y, msg->pose.orientation.z);
//放到位姿队列transform_queue_
transform_queue_.push(std::make_tuple(msg->header.stamp, pos, q));

2、DepthCallback:

depth_queue_.push(depth_map);//直接放入
SynchronizationAndProcess();//时间同步、depth类型处理、位姿变换、Raycast

SynchronizationAndProcess():时间同步、depth类型处理、位姿变换、Raycast

//认为位姿比深度图来得密集得多
//从位姿队列找和当前depth最接近的位姿(用迭代的方式),由R、t->Twc 放到transform_
while (transform_queue_.size() > 1 && std::get<0>(transform_queue_.front()) <= depth_time + ros::Duration(time_delay))
     sync_pos_ = std::get<1>(transform_queue_.front());
     sync_q_ = std::get<2>(transform_queue_.front());
     transform_queue_.pop();
//齐次变换T  Ra+t => Ta
transform_.block<3, 3>(0, 0) = sync_q_.toRotationMatrix();
transform_.block<3, 1>(0, 3) = sync_pos_;	//[R|t]
transform_(3, 0) = transform_(3, 1) = transform_(3, 2) = 0;
transform_(3, 3) = 1;
//求Pc(相机在世界系下的位置)
transform_ = transform_*parameters_.T_D_B_*parameters_.T_B_C_;//Twc = word to depth * depth to body *  body to camera  (Twc也就是Pc)
raycast_origin_ = Eigen::Vector3d(transform_(0, 3), transform_(1, 3), transform_(2, 3))/transform_(3, 3);//归一
//如果输入的是深度图
//滤波 + 深度图转换到相对于本次camrea系的点云,push到cloud_
if constexpr(std::is_same<DepthMsgType, sensor_msgs::Image::ConstPtr>::value) DepthConversion();
//如果输入的是点云
pcl::fromROSMsg(*tmp, cloud_);//直接转换格式放进来

滤波步骤,对深度图每个像素:

  • 先判断是否在深度范围内
  • 位姿变换:本次camera系 -> world系 -> 上次camera系 -> 上次图像系(u,v)
  • 上次该点的depth和本次的depth差值小,就保留
//最后raycast(每帧深度图执行一次)
RaycastMultithread()

RaycastMultithread():

//if单线程:0:第0个线程;size():处理全部点;tt:第几帧了(用于raycast时减少计算)
RaycastProcess(0, cloud_.points.size(), tt);
//if多线程:i:第i个线程;part:每个线程处理多少点;tt:第几帧了
for (size_t i = 0; i < parameters_.ray_cast_num_thread_; ++i) 
    integration_threads.emplace_back(&Fiesta::RaycastProcess, this, i, part, tt);

RaycastProcess():

for (int idx = part*i; idx < part*(i + 1); idx++)//i个线程处理的点index = part*i ~ part*(i+1)
	//得到点云(占据)坐标
	pcl::PointXYZ pt = cloud_.points[idx];//深度图中的点变换到camera系后存到cloud_.points中
	Eigen::Vector4d tmp = transform_*Eigen::Vector4d(pt.x, pt.y, pt.z, 1);//变到世界系 Pw=Twc*Pc
    Eigen::Vector3d point = Eigen::Vector3d(tmp(0), tmp(1), tmp(2))/tmp(3);//Pw
    
    //设置占据
    tmp_idx = esdf_map_->SetOccupancy((Eigen::Vector3d) point, 1)//将这个占据点point(相对world)的index(相对world原点)添加到occupancy_queue_,返回index
    if (set_occ_[tmp_idx]==tt)//如果这个体素已经设为占据了(如果某体素格更新次数=帧数)(好几个点属于同一个体素),就不raycast了,跳到下一个
         continue;
    else//如果第一次占据,就设成占据
         set_occ_[tmp_idx] = tt;
    
    //raycast
    Raycast(raycast_origin_/parameters_.resolution_,//相机原点所属的体素格子
                  point/parameters_.resolution_,//占据点所属体素格子
                  parameters_.l_cornor_/parameters_.resolution_,
                  parameters_.r_cornor_/parameters_.resolution_,//地图边界
                  &output);//输出
	
	//设置空闲
	for (int i = output.size() - 2; i >= 0; i--) 
		tmp_idx = esdf_map_->SetOccupancy(tmp, 0);//output对应的体素格设为空
	    //如果某体素格更新次数=帧数,也就意味着本帧在更新过了,再往相机中心的raycast就不用做了(已经做过了)
	    if (set_free_[tmp_idx]==tt) //在往原点找,已经和其他射线交汇了,就不用再找了.
	       	breakelse 
	    	set_free_[tmp_idx] = tt;//赋值,证明已经raycast过了   

其中:

  • SetOccupancy:只要被raycast到了,都放到occupancy_queue_,而是否占据通过num_miss和num_hit_判断:num_hit_ >= num_miss_- num_hit_ =>占据的次数>空闲的次数,则记为占据(体素可能包含好几个点云)
Pos2Vox(pos, vox);//相对world的坐标转换为体素栅格坐标
idx = Vox2Idx(vox);//体素栅格坐标转换为(行向量)索引
num_miss_[idx]++;//所有的都++
num_hit_[idx] += occ;// +0(空) 或 +1 (占):即只有占据+1
occupancy_queue_.push(QueueElement{vox, 0.0});//vox:体素栅格坐标(占);
  • Raycast
1、步进时x,y,z增加的方向( + or - )。
2、求最小的正t,使start.x()+t*ds为整数(即决定下一步 x+stepX or y+stepY or z+stepZ )。
3、求变化步长step
4、从相机原点开始,output->push_back(Eigen::Vector3d(x, y, z));
5、更新: x+stepX or y+stepY or z+stepZ ,返回 2

3、UpdateEsdfEvent 回调

//更新占据栅格
esdf_map_->UpdateOccupancy(parameters_.global_update_);
//更新esdf
esdf_map_->UpdateESDF();
//发布
Visualization(esdf_map_, parameters_.global_vis_, "");

UpdateOccupancy():

while (!occupancy_queue_.empty())//所有raycast过的体素(当然包含顶端占据点)
	QueueElement xx = occupancy_queue_.front();
	int idx = Vox2Idx(xx.point_);//体素坐标xyz转换为向量的索引位置
	int occupy = Exist(idx);//更新前是否占据(用来判断状态是否变化)
	double log_odds_update = (num_hit_[idx] >= num_miss_[idx] - num_hit_[idx] ? prob_hit_log_ : prob_miss_log_);//判断是否占据,决定其对数概率值。本帧观测 占据的次数>空闲的次数 就用 prob_hit_log_(0.368),否则用prob_miss_log_(-0.296)
	
	//初始化该体素,注意这里!!!本来初始化地图时,所有体素初始化为负无穷,这里初始化occupancy_queue_里的体素,即在观测范围内的,就把他设为正无穷
	//这样更新最近障碍物时,肯定距离<正无穷,就可以更新到了。同时没被观测到的点,距离仍为-无穷,不会更新邻居时被更新。
	if (!global_map && !VoxInRange(xx.point_, false)) {
	  occupancy_buffer_[idx] = 0;//占据概率为0
	  distance_buffer_[idx] = infinity_;//最近障碍物距离为无穷(10000)
	}
	
	//更新占据概率occupancy_buffer_: L' = L + log(p/1-p)   他这儿有一个范围限制
	occupancy_buffer_[idx] = std::min(std::max(occupancy_buffer_[idx] + log_odds_update, clamp_min_log_), clamp_max_log_);
	
	//这个点 空闲->占据 放到insert_queue,距离设置为0    
	if (Exist(idx) && !occupy)  //现在占据&&之前不占据
	    insert_queue_.push(QueueElement{xx.point_, 0.0});
	
	//这个点 占据->空闲 放到delete_queue,距离设置为无穷    
	else if (!Exist(idx) && occupy) 
	    delete_queue_.push(QueueElement{xx.point_, (double) infinity_});

UpdateESDF():这部分参阅论文就好了

论文中的几个变量

xx.point_:pos
Exist(idx):occ
distance_buffer_:dis //地图大小,存了所有体素的最近障碍物dis
closest_obstacle_:coc
prev_\next_\head_:prev_\next_\head_
new_pos:nbr
idx:向量中的索引位置
  • 插入:
QueueElement xx = insert_queue_.front();
insert_queue_.pop();
int idx = Vox2Idx(xx.point_);
DeleteFromList(Vox2Idx(closest_obstacle_[idx]), idx);//双向链表: A的最近障碍物vox<->以vox为最近障碍物的体素
closest_obstacle_[idx] = xx.point_;//最近障碍物是自己
distance_buffer_[idx] = 0.0;//最近距离为0
InsertIntoList(idx, idx);//自己<->自己
update_queue_.push(xx);
  • 删除
QueueElement xx = delete_queue_.front();
delete_queue_.pop();
int idx = Vox2Idx(xx.point_);

//从头开始,把以idx为最近障碍物的体素obs_vox(索引为obs_idx),全处理一遍
int next_obs_idx;
for (int obs_idx = head_[idx]; obs_idx != undefined_; obs_idx = next_obs_idx) 
  closest_obstacle_[obs_idx] = Eigen::Vector3i(undefined_, undefined_, undefined_);//最近障碍物:未定义
  double distance = infinity_;//距离:无穷
  Eigen::Vector3i obs_vox = Idx2Vox(obs_idx);//索引转体素
  
  // 遍历他的邻居,找到有最近障碍物的邻居,把这个最近障碍物给他
  for (const auto &dir : dirs_) //dirs_是一个上下左右各+1的东西
      Eigen::Vector3i new_pos = obs_vox + dir;
      int new_pos_idx = Vox2Idx(new_pos);
      if (VoxInRange(new_pos) && closest_obstacle_[new_pos_idx](0) != undefined_ && Exist(Vox2Idx(closest_obstacle_[new_pos_idx]))) //有最近障碍物,且验证它是占据的(避免最近障碍物是刚刚删除的)
          double tmp = Dist(obs_vox, closest_obstacle_[new_pos_idx]);//vox到他邻居的最近障碍物的距离
          //比较:vox是以删除的障碍物为最近障碍物的点,vox到他邻居的最近障碍物的距离,小于他本来的距离(无穷或上一个邻居的距离)
          if (tmp < distance) {//vox到他邻居的最近障碍物的距离,小于他本来的距离
              distance = tmp;//修改它到最近障碍物的距离
              closest_obstacle_[obs_idx] = closest_obstacle_[new_pos_idx];
          break;
   // 删除双向链表
   prev_[obs_idx] = undefined_;
   next_obs_idx = next_[obs_idx];//处理链表指向的下一个
   next_[obs_idx] = undefined_;
   update_queue_.push(QueueElement{obs_vox, distance});//广度优先算法,如果这个体素被更新过,下次他的邻居也要被更新
  • 更新
    发生过删除和添加的点,都被放到了update_queue_里。这一步要更新这些点的邻居,即这个点变成了障碍物,他的邻居的最近障碍物很可能就需要改变。同时,使用广度优先搜索,邻居的邻居也很可能变化,把他们全部更新直到没有变化。
    先执行第三步的补丁,然后:
int new_obs_idx = Vox2Idx(closest_obstacle_[idx]);//最近障碍物index
for (const auto &dir : dirs_) //dirs_存了邻居的δ,即各个方向+
      Eigen::Vector3i new_pos = xx.point_ + dir;//邻居的位置
      int new_pos_id = Vox2Idx(new_pos);//邻居的index
      double tmp = Dist(new_pos, closest_obstacle_[idx]);//idx邻居到idx的最近障碍物的距离
      if (distance_buffer_[new_pos_id] > tmp) {//邻居到最近障碍物的距离比tmp远,需要更新这个邻居.
          closest_obstacle_[new_pos_id] = closest_obstacle_[idx];//改他的最近障碍物
          distance_buffer_[new_pos_id] = tmp;//改他的最近障碍物距离
          //改他的DLL
          DeleteFromList(Vox2Idx(closest_obstacle_[new_pos_id]), new_pos_id);
          InsertIntoList(new_obs_idx, new_pos_id);
          
          update_queue_.push(QueueElement{new_pos, tmp});//更新过的邻居也放进“更新过的点”的队列,下次他的邻居也更新

4、发布

发布占据栅格地图

esdf_map->GetPointCloud(pc, parameters_.vis_lower_bound_, parameters_.vis_upper_bound_);//遍历地图,把occupancy_buffer_,把占据的点拿出来,放到pc中
occupancy_pub_.publish(pc);

发布距离场

esdf_map->GetSliceMarker(slice_marker, parameters_.slice_vis_level_, 100,//切片高度
          Eigen::Vector4d(0, 1.0, 0, 1), parameters_.slice_vis_max_dist_);//遍地图中的每一个x,y,将其最近障碍物的距离从distance_buffer_中取出,发布出去(在范围内的)
slice_pub_.publish(slice_marker);

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

fiesta论文翻译和代码 的相关文章

  • TF 坐标变换(已整理)

    文章目录 坐标msg消息静态坐标变换1 C 43 43 实现发布方 demo01 static pub cpp订阅方 demo02 static sub cpp 2 Python实现发布方 demo01 static pub p py订阅方
  • ROS Action通信

    文章目录 自定义action文件 类似msg和service 服务端 action01 server cpp客户端 action02 client cpp服务端 action01 server p py客户端 action02 client
  • 位姿图优化小记2021.10.18

    1 场景描述 现在有一个小车在运动 xff0c 并搭载相机或激光雷达进行建图工作 xff0c 由于SLAM的作用 xff0c 在建图的同时小车也可以进行自身的定位 xff0c 因此建立的地图的参考都是相对于自身坐标系的 xff0c 也就是每
  • 【CRAHNs】CRAHNs网络中多径环境下大规模MIMO接收信道估计均衡技术

    1 软件版本 matlab2017b 2 本算法理论知识 对于大规模MIMO xff0c 通常情况下 xff0c 采用3D MIMO信道来实现 这是由于3D MIMO一般采用大规模的二维天线阵列 xff0c 不仅天线端口数较多 xff0c
  • VINS笔记1——滤波与优化

    1 滤波 1 1 什么是滤波 这里的卡尔曼滤波实际上和信号处理里面的滤波有很大的不同 信号处理里面的滤波 xff0c 假设一个正弦信号有很多毛刺 xff0c 想要对其进行滤波滤除毛刺 信号处理里面的做法是把信号进行FFT变换到频域 xff0
  • Ubuntu设置CMake编译时使用的OpenCV版本

    文章目录 1 方法一 xff1a 统一修改CMakeLists txt文件中的OpenCV版本1 1 具体操作1 2 命令讲解1 2 1 sed命令1 2 2 xargs命令1 2 3 find命令 2 方法二 xff1a 调用cmake命
  • ROS中常见的msg消息类型

    文章目录 1 基本数据类型1 1 三维向量Vector3 msg1 2 标头Header msg1 3 四元数Quaternion msg1 4 空间中三维点Point msg 2 传感器数据类型2 1 Imu msg 3 机器人状态数据类
  • VIO标定工具kalibr和imu_utils的使用

    0 参考资料 Kalibr进行IMU 43 相机的标定 xff1a 这个步骤写的非常好 xff0c 应该是目前看到的最符合的步骤了 使用ROS功能包标定相机内参 Kalibr标定camera IMU详细步骤 xff1a 这篇博客里给出了它的
  • ros功能包安装

    正确指令 xff1a sudo apt get install ros kinetic dwa local planner 以后安装安装包 xff0c 用sudo apt get install ros kinetic 缺少的PACKAGE
  • vins-mono编译问题--rosrun launch问题

    launch is neither a launch file in package nor is a launch file name解决办法 cd catkin ws source devel setup bash catkin ws
  • 软件工程中的框架是什么?什么是框架?

    IT领域 软件工程中所说的框架是什么 xff1f 1 1 什么是框架 xff1f 软件框架 xff08 software framework xff09 的标准定义 xff1a 通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范
  • Docker容器中远程连接实现GUI图形显示的配置方法

    1 输入xhost 43 没有问题的话会提示 access control disabled clients can connect from any host 2 使用echo DISPLAY查看本地显示器localhost 会打印结果
  • HAL库 串口收发函数解析

    一 UART Receive IT 对于CubeMX生成的代码 xff0c USART1 IRQHandler void 函数为了提高中断效率采用了回调机制 xff08 业务代码可以等中断关闭了再去处理 xff0c 这样中断处理不会占用太多
  • c++调用python

    在我们的生活中 xff0c 如果我们想调用其他程序的话 xff0c 往往会需要一些额外的代码 xff0c 比如说我们要调用 python去执行某些函数 在我们使用 python的过程中 xff0c 为了能够调用其他程序 xff0c 我们往往
  • 基于simulink的svm-dtc-adrc控制建模与仿真

    目录 一 理论基础 二 核心程序 三 仿真结论 一 理论基础 永磁电机由于没有励磁绕组和励磁装置 xff0c 不消耗励磁功率 xff0c 对磁极设在转子的电机 如一般同步电机 还可省去滑环和电刷 随着永磁材料和控制技术的发展 xff0c 永
  • 关于自制openmv的一些建议

    从接触到openmv开始一直都想制作一块自己的openmv xff0c 包括从硬件 xff0c 到烧录程序 最开始制作的版本是openmv3 xff0c 其实openmv3并不是属于自己制作 xff0c 而是下载的硬件电路城开源的openm
  • vue3创建文件报“组件名称应该总是由多个单词组成“Component name “index“ should always be multi-word

    在项目根目录下的 eslintrc js 文件中添加 vue multi word component names off 没有该文件就创建一个 module span class token punctuation span export
  • STM32和ARM的区别?

    下面先看一张图 xff1a 这张图是我在意大利与法国合资的意法半导体公司 xff08 ST xff0c 世界几大半导体公司之一 xff09 的官网上看到的 这说明 xff0c STM32是意法半导体公司的产品 意法半导体 xff08 ST
  • OrangePi 5 Docker下安装OpenWRT作软路由(同样适用于树莓派等设备)

    OrangePi5 Docker下安装OpenWRT作软路由 xff08 同样适用于树莓派等设备 xff09 说明 本文的软路由作为家中的二级路由 xff0c 用一根网线连接主路由的LAN口和二级路由的WAN口 xff08 当主路由使用配置

随机推荐

  • kubernetes-----k8s入门详解

    目录 docker的编排工具 k8s的介绍 k8s的特性 pod的分类 service 网络 通信 认证与存储 插件 docker的编排工具 docker的第一类编排工具 xff08 docker三剑客 xff09 docker compo
  • ROS机械臂开发:Moveit + Gazebo仿真/Gazebo配置

    一 ROS中的控制器插件 ros control的功能 xff1a ROS为开发者提供的机器人控制中间件 包含一系列控制器接口 传动装置接口 硬件接口 控制器工具箱等等 可以帮助机器人应用功能包快速落地 xff0c 提高开发效率 ros c
  • 匿名飞控openmv寻色块解读

    作者 xff1a 不会写代码的菜鸟 时间 xff1a 2019 7 26 源码 xff1a 匿名TI板飞控源码 43 openmvH4 说明 xff1a 限于本人水平有限 xff0c 并不能写的很详细 xff0c 还望各位能够补充
  • 校验和的计算方法

    实验要求 编写一个计算机程序用来计算一个文件的16位效验和 最快速的方法是用一个32位的整数来存放这个和 记住要处理进位 xff08 例如 xff0c 超过16位的那些位 xff09 xff0c 把它们加到效验和中 要求 xff1a 1 x
  • MT7621路由器芯片/处理器参数介绍

    MT7621路由器芯片包括一个880 MHz MIPS 1004Kc CPU双核 xff0c 一个5端口10 100 1000交换机 PHY和一个RGMII 嵌入式高性能cpu可以很容易地处理高级应用程序 如路由 安全和VoIP等 MT76
  • 谈谈你对事件的传递链和响应链的理解

    一 xff1a 响应者链 UIResponser包括了各种Touch message 的处理 xff0c 比如开始 xff0c 移动 xff0c 停止等等 常见的 UIResponser 有 UIView及子类 xff0c UIViCont
  • CMake 引入第三方库

    CMake 引入第三方库 在 CMake 中 xff0c 如何引入第三方库是一个常见的问题 在本文中 xff0c 我们将介绍 CMake 中引入第三方库的不同方法 xff0c 以及它们的优缺点 1 使用 find package 命令 在
  • u-boot的启动模式(面试常考)

    交互模式 uboot启动之后 xff0c 在倒计时减到0之前按任意键 xff0c uboot会进入到交互模式 xff0c 此时可以输入各种uboot命令 和uboot进行交互 自启动模式 uboot启动之后 xff0c 在倒计时减到0之前不
  • vins-fusion代码理解

    代码通读了一遍做些总结 xff0c 肯定有很多理解错了的地方 xff0c 清晰起见详细程序都放到引用链接里 从rosNodeTest cpp开始 main函数 ros span class token operator span span
  • vins博客的一部分1

    文章目录 imu callbackimg callback imu callback 从话题中读入各个数据的t x y z g y r xff0c 存放到acc和gry中 span class token comment 从话题读入 spa
  • vins博客的一部分2

    sync process 对两个imgBuf里的图像进行双目时间匹配 xff08 通过判断双目图像时间之差 lt 3ms xff09 xff0c 扔掉匹配不到的老帧 span class token keyword double span
  • vins博客的一部分3

    FeatureTracker trackImage 包含了 xff1a 帧间光流法 区域mask 检测特征点 左右目光流法匹配 计算像素速度 画图 跟踪上一帧的特征点 如果已经有特征点 xff0c 就直接进行LK追踪 xff0c 新的特征点
  • vins博客的一部分4

    processMeasurements 取出数据 将 featureBuf中 xff0c 最早帧的feature取出 xff1a feature 61 featureBuf front 节点的接收IMU的消息再imu callback中被放
  • vins博客的一部分5

    目录 initFirstIMUPose xff08 xff09 processIMU propagate initFirstIMUPose xff08 xff09 得到IUM的Z与重力对齐的旋转矩阵 xff1a IMU开始很大可能不是水平放
  • vins博客的一部分6

    processImage 输入是本帧的特征点 id cam id xyz uv vxvy 包含了检测关键帧 估计外部参数 初始化 状态估计 划窗等等 检测关键帧 选择margin帧 addFeatureCheckParallax 检测和上一
  • vins博客的一部分7

    目录 initFramePoseByPnP frame count Ps Rs tic ric triangulate frame count Ps Rs tic ric initFramePoseByPnP frame count Ps
  • vins博客的一部分8

    目录 optimization slideWindow optimization 优化先验残差 重投影残差 预积分残差 xff08 即要拟合的目标是 xff0c 之前边缘化后的先验值 xff0c 前后帧之间的IMU的预积分值 xff0c 每
  • 以下为WindowsNT下32位 C++程序,请计算sizeof的值

    转帖地址 xff1a http hi baidu com hikeba blog item 68ad9f10a7dd8003213f2ecf html char str 61 34 hello 34 char p1 61 str int n
  • vins博客的一部分9

    目录 IMUFactor xff08 imu约束 xff09 ProjectionTwoFrameOneCamFactor xff08 视觉约束 xff09 marginalize 边缘化约束 IMUFactor xff08 imu约束 x
  • fiesta论文翻译和代码

    论文 体素信息结构 VIS Namemean符号position体素坐标posoccupancy占用概率occESDF到最近障碍物的欧几里得距离disClosest Obstacle Coordinate最近障碍物的体素坐标cocobser