一起做激光反光板(四)-框架搭建

我们已经推导了基本的反光板建图和定位的基本公式,接下来,开始搭建一个框架,尝试进行反光板的建图定位的代码加进去。

首先,搭建一个ROS框架,在我的个人github的reflector_ekf_slam上上传一个基于激光反光板的EKF建图定位方案。

基本框架:

ROS接收topic:

scan: sensor_msgs::LaserScan
odom: nav_msgs::Odometry

需要注意的是:

(1)轮速计数据必须有线速度和角速度,轮速计的方差写死了:

Qu_ << 0.02 * 0.02, 0.f, 0.f, 0.034 * 0.034;

(2)只接受单线激光雷达的数据。

发出的topic:

ekf_slam/landmark:visualization_msgs::MarkerArray
ekf_slam/pose: geometry_msgs::PoseWithCovarianceStamped
ekf_slam/path: nav_msgs::Path

发布的消息:

(1)反光板地图

(2)实时位姿

(3)历史轨迹

反光板检测与匹配

(1)反光板检测:

其实代码中所写的检测方案是最容易想到的,但是在实际使用的时候,在工程上无法满足需求。有提升的方法,但是在博客中不太好介绍,故当前的检测要求是环境中布置的都是30cm长的反光板,且只能支持这一种反光板。检测的要求是长度不超过3cm的偏差。

另外,代码中没有进行运动畸变校正操作,这是非常危险的,因为在高速运动的过程中,运动畸变会很大,容易造成检测失败和关联错误。

(2)反光板匹配

反光板的匹配是通过马氏距离计算的,马氏距离的阈值设置为0.05。

(3)外参转换问题

外参在代码中写死了:

lidar_to_base_link_ << 0.41589, 0.25639, 0.0;

需要标定的呀。之所以写在类内,是因为之后打算做在线外参估计。当然,这个程序也可以作为单线激光雷达外参标定程序来用。

(4)观测残差

在类内写死了:

Qt_ << 0.03 * 0.03, 0.f, 0.f, 0.03 * 0.03; 

建图和定位EKF

建图和定位用的是一个框架,具体实现需要看代码。

地图的保存和读取

通过txt保存,后续可以改进为xml、json、proto等。保存的内容:

反光板的坐标 ( x , y ) (x,y) (x,y)和协方差 Σ \Sigma Σ

问题

(1)反光板检测和匹配(不再优化)

(2)激光帧未进行运动畸变校正

(3)激光帧的信息只用了反射强度,点云没用,有点可惜

(4)激光雷达的外参需要在线估计

后续待更新部分

(1)激光帧未进行运动畸变校正

(2)激光雷达的外参在线估计

(3)基于滑窗的EKF公式推导

(4)扩充观测:激光线特征、直角特征

(5)扩充观测:帧间ICP

(6)FEJ

(7)利用EKF位姿构建栅格地图

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
以下是一个基于ROS下2D激光雷达提取反光柱坐标的示例代码及注释,希望能对您有所帮助: ```python #!/usr/bin/env python # -*- coding: utf-8 -*- import rospy import math import numpy as np from sensor_msgs.msg import LaserScan from geometry_msgs.msg import PointStamped class ReflectivePillarDetection: def __init__(self): # 初始化ROS节点 rospy.init_node('reflective_pillar_detection', anonymous=True) # 订阅激光雷达数据 self.laser_sub = rospy.Subscriber('/scan', LaserScan, self.laser_callback) # 发布反光柱坐标 self.pillar_pub = rospy.Publisher('/reflective_pillar', PointStamped, queue_size=10) # 反光柱的最小距离,单位:米 self.pillar_min_distance = 0.2 # 反光柱的最大距离,单位:米 self.pillar_max_distance = 2.0 # 激光雷达数据中的最小角度,单位:弧度 self.angle_min = -math.pi / 2 # 激光雷达数据中的最大角度,单位:弧度 self.angle_max = math.pi / 2 def laser_callback(self, msg): # 获取激光雷达数据 ranges = msg.ranges # 获取激光雷达数据中的角度间隔 angle_increment = msg.angle_increment # 获取激光雷达数据中的起始角度 angle_start = msg.angle_min # 获取激光雷达数据中的结束角度 angle_end = msg.angle_max # 计算激光雷达数据中的角度值 angles = np.arange(angle_start, angle_end + angle_increment, angle_increment) # 初始反光柱坐标值 pillar_x = 0 pillar_y = 0 # 统计反光柱个数 pillar_count = 0 # 遍历激光雷达数据 for i in range(len(ranges)): # 获取当前激光雷达数据点的距离值 range_i = ranges[i] # 获取当前激光雷达数据点的角度值 angle_i = angles[i] # 如果当前激光雷达数据点距离小于最小距离或大于最大距离,则跳过该点 if range_i < self.pillar_min_distance or range_i > self.pillar_max_distance: continue # 如果当前激光雷达数据点的角度值不在最小角度和最大角度之间,则跳过该点 if angle_i < self.angle_min or angle_i > self.angle_max: continue # 计算当前激光雷达数据点的坐标值 x = range_i * math.cos(angle_i) y = range_i * math.sin(angle_i) # 如果当前激光雷达数据点的y值小于0,则跳过该点 if y < 0: continue # 更新反光柱坐标值 pillar_x += x pillar_y += y # 增加反光柱个数 pillar_count += 1 # 如果没有检测到反光柱,则不发布反光柱坐标 if pillar_count == 0: return # 计算反光柱坐标平均值 pillar_x /= pillar_count pillar_y /= pillar_count # 发布反光柱坐标 pillar_msg = PointStamped() pillar_msg.header.stamp = rospy.Time.now() pillar_msg.header.frame_id = 'laser' pillar_msg.point.x = pillar_x pillar_msg.point.y = pillar_y pillar_msg.point.z = 0 self.pillar_pub.publish(pillar_msg) if __name__ == '__main__': ReflectivePillarDetection() rospy.spin() ``` 注释中已经对代码进行了详细的解释,代码实现的主要思路是遍历激光雷达数据,依次计算每个数据点的坐标值,并更新反光柱坐标值。最后计算反光柱坐标平均值并发布。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值