rplidar屏蔽雷达角度

对于rplidar 雷达,特点是360度扫描结果,无死角。而有时候,我们没需要用到360度,只需要270度或者更少,这时需要在代码里对数据进行裁剪。

rplidar扫描角度的定义,如下图:

A1型号:


A2型号:



通常我们选取是laser 正前方的扇型数据,从上图可以看出

例如正面180度扇型数据,那么选取的度数为0~90,270~359的数据

270度面的扇型数据,选取度数为0~135, 225~359的数据

回到代码中

1.下载rplidar node的源码https://github.com/robopeak/rplidar_ros

2.打开node.cpp文件,简单看下逻辑

op_result = drv->grabScanData(nodes, count);
抓取一个完整的0-360度的扫描数据
op_result = drv->ascendScanData(nodes, count); //nodes[0] 代表0度角的扫描数据,即nodes[90]代表90度角的扫描数据
按照扫描角度升序方式将数据排序这样我们需要的数据就是nodes[0]~nodes[135],nodes[225]~nodes[359]。

然后用publish_scan将数据发布出去,

我所采取的方式是修改publish_scan函数,即将0~360的数据都传入该函数,这样有没有设置angle_compensate都不影响发布的数据。

默认是angle_compensate = true,即传入的数据是已经优化过的。我也试过外面进行角度裁剪,不过看扫描的结果,优化后的数据都堆到一起了,十分不准确。

如果想在main函数中进行裁剪,一定要搞清楚角度优化的原理。搞清楚下面变量的作用和优化算法,待更新~~

  1. const int angle_compensate_multiple = 1;
  2. int angle_compensate_offset = 0;
  3. rplidar_response_measurement_node_t angle_compensate_nodes[angle_compensate_nodes_count];
  4. memset(angle_compensate_nodes, 0, angle_compensate_nodes_count*sizeof(rplidar_response_measurement_node_t));
  5. int i = 0, j = 0;
  6. for( ; i < count; i++ ) {
  7.     if ( nodes[ i] .distance_q2 != 0) {
  8.       float angle = (float)((nodes[i].angle_q6_checkbit >> RPLIDAR_RESP_MEASUREMENT_ANGLE_SHIFT)/64.0f);
  9.       int angle_value = (int)(angle * angle_compensate_multiple);
  10.       if ((angle_value - angle_compensate_offset) < 0) angle_compensate_offset = angle_value;
  11.       for (j = 0; j < angle_compensate_multiple; j++) {
  12.           angle_compensate_nodes[angle_value-angle_compensate_offset+j] = nodes[i];
  13. }
  14. }
  15. }


查看publish_scan函数:
  1. void publish_scan(ros::Publisher *pub,
  2. rplidar_response_measurement_node_t *nodes, //扫描数据
  3. size_t node_count, ros::Time start, //扫描数据的个数,开始时间
  4. double scan_time, bool inverted, //扫描时长,是否是倒置的
  5. float angle_min, float angle_max, //最小角度和最大角度
  6. std::string frame_id)
  7. {
  8. static int scan_count = 0;
  9. sensor_msgs::LaserScan scan_msg;
  10. scan_msg.header.stamp = start;
  11. scan_msg.header.frame_id = frame_id;
  12. scan_count++;
  13. bool reversed = (angle_max > angle_min); //将最小和最大角度进行修正,是数据从小到大。
  14. if ( reversed ) {
  15. scan_msg.angle_min = M_PI - angle_max;
  16. scan_msg.angle_max = M_PI - angle_min;
  17. } else {
  18. scan_msg.angle_min = M_PI - angle_min;
  19. scan_msg.angle_max = M_PI - angle_max;
  20. }
  21. scan_msg.angle_increment =
  22. (scan_msg.angle_max - scan_msg.angle_min) / (double)(node_count-1);
  23. scan_msg.scan_time = scan_time;
  24. scan_msg.time_increment = scan_time / (double)(node_count-1);
  25. scan_msg.range_min = 0.15;
  26. scan_msg.range_max = 8.0;
  27. scan_msg.intensities.resize(node_count);
  28. scan_msg.ranges.resize(node_count);
  29. bool reverse_data = (!inverted && reversed) || (inverted && !reversed);
  30. if (!reverse_data) {
  31. for (size_t i = 0; i < node_count; i++) {
  32. float read_value = (float) nodes[ i] .distance_q2/ 4.0f/ 1000;
  33. if ( read_value == 0.0)
  34. scan_msg.ranges[ i] = std::numeric_limits< float>::infinity();
  35. else
  36. scan_msg.ranges[i] = read_value; //这里可以看出,scan_msg.range与node[i]是一一对应的。
  37. scan_msg.intensities[i] = (float) (nodes[i].sync_quality >> 2);
  38. }
  39. } else {
  40. for (size_t i = 0; i < node_count; i++) {
  41. float read_value = (float)nodes[i].distance_q2/4.0f/1000;
  42. if ( read_value == 0.0)
  43. scan_msg.ranges[ node_count-1-i] = std::numeric_limits< float>::infinity();
  44. else
  45. scan_msg.ranges[node_count-1-i] = read_value;
  46. scan_msg.intensities[node_count-1-i] = (float) (nodes[i].sync_quality >> 2);
  47. }
  48. }
  49. pub->publish(scan_msg);
  50. }


