雷达驱动(tlaser_slot)

代码参考:小程序Basic(aplt.leagor.basic)有一个雷达驱动实例tlaser_base。支持RPLIDAR A1M8、N10。

雷达硬件要求:要用于辅助解决机器人绑架,必须用视角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。

图1 tlaser_slot api
  1. (主线程)会在多种场合调用get_serial_path,从而得到雷达串口路径和波特率。
  2. (主线程)要开始导航了,会调用ros_instance::start_navigation_node,参数buildmap表示此次是否是建图,但不会把这参数传到雷达驱动。
  3. (start_navigation_node)调用驱动pre_start_laser方法。在这里,可做些运行节点线程前的准备工作。
  4. (start_navigation_node)创建并运行新线程:laser_driver_node。这线程的线程函数叫start_laser。
  5. (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

主要执行两个操作。

  1. 融入相机点云。融入操作:integrate_dcamera_LaserScan()。
  2. 发布两个话题,一个是融合了相机点云的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”。

全部评论: 0

    写评论: