YARP
Yet Another Robot Platform
rpLidar2.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include "rpLidar2.h"
20 
21 #include <yarp/os/Time.h>
22 #include <yarp/os/Log.h>
23 #include <yarp/os/LogStream.h>
24 #include <yarp/os/ResourceFinder.h>
25 
26 #include <cstdlib>
27 #include <cstring>
28 #include <iostream>
29 #include <limits>
30 #include <mutex>
31 
32 #ifndef _USE_MATH_DEFINES
33 #define _USE_MATH_DEFINES
34 #endif
35 #include <cmath>
36 
37 #ifndef DEG2RAD
38 #define DEG2RAD M_PI/180.0
39 #endif
40 
41 //#define LASER_DEBUG
42 //#define FORCE_SCAN
43 
44 using namespace std;
45 using namespace rp::standalone::rplidar;
46 
47 YARP_LOG_COMPONENT(RP2_LIDAR, "yarp.devices.rpLidar2")
48 
49 //-------------------------------------------------------------------------------------
50 
51 bool RpLidar2::open(yarp::os::Searchable& config)
52 {
53  string serial;
54  int baudrate;
55  u_result result;
56 
57  m_device_status = DEVICE_OK_STANBY;
58  m_min_distance = 0.1; //m
59  m_max_distance = 5; //m
60  m_pwm_val = 0;
61 
62  //parse all the parameters related to the linear/angular range of the sensor
63  if (this->parseConfiguration(config) == false)
64  {
65  yCError(RP2_LIDAR) << ": error parsing parameters";
66  return false;
67  }
68 
69  bool br = config.check("GENERAL");
70  if (br != false)
71  {
72  yarp::os::Searchable& general_config = config.findGroup("GENERAL");
73  if (general_config.check("serial_port") == false) { yCError(RP2_LIDAR) << "Missing serial_port param in GENERAL group"; return false; }
74  if (general_config.check("serial_baudrate") == false) { yCError(RP2_LIDAR) << "Missing serial_baudrate param in GENERAL group"; return false; }
75  if (general_config.check("sample_buffer_life") == false) { yCError(RP2_LIDAR) << "Missing sample_buffer_life param in GENERAL group"; return false; }
76 
77  baudrate = general_config.find("serial_baudrate").asInt32();
78  m_serialPort = general_config.find("serial_port").asString();
79  m_buffer_life = general_config.find("sample_buffer_life").asInt32();
80  if (general_config.check("motor_pwm"))
81  {
82  m_pwm_val = general_config.find("motor_pwm").asInt32();
83  }
84  if (general_config.check("thread_period"))
85  {
86  double thread_period = general_config.find("thread_period").asInt32() / 1000.0;
87  this->setPeriod(thread_period);
88  }
89  }
90  else
91  {
92  yCError(RP2_LIDAR) << "Missing GENERAL section";
93  return false;
94  }
95 
96  m_drv = RPlidarDriver::CreateDriver(rp::standalone::rplidar::DRIVER_TYPE_SERIALPORT);
97  if (!m_drv)
98  {
99  yCError(RP2_LIDAR) << "Create Driver fail, exit\n";
100  return false;
101  }
102 
103  if (IS_FAIL(m_drv->connect(m_serialPort.c_str(), (_u32)baudrate)))
104  {
105  yCError(RP2_LIDAR) << "Error, cannot bind to the specified serial port:", m_serialPort.c_str();
106  RPlidarDriver::DisposeDriver(m_drv);
107  return false;
108  }
109 
110  m_info = deviceinfo();
111  yCInfo(RP2_LIDAR, "max_dist %f, min_dist %f", m_max_distance, m_min_distance);
112 
113  bool m_inExpressMode=false;
114  result = m_drv->checkExpressScanSupported(m_inExpressMode);
115  if (result == RESULT_OK && m_inExpressMode==true)
116  {
117  yCInfo(RP2_LIDAR) << "Express scan mode is supported";
118  }
119  else
120  {
121  yCWarning(RP2_LIDAR) << "Device does not supports express scan mode";
122  }
123 
124  result = m_drv->startMotor();
125  if (result != RESULT_OK)
126  {
127  handleError(result);
128  return false;
129  }
130  yCInfo(RP2_LIDAR) << "Motor started successfully";
131 
132  if (m_pwm_val!=0)
133  {
134  if (m_pwm_val>0 && m_pwm_val<1023)
135  {
136  result = m_drv->setMotorPWM(m_pwm_val);
137  if (result != RESULT_OK)
138  {
139  handleError(result);
140  return false;
141  }
142  yCInfo(RP2_LIDAR) << "Motor pwm set to "<< m_pwm_val;
143  }
144  else
145  {
146  yCError(RP2_LIDAR) << "Invalid motor pwm request " << m_pwm_val <<". It should be a value between 0 and 1023.";
147  return false;
148  }
149  }
150  else
151  {
152  yCInfo(RP2_LIDAR) << "Motor pwm set to default value (600?)";
153  }
154 
155  bool forceScan =false;
156  result = m_drv->startScan(forceScan,m_inExpressMode);
157 
158  if (result != RESULT_OK)
159  {
160  handleError(result);
161  return false;
162  }
163  yCInfo(RP2_LIDAR) << "Scan started successfully";
164 
165  yCInfo(RP2_LIDAR) << "Device info:" << m_info;
166  yCInfo(RP2_LIDAR,"max_angle %f, min_angle %f", m_max_angle, m_min_angle);
167  yCInfo(RP2_LIDAR,"resolution %f", m_resolution);
168  yCInfo(RP2_LIDAR,"sensors %zu", m_sensorsNum);
169  PeriodicThread::start();
170  return true;
171 }
172 
174 {
175  m_drv->stopMotor();
176  RPlidarDriver::DisposeDriver(m_drv);
177  PeriodicThread::stop();
178  yCInfo(RP2_LIDAR) << "rpLidar closed";
179  return true;
180 }
181 
182 bool RpLidar2::setDistanceRange(double min, double max)
183 {
184  std::lock_guard<std::mutex> guard(m_mutex);
185  m_min_distance = min;
186  m_max_distance = max;
187  return true;
188 }
189 
190 bool RpLidar2::setScanLimits(double min, double max)
191 {
192  std::lock_guard<std::mutex> guard(m_mutex);
193  m_min_angle = min;
194  m_max_angle = max;
195  return true;
196 }
197 
199 {
200  std::lock_guard<std::mutex> guard(m_mutex);
201  m_resolution = step;
202  return true;
203 }
204 
205 bool RpLidar2::setScanRate(double rate)
206 {
207  std::lock_guard<std::mutex> guard(m_mutex);
208  yCWarning(RP2_LIDAR, "setScanRate not yet implemented");
209  return false;
210 }
211 
213 {
214  return true;
215 }
216 
217 //#define DEBUG_LOCKING 1
218 #ifndef _countof
219 #define _countof(_Array) (int)(sizeof(_Array) / sizeof (_Array[0]))
220 #endif
221 
223 {
224  u_result op_result;
225  rplidar_response_measurement_node_t nodes[2048];
226  size_t count = _countof(nodes);
227  static int life = 0;
228  op_result = m_drv->grabScanData(nodes, count);
229  if (op_result != RESULT_OK)
230  {
231  yCError(RP2_LIDAR) << m_serialPort << ": grabbing scan data failed";
232  handleError(op_result);
233  return;
234  }
235 
236  float frequency=0;
237  bool is4kmode=false;
238  op_result = m_drv->getFrequency(m_inExpressMode, count, frequency, is4kmode);
239  if (op_result != RESULT_OK)
240  {
241  yCError(RP2_LIDAR) << "getFrequency failed";
242  }
243 
244  m_drv->ascendScanData(nodes, count);
245 
246  if (op_result != RESULT_OK)
247  {
248  yCError(RP2_LIDAR) << "ascending scan data failed\n";
249  handleError(op_result);
250  return;
251  }
252 
253  if (m_buffer_life && life%m_buffer_life == 0)
254  {
255  for (size_t i=0 ;i<m_laser_data.size(); i++)
256  {
257  //m_laser_data[i]=0; //0 is a terribly unsafe value and should be avoided.
258  m_laser_data[i]=std::numeric_limits<double>::infinity();
259  }
260  }
261 
262  for (size_t i = 0; i < count; ++i)
263  {
264 
265  double distance = nodes[i].distance_q2 / 4.0f / 1000.0; //m
266  double angle = (float)((nodes[i].angle_q6_checkbit >> RPLIDAR_RESP_MEASUREMENT_ANGLE_SHIFT)/64.0f); //deg
267  double quality = nodes[i].sync_quality >> RPLIDAR_RESP_MEASUREMENT_QUALITY_SHIFT;
268  angle = (360 - angle);
269 
270  if (angle >= 360)
271  {
272  angle -= 360;
273  }
274 
275  //checkme, is it useful?
276  if (angle > 360)
277  {
278  yCWarning(RP2_LIDAR) << "Invalid angle";
279  }
280 
281  if (quality == 0 || distance == 0)
282  {
283  distance = std::numeric_limits<double>::infinity();
284  }
285 
286  int elem = (int)(angle / m_resolution);
287  if (elem >= 0 && elem < (int)m_laser_data.size())
288  {
289  m_laser_data[elem] = distance;
290  }
291  else
292  {
293  yCDebug(RP2_LIDAR) << "RpLidar::run() invalid angle: elem" << elem << ">" << "laser_data.size()" << m_laser_data.size();
294  }
295  }
296  applyLimitsOnLaserData();
297 
298  life++;
299  return;
300 }
301 
303 {
304 #ifdef LASER_DEBUG
305  yCDebug(RP2_LIDAR,"RpLidar Thread releasing...");
306  yCDebug(RP2_LIDAR,"... done.");
307 #endif
308 
309  return;
310 }
311 
312 void RpLidar2::handleError(u_result error)
313 {
314  switch (error)
315  {
316  case RESULT_FAIL_BIT:
317  yCError(RP2_LIDAR) << "error: 'FAIL BIT'";
318  break;
319  case RESULT_ALREADY_DONE:
320  yCError(RP2_LIDAR) << "error: 'ALREADY DONE'";
321  break;
322  case RESULT_INVALID_DATA:
323  yCError(RP2_LIDAR) << "error: 'INVALID DATA'";
324  break;
325  case RESULT_OPERATION_FAIL:
326  yCError(RP2_LIDAR) << "error: 'OPERATION FAIL'";
327  break;
328  case RESULT_OPERATION_TIMEOUT:
329  yCError(RP2_LIDAR) << "error: 'OPERATION TIMEOUT'";
330  break;
331  case RESULT_OPERATION_STOP:
332  yCError(RP2_LIDAR) << "error: 'OPERATION STOP'";
333  break;
334  case RESULT_OPERATION_NOT_SUPPORT:
335  yCError(RP2_LIDAR) << "error: 'OPERATION NOT SUPPORT'";
336  break;
337  case RESULT_FORMAT_NOT_SUPPORT:
338  yCError(RP2_LIDAR) << "error: 'FORMAT NOT SUPPORT'";
339  break;
340  case RESULT_INSUFFICIENT_MEMORY:
341  yCError(RP2_LIDAR) << "error: 'INSUFFICENT MEMORY'";
342  break;
343  }
344 }
345 
346 std::string RpLidar2::deviceinfo()
347 {
348  if (m_drv)
349  {
350  u_result result;
351  rplidar_response_device_info_t info;
352  string serialNumber;
353 
354  result = m_drv->getDeviceInfo(info);
355  if (result != RESULT_OK)
356  {
357  handleError(result);
358  return {};
359  }
360 
361  for (unsigned char i : info.serialnum)
362  {
363  serialNumber += to_string(i);
364  }
365 
366  return "Firmware Version: " + to_string(info.firmware_version) +
367  "\nHardware Version: " + to_string(info.hardware_version) +
368  "\nModel: " + to_string(info.model) +
369  "\nSerial Number:" + serialNumber;
370  }
371  return {};
372 }
LogStream.h
yarp::os::Searchable
A base class for nested structures that can be searched.
Definition: Searchable.h:69
yarp::os::Searchable::findGroup
virtual Bottle & findGroup(const std::string &key) const =0
Gets a list corresponding to a given keyword.
yCWarning
#define yCWarning(component,...)
Definition: LogComponent.h:146
_countof
#define _countof(_Array)
Definition: rpLidar2.cpp:219
RP2_LIDAR
const yarp::os::LogComponent & RP2_LIDAR()
Definition: rpLidar2.cpp:47
YARP_LOG_COMPONENT
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:80
RpLidar2::threadInit
bool threadInit() override
Initialization method.
Definition: rpLidar2.cpp:212
rpLidar2.h
RpLidar2::threadRelease
void threadRelease() override
Release method.
Definition: rpLidar2.cpp:302
Log.h
RpLidar2
rpLidar2: Documentation to be added
Definition: rpLidar2.h:50
RpLidar2::run
void run() override
Loop function.
Definition: rpLidar2.cpp:222
RpLidar2::setDistanceRange
bool setDistanceRange(double min, double max) override
set the device detection range.
Definition: rpLidar2.cpp:182
yarp::os::Value::asString
virtual std::string asString() const
Get string value.
Definition: Value.cpp:237
yarp::os::Searchable::check
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
RpLidar2::setScanRate
bool setScanRate(double rate) override
set the scan rate (scans per seconds)
Definition: rpLidar2.cpp:205
yarp::os::Searchable::find
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
RpLidar2::setHorizontalResolution
bool setHorizontalResolution(double step) override
get the angular step between two measurments (if available)
Definition: rpLidar2.cpp:198
RpLidar2::setScanLimits
bool setScanLimits(double min, double max) override
set the scan angular range.
Definition: rpLidar2.cpp:190
yCError
#define yCError(component,...)
Definition: LogComponent.h:157
yarp::os::Value::asInt32
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition: Value.cpp:207
yCInfo
#define yCInfo(component,...)
Definition: LogComponent.h:135
yCDebug
#define yCDebug(component,...)
Definition: LogComponent.h:112
yarp
The main, catch-all namespace for YARP.
Definition: environment.h:18
Time.h
RpLidar2::close
bool close() override
Close the DeviceDriver.
Definition: rpLidar2.cpp:173
ResourceFinder.h