YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
rpLidar3.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 "rpLidar3.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(RP_LIDAR3, "yarp.devices.RpLidar3")
35
36//-------------------------------------------------------------------------------------
37bool RpLidar3::startMotor()
38{
39 u_result result = m_drv->startMotor();
40 if (result != RESULT_OK)
41 {
42 handleError(result);
43 yCError(RP_LIDAR3) << "Unable to start motor";
44 return false;
45 }
46 yCInfo(RP_LIDAR3) << "Motor started successfully";
47
48 if (m_pwm_val > 0 && m_pwm_val < 1023)
49 {
50 result = m_drv->setMotorPWM(m_pwm_val);
51 if (result != RESULT_OK)
52 {
53 handleError(result);
54 yCError(RP_LIDAR3) << "Unable to setMotorPWM";
55 return false;
56 }
57 yCInfo(RP_LIDAR3) << "Motor pwm set to " << m_pwm_val;
58 }
59 else
60 {
61 yCError(RP_LIDAR3) << "Invalid motor pwm request " << m_pwm_val << ". It should be a value between 0 and 1023.";
62 return false;
63 }
64
65 return true;
66}
67
68bool RpLidar3::startScan()
69{
71 std::vector<RplidarScanMode> scanModes;
72 u_result op_result = m_drv->getAllSupportedScanModes(scanModes);
73 yCInfo(RP_LIDAR3) << "List of Scan Modes";
74 for (size_t i = 0; i < scanModes.size(); i++)
75 {
76 yCInfo(RP_LIDAR3) << "id:" << scanModes[i].id
77 << ", mode:" << scanModes[i].scan_mode
78 << ", max distance:" << scanModes[i].max_distance
79 << ", us per sample:" << scanModes[i].us_per_sample
80 << ", samples/s:" << 1.0 / scanModes[i].us_per_sample * 1000000;
81 }
82
83 yInfo() << "Using scan mode: " << m_scan_mode;
84
85 if (IS_OK(op_result))
86 {
88 for (std::vector<RplidarScanMode>::iterator iter = scanModes.begin(); iter != scanModes.end(); iter++)
89 {
90 if (iter->scan_mode == m_scan_mode)
91 {
93 break;
94 }
95 }
96
97 if (selectedScanMode == _u16(-1))
98 {
99 yCInfo(RP_LIDAR3, "scan mode `%s' is not supported by lidar, supported modes:", m_scan_mode.c_str());
100 for (std::vector<RplidarScanMode>::iterator iter = scanModes.begin(); iter != scanModes.end(); iter++)
101 {
102 yCInfo(RP_LIDAR3, "\t%s: max_distance: %.1f m, Point number: %.1fK", iter->scan_mode, iter->max_distance, (1000 / iter->us_per_sample));
103 }
105 }
106 else
107 {
108 op_result = m_drv->startScanExpress(false /* not force scan */, selectedScanMode, 0, &current_scan_mode);
109 }
110 }
111
112 if (op_result != RESULT_OK)
113 {
114 handleError(op_result);
115 return false;
116 }
117
118 yCInfo(RP_LIDAR3) << "Scan started successfully";
119 return true;
120}
121
123{
124 std::string serial;
125 int baudrate;
126
128
129 //parse all the parameters related to the linear/angular range of the sensor
130 if (this->parseConfiguration(config) == false)
131 {
132 yCError(RP_LIDAR3) << ": error parsing parameters";
133 return false;
134 }
135
136 bool br = config.check("GENERAL");
137 if (br != false)
138 {
139 //general options
140 {
141 yarp::os::Searchable& general_config = config.findGroup("GENERAL");
142 if (general_config.check("serial_port") == false) { yCError(RP_LIDAR3) << "Missing serial_port param in GENERAL group"; return false; }
143 if (general_config.check("serial_baudrate") == false) { yCError(RP_LIDAR3) << "Missing serial_baudrate param in GENERAL group"; return false; }
144 if (general_config.check("sample_buffer_life") == false) { yCError(RP_LIDAR3) << "Missing sample_buffer_life param in GENERAL group"; return false; }
145 if (general_config.check("thread_period"))
146 {
147 double thread_period = general_config.find("thread_period").asInt32() / 1000.0;
148 this->setPeriod(thread_period);
149 }
150
151 baudrate = general_config.find("serial_baudrate").asInt32();
152 m_serialPort = general_config.find("serial_port").asString();
153 m_buffer_life = general_config.find("sample_buffer_life").asInt32();
154 }
155
156 //options specific to the rplidar sdk
157 {
158 yarp::os::Searchable& rplidar_config = config.findGroup("RPLIDAR");
159 if (rplidar_config.check("motor_pwm"))
160 {
161 m_pwm_val = rplidar_config.find("motor_pwm").asInt32();
162 }
163 if (rplidar_config.check("express_mode"))
164 {
165 m_inExpressMode = rplidar_config.find("express_mode").asInt32();
166 }
167 if (rplidar_config.check("scan_mode"))
168 {
169 m_scan_mode = rplidar_config.find("scan_mode").asString();
170 }
171 if (rplidar_config.check("force_scan"))
172 {
173 m_force_scan = rplidar_config.find("force_scan").asInt32();
174 }
175 }
176 }
177 else
178 {
179 yCError(RP_LIDAR3) << "Missing GENERAL section";
180 return false;
181 }
182
183 m_drv = RPlidarDriver::CreateDriver(rp::standalone::rplidar::DRIVER_TYPE_SERIALPORT);
184 if (!m_drv)
185 {
186 yCError(RP_LIDAR3) << "Create Driver fail, exit\n";
187 return false;
188 }
189
190 if (IS_FAIL(m_drv->connect(m_serialPort.c_str(), (_u32)baudrate)))
191 {
192 yCError(RP_LIDAR3) << "Error, cannot bind to the specified serial port:", m_serialPort.c_str();
193 RPlidarDriver::DisposeDriver(m_drv);
194 return false;
195 }
196
197 if (!deviceinfo()) return false;
198 if (!startMotor()) return false;
199 if (!startScan()) return false;
200
201 yCInfo(RP_LIDAR3) << "Device info:" << m_info;
202 yCInfo(RP_LIDAR3,"max_dist %f, min_dist %f", m_max_distance, m_min_distance);
203 yCInfo(RP_LIDAR3,"max_angle %f, min_angle %f", m_max_angle, m_min_angle);
204 yCInfo(RP_LIDAR3,"resolution %f", m_resolution);
205 yCInfo(RP_LIDAR3,"sensors %zu", m_sensorsNum);
207 return true;
208}
209
211{
212 yCDebug(RP_LIDAR3) << "closing..";
214
215 m_drv->stopMotor();
216 m_drv->stop();
217 RPlidarDriver::DisposeDriver(m_drv);
218 yCInfo(RP_LIDAR3) << "rpLidar closed";
219 return true;
220}
221
223{
224 std::lock_guard<std::mutex> guard(m_mutex);
225 m_min_distance = min;
226 m_max_distance = max;
227 return ReturnValue_ok;
228}
229
231{
232 std::lock_guard<std::mutex> guard(m_mutex);
233 m_min_angle = min;
234 m_max_angle = max;
235 return ReturnValue_ok;
236}
237
239{
240 std::lock_guard<std::mutex> guard(m_mutex);
242 return ReturnValue_ok;
243}
244
246{
247 std::lock_guard<std::mutex> guard(m_mutex);
248 yCWarning(RP_LIDAR3, "setScanRate not yet implemented");
249 return ReturnValue::return_code::return_value_error_not_implemented_by_device;
250}
251
253{
254 return true;
255}
256
257//#define DEBUG_LOCKING 1
258#ifndef _countof
259#define _countof(_Array) (int)(sizeof(_Array) / sizeof (_Array[0]))
260#endif
261
263{
264 bool b = updateLidarData();
265 if (b)
266 {
267 m_mutex.unlock();
268 }
269 else
270 {
271 yCWarning(RP_LIDAR3, "updateLidarData() failed.");
272 }
273 return;
274}
275
277{
279 size_t count = m_nodes_num;
280 static int life = 0;
281 op_result = m_drv->grabScanDataHq(m_nodes, count);
282 if (op_result != RESULT_OK)
283 {
284 yCError(RP_LIDAR3) << m_serialPort << ": grabbing scan data failed";
285 handleError(op_result);
286 return false;
287 }
288
289 m_drv->ascendScanData(m_nodes, count);
290
291 if (op_result != RESULT_OK)
292 {
293 yCError(RP_LIDAR3) << "ascending scan data failed\n";
294 handleError(op_result);
295 return false;
296 }
297
298 if (m_buffer_life && life % m_buffer_life == 0)
299 {
300 for (size_t i = 0; i < m_laser_data.size(); i++)
301 {
302 //m_laser_data[i]=0; //0 is a terribly unsafe value and should be avoided.
303 m_laser_data[i] = std::numeric_limits<double>::infinity();
304 }
305 }
306
307 //this lock protects m_laser_data. It is released at the end of the run(),
308 //after that the following methods are called: applyLimitsOnLaserData(), updateTimestamp()
309 m_mutex.lock();
310
311 for (size_t i = 0; i < count; ++i)
312 {
313
314 double distance = (m_nodes[i].dist_mm_q2 / 1000.f / (1 << 2)); //m
315 double angle = (m_nodes[i].angle_z_q14 * 90.f / (1 << 14)); //deg
316 double quality = (m_nodes[i].quality >> RPLIDAR_RESP_MEASUREMENT_QUALITY_SHIFT); //to be verified
317 angle = (360 - angle);
318
319 if (angle >= 360)
320 {
321 angle -= 360;
322 }
323
324 //checkme, is it useful?
325 if (angle > 360)
326 {
327 yCWarning(RP_LIDAR3) << "Invalid angle";
328 }
329
330 if (quality == 0 || distance == 0)
331 {
332 distance = std::numeric_limits<double>::infinity();
333 }
334
335 int elem = (int)(angle / m_resolution);
336 if (elem >= 0 && elem < (int)m_laser_data.size())
337 {
339 }
340 else
341 {
342 yCDebug(RP_LIDAR3) << "RpLidar::run() invalid angle: elem" << elem << ">" << "laser_data.size()" << m_laser_data.size();
343 }
344 }
345
346 life++;
347 return true;
348}
349
351{
352#ifdef LASER_DEBUG
353 yCDebug(RP_LIDAR3,"RpLidar Thread releasing...");
354 yCDebug(RP_LIDAR3,"... done.");
355#endif
356
357 return;
358}
359
360void RpLidar3::handleError(u_result error)
361{
362 switch (error)
363 {
364 case RESULT_FAIL_BIT:
365 yCError(RP_LIDAR3) << "error: 'FAIL BIT'";
366 break;
368 yCError(RP_LIDAR3) << "error: 'ALREADY DONE'";
369 break;
371 yCError(RP_LIDAR3) << "error: 'INVALID DATA'";
372 break;
374 yCError(RP_LIDAR3) << "error: 'OPERATION FAIL'";
375 break;
377 yCError(RP_LIDAR3) << "error: 'OPERATION TIMEOUT'";
378 break;
380 yCError(RP_LIDAR3) << "error: 'OPERATION STOP'";
381 break;
383 yCError(RP_LIDAR3) << "error: 'OPERATION NOT SUPPORT'";
384 break;
386 yCError(RP_LIDAR3) << "error: 'FORMAT NOT SUPPORT'";
387 break;
389 yCError(RP_LIDAR3) << "error: 'INSUFFICENT MEMORY'";
390 break;
391 }
392}
393
394bool RpLidar3::deviceinfo()
395{
396 if (m_drv)
397 {
398 u_result result;
400 std::string serialNumber;
401
402 result = m_drv->getDeviceInfo(info);
403 if (result != RESULT_OK)
404 {
405 handleError(result);
406 yCError(RP_LIDAR3) << "Unable to getDeviceInfo";
407 return false;
408 }
409
410 for (unsigned char i : info.serialnum)
411 {
412 serialNumber += std::to_string(i);
413 }
414
415 m_info = std::string("Firmware Version: ") + std::to_string(info.firmware_version) +
416 "\nHardware Version: " + std::to_string(info.hardware_version) +
417 "\nModel: " + std::to_string(info.model) +
418 "\nSerial Number:" + serialNumber;
419 return true;
420 }
421 yCError(RP_LIDAR3) << "sdk driver not initialized?!";
422 return false;
423}
#define yInfo(...)
Definition Log.h:319
#define ReturnValue_ok
Definition ReturnValue.h:77
rpLidar3: The device driver for the RP2 lidar
Definition rpLidar3.h:50
const size_t m_nodes_num
Definition rpLidar3.h:63
rplidar_response_measurement_node_hq_t * m_nodes
Definition rpLidar3.h:64
std::string m_serialPort
Definition rpLidar3.h:61
bool acquireDataFromHW() override final
This method should be implemented by the user, and contain the logic to grab data from the hardware.
Definition rpLidar3.cpp:276
void run() override
Loop function.
Definition rpLidar3.cpp:262
bool m_force_scan
Definition rpLidar3.h:58
int m_pwm_val
Definition rpLidar3.h:60
yarp::dev::ReturnValue setScanLimits(double min, double max) override
set the scan angular range.
Definition rpLidar3.cpp:230
std::string m_scan_mode
Definition rpLidar3.h:59
void threadRelease() override
Release method.
Definition rpLidar3.cpp:350
bool m_inExpressMode
Definition rpLidar3.h:57
yarp::dev::ReturnValue setScanRate(double rate) override
set the scan rate (scans per seconds)
Definition rpLidar3.cpp:245
bool threadInit() override
Initialization method.
Definition rpLidar3.cpp:252
yarp::dev::ReturnValue setDistanceRange(double min, double max) override
set the device detection range.
Definition rpLidar3.cpp:222
bool close() override
Close the DeviceDriver.
Definition rpLidar3.cpp:210
int m_buffer_life
Definition rpLidar3.h:56
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
Definition rpLidar3.cpp:122
yarp::dev::ReturnValue setHorizontalResolution(double step) override
get the angular step between two measurements (if available)
Definition rpLidar3.cpp:238
rplidardrv * m_drv
Definition rpLidar3.h:62
virtual bool updateLidarData()
This utility method calls in sequence: grabDataFromHW(), updateTimestamp and applyLimitsOnLaserData()...
yarp::dev::IRangefinder2D::Device_status m_device_status
bool parseConfiguration(yarp::os::Searchable &config)
A mini-server for performing network communication in the background.
bool setPeriod(double period)
Set the (new) period of the thread.
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
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
virtual Bottle & findGroup(const std::string &key) const =0
Gets a list corresponding to a given keyword.
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
const yarp::os::LogComponent & RP_LIDAR3()
Definition rpLidar3.cpp:34