rsdriver.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007 Austin Robot Technology, Patrick Beeson
3  * Copyright (C) 2009-2012 Austin Robot Technology, Jack O'Quin
4  * Copyright (C) 2017 Robosense, Tony Zhang
5  *
6  * License: Modified BSD Software License Agreement
7  *
8 
9  Copyright (C) 2010-2013 Austin Robot Technology, and others
10  All rights reserved.
11 
12 
13 Modified BSD License:
14 --------------------
15 
16  Redistribution and use in source and binary forms, with or without
17  modification, are permitted provided that the following conditions
18  are met:
19 
20  * Redistributions of source code must retain the above copyright
21  notice, this list of conditions and the following disclaimer.
22 
23  * Redistributions in binary form must reproduce the above
24  copyright notice, this list of conditions and the following
25  disclaimer in the documentation and/or other materials provided
26  with the distribution.
27 
28  * Neither the names of the University of Texas at Austin, nor
29  Austin Robot Technology, nor the names of other contributors may
30  be used to endorse or promote products derived from this
31  software without specific prior written permission.
32 
33  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
34  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
35  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
36  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
37  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
38  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
39  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
40  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
41  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
43  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
44 POSSIBILITY OF SUCH DAMAGE.
45  */
46 
51 #include "rsdriver.h"
52 #include <rslidar_msgs/rslidarScan.h>
53 
54 namespace rslidar_driver
55 {
57 {
58  // use private node handle to get parameters
59  private_nh.param("frame_id", config_.frame_id, std::string("rslidar"));
60 
61  std::string tf_prefix = tf::getPrefixParam(private_nh);
62  ROS_DEBUG_STREAM("tf_prefix: " << tf_prefix);
63  config_.frame_id = tf::resolve(tf_prefix, config_.frame_id);
64 
65  // get model name, validate string, determine packet rate
66  private_nh.param("model", config_.model, std::string("RS16"));
67  double packet_rate; // packet frequency (Hz)
68  std::string model_full_name;
69 
70  // product model
71  if (config_.model == "RS16")
72  {
73  packet_rate = 840;
74  model_full_name = "RS-LiDAR-16";
75  }
76  else if (config_.model == "RS32")
77  {
78  packet_rate = 1690;
79  model_full_name = "RS-LiDAR-32";
80  }
81  else
82  {
83  ROS_ERROR_STREAM("unknown LIDAR model: " << config_.model);
84  packet_rate = 2600.0;
85  }
86  std::string deviceName(std::string("Robosense ") + model_full_name);
87 
88  private_nh.param("rpm", config_.rpm, 600.0);
89  double frequency = (config_.rpm / 60.0); // expected Hz rate
90 
91  // default number of packets for each scan is a single revolution
92  // (fractions rounded up)
93 
94  int npackets = (int)ceil(packet_rate / frequency);
95  private_nh.param("npackets", config_.npackets, npackets);
96  ROS_INFO_STREAM("publishing " << config_.npackets << " packets per scan");
97 
98  std::string dump_file;
99  private_nh.param("pcap", dump_file, std::string(""));
100 
101  int msop_udp_port;
102  private_nh.param("msop_port", msop_udp_port, (int)MSOP_DATA_PORT_NUMBER);
103  int difop_udp_port;
104  private_nh.param("difop_port", difop_udp_port, (int)DIFOP_DATA_PORT_NUMBER);
105 
106  double cut_angle;
107  private_nh.param("cut_angle", cut_angle, -0.01);
108  if (cut_angle < 0.0)
109  {
110  ROS_INFO_STREAM("Cut at specific angle feature deactivated.");
111  }
112  else if (cut_angle < 360)
113  {
114  ROS_INFO_STREAM("Cut at specific angle feature activated. "
115  "Cutting rslidar points always at "
116  << cut_angle << " degree.");
117  }
118  else
119  {
120  ROS_ERROR_STREAM("cut_angle parameter is out of range. Allowed range is "
121  << "between 0.0 and 360 negative values to deactivate this feature.");
122  cut_angle = -0.01;
123  }
124 
125  // Convert cut_angle from radian to one-hundredth degree,
126  // which is used in rslidar packets
127  config_.cut_angle = static_cast<int>(cut_angle * 100);
128 
129  // Initialize dynamic reconfigure
130  srv_ = boost::make_shared<dynamic_reconfigure::Server<rslidar_driver::rslidarNodeConfig> >(private_nh);
131  dynamic_reconfigure::Server<rslidar_driver::rslidarNodeConfig>::CallbackType f;
132  f = boost::bind(&rslidarDriver::callback, this, _1, _2);
133  srv_->setCallback(f); // Set callback function und call initially
134 
135  // initialize diagnostics
136  diagnostics_.setHardwareID(deviceName);
137  const double diag_freq = packet_rate / config_.npackets;
138  diag_max_freq_ = diag_freq;
139  diag_min_freq_ = diag_freq;
140  // ROS_INFO("expected frequency: %.3f (Hz)", diag_freq);
141 
142  using namespace diagnostic_updater;
143  diag_topic_.reset(new TopicDiagnostic("rslidar_packets", diagnostics_,
146 
147  // open rslidar input device or file
148  if (dump_file != "") // have PCAP file?
149  {
150  // read data from packet capture file
151  msop_input_.reset(new rslidar_driver::InputPCAP(private_nh, msop_udp_port, packet_rate, dump_file));
152  difop_input_.reset(new rslidar_driver::InputPCAP(private_nh, difop_udp_port, packet_rate, dump_file));
153  }
154  else
155  {
156  // read data from live socket
157  msop_input_.reset(new rslidar_driver::InputSocket(private_nh, msop_udp_port));
158  difop_input_.reset(new rslidar_driver::InputSocket(private_nh, difop_udp_port));
159  }
160 
161  // raw packet output topic
162  msop_output_ = node.advertise<rslidar_msgs::rslidarScan>("rslidar_packets", 10);
163  difop_output_ = node.advertise<rslidar_msgs::rslidarPacket>("rslidar_packets_difop", 10);
164  difop_thread_ = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&rslidarDriver::difopPoll, this)));
165 }
166 
172 {
173  // Allocate a new shared pointer for zero-copy sharing with other nodelets.
174  rslidar_msgs::rslidarScanPtr scan(new rslidar_msgs::rslidarScan);
175 
176  // Since the rslidar delivers data at a very high rate, keep
177  // reading and publishing scans as fast as possible.
178  if (config_.cut_angle >= 0) // Cut at specific angle feature enabled
179  {
180  scan->packets.reserve(config_.npackets);
181  rslidar_msgs::rslidarPacket tmp_packet;
182  while (true)
183  {
184  while (true)
185  {
186  int rc = msop_input_->getPacket(&tmp_packet, config_.time_offset);
187  if (rc == 0)
188  break; // got a full packet?
189  if (rc < 0)
190  return false; // end of file reached?
191  }
192  scan->packets.push_back(tmp_packet);
193 
194  static int ANGLE_HEAD = -36001; // note: cannot be set to -1, or stack smashing
195  static int last_azimuth = ANGLE_HEAD;
196 
197  int azimuth = 256 * tmp_packet.data[44] + tmp_packet.data[45];
198  // int azimuth = *( (u_int16_t*) (&tmp_packet.data[azimuth_data_pos]));
199 
200  // Handle overflow 35999->0
201  if (azimuth < last_azimuth)
202  {
203  last_azimuth -= 36000;
204  }
205  // Check if currently passing cut angle
206  if (last_azimuth != ANGLE_HEAD && last_azimuth < config_.cut_angle && azimuth >= config_.cut_angle)
207  {
208  last_azimuth = azimuth;
209  break; // Cut angle passed, one full revolution collected
210  }
211  last_azimuth = azimuth;
212  }
213  }
214  else // standard behaviour
215  {
216  scan->packets.resize(config_.npackets);
217  for (int i = 0; i < config_.npackets; ++i)
218  {
219  while (true)
220  {
221  // keep reading until full packet received
222  int rc = msop_input_->getPacket(&scan->packets[i], config_.time_offset);
223  if (rc == 0)
224  break; // got a full packet?
225  if (rc < 0)
226  return false; // end of file reached?
227  }
228  }
229  }
230 
231  // publish message using time of last packet read
232  ROS_DEBUG("Publishing a full rslidar scan.");
233  scan->header.stamp = scan->packets.back().stamp;
234  scan->header.frame_id = config_.frame_id;
235  msop_output_.publish(scan);
236 
237  // notify diagnostics that a message has been published, updating its status
238  diag_topic_->tick(scan->header.stamp);
240 
241  return true;
242 }
243 
245 {
246  // reading and publishing scans as fast as possible.
247  rslidar_msgs::rslidarPacketPtr difop_packet_ptr(new rslidar_msgs::rslidarPacket);
248  while (ros::ok())
249  {
250  // keep reading
251  rslidar_msgs::rslidarPacket difop_packet_msg;
252  int rc = difop_input_->getPacket(&difop_packet_msg, config_.time_offset);
253  if (rc == 0)
254  {
255  // std::cout << "Publishing a difop data." << std::endl;
256  ROS_DEBUG("Publishing a difop data.");
257  *difop_packet_ptr = difop_packet_msg;
258  difop_output_.publish(difop_packet_ptr);
259  }
260  if (rc < 0)
261  return; // end of file reached?
262  ros::spinOnce();
263  }
264 }
265 
266 void rslidarDriver::callback(rslidar_driver::rslidarNodeConfig& config, uint32_t level)
267 {
268  ROS_INFO("Reconfigure Request");
269  config_.time_offset = config.time_offset;
270 }
271 }
diagnostic_updater::Updater diagnostics_
Definition: rsdriver.h:109
ros::Publisher difop_output_
Definition: rsdriver.h:106
void publish(const boost::shared_ptr< M > &message) const
std::string getPrefixParam(ros::NodeHandle &nh)
f
rslidarDriver(ros::NodeHandle node, ros::NodeHandle private_nh)
rslidarDriver
Definition: rsdriver.cpp:56
void setHardwareID(const std::string &hwid)
ros::Publisher msop_output_
Definition: rsdriver.h:105
static uint16_t MSOP_DATA_PORT_NUMBER
Definition: input.h:83
boost::shared_ptr< Input > msop_input_
Definition: rsdriver.h:103
int npackets
number of packets to collect
Definition: rsdriver.h:97
std::string resolve(const std::string &prefix, const std::string &frame_name)
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
ROSCPP_DECL bool ok()
struct rslidar_driver::rslidarDriver::@0 config_
Live rslidar input from socket.
Definition: input.h:113
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
boost::shared_ptr< diagnostic_updater::TopicDiagnostic > diag_topic_
Definition: rsdriver.h:112
void callback(rslidar_driver::rslidarNodeConfig &config, uint32_t level)
Callback for dynamic reconfigure.
Definition: rsdriver.cpp:266
#define ROS_DEBUG_STREAM(args)
boost::shared_ptr< Input > difop_input_
Definition: rsdriver.h:104
#define ROS_INFO_STREAM(args)
rslidar input from PCAP dump file.
Definition: input.h:135
#define ROS_ERROR_STREAM(args)
static uint16_t DIFOP_DATA_PORT_NUMBER
Definition: input.h:84
ROSCPP_DECL void spinOnce()
boost::shared_ptr< boost::thread > difop_thread_
Definition: rsdriver.h:113
boost::shared_ptr< dynamic_reconfigure::Server< rslidar_driver::rslidarNodeConfig > > srv_
Pointer to dynamic reconfigure service srv_.
Definition: rsdriver.h:90
#define ROS_DEBUG(...)


rslidar_driver
Author(s): Tony Zhang , Tony Zhang
autogenerated on Mon Jun 10 2019 14:41:07