node.cpp
Go to the documentation of this file.
1 /*
2  * RPLIDAR ROS NODE
3  *
4  * Copyright (c) 2009 - 2014 RoboPeak Team
5  * http://www.robopeak.com
6  * Copyright (c) 2014 - 2016 Shanghai Slamtec Co., Ltd.
7  * http://www.slamtec.com
8  *
9  */
10 /*
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright notice,
15  * this list of conditions and the following disclaimer.
16  *
17  * 2. Redistributions in binary form must reproduce the above copyright notice,
18  * this list of conditions and the following disclaimer in the documentation
19  * and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
25  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 
35 #include "ros/ros.h"
36 #include "sensor_msgs/LaserScan.h"
37 #include "std_srvs/Empty.h"
38 #include "rplidar.h"
39 
40 #ifndef _countof
41 #define _countof(_Array) (int)(sizeof(_Array) / sizeof(_Array[0]))
42 #endif
43 
44 #define DEG2RAD(x) ((x)*M_PI/180.)
45 
46 using namespace rp::standalone::rplidar;
47 
48 RPlidarDriver * drv = NULL;
49 
52  size_t node_count, ros::Time start,
53  double scan_time, bool inverted,
54  float angle_min, float angle_max,
55  float max_distance,
56  std::string frame_id)
57 {
58  static int scan_count = 0;
59  sensor_msgs::LaserScan scan_msg;
60 
61  scan_msg.header.stamp = start;
62  scan_msg.header.frame_id = frame_id;
63  scan_count++;
64 
65  bool reversed = (angle_max > angle_min);
66  if ( reversed ) {
67  scan_msg.angle_min = M_PI - angle_max;
68  scan_msg.angle_max = M_PI - angle_min;
69  } else {
70  scan_msg.angle_min = M_PI - angle_min;
71  scan_msg.angle_max = M_PI - angle_max;
72  }
73  scan_msg.angle_increment =
74  (scan_msg.angle_max - scan_msg.angle_min) / (double)(node_count-1);
75 
76  scan_msg.scan_time = scan_time;
77  scan_msg.time_increment = scan_time / (double)(node_count-1);
78  scan_msg.range_min = 0.15;
79  scan_msg.range_max = max_distance;//8.0;
80 
81  scan_msg.intensities.resize(node_count);
82  scan_msg.ranges.resize(node_count);
83  bool reverse_data = (!inverted && reversed) || (inverted && !reversed);
84  if (!reverse_data) {
85  for (size_t i = 0; i < node_count; i++) {
86  float read_value = (float) nodes[i].dist_mm_q2/4.0f/1000;
87  if (read_value == 0.0)
88  scan_msg.ranges[i] = std::numeric_limits<float>::infinity();
89  else
90  scan_msg.ranges[i] = read_value;
91  scan_msg.intensities[i] = (float) (nodes[i].quality >> 2);
92  }
93  } else {
94  for (size_t i = 0; i < node_count; i++) {
95  float read_value = (float)nodes[i].dist_mm_q2/4.0f/1000;
96  if (read_value == 0.0)
97  scan_msg.ranges[node_count-1-i] = std::numeric_limits<float>::infinity();
98  else
99  scan_msg.ranges[node_count-1-i] = read_value;
100  scan_msg.intensities[node_count-1-i] = (float) (nodes[i].quality >> 2);
101  }
102  }
103 
104  pub->publish(scan_msg);
105 }
106 
108 {
109  u_result op_result;
110  rplidar_response_device_info_t devinfo;
111 
112  op_result = drv->getDeviceInfo(devinfo);
113  if (IS_FAIL(op_result)) {
114  if (op_result == RESULT_OPERATION_TIMEOUT) {
115  ROS_ERROR("Error, operation time out. RESULT_OPERATION_TIMEOUT! ");
116  } else {
117  ROS_ERROR("Error, unexpected error, code: %x",op_result);
118  }
119  return false;
120  }
121 
122  // print out the device serial number, firmware and hardware version number..
123  printf("RPLIDAR S/N: ");
124  for (int pos = 0; pos < 16 ;++pos) {
125  printf("%02X", devinfo.serialnum[pos]);
126  }
127  printf("\n");
128  ROS_INFO("Firmware Ver: %d.%02d",devinfo.firmware_version>>8, devinfo.firmware_version & 0xFF);
129  ROS_INFO("Hardware Rev: %d",(int)devinfo.hardware_version);
130  return true;
131 }
132 
134 {
135  u_result op_result;
136  rplidar_response_device_health_t healthinfo;
137 
138  op_result = drv->getHealth(healthinfo);
139  if (IS_OK(op_result)) {
140  ROS_INFO("RPLidar health status : %d", healthinfo.status);
141  if (healthinfo.status == RPLIDAR_STATUS_ERROR) {
142  ROS_ERROR("Error, rplidar internal error detected. Please reboot the device to retry.");
143  return false;
144  } else {
145  return true;
146  }
147 
148  } else {
149  ROS_ERROR("Error, cannot retrieve rplidar health code: %x", op_result);
150  return false;
151  }
152 }
153 
154 bool stop_motor(std_srvs::Empty::Request &req,
155  std_srvs::Empty::Response &res)
156 {
157  if(!drv)
158  return false;
159 
160  ROS_DEBUG("Stop motor");
161  drv->stop();
162  drv->stopMotor();
163  return true;
164 }
165 
166 bool start_motor(std_srvs::Empty::Request &req,
167  std_srvs::Empty::Response &res)
168 {
169  if(!drv)
170  return false;
171  ROS_DEBUG("Start motor");
172  drv->startMotor();
173  drv->startScan(0,1);
174  return true;
175 }
176 
178 {
179  return node.angle_z_q14 * 90.f / 16384.f;
180 }
181 
182 int main(int argc, char * argv[]) {
183  ros::init(argc, argv, "rplidar_node");
184 
185  std::string channel_type;
186  std::string tcp_ip;
187  std::string serial_port;
188  int tcp_port = 20108;
189  int serial_baudrate = 115200;
190  std::string frame_id;
191  bool inverted = false;
192  bool angle_compensate = true;
193  float max_distance = 8.0;
194  int angle_compensate_multiple = 1;//it stand of angle compensate at per 1 degree
195  std::string scan_mode;
196  ros::NodeHandle nh;
197  ros::Publisher scan_pub = nh.advertise<sensor_msgs::LaserScan>("scan", 1000);
198  ros::NodeHandle nh_private("~");
199  nh_private.param<std::string>("channel_type", channel_type, "serial");
200  nh_private.param<std::string>("tcp_ip", tcp_ip, "192.168.0.7");
201  nh_private.param<int>("tcp_port", tcp_port, 20108);
202  nh_private.param<std::string>("serial_port", serial_port, "/dev/ttyUSB0");
203  nh_private.param<int>("serial_baudrate", serial_baudrate, 115200/*256000*/);//ros run for A1 A2, change to 256000 if A3
204  nh_private.param<std::string>("frame_id", frame_id, "laser_frame");
205  nh_private.param<bool>("inverted", inverted, false);
206  nh_private.param<bool>("angle_compensate", angle_compensate, false);
207  nh_private.param<std::string>("scan_mode", scan_mode, std::string());
208 
209  ROS_INFO("RPLIDAR running on ROS package rplidar_ros. SDK Version:"RPLIDAR_SDK_VERSION"");
210 
211  u_result op_result;
212 
213  // create the driver instance
214  if(channel_type == "tcp"){
216  }
217  else{
219  }
220 
221 
222  if (!drv) {
223  ROS_ERROR("Create Driver fail, exit");
224  return -2;
225  }
226 
227  if(channel_type == "tcp"){
228  // make connection...
229  if (IS_FAIL(drv->connect(tcp_ip.c_str(), (_u32)tcp_port))) {
230  ROS_ERROR("Error, cannot bind to the specified serial port %s.",serial_port.c_str());
232  return -1;
233  }
234 
235  }
236  else{
237  // make connection...
238  if (IS_FAIL(drv->connect(serial_port.c_str(), (_u32)serial_baudrate))) {
239  ROS_ERROR("Error, cannot bind to the specified serial port %s.",serial_port.c_str());
241  return -1;
242  }
243 
244  }
245 
246  // get rplidar device info
247  if (!getRPLIDARDeviceInfo(drv)) {
248  return -1;
249  }
250 
251  // check health...
252  if (!checkRPLIDARHealth(drv)) {
254  return -1;
255  }
256 
257  ros::ServiceServer stop_motor_service = nh.advertiseService("stop_motor", stop_motor);
258  ros::ServiceServer start_motor_service = nh.advertiseService("start_motor", start_motor);
259 
260  drv->startMotor();
261 
262  RplidarScanMode current_scan_mode;
263  if (scan_mode.empty()) {
264  op_result = drv->startScan(false /* not force scan */, true /* use typical scan mode */, 0, &current_scan_mode);
265  } else {
266  std::vector<RplidarScanMode> allSupportedScanModes;
267  op_result = drv->getAllSupportedScanModes(allSupportedScanModes);
268 
269  if (IS_OK(op_result)) {
270  _u16 selectedScanMode = _u16(-1);
271  for (std::vector<RplidarScanMode>::iterator iter = allSupportedScanModes.begin(); iter != allSupportedScanModes.end(); iter++) {
272  if (iter->scan_mode == scan_mode) {
273  selectedScanMode = iter->id;
274  break;
275  }
276  }
277 
278  if (selectedScanMode == _u16(-1)) {
279  ROS_ERROR("scan mode `%s' is not supported by lidar, supported modes:", scan_mode.c_str());
280  for (std::vector<RplidarScanMode>::iterator iter = allSupportedScanModes.begin(); iter != allSupportedScanModes.end(); iter++) {
281  ROS_ERROR("\t%s: max_distance: %.1f m, Point number: %.1fK", iter->scan_mode,
282  iter->max_distance, (1000/iter->us_per_sample));
283  }
284  op_result = RESULT_OPERATION_FAIL;
285  } else {
286  op_result = drv->startScanExpress(false /* not force scan */, selectedScanMode, 0, &current_scan_mode);
287  }
288  }
289  }
290 
291  if(IS_OK(op_result))
292  {
293  //default frequent is 10 hz (by motor pwm value), current_scan_mode.us_per_sample is the number of scan point per us
294  angle_compensate_multiple = (int)(1000*1000/current_scan_mode.us_per_sample/10.0/360.0);
295  if(angle_compensate_multiple < 1)
296  angle_compensate_multiple = 1;
297  max_distance = current_scan_mode.max_distance;
298  ROS_INFO("current scan mode: %s, max_distance: %.1f m, Point number: %.1fK , angle_compensate: %d", current_scan_mode.scan_mode,
299  current_scan_mode.max_distance, (1000/current_scan_mode.us_per_sample), angle_compensate_multiple);
300  }
301  else
302  {
303  ROS_ERROR("Can not start scan: %08x!", op_result);
304  }
305 
306  ros::Time start_scan_time;
307  ros::Time end_scan_time;
308  double scan_duration;
309  while (ros::ok()) {
311  size_t count = _countof(nodes);
312 
313  start_scan_time = ros::Time::now();
314  op_result = drv->grabScanDataHq(nodes, count);
315  end_scan_time = ros::Time::now();
316  scan_duration = (end_scan_time - start_scan_time).toSec();
317 
318  if (op_result == RESULT_OK) {
319  op_result = drv->ascendScanData(nodes, count);
320  float angle_min = DEG2RAD(0.0f);
321  float angle_max = DEG2RAD(359.0f);
322  if (op_result == RESULT_OK) {
323  if (angle_compensate) {
324  //const int angle_compensate_multiple = 1;
325  const int angle_compensate_nodes_count = 360*angle_compensate_multiple;
326  int angle_compensate_offset = 0;
327  rplidar_response_measurement_node_hq_t angle_compensate_nodes[angle_compensate_nodes_count];
328  memset(angle_compensate_nodes, 0, angle_compensate_nodes_count*sizeof(rplidar_response_measurement_node_hq_t));
329 
330  int i = 0, j = 0;
331  for( ; i < count; i++ ) {
332  if (nodes[i].dist_mm_q2 != 0) {
333  float angle = getAngle(nodes[i]);
334  int angle_value = (int)(angle * angle_compensate_multiple);
335  if ((angle_value - angle_compensate_offset) < 0) angle_compensate_offset = angle_value;
336  for (j = 0; j < angle_compensate_multiple; j++) {
337  angle_compensate_nodes[angle_value-angle_compensate_offset+j] = nodes[i];
338  }
339  }
340  }
341 
342  publish_scan(&scan_pub, angle_compensate_nodes, angle_compensate_nodes_count,
343  start_scan_time, scan_duration, inverted,
344  angle_min, angle_max, max_distance,
345  frame_id);
346  } else {
347  int start_node = 0, end_node = 0;
348  int i = 0;
349  // find the first valid node and last valid node
350  while (nodes[i++].dist_mm_q2 == 0);
351  start_node = i-1;
352  i = count -1;
353  while (nodes[i--].dist_mm_q2 == 0);
354  end_node = i+1;
355 
356  angle_min = DEG2RAD(getAngle(nodes[start_node]));
357  angle_max = DEG2RAD(getAngle(nodes[end_node]));
358 
359  publish_scan(&scan_pub, &nodes[start_node], end_node-start_node +1,
360  start_scan_time, scan_duration, inverted,
361  angle_min, angle_max, max_distance,
362  frame_id);
363  }
364  } else if (op_result == RESULT_OPERATION_FAIL) {
365  // All the data is invalid, just publish them
366  float angle_min = DEG2RAD(0.0f);
367  float angle_max = DEG2RAD(359.0f);
368 
369  publish_scan(&scan_pub, nodes, count,
370  start_scan_time, scan_duration, inverted,
371  angle_min, angle_max, max_distance,
372  frame_id);
373  }
374  }
375 
376  ros::spinOnce();
377  }
378 
379  // done!
380  drv->stop();
381  drv->stopMotor();
383  return 0;
384 }
_u32 dist_mm_q2
Definition: rplidar_cmd.h:3
#define IS_OK(x)
Definition: rptypes.h:113
virtual u_result stop(_u32 timeout=DEFAULT_TIMEOUT)=0
void publish(const boost::shared_ptr< M > &message) const
bool getRPLIDARDeviceInfo(RPlidarDriver *drv)
Definition: node.cpp:107
f
int main(int argc, char *argv[])
Definition: node.cpp:182
virtual u_result grabScanDataHq(rplidar_response_measurement_node_hq_t *nodebuffer, size_t &count, _u32 timeout=DEFAULT_TIMEOUT)=0
bool stop_motor(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
Definition: node.cpp:154
_u8 quality
Definition: rplidar_cmd.h:4
void publish_scan(ros::Publisher *pub, rplidar_response_measurement_node_hq_t *nodes, size_t node_count, ros::Time start, double scan_time, bool inverted, float angle_min, float angle_max, float max_distance, std::string frame_id)
Definition: node.cpp:50
static void DisposeDriver(RPlidarDriver *drv)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
virtual u_result startScanExpress(bool force, _u16 scanMode, _u32 options=0, RplidarScanMode *outUsedScanMode=NULL, _u32 timeout=DEFAULT_TIMEOUT)=0
#define RESULT_OK
Definition: rptypes.h:102
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
virtual u_result stopMotor()=0
Stop RPLIDAR&#39;s motor when using accessory board.
#define RPLIDAR_STATUS_ERROR
Definition: rplidar_cmd.h:141
virtual u_result startMotor()=0
Start RPLIDAR&#39;s motor when using accessory board.
#define IS_FAIL(x)
Definition: rptypes.h:114
#define RPLIDAR_SDK_VERSION
Definition: rplidar.h:44
#define DEG2RAD(x)
Definition: node.cpp:44
#define ROS_INFO(...)
#define _countof(_Array)
Definition: node.cpp:41
ROSCPP_DECL bool ok()
#define RESULT_OPERATION_TIMEOUT
Definition: rptypes.h:107
virtual u_result startScan(bool force, bool useTypicalScan, _u32 options=0, RplidarScanMode *outUsedScanMode=NULL)=0
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
virtual u_result ascendScanData(rplidar_response_measurement_node_hq_t *nodebuffer, size_t count)=0
virtual u_result getAllSupportedScanModes(std::vector< RplidarScanMode > &outModes, _u32 timeoutInMs=DEFAULT_TIMEOUT)=0
Get all scan modes that supported by lidar.
virtual u_result getDeviceInfo(rplidar_response_device_info_t &info, _u32 timeout=DEFAULT_TIMEOUT)=0
uint32_t _u32
Definition: rptypes.h:69
static float getAngle(const rplidar_response_measurement_node_t &node)
static RPlidarDriver * CreateDriver(_u32 drivertype=DRIVER_TYPE_SERIALPORT)
#define RESULT_OPERATION_FAIL
Definition: rptypes.h:106
static Time now()
bool start_motor(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
Definition: node.cpp:166
virtual u_result connect(const char *, _u32, _u32 flag=0)=0
uint16_t _u16
Definition: rptypes.h:66
ROSCPP_DECL void spinOnce()
#define ROS_ERROR(...)
bool checkRPLIDARHealth(RPlidarDriver *drv)
Definition: node.cpp:133
RPlidarDriver * drv
Definition: node.cpp:48
virtual u_result getHealth(rplidar_response_device_health_t &health, _u32 timeout=DEFAULT_TIMEOUT)=0
uint32_t u_result
Definition: rptypes.h:100
#define ROS_DEBUG(...)


rplidar_ros
Author(s):
autogenerated on Wed Mar 20 2019 07:54:15