Ros

sensor_msgs::LaserScan

Ros用LaserScan封装环境深度信息。激达雷达、深度摄像头用它定义发出的topic。

$ rosmsg show sensor_msgs/LaserScan
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

注:表中node_count表示这一帧包含的扫描点数目。

字段单位注释思岚RPLIDAR A1M8
angle_min弧度可检测范围的起始角度DEG2RAD(-179)
angle_max弧度可检测范围的终止角度,与angle_min组成传感器的FOV(视场角)DEG2RAD(180)
angle_increment弧度这一帧中相邻扫描点之间的夹角。一帧中所有扫描点间用同一步长(angle_max - angle_min) / (node_count-1)
time_increment这一帧中相邻扫描点之间的时间步长。当传感器处于相对运动状态时进行补偿使用scan_time / (node_count-1)
scan_time采集这一帧耗费的时间 
range_min最近可检测深度的阀值0.15
range_max最远可检测深度的阀值12
ranges存储这一帧深度数据的数组 

 

一、示例:思岚RPLIDAR A1M8如何生成LaserScan

/src/node.cpp
void publish_scan(ros::Publisher *pub,
                  rplidar_response_measurement_node_hq_t *nodes,
                  size_t node_count, ros::Time start,
                  double scan_time, bool inverted,
                  float angle_min, float angle_max,
                  float max_distance,
                  std::string frame_id)
{     
    // node_count表示这一帧包含的扫描点数目。值720,物理意义是每隔0.5度存在个扫描点。
    static int scan_count = 0;
    sensor_msgs::LaserScan scan_msg;

    scan_msg.header.stamp = start;
    scan_msg.header.frame_id = frame_id;
    scan_count++;

    // angle_min = DEG2RAD(0.0f) <= 0
    // float angle_max = DEG2RAD(359.0f) <= 6.26573
    bool reversed = (angle_max > angle_min);
    if ( reversed ) {
      scan_msg.angle_min =  M_PI - angle_max;
      scan_msg.angle_max =  M_PI - angle_min;
      // [angle_min, angle_max]换成角度相当于[-179, 180]
    } else {
      ...
    }
    scan_msg.angle_increment =
        (scan_msg.angle_max - scan_msg.angle_min) / (double)(node_count-1);

    scan_msg.scan_time = scan_time;
    scan_msg.time_increment = scan_time / (double)(node_count-1);
    scan_msg.range_min = 0.15; // A1M8最小测距15cm
    // A1M8最大测距和工作模式有关。工作在性能优先(Boost)模式时,最大测距12米
    scan_msg.range_max = max_distance; // 12.0

    scan_msg.intensities.resize(node_count);
    scan_msg.ranges.resize(node_count);
    bool reverse_data = (!inverted && reversed) || (inverted && !reversed);
    if (!reverse_data) {
        ...
    } else {
        for (size_t i = 0; i < node_count; i++) {
            // 公式dist_mm_q2/4.0f/1000算出该角度上障碍物距离。单位:米
            float read_value = (float)nodes[i].dist_mm_q2/4.0f/1000;
            if (read_value == 0.0) {
                // read_value = 0表示在range_max(12)米内该角度没障碍物
                scan_msg.ranges[node_count-1-i] = std::numeric_limits::infinity();
            } else
                scan_msg.ranges[node_count-1-i] = read_value;
            scan_msg.intensities[node_count-1-i] = (float) (nodes[i].quality >> 2);
        }
    }

    pub->publish(scan_msg);
}

为直观理解,让看下ranges中720个扫描点在直角坐标系的分布情况。红色表示该角度对应的扫描点深度值不是0,即存在障碍物。注意,图1是ranges中扫描点顺序,不是publish_scan中参数nodes中扫描点的顺序,reverse_data=true时,它们是相反。

图1 直角坐标系中显示一帧数据

A1M8在LaserScan报告的视场角是[-179, 180],因而ranges[0]存储的是-179度时的深度值。通过逆时针旋转,一直到180度,即ranges[719]存储的是180度时的深度值。也就是说,第3象限存储ranges最前面的1/4扫描点,第4象限是(1/4, 1/2),第1象限是(1/2, 3/4),第2象限则是最后的1/4。

全部评论: 0

    写评论: