重定位算法(二)

news/2025/2/1 11:17:40/文章来源:https://www.cnblogs.com/wentZh2004/p/18694771

精读陈佬的重定位算法

一、代码框架

1.main函数

采用了ros2的可组合节点,main函数被cmakelist的一句注册节点代替,只需要看该类的构造函数即可。
首先是参数定义:

  this->declare_parameter("num_threads", 4);this->declare_parameter("num_neighbors", 20);this->declare_parameter("global_leaf_size", 0.25);this->declare_parameter("registered_leaf_size", 0.25);this->declare_parameter("max_dist_sq", 1.0);this->declare_parameter("map_frame", "map");this->declare_parameter("odom_frame", "odom");this->declare_parameter("base_frame", "");this->declare_parameter("lidar_frame", "");this->declare_parameter("prior_pcd_file", "");this->get_parameter("num_threads", num_threads_);this->get_parameter("num_neighbors", num_neighbors_);this->get_parameter("global_leaf_size", global_leaf_size_);this->get_parameter("registered_leaf_size", registered_leaf_size_);this->get_parameter("max_dist_sq", max_dist_sq_);this->get_parameter("map_frame", map_frame_);this->get_parameter("odom_frame", odom_frame_);this->get_parameter("base_frame", base_frame_);this->get_parameter("lidar_frame", lidar_frame_);this->get_parameter("prior_pcd_file", prior_pcd_file_);

接着预载点云信息,并将点云参考系从雷达转到底盘:

void SmallGicpRelocalizationNode::loadGlobalMap(const std::string & file_name)
{if (pcl::io::loadPCDFile<pcl::PointXYZ>(file_name, *global_map_) == -1) {RCLCPP_ERROR(this->get_logger(), "Couldn't read PCD file: %s", file_name.c_str());return;}RCLCPP_INFO(this->get_logger(), "Loaded global map with %zu points", global_map_->points.size());// NOTE: Transform global pcd_map (based on `lidar_odom` frame) to the `odom` frameEigen::Affine3d odom_to_lidar_odom;while (true) {try {auto tf_stamped = tf_buffer_->lookupTransform(base_frame_, lidar_frame_, this->now(), rclcpp::Duration::from_seconds(1.0));odom_to_lidar_odom = tf2::transformToEigen(tf_stamped.transform);RCLCPP_INFO_STREAM(this->get_logger(), "odom_to_lidar_odom: translation = "<< odom_to_lidar_odom.translation().transpose() << ", rpy = "<< odom_to_lidar_odom.rotation().eulerAngles(0, 1, 2).transpose());break;} catch (tf2::TransformException & ex) {RCLCPP_WARN(this->get_logger(), "TF lookup failed: %s Retrying...", ex.what());rclcpp::sleep_for(std::chrono::seconds(1));}}pcl::transformPointCloud(*global_map_, *global_map_, odom_to_lidar_odom);
}

接着对上步得到的点云进行降采样处理

  target_ = small_gicp::voxelgrid_sampling_omp<pcl::PointCloud<pcl::PointXYZ>, pcl::PointCloud<pcl::PointCovariance>>(*global_map_, global_leaf_size_);

然后就是计算点云的协方差矩阵并得出Kd搜索树

  // Estimate covariances of points 估计点的协方差small_gicp::estimate_covariances_omp(*target_, num_neighbors_, num_threads_);// Create KdTree for targettarget_tree_ = std::make_shared<small_gicp::KdTree<pcl::PointCloud<pcl::PointCovariance>>>(target_, small_gicp::KdTreeBuilderOMP(num_threads_));

