YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
rpLidar2.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: LGPL-2.1-or-later
4 */
5
6#include "rpLidar2.h"
7
8#include <yarp/os/Time.h>
9#include <yarp/os/Log.h>
10#include <yarp/os/LogStream.h>
12
13#include <cstdlib>
14#include <cstring>
15#include <iostream>
16#include <limits>
17#include <mutex>
18
19#ifndef _USE_MATH_DEFINES
20#define _USE_MATH_DEFINES
21#endif
22#include <cmath>
23
24#ifndef DEG2RAD
25#define DEG2RAD M_PI/180.0
26#endif
27
28//#define LASER_DEBUG
29//#define FORCE_SCAN
30
31using namespace rp::standalone::rplidar;
32using namespace yarp::dev;
33
34YARP_LOG_COMPONENT(RP2_LIDAR, "yarp.devices.rpLidar2")
35
36//-------------------------------------------------------------------------------------
37
38bool RpLidar2::open(yarp::os::Searchable& config)
39{
40 std::string serial;
41 int baudrate;
42 u_result result;
43
44 m_device_status = DEVICE_OK_STANDBY;
45 m_min_distance = 0.1; //m
46 m_max_distance = 5; //m
47 m_pwm_val = 0;
48
49 //parse all the parameters related to the linear/angular range of the sensor
50 if (this->parseConfiguration(config) == false)
51 {
52 yCError(RP2_LIDAR) << ": error parsing parameters";
53 return false;
54 }
55
56 bool br = config.check("GENERAL");
57 if (br != false)
58 {
59 yarp::os::Searchable& general_config = config.findGroup("GENERAL");
60 if (general_config.check("serial_port") == false) { yCError(RP2_LIDAR) << "Missing serial_port param in GENERAL group"; return false; }
61 if (general_config.check("serial_baudrate") == false) { yCError(RP2_LIDAR) << "Missing serial_baudrate param in GENERAL group"; return false; }
62 if (general_config.check("sample_buffer_life") == false) { yCError(RP2_LIDAR) << "Missing sample_buffer_life param in GENERAL group"; return false; }
63
64 baudrate = general_config.find("serial_baudrate").asInt32();
65 m_serialPort = general_config.find("serial_port").asString();
66 m_buffer_life = general_config.find("sample_buffer_life").asInt32();
67 if (general_config.check("motor_pwm"))
68 {
69 m_pwm_val = general_config.find("motor_pwm").asInt32();
70 }
71 if (general_config.check("thread_period"))
72 {
73 double thread_period = general_config.find("thread_period").asInt32() / 1000.0;
74 this->setPeriod(thread_period);
75 }
76 }
77 else
78 {
79 yCError(RP2_LIDAR) << "Missing GENERAL section";
80 return false;
81 }
82
83 m_drv = RPlidarDriver::CreateDriver(rp::standalone::rplidar::DRIVER_TYPE_SERIALPORT);
84 if (!m_drv)
85 {
86 yCError(RP2_LIDAR) << "Create Driver fail, exit\n";
87 return false;
88 }
89
90 if (IS_FAIL(m_drv->connect(m_serialPort.c_str(), (_u32)baudrate)))
91 {
92 yCError(RP2_LIDAR) << "Error, cannot bind to the specified serial port:", m_serialPort.c_str();
93 RPlidarDriver::DisposeDriver(m_drv);
94 return false;
95 }
96
97 m_info = deviceinfo();
98 yCInfo(RP2_LIDAR, "max_dist %f, min_dist %f", m_max_distance, m_min_distance);
99
100 bool m_inExpressMode=false;
101 result = m_drv->checkExpressScanSupported(m_inExpressMode);
102 if (result == RESULT_OK && m_inExpressMode==true)
103 {
104 yCInfo(RP2_LIDAR) << "Express scan mode is supported";
105 }
106 else
107 {
108 yCWarning(RP2_LIDAR) << "Device does not supports express scan mode";
109 }
110
111 result = m_drv->startMotor();
112 if (result != RESULT_OK)
113 {
114 handleError(result);
115 return false;
116 }
117 yCInfo(RP2_LIDAR) << "Motor started successfully";
118
119 if (m_pwm_val!=0)
120 {
121 if (m_pwm_val>0 && m_pwm_val<1023)
122 {
123 result = m_drv->setMotorPWM(m_pwm_val);
124 if (result != RESULT_OK)
125 {
126 handleError(result);
127 return false;
128 }
129 yCInfo(RP2_LIDAR) << "Motor pwm set to "<< m_pwm_val;
130 }
131 else
132 {
133 yCError(RP2_LIDAR) << "Invalid motor pwm request " << m_pwm_val <<". It should be a value between 0 and 1023.";
134 return false;
135 }
136 }
137 else
138 {
139 yCInfo(RP2_LIDAR) << "Motor pwm set to default value (600?)";
140 }
141
142 bool forceScan =false;
143 result = m_drv->startScan(forceScan,m_inExpressMode);
144
145 if (result != RESULT_OK)
146 {
147 handleError(result);
148 return false;
149 }
150 yCInfo(RP2_LIDAR) << "Scan started successfully";
151
152 yCInfo(RP2_LIDAR) << "Device info:" << m_info;
153 yCInfo(RP2_LIDAR,"max_angle %f, min_angle %f", m_max_angle, m_min_angle);
154 yCInfo(RP2_LIDAR,"resolution %f", m_resolution);
155 yCInfo(RP2_LIDAR,"sensors %zu", m_sensorsNum);
157 return true;
158}
159
161{
163
164 m_drv->stopMotor();
165 RPlidarDriver::DisposeDriver(m_drv);
166 yCInfo(RP2_LIDAR) << "rpLidar closed";
167 return true;
168}
169
171{
172 std::lock_guard<std::mutex> guard(m_mutex);
173 m_min_distance = min;
174 m_max_distance = max;
175 return ReturnValue_ok;
176}
177
179{
180 std::lock_guard<std::mutex> guard(m_mutex);
181 m_min_angle = min;
182 m_max_angle = max;
183 return ReturnValue_ok;
184}
185
187{
188 std::lock_guard<std::mutex> guard(m_mutex);
190 return ReturnValue_ok;
191}
192
194{
195 std::lock_guard<std::mutex> guard(m_mutex);
196 yCWarning(RP2_LIDAR, "setScanRate not yet implemented");
197 return ReturnValue::return_code::return_value_error_not_implemented_by_device;
198}
199
201{
202 return true;
203}
204
205//#define DEBUG_LOCKING 1
206#ifndef _countof
207#define _countof(_Array) (int)(sizeof(_Array) / sizeof (_Array[0]))
208#endif
209
211{
213 m_mutex.unlock();
214 return;
215}
216
218{
221 size_t count = _countof(nodes);
222 static int life = 0;
223 op_result = m_drv->grabScanData(nodes, count);
224 if (op_result != RESULT_OK)
225 {
226 yCError(RP2_LIDAR) << m_serialPort << ": grabbing scan data failed";
227 handleError(op_result);
228 return false;
229 }
230
231 float frequency = 0;
232 bool is4kmode = false;
233 op_result = m_drv->getFrequency(m_inExpressMode, count, frequency, is4kmode);
234 if (op_result != RESULT_OK)
235 {
236 yCError(RP2_LIDAR) << "getFrequency failed";
237 return false;
238 }
239
240 m_drv->ascendScanData(nodes, count);
241
242 if (op_result != RESULT_OK)
243 {
244 yCError(RP2_LIDAR) << "ascending scan data failed\n";
245 handleError(op_result);
246 return false;
247 }
248
249 if (m_buffer_life && life % m_buffer_life == 0)
250 {
251 for (size_t i = 0; i < m_laser_data.size(); i++)
252 {
253 //m_laser_data[i]=0; //0 is a terribly unsafe value and should be avoided.
254 m_laser_data[i] = std::numeric_limits<double>::infinity();
255 }
256 }
257
258 //this lock protects m_laser_data. It is released at the end of the run(),
259 //after that the following methods are called: applyLimitsOnLaserData(), updateTimestamp()
260 m_mutex.lock();
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 {
290 }
291 else
292 {
293 yCDebug(RP2_LIDAR) << "RpLidar::run() invalid angle: elem" << elem << ">" << "laser_data.size()" << m_laser_data.size();
294 }
295 }
296
297 life++;
298 return true;
299}
300
302{
303#ifdef LASER_DEBUG
304 yCDebug(RP2_LIDAR,"RpLidar Thread releasing...");
305 yCDebug(RP2_LIDAR,"... done.");
306#endif
307
308 return;
309}
310
311void RpLidar2::handleError(u_result error)
312{
313 switch (error)
314 {
315 case RESULT_FAIL_BIT:
316 yCError(RP2_LIDAR) << "error: 'FAIL BIT'";
317 break;
319 yCError(RP2_LIDAR) << "error: 'ALREADY DONE'";
320 break;
322 yCError(RP2_LIDAR) << "error: 'INVALID DATA'";
323 break;
325 yCError(RP2_LIDAR) << "error: 'OPERATION FAIL'";
326 break;
328 yCError(RP2_LIDAR) << "error: 'OPERATION TIMEOUT'";
329 break;
331 yCError(RP2_LIDAR) << "error: 'OPERATION STOP'";
332 break;
334 yCError(RP2_LIDAR) << "error: 'OPERATION NOT SUPPORT'";
335 break;
337 yCError(RP2_LIDAR) << "error: 'FORMAT NOT SUPPORT'";
338 break;
340 yCError(RP2_LIDAR) << "error: 'INSUFFICENT MEMORY'";
341 break;
342 }
343}
344
345std::string RpLidar2::deviceinfo()
346{
347 if (m_drv)
348 {
349 u_result result;
351 std::string serialNumber;
352
353 result = m_drv->getDeviceInfo(info);
354 if (result != RESULT_OK)
355 {
356 handleError(result);
357 return {};
358 }
359
360 for (unsigned char i : info.serialnum)
361 {
362 serialNumber += std::to_string(i);
363 }
364
365 return "Firmware Version: " + std::to_string(info.firmware_version) +
366 "\nHardware Version: " + std::to_string(info.hardware_version) +
367 "\nModel: " + std::to_string(info.model) +
368 "\nSerial Number:" + serialNumber;
369 }
370 return {};
371}
#define ReturnValue_ok
Definition ReturnValue.h:77
rpLidar2: The device driver for the RP2 lidar
Definition rpLidar2.h:47
rplidardrv * m_drv
Definition rpLidar2.h:57
int m_buffer_life
Definition rpLidar2.h:53
yarp::dev::ReturnValue setDistanceRange(double min, double max) override
set the device detection range.
Definition rpLidar2.cpp:170
bool close() override
Close the DeviceDriver.
Definition rpLidar2.cpp:160
bool threadInit() override
Initialization method.
Definition rpLidar2.cpp:200
bool m_inExpressMode
Definition rpLidar2.h:54
bool acquireDataFromHW() override final
This method should be implemented by the user, and contain the logic to grab data from the hardware.
Definition rpLidar2.cpp:217
std::string m_serialPort
Definition rpLidar2.h:56
void threadRelease() override
Release method.
Definition rpLidar2.cpp:301
void run() override
Loop function.
Definition rpLidar2.cpp:210
yarp::dev::ReturnValue setScanLimits(double min, double max) override
set the scan angular range.
Definition rpLidar2.cpp:178
yarp::dev::ReturnValue setHorizontalResolution(double step) override
get the angular step between two measurements (if available)
Definition rpLidar2.cpp:186
yarp::dev::ReturnValue setScanRate(double rate) override
set the scan rate (scans per seconds)
Definition rpLidar2.cpp:193
virtual bool updateLidarData()
This utility method calls in sequence: grabDataFromHW(), updateTimestamp and applyLimitsOnLaserData()...
A mini-server for performing network communication in the background.
bool start()
Call this to start the thread.
void step()
Call this to "step" the thread rather than starting it.
void stop()
Call this to stop the thread, this call blocks until the thread is terminated (and releaseThread() ca...
A base class for nested structures that can be searched.
Definition Searchable.h:31
size_t size() const
Definition Vector.h:341
#define yCInfo(component,...)
#define yCError(component,...)
#define yCWarning(component,...)
#define yCDebug(component,...)
#define YARP_LOG_COMPONENT(name,...)
For streams capable of holding different kinds of content, check what they actually have.
Definition jointData.cpp:13
The main, catch-all namespace for YARP.
Definition dirs.h:16
#define _countof(_Array)
Definition rpLidar2.cpp:207
const yarp::os::LogComponent & RP2_LIDAR()
Definition rpLidar2.cpp:34