YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
laserHokuyo.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#define _USE_MATH_DEFINES
7
8#include "laserHokuyo.h"
9
10#include <yarp/os/Time.h>
11#include <yarp/os/Log.h>
12#include <yarp/os/LogStream.h>
13
14#include <cmath>
15#include <cstdlib>
16#include <cstring>
17#include <iostream>
18#include <limits>
19
20#ifndef DEG2RAD
21#define DEG2RAD M_PI/180.0
22#endif
23
24using namespace yarp::sig;
25
26namespace {
27YARP_LOG_COMPONENT(LASERHOKUYO, "yarp.devices.laserHokuyo")
28}
29
31{
33 info = "Hokuyo Laser";
35
36 yCTrace(LASERHOKUYO, "%s", config.toString().c_str());
37
38 bool br = config.check("GENERAL");
39 if (br == false)
40 {
41 yCError(LASERHOKUYO, "cannot read 'GENERAL' section");
42 return false;
43 }
45
46 //list of mandatory options
47 //TODO change comments
48 period = general_config.check("Period", Value(50), "Period of the sampling thread").asInt32() / 1000.0;
49
50 if (general_config.check("max_angle") == false) { yCError(LASERHOKUYO) << "Missing max_angle param"; return false; }
51 if (general_config.check("min_angle") == false) { yCError(LASERHOKUYO) << "Missing min_angle param"; return false; }
52 max_angle = general_config.find("max_angle").asFloat64();
53 min_angle = general_config.find("min_angle").asFloat64();
54
55 start_position = general_config.check("Start_Position", Value(0), "Start position").asInt32();
56 end_position = general_config.check("End_Position", Value(1080), "End Position").asInt32();
57
58 error_codes = general_config.check("Convert_Error_Codes", Value(0), "Substitute error codes with legal measurments").asInt32();
59 std::string s = general_config.check("Laser_Mode", Value("GD"), "Laser Mode (GD/MD").asString();
60
61 if (general_config.check("Measurement_Units"))
62 {
63 yCError(LASERHOKUYO) << "Deprecated parameter 'Measurement_Units'. Please Remove it from the configuration file.";
64 }
65
66 if (error_codes==1)
67 {
68 yCInfo(LASERHOKUYO, "'error_codes' option enabled. Invalid samples will be substituted with out-of-range measurements.");
69 }
70 if (s=="GD")
71 {
73 yCInfo(LASERHOKUYO, "Using GD mode (single acquisition)");
74 }
75 else if (s=="MD")
76 {
78 yCInfo(LASERHOKUYO, "Using MD mode (continuous acquisition)");
79 }
80 else
81 {
83 yCError(LASERHOKUYO, "Laser_mode not found. Using GD mode (single acquisition)");
84 }
86
87 bool br2 = config.check("SERIAL_PORT_CONFIGURATION");
88 if (br2 == false)
89 {
90 yCError(LASERHOKUYO, "cannot read 'SERIAL_PORT_CONFIGURATION' section");
91 return false;
92 }
93 yarp::os::Searchable& serial_config = config.findGroup("SERIAL_PORT_CONFIGURATION");
94 std::string ss = serial_config.toString();
95 Property prop;
96 prop.fromString(ss);
97 prop.put("device", "serialport");
98
99 driver.open(prop);
100 if (!driver.isValid())
101 {
102 yCError(LASERHOKUYO, "Error opening PolyDriver check parameters");
103 return false;
104 }
105
106 pSerial=nullptr;
108
109 if (!pSerial)
110 {
111 yCError(LASERHOKUYO, "Error opening serial driver. Device not available");
112 return false;
113 }
114
115 Bottle b;
117 std::string ans;
118
119 // *** Check if the URG device is present ***
120 b.addString("SCIP2.0\n");
121 pSerial->send(b);
124 if (b_ans.size()>0)
125 {
126 yCInfo(LASERHOKUYO, "URG device successfully initialized.");
127 yCDebug(LASERHOKUYO, "%s", b_ans.get(0).asString().c_str());
128 }
129 else
130 {
131 yCError(LASERHOKUYO, "Error: URG device not found.");
132 //return false;
133 }
134 b.clear();
135 b_ans.clear();
136
137 // *** Change the baud rate to 115200 ***
138 /*b.addString("SS01152001\n");
139 pSerial->send(b);
140 yarp::os::SystemClock::delaySystem(0.040);
141 pSerial->receive(b_ans);
142 ans = b_ans.get(0).asString();
143 yCDebug(LASERHOKUYO, "%s",ans.c_str());
144 b.clear();
145 b_ans.clear();*/
146
147 // *** Read the firmware version parameters ***
148 b.addString("VV\n");
149 pSerial->send(b);
152 ans = b_ans.get(0).asString();
153 yCDebug(LASERHOKUYO, "%s",ans.c_str());
154 b.clear();
155 b_ans.clear();
156
157 // *** Read the sensor specifications ***
158 b.addString("II\n");
159 pSerial->send(b);
162 ans = b_ans.get(0).asString();
163 yCDebug(LASERHOKUYO, "%s", ans.c_str());
164 b.clear();
165 b_ans.clear();
166
167 // *** Read the URG configuration parameters ***
168 b.addString("PP\n");
169 pSerial->send(b);
172 /*
173 syntax of the answer:
174 MODL ... Model information of the sensor.
175 DMIN ... Minimum measurable distance [mm]
176 DMAX ... Maximum measurable distance [mm]
177 ARES ... Angular resolution(Number of splits in 360 degree)
178 AMIN ... First Step of the Measurement Range
179 AMAX ... Last Step of the Measurement Range
180 AFRT ... Step number on the sensor's front axis
181 SCAN ... Standard angular velocity
182 */
183 ans = b_ans.get(0).asString();
184 yCDebug(LASERHOKUYO, "%s", ans.c_str());
185 //parsing the answer
186 size_t found;
187 found = ans.find("MODL");
188 if (found != std::string::npos) {
189 sensor_properties.MODL = std::string(ans.c_str() + found + 5);
190 }
191 found = ans.find("DMIN");
192 if (found != std::string::npos) {
193 sensor_properties.DMIN = atoi(ans.c_str() + found + 5);
194 }
195 found = ans.find("DMAX");
196 if (found != std::string::npos) {
197 sensor_properties.DMAX = atoi(ans.c_str() + found + 5);
198 }
199 found = ans.find("ARES");
200 if (found != std::string::npos) {
201 sensor_properties.ARES = atoi(ans.c_str() + found + 5);
202 }
203 found = ans.find("AMIN");
204 if (found != std::string::npos) {
205 sensor_properties.AMIN = atoi(ans.c_str() + found + 5);
206 }
207 found = ans.find("AMAX");
208 if (found != std::string::npos) {
209 sensor_properties.AMAX = atoi(ans.c_str() + found + 5);
210 }
211 found = ans.find("AFRT");
212 if (found != std::string::npos) {
213 sensor_properties.AFRT = atoi(ans.c_str() + found + 5);
214 }
215 found = ans.find("SCAN");
216 if (found != std::string::npos) {
217 sensor_properties.SCAN = atoi(ans.c_str() + found + 5);
218 }
219 b.clear();
220 b_ans.clear();
221
222 // *** Turns on the Laser ***
223 b.addString("BM\n");
224 pSerial->send(b);
227 // @@@TODO: Check the answer
228 b.clear();
229 b_ans.clear();
230
231
232
233 //elements are:
234 sensorsNum=16*12;
236
237 if (laser_mode==MD_MODE)
238 {
239 // *** Starts endless acquisition mode***
240 char message [255];
241 std::snprintf(message, 255, "MD%04d%04d%02d%01d%02d\n",start_position,end_position,1,1,0);
242 b.addString(message);
243 pSerial->send(b);
244 b.clear();
245 b_ans.clear();
246 }
247
248 else if (laser_mode==GD_MODE)
249 {
250 // *** Starts one single acquisition ***
251 char message [255];
252 std::snprintf(message, 255, "GD%04d%04d%02d\n",start_position,end_position,1);
253 b.addString(message);
254 pSerial->send(b);
255 b.clear();
256 b_ans.clear();
257 }
258
259 return PeriodicThread::start();
260}
261
263{
265
266 Bottle b;
268
269 // *** Turns off the Laser ***
270 b.addString("QT\n");
271 pSerial->send(b);
273
274 // @@@TODO: Check the answer
275
276 b.clear();
277 b_ans.clear();
278
279 driver.close();
280 return true;
281}
282
284{
285 //should return range 0.1-30m (or 100, 30000mm depending on the measurement units)
286 min = 0.1;
287 max = 30;
288 return ReturnValue_ok;
289}
290
292{
293 yCError(LASERHOKUYO, "setDistanceRange NOT YET IMPLEMENTED");
294 return ReturnValue::return_code::return_value_error_not_implemented_by_device;
295}
296
298{
299 //degrees
300 min = min_angle;
301 max = max_angle;
302 return ReturnValue_ok;
303}
304
306{
307 yCError(LASERHOKUYO, "setScanLimits NOT YET IMPLEMENTED");
308 return ReturnValue::return_code::return_value_error_not_implemented_by_device;
309}
310
312{
313 step = 0.25; //deg //1080*0.25=270
314 return ReturnValue_ok;
315}
316
318{
319 yCError(LASERHOKUYO, "setHorizontalResolution NOT YET IMPLEMENTED");
320 return ReturnValue::return_code::return_value_error_not_implemented_by_device;
321}
322
324{
325 rate = 20; //20 Hz = 50 ms
326 return ReturnValue_ok;
327}
328
330{
331 yCError(LASERHOKUYO, "setScanRate NOT YET IMPLEMENTED");
332 return ReturnValue::return_code::return_value_error_not_implemented_by_device;
333}
334
336{
338 {
339 mutex.lock();
340 yCTrace(LASERHOKUYO, "data: %s", laser_data.toString().c_str());
341 out = laser_data;
342 mutex.unlock();
344 return ReturnValue_ok;
345 }
347 return ReturnValue::return_code::return_value_error_not_ready;
348}
349
350ReturnValue laserHokuyo::getLaserMeasurement(std::vector<LaserMeasurementData> &data, double* timestamp)
351{
353 {
354 mutex.lock();
355 yCTrace(LASERHOKUYO, "data: %s", laser_data.toString().c_str());
356 size_t size = laser_data.size();
357 data.resize(size);
358 if (max_angle < min_angle)
359 {
360 yCError(LASERHOKUYO) << "getLaserMeasurement failed";
361 mutex.unlock();
362 return ReturnValue::return_code::return_value_error_method_failed;
363 }
364
366 for (size_t i = 0; i < size; i++)
367 {
368 double angle = (i / double(size)*laser_angle_of_view + min_angle)* DEG2RAD;
369 data[i].set_polar(laser_data[i], angle);
370 }
371 mutex.unlock();
373 return ReturnValue_ok;
374 }
375
377 return ReturnValue::return_code::return_value_error_not_ready;
378}
380{
381 mutex.lock();
382 status = device_status;
383 mutex.unlock();
384 return ReturnValue_ok;
385}
386
388{
389 yCTrace(LASERHOKUYO, "laserHokuyo:: thread initialising...");
390 yCTrace(LASERHOKUYO, "... done!");
391 return true;
392}
393
394inline int laserHokuyo::calculateCheckSum(const char* buffer, int size, char actual_sum)
395{
396 char expected_sum = 0x00;
397 int i;
398
399 for (i = 0; i < size; ++i)
400 {
401 expected_sum += buffer[i];
402 }
403 expected_sum = (expected_sum & 0x3f) + 0x30;
404
405 return (expected_sum == actual_sum) ? 0 : -1;
406}
407
408inline long laserHokuyo::decodeDataValue(const char* data, int data_byte)
409{
410 long value = 0;
411 for (int i = 0; i < data_byte; ++i)
412 {
413 value <<= 6;
414 value &= ~0x3f;
415 value |= data[i] - 0x30;
416 }
417 return value;
418}
419
420int laserHokuyo::readData(const Laser_mode_type laser_mode, const char* text_data, const int text_data_len, int current_line, yarp::sig::Vector& data)
421{
422 static char data_block [4000];
423
424 if (text_data_len==0)
425 {
427 }
428
429// long int timestamp = 0 ;
430
431 // termination complete check
432 if (text_data_len == 1 &&
433 text_data[0] == '\n')
434 {
435 //Decode the data
436 int len = strlen(data_block);
437 for (int value_counter =0; value_counter < len; value_counter+=3)
438 {
439 int value = decodeDataValue(data_block+value_counter, 3);
440 if (value<sensor_properties.DMIN && error_codes==1)
441 {
442 value=sensor_properties.DMAX;
443 }
444 //units are m
445 data.push_back(value/1000.0);
446 }
448 }
449
450 // check in the first line if it is a valid answer to GD command
451 if (current_line == 0)
452 {
453 data_block[0]='\0'; //resets the datablock;
454 if ((laser_mode == MD_MODE && (text_data[0] != 'M' || text_data[1] != 'D')) ||
455 (laser_mode == GD_MODE && (text_data[0] != 'G' || text_data[1] != 'D')))
456 {
457 yCTrace(LASERHOKUYO, "Invalid answer to a MD command: %s", text_data);
459 } else {
460 return HOKUYO_STATUS_OK;
461 }
462 }
463
464 // check in the second line if the status of the sensor is ok
465 if (current_line == 1)
466 {
467 if ((laser_mode == MD_MODE && (text_data[0] != '9' || text_data[1] != '9' || text_data[2] != 'b' )) ||
468 (laser_mode == GD_MODE && (text_data[0] != '0' || text_data[1] != '0' || text_data[2] != 'P' )))
469 {
470 yCTrace(LASERHOKUYO, "Invalid sensor status: %s", text_data);
472 } else {
473 return HOKUYO_STATUS_OK;
474 }
475 }
476
477 // verify the checksum for all the following lines
478 if (current_line >= 2)
479 {
481 if (calculateCheckSum(text_data, text_data_len - 2, expected_checksum) < 0)
482 {
483 yCTrace(LASERHOKUYO, "Checksum error, line: %d: %s", current_line, text_data);
485 }
486 }
487
488 // read the sensor time stamp in the third line
489 if (current_line == 2)
490 {
491// timestamp = decodeDataValue(text_data, 4);
492 }
493
494 // read the data in the next lines
495 if (current_line >= 3)
496 {
498 }
499
500 //increments the lines counter
501 //current_line++;
502
503 return HOKUYO_STATUS_OK;
504}
505
507{
508 //send the GD command: get one single measurement, D precision
509 Bottle b;
511 constexpr int buffer_size = 128;
512 char command [buffer_size];
513 char answer [buffer_size];
514 static double old;
516
517 std::string data_text;
519 double t2 = 0;
520 bool timeout = false;
521 bool rx_completed = false;
522 bool error = false;
523 int current_line =0;
524 double maxtime=1;
525 do
526 {
527 int answer_len = pSerial->receiveLine(answer, buffer_size);
530 {
531 error = true;
532 }
534 {
535 current_line++;
536 }
538 {
539 rx_completed = true;
540 }
542 if (t2 - t1 > maxtime) {
543 timeout = true;
544 }
545 }
546 while (rx_completed == false && timeout == false && error == false);
547
548 if (timeout)
549 {
550 yCError(LASERHOKUYO, "laserHokuyo Timeout!");
551 }
552 if (error)
553 {
554 yCError(LASERHOKUYO, "laserHokuyo Communication Error, internal status=%d",internal_status);
555 }
556 yCTrace(LASERHOKUYO, "time: %.3f %.3f",t2-t1, t2-old);
557 old = t2;
558
559 mutex.lock();
560
561 if (rx_completed)
562 {
564 }
565 mutex.unlock();
566
567 if (laser_mode==GD_MODE)
568 {
569 std::snprintf(command, buffer_size, "GD%04d%04d%02d\n",start_position,end_position,1);
570 b.addString(command);
571 pSerial->send(b);
572 }
573
574 //SystemClock::delaySystem (0.100);
575}
576
578{
579 yCTrace(LASERHOKUYO, "laserHokuyo Thread releasing...");
580 yCTrace(LASERHOKUYO, "... done.");
581}
582
584{
585 this->mutex.lock();
586 device_info = info;
587 this->mutex.unlock();
588 return ReturnValue_ok;
589}
#define DEG2RAD
#define ReturnValue_ok
Definition ReturnValue.h:77
Device_status device_status
Definition laserHokuyo.h:46
yarp::dev::ReturnValue getDeviceStatus(Device_status &status) override
get the device status
yarp::dev::ReturnValue getLaserMeasurement(std::vector< yarp::sig::LaserMeasurementData > &data, double *timestamp) override
Get the device measurements.
std::string info
Definition laserHokuyo.h:45
PolyDriver driver
Definition laserHokuyo.h:31
double period
Definition laserHokuyo.h:37
int internal_status
Definition laserHokuyo.h:44
yarp::dev::ReturnValue setScanRate(double rate) override
set the scan rate (scans per seconds)
@ HOKUYO_STATUS_ERROR_INVALID_CHECKSUM
Definition laserHokuyo.h:55
@ HOKUYO_STATUS_NOT_READY
Definition laserHokuyo.h:57
@ HOKUYO_STATUS_ERROR_BUSY
Definition laserHokuyo.h:53
@ HOKUYO_STATUS_ERROR_INVALID_COMMAND
Definition laserHokuyo.h:54
@ HOKUYO_STATUS_ERROR_NOTHING_RECEIVED
Definition laserHokuyo.h:56
@ HOKUYO_STATUS_ACQUISITION_COMPLETE
Definition laserHokuyo.h:51
yarp::dev::ReturnValue setHorizontalResolution(double step) override
get the angular step between two measurements (if available)
ISerialDevice * pSerial
Definition laserHokuyo.h:32
yarp::dev::ReturnValue setScanLimits(double min, double max) override
set the scan angular range.
void run() override
Loop function.
std::mutex mutex
Definition laserHokuyo.h:34
yarp::dev::ReturnValue getRawData(yarp::sig::Vector &data, double *timestamp) override
Get the device measurements.
yarp::dev::ReturnValue getScanRate(double &rate) override
get the scan rate (scans per seconds)
yarp::dev::ReturnValue getScanLimits(double &min, double &max) override
get the scan angular range.
void threadRelease() override
Release method.
int start_position
Definition laserHokuyo.h:39
yarp::sig::Vector laser_data
Definition laserHokuyo.h:74
double min_angle
Definition laserHokuyo.h:41
struct laserHokuyo::sensor_property_struct sensor_properties
bool threadInit() override
Initialization method.
bool close() override
Close the DeviceDriver.
yarp::dev::ReturnValue getDistanceRange(double &min, double &max) override
get the device detection range
yarp::dev::ReturnValue setDistanceRange(double min, double max) override
set the device detection range.
double max_angle
Definition laserHokuyo.h:42
yarp::dev::ReturnValue getHorizontalResolution(double &step) override
get the angular step between two measurements.
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
Laser_mode_type laser_mode
Definition laserHokuyo.h:60
yarp::dev::ReturnValue getDeviceInfo(std::string &device_info) override
get the device hardware characteristics
bool view(T *&x)
Get an interface to the device driver.
virtual int receiveLine(char *line, const int MaxLineLength)=0
Gets one line (a sequence of chars with a ending '\n' or '\r') from the receive queue.
virtual bool send(const yarp::os::Bottle &msg)=0
Sends a string of chars to the serial communications channel.
virtual bool receive(yarp::os::Bottle &msg)=0
Gets the existing chars in the receive queue.
bool close() override
Close the DeviceDriver.
bool isValid() const
Check if device is valid.
bool open(const std::string &txt)
Construct and configure a device by its common name.
A simple collection of objects that can be described and transmitted in a portable way.
Definition Bottle.h:64
void clear()
Empties the bottle of any objects it contains.
Definition Bottle.cpp:121
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition Bottle.cpp:170
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 class for storing options and configuration information.
Definition Property.h:33
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition Property.cpp:987
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 std::string toString() const =0
Return a standard text representation of the content of the object.
virtual Bottle & findGroup(const std::string &key) const =0
Gets a list corresponding to a given keyword.
static double nowSystem()
static void delaySystem(double seconds)
A single value (typically within a Bottle).
Definition Value.h:43
std::string toString(int precision=-1, int width=-1) const
Creates a string object containing a text representation of the object.
Definition Vector.h:377
void resize(size_t size) override
Resize the vector.
Definition Vector.h:221
size_t size() const
Definition Vector.h:341
void push_back(const T &elem)
Push a new element in the vector: size is changed.
Definition Vector.h:268
#define yCInfo(component,...)
#define yCError(component,...)
#define yCTrace(component,...)
#define yCDebug(component,...)
#define YARP_LOG_COMPONENT(name,...)