激光雷达的功能包为sensor_ws下的bluesea功能包。
激光雷达,全称为激光探测和测距雷达(Light Detection and
Ranging),又称光学雷达。它是一种利用激光束来测量物体距离、形状和运动的设备。它通过发射激光束,然后测量激光束从发射器到目标物体反射回来所需的时间,从而计算出物体的距离。激光雷达可以产生高精度的二维和三维空间图像,因此在自动驾驶、机器人、地图制作等领域内得到广泛应用。激光雷达的优点包括测量精度高、测量范围广、可靠性高、抗干扰能力强等。
无人机测绘 | 扫地机器人避障 | 自动驾驶 |
---|---|---|
![]() |
![]() |
![]() |
在机器人上,我们使用的雷达种类主要是固态激光雷达和旋转式激光雷达。
固态激光雷达:
固态激光雷达是一种利用固态激光器作为光源的激光雷达。相比于其他类型的激光雷达,固态激光雷达的优点在于其结构简单、体积小、功耗低、寿命长等特点。此外,由于固态激光雷达采用了先进的半导体激光器技术,因此其测距、测量精度和信噪比也更高。
固态激光雷达通常由激光发射器、接收器、光学系统、信号处理器和控制单元等组件组成。其中,激光发射器负责发射激光束,光学系统则用于收集反射回来的光信号,并将其聚焦到接收器上。接收器会将接收到的光信号转化为电信号,并通过信号处理器进行处理,最终输出三维点云数据。控制单元则负责对激光雷达进行控制和管理。
固态激光雷达主要应用于自动驾驶、机器人、测绘、工业检测等领域。例如,在自动驾驶中,固态激光雷达可以用于检测和识别道路上的障碍物和行驶路线,为高/低速自动驾驶提供高精度的环境感知和定位服务。
旋转式激光雷达:
旋转式激光雷达是一种常见的激光雷达,它采用旋转镜片或它们的组合来扫描激光束。相比于固态激光雷达,旋转式激光雷达的主要优点在于其能够实现全方位的扫描,因此能够获取更加完整和准确的环境信息。
旋转式激光雷达通常由激光发射器、旋转镜片、接收器、光学系统、信号处理器和控制单元等组件组成。其中,激光发射器向旋转镜片发射激光束,旋转镜片则将激光束扫描到不同的方向。接收器接收反射回来的光信号,并将其转化为电信号。信号处理器对这些电信号进行处理,并生成点云数据。控制单元则负责对激光雷达进行控制和管理。
旋转式激光雷达广泛应用于机器人、自动驾驶、无人机、地形测量、建筑物信息模型等领域。例如,在机器人领域,旋转式激光雷达可以用于机器人的定位和导航,提供环境感知能力。在自动驾驶领域,旋转式激光雷达可以用于车辆的障碍物检测和路径规划。
不论是什么类型的激光雷达,它采用的测距原理都是发射器发射激光,接收器接收激光,利用激光束的时差测量原理实现的。具体来说,激光雷达发射出一个激光束,激光束照射到目标物体上并被反射回来,激光雷达接收到反射回来的激光束并记录下反射回来的时间。由于激光传播速度是已知的,因此可以根据反射时间计算出激光束从激光雷达到目标物体的距离。
激光雷达是卓越之星与智行系列非常重要的传感器,我们通常用它来进行导航与避障等功能的开发。
激光雷达与搭载ROS系统的AI核心处理器通过串口连接。
在卓越之星与智行系列产品中,我们使用的激光雷达的ROS驱动在sensor_ws工作空间内,sensor_ws是所有与传感器息息相关的工作空间。激光雷达代码在bluesea文件夹内。
我们在VSCode中RemoteSSH模式下远程打开一个终端
激光雷达在AI处理器上做了相应的串口绑定,如果正确连接了雷达,会在Linux系统挂载相应的端口号,在终端输入下面指令查询雷达硬件是否连接:
ls /dev/lidar
下面现象证明已经正确连接在指定端口:
在雷达驱动功能包中,由于不同构型的安装位置不同,雷达可能存在正装,倒装,反装等安装方式,我们需要屏蔽不同的安装角度,因此,针对不同的构型,需要启动不同的launch文件来驱动激光雷达。
如果是智行W2A,在终端中输入下面的launch,启动激光雷达。
roslaunch bluesea2 lidar_e200_w2a.launch
如果是智行W2C,在终端中输入下面的launch,启动激光雷达。
roslaunch bluesea2 lidar_e200_w2c.launch
如果是智行W2U,在终端中输入下面的launch,启动激光雷达。
roslaunch bluesea2 lidar_e200_w2u.launch
如果是智行W3S,在终端中输入下面的launch,启动激光雷达。
roslaunch bluesea2 lidar_e200_w3s.launch
如果是智行W4A,在终端中输入下面的launch,启动激光雷达。
roslaunch bluesea2 lidar_e200_w4a.launch
这里,我们以智行W2A的雷达启动launch为例进行分析:
<node name="lidar01" pkg="bluesea2" type="bluesea2_node" output="screen">
#ROS#
<param name="topic" value="scan"/>
<param name="frame_id" value="laser_link"/>
#DATA#
<param name="logPath" value="/tmp/log"/>
<param name="raw_bytes" value="3"/>
<param name="min_dist" value="0.1"/>
<param name="max_dist" value="50.0"/>
<param name="zero_shift" value="0"/>
<param name="from_zero" value="false"/>
<param name="output_scan" value="true"/>
<param name="output_cloud" value="false"/>
<param name="output_360" value="true"/>
<param name="with_checksum" value="true"/>
<param name="inverted" value="true"/>
<param name="reversed" value="false"/>
<param name="hard_resample" value="false"/>
<param name="soft_resample" value="false"/>
<param name="with_angle_filter" value="true"/>
<param name="min_angle" value="-3.1415926"/>
<param name="max_angle" value="3.1415926"/>
<rosparam param="mask1">[0.52,0.98]</rosparam>
<rosparam param="mask2">[-0.98,-0.52]</rosparam>
<rosparam param="mask3">[2.09,2.62]</rosparam>
<rosparam param="mask4">[-2.62,-2.09]</rosparam>
<param name="error_circle" value="3"/>
<param name="error_scale" value="0.9"/>
#CONNECT#
<param name="type" value="uart"/>
<param name="port" value="/dev/lidar"/>
<param name="baud_rate" value="921600"/>
#GET#
<param name="uuid" value="-1"/>
<param name="model" value="1"/>
#SET#
<param name="rpm" value="-1"/>
<param name="resample_res" value="-1"/>
<param name="unit_is_mm" value="-1"/>
<param name="with_smooth" value="-1"/>
<param name="with_deshadow" value="-1"/>
<param name="with_confidence" value="-1"/>
</node>
可以看到,激光雷达是通过一个名为bluesea_node的节点驱动与硬件的通信,通信方式为串口,串口号绑定为/dev/lidar,波特率921600,向外发布的topic为scan(也可以自行修改为其他的topic),激光雷达数据的frame_id为laser_link,可作为与机器人本地,地图等坐标系坐标变换的依据。
启动通信launch后,可以观察到如下现象,终端打印出通信信息,证明激光雷达开始正常工作了。
rostopic echo /scan --noarr
右侧的”+“号新建终端,输入下面指令:
根据此,可总结激光雷达的消息信息:
Topic | /scan |
---|---|
frame_id | laser_link |
扫描角度 | -pi ~ pi |
角度分辨率 | -0.00349(2*pi / 1800) |
扫描最小距离 | 0.1m |
扫描最大距离 | 50m |
一圈多少个点 | 1800 |
使用Nomachine使用Rviz查看(将Global Option下Fixed Frame设置为激光雷达的frame_id:laser_link):
然后添加激光雷达数据源:
左下角Add-》选择By topic-》选择/scan下的LaserScan
得到了激光雷达的数据可视化展示:
得到了激光雷达信息的展示,线条是激光点打在障碍物
![]() |
|
---|
接下来我们实现一个 ROS 节点来获取从驱动传来的单线激光雷达信息,获取名为/scan 的主题中激光点的个数,以及第一个和最后一个激光点的距离数据;
一般来说,ROS上关于传感器处理的程序使用C++来进行开发,运行效率和实时性更强,这里不给出Python程序,感兴趣的同学可以自行实现。
#include <ros/ros.h>
#include <sensor_msgs/LaserScan.h>
void scanCallback(const sensor_msgs::LaserScan::ConstPtr &scan) {
// 获取激光点的个数
int num_points = (scan->angle_max - scan->angle_min) / scan->angle_increment;
ROS_INFO_STREAM("Number of points: " << num_points);
// 获取第一个激光点的距离,位于机器人正前方,角度-pi
float first_range = scan->ranges[0];
ROS_INFO_STREAM("First range: " << first_range);
// 获取最后一个激光点(1800)的距离,位于机器人正前方,角度pi
float last_range = scan->ranges[num_points - 1];
ROS_INFO_STREAM("Last range: " << last_range);
// 获取中间激光点(900)的距离,位于机器人正后方,角度0
float half_range = scan->ranges[num_points/2];
ROS_INFO_STREAM("Half range: " << half_range );
// 获取左侧激光点(450)的距离,位于机器人正左方,角度-pi/2
float left_range = scan->ranges[num_points/4];
ROS_INFO_STREAM("Left range: " << left_arange );
// 获取右侧激光点(1350)的距离,位于机器人正右方,角度pi/2
float right_range = scan->ranges[num_points / 4 * 3];
ROS_INFO_STREAM("Right range: " << right_range );
}
int main(int argc, char **argv) {
// 初始化ROS节点
ros::init(argc, argv, "laser_scan_listener");
// 创建节点句柄
ros::NodeHandle n;
// 订阅/scan话题
ros::Subscriber sub = n.subscribe("/scan", 1000, scanCallback);
// 循环等待回调函数
ros::spin();
return 0;
}
运行上述节点,打印出激光雷达五个点的距离,通过这个案例,打印出激光雷达正前方,正左方,正后方,正右方四个方向的障碍物距离。