YARP
Yet Another Robot Platform
Map2D_nws_ros.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 "Map2D_nws_ros.h"
7 
8 #include <yarp/os/Log.h>
9 #include <yarp/os/LogComponent.h>
10 #include <yarp/os/LogStream.h>
11 #include <yarp/os/Node.h>
12 #include <yarp/os/Publisher.h>
13 #include <yarp/os/Subscriber.h>
14 
15 #include <yarp/dev/GenericVocabs.h>
16 #include <yarp/dev/IMap2D.h>
17 #include <yarp/dev/INavigation2D.h>
18 
19 #include <yarp/math/Math.h>
20 
22 #include <yarp/rosmsg/TickTime.h>
23 
24 #include <cstdlib>
25 #include <fstream>
26 #include <limits>
27 #include <mutex>
28 #include <sstream>
29 
30 using namespace yarp::sig;
31 using namespace yarp::dev;
32 using namespace yarp::dev::Nav2D;
33 using namespace yarp::os;
34 
35 namespace {
36 YARP_LOG_COMPONENT(MAP2D_NWS_ROS, "yarp.device.map2D_nws_ros")
37 }
38 
39 #ifndef M_PI
40 #define M_PI 3.14159265358979323846
41 #endif
42 
43 #define RAD2DEG 180/M_PI
44 #define DEG2RAD M_PI/180
45 
51 {
52  m_enable_publish_map = false;
53  m_enable_subscribe_map = false;
54  m_node = nullptr;
55 }
56 
58 
59 bool Map2D_nws_ros::read(yarp::os::ConnectionReader& connection)
60 {
61  yarp::os::Bottle command;
62  yarp::os::Bottle reply;
63  bool ok = command.read(connection);
64  if (!ok) {
65  return false;
66  }
67 
68  reply.clear();
69 
70  if (command.get(0).isString() && command.get(0).asString() == "help")
71  {
72  reply.addVocab32("many");
73  reply.addString("No commands currently available:");
74  }
75  else
76  {
77  yCError(MAP2D_NWS_ROS) << "Invalid command. Try `help`";
78  reply.addVocab32(VOCAB_ERR);
79  }
80 
81  yarp::os::ConnectionWriter* returnToSender = connection.getWriter();
82  if (returnToSender != nullptr)
83  {
84  reply.write(*returnToSender);
85  }
86 
87  return true;
88 }
89 
91 {
92  Property params;
93  params.fromString(config.toString());
94 
95  if (!config.check("name"))
96  {
97  m_rpcPortName = "/map2D_nws_ros/rpc";
98  }
99  else
100  {
101  m_rpcPortName = config.find("name").asString();
102  }
103 
104  //subdevice handling
105  if (config.check("subdevice"))
106  {
107  Property p;
108  p.fromString(config.toString(), false);
109  p.put("device", config.find("subdevice").asString());
110 
111  if (!m_drv.open(p) || !m_drv.isValid())
112  {
113  yCError(MAP2D_NWS_ROS) << "Failed to open subdevice.. check params";
114  return false;
115  }
116 
117  if (!attach(&m_drv))
118  {
119  yCError(MAP2D_NWS_ROS) << "Failed to open subdevice.. check params";
120  return false;
121  }
122  }
123  else
124  {
125  yCInfo(MAP2D_NWS_ROS) << "Waiting for device to attach";
126  }
127 
128  //open rpc port
129  if (!m_rpcPort.open(m_rpcPortName))
130  {
131  yCError(MAP2D_NWS_ROS, "Failed to open port %s", m_rpcPortName.c_str());
132  return false;
133  }
134  m_rpcPort.setReader(*this);
135 
136  //ROS configuration
137  if (config.check("ROS"))
138  {
139  yCInfo(MAP2D_NWS_ROS, "Configuring ROS params");
140  Bottle ROS_config = config.findGroup("ROS");
141 
142  if (ROS_config.find("enable_publisher").asInt32() == 1 || ROS_config.find("enable_publisher").asString() == "true")
143  {
144  m_enable_publish_map = true;
145  yCInfo(MAP2D_NWS_ROS) << "Enabled ROS publisher";
146  }
147 
148  if (ROS_config.find("enable_subscriber").asInt32() == 1 || ROS_config.find("enable_subscriber").asString() == "true")
149  {
150  m_enable_subscribe_map = true;
151  yCInfo(MAP2D_NWS_ROS) << "Enabled ROS subscriber";
152  }
153 
154  if (m_enable_publish_map)
155  {
156  if (m_node == nullptr)
157  {
158  m_node = new yarp::os::Node(ROSNODENAME);
159  }
160  if (!m_publisherPort_map.topic(ROSTOPICNAME_MAP))
161  {
162  yCError(MAP2D_NWS_ROS) << "Unable to publish to" << ROSTOPICNAME_MAP << "topic, check your YARP-ROS network configuration";
163  return false;
164  }
165  if (!m_publisherPort_metamap.topic(ROSTOPICNAME_MAPMETADATA))
166  {
167  yCError(MAP2D_NWS_ROS) << "Unable to publish to " << ROSTOPICNAME_MAPMETADATA << " topic, check your YARP-ROS network configuration";
168  return false;
169  }
170  //should I publish the map now? with which name ?
171  //publishMapToRos();
172  }
173 
174  if (m_enable_subscribe_map)
175  {
176  if (!m_subscriberPort_map.topic(ROSTOPICNAME_MAP))
177  {
178  yCError(MAP2D_NWS_ROS) << "Unable to subscribe to " << ROSTOPICNAME_MAP << " topic, check your YARP-ROS network configuration";
179  return false;
180  }
181  if (!m_subscriberPort_metamap.topic(ROSTOPICNAME_MAPMETADATA))
182  {
183  yCError(MAP2D_NWS_ROS) << "Unable to subscribe to " << ROSTOPICNAME_MAPMETADATA << " topic, check your YARP-ROS network configuration";
184  return false;
185  }
186  m_subscriberPort_map.setStrict();
187  m_subscriberPort_metamap.setStrict();
188 
189  //should I subscribe the map now ? with which name ?
190  //subscribeMapFromRos();
191  }
192  }
193  else
194  {
195  //no ROS options
196  yCWarning(MAP2D_NWS_ROS) << "ROS Group not configured";
197  }
198 
199  return true;
200 }
201 
202 bool Map2D_nws_ros::publishMapToRos(std::string map_name)
203 {
204  MapGrid2D current_map;
205  if (!m_iMap2D->get_map(map_name, current_map))
206  {
207  yCError(MAP2D_NWS_ROS) << "publishMapToRos() " << map_name << " does not exists";
208  return false;
209  }
210 
211  double tmp = 0;
212  yarp::rosmsg::nav_msgs::OccupancyGrid& ogrid = m_publisherPort_map.prepare();
213  ogrid.clear();
214  ogrid.info.height = current_map.height();
215  ogrid.info.width = current_map.width();
216  current_map.getResolution(tmp);
217  ogrid.info.resolution = tmp;
218  ogrid.header.frame_id = "map";
219  ogrid.info.map_load_time.sec = 0;
220  ogrid.info.map_load_time.nsec = 0;
221  double x, y, t;
222  current_map.getOrigin(x, y, t);
223  ogrid.info.origin.position.x = x;
224  ogrid.info.origin.position.y = y;
226  yarp::sig::Vector v(4);
227  v[0] = 0; v[1] = 0; v[2] = 1; v[3] = t * DEG2RAD;
228  q.fromAxisAngle(v);
229  ogrid.info.origin.orientation.x = q.x();
230  ogrid.info.origin.orientation.y = q.y();
231  ogrid.info.origin.orientation.z = q.z();
232  ogrid.info.origin.orientation.w = q.w();
233  ogrid.data.resize(current_map.width() * current_map.height());
234  int index = 0;
236  for (cell.y = current_map.height(); cell.y-- > 0;) {
237  for (cell.x = 0; cell.x < current_map.width(); cell.x++)
238  {
239  current_map.getOccupancyData(cell, tmp);
240  ogrid.data[index++] = (int)tmp;
241  }
242  }
243 
244  m_publisherPort_map.write();
245 
246  //what about the m_publisherPort_metamap ?
247  //I don't know...
248 
249  return true;
250 }
251 
252 bool Map2D_nws_ros::subscribeMapFromRos(std::string map_name)
253 {
254  //In this block receives data from a ROS topic and stores data on attached device
255  //yarp::os::Time::delay(5);
256  yarp::rosmsg::nav_msgs::OccupancyGrid* map_ros = nullptr;
257  yarp::rosmsg::nav_msgs::MapMetaData* metamap_ros = nullptr;
258 
259  map_ros = m_subscriberPort_map.read(true);
260  metamap_ros = m_subscriberPort_metamap.read(true);
261  if (map_ros != nullptr && metamap_ros != nullptr)
262  {
263  yCInfo(MAP2D_NWS_ROS) << "Received map for ROS";
264  std::string map_name = "ros_map";
265  MapGrid2D map;
266  map.setSize_in_cells(map_ros->info.width,map_ros->info.height);
267  map.setResolution(map_ros->info.resolution);
268  map.setMapName(map_name);
270  map_ros->info.origin.orientation.y,
271  map_ros->info.origin.orientation.z,
272  map_ros->info.origin.orientation.w);
273  yarp::sig::Matrix mat = quat.toRotationMatrix4x4();
275  double orig_angle = vec[2];
276  map.setOrigin(map_ros->info.origin.position.x,map_ros->info.origin.position.y,orig_angle);
277  for (size_t y = 0; y < map_ros->info.height; y++)
278  {
279  for (size_t x = 0; x < map_ros->info.width; x++)
280  {
281  XYCell cell(x,map_ros->info.height - 1 - y);
282  double occ = map_ros->data[x + y * map_ros->info.width];
283  map.setOccupancyData(cell,occ);
284 
285  if (occ >= 0 && occ <= 70) {
286  map.setMapFlag(cell, MapGrid2D::MAP_CELL_FREE);
287  } else if (occ >= 71 && occ <= 100) {
288  map.setMapFlag(cell, MapGrid2D::MAP_CELL_WALL);
289  } else {
290  map.setMapFlag(cell, MapGrid2D::MAP_CELL_UNKNOWN);
291  }
292  }
293  }
294  if (m_iMap2D->store_map(map))
295  {
296  yCInfo(MAP2D_NWS_ROS) << "Added map " << map.getMapName() << " to storage";
297  return true;
298  }
299 
300  yCInfo(MAP2D_NWS_ROS) << "Unable to add map " << map.getMapName() << " to storage";
301  return false;
302  }
303 
304  return false;
305 }
306 
308 {
309  yCTrace(MAP2D_NWS_ROS, "Close");
310  if (m_enable_publish_map)
311  {
312  m_publisherPort_map.interrupt();
313  m_publisherPort_metamap.interrupt();
314  m_publisherPort_map.close();
315  m_publisherPort_metamap.close();
316  }
317  if (m_enable_subscribe_map)
318  {
319  m_subscriberPort_map.interrupt();
320  m_subscriberPort_metamap.interrupt();
321  m_subscriberPort_map.close();
322  m_subscriberPort_metamap.close();
323  }
324  return true;
325 }
326 
327 bool Map2D_nws_ros::updateVizMarkers(std::string map_name)
328 {
329  if (m_publisherPort_markers.asPort().isOpen()==false)
330  {
331  m_publisherPort_markers.topic("/locationServerMarkers");
332  }
333  yarp::rosmsg::TickDuration dur; dur.sec = 0xFFFFFFFF;
334  double yarpTimeStamp = yarp::os::Time::now();
335  uint64_t time;
336  uint64_t nsec_part;
337  uint64_t sec_part;
339  time = (uint64_t)(yarpTimeStamp * 1000000000UL);
340  nsec_part = (time % 1000000000UL);
341  sec_part = (time / 1000000000UL);
342  if (sec_part > std::numeric_limits<unsigned int>::max())
343  {
344  yCWarning(MAP2D_NWS_ROS) << "Timestamp exceeded the 64 bit representation, resetting it to 0";
345  sec_part = 0;
346  }
347 
350  yarp::sig::Vector rpy(3);
352 
353  yarp::rosmsg::visualization_msgs::MarkerArray& markers = m_publisherPort_markers.prepare();
354  markers.markers.clear();
355 
356  std::vector<std::string> locations;
357  int count = 1;
358  m_iMap2D->getLocationsList(locations);
359  for (auto it : locations)
360  {
362  m_iMap2D->getLocation(it, loc);
363  rpy[0] = 0; //x
364  rpy[1] = 0; //y
365  rpy[2] = loc.theta / 180 * 3.14159265359; //z
367  q.fromRotationMatrix(m);
368 
369  marker.header.frame_id = "map";
370  tt.sec = (yarp::os::NetUint32) sec_part;;
371  tt.nsec = (yarp::os::NetUint32) nsec_part;;
372  marker.header.stamp = tt;
373  marker.ns = "my_namespace";
374  marker.id = count;
377  marker.pose.position.x = loc.x;
378  marker.pose.position.y = loc.y;
379  marker.pose.position.z = 0;
380  marker.pose.orientation.x = q.x();
381  marker.pose.orientation.y = q.y();
382  marker.pose.orientation.z = q.z();
383  marker.pose.orientation.w = q.w();
384  marker.scale.x = 1;
385  marker.scale.y = 0.1;
386  marker.scale.z = 0.1;
387  marker.color.a = 1.0;
388  marker.color.r = 0.0;
389  marker.color.g = 1.0;
390  marker.color.b = 0.0;
391  marker.lifetime = dur;
392  marker.text = it;
393  markers.markers.push_back(marker);
394  count++;
395  }
396 
397  m_publisherPort_markers.write();
398  return true;
399 }
400 
401 
403 {
404  m_iMap2D = nullptr;
405  return true;
406 }
407 
409 {
410  if (driver->isValid())
411  {
412  driver->view(m_iMap2D);
413  }
414 
415  if (nullptr == m_iMap2D)
416  {
417  yCError(MAP2D_NWS_ROS, "Subdevice passed to attach method is invalid");
418  return false;
419  }
420 
421  return true;
422 }
float t
#define ROSNODENAME
constexpr yarp::conf::vocab32_t VOCAB_ERR
Definition: GenericVocabs.h:17
bool ret
#define DEG2RAD
#define ROSTOPICNAME_MAP
Definition: Map2D_nws_ros.h:86
#define ROSTOPICNAME_MAPMETADATA
Definition: Map2D_nws_ros.h:87
bool close() override
Close the DeviceDriver.
bool attach(yarp::dev::PolyDriver *driver) override
Attach to another object.
bool detach() override
Detach the object (you must have first called attach).
bool open(yarp::os::Searchable &params) override
Open the DeviceDriver.
Map2D_nws_ros()
Map2D_nws_ros.
bool view(T *&x)
Get an interface to the device driver.
Definition: DeviceDriver.h:74
size_t height() const
Retrieves the map height, expressed in cells.
Definition: MapGrid2D.cpp:177
bool setResolution(double resolution)
Sets the resolution of the map, i.e.
Definition: MapGrid2D.cpp:1058
bool setOrigin(double x, double y, double theta)
Sets the origin of the map reference frame (according to ROS convention)
Definition: MapGrid2D.cpp:1024
std::string getMapName() const
Retrieves the map name.
Definition: MapGrid2D.cpp:1085
bool setSize_in_cells(size_t x, size_t y)
Sets the size of the map in cells.
Definition: MapGrid2D.cpp:1108
void getOrigin(double &x, double &y, double &theta) const
Retrieves the origin of the map reference frame (according to ROS convention)
Definition: MapGrid2D.cpp:1051
bool setMapName(std::string map_name)
Sets the map name.
Definition: MapGrid2D.cpp:1074
bool setMapFlag(XYCell cell, map_flags flag)
Set the flag of a specific cell of the map.
Definition: MapGrid2D.cpp:1136
size_t width() const
Retrieves the map width, expressed in cells.
Definition: MapGrid2D.cpp:182
bool setOccupancyData(XYCell cell, double occupancy)
Set the occupancy data of a specific cell of the map.
Definition: MapGrid2D.cpp:1158
bool getOccupancyData(XYCell cell, double &occupancy) const
Retrieves the occupancy data of a specific cell of the map.
Definition: MapGrid2D.cpp:1176
void getResolution(double &resolution) const
Retrieves the resolution of the map, i.e.
Definition: MapGrid2D.cpp:1069
A container for a device driver.
Definition: PolyDriver.h:24
bool isValid() const
Check if device is valid.
Definition: PolyDriver.cpp:196
void fromRotationMatrix(const yarp::sig::Matrix &R)
Converts a rotation matrix to a quaternion.
Definition: Quaternion.cpp:162
double x() const
Definition: Quaternion.cpp:81
void fromAxisAngle(const yarp::sig::Vector &v)
Computes the quaternion from an axis-angle representation.
Definition: Quaternion.cpp:282
double z() const
Definition: Quaternion.cpp:91
double w() const
Definition: Quaternion.cpp:76
double y() const
Definition: Quaternion.cpp:86
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:74
void addVocab32(yarp::conf::vocab32_t x)
Places a vocabulary item in the bottle, at the end of the list.
Definition: Bottle.cpp:164
bool read(ConnectionReader &reader) override
Set the bottle's value based on input from a network connection.
Definition: Bottle.cpp:240
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:246
void clear()
Empties the bottle of any objects it contains.
Definition: Bottle.cpp:121
bool write(ConnectionWriter &writer) const override
Output a representation of the bottle to a network connection.
Definition: Bottle.cpp:230
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition: Bottle.cpp:170
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Bottle.cpp:287
An interface for reading from a network connection.
virtual ConnectionWriter * getWriter()=0
Gets a way to reply to the message, if possible.
An interface for writing to a network connection.
The Node class.
Definition: Node.h:24
A class for storing options and configuration information.
Definition: Property.h:34
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
Definition: Property.cpp:1063
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition: Property.cpp:1015
A base class for nested structures that can be searched.
Definition: Searchable.h:66
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
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.
virtual bool isString() const
Checks if value is a string.
Definition: Value.cpp:156
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition: Value.cpp:204
virtual std::string asString() const
Get string value.
Definition: Value.cpp:234
std::uint32_t nsec
Definition: TickTime.h:30
std::uint32_t sec
Definition: TickTime.h:29
yarp::conf::float64_t y
Definition: Point.h:33
yarp::conf::float64_t x
Definition: Point.h:32
yarp::conf::float64_t z
Definition: Point.h:34
yarp::rosmsg::geometry_msgs::Point position
Definition: Pose.h:33
yarp::rosmsg::geometry_msgs::Quaternion orientation
Definition: Pose.h:34
yarp::conf::float64_t y
Definition: Vector3.h:38
yarp::conf::float64_t z
Definition: Vector3.h:39
yarp::conf::float64_t x
Definition: Vector3.h:37
yarp::rosmsg::geometry_msgs::Pose origin
Definition: MapMetaData.h:46
yarp::conf::float32_t resolution
Definition: MapMetaData.h:43
yarp::rosmsg::TickTime map_load_time
Definition: MapMetaData.h:42
bool read(yarp::os::ConnectionReader &connection) override
Read this object from a network connection.
Definition: MapMetaData.h:130
std::vector< std::int8_t > data
Definition: OccupancyGrid.h:43
yarp::rosmsg::nav_msgs::MapMetaData info
Definition: OccupancyGrid.h:42
yarp::rosmsg::std_msgs::Header header
Definition: OccupancyGrid.h:41
bool read(yarp::os::ConnectionReader &connection) override
Read this object from a network connection.
yarp::conf::float32_t b
Definition: ColorRGBA.h:34
yarp::conf::float32_t a
Definition: ColorRGBA.h:35
yarp::conf::float32_t g
Definition: ColorRGBA.h:33
yarp::conf::float32_t r
Definition: ColorRGBA.h:32
yarp::rosmsg::TickTime stamp
Definition: Header.h:45
std::vector< yarp::rosmsg::visualization_msgs::Marker > markers
Definition: MarkerArray.h:30
yarp::rosmsg::std_msgs::ColorRGBA color
Definition: Marker.h:101
static const std::uint8_t ARROW
Definition: Marker.h:78
yarp::rosmsg::TickDuration lifetime
Definition: Marker.h:102
yarp::rosmsg::geometry_msgs::Vector3 scale
Definition: Marker.h:100
static const std::uint8_t ADD
Definition: Marker.h:90
yarp::rosmsg::geometry_msgs::Pose pose
Definition: Marker.h:99
yarp::rosmsg::std_msgs::Header header
Definition: Marker.h:94
A class for a Matrix.
Definition: Matrix.h:43
#define yCInfo(component,...)
Definition: LogComponent.h:132
#define yCError(component,...)
Definition: LogComponent.h:154
#define yCTrace(component,...)
Definition: LogComponent.h:85
#define yCWarning(component,...)
Definition: LogComponent.h:143
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:77
An interface for the device drivers.
yarp::sig::Matrix rpy2dcm(const yarp::sig::Vector &rpy)
Converts roll-pitch-yaw angles in the corresponding dcm (direction cosine matrix) rotation matrix (de...
Definition: math.cpp:847
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:808
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition: Time.cpp:121
An interface to the operating system, including Port based communication.
std::uint32_t NetUint32
Definition of the NetUint32 type.
Definition: NetUint32.h:30
Signal processing.
Definition: Image.h:22