最后就是一堆的订阅和接收话题,接下来对每个订阅和接收进行分析

  pcd_sub_ = this->create_subscription<sensor_msgs::msg::PointCloud2>("registered_scan", 10,std::bind(&SmallGicpRelocalizationNode::registeredPcdCallback, this, std::placeholders::_1));initial_pose_sub_ = this->create_subscription<geometry_msgs::msg::PoseWithCovarianceStamped>("initialpose", 10,std::bind(&SmallGicpRelocalizationNode::initialPoseCallback, this, std::placeholders::_1));register_timer_ = this->create_wall_timer(std::chrono::milliseconds(500),  // 2 Hzstd::bind(&SmallGicpRelocalizationNode::performRegistration, this));transform_timer_ = this->create_wall_timer(std::chrono::milliseconds(50),  // 20 Hzstd::bind(&SmallGicpRelocalizationNode::publishTransform, this));

2.pcd_sub

该函数的作用是将传感器获得的点云数据进行降采样和生成kd搜索树

void SmallGicpRelocalizationNode::registeredPcdCallback(const sensor_msgs::msg::PointCloud2::SharedPtr msg)
{last_scan_time_ = msg->header.stamp;pcl::fromROSMsg(*msg, *registered_scan_);// Downsample Registered points and convert them into pcl::PointCloud<pcl::PointCovariance>.source_ = small_gicp::voxelgrid_sampling_omp<pcl::PointCloud<pcl::PointXYZ>, pcl::PointCloud<pcl::PointCovariance>>(*registered_scan_, registered_leaf_size_);// Estimate point covariancessmall_gicp::estimate_covariances_omp(*source_, num_neighbors_, num_threads_);// Create KdTree for source.source_tree_ = std::make_shared<small_gicp::KdTree<pcl::PointCloud<pcl::PointCovariance>>>(source_, small_gicp::KdTreeBuilderOMP(num_threads_));
}

3.initial_pose_sub

该函数的作用是获得初始位姿并赋值(可以没有,没有就是默认【0,0,0】)

void SmallGicpRelocalizationNode::initialPoseCallback(const geometry_msgs::msg::PoseWithCovarianceStamped::SharedPtr msg)
{RCLCPP_INFO(this->get_logger(), "Received initial pose: [x: %f, y: %f, z: %f]", msg->pose.pose.position.x,msg->pose.pose.position.y, msg->pose.pose.position.z);Eigen::Isometry3d initial_pose;initial_pose.translation() << msg->pose.pose.position.x, msg->pose.pose.position.y,msg->pose.pose.position.z;initial_pose.linear() = Eigen::Quaterniond(msg->pose.pose.orientation.w, msg->pose.pose.orientation.x,msg->pose.pose.orientation.y, msg->pose.pose.orientation.z).toRotationMatrix();previous_result_t_ = initial_pose;result_t_ = initial_pose;
}

4.register_timer

该函数是核心部分,以上一步获得的初始位姿(如果有)为初始变换来对齐点云,使用的是gip函数库的align函数

void SmallGicpRelocalizationNode::performRegistration()
{if (!source_ || !source_tree_) {return;}register_->reduction.num_threads = num_threads_;register_->rejector.max_dist_sq = max_dist_sq_;// Align point clouds using the previous result as the initial transformation 使用上一个结果作为初始变换来对齐点云auto result = register_->align(*target_, *source_, *target_tree_, previous_result_t_);if (!result.converged) {RCLCPP_WARN(this->get_logger(), "GICP did not converge.");return;}result_t_ = result.T_target_source;previous_result_t_ = result.T_target_source;
}

5.transform_timer

将第4步获得的点云差进行tf转换作用到实际中去

void SmallGicpRelocalizationNode::publishTransform()
{if (result_t_.matrix().isZero()) {return;}geometry_msgs::msg::TransformStamped transform_stamped;// `+ 0.1` means transform into future. according to https://robotics.stackexchange.com/a/96615transform_stamped.header.stamp = last_scan_time_ + rclcpp::Duration::from_seconds(0.1);transform_stamped.header.frame_id = map_frame_;transform_stamped.child_frame_id = odom_frame_;const Eigen::Vector3d translation = result_t_.translation();const Eigen::Quaterniond rotation(result_t_.rotation());transform_stamped.transform.translation.x = translation.x();transform_stamped.transform.translation.y = translation.y();transform_stamped.transform.translation.z = translation.z();transform_stamped.transform.rotation.x = rotation.x();transform_stamped.transform.rotation.y = rotation.y();transform_stamped.transform.rotation.z = rotation.z();transform_stamped.transform.rotation.w = rotation.w();tf_broadcaster_->sendTransform(transform_stamped);
}

至此就是此代码的全部逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/877510.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qwen2.5-VL:更强大的多模态大模型|附实测结果

模型更新简述 几天前,通义千问更新了最新的多模态大模型Qwen2.5-VL,拥有包含 3B、7B 和 72B 在内的 3 个模型尺寸,同时完全开源,可在huggingface和modelscope下载到所有模型权重。 1. 更灵活的时空维度处理 ● 空间维度上,动态地将不同尺寸的图像转换为不同长度的token,并…

第五节上,图像分类实战,食物分类

随机种子固定随机结果,方便复现 def seed_everything(seed):torch.manual_seed(seed)torch.cuda.manual_seed(seed)torch.cuda.manual_seed_all(seed)torch.backends.cudnn.benchmark = Falsetorch.backends.cudnn.deterministic = Truerandom.seed(seed)np.random.seed(seed)o…

对比使用DeepSeek与文新一言,了解DeepSeek的关键技术论文

DeepSeek是国内大模型技术的新秀,最近也在业界和媒体界火爆出圈,所以想学习一下其技术。 大模型时代,学习知识,当然首先想到利用大模型,由于在过去一年,对DeepSeek使用不多,所以想和文新一言(4.0 Turbo)对比使用。 通过对比,针对同一个问题“DeepSeek发扬开源文化,将…

Cisco NX-OS Software Release 10.5(2)F - 网络操作系统软件

Cisco NX-OS Software Release 10.5(2)F - 网络操作系统软件Cisco NX-OS Software Release 10.5(2)F - 网络操作系统软件 NX-OS 网络操作系统 请访问原文链接:https://sysin.org/blog/cisco-nx-os-10/ 查看最新版。原创作品,转载请保留出处。 作者主页:sysin.orgCisco NX-OS…

pdf处理--tts(待重写)

1.提取正文2.裁剪页眉 https://smallpdf.com/cn/crop-pdf#r=crop-pages3.拆分4.ocr 效果图--白描:效果图--4Videosoft PDF Converter Ultimate:5.阅读器与tts引擎 开源阅读:https://github.com/gedoor/legado tts-server-android:https://github.com/jing332/tts-server-an…

INFINI Labs 产品更新 | Console 发布 TopN 功能,Easysearch 新增 Rollup 能力等

INFINI Labs 产品全新发布!此次更新为大家带来了 Console 的全新 TopN 功能,让您能够更高效地定位最关键的节点或索引;Easysearch 新增 Rollup 能力,大幅提升监控指标的存储周期并优化分析体验;此外,Framework 还修复了多项缺陷并进行了多处优化。欢迎下载体验,探索更多…

03-一个例子

登录被测系统bysms双击运行runserver.bat 访问页面:http://127.0.0.1/mgr/sign.html 账号:byhy,密码:88888888 可以直接在pycharm的Terminal中运行hytest,不需要打开命令行窗口 浏览器驱动的打印信息: 禁止 chromedriver 日志写屏1 from selenium import webdriver 2 3 …

blog tips

markdown 内嵌 html 使图片并排点击查看代码 <div style="display: flex; gap: 10px; justify-content: space-between;"><img src="图片1地址" style="width: 49%; height: auto;"/><img src="图片2地址" style="…

【数学】已知正方形相邻两点坐标求另外两点坐标

已知正方形相邻两点(a,b)与(c,d)坐标公式: \( (x_3,y_3) = (c + (b-d), d - (a-c)) \\ (x_4,y_4) = (a + (b-d), b - (a-c)) \\ (x_5,y_5) = (a - (b-d), b + (a-c)) \\ (x_6,y_6) = (c - (b-d), d + (a-c)) \)

25.1.31小记

多态类型声明类型 : 定义时候的类型 动态类型 : 运行到那里的时候对应的具体类型 向上造型(cast) : 将子类类型的对象赋给父类的变量 (不能将一个父类的变量赋予一个子类的变量) 赋值运算符 : 将管理者管理的对象进行改变(改变的是指针)其中造型(cast)的意义是将某…

MacOS修改应用快捷键的一般思路

具体步骤为:使用CheatSheet软件查看菜单项名称 在系统设置中修改菜单项的快捷键举个例子:修改Chrome中左右切换tab的快捷键(系统语言为英文,中文同理) 默认采用Ccontrol Tab和Control + Shift + Tab(或Command Shift [和Command Shift ])可以左右切换tab。 现在希望将其…

UE4.27, 模块实践, Slate的UI开发 (一)

1. 基本概念1.1. Slate是虚幻UI框架设计的底层,该框架中最基本的类是SWidget1.1.1.显然,我们容易注意到,直属于该框架的类拥有着指定的命名规则,即以S开头1.2. UMG, UWidget, Slate关联1.2.1. UMG:Unreal Motion Graphics UI Designer 虚幻的图形界面设计工具1.2.2. 单纯Sl…