YARP
Yet Another Robot Platform
laserFromExternalPort.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 #define _USE_MATH_DEFINES
20 
21 #include "laserFromExternalPort.h"
22 
23 #include <yarp/os/Time.h>
24 #include <yarp/os/Log.h>
25 #include <yarp/os/LogStream.h>
26 #include <yarp/os/ResourceFinder.h>
27 #include <yarp/math/Math.h>
28 
29 #include <cmath>
30 #include <cstring>
31 #include <cstdlib>
32 #include <iostream>
33 #include <limits>
34 #include <mutex>
35 
36 using namespace std;
37 using namespace yarp::os;
38 using namespace yarp::dev;
39 
40 #ifndef DEG2RAD
41 #define DEG2RAD M_PI/180.0
42 #endif
43 
44 #ifndef RAD2DEG
45 #define RAD2DEG 180/M_PI
46 #endif
47 
48 YARP_LOG_COMPONENT(LASER_FROM_EXTERNAL_PORT, "yarp.devices.laserFromExternalPort")
49 
50 /*
51 yarpdev --device Rangefinder2DWrapper --subdevice laserFromExternalPort \
52 --SENSOR::input_ports_name "(/port1 /port2)" \
53 --TRANSFORM_CLIENT::local /LaserFromExternalPort/tfClient \
54 --TRANSFORM_CLIENT::remote /transformServer \
55 --TRANSFORMS::src_frames "(/frame1 /frame2)" \
56 --TRANSFORMS::dst_frame /output_frame
57 --period 10 \
58 --name /outlaser:o
59 
60 yarpdev --device Rangefinder2DWrapper --subdevice laserFromExternalPort \
61 --SENSOR::min_angle 0
62 --SENSOR::max_angle 360
63 --SENSOR::resolution 0.5
64 --SENSOR::input_ports_name "(/port1 /port2)" \
65 --TRANSFORM_CLIENT::local /LaserFromExternalPort/tfClient \
66 --TRANSFORM_CLIENT::remote /transformServer \
67 --TRANSFORMS::src_frames "(/frame1 /frame2)" \
68 --TRANSFORMS::dst_frame /output_frame
69 --period 10 \
70 --name /outlaser:o
71 */
72 
73 double constrainAngle(double x)
74 {
75  x = fmod(x, 360);
76  if (x < 0)
77  x += 360;
78  return x;
79 }
80 
82 {
83  m_contains_data=false;
84 }
85 
87 {
88  m_port_mutex.lock();
89  m_lastScan = b;
90  getEnvelope(m_lastStamp);
91  m_contains_data=true;
92  m_port_mutex.unlock();
93 }
94 
96 {
97  //this blocks untils the first data is received;
98  size_t counter =0;
99  while (m_contains_data==false)
100  {
102  if (counter++ > 100) {yCDebug(LASER_FROM_EXTERNAL_PORT) << "Waiting for incoming data..."; counter=0;}
103  }
104 
105  m_port_mutex.lock();
106  data = m_lastScan;
107  stmp = m_lastStamp;
108  m_port_mutex.unlock();
109 }
110 
111 //-------------------------------------------------------------------------------------
112 
114 {
115  Property subConfig;
116  m_info = "LaserFromExternalPort device";
117 
118 #ifdef LASER_DEBUG
119  yCDebug(LASER_FROM_EXTERNAL_PORT) << "%s\n", config.toString().c_str());
120 #endif
121 
122  if (this->parseConfiguration(config) == false)
123  {
124  yCError(LASER_FROM_EXTERNAL_PORT) << "Error parsing parameters";
125  return false;
126  }
127 
128  yarp::os::Searchable& general_config = config.findGroup("SENSOR");
129 
130  if (general_config.check("input_ports_name")) //this parameter is optional
131  {
132  yarp::os::Bottle* portlist = general_config.find("input_ports_name").asList();
133  if (portlist)
134  {
135  for (size_t i = 0; i < portlist->size(); i++)
136  m_port_names.push_back(portlist->get(i).asString());
137  }
138  else
139  {
140  m_port_names.push_back("/laserFromExternalPort:i");
141  }
142 
143  for (size_t i = 0; i < m_port_names.size(); i++)
144  {
145  InputPortProcessor proc;
146  m_input_ports.push_back(proc);
147  }
148  m_last_stamp.resize(m_port_names.size());
149  m_last_scan_data.resize(m_port_names.size());
150  }
151 
152  if (general_config.check("base_type")) //this parameter is optional
153  {
154  string bt = general_config.find("base_type").asString();
155  if (bt=="infinity") { m_base_type = base_enum::BASE_IS_INF; }
156  else if (bt=="nan") { m_base_type = base_enum::BASE_IS_NAN; }
157  else if (bt=="zero") {m_base_type = base_enum::BASE_IS_ZERO;}
158  else { yCError(LASER_FROM_EXTERNAL_PORT) << "Invalid value of param base_type"; return false;
159  }
160  }
161 
162  //set the base value
163  m_empty_laser_data = m_laser_data;
164  if (m_base_type == base_enum::BASE_IS_INF)
165  {
166  for (size_t i = 0; i < m_empty_laser_data.size(); i++) m_empty_laser_data[i] = std::numeric_limits<double>::infinity();
167  }
168  else if (m_base_type == base_enum::BASE_IS_NAN)
169  {
170  for (size_t i = 0; i < m_empty_laser_data.size(); i++) m_empty_laser_data[i] = std::nanf("");
171  }
172  else if (m_base_type == base_enum::BASE_IS_ZERO)
173  {
174  for (size_t i = 0; i < m_empty_laser_data.size(); i++) m_empty_laser_data[i] = 0;
175  }
176  else
177  {
178  yCError(LASER_FROM_EXTERNAL_PORT) << "Invalid m_base_type";
179  return false;
180  }
181 
182  if (general_config.check("override")) //this parameter is optional
183  {
184  if (m_input_ports.size() != 1)
185  {
186  yCError(LASER_FROM_EXTERNAL_PORT) << "option override cannot be used when multiple ports are involved";
187  return false;
188  }
189  else
190  {
191  m_option_override_limits = true;
192  }
193  }
194 
195  //open the tc client
196  if (config.check("TRANSFORMS") && config.check("TRANSFORM_CLIENT"))
197  {
198  yarp::os::Searchable& transforms_config = config.findGroup("TRANSFORMS");
199  yarp::os::Bottle* src_frames_list = transforms_config.find("src_frames").asList();
200  if (src_frames_list)
201  {
202  if (src_frames_list->size() != m_input_ports.size())
203  {
204  yCError(LASER_FROM_EXTERNAL_PORT) << "src_frames invalid number";
205  return false;
206  }
207  for (size_t i = 0; i < src_frames_list->size(); i++)
208  {
209  m_src_frame_id.push_back(src_frames_list->get(i).asString());
210  }
211  }
212  else
213  {
214  yCError(LASER_FROM_EXTERNAL_PORT) << "src_frames invalid value or param not found";
215  return false;
216  }
217  m_dst_frame_id = transforms_config.find("dst_frame").asString();
218  if (m_dst_frame_id=="")
219  {
220  yCError(LASER_FROM_EXTERNAL_PORT) << "dst_frame param not found";
221  return false;
222  }
223 
224 
225  std::string client_cfg_string = config.findGroup("TRANSFORM_CLIENT").toString();
226  if (client_cfg_string=="")
227  {
228  yCError(LASER_FROM_EXTERNAL_PORT) << "TRANSFORM_CLIENT param not found";
229  return false;
230  }
231 
232  Property tcprop;
233  tcprop.fromString(client_cfg_string);
234  tcprop.put("device", "transformClient");
235 
236  m_tc_driver.open(tcprop);
237  if (!m_tc_driver.isValid())
238  {
239  yCError(LASER_FROM_EXTERNAL_PORT) << "Error opening PolyDriver check parameters";
240  return false;
241  }
242  m_tc_driver.view(m_iTc);
243  if (!m_iTc)
244  {
245  yCError(LASER_FROM_EXTERNAL_PORT) << "Error opening iFrameTransform interface. Device not available";
246  return false;
247  }
249  }
250 
251  for (size_t i=0; i<m_input_ports.size(); i++)
252  {
253  m_input_ports[i].useCallback();
254  if (m_input_ports[i].open(m_port_names[i]) == false)
255  {
256  yCError(LASER_FROM_EXTERNAL_PORT) << "Error opening port:" << m_port_names[i];
257  return false;
258  }
259  }
260  PeriodicThread::start();
261 
262  yCInfo(LASER_FROM_EXTERNAL_PORT, "LaserFromExternalPort: Sensor ready");
263  return true;
264 }
265 
267 {
268  PeriodicThread::stop();
269 
270  for (auto it=m_input_ports.begin(); it!= m_input_ports.end(); it++)
271  {
272  it->close();
273  }
274 
275  yCInfo(LASER_FROM_EXTERNAL_PORT) << "LaserFromExternalPort closed";
276  return true;
277 }
278 
279 
280 
281 bool LaserFromExternalPort::setDistanceRange(double min, double max)
282 {
283  std::lock_guard<std::mutex> guard(m_mutex);
284  m_min_distance = min;
285  m_max_distance = max;
286  return true;
287 }
288 
289 bool LaserFromExternalPort::setScanLimits(double min, double max)
290 {
291  std::lock_guard<std::mutex> guard(m_mutex);
292  yCWarning(LASER_FROM_EXTERNAL_PORT) << "setScanLimits not yet implemented";
293  return true;
294 }
295 
296 
297 
299 {
300  std::lock_guard<std::mutex> guard(m_mutex);
301  yCWarning(LASER_FROM_EXTERNAL_PORT, "setHorizontalResolution not yet implemented");
302  return true;
303 }
304 
306 {
307  std::lock_guard<std::mutex> guard(m_mutex);
308  yCWarning(LASER_FROM_EXTERNAL_PORT, "setScanRate not yet implemented");
309  return false;
310 }
311 
312 
313 
315 {
316 #ifdef LASER_DEBUG
317  yCDebug(LASER_FROM_EXTERNAL_PORT) <<"LaserFromExternalPort:: thread initialising...\n");
318  yCDebug(LASER_FROM_EXTERNAL_PORT) <<"... done!\n");
319 #endif
320 
321  return true;
322 }
323 
325 {
326  yarp::sig::Vector temp(3);
327  temp = yarp::math::dcm2rpy(m);
328  double t_off_rad = temp[2];
329  double x_off = m[0][3];
330  double y_off = m[1][3];
331 
332 #ifdef DO_NOTHING_DEBUG
333  double x_off = 0;
334  double y_off = 0;
335  double t_off_deg = 0;
336  double t_off_rad = 0;
337 #endif
338 
340  double resolution = (scan_data.angle_max - scan_data.angle_min)/ scan_data.scans.size(); // deg/elem
341  for (size_t i = 0; i < scan_data.scans.size(); i++)
342  {
343  double distance = scan_data.scans[i];
344  if (distance == std::numeric_limits<double>::infinity())
345  {
346  distance = 100;
347  }
348  if (std::isnan(distance))
349  {
350  //skip nan
351  }
352  else
353  {
354  //if we received a valid value, process it and put it in the right slot
355  double angle_input_deg = (i * resolution) + scan_data.angle_min;
356  double angle_input_rad = (angle_input_deg) * DEG2RAD;
357 
358  //calculate vertical and horizontal components of input angle
359  double Ay = (sin(angle_input_rad + t_off_rad) * distance);
360  double Ax = (cos(angle_input_rad + t_off_rad) * distance);
361 
362  //calculate vertical and horizontal components of new angle with offset.
363  double By = Ay + y_off;
364  double Bx = Ax + x_off;
365 
366  double angle_output_rad = atan2(By, Bx); //the output is (-pi +pi)
367  double angle_output_deg = angle_output_rad * RAD2DEG; //the output is (-180 +180)
368  angle_output_deg = constrainAngle(angle_output_deg); //the output is (0 360(
369 
370  //check if angle is inside the min max limits of the target vector, otherwise skip it
371  if (angle_output_deg > m_max_angle) { continue; }
372  if (angle_output_deg < m_min_angle) { continue; }
373 
374  //compute the new slot
375  int new_i = lrint ((angle_output_deg - m_min_angle) / m_resolution);
376  if (static_cast<size_t>(new_i) == m_laser_data.size()) {new_i=0;}
377 
378  yCAssert(LASER_FROM_EXTERNAL_PORT, new_i >= 0);
379  yCAssert(LASER_FROM_EXTERNAL_PORT, static_cast<size_t>(new_i) < m_laser_data.size());
380 
381  //compute the distance
382  double newdistance = std::sqrt((Bx * Bx) + (By * By));
383 
384  //assignment on empty (nan) slots or in valid slots if distance is shorter
385  if (std::isnan(m_laser_data[new_i]))
386  {
387  m_laser_data[new_i] = newdistance;
388  }
389  else if (newdistance < m_laser_data[new_i])
390  {
391  m_laser_data[new_i] = newdistance;
392  }
393  }
394  }
395 }
396 
398 {
399 #ifdef DEBUG_TIMING
400  double t1 = yarp::os::Time::now();
401 #endif
402  std::lock_guard<std::mutex> guard(m_mutex);
403  m_laser_data = m_empty_laser_data;
404 
405  size_t nports= m_input_ports.size();
406  if (nports == 1) //one single port, optimes version
407  {
408  m_input_ports[0].getLast(m_last_scan_data[0], m_last_stamp[0]);
409  size_t received_scans = m_last_scan_data[0].scans.size();
410 
411  if (m_option_override_limits)
412  {
413  //this overrides user setting with parameters received from the port
414  m_sensorsNum = received_scans;
415  m_max_angle = m_last_scan_data[0].angle_max;
416  m_min_angle = m_last_scan_data[0].angle_min;
417  m_max_distance = m_last_scan_data[0].range_max;
418  m_min_distance = m_last_scan_data[0].range_min;
419  m_resolution = received_scans / (m_max_angle - m_min_angle);
420  if (m_laser_data.size() != m_sensorsNum) m_laser_data.resize(m_sensorsNum);
421  }
422 
423  if (m_iTc==nullptr)
424  {
425  for (size_t elem = 0; elem < m_sensorsNum; elem++)
426  {
427  m_laser_data[elem] = m_last_scan_data[0].scans[elem]; //m
428  }
429  }
430  else
431  {
432  yarp::sig::Matrix m(4, 4); m.eye();
433  bool frame_exists = m_iTc->getTransform(m_src_frame_id[0], m_dst_frame_id, m);
434  if (frame_exists == false)
435  {
436  yCWarning(LASER_FROM_EXTERNAL_PORT) << "Unable to found m matrix" << "and" << m_dst_frame_id;
437  }
438  calculate(m_last_scan_data[0], m);
439  }
440  }
441  else //multiple ports
442  {
443  for (size_t i=0; i<nports;i++)
444  {
445  yarp::sig::Matrix m(4, 4); m.eye();
446  bool frame_exists = m_iTc->getTransform(m_src_frame_id[i], m_dst_frame_id, m);
447  if (frame_exists == false)
448  {
449  yCWarning(LASER_FROM_EXTERNAL_PORT) << "Unable to found m matrix between" << "and" << m_dst_frame_id;
450  }
451  m_input_ports[i].getLast(m_last_scan_data[i], m_last_stamp[i]);
452  calculate(m_last_scan_data[i], m);
453  }
454  }
455 
456  applyLimitsOnLaserData();
457 
458  return;
459 }
460 
462 {
463 #ifdef LASER_DEBUG
464  yCDebug(LASER_FROM_EXTERNAL_PORT) <<"Thread releasing...");
465  yCDebug(LASER_FROM_EXTERNAL_PORT) <<"... done.");
466 #endif
467 
468  return;
469 }
LogStream.h
yarp::os::Bottle
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:73
yarp::os::Bottle::toString
std::string toString() const override
Gives a human-readable textual representation of the bottle.
Definition: Bottle.cpp:214
yarp::os::Property::put
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition: Property.cpp:998
yarp::os::Searchable
A base class for nested structures that can be searched.
Definition: Searchable.h:69
yarp::os::Bottle::size
size_type size() const
Gets the number of elements in the bottle.
Definition: Bottle.cpp:254
yarp::dev::LaserScan2D::angle_max
double angle_max
last angle of the scan [deg]
Definition: LaserScan2D.h:38
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
LaserFromExternalPort::threadRelease
void threadRelease() override
Release method.
Definition: laserFromExternalPort.cpp:461
InputPortProcessor
Definition: AnalogSensorClient.h:30
yarp::math::dcm2rpy
yarp::sig::Vector dcm2rpy(const yarp::sig::Matrix &R)
Converts a dcm (direction cosine matrix) rotation matrix to roll-pitch-yaw angles (defined in Math....
Definition: math.cpp:780
yarp::os::Searchable::toString
virtual std::string toString() const =0
Return a standard text representation of the content of the object.
yarp::os::Property::fromString
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
Definition: Property.cpp:1046
YARP_LOG_COMPONENT
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:80
LaserFromExternalPort::run
void run() override
Loop function.
Definition: laserFromExternalPort.cpp:397
laserFromExternalPort.h
yarp::dev::LaserScan2D
Definition: LaserScan2D.h:28
InputPortProcessor::onRead
void onRead(yarp::sig::Vector &v) override
Definition: AnalogSensorClient.cpp:52
yarp::os::Time::now
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition: Time.cpp:124
yarp::dev
An interface for the device drivers.
Definition: audioBufferSizeData.cpp:17
InputPortProcessor::InputPortProcessor
InputPortProcessor()
Definition: AnalogSensorClient.cpp:46
yarp::sig::VectorOf< double >
Log.h
LaserFromExternalPort::setHorizontalResolution
bool setHorizontalResolution(double step) override
get the angular step between two measurments (if available)
Definition: laserFromExternalPort.cpp:298
LASER_FROM_EXTERNAL_PORT
const yarp::os::LogComponent & LASER_FROM_EXTERNAL_PORT()
Definition: laserFromExternalPort.cpp:48
LaserFromExternalPort::calculate
void calculate(yarp::dev::LaserScan2D scan, yarp::sig::Matrix m)
Definition: laserFromExternalPort.cpp:324
RAD2DEG
#define RAD2DEG
Definition: laserFromExternalPort.cpp:45
yarp::os::Bottle::get
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:249
InputPortProcessor::getLast
int getLast(yarp::sig::Vector &data, yarp::os::Stamp &stmp)
Definition: AnalogSensorClient.cpp:104
Math.h
BASE_IS_ZERO
@ BASE_IS_ZERO
Definition: laserFromExternalPort.h:46
yarp::sig::Matrix::eye
const Matrix & eye()
Build an identity matrix, don't resize.
Definition: Matrix.cpp:429
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.
BASE_IS_NAN
@ BASE_IS_NAN
Definition: laserFromExternalPort.h:44
yarp::os::Searchable::find
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
DEG2RAD
#define DEG2RAD
Definition: laserFromExternalPort.cpp:41
BASE_IS_INF
@ BASE_IS_INF
Definition: laserFromExternalPort.h:45
constrainAngle
double constrainAngle(double x)
Definition: laserFromExternalPort.cpp:73
LaserFromExternalPort::threadInit
bool threadInit() override
Initialization method.
Definition: laserFromExternalPort.cpp:314
LaserFromExternalPort::open
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
Definition: laserFromExternalPort.cpp:113
yCAssert
#define yCAssert(component, x)
Definition: LogComponent.h:172
yarp::os::Stamp
An abstraction for a time stamp and/or sequence number.
Definition: Stamp.h:25
yarp::dev::LaserScan2D::angle_min
double angle_min
first angle of the scan [deg]
Definition: LaserScan2D.h:34
yCError
#define yCError(component,...)
Definition: LogComponent.h:157
LaserFromExternalPort::close
bool close() override
Close the DeviceDriver.
Definition: laserFromExternalPort.cpp:266
yCInfo
#define yCInfo(component,...)
Definition: LogComponent.h:135
LaserFromExternalPort::setDistanceRange
bool setDistanceRange(double min, double max) override
set the device detection range.
Definition: laserFromExternalPort.cpp:281
yarp::os
An interface to the operating system, including Port based communication.
Definition: AbstractCarrier.h:17
yCDebug
#define yCDebug(component,...)
Definition: LogComponent.h:112
yarp::os::Value::asList
virtual Bottle * asList() const
Get list value.
Definition: Value.cpp:243
Time.h
yarp::sig::VectorOf::size
size_t size() const
Definition: Vector.h:355
yarp::dev::LaserScan2D::scans
yarp::sig::Vector scans
the scan data, measured in [m].
Definition: LaserScan2D.h:50
LaserFromExternalPort::setScanRate
bool setScanRate(double rate) override
set the scan rate (scans per seconds)
Definition: laserFromExternalPort.cpp:305
yarp::os::Time::delay
void delay(double seconds)
Wait for a certain number of seconds.
Definition: Time.cpp:114
ResourceFinder.h
yarp::os::Property
A class for storing options and configuration information.
Definition: Property.h:37
LaserFromExternalPort::setScanLimits
bool setScanLimits(double min, double max) override
set the scan angular range.
Definition: laserFromExternalPort.cpp:289
yarp::sig::Matrix
A class for a Matrix.
Definition: Matrix.h:46