代码参考:小程序Basic(aplt.leagor.basic)有一个雷达驱动实例tlaser_base。支持N10、RPLIDAR A1M8。
雷达硬件要求:要用于辅助解决机器人绑架,必须用视角360度的激光雷达,不能深度摄像头。更要硬件参数参考“硬件规范”。
一、输出规范
1.1 settings.cfg
laser_driver = true
根下需存在键“laser_driver”,值是bool类型的“true”。
1.2 libroseaplt.so需输出函数:aplt_create_laser_slot
void* aplt_create_laser_slot();
返回值是个指向aplt::tlaser_slot对象的指针。
二、tlaser_slot api
对雷达驱动,核心就一个功能。
- 发布话题:/scan,消息类型:sensor_msgs::LaserScan,frame_id须是laser。但发布时不要调用类似“pub_.publish(msg)”,而是调用rose_ros提供的ros.laser_publish_scan(msg)。
发布时为什么要调用rose_ros提供的ros.laser_publish_scan(msg)?——launcher要把雷达驱动发的LaserScan和其它传感器进行融合,像深度相机,融合后的LaserScan再以话题名“scan”发出。也就是说,scan话题内容是多传感器融合后的LaserScan。话题叫“scan”,是为和cartographer中的变量kLaserScanTopic值保持一致。
ros.laser_publish_scan在发出scan话题时,还会发出话题laser_scan,其内容才是雷达驱动的sensor_msgs::LaserScan。

- (主线程)会在多种场合调用get_serial_path,从而得到雷达串口路径和波特率。
- (主线程)要开始导航了,会调用ros_instance::start_navigation_node,参数buildmap表示此次是否是建图,但不会把这参数传到雷达驱动。
- (start_navigation_node)调用驱动pre_start_laser方法。在这里,可做些运行节点线程前的准备工作。
- (start_navigation_node)创建并运行新线程:laser_driver_node。这线程的线程函数叫start_laser。
- (start_laser)这是驱动必须重载的函数,运行在节点线程(laser_driver_node)。这个函数行为非常像ros中已有的雷达节点,所以线程名用了“_node”字样。它一般要做几件事。1)打开/关闭串口;2)发布话题:/scan,消息类型:sensor_msgs::LaserScan,frame_id须是laser。
三、雷达数据后绪传播
3.1 (laser_driver_node节点线程)雷达驱动调用ros.laser_publish_scan
主要执行两个操作。
- 融入相机点云。融入操作:integrate_dcamera_LaserScan()。
- 发布两个话题,一个是融合了相机点云的scan,一个雷达驱动直接出来的laser_scan。
3.2 (主线程)接收到scan话题,调用对应处理例程tros_instance::did_scan_subscribed。在那里会执行kidnap_slice。
为什么launcher不在ros.laser_publish_scan就调用kidnap_slice等操作,而是要额外出来一个接收scan话题的did_scan_subscribed?
- kidnap_slice有可能须要重启cartographer_node节点,并一直等到重启成功。这cartographer_node重启需要接收到scan话题,可能发送scan话题却laser_publish_scan阻住了,编程一不注意就可能造成死锁。
- ros.laser_publish_scan不是运行在主线程,kidnap_slice是必须运行在主线程的。
3.3 (cartographer_node节点线程)接收scan话题,进行slam建图
char kLaserScanTopic[] = "scan";
cartographer_node中变量kLaserScanTopic指示要从哪话题接收前端传感器数据,正是因为它,决定了话题要叫“scan”。