lslidar_c16_driver.cc
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 
18 #include <string>
19 #include <cmath>
20 #include <unistd.h>
21 #include <sys/socket.h>
22 #include <arpa/inet.h>
23 #include <poll.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <sys/file.h>
27 
28 #include <ros/ros.h>
29 #include <tf/transform_listener.h>
30 
32 
33 namespace lslidar_c16_driver {
34 
37  nh(n),
38  pnh(pn),
39  socket_id(-1){
40  return;
41 }
42 
44  (void) close(socket_id);
45  return;
46 }
47 
49 
50  //pnh.param("frame_id", frame_id, std::string("lslidar"));
51  pnh.param("lidar_ip", lidar_ip_string, std::string("192.168.1.222"));
52  pnh.param<int>("device_port", UDP_PORT_NUMBER,2368);
53  pnh.param<bool>("add_multicast", add_multicast, false);
54  pnh.param("group_ip", group_ip_string, std::string("234.2.3.2"));
55  inet_aton(lidar_ip_string.c_str(), &lidar_ip);
56  ROS_INFO_STREAM("Opening UDP socket: address " << lidar_ip_string);
57  if(add_multicast) ROS_INFO_STREAM("Opening UDP socket: group_address " << group_ip_string);
58  ROS_INFO_STREAM("Opening UDP socket: port " << UDP_PORT_NUMBER);
59  return true;
60 }
61 
63 
64  // ROS diagnostics
65  diagnostics.setHardwareID("Lslidar_C16");
66  // c16 publishs 20*16 thousands points per second.
67  // Each packet contains 12 blocks. And each block
68  // contains 32 points. Together provides the
69  // packet rate.
70  const double diag_freq = 16*20000.0 / (12*32);
71  diag_max_freq = diag_freq;
72  diag_min_freq = diag_freq;
73  ROS_INFO("expected frequency: %.3f (Hz)", diag_freq);
74 
75  using namespace diagnostic_updater;
76  diag_topic.reset(new TopicDiagnostic(
77  "lslidar_packets", diagnostics,
80 
81  // Output
82  packet_pub = nh.advertise<lslidar_c16_msgs::LslidarC16Packet>(
83  "lslidar_packet", 100);
84  return true;
85 }
86 
88  socket_id = socket(PF_INET, SOCK_DGRAM, 0);
89  if (socket_id == -1) {
90  perror("socket");
91  return false;
92  }
93 
94  sockaddr_in my_addr; // my address information
95  memset(&my_addr, 0, sizeof(my_addr)); // initialize to zeros
96  my_addr.sin_family = AF_INET; // host byte order
97  my_addr.sin_port = htons(UDP_PORT_NUMBER); // short, in network byte order
98  ROS_INFO_STREAM("Opening UDP socket: port " << UDP_PORT_NUMBER);
99  my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill in my IP
100 
101  if (bind(socket_id, (sockaddr *)&my_addr, sizeof(sockaddr)) == -1) {
102  perror("bind"); // TODO: ROS_ERROR errno
103  return false;
104  }
105  //add multicast
106  if(add_multicast){
107  ip_mreq groupcast;
108  groupcast.imr_interface.s_addr=INADDR_ANY;
109  groupcast.imr_multiaddr.s_addr=inet_addr(group_ip_string.c_str());
110 
111  if(setsockopt(socket_id,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&groupcast,sizeof(groupcast))<0) {
112  perror("set multicast error");
113  close(socket_id);
114  return false;
115  }
116  }
117  if (fcntl(socket_id, F_SETFL, O_NONBLOCK|FASYNC) < 0) {
118  perror("non-block");
119  return false;
120  }
121 
122  return true;
123 }
124 
126 
127  this->initTimeStamp();
128 
129  if (!loadParameters()) {
130  ROS_ERROR("Cannot load all required ROS parameters...");
131  return false;
132  }
133 
134  if (!createRosIO()) {
135  ROS_ERROR("Cannot create all ROS IO...");
136  return false;
137  }
138 
139  if (!openUDPPort()) {
140  ROS_ERROR("Cannot open UDP port...");
141  return false;
142  }
143  ROS_INFO("Initialised lslidar c16 without error");
144  return true;
145 }
146 
148  lslidar_c16_msgs::LslidarC16PacketPtr& packet) {
149 
150  double time1 = ros::Time::now().toSec();
151 
152  struct pollfd fds[1];
153  fds[0].fd = socket_id;
154  fds[0].events = POLLIN;
155  static const int POLL_TIMEOUT = 2000; // one second (in msec)
156 
157  sockaddr_in sender_address;
158  socklen_t sender_address_len = sizeof(sender_address);
159 
160  while (true)
161  {
162  // Unfortunately, the Linux kernel recvfrom() implementation
163  // uses a non-interruptible sleep() when waiting for data,
164  // which would cause this method to hang if the device is not
165  // providing data. We poll() the device first to make sure
166  // the recvfrom() will not block.
167  //
168  // Note, however, that there is a known Linux kernel bug:
169  //
170  // Under Linux, select() may report a socket file descriptor
171  // as "ready for reading", while nevertheless a subsequent
172  // read blocks. This could for example happen when data has
173  // arrived but upon examination has wrong checksum and is
174  // discarded. There may be other circumstances in which a
175  // file descriptor is spuriously reported as ready. Thus it
176  // may be safer to use O_NONBLOCK on sockets that should not
177  // block.
178 
179  // poll() until input available
180  do {
181  int retval = poll(fds, 1, POLL_TIMEOUT);
182  if (retval < 0) // poll() error?
183  {
184  if (errno != EINTR)
185  ROS_ERROR("poll() error: %s", strerror(errno));
186  return 1;
187  }
188  if (retval == 0) // poll() timeout?
189  {
190  ROS_WARN("lslidar poll() timeout");
191  return 1;
192  }
193  if ((fds[0].revents & POLLERR)
194  || (fds[0].revents & POLLHUP)
195  || (fds[0].revents & POLLNVAL)) // device error?
196  {
197  ROS_ERROR("poll() reports lslidar error");
198  return 1;
199  }
200  } while ((fds[0].revents & POLLIN) == 0);
201 
202  // Receive packets that should now be available from the
203  // socket using a blocking read.
204  ssize_t nbytes = recvfrom(socket_id, &packet->data[0], PACKET_SIZE, 0,
205  (sockaddr*) &sender_address, &sender_address_len);
206 
207 // ROS_DEBUG_STREAM("incomplete lslidar packet read: "
208 // << nbytes << " bytes");
209 
210  if (nbytes < 0)
211  {
212  if (errno != EWOULDBLOCK)
213  {
214  perror("recvfail");
215  ROS_INFO("recvfail");
216  return 1;
217  }
218  }
219  else if ((size_t) nbytes == PACKET_SIZE)
220  {
221  // read successful,
222  // if packet is not from the lidar scanner we selected by IP,
223  // continue otherwise we are done
224  if( lidar_ip_string != "" && sender_address.sin_addr.s_addr != lidar_ip.s_addr )
225  continue;
226  else
227  break; //done
228  }
229 
230 
231 
232  }
233  this->getFPGA_GPSTimeStamp(packet);
234 
235  // Average the times at which we begin and end reading. Use that to
236  // estimate when the scan occurred.
237  double time2 = ros::Time::now().toSec();
238 // packet->stamp = ros::Time((time2 + time1) / 2.0);
239  packet->stamp = this->timeStamp;
240  return 0;
241 }
242 
244 {
245  // Allocate a new shared pointer for zero-copy sharing with other nodelets.
246  lslidar_c16_msgs::LslidarC16PacketPtr packet(
247  new lslidar_c16_msgs::LslidarC16Packet());
248 
249  // Since the lslidar delivers data at a very high rate, keep
250  // reading and publishing scans as fast as possible.
251  //for (int i = 0; i < config_.npackets; ++i)
252  // {
253  // while (true)
254  // {
255  // // keep reading until full packet received
256  // int rc = input_->getPacket(&scan->packets[i]);
257  // if (rc == 0) break; // got a full packet?
258  // if (rc < 0) return false; // end of file reached?
259  // }
260  // }
261  while (true)
262  {
263  // keep reading until full packet received
264  int rc = getPacket(packet);
265  if (rc == 0) break; // got a full packet?
266  if (rc < 0) return false; // end of file reached?
267  }
268 
269  // publish message using time of last packet read
270  ROS_DEBUG("Publishing a full lslidar scan.");
271  packet_pub.publish(*packet);
272 
273  // notify diagnostics that a message has been published, updating
274  // its status
275  diag_topic->tick(packet->stamp);
277 
278  return true;
279 }
280 
282 {
283  int i;
284 
285  for(i = 0;i < 10;i ++)
286  {
287  this->packetTimeStamp[i] = 0;
288  }
289  this->pointcloudTimeStamp = 0;
290 
291  this->timeStamp = ros::Time(0.0);
292 }
293 
294 void LslidarC16Driver::getFPGA_GPSTimeStamp(lslidar_c16_msgs::LslidarC16PacketPtr &packet)
295 {
296  unsigned char head2[] = {packet->data[0],packet->data[1],packet->data[2],packet->data[3]};
297 
298  if(head2[0] == 0xA5 && head2[1] == 0xFF)
299  {
300  if(head2[2] == 0x00 && head2[3] == 0x5A)
301  {
302  this->packetTimeStamp[4] = packet->data[41];
303  this->packetTimeStamp[5] = packet->data[40];
304  this->packetTimeStamp[6] = packet->data[39];
305  this->packetTimeStamp[7] = packet->data[38];
306  this->packetTimeStamp[8] = packet->data[37];
307  this->packetTimeStamp[9] = packet->data[36];
308 
309  cur_time.tm_sec = this->packetTimeStamp[4];
310  cur_time.tm_min = this->packetTimeStamp[5];
311  cur_time.tm_hour = this->packetTimeStamp[6];
312  cur_time.tm_mday = this->packetTimeStamp[7];
313  cur_time.tm_mon = this->packetTimeStamp[8]-1;
314  cur_time.tm_year = this->packetTimeStamp[9]+2000-1900;
315  this->pointcloudTimeStamp = static_cast<uint64_t>(timegm(&cur_time));
316 
317  if (GPSCountingTS != this->pointcloudTimeStamp)
318  {
319  cnt_gps_ts = 0;
321  }
322  else if (cnt_gps_ts == 3)
323  {
325  }
326  else
327  {
328  cnt_gps_ts ++;
329  }
330 // ROS_DEBUG("GPS: y:%d m:%d d:%d h:%d m:%d s:%d",
331 // cur_time.tm_year,cur_time.tm_mon,cur_time.tm_mday,cur_time.tm_hour,cur_time.tm_min,cur_time.tm_sec);
332  }
333  }
334  else if(head2[0] == 0xFF && head2[1] == 0xEE)
335  {
336  uint64_t packet_timestamp;
337  packet_timestamp = (packet->data[1200] +
338  packet->data[1201] * pow(2, 8) +
339  packet->data[1202] * pow(2, 16) +
340  packet->data[1203] * pow(2, 24)) * 1e3;
341 
342 
343  if ((last_FPGA_ts - packet_timestamp) > 0)
344  {
346 
347  // ROS_DEBUG("This is step time, using new GPS ts %lu", GPS_ts);
348  }
349 
350  last_FPGA_ts = packet_timestamp;
351  // timeStamp = ros::Time(this->pointcloudTimeStamp+total_us/10e5);
352 
353  timeStamp = ros::Time(GPS_ts, packet_timestamp);
354 // ROS_DEBUG("ROS TS: %f, GPS: y:%d m:%d d:%d h:%d m:%d s:%d; FPGA: us:%lu",
355 // timeStamp.toSec(), GPS_ts, packet_timestamp);
356 
357  }
358 }
359 
360 } // namespace lslidar_driver
void publish(const boost::shared_ptr< M > &message) const
void setHardwareID(const std::string &hwid)
int getPacket(lslidar_c16_msgs::LslidarC16PacketPtr &msg)
static uint16_t PACKET_SIZE
#define ROS_WARN(...)
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
diagnostic_updater::Updater diagnostics
boost::shared_ptr< diagnostic_updater::TopicDiagnostic > diag_topic
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
#define ROS_INFO_STREAM(args)
static Time now()
void getFPGA_GPSTimeStamp(lslidar_c16_msgs::LslidarC16PacketPtr &packet)
#define ROS_ERROR(...)
LslidarC16Driver(ros::NodeHandle &n, ros::NodeHandle &pn)
#define ROS_DEBUG(...)


lslidar_c16_driver
Author(s): Yutong
autogenerated on Thu Aug 22 2019 03:51:43