修改后的代码:

  1. void publish_scan(ros::Publisher *pub,
  2. rplidar_response_measurement_node_t *nodes,
  3. size_t node_count, ros::Time start,
  4. double scan_time, bool inverted,
  5. float angle_min, float angle_max,
  6. std::string frame_id)
  7. {
  8. static int scan_count = 0;
  9. sensor_msgs::LaserScan scan_msg;
  10. scan_msg.header.stamp = start;
  11. scan_msg.header.frame_id = frame_id;
  12. scan_count++;
  13. bool reversed = (angle_max > angle_min);
  14. if ( reversed ) {
  15. scan_msg.angle_min = M_PI - angle_max;
  16. scan_msg.angle_max = M_PI - angle_min;
  17. } else {
  18. scan_msg.angle_min = M_PI - angle_min;
  19. scan_msg.angle_max = M_PI - angle_max;
  20. }
  21. scan_msg.angle_increment =
  22. (scan_msg.angle_max - scan_msg.angle_min) / (double)(node_count-1);
  23. scan_msg.scan_time = scan_time;
  24. scan_msg.time_increment = scan_time / (double)(node_count-1);
  25. scan_msg.range_min = 0.15;
  26. scan_msg.range_max = 8.0;
  27. scan_msg.intensities.resize(node_count);
  28. scan_msg.ranges.resize(node_count);
  29. bool reverse_data = (!inverted && reversed) || (inverted && !reversed); //修改后的代码reverse_data就没有用处了。
  30. /* 将rplidar放到hokuyo的位置,角度信息见上面的图如下
  31. 0度/前
  32. 270度/左 rplidar的方向 90度/右
  33. 180度/后
  34. kobuki接收到 LaserScan scan_msg.ranges数据对应的角度信息
  35. 180度/前
  36. 270度/左 kobuki的方向 90度/右
  37. 0度/后
  38. 要把 0~90度对应的node数据映射到 180~90度的scan_msg.ranges中
  39. 要把 90~180度对应的node数据映射到 90~0度的scan_msg.ranges中
  40. 要把 180~270度对应的node数据映射到 359~270度的scan_msg.ranges中
  41. 要把 270~359度对应的node数据映射到 270~180度的scan_msg.ranges中
  42. */
  43. const size_t degree_90 = 90; //固定值,算法需要
  44. const size_t degree_270 = 270; //固定值,算法需要
  45. const size_t left_degrees = 225; // 裁剪的范围 保留数据225~359.
  46. const size_t right_degrees = 135; // 裁剪的范围 保留数据0~135.
  47. //先全部置inf,注意:如果初始化是0,则表示范围内无障碍,故不能置0。inf表示无数据
  48. for (size_t i = 0; i < node_count; i++){
  49. scan_msg.ranges[ i] = std::numeric_limits< float>::infinity();
  50. }
  51. //将数据分别对应设置进去
  52. for (size_t i = 0; i < node_count; i++)
  53. {
  54. float read_value = (float) nodes[i].distance_q2/4.0f/1000;
  55. if (i < right_degrees)
  56. {
  57. if (read_value == 0.0) scan_msg.ranges[2*degree_90 - i] = std::numeric_limits<float>::infinity();
  58. else
  59. scan_msg.ranges[2*degree_90 - i] = read_value;
  60. scan_msg.intensities[2*degree_90 - i] = (float) (nodes[i].sync_quality >> 2);
  61. }
  62. else if (i > left_degrees)
  63. {
  64. if (read_value == 0.0) scan_msg.ranges[2*degree_270 - i] = std::numeric_limits <float>::infinity();
  65. else
  66. scan_msg.ranges[2*degree_270 - i] = read_value;
  67. scan_msg.intensities[2*degree_270 - i] = (float) (nodes[i].sync_quality >> 2);
  68. }
  69. else
  70. {
  71. //do nothing;
  72. }
  73. }
  74. //发布出去
  75. pub->publish(scan_msg);
  76. }

讲需要裁剪的角度放到launch文件中,当作参数传入,比在代码中修改好很多

例如:在rplidar.launch文件中加入

  1. <param name="cut_angle" type="bool" value="true"/>
  2. <param name="right_degrees" type="int" value="90"/>
  3. <param name="left_degrees" type="int" value="270"/>
然后在main函数中增加
  1. /**/
  2. nh_private.param <bool>("cut_angle", cut_angle, false);
  3. if (cut_angle){
  4. nh_private.param <int>("left_degrees", left_degrees, 180);
  5. nh_private.param <int>("right_degrees", right_degrees, 180);
  6. }
  7. /**/
就可以实现。

猜你喜欢

转载自blog.csdn.net/u014453443/article/details/80890238