map.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-9, Ubiquity Robotics
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  *
30  */
31 
32 #include <fiducial_slam/helpers.h>
33 #include <fiducial_slam/map.h>
34 
36 #include <tf2/LinearMath/Vector3.h>
37 #include <string>
38 
39 #include <std_msgs/ColorRGBA.h>
40 #include <std_msgs/String.h>
41 
42 #include <geometry_msgs/Point.h>
43 #include <geometry_msgs/PoseWithCovarianceStamped.h>
44 #include <geometry_msgs/TransformStamped.h>
45 #include <visualization_msgs/Marker.h>
46 
47 #include <boost/filesystem.hpp>
48 
49 
50 static double systematic_error = 0.01;
51 
52 // Constructor for observation
54  this->fid = fid;
55 
56  T_camFid = camFid;
58  T_fidCam.transform = T_camFid.transform.inverse();
59 }
60 
61 // Update a fiducial position in map with a new estimate
63  pose.update(newPose);
64  numObs++;
65 }
66 
67 // Create a fiducial from an estimate of its position in the map
69  this->id = id;
70  this->pose = pose;
71  this->lastPublished = ros::Time(0);
72  this->numObs = 0;
73  this->visible = false;
74 }
75 
76 // Constructor for map
77 
78 Map::Map(ros::NodeHandle &nh) : tfBuffer(ros::Duration(30.0)) {
79  frameNum = 0;
80  initialFrameNum = 0;
81  originFid = -1;
82  isInitializingMap = false;
83  havePose = false;
84  fiducialToAdd = -1;
85 
86  listener = make_unique<tf2_ros::TransformListener>(tfBuffer);
87 
88  robotPosePub =
89  ros::Publisher(nh.advertise<geometry_msgs::PoseWithCovarianceStamped>("/fiducial_pose", 1));
91  nh.advertise<geometry_msgs::PoseWithCovarianceStamped>("/fiducial_slam/camera_pose", 1));
92 
93  markerPub = ros::Publisher(nh.advertise<visualization_msgs::Marker>("/fiducials", 100));
94  mapPub = ros::Publisher(nh.advertise<fiducial_msgs::FiducialMapEntryArray>("/fiducial_map", 1));
95 
96  clearSrv = nh.advertiseService("clear_map", &Map::clearCallback, this);
97  addSrv = nh.advertiseService("add_fiducial", &Map::addFiducialCallback, this);
98 
99  nh.param<std::string>("map_frame", mapFrame, "map");
100  nh.param<std::string>("odom_frame", odomFrame, "odom");
101  nh.param<std::string>("base_frame", baseFrame, "base_footprint");
102 
103  nh.param<float>("tf_publish_interval", tfPublishInterval, 1.0);
104  nh.param<bool>("publish_tf", publishPoseTf, true);
105  nh.param<double>("systematic_error", systematic_error, 0.01);
106  nh.param<double>("future_date_transforms", future_date_transforms, 0.1);
107  nh.param<bool>("publish_6dof_pose", publish_6dof_pose, false);
108  nh.param<bool>("read_only_map", readOnly, false);
109 
110  std::fill(covarianceDiagonal.begin(), covarianceDiagonal.end(), 0);
111  overridePublishedCovariance = nh.getParam("covariance_diagonal", covarianceDiagonal);
112  if (overridePublishedCovariance) {
113  if (covarianceDiagonal.size() != 6) {
114  ROS_WARN("ignoring covariance_diagonal because it has %ld elements, not 6", covarianceDiagonal.size());
115  overridePublishedCovariance = false;
116  }
117  // Check to make sure that the diagonal is non-zero
118  for (auto variance : covarianceDiagonal) {
119  if (variance == 0) {
120  ROS_WARN("ignoring covariance_diagonal because it has 0 values");
121  std::fill(covarianceDiagonal.begin(), covarianceDiagonal.end(), 0);
122  break;
123  }
124  }
125  }
126 
127  // threshold of object error for using multi-fidicial pose
128  // set -ve to never use
129  nh.param<double>("multi_error_theshold", multiErrorThreshold, -1);
130 
131  nh.param<std::string>("map_file", mapFilename,
132  std::string(getenv("HOME")) + "/.ros/slam/map.txt");
133 
134  boost::filesystem::path mapPath(mapFilename);
135  boost::filesystem::path dir = mapPath.parent_path();
136  boost::filesystem::create_directories(dir);
137 
138  std::string initialMap;
139  nh.param<std::string>("initial_map_file", initialMap, "");
140 
141  if (!initialMap.empty()) {
142  loadMap(initialMap);
143  } else {
144  loadMap();
145  }
146 
147  publishMarkers();
148 }
149 
150 // Update map with a set of observations
151 
152 void Map::update(std::vector<Observation> &obs, const ros::Time &time) {
153  ROS_INFO("Updating map with %d observations. Map has %d fiducials", (int)obs.size(),
154  (int)fiducials.size());
155 
156  frameNum++;
157 
158  if (obs.size() > 0 && fiducials.size() == 0) {
159  isInitializingMap = true;
160  }
161 
162  if (isInitializingMap) {
163  autoInit(obs, time);
164  } else {
166  T_mapCam.frame_id_ = mapFrame;
167 
168  if (updatePose(obs, time, T_mapCam) > 0 && obs.size() > 1 && !readOnly) {
169  updateMap(obs, time, T_mapCam);
170  }
171  }
172 
173  handleAddFiducial(obs);
174 
175  publishMap();
176 }
177 
178 // update estimates of observed fiducials from previously estimated
179 // camera pose
180 
181 void Map::updateMap(const std::vector<Observation> &obs, const ros::Time &time,
182  const tf2::Stamped<TransformWithVariance> &T_mapCam) {
183  for (auto &map_pair : fiducials) {
184  Fiducial &f = map_pair.second;
185  f.visible = false;
186  }
187 
188  for (const Observation &o : obs) {
189  // This should take into account the variances from both
190  tf2::Stamped<TransformWithVariance> T_mapFid = T_mapCam * o.T_camFid;
191  T_mapFid.frame_id_ = mapFrame;
192 
193  // New scope for logging vars
194  {
195  tf2::Vector3 trans = T_mapFid.transform.getOrigin();
196 
197  ROS_INFO("Estimate of %d %lf %lf %lf var %lf %lf", o.fid, trans.x(), trans.y(),
198  trans.z(), o.T_camFid.variance, T_mapFid.variance);
199 
200  if (std::isnan(trans.x()) || std::isnan(trans.y()) || std::isnan(trans.z())) {
201  ROS_WARN("Skipping NAN estimate\n");
202  continue;
203  };
204  }
205 
206  if (fiducials.find(o.fid) == fiducials.end()) {
207  ROS_INFO("New fiducial %d", o.fid);
208  fiducials[o.fid] = Fiducial(o.fid, T_mapFid);
209  }
210  Fiducial &f = fiducials[o.fid];
211  f.visible = true;
212  if (f.pose.variance != 0) {
213  f.update(T_mapFid);
214  f.numObs++;
215  }
216 
217  for (const Observation &observation : obs) {
218  int fid = observation.fid;
219  if (f.id != fid) {
220  f.links.insert(fid);
221  }
222  }
223  publishMarker(fiducials[o.fid]);
224  }
225 }
226 
227 // lookup specified transform
228 
229 bool Map::lookupTransform(const std::string &from, const std::string &to, const ros::Time &time,
230  tf2::Transform &T) const {
231  geometry_msgs::TransformStamped transform;
232 
233  try {
234  transform = tfBuffer.lookupTransform(from, to, time, ros::Duration(0.5));
235 
236  tf2::fromMsg(transform.transform, T);
237  return true;
238  } catch (tf2::TransformException &ex) {
239  ROS_WARN("%s", ex.what());
240  return false;
241  }
242 }
243 
244 // update pose estimate of robot. We combine the camera->base_link
245 // tf to each estimate so we can evaluate how good they are. A good
246 // estimate would have z == roll == pitch == 0.
247 int Map::updatePose(std::vector<Observation> &obs, const ros::Time &time,
249  int numEsts = 0;
253 
254  if (obs.size() == 0) {
255  return 0;
256  }
257 
258  if (lookupTransform(obs[0].T_camFid.frame_id_, baseFrame, time, T_camBase.transform)) {
259  tf2::Vector3 c = T_camBase.transform.getOrigin();
260  ROS_INFO("camera->base %lf %lf %lf", c.x(), c.y(), c.z());
261  T_camBase.variance = 1.0;
262  } else {
263  ROS_ERROR("Cannot determine tf from camera to robot\n");
264  }
265 
266  if (lookupTransform(baseFrame, obs[0].T_camFid.frame_id_, time, T_baseCam.transform)) {
267  tf2::Vector3 c = T_baseCam.transform.getOrigin();
268  ROS_INFO("base->camera %lf %lf %lf", c.x(), c.y(), c.z());
269  T_baseCam.variance = 1.0;
270  } else {
271  ROS_ERROR("Cannot determine tf from robot to camera\n");
272  return numEsts;
273  }
274 
275  for (Observation &o : obs) {
276  if (fiducials.find(o.fid) != fiducials.end()) {
277  const Fiducial &fid = fiducials[o.fid];
278 
279  tf2::Stamped<TransformWithVariance> p = fid.pose * o.T_fidCam;
280 
281  p.frame_id_ = mapFrame;
282  p.stamp_ = o.T_fidCam.stamp_;
283 
284  p.setData(p * T_camBase);
285  auto position = p.transform.getOrigin();
286  double roll, pitch, yaw;
287  p.transform.getBasis().getRPY(roll, pitch, yaw);
288 
289  // Create variance according to how well the robot is upright on the ground
290  // TODO: Create variance for each DOF
291  // TODO: Take into account position according to odom
292  auto cam_f = o.T_camFid.transform.getOrigin();
293  double s1 = std::pow(position.z() / cam_f.z(), 2) *
294  (std::pow(cam_f.x(), 2) + std::pow(cam_f.y(), 2));
295  double s2 = position.length2() * std::pow(std::sin(roll), 2);
296  double s3 = position.length2() * std::pow(std::sin(pitch), 2);
297  p.variance = s1 + s2 + s3 + systematic_error;
298  o.T_camFid.variance = p.variance;
299 
300  ROS_INFO("Pose %d %lf %lf %lf %lf %lf %lf %lf", o.fid, position.x(), position.y(),
301  position.z(), roll, pitch, yaw, p.variance);
302 
303  // drawLine(fid.pose.getOrigin(), o.position);
304 
305  if (std::isnan(position.x()) || std::isnan(position.y()) || std::isnan(position.z())) {
306  ROS_WARN("Skipping NAN estimate\n");
307  continue;
308  };
309 
310  // compute base_link pose based on this estimate
311 
312  if (numEsts == 0) {
313  T_mapBase = p;
314  } else {
315  T_mapBase.setData(averageTransforms(T_mapBase, p));
316  T_mapBase.stamp_ = p.stamp_;
317  }
318  numEsts++;
319  }
320  }
321 
322  if (numEsts == 0) {
323  ROS_INFO("Finished frame - no estimates\n");
324  return numEsts;
325  }
326 
327  // New scope for logging vars
328  {
329  tf2::Vector3 trans = T_mapBase.transform.getOrigin();
330  double r, p, y;
331  T_mapBase.transform.getBasis().getRPY(r, p, y);
332 
333  ROS_INFO("Pose ALL %lf %lf %lf %lf %lf %lf %f", trans.x(), trans.y(), trans.z(), r, p, y,
334  T_mapBase.variance);
335  }
336 
337  tf2::Stamped<TransformWithVariance> basePose = T_mapBase;
338  basePose.frame_id_ = mapFrame;
339  auto robotPose = toPose(basePose);
340 
342  for (int i = 0; i <= 5; i++) {
343  robotPose.pose.covariance[i * 6 + i] = covarianceDiagonal[i]; // Fill the diagonal
344  }
345  }
346 
347  T_mapCam = T_mapBase * T_baseCam;
348 
349  robotPosePub.publish(robotPose);
350 
351  tf2::Stamped<TransformWithVariance> outPose = basePose;
352  outPose.frame_id_ = mapFrame;
353  std::string outFrame = baseFrame;
354 
355  if (!odomFrame.empty()) {
356  tf2::Transform odomTransform;
357  if (lookupTransform(odomFrame, baseFrame, outPose.stamp_, odomTransform)) {
358  outPose.setData(basePose * odomTransform.inverse());
359  outFrame = odomFrame;
360 
361  tf2::Vector3 c = odomTransform.getOrigin();
362  ROS_INFO("odom %lf %lf %lf", c.x(), c.y(), c.z());
363  }
364  else {
365  // Don't publish anything if map->odom was requested and is unavailaable
366  return numEsts;
367  }
368  }
369 
370  // Make outgoing transform make sense - ie only consist of x, y, yaw
371  // This can be disabled via the publish_6dof_pose param, mainly for debugging
372  if (!publish_6dof_pose) {
373  tf2::Vector3 translation = outPose.transform.getOrigin();
374  translation.setZ(0);
375  outPose.transform.setOrigin(translation);
376  double roll, pitch, yaw;
377  outPose.transform.getBasis().getRPY(roll, pitch, yaw);
378  outPose.transform.getBasis().setRPY(0, 0, yaw);
379  }
380 
381  poseTf = toMsg(outPose);
382  poseTf.child_frame_id = outFrame;
383  havePose = true;
384 
385  if (publishPoseTf) {
386  publishTf();
387  }
388 
389  ROS_INFO("Finished frame. Estimates %d\n", numEsts);
390  return numEsts;
391 }
392 
393 // Publish map -> odom tf
394 
399 }
400 
401 // publish latest tf if enough time has elapsed
402 
403 void Map::update() {
404  ros::Time now = ros::Time::now();
405  if (publishPoseTf && havePose && tfPublishInterval != 0.0 &&
406  (now - tfPublishTime).toSec() > tfPublishInterval) {
407  publishTf();
408  tfPublishTime = now;
409  }
410  publishMarkers();
411 }
412 
413 // Find closest fiducial to camera
414 
415 static int findClosestObs(const std::vector<Observation> &obs) {
416  double smallestDist = -1;
417  int closestIdx = -1;
418 
419  for (size_t i = 0; i < obs.size(); i++) {
420  const Observation &o = obs[i];
421  double d = o.T_camFid.transform.getOrigin().length2();
422  if (smallestDist < 0 || d < smallestDist) {
423  smallestDist = d;
424  closestIdx = i;
425  }
426  }
427 
428  return closestIdx;
429 }
430 
431 // Initialize a map from the closest observed fiducial
432 // Figure out the closest marker, and then figure out the
433 // pose of that marker such that base_link is at the origin of the
434 // map frame
435 
436 void Map::autoInit(const std::vector<Observation> &obs, const ros::Time &time) {
437  ROS_INFO("Auto init map %d", frameNum);
438 
439  tf2::Transform T_baseCam;
440 
441  if (fiducials.size() == 0) {
442  int idx = findClosestObs(obs);
443 
444  if (idx == -1) {
445  ROS_WARN("Could not find a fiducial to initialize map from");
446  return;
447  }
448  const Observation &o = obs[idx];
449  originFid = o.fid;
450 
451  ROS_INFO("Initializing map from fiducial %d", o.fid);
452 
454 
455  if (lookupTransform(baseFrame, o.T_camFid.frame_id_, o.T_camFid.stamp_, T_baseCam)) {
456  T.setData(T_baseCam * T);
457  }
458 
459  fiducials[o.fid] = Fiducial(o.fid, T);
460  } else {
461  for (const Observation &o : obs) {
462  if (o.fid == originFid) {
464 
465  tf2::Vector3 trans = T.transform.getOrigin();
466  ROS_INFO("Estimate of %d from base %lf %lf %lf err %lf", o.fid, trans.x(),
467  trans.y(), trans.z(), o.T_camFid.variance);
468 
469  if (lookupTransform(baseFrame, o.T_camFid.frame_id_, o.T_camFid.stamp_,
470  T_baseCam)) {
471  T.setData(T_baseCam * T);
472  }
473 
474  fiducials[originFid].update(T);
475  break;
476  }
477  }
478  }
479 
480  if (frameNum - initialFrameNum > 10 && originFid != -1) {
481  isInitializingMap = false;
482 
483  fiducials[originFid].pose.variance = 0.0;
484  }
485 }
486 
487 // Attempt to add the specified fiducial to the map
488 
489 void Map::handleAddFiducial(const std::vector<Observation> &obs) {
490 
491  if (fiducialToAdd == -1) {
492  return;
493  }
494 
495  if (fiducials.find(fiducialToAdd) != fiducials.end()) {
496  ROS_INFO("Fiducial %d is already in map - ignoring add request",
497  fiducialToAdd);
498  fiducialToAdd = -1;
499  return;
500  }
501 
502  for (const Observation &o : obs) {
503  if (o.fid == fiducialToAdd) {
504  ROS_INFO("Adding fiducial_id %d to map", fiducialToAdd);
505 
506 
508 
509  // Take into account position of camera on base
510  tf2::Transform T_baseCam;
511  if (lookupTransform(baseFrame, o.T_camFid.frame_id_,
512  o.T_camFid.stamp_, T_baseCam)) {
513  T.setData(T_baseCam * T);
514  }
515 
516  // Take into account position of robot in the world if known
517  tf2::Transform T_mapBase;
518  if (lookupTransform(mapFrame, baseFrame, ros::Time(0), T_mapBase)) {
519  T.setData(T_mapBase * T);
520  }
521  else {
522  ROS_INFO("Placing robot at the origin");
523  }
524 
525  fiducials[o.fid] = Fiducial(o.fid, T);
526  fiducials[originFid].pose.variance = 0.0;
527  isInitializingMap = false;
528 
529  fiducialToAdd = -1;
530  return;
531  }
532  }
533 
534  ROS_INFO("Unable to add fiducial %d to map", fiducialToAdd);
535 }
536 
537 // save map to file
538 
539 bool Map::saveMap() { return saveMap(mapFilename); }
540 
541 bool Map::saveMap(std::string filename) {
542  ROS_INFO("Saving map with %d fiducials to file %s\n", (int)fiducials.size(), filename.c_str());
543 
544  FILE *fp = fopen(filename.c_str(), "w");
545  if (fp == NULL) {
546  ROS_WARN("Could not open %s for write\n", filename.c_str());
547  return false;
548  }
549 
550  for (auto &map_pair : fiducials) {
551  Fiducial &f = map_pair.second;
552  tf2::Vector3 trans = f.pose.transform.getOrigin();
553  double rx, ry, rz;
554  f.pose.transform.getBasis().getRPY(rx, ry, rz);
555 
556  fprintf(fp, "%d %lf %lf %lf %lf %lf %lf %lf %d", f.id, trans.x(), trans.y(), trans.z(),
557  rad2deg(rx), rad2deg(ry), rad2deg(rz), f.pose.variance, f.numObs);
558 
559  for (const auto linked_fid : f.links) {
560  fprintf(fp, " %d", linked_fid);
561  }
562  fprintf(fp, "\n");
563  }
564  fclose(fp);
565  return true;
566 }
567 
568 // Load map from file
569 
570 bool Map::loadMap() { return loadMap(mapFilename); }
571 
572 bool Map::loadMap(std::string filename) {
573  int numRead = 0;
574 
575  ROS_INFO("Load map %s", filename.c_str());
576 
577  FILE *fp = fopen(filename.c_str(), "r");
578  if (fp == NULL) {
579  ROS_WARN("Could not open %s for read\n", filename.c_str());
580  return false;
581  }
582 
583  const int BUFSIZE = 2048;
584  char linebuf[BUFSIZE];
585  char linkbuf[BUFSIZE];
586 
587  while (!feof(fp)) {
588  if (fgets(linebuf, BUFSIZE - 1, fp) == NULL) break;
589 
590  int id;
591  double tx, ty, tz, rx, ry, rz, var;
592  int numObs = 0;
593 
594  linkbuf[0] = '\0';
595  int nElems = sscanf(linebuf, "%d %lf %lf %lf %lf %lf %lf %lf %d%[^\t\n]*s", &id, &tx, &ty,
596  &tz, &rx, &ry, &rz, &var, &numObs, linkbuf);
597  if (nElems == 9 || nElems == 10) {
598  tf2::Vector3 tvec(tx, ty, tz);
599  tf2::Quaternion q;
600  q.setRPY(deg2rad(rx), deg2rad(ry), deg2rad(rz));
601 
602  auto twv = TransformWithVariance(tvec, q, var);
603  // TODO: figure out what the timestamp in Fiducial should be
604  Fiducial f =
606  f.numObs = numObs;
607 
608  std::istringstream ss(linkbuf);
609  std::string s;
610  while (getline(ss, s, ' ')) {
611  if (!s.empty()) {
612  f.links.insert(stoi(s));
613  }
614  }
615  fiducials[id] = f;
616  numRead++;
617  } else {
618  ROS_WARN("Invalid line: %s", linebuf);
619  }
620  }
621 
622  fclose(fp);
623  ROS_INFO("Load map %s read %d entries", filename.c_str(), numRead);
624  return true;
625 }
626 
627 // Publish the map
628 
630  fiducial_msgs::FiducialMapEntryArray fmea;
631  std::map<int, Fiducial>::iterator it;
632 
633  for (const auto &map_pair : fiducials) {
634  const Fiducial &f = map_pair.second;
635 
636  fiducial_msgs::FiducialMapEntry fme;
637  fme.fiducial_id = f.id;
638 
639  tf2::Vector3 t = f.pose.transform.getOrigin();
640  fme.x = t.x();
641  fme.y = t.y();
642  fme.z = t.z();
643 
644  double rx, ry, rz;
645  f.pose.transform.getBasis().getRPY(rx, ry, rz);
646  fme.rx = rx;
647  fme.ry = ry;
648  fme.rz = rz;
649 
650  fmea.fiducials.push_back(fme);
651  }
652 
653  mapPub.publish(fmea);
654 }
655 
656 // Publish the next marker visualization messages that hasn't been
657 // published recently
658 
660  ros::Time now = ros::Time::now();
661  std::map<int, Fiducial>::iterator it;
662 
663  for (auto &map_pair : fiducials) {
664  Fiducial &f = map_pair.second;
665  if ((now - f.lastPublished).toSec() > 1.0) {
666  publishMarker(f);
667  }
668  }
669 }
670 
671 // Publish visualization messages for a single fiducial
672 
675 
676  // Flattened cube
677  visualization_msgs::Marker marker;
678  marker.type = visualization_msgs::Marker::CUBE;
679  marker.action = visualization_msgs::Marker::ADD;
680  toMsg(fid.pose.transform, marker.pose);
681 
682  marker.scale.x = 0.15;
683  marker.scale.y = 0.15;
684  marker.scale.z = 0.01;
685  if (fid.visible) {
686  marker.color.r = 1.0f;
687  marker.color.g = 0.0f;
688  marker.color.b = 0.0f;
689  marker.color.a = 1.0f;
690  } else {
691  marker.color.r = 0.0f;
692  marker.color.g = 1.0f;
693  marker.color.b = 0.0f;
694  marker.color.a = 1.0f;
695  }
696  marker.id = fid.id;
697  marker.ns = "fiducial";
698  marker.header.frame_id = mapFrame;
699  markerPub.publish(marker);
700 
701  // cylinder scaled by stddev
702  visualization_msgs::Marker cylinder;
703  cylinder.type = visualization_msgs::Marker::CYLINDER;
704  cylinder.action = visualization_msgs::Marker::ADD;
705  cylinder.header.frame_id = mapFrame;
706  cylinder.color.r = 0.0f;
707  cylinder.color.g = 0.0f;
708  cylinder.color.b = 1.0f;
709  cylinder.color.a = 0.5f;
710  cylinder.id = fid.id + 10000;
711  cylinder.ns = "sigma";
712  cylinder.scale.x = cylinder.scale.y = std::max(std::sqrt(fid.pose.variance), 0.1);
713  cylinder.scale.z = 0.01;
714  cylinder.pose.position.x = marker.pose.position.x;
715  cylinder.pose.position.y = marker.pose.position.y;
716  cylinder.pose.position.z = marker.pose.position.z;
717  cylinder.pose.position.z += (marker.scale.z / 2.0) + 0.05;
718  markerPub.publish(cylinder);
719 
720  // Text
721  visualization_msgs::Marker text;
722  text.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
723  text.action = visualization_msgs::Marker::ADD;
724  text.header.frame_id = mapFrame;
725  text.color.r = text.color.g = text.color.b = text.color.a = 1.0f;
726  text.id = fid.id;
727  text.scale.x = text.scale.y = text.scale.z = 0.1;
728  text.pose.position.x = marker.pose.position.x;
729  text.pose.position.y = marker.pose.position.y;
730  text.pose.position.z = marker.pose.position.z;
731  text.pose.position.z += (marker.scale.z / 2.0) + 0.1;
732  text.id = fid.id + 30000;
733  text.ns = "text";
734  text.text = std::to_string(fid.id);
735  markerPub.publish(text);
736 
737  // Links
738  visualization_msgs::Marker links;
739  links.type = visualization_msgs::Marker::LINE_LIST;
740  links.action = visualization_msgs::Marker::ADD;
741  links.header.frame_id = mapFrame;
742  links.color.r = 0.0f;
743  links.color.g = 0.0f;
744  links.color.b = 1.0f;
745  links.color.a = 1.0f;
746  links.id = fid.id + 40000;
747  links.ns = "links";
748  links.scale.x = links.scale.y = links.scale.z = 0.02;
749  links.pose.position.x = 0;
750  links.pose.position.y = 0;
751  links.pose.position.z = 0;
752 
753  geometry_msgs::Point gp0, gp1;
754  tf2::Vector3 p0 = fid.pose.transform.getOrigin();
755  gp0.x = p0.x();
756  gp0.y = p0.y();
757  gp0.z = p0.z();
758 
759  std::map<int, int>::iterator lit;
760  for (const auto linked_fid : fid.links) {
761  // only draw links in one direction
762  if (fid.id < linked_fid) {
763  if (fiducials.find(linked_fid) != fiducials.end()) {
764  tf2::Vector3 p1 = fiducials[linked_fid].pose.transform.getOrigin();
765  gp1.x = p1.x();
766  gp1.y = p1.y();
767  gp1.z = p1.z();
768  links.points.push_back(gp0);
769  links.points.push_back(gp1);
770  }
771  }
772  }
773 
774  markerPub.publish(links);
775 }
776 
777 // Publish a line marker between two points
778 
779 void Map::drawLine(const tf2::Vector3 &p0, const tf2::Vector3 &p1) {
780  static int lid = 60000;
781  visualization_msgs::Marker line;
782  line.type = visualization_msgs::Marker::LINE_LIST;
783  line.action = visualization_msgs::Marker::ADD;
784  line.header.frame_id = mapFrame;
785  line.color.r = 1.0f;
786  line.color.g = 0.0f;
787  line.color.b = 0.0f;
788  line.color.a = 1.0f;
789  line.id = lid++;
790  line.ns = "lines";
791  line.scale.x = line.scale.y = line.scale.z = 0.01;
792  line.pose.position.x = 0;
793  line.pose.position.y = 0;
794  geometry_msgs::Point gp0, gp1;
795  gp0.x = p0.x();
796  gp0.y = p0.y();
797  gp0.z = p0.z();
798  gp1.x = p1.x();
799  gp1.y = p1.y();
800  gp1.z = p1.z();
801  line.points.push_back(gp0);
802  line.points.push_back(gp1);
803 
804  markerPub.publish(line);
805 }
806 
807 // Service to clear the map and enable auto initialization
808 
809 bool Map::clearCallback(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res) {
810  ROS_INFO("Clearing fiducial map from service call");
811 
812  fiducials.clear();
814  originFid = -1;
815 
816  return true;
817 }
818 
819 // Service to add a fiducial to the map
820 
821 bool Map::addFiducialCallback(fiducial_slam::AddFiducial::Request &req,
822  fiducial_slam::AddFiducial::Response &res)
823 {
824  ROS_INFO("Request to add fiducial %d to map", req.fiducial_id);
825  fiducialToAdd = req.fiducial_id;
826 
827  return true;
828 }
d
ros::Time lastPublished
Definition: map.h:82
ros::Publisher cameraPosePub
Definition: map.h:101
void setRPY(const tf2Scalar &roll, const tf2Scalar &pitch, const tf2Scalar &yaw)
constexpr double deg2rad(double deg)
Definition: helpers.h:11
double future_date_transforms
Definition: map.h:114
void update()
Definition: map.cpp:403
tf2::Stamped< TransformWithVariance > T_fidCam
Definition: map.h:65
void publishMarkers()
Definition: map.cpp:659
std::string odomFrame
Definition: map.h:111
bool clearCallback(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
Definition: map.cpp:809
void autoInit(const std::vector< Observation > &obs, const ros::Time &time)
Definition: map.cpp:436
void publish(const boost::shared_ptr< M > &message) const
void publishTf()
Definition: map.cpp:395
constexpr double rad2deg(double rad)
Definition: helpers.h:14
ros::ServiceServer clearSrv
Definition: map.h:103
bool publishPoseTf
Definition: map.h:129
XmlRpcServer s
tf2_ros::Buffer tfBuffer
Definition: map.h:95
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration timeout) const
static int findClosestObs(const std::vector< Observation > &obs)
Definition: map.cpp:415
int id
Definition: map.h:76
bool havePose
Definition: map.h:127
void publishMap()
Definition: map.cpp:629
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
Map(ros::NodeHandle &nh)
Definition: map.cpp:78
TFSIMD_FORCE_INLINE const tfScalar & y() const
bool loadMap()
Definition: map.cpp:570
#define ROS_WARN(...)
geometry_msgs::TransformStamped t
std::vector< double > covarianceDiagonal
Definition: map.h:125
geometry_msgs::TransformStamped toMsg(const tf2::Stamped< TransformWithVariance > &in)
void handleAddFiducial(const std::vector< Observation > &obs)
Definition: map.cpp:489
std::unique_ptr< tf2_ros::TransformListener > listener
Definition: map.h:96
Definition: map.h:74
geometry_msgs::TransformStamped poseTf
Definition: map.h:131
void updateMap(const std::vector< Observation > &obs, const ros::Time &time, const tf2::Stamped< TransformWithVariance > &cameraPose)
Definition: map.cpp:181
bool isInitializingMap
Definition: map.h:118
ros::ServiceServer addSrv
Definition: map.h:104
bool visible
Definition: map.h:78
TF2SIMD_FORCE_INLINE Vector3 & getOrigin()
std::map< int, Fiducial > fiducials
Definition: map.h:133
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
ros::Time stamp_
TransformWithVariance averageTransforms(const TransformWithVariance &t1, const TransformWithVariance &t2)
std::set< int > links
Definition: map.h:79
void fromMsg(const A &, B &b)
Transform inverse() const
std::string mapFrame
Definition: map.h:110
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
list roll
Definition: fit_plane.py:42
geometry_msgs::PoseWithCovarianceStamped toPose(const tf2::Stamped< TransformWithVariance > &in)
void sendTransform(const geometry_msgs::TransformStamped &transform)
static double systematic_error
Definition: map.cpp:50
void update(const tf2::Stamped< TransformWithVariance > &newPose)
Definition: map.cpp:62
bool saveMap()
Definition: map.cpp:539
ros::Publisher mapPub
Definition: map.h:99
std::string frame_id_
ros::Time tfPublishTime
Definition: map.h:130
float tfPublishInterval
Definition: map.h:128
int fid
Definition: map.h:64
ros::Publisher robotPosePub
Definition: map.h:100
int initialFrameNum
Definition: map.h:121
bool readOnly
Definition: map.h:119
int fiducialToAdd
Definition: map.h:134
bool overridePublishedCovariance
Definition: map.h:124
void publishMarker(Fiducial &fid)
Definition: map.cpp:673
list pitch
Definition: fit_plane.py:43
bool getParam(const std::string &key, std::string &s) const
int originFid
Definition: map.h:122
Observation()
Definition: map.h:68
static Time now()
void drawLine(const tf2::Vector3 &p0, const tf2::Vector3 &p1)
Definition: map.cpp:779
int updatePose(std::vector< Observation > &obs, const ros::Time &time, tf2::Stamped< TransformWithVariance > &cameraPose)
Definition: map.cpp:247
tf2_ros::TransformBroadcaster broadcaster
Definition: map.h:94
int frameNum
Definition: map.h:120
Fiducial()
Definition: map.h:86
tf2::Stamped< TransformWithVariance > pose
Definition: map.h:81
bool addFiducialCallback(fiducial_slam::AddFiducial::Request &req, fiducial_slam::AddFiducial::Response &res)
Definition: map.cpp:821
bool publish_6dof_pose
Definition: map.h:115
int numObs
Definition: map.h:77
double multiErrorThreshold
Definition: map.h:116
std::string mapFilename
Definition: map.h:109
#define ROS_ERROR(...)
tf2::Stamped< TransformWithVariance > T_camFid
Definition: map.h:66
void setData(const T &input)
bool lookupTransform(const std::string &from, const std::string &to, const ros::Time &time, tf2::Transform &T) const
Definition: map.cpp:229
ros::Publisher markerPub
Definition: map.h:98
std::string baseFrame
Definition: map.h:113


fiducial_slam
Author(s): Jim Vaughan
autogenerated on Tue Jun 1 2021 03:03:29