ROS下Python2转Python3的URG激光雷达180度滤波失效问题
问题现象
将Python2版本可正常运行的URG激光雷达滤波代码迁移至Python3,目标是将原270度扫描输出裁剪为180度范围。ROS环境下启动launch文件无报错、进程运行正常,但RVIZ中观测到传感器仍输出270度扫描数据,未实现预期裁剪效果。
根因定位
- RVIZ显示话题配置错误:滤波节点发布的裁剪后数据话题为
/scan_filtered,若RVIZ中订阅的是URG驱动原生发布的/scan话题,会一直显示原始270度扫描数据,和滤波节点逻辑无关。 - launch文件中URG驱动参数配置无效:配置的
angle_max=-2.3562、angle_min=2.3562违反ROS LaserScan消息规范(要求angle_min < angle_max),同时start_angle=270、end_angle=40的跨零配置未做正确适配,驱动会直接忽略无效参数,默认输出270度原始扫描数据。 - 滤波代码硬编码索引适配性差:代码中写死索引偏移
ID_0DEG=180、ID_180DEG=900,未根据原始扫描数据的实际角度范围、角度增量动态计算裁剪位置,若原始点云数量、角度分辨率和硬编码预期不匹配,会出现裁剪错位、范围不符合预期的问题。 - Python3下列表初始化逻辑冗余:原代码用
list(range(num_filter))生成整数类型的空列表再循环赋值,虽然不会直接报错,但存在类型隐式转换风险,且循环赋值效率低于原生切片操作。
修复方案
修正RVIZ显示配置
打开RVIZ的LaserScan插件配置,将订阅的Topic从原始/scan修改为滤波节点输出的/scan_filtered,确认Fixed Frame设置为lrf_link或存在正确TF变换的父坐标系。修正launch文件URG驱动参数
删除无效的反角度、跨零角度配置,若需要直接让雷达硬件输出180度数据,可将参数修改为如下内容:
<node pkg="urg_node" name="urg_node" type="urg_node"> <param name="ip_address" value="192.168.0.10"/> <param name="frame_id" value="lrf_link" /> <!-- 180度扫描对应-90°~+90°,换算为弧度是-1.5708~1.5708 --> <param name="angle_min" value="-1.5708" /> <param name="angle_max" value="1.5708" /> </node>
如果需要保留软件裁剪逻辑、让雷达输出原生270度数据再做滤波,可以注释掉angle_min、angle_max相关配置,使用驱动默认参数即可。
- 修正滤波代码硬编码逻辑
替换原代码中固定索引裁剪的逻辑,根据原始激光数据的角度参数动态计算裁剪范围,增加边界保护,用Python原生切片替代循环赋值,修正后的回调函数代码如下:
def call_scan(self, data): self.newdata.header = data.header # 目标裁剪范围:正前方-90°~+90° target_min = -math.pi / 2.0 target_max = math.pi / 2.0 self.newdata.angle_min = target_min self.newdata.angle_max = target_max self.newdata.angle_increment = data.angle_increment self.newdata.time_increment = data.time_increment self.newdata.scan_time = data.scan_time self.newdata.range_min = data.range_min self.newdata.range_max = data.range_max # 动态计算裁剪索引,替代硬编码 start_idx = int(round((target_min - data.angle_min) / data.angle_increment)) end_idx = int(round((target_max - data.angle_min) / data.angle_increment)) # 索引越界保护 start_idx = max(0, start_idx) end_idx = min(len(data.ranges) - 1, end_idx) # 切片直接截取数据,兼容Python3类型要求 self.newdata.ranges = list(data.ranges[start_idx:end_idx+1]) self.newdata.intensities = list(data.intensities[start_idx:end_idx+1]) self.pub_scan.publish(self.newdata) # 后续Range消息发布逻辑适配实际数据长度 for x in range(0, len(self.newdata.ranges), STEP2): self.range.field_of_view = int(AREA_ANGLE - x * AREA_ANGLE / len(self.newdata.ranges)) self.range.range = self.newdata.ranges[x] self.pub_range.publish(self.range)
- 功能验证
启动launch文件后,依次执行以下操作验证:- 执行
rostopic list,确认存在/scan和/scan_filtered两个话题 - 执行
rostopic echo /scan_filtered -n1,查看输出的angle_min=-1.57、angle_max=1.57,ranges数组长度为720左右(对应0.25度角分辨率的180度扫描) - 回到RVIZ查看点云显示,确认扫描范围为正前方180度。
- 执行
内容的提问来源于stack exchange,提问作者mattcrouse
相关产品推荐
相关产品推荐

