全国大学生智能汽车竞赛--讯飞组解读(五)

2026.01.16

激光雷达

测试雷达启动

官方的激光雷达功能包为ydlidar,主要的启动文件为ydlidar.launch

roslaunch ydlidar ydlidar.launch

终端有如下输出并且听到雷达转起来说明启动正常。

图片走丢了...
雷达正常启动

rviz的使用

rviz是ROS的一个可视化工具,熟练使用rviz可以大大提高我们的调试效率。接下来我们将尝试使用rviz查看雷达数据。

在激光雷达启动的同时,另一个终端执行rviz,这时桌面会弹出rviz窗口。

图片走丢了...
rviz窗口

在右上方Fixed Frame中选择base_link,然后点击右下方add选择LaserScan

图片走丢了...
添加配置

你会发现LaserScan被添加到了右边栏,接着点击LaserScan中的Topic选择/scan话题,这相当于rviz订阅了雷达话题并且可视化显示出来。接着右边就会显示出激光点。上方点击Move Camera后,就可以用鼠标在图中移动视角,鼠标滚轮可以缩放,按住shift移动可以平移视角。你也可以将Size设置大一点看得更清楚,其他的参数不再赘述。

图片走丢了...
雷达可视化

这里解释一下:Fixed Frame是全局参考坐标系,选择baselink相当于以小车底盘中心为全局参考坐标系。你也可以选择为laser_frame为全局参考坐标系,会发现激光点没有什么区别。这是因为雷达安装在小车头部,其坐标原点的偏移量很小,所以看不出来区别。

可以在雷达启动文件ydlidar.launch的末尾发现:

<node pkg="tf" type="static_transform_publisher" name="base_link_to_laser"
    args="0.11 0.0 0.13 -0.07 0.0  0.0 /base_link /laser_frame 40" />

这其实就是发布了雷达与小车底盘的位置关系,args中定义的就是相对位置和偏移量等。你可以这么来理解TF:小车上安装了许多传感器,那么ROS如何知道这些传感器安装在哪呢?所以你需要设定一个全局参考坐标系(通常为小车底盘中心),然后发布每个传感器与小车底盘中心的相对位置关系。这样ROS就知道每个传感器的安装位置了。

为什么要这么做呢?比如雷达是安装在小车头部而并非中心的,那么测出前方障碍物的距离就是相对于头部的距离。如果我们知道雷达与base_link的TF关系,就可以用TF变换将障碍物的位置换算到小车中心。

你可以在rviz中添加TF,就可以直观的看到雷达和底盘的位置关系。

图片走丢了...
TF可视化

雷达可视化启动

我们知道,一个launch文件可以包含多个节点。这里我们将编写自己的launch文件,同时启动雷达和rviz,这样就不用每次开很多终端一个一个开节点。在以后,你也可以将需要的节点全部放到一个launch文件中,就可以实现一键启动。

在我们自己的功能包benz下创建一个launch目录,再新建一个show_laser.launch,添加以下代码:

<launch>
    <include file="$(find ydlidar)/launch/ydlidar.launch" />
    <node name="rviz" pkg="rviz" type="rviz" args="" output="screen"/>
</launch>

运行会发现同时启动了雷达和rviz,但是rviz没有任何配置。

roslaunch benz show_laser.launch

在rviz上将需要的配置添加后,你可以在功能包下创建一个config目录,然后点击右上角File选择save config as将文件保存到该目录下。此后你可以在launch文件中添加这个参数文件,可以直接打开需要的配置。注意在修改rviz配置后需要ctrl+S保存。

<launch>
    <include file="$(find ydlidar)/launch/ydlidar.launch" />
    <node name="rviz" pkg="rviz" type="rviz" args="-d $(find benz)/config/show_lidar.rviz" output="screen"/>
</launch>

获取激光雷达数据

启动雷达后,在终端执行

rosmsg show sensor_msgs/LaserScan

可以看到雷达数据格式如下,其中比较重要的是angle_minangle_maxangle_increment

std_msgs/Header header
  uint32 seq
  time stamp
  string frame_id
float32 angle_min        # 扫描开始角度(弧度)
float32 angle_max        # 扫描结束角度(弧度)
float32 angle_increment  # 两个测量点之间的角度间隔(弧度)
float32 time_increment   # 两个测量点之间的时间间隔(秒)
float32 scan_time        # 一次扫描所用时间(秒)
float32 range_min        # 最小可测距离(米)
float32 range_max        # 最大可测距离(米)
float32[] ranges         # 距离数组(米)
float32[] intensities    # 反射强度数组(可选)

执行以下命令查看具体数据的值。

rostopic echo /scan --noarr

可以从其中一条中看到类似。

angle_min: -3.1415927410125732
angle_max: 3.1415927410125732
angle_increment: 0.00691219512373209

通过这三个值以及激光数组ranges的长度我们就可以计算出角度与数组索引的关系(具体计算交给AI)。下面用一个demo获取小车正前方障碍物的距离。

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
import rospy
from sensor_msgs.msg import LaserScan

def scan_callback(msg):
    """
    获取正前方障碍物距离
    """
    # 计算正前方索引
    # angle_min + i * angle_increment = 0
    # i = round(-angle_min / angle_increment)
    i = round(-msg.angle_min / msg.angle_increment)

    # 防止索引越界
    if i < 0 or i >= len(msg.ranges):
        rospy.logwarn("前方索引越界")
        return

    front_distance = msg.ranges[i]
    rospy.loginfo("正前方障碍物距离: {:.2f} m".format(front_distance))

def main():
    rospy.init_node('front_lidar_distance')
    rospy.Subscriber('/scan', LaserScan, scan_callback)
    rospy.spin()

if __name__ == '__main__':
    main()

更多关于全国大学生智能汽车的分享,请访问个人主页。 期待你的评论与交流!