lslidar_c16_decoder.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of lslidar_c16 driver.
3  *
4  * The driver is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * The driver is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with the driver. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
19 #include <std_msgs/Int8.h>
20 
21 using namespace std;
22 
23 namespace lslidar_c16_decoder {
24 LslidarC16Decoder::LslidarC16Decoder(
26  nh(n),
27  pnh(pn),
28  publish_point_cloud(true),
29  is_first_sweep(true),
30  last_azimuth(0.0),
31  sweep_start_time(0.0),
32  // layer_num(8),
33  packet_start_time(0.0),
34  sweep_data(new lslidar_c16_msgs::LslidarC16Sweep()),
35  multi_scan(new lslidar_c16_msgs::LslidarC16Layer())
36  {
37  return;
38 }
39 
41  pnh.param<int>("point_num", point_num, 1000);
42  pnh.param<int>("channel_num", layer_num, 8);
43  pnh.param<double>("min_range", min_range, 0.5);
44  pnh.param<double>("max_range", max_range, 100.0);
45  pnh.param<double>("angle_disable_min", angle_disable_min,-1);
46  pnh.param<double>("angle_disable_max", angle_disable_max, -1);
47  pnh.param<double>("angle3_disable_min", angle3_disable_min, -1);
48  pnh.param<double>("angle3_disable_max", angle3_disable_max, -1);
49  double tmp_min, tmp_max;
50  ROS_WARN("discard Point cloud angle from %2.2f to %2.2f", angle3_disable_min, angle3_disable_max);
51  tmp_min = 2*M_PI - angle3_disable_max;
52  tmp_max = 2*M_PI - angle3_disable_min;
53  angle3_disable_min = tmp_min;
54  angle3_disable_max = tmp_max;
55  ROS_WARN("switch angle from %2.2f to %2.2f in left hand rule", angle3_disable_min, angle3_disable_max);
56  pnh.param<double>("frequency", frequency, 20.0);
57  pnh.param<bool>("publish_point_cloud", publish_point_cloud, true);
58  pnh.param<bool>("publish_scan", publish_scan, false);
59  pnh.param<bool>("apollo_interface", apollo_interface, false);
60  //pnh.param<string>("fixed_frame_id", fixed_frame_id, "map");
61  pnh.param<string>("frame_id", frame_id, "lslidar");
62 
63  pnh.param<bool>("use_gps_ts", use_gps_ts, false);
64  ROS_WARN("Using GPS timestamp or not %d", use_gps_ts);
65  angle_base = M_PI*2 / point_num;
66 
67  if (publish_scan)
68  {
69  ROS_INFO("require to publish scan type message");
70  } else{
71  ROS_WARN("scan message not publish");
72  }
73 
74  if (apollo_interface)
75  ROS_WARN("This is apollo interface mode");
76  return true;
77 }
78 
80  packet_sub = nh.subscribe<lslidar_c16_msgs::LslidarC16Packet>(
81  "lslidar_packet", 100, &LslidarC16Decoder::packetCallback, this);
83  "layer_num", 100, &LslidarC16Decoder::layerCallback, this);
84  sweep_pub = nh.advertise<lslidar_c16_msgs::LslidarC16Sweep>(
85  "lslidar_sweep", 10);
86  point_cloud_pub = nh.advertise<sensor_msgs::PointCloud2>(
87  "lslidar_point_cloud", 10);
88  scan_pub = nh.advertise<sensor_msgs::LaserScan>(
89  "scan", 100);
90  channel_scan_pub = nh.advertise<lslidar_c16_msgs::LslidarC16Layer>(
91  "scan_channel", 100);
92  return true;
93 }
94 
96  if (!loadParameters()) {
97  ROS_ERROR("Cannot load all required parameters...");
98  return false;
99  }
100 
101  if (!createRosIO()) {
102  ROS_ERROR("Cannot create ROS I/O...");
103  return false;
104  }
105 
106  // Fill in the altitude for each scan.
107  for (size_t scan_idx = 0; scan_idx < 16; ++scan_idx) {
108  size_t remapped_scan_idx = scan_idx%2 == 0 ? scan_idx/2 : scan_idx/2+8;
109  sweep_data->scans[remapped_scan_idx].altitude = scan_altitude[scan_idx];
110  }
111 
112  // Create the sin and cos table for different azimuth values.
113  for (size_t i = 0; i < 6300; ++i) {
114  double angle = static_cast<double>(i) / 1000.0;
115  cos_azimuth_table[i] = cos(angle);
116  sin_azimuth_table[i] = sin(angle);
117  }
118 
119  return true;
120 }
121 
123  for (size_t blk_idx = 0; blk_idx < BLOCKS_PER_PACKET; ++blk_idx) {
124  if (packet->blocks[blk_idx].header != UPPER_BANK) {
125  //ROS_WARN("Skip invalid LS-16 packet: block %lu header is %x",
126  //blk_idx, packet->blocks[blk_idx].header);
127  return false;
128  }
129  }
130  return true;
131 }
132 
133 
135 // VPointCloud::Ptr point_cloud(new VPointCloud());
136  pcl::PointCloud<pcl::PointXYZI>::Ptr point_cloud(new pcl::PointCloud<pcl::PointXYZI>);
137  // pcl_conversions::toPCL(sweep_data->header).stamp;
138  point_cloud->header.frame_id = frame_id;
139  point_cloud->height = 1;
140 
141  for (size_t i = 0; i < 16; ++i) {
142  const lslidar_c16_msgs::LslidarC16Scan& scan = sweep_data->scans[i];
143  // The first and last point in each scan is ignored, which
144  // seems to be corrupted based on the received data.
145  // TODO: The two end points should be removed directly
146  // in the scans.
147  double timestamp = ros::Time::now().toSec();
148  if (use_gps_ts){
149  point_cloud->header.stamp = static_cast<uint64_t>(sweep_start_time * 1e6);
150  }
151  else{
152  point_cloud->header.stamp = static_cast<uint64_t>(timestamp * 1e6);
153  }
154 
155  if (scan.points.size() == 0) continue;
156  size_t j;
157  pcl::PointXYZI point;
158  for (j = 1; j < scan.points.size()-1; ++j) {
159  if ((scan.points[j].azimuth > angle3_disable_min) and (scan.points[j].azimuth < angle3_disable_max))
160  {
161  continue;
162  }
163  point.x = scan.points[j].x;
164  point.y = scan.points[j].y;
165  point.z = scan.points[j].z;
166  point.intensity = scan.points[j].intensity;
167  point_cloud->points.push_back(point);
168  ++point_cloud->width;
169  }
170  }
171 
172  sensor_msgs::PointCloud2 pc_msg;
173  pcl::toROSMsg(*point_cloud, pc_msg);
174  point_cloud_pub.publish(pc_msg);
175 
176  return;
177 }
178 
179 // void LslidarC16Decoder::publishPointCloud() {
180 // pcl::PointCloud<pcl::PointXYZIT>::Ptr point_cloud(
181 // new pcl::PointCloud<pcl::PointXYZIT>());
182 // point_cloud->header.stamp =
183 // pcl_conversions::toPCL(sweep_data->header).stamp;
184 // point_cloud->header.frame_id = frame_id;
185 // point_cloud->height = 1;
186 
187 // for (size_t i = 0; i < 16; ++i) {
188 // const lslidar_c16_msgs::LslidarC16Scan& scan = sweep_data->scans[i];
189 // // The first and last point in each scan is ignored, which
190 // // seems to be corrupted based on the received data.
191 // // TODO: The two end points should be removed directly
192 // // in the scans.
193 // if (scan.points.size() == 0) continue;
194 // size_t j;
195 // for (j = 1; j < scan.points.size()-1; ++j) {
196 
197 // pcl::PointXYZIT point;
198 // point.x = scan.points[j].x;
199 // point.y = scan.points[j].y;
200 // point.z = scan.points[j].z;
201 // point.intensity = scan.points[j].intensity;
202 // point.timestamp = ros::Time::now();
203 // point_cloud->points.push_back(point);
204 // ++point_cloud->width;
205 // }
206 
207 // }
208 
209 // // if(point_cloud->width > 2000)
210 // {
211 // point_cloud_pub.publish(point_cloud);
212 // }
213 // return;
214 // }
215 
217 {
218  multi_scan = lslidar_c16_msgs::LslidarC16LayerPtr(
219  new lslidar_c16_msgs::LslidarC16Layer());
220  // lslidar_c16_msgs::LslidarC16Layer multi_scan(new lslidar_c16_msgs::LslidarC16Layer);
221  sensor_msgs::LaserScan scan;
222 
223  int layer_num_local = layer_num;
224  ROS_INFO_ONCE("default channel is %d", layer_num_local );
225  if(sweep_data->scans[layer_num_local].points.size() <= 1)
226  return;
227 
228  for (uint16_t j=0; j<16; j++)
229  {
230  scan.header.frame_id = frame_id;
231  scan.header.stamp = sweep_data->header.stamp;
232 
233  scan.angle_min = 0.0;
234  scan.angle_max = 2.0*M_PI;
235  scan.angle_increment = (scan.angle_max - scan.angle_min)/point_num;
236 
237  // scan.time_increment = motor_speed_/1e8;
238  scan.range_min = min_range;
239  scan.range_max = max_range;
240  scan.ranges.reserve(point_num);
241  scan.ranges.assign(point_num, std::numeric_limits<float>::infinity());
242 
243  scan.intensities.reserve(point_num);
244  scan.intensities.assign(point_num, std::numeric_limits<float>::infinity());
245 
246  for(uint16_t i = 0; i < sweep_data->scans[j].points.size(); i++)
247  {
248  double point_azimuth = sweep_data->scans[j].points[i].azimuth;
249  int point_idx = point_azimuth / angle_base;
250  if (fmod(point_azimuth, angle_base) > (angle_base/2.0))
251  {
252  point_idx ++;
253  }
254 
255  if (point_idx >= point_num)
256  point_idx = 0;
257  if (point_idx < 0)
258  point_idx = point_num - 1;
259 
260  scan.ranges[point_num - 1-point_idx] = sweep_data->scans[j].points[i].distance;
261  scan.intensities[point_num - 1-point_idx] = sweep_data->scans[j].points[i].intensity;
262  }
263 
264  for (int i = point_num - 1; i >= 0; i--)
265  {
266  if((i >= angle_disable_min*point_num/360) && (i < angle_disable_max*point_num/360))
267  scan.ranges[i] = std::numeric_limits<float>::infinity();
268  }
269 
270  multi_scan->scan_channel[j] = scan;
271  if (j == layer_num_local)
272  scan_pub.publish(scan);
273  }
274 
276 
277 }
278 
279 
281 {
282  sensor_msgs::LaserScan::Ptr scan(new sensor_msgs::LaserScan);
283  int layer_num_local = layer_num;
284  ROS_INFO_ONCE("default channel is %d", layer_num_local);
285  if(sweep_data->scans[layer_num_local].points.size() <= 1)
286  return;
287 
288  scan->header.frame_id = frame_id;
289  scan->header.stamp = sweep_data->header.stamp;
290 
291  scan->angle_min = 0.0;
292  scan->angle_max = 2.0*M_PI;
293  scan->angle_increment = (scan->angle_max - scan->angle_min)/point_num;
294 
295  // scan->time_increment = motor_speed_/1e8;
296  scan->range_min = min_range;
297  scan->range_max = max_range;
298  scan->ranges.reserve(point_num);
299  scan->ranges.assign(point_num, std::numeric_limits<float>::infinity());
300 
301  scan->intensities.reserve(point_num);
302  scan->intensities.assign(point_num, std::numeric_limits<float>::infinity());
303 
304  for(uint16_t i = 0; i < sweep_data->scans[layer_num_local].points.size(); i++)
305  {
306  double point_azimuth = sweep_data->scans[layer_num_local].points[i].azimuth;
307  int point_idx = point_azimuth / angle_base;
308 // printf("azi %f, point idx %d\t", point_azimuth, point_idx);
309  if (fmod(point_azimuth, angle_base) > (angle_base/2.0))
310  {
311  point_idx ++;
312 // printf("\t new idx %d", point_idx);
313  }
314 // printf("\n");
315 
316  if (point_idx >= point_num)
317  point_idx = 0;
318  if (point_idx < 0)
319  point_idx = point_num - 1;
320 
321  scan->ranges[point_num - 1-point_idx] = sweep_data->scans[layer_num_local].points[i].distance;
322  scan->intensities[point_num - 1-point_idx] = sweep_data->scans[layer_num_local].points[i].intensity;
323  }
324 
325  for (int i = point_num - 1; i >= 0; i--)
326  {
327  if((i >= angle_disable_min*point_num/360) && (i < angle_disable_max*point_num/360))
328  scan->ranges[i] = std::numeric_limits<float>::infinity();
329  }
330 
331  scan_pub.publish(scan);
332 
333 }
334 
335 
336 point_struct LslidarC16Decoder::getMeans(std::vector<point_struct> clusters)
337 {
338  point_struct tmp;
339  int num = clusters.size();
340  if (num == 0)
341  {
342  tmp.distance = std::numeric_limits<float>::infinity();
343  tmp.intensity = std::numeric_limits<float>::infinity();
344 
345  }
346  else
347  {
348  double mean_distance = 0, mean_intensity = 0;
349 
350  for (int i = 0; i < num; i++)
351  {
352  mean_distance += clusters[i].distance;
353  mean_intensity += clusters[i].intensity;
354  }
355 
356  tmp.distance = mean_distance / num;
357  tmp.intensity = mean_intensity / num;
358  }
359  return tmp;
360 }
361 
363 
364  // Compute the azimuth angle for each firing.
365  for (size_t fir_idx = 0; fir_idx < FIRINGS_PER_PACKET; fir_idx+=2) {
366  size_t blk_idx = fir_idx / 2;
368  packet->blocks[blk_idx].rotation);
369  }
370 
371  // Interpolate the azimuth values
372  for (size_t fir_idx = 1; fir_idx < FIRINGS_PER_PACKET; fir_idx+=2) {
373  size_t lfir_idx = fir_idx - 1;
374  size_t rfir_idx = fir_idx + 1;
375 
376  double azimuth_diff;
377  if (fir_idx == FIRINGS_PER_PACKET - 1) {
378  lfir_idx = fir_idx - 3;
379  rfir_idx = fir_idx - 1;
380  }
381 
382  azimuth_diff = firings[rfir_idx].firing_azimuth -
383  firings[lfir_idx].firing_azimuth;
384  azimuth_diff = azimuth_diff < 0 ? azimuth_diff + 2*M_PI : azimuth_diff;
385 
386  firings[fir_idx].firing_azimuth =
387  firings[fir_idx-1].firing_azimuth + azimuth_diff/2.0;
388 
389 
390  firings[fir_idx].firing_azimuth =
391  firings[fir_idx].firing_azimuth > 2*M_PI ?
392  firings[fir_idx].firing_azimuth-2*M_PI : firings[fir_idx].firing_azimuth;
393  }
394 
395  // Fill in the distance and intensity for each firing.
396  for (size_t blk_idx = 0; blk_idx < BLOCKS_PER_PACKET; ++blk_idx) {
397  const RawBlock& raw_block = packet->blocks[blk_idx];
398 
399  for (size_t blk_fir_idx = 0; blk_fir_idx < FIRINGS_PER_BLOCK; ++blk_fir_idx){
400  size_t fir_idx = blk_idx*FIRINGS_PER_BLOCK + blk_fir_idx;
401 
402  double azimuth_diff = 0.0;
403  if (fir_idx < FIRINGS_PER_PACKET - 1)
404  azimuth_diff = firings[fir_idx+1].firing_azimuth -
405  firings[fir_idx].firing_azimuth;
406  else
407  azimuth_diff = firings[fir_idx].firing_azimuth -
408  firings[fir_idx-1].firing_azimuth;
409 
410  for (size_t scan_fir_idx = 0; scan_fir_idx < SCANS_PER_FIRING; ++scan_fir_idx){
411  size_t byte_idx = RAW_SCAN_SIZE * (
412  SCANS_PER_FIRING*blk_fir_idx + scan_fir_idx);
413 
414  // Azimuth
415  firings[fir_idx].azimuth[scan_fir_idx] = firings[fir_idx].firing_azimuth +
416  (scan_fir_idx*DSR_TOFFSET/FIRING_TOFFSET) * azimuth_diff;
417 
418  // Distance
419  TwoBytes raw_distance;
420  raw_distance.bytes[0] = raw_block.data[byte_idx];
421  raw_distance.bytes[1] = raw_block.data[byte_idx+1];
422  firings[fir_idx].distance[scan_fir_idx] = static_cast<double>(
423  raw_distance.distance) * DISTANCE_RESOLUTION;
424 
425  // Intensity
426  firings[fir_idx].intensity[scan_fir_idx] = static_cast<double>(
427  raw_block.data[byte_idx+2]);
428  }
429  }
430  }
431  // for (size_t fir_idx = 0; fir_idx < FIRINGS_PER_PACKET; ++fir_idx)
432  //{
433  // ROS_WARN("[%f %f %f]", firings[fir_idx].azimuth[0], firings[fir_idx].distance[0], firings[fir_idx].intensity[0]);
434  //}
435  return;
436 }
437 
438 void LslidarC16Decoder::layerCallback(const std_msgs::Int8Ptr& msg){
439  int num = msg->data;
440  if (num < 0)
441  {
442  num = 0;
443  ROS_WARN("layer num outside of the index, select layer 0 instead!");
444  }
445  else if (num > 15)
446  {
447  num = 15;
448  ROS_WARN("layer num outside of the index, select layer 15 instead!");
449  }
450  ROS_INFO("select layer num: %d", msg->data);
451  layer_num = num;
452  return;
453 }
454 
456  const lslidar_c16_msgs::LslidarC16PacketConstPtr& msg) {
457  // ROS_WARN("packetCallBack");
458  // Convert the msg to the raw packet type.
459  const RawPacket* raw_packet = (const RawPacket*) (&(msg->data[0]));
460 
461  // Check if the packet is valid
462  if (!checkPacketValidity(raw_packet)) return;
463 
464  // Decode the packet
465  decodePacket(raw_packet);
466 
467  // Find the start of a new revolution
468  // If there is one, new_sweep_start will be the index of the start firing,
469  // otherwise, new_sweep_start will be FIRINGS_PER_PACKET.
470  size_t new_sweep_start = 0;
471  do {
472  // if (firings[new_sweep_start].firing_azimuth < last_azimuth) break;
473  if (fabs(firings[new_sweep_start].firing_azimuth - last_azimuth) > M_PI) break;
474  else {
475  last_azimuth = firings[new_sweep_start].firing_azimuth;
476  ++new_sweep_start;
477  }
478  } while (new_sweep_start < FIRINGS_PER_PACKET);
479  // ROS_WARN("new_sweep_start %d", new_sweep_start);
480 
481  // The first sweep may not be complete. So, the firings with
482  // the first sweep will be discarded. We will wait for the
483  // second sweep in order to find the 0 azimuth angle.
484  size_t start_fir_idx = 0;
485  size_t end_fir_idx = new_sweep_start;
486  if (is_first_sweep &&
487  new_sweep_start == FIRINGS_PER_PACKET) {
488  // The first sweep has not ended yet.
489  return;
490  } else {
491  if (is_first_sweep) {
492  is_first_sweep = false;
493  start_fir_idx = new_sweep_start;
494  end_fir_idx = FIRINGS_PER_PACKET;
495  sweep_start_time = msg->stamp.toSec() +
496  FIRING_TOFFSET * (end_fir_idx-start_fir_idx) * 1e-6;
497  }
498  }
499 
500  for (size_t fir_idx = start_fir_idx; fir_idx < end_fir_idx; ++fir_idx) {
501  for (size_t scan_idx = 0; scan_idx < SCANS_PER_FIRING; ++scan_idx) {
502  // Check if the point is valid.
503  if (!isPointInRange(firings[fir_idx].distance[scan_idx])) continue;
504 
505  // Convert the point to xyz coordinate
506  size_t table_idx = floor(firings[fir_idx].azimuth[scan_idx]*1000.0+0.5);
507  //cout << table_idx << endl;
508  double cos_azimuth = cos_azimuth_table[table_idx];
509  double sin_azimuth = sin_azimuth_table[table_idx];
510 
511  //double x = firings[fir_idx].distance[scan_idx] *
512  // cos_scan_altitude[scan_idx] * sin(firings[fir_idx].azimuth[scan_idx]);
513  //double y = firings[fir_idx].distance[scan_idx] *
514  // cos_scan_altitude[scan_idx] * cos(firings[fir_idx].azimuth[scan_idx]);
515  //double z = firings[fir_idx].distance[scan_idx] *
516  // sin_scan_altitude[scan_idx];
517 
518  double x = firings[fir_idx].distance[scan_idx] *
519  cos_scan_altitude[scan_idx] * sin_azimuth;
520  double y = firings[fir_idx].distance[scan_idx] *
521  cos_scan_altitude[scan_idx] * cos_azimuth;
522  double z = firings[fir_idx].distance[scan_idx] *
523  sin_scan_altitude[scan_idx];
524 
525  double x_coord = y;
526  double y_coord = -x;
527  double z_coord = z;
528 
529  // Compute the time of the point
530  double time = packet_start_time +
531  FIRING_TOFFSET*fir_idx + DSR_TOFFSET*scan_idx;
532 
533  // Remap the index of the scan
534  int remapped_scan_idx = scan_idx%2 == 0 ? scan_idx/2 : scan_idx/2+8;
535  sweep_data->scans[remapped_scan_idx].points.push_back(
536  lslidar_c16_msgs::LslidarC16Point());
537 
538  lslidar_c16_msgs::LslidarC16Point& new_point = // new_point 为push_back最后一个的引用
539  sweep_data->scans[remapped_scan_idx].points[
540  sweep_data->scans[remapped_scan_idx].points.size()-1];
541 
542  // Pack the data into point msg
543  new_point.time = time;
544  new_point.x = x_coord;
545  new_point.y = y_coord;
546  new_point.z = z_coord;
547  new_point.azimuth = firings[fir_idx].azimuth[scan_idx];
548  new_point.distance = firings[fir_idx].distance[scan_idx];
549  new_point.intensity = firings[fir_idx].intensity[scan_idx];
550  }
551  }
552 
553  packet_start_time += FIRING_TOFFSET * (end_fir_idx-start_fir_idx);
554 
555  // A new sweep begins
556  if (end_fir_idx != FIRINGS_PER_PACKET) {
557  // ROS_WARN("A new sweep begins");
558  // Publish the last revolution
559  sweep_data->header.frame_id = "sweep";
560 
561  if (use_gps_ts){
562  sweep_data->header.stamp = ros::Time(sweep_start_time);
563  }
564  else{
565  sweep_data->header.stamp = ros::Time::now();
566  }
567 
568 
570 
571  if (publish_point_cloud){
573  }
574  if (publish_scan){
575  publishScan();
576  // publishChannelScan();
577  }
578  // else{
579  // publishScan();
580  // }
581 
582  sweep_data = lslidar_c16_msgs::LslidarC16SweepPtr(
583  new lslidar_c16_msgs::LslidarC16Sweep());
584 
585  // Prepare the next revolution
586  sweep_start_time = msg->stamp.toSec() +
587  FIRING_TOFFSET * (end_fir_idx-start_fir_idx) * 1e-6;
588 
589  packet_start_time = 0.0;
591 
592  start_fir_idx = end_fir_idx;
593  end_fir_idx = FIRINGS_PER_PACKET;
594 
595  for (size_t fir_idx = start_fir_idx; fir_idx < end_fir_idx; ++fir_idx) {
596  for (size_t scan_idx = 0; scan_idx < SCANS_PER_FIRING; ++scan_idx) {
597  // Check if the point is valid.
598  if (!isPointInRange(firings[fir_idx].distance[scan_idx])) continue;
599 
600  // Convert the point to xyz coordinate
601  size_t table_idx = floor(firings[fir_idx].azimuth[scan_idx]*1000.0+0.5);
602  //cout << table_idx << endl;
603  double cos_azimuth = cos_azimuth_table[table_idx];
604  double sin_azimuth = sin_azimuth_table[table_idx];
605 
606  //double x = firings[fir_idx].distance[scan_idx] *
607  // cos_scan_altitude[scan_idx] * sin(firings[fir_idx].azimuth[scan_idx]);
608  //double y = firings[fir_idx].distance[scan_idx] *
609  // cos_scan_altitude[scan_idx] * cos(firings[fir_idx].azimuth[scan_idx]);
610  //double z = firings[fir_idx].distance[scan_idx] *
611  // sin_scan_altitude[scan_idx];
612 
613  double x = firings[fir_idx].distance[scan_idx] *
614  cos_scan_altitude[scan_idx] * sin_azimuth;
615  double y = firings[fir_idx].distance[scan_idx] *
616  cos_scan_altitude[scan_idx] * cos_azimuth;
617  double z = firings[fir_idx].distance[scan_idx] *
618  sin_scan_altitude[scan_idx];
619 
620  double x_coord = y;
621  double y_coord = -x;
622  double z_coord = z;
623 
624  // Compute the time of the point
625  double time = packet_start_time +
626  FIRING_TOFFSET*(fir_idx-start_fir_idx) + DSR_TOFFSET*scan_idx;
627 
628  // Remap the index of the scan
629  int remapped_scan_idx = scan_idx%2 == 0 ? scan_idx/2 : scan_idx/2+8;
630  sweep_data->scans[remapped_scan_idx].points.push_back(
631  lslidar_c16_msgs::LslidarC16Point());
632  lslidar_c16_msgs::LslidarC16Point& new_point =
633  sweep_data->scans[remapped_scan_idx].points[
634  sweep_data->scans[remapped_scan_idx].points.size()-1];
635 
636  // Pack the data into point msg
637  new_point.time = time;
638  new_point.x = x_coord;
639  new_point.y = y_coord;
640  new_point.z = z_coord;
641  new_point.azimuth = firings[fir_idx].azimuth[scan_idx];
642  new_point.distance = firings[fir_idx].distance[scan_idx];
643  new_point.intensity = firings[fir_idx].intensity[scan_idx];
644  }
645  }
646 
647  packet_start_time += FIRING_TOFFSET * (end_fir_idx-start_fir_idx);
648  }
649  // ROS_WARN("pack end");
650  return;
651 }
652 
653 } // end namespace lslidar_c16_decoder
654 
static const double DISTANCE_RESOLUTION
uint16_t rotation
0-35999, divide by 100 to get degrees
void layerCallback(const std_msgs::Int8Ptr &msg)
point_struct getMeans(std::vector< point_struct > clusters)
void packetCallback(const lslidar_c16_msgs::LslidarC16PacketConstPtr &msg)
void publish(const boost::shared_ptr< M > &message) const
#define ROS_INFO_ONCE(...)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
bool isPointInRange(const double &distance)
static const int FIRINGS_PER_BLOCK
TFSIMD_FORCE_INLINE tfScalar distance(const Vector3 &v) const
TFSIMD_FORCE_INLINE const tfScalar & y() const
#define ROS_WARN(...)
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
static const double cos_scan_altitude[16]
static const int FIRINGS_PER_PACKET
static const double FIRING_TOFFSET
void decodePacket(const RawPacket *packet)
double rawAzimuthToDouble(const uint16_t &raw_azimuth)
lslidar_c16_msgs::LslidarC16LayerPtr multi_scan
static const double scan_altitude[16]
static const int RAW_SCAN_SIZE
lslidar_c16_msgs::LslidarC16SweepPtr sweep_data
#define ROS_INFO(...)
static const int SCANS_PER_FIRING
bool param(const std::string &param_name, T &param_val, const T &default_val) const
TFSIMD_FORCE_INLINE const tfScalar & x() const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
TFSIMD_FORCE_INLINE const tfScalar & z() const
static const double sin_scan_altitude[16]
static const double DSR_TOFFSET
static const int BLOCKS_PER_PACKET
bool checkPacketValidity(const RawPacket *packet)
void toROSMsg(const sensor_msgs::PointCloud2 &cloud, sensor_msgs::Image &image)
static Time now()
static const uint16_t UPPER_BANK
#define ROS_ERROR(...)


lslidar_c16_decoder
Author(s): Yutong
autogenerated on Thu Aug 22 2019 03:51:41