lslidar_n301_decoder.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of lslidar_n301 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 
20 using namespace std;
21 
22 namespace lslidar_n301_decoder {
23 LslidarN301Decoder::LslidarN301Decoder(
25  nh(n),
26  pnh(pn),
27  publish_point_cloud(true),
28  use_gps_ts(false),
29  is_first_sweep(true),
30  last_azimuth(0.0),
31  sweep_start_time(0.0),
32  packet_start_time(0.0),
33  sweep_data(new lslidar_n301_msgs::LslidarN301Sweep()){
34  return;
35 }
36 
38  pnh.param<int>("point_num", point_num, 1000);
39  pnh.param<double>("min_range", min_range, 0.5);
40  pnh.param<double>("max_range", max_range, 100.0);
41  pnh.param<double>("angle_disable_min", angle_disable_min,-1);
42  pnh.param<double>("angle_disable_max", angle_disable_max, -1);
43 
44  pnh.param<double>("frequency", frequency, 20.0);
45  pnh.param<bool>("publish_point_cloud", publish_point_cloud, false);
46  pnh.param<bool>("use_gps_ts", use_gps_ts, false);
47  pnh.param<string>("fixed_frame_id", fixed_frame_id, "map");
48  pnh.param<string>("child_frame_id", child_frame_id, "lslidar");
49 
50  angle_base = M_PI*2 / point_num;
51 
52  ROS_WARN("Using GPS timestamp or not %d", use_gps_ts);
53  return true;
54 }
55 
57  packet_sub = nh.subscribe<lslidar_n301_msgs::LslidarN301Packet>(
58  "lslidar_packet", 100, &LslidarN301Decoder::packetCallback, this);
59  sweep_pub = nh.advertise<lslidar_n301_msgs::LslidarN301Sweep>(
60  "lslidar_sweep", 10);
61  point_cloud_pub = nh.advertise<sensor_msgs::PointCloud2>(
62  "lslidar_point_cloud", 10);
63  scan_pub = nh.advertise<sensor_msgs::LaserScan>(
64  "scan", 100);
65  return true;
66 }
67 
69  if (!loadParameters()) {
70  ROS_ERROR("Cannot load all required parameters...");
71  return false;
72  }
73 
74  if (!createRosIO()) {
75  ROS_ERROR("Cannot create ROS I/O...");
76  return false;
77  }
78 
79  // Fill in the altitude for each scan.
80  for (size_t scan_idx = 0; scan_idx < 16; ++scan_idx) {
81  size_t remapped_scan_idx = scan_idx%2 == 0 ? scan_idx/2 : scan_idx/2+8;
82  sweep_data->scans[remapped_scan_idx].altitude = scan_altitude[scan_idx];
83  }
84 
85  // Create the sin and cos table for different azimuth values.
86  for (size_t i = 0; i < 6300; ++i) {
87  double angle = static_cast<double>(i) / 1000.0;
88  cos_azimuth_table[i] = cos(angle);
89  sin_azimuth_table[i] = sin(angle);
90  }
91 
92  return true;
93 }
94 
96  for (size_t blk_idx = 0; blk_idx < BLOCKS_PER_PACKET; ++blk_idx) {
97  if (packet->blocks[blk_idx].header != UPPER_BANK) {
98  ROS_WARN("Skip invalid LS-16 packet: block %lu header is %x",
99  blk_idx, packet->blocks[blk_idx].header);
100  return false;
101  }
102  }
103  return true;
104 }
105 
107 // pcl::PointCloud<pcl::PointXYZI>::Ptr point_cloud(
108 // new pcl::PointCloud<pcl::PointXYZI>());
109 
110  VPointCloud::Ptr point_cloud(new VPointCloud());
111  double timestamp = sweep_data->header.stamp.toSec();
112  point_cloud->header.stamp =
113  pcl_conversions::toPCL(sweep_data->header).stamp;
114  point_cloud->header.frame_id = child_frame_id;
115  point_cloud->height = 1;
116 
117  for (size_t i = 0; i < 16; ++i) {
118  const lslidar_n301_msgs::LslidarN301Scan& scan = sweep_data->scans[i];
119  // The first and last point in each scan is ignored, which
120  // seems to be corrupted based on the received data.
121  // TODO: The two end points should be removed directly
122  // in the scans.
123  if (scan.points.size() == 0) continue;
124  size_t j;
125  for (j = 1; j < scan.points.size()-1; ++j) {
126 
127  VPoint point;
128  point.timestamp = timestamp - (scan.points.size()-1 - j)*0.05;
129  point.x = scan.points[j].x;
130  point.y = scan.points[j].y;
131  point.z = scan.points[j].z;
132  point.intensity = scan.points[j].intensity;
133  point_cloud->points.push_back(point);
134  ++point_cloud->width;
135  }
136 
137  }
138 
139  // if(point_cloud->width > 2000)
140  {
141  point_cloud_pub.publish(point_cloud);
142  }
143 
144 
145  return;
146 }
147 
149 {
150  sensor_msgs::LaserScan::Ptr scan(new sensor_msgs::LaserScan);
151 
152  if(sweep_data->scans[0].points.size() <= 1)
153  return;
154  time_t tick = (time_t) sweep_end_time_gps;
155  struct tm tm;
156  tm = *localtime(&tick);
157 
158 // char s[100];
159 // strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", &tm);
160 // ROS_DEBUG("Timestamp: sec: %lu, nsec: %lu; Actual Time: %s", sweep_end_time_gps, sweep_end_time_hardware, s);
161 
162  scan->header.frame_id = child_frame_id;
163  scan->header.stamp = sweep_data->header.stamp; // timestamp will obtained from sweep data stamp
164 // ros::Time changetime(sweep_end_time_gps, sweep_end_time_hardware);
165 // scan->header.stamp = changetime;
166  scan->angle_min = 0.0;
167  scan->angle_max = 2.0*M_PI;
168  scan->angle_increment = (scan->angle_max - scan->angle_min)/point_num;
169 
170  scan->time_increment = 0.05; //s
171  scan->scan_time =1/10.0; //s
172  scan->range_min = min_range;
173  scan->range_max = max_range;
174  scan->ranges.reserve(point_num);
175  scan->ranges.assign(point_num, std::numeric_limits<float>::infinity());
176 
177  scan->intensities.reserve(point_num);
178  scan->intensities.assign(point_num, std::numeric_limits<float>::infinity());
179 
180  for(uint16_t i = 0; i < sweep_data->scans[0].points.size(); i++)
181  {
182  int point_idx = sweep_data->scans[0].points[i].azimuth / angle_base;
183 
184  if (point_idx >= point_num)
185  point_idx = 0;
186  if (point_idx < 0)
187  point_idx = point_num - 1;
188 
189  scan->ranges[point_num - 1-point_idx] = sweep_data->scans[0].points[i].distance;
190  scan->intensities[point_num - 1-point_idx] = sweep_data->scans[0].points[i].intensity;
191  }
192 
193  for (int i = point_num - 1; i >= 0; i--)
194  {
195  if((i >= angle_disable_min*point_num/360) && (i < angle_disable_max*point_num/360))
196  scan->ranges[i] = std::numeric_limits<float>::infinity();
197  }
198 
199  scan_pub.publish(scan);
200 
201 }
202 
203 point_struct LslidarN301Decoder::getMeans(std::vector<point_struct> clusters)
204 {
205  point_struct tmp;
206  int num = clusters.size();
207  if (num == 0)
208  {
209  tmp.distance = std::numeric_limits<float>::infinity();
210  tmp.intensity = std::numeric_limits<float>::infinity();
211 
212  }
213  else
214  {
215  double mean_distance = 0, mean_intensity = 0;
216 
217  for (int i = 0; i < num; i++)
218  {
219  mean_distance += clusters[i].distance;
220  mean_intensity += clusters[i].intensity;
221  }
222 
223  tmp.distance = mean_distance / num;
224  tmp.intensity = mean_intensity / num;
225  }
226  return tmp;
227 }
228 
230 
231  //uint64_t ptime =mktime(&t)*1e6;
232 // ROS_INFO("get_gps_stamp : %d-%d-%d %d:%d:%d", t.tm_year, t.tm_mon,
233  // t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
234  uint64_t ptime =static_cast<uint64_t>(timegm(&t));
235  return ptime;
236 }
237 
239  // Compute the azimuth angle for each firing.
240  for (size_t fir_idx = 0; fir_idx < FIRINGS_PER_PACKET; fir_idx+=2) {
241  size_t blk_idx = fir_idx / 2;
243  packet->blocks[blk_idx].rotation);
244  }
245 
246  // Interpolate the azimuth values
247  for (size_t fir_idx = 1; fir_idx < FIRINGS_PER_PACKET; fir_idx+=2) {
248  size_t lfir_idx = fir_idx - 1;
249  size_t rfir_idx = fir_idx + 1;
250 
251  double azimuth_diff;
252  if (fir_idx == FIRINGS_PER_PACKET - 1) {
253  lfir_idx = fir_idx - 3;
254  rfir_idx = fir_idx - 1;
255  }
256 
257  azimuth_diff = firings[rfir_idx].firing_azimuth -
258  firings[lfir_idx].firing_azimuth;
259  azimuth_diff = azimuth_diff < 0 ? azimuth_diff + 2*M_PI : azimuth_diff;
260 
261  firings[fir_idx].firing_azimuth =
262  firings[fir_idx-1].firing_azimuth + azimuth_diff/2.0;
263 
264 
265  firings[fir_idx].firing_azimuth =
266  firings[fir_idx].firing_azimuth > 2*M_PI ?
267  firings[fir_idx].firing_azimuth-2*M_PI : firings[fir_idx].firing_azimuth;
268  }
269 
270  // Fill in the distance and intensity for each firing.
271  for (size_t blk_idx = 0; blk_idx < BLOCKS_PER_PACKET; ++blk_idx) {
272  const RawBlock& raw_block = packet->blocks[blk_idx];
273 
274  for (size_t blk_fir_idx = 0; blk_fir_idx < FIRINGS_PER_BLOCK; ++blk_fir_idx){
275  size_t fir_idx = blk_idx*FIRINGS_PER_BLOCK + blk_fir_idx;
276 
277  double azimuth_diff = 0.0;
278  if (fir_idx < FIRINGS_PER_PACKET - 1)
279  azimuth_diff = firings[fir_idx+1].firing_azimuth -
280  firings[fir_idx].firing_azimuth;
281  else
282  azimuth_diff = firings[fir_idx].firing_azimuth -
283  firings[fir_idx-1].firing_azimuth;
284 
285  for (size_t scan_fir_idx = 0; scan_fir_idx < SCANS_PER_FIRING; ++scan_fir_idx){
286  size_t byte_idx = RAW_SCAN_SIZE * (
287  SCANS_PER_FIRING*blk_fir_idx + scan_fir_idx);
288 
289  // Azimuth
290  firings[fir_idx].azimuth[scan_fir_idx] = firings[fir_idx].firing_azimuth +
291  (scan_fir_idx*DSR_TOFFSET/FIRING_TOFFSET) * azimuth_diff;
292 
293  // Distance
294  TwoBytes raw_distance;
295  raw_distance.bytes[0] = raw_block.data[byte_idx];
296  raw_distance.bytes[1] = raw_block.data[byte_idx+1];
297  firings[fir_idx].distance[scan_fir_idx] = static_cast<double>(
298  raw_distance.distance) * DISTANCE_RESOLUTION;
299 
300  // Intensity
301  firings[fir_idx].intensity[scan_fir_idx] = static_cast<double>(
302  raw_block.data[byte_idx+2]);
303 
304 
305  }
306 
307  //extract gps_time
308  pTime.tm_year = raw_block.data[90]+2000-1900;
309  pTime.tm_mon = raw_block.data[91]-1;
310  pTime.tm_mday = raw_block.data[92];
311  pTime.tm_hour = raw_block.data[93];
312  pTime.tm_min = raw_block.data[94];
313  pTime.tm_sec = raw_block.data[95];
314 
315  }
316 
317  }
318 
319  // resolve the timestamp in the end of packet
320  packet_timestamp = (packet->time_stamp_yt[0] +
321  packet->time_stamp_yt[1] * pow(2, 8) +
322  packet->time_stamp_yt[2] * pow(2, 16) +
323  packet->time_stamp_yt[3] * pow(2, 24)) * 1e3;
324  // ROS_DEBUG("nsec part: %lu", packet_timestamp);
325  return;
326 }
327 
329  const lslidar_n301_msgs::LslidarN301PacketConstPtr& msg) {
330  // ROS_WARN("packetCallBack");
331  // Convert the msg to the raw packet type.
332  const RawPacket* raw_packet = (const RawPacket*) (&(msg->data[0]));
333 
334  // Check if the packet is valid+
335  if (!checkPacketValidity(raw_packet)) return;
336 
337  // Decode the packet
338  decodePacket(raw_packet);
339 
340  // Find the start of a new revolution
341  // If there is one, new_sweep_start will be the index of the start firing,
342  // otherwise, new_sweep_start will be FIRINGS_PER_PACKET. FIRINGS_PER_PACKET = 24
343  size_t new_sweep_start = 0;
344  do {
345  // if (firings[new_sweep_start].firing_azimuth < last_azimuth) break;
346  if (fabs(firings[new_sweep_start].firing_azimuth - last_azimuth) > M_PI) break;
347  else {
348  last_azimuth = firings[new_sweep_start].firing_azimuth;
349  ++new_sweep_start;
350  }
351  } while (new_sweep_start < FIRINGS_PER_PACKET);
352  // ROS_WARN("new_sweep_start %d", new_sweep_start);
353 
354  // The first sweep may not be complete. So, the firings with
355  // the first sweep will be discarded. We will wait for the
356  // second sweep in order to find the 0 azimuth angle.
357  size_t start_fir_idx = 0;
358  size_t end_fir_idx = new_sweep_start;
359  if (is_first_sweep &&
360  new_sweep_start == FIRINGS_PER_PACKET) {
361  // The first sweep has not ended yet.
362  return;
363  } else {
364  if (is_first_sweep) {
365  is_first_sweep = false;
366  start_fir_idx = new_sweep_start;
367  end_fir_idx = FIRINGS_PER_PACKET;
368  // sweep_start_time = msg->stamp.toSec() +
369  // FIRING_TOFFSET * (end_fir_idx-start_fir_idx) * 1e-6;
371  }
372  }
373 
374  for (size_t fir_idx = start_fir_idx; fir_idx < end_fir_idx; ++fir_idx) {
375  for (size_t scan_idx = 0; scan_idx < SCANS_PER_FIRING; ++scan_idx) {
376  // Check if the point is valid.
377  if (!isPointInRange(firings[fir_idx].distance[scan_idx])) continue;
378 
379  // Convert the point to xyz coordinate
380  size_t table_idx = floor(firings[fir_idx].azimuth[scan_idx]*1000.0+0.5);
381  //cout << table_idx << endl;
382  double cos_azimuth = cos_azimuth_table[table_idx];
383  double sin_azimuth = sin_azimuth_table[table_idx];
384 
385  //double x = firings[fir_idx].distance[scan_idx] *
386  // cos_scan_altitude[scan_idx] * sin(firings[fir_idx].azimuth[scan_idx]);
387  //double y = firings[fir_idx].distance[scan_idx] *
388  // cos_scan_altitude[scan_idx] * cos(firings[fir_idx].azimuth[scan_idx]);
389  //double z = firings[fir_idx].distance[scan_idx] *
390  // sin_scan_altitude[scan_idx];
391 
392  double x = firings[fir_idx].distance[scan_idx] *
393  cos_scan_altitude[scan_idx] * sin_azimuth;
394  double y = firings[fir_idx].distance[scan_idx] *
395  cos_scan_altitude[scan_idx] * cos_azimuth;
396  double z = firings[fir_idx].distance[scan_idx] *
397  sin_scan_altitude[scan_idx];
398 
399  double x_coord = y;
400  double y_coord = -x;
401  double z_coord = z;
402 
403  // Compute the time of the point
404  // double time = packet_start_time +
405  // FIRING_TOFFSET*fir_idx + DSR_TOFFSET*scan_idx;
406 
407  // get timestamp from gps and hardware instead
408  double time = sweep_end_time_gps*1.0 + sweep_end_time_hardware*1e-9;
409 
410  // Remap the index of the scan
411  int remapped_scan_idx = scan_idx%2 == 0 ? scan_idx/2 : scan_idx/2+8;
412  sweep_data->scans[remapped_scan_idx].points.push_back(
413  lslidar_n301_msgs::LslidarN301Point());
414 
415  lslidar_n301_msgs::LslidarN301Point& new_point = // new_point 为push_back最后一个的引用
416  sweep_data->scans[remapped_scan_idx].points[
417  sweep_data->scans[remapped_scan_idx].points.size()-1];
418 
419  // Pack the data into point msg
420  new_point.time = time;
421  new_point.x = x_coord;
422  new_point.y = y_coord;
423  new_point.z = z_coord;
424  new_point.azimuth = firings[fir_idx].azimuth[scan_idx];
425  new_point.distance = firings[fir_idx].distance[scan_idx];
426  new_point.intensity = firings[fir_idx].intensity[scan_idx];
427  }
428  }
429 
430  packet_start_time += FIRING_TOFFSET * (end_fir_idx-start_fir_idx);
431 
432  // A new sweep begins
433  if (end_fir_idx != FIRINGS_PER_PACKET) {
434  // ROS_WARN("A new sweep begins");
435  // Publish the last revolution
438 
439  sweep_data->header.frame_id = "sweep";
440  if (use_gps_ts){
442  }
443  else{
444  sweep_data->header.stamp = ros::Time::now();
445  }
446 
448 
450 
451  publishScan();
452 
453  sweep_data = lslidar_n301_msgs::LslidarN301SweepPtr(
454  new lslidar_n301_msgs::LslidarN301Sweep());
455 
456  // Prepare the next revolution
457  // sweep_start_time = msg->stamp.toSec() +
458  // FIRING_TOFFSET * (end_fir_idx-start_fir_idx) * 1e-6;
460 
461  packet_start_time = 0.0;
463 
464  start_fir_idx = end_fir_idx;
465  end_fir_idx = FIRINGS_PER_PACKET;
466 
467  for (size_t fir_idx = start_fir_idx; fir_idx < end_fir_idx; ++fir_idx) {
468  for (size_t scan_idx = 0; scan_idx < SCANS_PER_FIRING; ++scan_idx) {
469  // Check if the point is valid.
470  if (!isPointInRange(firings[fir_idx].distance[scan_idx])) continue;
471 
472  // Convert the point to xyz coordinate
473  size_t table_idx = floor(firings[fir_idx].azimuth[scan_idx]*1000.0+0.5);
474  //cout << table_idx << endl;
475  double cos_azimuth = cos_azimuth_table[table_idx];
476  double sin_azimuth = sin_azimuth_table[table_idx];
477 
478  //double x = firings[fir_idx].distance[scan_idx] *
479  // cos_scan_altitude[scan_idx] * sin(firings[fir_idx].azimuth[scan_idx]);
480  //double y = firings[fir_idx].distance[scan_idx] *
481  // cos_scan_altitude[scan_idx] * cos(firings[fir_idx].azimuth[scan_idx]);
482  //double z = firings[fir_idx].distance[scan_idx] *
483  // sin_scan_altitude[scan_idx];
484 
485  double x = firings[fir_idx].distance[scan_idx] *
486  cos_scan_altitude[scan_idx] * sin_azimuth;
487  double y = firings[fir_idx].distance[scan_idx] *
488  cos_scan_altitude[scan_idx] * cos_azimuth;
489  double z = firings[fir_idx].distance[scan_idx] *
490  sin_scan_altitude[scan_idx];
491 
492  double x_coord = y;
493  double y_coord = -x;
494  double z_coord = z;
495 
496  // Compute the time of the point
497  // double time = packet_start_time +
498  // FIRING_TOFFSET*(fir_idx-start_fir_idx) + DSR_TOFFSET*scan_idx;
499 
500  // get timestamp from gps and hardware instead
501  double time = sweep_end_time_gps*1.0 + sweep_end_time_hardware*1e-9;
502 
503  // Remap the index of the scan
504  int remapped_scan_idx = scan_idx%2 == 0 ? scan_idx/2 : scan_idx/2+8;
505  sweep_data->scans[remapped_scan_idx].points.push_back(
506  lslidar_n301_msgs::LslidarN301Point());
507  lslidar_n301_msgs::LslidarN301Point& new_point =
508  sweep_data->scans[remapped_scan_idx].points[
509  sweep_data->scans[remapped_scan_idx].points.size()-1];
510 
511  // Pack the data into point msg
512  new_point.time = time;
513  new_point.x = x_coord;
514  new_point.y = y_coord;
515  new_point.z = z_coord;
516  new_point.azimuth = firings[fir_idx].azimuth[scan_idx];
517  new_point.distance = firings[fir_idx].distance[scan_idx];
518  new_point.intensity = firings[fir_idx].intensity[scan_idx];
519  }
520  }
521 
522  packet_start_time += FIRING_TOFFSET * (end_fir_idx-start_fir_idx);
523  }
524  // ROS_WARN("pack end");
525  return;
526 }
527 
528 } // end namespace lslidar_n301_decoder
529 
530  // ROS_WARN("[%f %f %f]", firings[fir_idx].azimuth[0], firings[fir_idx].distance[0], firings[fir_idx].intensity[0]);
static const double scan_altitude[16]
point_struct getMeans(std::vector< point_struct > clusters)
void publish(const boost::shared_ptr< M > &message) const
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
lslidar_n301_msgs::LslidarN301SweepPtr sweep_data
TFSIMD_FORCE_INLINE tfScalar distance(const Vector3 &v) const
TFSIMD_FORCE_INLINE const tfScalar & y() const
#define ROS_WARN(...)
static const int SCANS_PER_FIRING
pcl::PointCloud< VPoint > VPointCloud
static const int BLOCKS_PER_PACKET
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
static const double FIRING_TOFFSET
void packetCallback(const lslidar_n301_msgs::LslidarN301PacketConstPtr &msg)
static const double cos_scan_altitude[16]
static const double sin_scan_altitude[16]
double rawAzimuthToDouble(const uint16_t &raw_azimuth)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
uint16_t rotation
0-35999, divide by 100 to get degrees
TFSIMD_FORCE_INLINE const tfScalar & x() const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
bool isPointInRange(const double &distance)
TFSIMD_FORCE_INLINE const tfScalar & z() const
bool checkPacketValidity(const RawPacket *packet)
static const double DSR_TOFFSET
static const int FIRINGS_PER_PACKET
static const int RAW_SCAN_SIZE
unsigned long uint64_t
Definition: check.cpp:6
static Time now()
static const uint16_t UPPER_BANK
static const int FIRINGS_PER_BLOCK
static const double DISTANCE_RESOLUTION
#define ROS_ERROR(...)
void toPCL(const ros::Time &stamp, pcl::uint64_t &pcl_stamp)


lslidar_n301_decoder
Author(s): Nick Shu
autogenerated on Thu Sep 26 2019 03:58:31