YARP
Yet Another Robot Platform
fakeLaser.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * All rights reserved.
4  *
5  * This software may be modified and distributed under the terms of the
6  * BSD-3-Clause license. See the accompanying LICENSE file for details.
7  */
8 
9 #define _USE_MATH_DEFINES
10 
11 #include "fakeLaser.h"
12 
13 #include <yarp/os/Time.h>
14 #include <yarp/os/Log.h>
15 #include <yarp/os/LogStream.h>
16 #include <yarp/math/Vec2D.h>
17 #include <iostream>
18 #include <limits>
19 #include <cstring>
20 #include <cstdlib>
21 #include <cmath>
22 
23 //#define LASER_DEBUG
24 #ifndef DEG2RAD
25 #define DEG2RAD M_PI/180.0
26 #endif
27 
28 YARP_LOG_COMPONENT(FAKE_LASER, "yarp.devices.fakeLaser")
29 
30 using namespace std;
31 using namespace yarp::os;
32 using namespace yarp::dev;
33 using namespace yarp::dev::Nav2D;
34 
35 // see FakeLaser.h for device documentation
36 
37 bool FakeLaser::open(yarp::os::Searchable& config)
38 {
39  m_info = "Fake Laser device for test/debugging";
40  m_device_status = DEVICE_OK_STANBY;
41 
42 #ifdef LASER_DEBUG
43  yCDebug(FAKE_LASER) << "%s\n", config.toString().c_str());
44 #endif
45 
46  if (config.check("help"))
47  {
48  yCInfo(FAKE_LASER,"Some examples:");
49  yCInfo(FAKE_LASER,"yarpdev --device fakeLaser --help");
50  yCInfo(FAKE_LASER,"yarpdev --device Rangefinder2DWrapper --subdevice fakeLaser --period 10 --name /fakeLaser:o --test no_obstacles");
51  yCInfo(FAKE_LASER,"yarpdev --device Rangefinder2DWrapper --subdevice fakeLaser --period 10 --name /fakeLaser:o --test use_pattern");
52  yCInfo(FAKE_LASER,"yarpdev --device Rangefinder2DWrapper --subdevice fakeLaser --period 10 --name /fakeLaser:o --test use_constant --const_distance 0.5");
53  yCInfo(FAKE_LASER,"yarpdev --device Rangefinder2DWrapper --subdevice fakeLaser --period 10 --name /fakeLaser:o --test use_constant --const_distance 0.5 --SENSOR::resolution 0.5 --SKIP::min 0 50 --SKIP::max 10 60");
54  yCInfo(FAKE_LASER,"yarpdev --device Rangefinder2DWrapper --subdevice fakeLaser --period 10 --name /fakeLaser:o --test use_mapfile --map_file mymap.map");
55  yCInfo(FAKE_LASER,"yarpdev --device Rangefinder2DWrapper --subdevice fakeLaser --period 10 --name /fakeLaser:o --test use_mapfile --map_file mymap.map --localization_port /fakeLaser/location:i");
56  yCInfo(FAKE_LASER,"yarpdev --device Rangefinder2DWrapper --subdevice fakeLaser --period 10 --name /fakeLaser:o --test use_mapfile --map_file mymap.map --localization_server /localizationServer");
57  yCInfo(FAKE_LASER,"yarpdev --device Rangefinder2DWrapper --subdevice fakeLaser --period 10 --name /fakeLaser:o --test use_mapfile --map_file mymap.map --localization_client /fakeLaser/localizationClient --localization_server /localizationServer");
58  return false;
59  }
60 
61  bool br = config.check("GENERAL");
62  if (br != false)
63  {
64  yarp::os::Searchable& general_config = config.findGroup("GENERAL");
65  m_period = general_config.check("Period", Value(50), "Period of the sampling thread").asInt32() / 1000.0;
66  }
67 
68  string string_test_mode = config.check("test", Value(string("use_pattern")), "string to select test mode").asString();
69  if (string_test_mode == "no_obstacles") { m_test_mode = NO_OBSTACLES; }
70  else if (string_test_mode == "use_pattern") { m_test_mode = USE_PATTERN; }
71  else if (string_test_mode == "use_mapfile") { m_test_mode = USE_MAPFILE; }
72  else if (string_test_mode == "use_constant") { m_test_mode = USE_CONSTANT_VALUE; }
73  else { yCError(FAKE_LASER) << "invalid/unknown value for param 'test'"; return false; }
74 
75  //parse all the parameters related to the linear/angular range of the sensor
76  if (this->parseConfiguration(config) == false)
77  {
78  yCError(FAKE_LASER) << ": error parsing parameters";
79  return false;
80  }
81 
82  //the different fake laser modalities
83  else if (m_test_mode == USE_CONSTANT_VALUE)
84  {
85  if (config.check("const_distance"))
86  {
87  m_const_value = config.check("const_distance", Value(1.0), "default constant distance").asFloat64();
88  }
89  }
90  else if (m_test_mode == USE_MAPFILE)
91  {
92  string map_file;
93  if (config.check("map_file"))
94  {
95  map_file = config.check("map_file",Value(string("map.yaml")),"map filename").asString();
96  }
97  else
98  {
99  yCError(FAKE_LASER) << "Missing map_file";
100  return false;
101  }
102  bool ret = m_map.loadFromFile(map_file);
103  if (ret == false)
104  {
105  yCError(FAKE_LASER) << "A problem occurred while opening:" << map_file;
106  return false;
107  }
108 
109  if (config.check("localization_port"))
110  {
111  string localization_port_name = config.check("localization_port", Value(string("/fakeLaser/location:i")), "name of localization input port").asString();
113  m_loc_port->open(localization_port_name);
114  yCInfo(FAKE_LASER) << "Robot localization will be obtained from port" << localization_port_name;
115  m_loc_mode = LOC_FROM_PORT;
116  }
117  else if (config.check("localization_client") ||
118  config.check("localization_server" ))
119  {
120  Property loc_options;
121  string localization_client_name = config.check("localization_client", Value(string("/fakeLaser/localizationClient")), "local name of localization client device").asString();
122  string localization_server_name = config.check("localization_server", Value(string("/localizationServer")), "the name of the remote localization server device").asString();
123  loc_options.put("device", "localization2DClient");
124  loc_options.put("local", localization_client_name);
125  loc_options.put("remote", localization_server_name);
126  loc_options.put("period", 10);
127  m_pLoc = new PolyDriver;
128  if (m_pLoc->open(loc_options) == false)
129  {
130  yCError(FAKE_LASER) << "Unable to open localization driver";
131  return false;
132  }
133  m_pLoc->view(m_iLoc);
134  if (m_iLoc == nullptr)
135  {
136  yCError(FAKE_LASER) << "Unable to open localization interface";
137  return false;
138  }
139  yCInfo(FAKE_LASER) << "Robot localization will be obtained from localization server: " << localization_server_name;
140  m_loc_mode = LOC_FROM_CLIENT;
141  }
142  else
143  {
144  yCInfo(FAKE_LASER) << "No localization method selected. Robot location set to 0,0,0";
145  m_loc_mode = LOC_NOT_SET;
146  }
147 
148  m_robot_loc_x=0;
149  m_robot_loc_y=0;
150  m_robot_loc_t=0;
151  }
152 
153  yCInfo(FAKE_LASER) << "Starting debug mode";
154  yCInfo(FAKE_LASER) << "test mode:"<< m_test_mode;
155  return PeriodicThread::start();
156 }
157 
159 {
160  PeriodicThread::stop();
161 
162  driver.close();
163 
164  if (m_loc_port)
165  {
167  m_loc_port->close();
168  }
169  return true;
170 }
171 
172 bool FakeLaser::setDistanceRange(double min, double max)
173 {
174  m_mutex.lock();
175  m_min_distance = min;
176  m_max_distance = max;
177  m_mutex.unlock();
178  return true;
179 }
180 
181 bool FakeLaser::setScanLimits(double min, double max)
182 {
183  m_mutex.lock();
184  m_min_angle = min;
185  m_max_angle = max;
186  m_mutex.unlock();
187  return true;
188 }
189 
191 {
192  m_mutex.lock();
193  m_resolution = step;
194  m_mutex.unlock();
195  return true;
196 }
197 
198 bool FakeLaser::setScanRate(double rate)
199 {
200  m_mutex.lock();
201  m_period = (1.0 / rate);
202  m_mutex.unlock();
203  return false;
204 }
205 
207 {
208 #ifdef LASER_DEBUG
209  yCDebug(FAKE_LASER)<<"thread initialising...\n");
210  yCDebug(FAKE_LASER)<<"... done!\n");
211 #endif
212 
213  return true;
214 }
215 
217 {
218  m_mutex.lock();
220  double t = yarp::os::Time::now();
221  static double t_orig = yarp::os::Time::now();
222  double size = (t - (t_orig));
223 
224  static int test_count = 0;
225  static int test = 0;
226 
227  if (m_test_mode == USE_PATTERN)
228  {
229  for (size_t i = 0; i < m_sensorsNum; i++)
230  {
231  double value = 0;
232  if (test == 0)
233  { value = i / 100.0; }
234  else if (test == 1)
235  { value = size * 2; }
236  else if (test == 2)
237  {
238  if (i <= 10) { value = 1.0 + i / 20.0; }
239  else if (i >= 90 && i <= 100) { value = 2.0 + (i - 90) / 20.0; }
240  else { value = m_min_distance; }
241  }
242  m_laser_data.push_back(value);
243  }
244 
245  test_count++;
246  if (test_count == 60)
247  {
248  test_count = 0; test++; if (test > 2) { test = 0; }
249  t_orig = yarp::os::Time::now();
250  }
251  }
252  else if (m_test_mode == NO_OBSTACLES)
253  {
254  for (size_t i = 0; i < m_sensorsNum; i++)
255  {
256  m_laser_data.push_back(std::numeric_limits<double>::infinity());
257  }
258  }
259  else if (m_test_mode == USE_CONSTANT_VALUE)
260  {
261  for (size_t i = 0; i < m_sensorsNum; i++)
262  {
264  }
265  }
266  else if (m_test_mode == USE_MAPFILE)
267  {
268  if (m_loc_mode == LOC_NOT_SET)
269  {
270  //do nothing
271  }
272  else if (m_loc_mode == LOC_FROM_PORT)
273  {
274  Bottle* b = m_loc_port->read(false);
275  if (b)
276  {
277  m_robot_loc_x = b->get(0).asFloat64();
278  m_robot_loc_y = b->get(1).asFloat64();
279  m_robot_loc_t = b->get(2).asFloat64();
280  }
281  }
282  else if (m_loc_mode == LOC_FROM_CLIENT)
283  {
284  Map2DLocation loc;
285  if (m_iLoc->getCurrentPosition(loc))
286  {
287  m_robot_loc_x = loc.x;
288  m_robot_loc_y = loc.y;
289  m_robot_loc_t = loc.theta;
290  }
291  else
292  {
293  yCError(FAKE_LASER) << "Error occurred while getting current position from localization server";
294  }
295  }
296  else
297  {
298  yCDebug(FAKE_LASER) << "No localization mode selected. This branch should be not reachable.";
299  }
300 
301  for (size_t i = 0; i < m_sensorsNum; i++)
302  {
303  //compute the ray in the robot reference frame
304  double ray_angle = i* m_resolution + m_min_angle;
305  double ray_target_x = m_max_distance * cos(ray_angle * DEG2RAD);
306  double ray_target_y = m_max_distance * sin(ray_angle * DEG2RAD);
307 
308  //transforms the ray from the robot to the world reference frame
309  XYWorld ray_world;
310  ray_world.x = ray_target_x *cos(m_robot_loc_t*DEG2RAD) - ray_target_y *sin(m_robot_loc_t*DEG2RAD) + m_robot_loc_x;
311  ray_world.y = ray_target_x *sin(m_robot_loc_t*DEG2RAD) + ray_target_y *cos(m_robot_loc_t*DEG2RAD) + m_robot_loc_y;
313  if (m_map.isInsideMap(ray_world))
314  {
315  XYCell dst = m_map.world2Cell(ray_world);
316  double distance = checkStraightLine(src, dst);
317  double simulated_noise = (*m_dis)(*m_gen);
318  m_laser_data.push_back(distance + simulated_noise);
319  }
320  else
321  {
322  m_laser_data.push_back(std::numeric_limits<double>::infinity());
323  }
324  }
325  }
326  //for all the different types of tests, apply the limits
328 
329  //set the device status
331 
332  m_mutex.unlock();
333  return;
334 }
335 
336 double FakeLaser::checkStraightLine(XYCell src, XYCell dst)
337 {
338  XYCell src_final = src;
339 
340  //here using the fast Bresenham algorithm
341  int dx = abs(int(dst.x - src.x));
342  int dy = abs(int(dst.y - src.y));
343  int err = dx - dy;
344 
345  int sx;
346  int sy;
347  if (src.x < dst.x) { sx = 1; } else { sx = -1; }
348  if (src.y < dst.y) { sy = 1; } else { sy = -1; }
349 
350  while (true)
351  {
352  //if (m_map.isFree(src) == false)
353  if (m_map.isWall(src))
354  {
355  XYWorld world_start = m_map.cell2World(src);
356  XYWorld world_end = m_map.cell2World(src_final);
357  return sqrt(pow(world_start.x - world_end.x, 2) + pow(world_start.y - world_end.y, 2));
358  }
359  if (src.x == dst.x && src.y == dst.y) break;
360  int e2 = err * 2;
361  if (e2 > -dy)
362  {
363  err = err - dy;
364  src.x += sx;
365  }
366  if (e2 < dx)
367  {
368  err = err + dx;
369  src.y += sy;
370  }
371  }
372  return std::numeric_limits<double>::infinity();
373 }
374 
376 {
377 #ifdef LASER_DEBUG
378  yCDebug(FAKE_LASER) << "FakeLaser Thread releasing...");
379  yCDebug(FAKE_LASER) << "... done.");
380 #endif
381 }
float t
bool ret
fakeLaser : fake sensor device driver for testing purposes and reference for IRangefinder2D devices.
Definition: fakeLaser.h:62
double m_robot_loc_y
Definition: fakeLaser.h:79
double m_robot_loc_x
Definition: fakeLaser.h:78
double m_period
Definition: fakeLaser.h:71
void run() override
Loop function.
Definition: fakeLaser.cpp:216
yarp::dev::Nav2D::MapGrid2D m_map
Definition: fakeLaser.h:72
bool setDistanceRange(double min, double max) override
set the device detection range.
Definition: fakeLaser.cpp:172
double m_robot_loc_t
Definition: fakeLaser.h:80
@ USE_CONSTANT_VALUE
Definition: fakeLaser.h:64
@ NO_OBSTACLES
Definition: fakeLaser.h:64
@ USE_MAPFILE
Definition: fakeLaser.h:64
@ USE_PATTERN
Definition: fakeLaser.h:64
yarp::dev::Nav2D::ILocalization2D * m_iLoc
Definition: fakeLaser.h:75
localization_mode_t m_loc_mode
Definition: fakeLaser.h:69
bool threadInit() override
Initialization method.
Definition: fakeLaser.cpp:206
yarp::os::BufferedPort< yarp::os::Bottle > * m_loc_port
Definition: fakeLaser.h:73
yarp::dev::PolyDriver driver
Definition: fakeLaser.h:67
test_mode_t m_test_mode
Definition: fakeLaser.h:68
bool setScanRate(double rate) override
set the scan rate (scans per seconds)
Definition: fakeLaser.cpp:198
bool setScanLimits(double min, double max) override
set the scan angular range.
Definition: fakeLaser.cpp:181
bool close() override
Close the DeviceDriver.
Definition: fakeLaser.cpp:158
void threadRelease() override
Release method.
Definition: fakeLaser.cpp:375
@ LOC_NOT_SET
Definition: fakeLaser.h:65
@ LOC_FROM_CLIENT
Definition: fakeLaser.h:65
@ LOC_FROM_PORT
Definition: fakeLaser.h:65
bool setHorizontalResolution(double step) override
get the angular step between two measurments (if available)
Definition: fakeLaser.cpp:190
double m_const_value
Definition: fakeLaser.h:85
yarp::dev::IRangefinder2D::Device_status m_device_status
virtual bool getCurrentPosition(yarp::dev::Nav2D::Map2DLocation &loc)=0
Gets the current position of the robot w.r.t world reference frame.
XYCell world2Cell(XYWorld world) const
bool isInsideMap(XYCell cell) const
Checks if a cell is inside the map.
XYWorld cell2World(XYCell cell) const
bool isWall(XYCell cell) const
Checks if a specific cell of the map contains a wall.
Definition: MapGrid2D.cpp:125
A container for a device driver.
Definition: PolyDriver.h:27
bool close() override
Close the DeviceDriver.
Definition: PolyDriver.cpp:176
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:73
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:249
void close() override
Stop port activity.
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
void interrupt() override
Interrupt any current reads or writes attached to the port.
T * read(bool shouldWait=true) override
Read an available object from the port.
void step()
Call this to "step" the thread rather than starting it.
A class for storing options and configuration information.
Definition: Property.h:37
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition: Property.cpp:998
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition: Property.cpp:1024
A base class for nested structures that can be searched.
Definition: Searchable.h:69
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.
A single value (typically within a Bottle).
Definition: Value.h:47
virtual yarp::conf::float64_t asFloat64() const
Get 64-bit floating point value.
Definition: Value.cpp:225
void push_back(const T &elem)
Push a new element in the vector: size is changed.
Definition: Vector.h:282
const yarp::os::LogComponent & FAKE_LASER()
Definition: fakeLaser.cpp:28
#define DEG2RAD
Definition: fakeLaser.cpp:25
#define yCInfo(component,...)
Definition: LogComponent.h:135
#define yCError(component,...)
Definition: LogComponent.h:157
#define yCDebug(component,...)
Definition: LogComponent.h:112
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:80
yarp::math::Vec2D< double > XYWorld
Definition: NavTypes.h:24
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition: Time.cpp:124
The main, catch-all namespace for YARP.
Definition: environment.h:18