tango_ros_nodelet.cpp
Go to the documentation of this file.
1 // Copyright 2016 Intermodalics All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
18 
19 #include <cmath>
20 #include <ctime>
21 #include <iostream>
22 #include <vector>
23 #include <sstream>
24 
25 #include <glog/logging.h>
26 
27 #include <dynamic_reconfigure/config_tools.h>
28 #include <dynamic_reconfigure/server.h>
29 #include <geometry_msgs/PoseStamped.h>
32 #include <std_msgs/Int8.h>
34 
36 
37 namespace {
38 std::vector<std::string> SplitCommaSeparatedString(const std::string& comma_separated_string) {
39  std::vector<std::string> output;
40  std::stringstream ss(comma_separated_string);
41 
42  std::string string_element;
43  while (std::getline(ss, string_element, ',')) {
44  output.push_back(string_element);
45  }
46  return output;
47 }
48 // This function routes onPoseAvailable callback to the application object for
49 // handling.
50 // @param context, context will be a pointer to a TangoRosNodelet
51 // instance on which to call the callback.
52 // @param pose, pose data to route to onPoseAvailable function.
53 void OnPoseAvailableRouter(void* context, const TangoPoseData* pose) {
55  static_cast<tango_ros_native::TangoRosNodelet*>(context);
56  app->OnPoseAvailable(pose);
57 }
58 // This function routes onPointCloudAvailable callback to the application
59 // object for handling.
60 // @param context, context will be a pointer to a TangoRosNodelet
61 // instance on which to call the callback.
62 // @param point_cloud, point cloud data to route to OnPointCloudAvailable
63 // function.
64 void OnPointCloudAvailableRouter(void* context,
65  const TangoPointCloud* point_cloud) {
67  static_cast<tango_ros_native::TangoRosNodelet*>(context);
68  app->OnPointCloudAvailable(point_cloud);
69 }
70 // This function routes OnFrameAvailable callback to the application
71 // object for handling.
72 // @param context, context will be a pointer to a TangoRosNodelet
73 // instance on which to call the callback.
74 // @param camera_id, the ID of the camera. Only TANGO_CAMERA_COLOR and
75 // TANGO_CAMERA_FISHEYE are supported.
76 // @param buffer, image data to route to OnFrameAvailable function.
77 void OnFrameAvailableRouter(void* context, TangoCameraId camera_id,
78  const TangoImageBuffer* buffer) {
80  static_cast<tango_ros_native::TangoRosNodelet*>(context);
81  app->OnFrameAvailable(camera_id, buffer);
82 }
83 
84 // Compute fisheye distorted coordinates from undistorted coordinates.
85 // The distortion model used by the Tango fisheye camera is called FOV and is
86 // described in 'Straight lines have to be straight' by Frederic Devernay and
87 // Olivier Faugeras. See https://hal.inria.fr/inria-00267247/document.
88 void ApplyFovModel(
89  double xu, double yu, double w, double w_inverse, double two_tan_w_div_two,
90  double* xd, double* yd) {
91  double ru = sqrt(xu * xu + yu * yu);
92  constexpr double epsilon = 1e-7;
93  if (w < epsilon || ru < epsilon) {
94  *xd = xu;
95  *yd = yu ;
96  } else {
97  double rd_div_ru = std::atan(ru * two_tan_w_div_two) * w_inverse / ru;
98  *xd = xu * rd_div_ru;
99  *yd = yu * rd_div_ru;
100  }
101 }
102 // Compute the warp maps to undistort the Tango fisheye image using the FOV
103 // model. See OpenCV documentation for more information on warp maps:
104 // http://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html
105 // @param fisheye_camera_info the fisheye camera intrinsics.
106 // @param cv_warp_map_x the output map for the x direction.
107 // @param cv_warp_map_y the output map for the y direction.
108 void ComputeWarpMapsToRectifyFisheyeImage(
109  const sensor_msgs::CameraInfo& fisheye_camera_info,
110  cv::Mat* cv_warp_map_x, cv::Mat* cv_warp_map_y) {
111  const double fx = fisheye_camera_info.K[0];
112  const double fy = fisheye_camera_info.K[4];
113  const double cx = fisheye_camera_info.K[2];
114  const double cy = fisheye_camera_info.K[5];
115  const double w = fisheye_camera_info.D[0];
116  // Pre-computed variables for more efficiency.
117  const double fy_inverse = 1.0 / fy;
118  const double fx_inverse = 1.0 / fx;
119  const double w_inverse = 1 / w;
120  const double two_tan_w_div_two = 2.0 * std::tan(w * 0.5);
121  // Compute warp maps in x and y directions.
122  // OpenCV expects maps from dest to src, i.e. from undistorted to distorted
123  // pixel coordinates.
124  for(int iu = 0; iu < fisheye_camera_info.height; ++iu) {
125  for (int ju = 0; ju < fisheye_camera_info.width; ++ju) {
126  double xu = (ju - cx) * fx_inverse;
127  double yu = (iu - cy) * fy_inverse;
128  double xd, yd;
129  ApplyFovModel(xu, yu, w, w_inverse, two_tan_w_div_two, &xd, &yd);
130  double jd = cx + xd * fx;
131  double id = cy + yd * fy;
132  cv_warp_map_x->at<float>(iu, ju) = jd;
133  cv_warp_map_y->at<float>(iu, ju) = id;
134  }
135  }
136 }
137 // Returns a string corresponding to current date and time.
138 // The format is as follow: year-month-day_hour-min-sec.
139 std::string GetCurrentDateAndTime() {
140  std::time_t currentTime;
141  struct tm* currentDateTime;
142  std::time(&currentTime);
143  currentDateTime = std::localtime(&currentTime);
144  int day = currentDateTime->tm_mday;
145  int month = currentDateTime->tm_mon + 1;
146  int year = currentDateTime->tm_year + 1900;
147  int hour = currentDateTime->tm_hour;
148  int min = currentDateTime->tm_min;
149  int sec = currentDateTime->tm_sec;
150  std::ostringstream oss;
151  oss << year << "-" << month << "-" << day << "_" << hour << "-" << min << "-" << sec;
152  return oss.str();
153 }
154 // Returns device boottime in second.
155 double GetBootTimeInSecond() {
156  struct timespec res_boot;
157  clock_gettime(CLOCK_BOOTTIME, &res_boot);
158  return res_boot.tv_sec + (double) res_boot.tv_nsec / 1e9;
159 }
160 // Save an Area Description File (ADF) and set its name.
161 // @param map_name Name of the ADF
162 // @param[out] map_uuid Uuid of the ADF.
163 // @param[out] message Contains an error message in case of failure.
164 // Returns true if the ADF was successfully saved and named, false otherwise.
165 bool SaveTangoAreaDescription(const std::string& map_name,
166  std::string& map_uuid, std::string& message) {
167  TangoErrorType result;
168  TangoUUID map_tango_uuid;
169  result = TangoService_saveAreaDescription(&map_tango_uuid);
170  if (result != TANGO_SUCCESS) {
171  LOG(ERROR) << "Error while saving area description, error: " << result;
172  message = "Could not save the map. "
173  "Did you allow the app to use area learning?";
174  return false;
175  }
177  result = TangoService_getAreaDescriptionMetadata(map_tango_uuid, &metadata);
178  if (result != TANGO_SUCCESS) {
179  LOG(ERROR) << "Error while trying to access area description metadata, error: " << result;
180  message = "Could not access map metadata";
181  return false;
182  }
183  result = TangoAreaDescriptionMetadata_set(metadata, "name", map_name.capacity(), map_name.c_str());
184  if (result != TANGO_SUCCESS) {
185  LOG(ERROR) << "Error while trying to change area description metadata, error: " << result;
186  message = "Could not set the name of the map";
187  return false;
188  }
189  result = TangoService_saveAreaDescriptionMetadata(map_tango_uuid, metadata);
190  if (result != TANGO_SUCCESS) {
191  LOG(ERROR) << "Error while saving new area description metadata, error: " << result;
192  message = "Could not save map metadata";
193  return false;
194  }
195  result = TangoAreaDescriptionMetadata_free(metadata);
196  if (result != TANGO_SUCCESS) {
197  LOG(ERROR) << "Error while trying to free area description metadata, error: " << result;
198  message = "Could not free map metadata";
199  return false;
200  }
201  map_uuid = static_cast<std::string>(map_tango_uuid);
202  return true;
203 }
204 // Get the uuid of the ADF currently used by Tango.
205 // @param tango_config Current configuration of Tango.
206 // @param[out] adf_uuid Uuid of the current ADF, empty if Tango
207 // is not using an ADF for localization.
208 bool GetCurrentADFUuid(const TangoConfig& tango_config, std::string& adf_uuid) {
209  char current_adf_uuid[TANGO_UUID_LEN];
210  const char* config_load_area_description_UUID = "config_load_area_description_UUID";
212  tango_config, config_load_area_description_UUID, current_adf_uuid,
213  TANGO_UUID_LEN);
214  if (result != TANGO_SUCCESS) {
215  LOG(ERROR) << "TangoConfig_getString "
216  << config_load_area_description_UUID << " error: " << result;
217  return false;
218  }
219  adf_uuid = std::string(current_adf_uuid);
220  return true;
221 }
222 
223 template<typename T>
224 void SetDefaultValueIfParamDoesNotExist(
225  const ros::NodeHandle& node_handle, const std::string& param_name,
226  T default_value) {
227  if (!node_handle.hasParam(param_name)) {
228  node_handle.setParam(param_name, default_value);
229  }
230 }
231 template<typename T>
232 void GetParamValueAndSetDefaultValueIfParamDoesNotExist(
233  const ros::NodeHandle& node_handle, const std::string& param_name,
234  T default_value, T& param_value) {
235  if (node_handle.hasParam(param_name)) {
236  node_handle.getParam(param_name, param_value);
237  } else {
238  param_value = default_value;
239  node_handle.setParam(param_name, default_value);
240  }
241 }
242 
243 void InvertTransformStamped(const geometry_msgs::TransformStamped& a_T_b,
244  geometry_msgs::TransformStamped* b_T_a) {
245  geometry_msgs::Transform a_T_b_msg = a_T_b.transform;
246  tf2::Transform a_T_b_tf;
247  tf2::fromMsg(a_T_b_msg, a_T_b_tf);
248  tf2::Transform b_T_a_tf = a_T_b_tf.inverse();
249  geometry_msgs::Transform b_T_a_msg = tf2::toMsg(b_T_a_tf);
250  b_T_a->transform = b_T_a_msg;
251  b_T_a->header = a_T_b.header;
252  b_T_a->header.frame_id = a_T_b.child_frame_id;
253  b_T_a->child_frame_id = a_T_b.header.frame_id;
254 }
255 } // namespace
256 
257 namespace tango_ros_native {
258 TangoRosNodelet::TangoRosNodelet() : run_threads_(false), tango_config_(nullptr),
259  t3dr_context_(nullptr), point_cloud_manager_(nullptr),
260  image_buffer_manager_(nullptr), new_point_cloud_available_for_t3dr_(false) {}
261 
264  const uint32_t queue_size = 1;
265  const bool latching = true;
268  queue_size, latching);
270  node_handle_.advertise<geometry_msgs::TransformStamped>(
271  START_OF_SERVICE_T_DEVICE_TOPIC_NAME, queue_size, latching);
273  node_handle_.advertise<geometry_msgs::TransformStamped>(
274  AREA_DESCRIPTION_T_START_OF_SERVICE_TOPIC_NAME, queue_size, latching);
275 
277 
278  static_occupancy_grid_publisher_ = node_handle_.advertise<nav_msgs::OccupancyGrid>(
279  STATIC_OCCUPANCY_GRID_TOPIC_NAME, queue_size, latching);
280 
281  get_map_name_service_ = node_handle_.advertiseService<tango_ros_messages::GetMapName::Request,
282  tango_ros_messages::GetMapName::Response>(GET_MAP_NAME_SERVICE_NAME,
283  boost::bind(&TangoRosNodelet::GetMapNameServiceCallback, this, _1, _2));
284 
285  get_map_uuids_service_ = node_handle_.advertiseService<tango_ros_messages::GetMapUuids::Request,
286  tango_ros_messages::GetMapUuids::Response>(GET_MAP_UUIDS_SERVICE_NAME,
287  boost::bind(&TangoRosNodelet::GetMapUuidsServiceCallback, this, _1, _2));
288 
289  save_map_service_ = node_handle_.advertiseService<tango_ros_messages::SaveMap::Request,
290  tango_ros_messages::SaveMap::Response>(SAVE_MAP_SERVICE_NAME,
291  boost::bind(&TangoRosNodelet::SaveMapServiceCallback, this, _1, _2));
292  load_occupancy_grid_service_ = node_handle_.advertiseService<tango_ros_messages::LoadOccupancyGrid::Request,
293  tango_ros_messages::LoadOccupancyGrid::Response>(LOAD_OCCUPANCY_GRID_SERVICE_NAME,
294  boost::bind(&TangoRosNodelet::LoadOccupancyGridServiceCallback, this, _1, _2));
295 
296  tango_connect_service_ = node_handle_.advertiseService<tango_ros_messages::TangoConnect::Request,
297  tango_ros_messages::TangoConnect::Response>(
298  CONNECT_SERVICE_NAME, boost::bind(
300 
302 
303  SetDefaultValueIfParamDoesNotExist(
305  SetDefaultValueIfParamDoesNotExist(
307  SetDefaultValueIfParamDoesNotExist(
309  SetDefaultValueIfParamDoesNotExist(
312  SetDefaultValueIfParamDoesNotExist(
314  SetDefaultValueIfParamDoesNotExist(
316  SetDefaultValueIfParamDoesNotExist(node_handle_,
319  SetDefaultValueIfParamDoesNotExist(node_handle_,
322  SetDefaultValueIfParamDoesNotExist(node_handle_,
325  SetDefaultValueIfParamDoesNotExist(node_handle_,
328  SetDefaultValueIfParamDoesNotExist(node_handle_,
331  SetDefaultValueIfParamDoesNotExist(node_handle_,
334  SetDefaultValueIfParamDoesNotExist(
336  GetParamValueAndSetDefaultValueIfParamDoesNotExist(
338  GetParamValueAndSetDefaultValueIfParamDoesNotExist(
340  GetParamValueAndSetDefaultValueIfParamDoesNotExist(
342  GetParamValueAndSetDefaultValueIfParamDoesNotExist(
344  GetParamValueAndSetDefaultValueIfParamDoesNotExist(
346  int t3dr_occupancy_grid_threshold =
348  GetParamValueAndSetDefaultValueIfParamDoesNotExist(node_handle_,
350  static_cast<int>(
352  t3dr_occupancy_grid_threshold);
353  t3dr_occupancy_grid_threshold_ = t3dr_occupancy_grid_threshold;
354  GetParamValueAndSetDefaultValueIfParamDoesNotExist(
358  GetParamValueAndSetDefaultValueIfParamDoesNotExist(
362 }
363 
365  TangoDisconnect();
366 }
367 
369  const uint32_t queue_size = 1;
370  const bool latching = true;
371  // Advertise topics that need depth camera and/or color camera only if cameras are enable.
372  if (enable_depth_) {
374  node_handle_.advertise<sensor_msgs::PointCloud2>(
375  POINT_CLOUD_TOPIC_NAME, queue_size, latching);
377  node_handle_.advertise<sensor_msgs::LaserScan>(
378  LASER_SCAN_TOPIC_NAME, queue_size, latching);
379  } else {
382  }
383  if (enable_color_camera_) {
384  try {
386  image_transport_->advertiseCamera(COLOR_IMAGE_TOPIC_NAME,
387  queue_size, latching);
390  queue_size, latching);
391  } catch (const image_transport::Exception& e) {
392  LOG(ERROR) << "Error while creating color image transport publishers" << e.what();
393  return TANGO_ERROR;
394  }
395  } else {
398  }
400  if (enable_depth_ && enable_color_camera_ && enable_3dr_mesh_) {
402  node_handle_.advertise<visualization_msgs::MarkerArray>(
403  COLOR_MESH_TOPIC_NAME, queue_size, latching);
404  } else {
406  }
408  if (enable_depth_ && enable_color_camera_ && enable_3dr_occupancy_grid_){
409  occupancy_grid_publisher_ = node_handle_.advertise<nav_msgs::OccupancyGrid>(
410  OCCUPANCY_GRID_TOPIC_NAME, queue_size, latching);
411  } else {
413  }
415  try {
418  queue_size, latching);
421  queue_size, latching);
422  } catch (const image_transport::Exception& e) {
423  LOG(ERROR) << "Error while creating fisheye image transport publishers" << e.what();
424  return TANGO_ERROR;
425  }
426  } else {
429  }
430 
434  TangoPoseData pose;
435  time_t current_time = time(NULL);
436  time_t end = current_time + 10;
437  while (current_time < end) {
438  TangoService_getPoseAtTime(0.0, pair, &pose);
439  if (pose.status_code == TANGO_POSE_VALID) {
440  break;
441  }
442  sleep(1);
443  current_time = time(NULL);
444  }
445  if (pose.status_code != TANGO_POSE_VALID) {
446  LOG(ERROR) << "Error, could not get a first valid pose.";
448  return TANGO_INVALID;
449  }
450  time_offset_ = ros::Time::now().toSec() - GetBootTimeInSecond();
451 
452  TangoCameraIntrinsics tango_camera_intrinsics;
453  TangoService_getCameraIntrinsics(TANGO_CAMERA_FISHEYE, &tango_camera_intrinsics);
456  fisheye_camera_info_manager_->setCameraName("fisheye_1");
457  // Cache warp maps for more efficiency.
458  cv_warp_map_x_.create(fisheye_camera_info_.height, fisheye_camera_info_.width, CV_32FC1);
459  cv_warp_map_y_.create(fisheye_camera_info_.height, fisheye_camera_info_.width, CV_32FC1);
460  ComputeWarpMapsToRectifyFisheyeImage(fisheye_camera_info_, &cv_warp_map_x_, &cv_warp_map_y_);
461  fisheye_image_rect_.create(fisheye_camera_info_.height, fisheye_camera_info_.width, CV_8UC1);
462 
463  TangoService_getCameraIntrinsics(TANGO_CAMERA_COLOR, &tango_camera_intrinsics);
466  color_camera_info_manager_->setCameraName("color_1");
467  // Cache camera model for more efficiency.
469 
470  if (enable_3dr_mesh_ || enable_3dr_occupancy_grid_) {
472  tango_camera_intrinsics, &t3dr_color_camera_intrinsics_);
475  }
476  return TANGO_SUCCESS;
477 }
478 
480  const char* function_name = "TangoRosNodelet::TangoSetupConfig()";
481 
483  if (tango_config_ == nullptr) {
484  LOG(ERROR) << function_name << ", TangoService_getConfig error.";
485  return TANGO_ERROR;
486  }
487 
488  TangoErrorType result;
489  const char* config_enable_motion_tracking = "config_enable_motion_tracking";
490  result = TangoConfig_setBool(tango_config_, config_enable_motion_tracking, true);
491  if(result != TANGO_SUCCESS) {
492  LOG(ERROR) << function_name << ", TangoConfig_setBool "
493  << config_enable_motion_tracking << " error: " << result;
494  return result;
495  }
496  bool create_new_map;
497  node_handle_.param(CREATE_NEW_MAP_PARAM_NAME, create_new_map, false);
498  const char* config_enable_learning_mode = "config_enable_learning_mode";
499  result = TangoConfig_setBool(tango_config_, config_enable_learning_mode, create_new_map);
500  if (result != TANGO_SUCCESS) {
501  LOG(ERROR) << function_name << ", TangoConfig_setBool "
502  << config_enable_learning_mode << " error: " << result;
503  return result;
504  }
505  if (!create_new_map) {
506  bool enable_drift_correction = false;
507  int localization_mode;
510  if (localization_mode == LocalizationMode::ONLINE_SLAM) {
511  enable_drift_correction = true;
512  }
513  const char* config_enable_drift_correction = "config_enable_drift_correction";
514  result = TangoConfig_setBool(tango_config_, config_enable_drift_correction, enable_drift_correction);
515  if (result != TANGO_SUCCESS) {
516  LOG(ERROR) << function_name << ", TangoConfig_setBool "
517  << config_enable_drift_correction << " error: " << result;
518  return result;
519  }
520  if (localization_mode == LocalizationMode::LOCALIZATION) {
521  std::string map_uuid_to_load = "";
522  node_handle_.param<std::string>(LOCALIZATION_MAP_UUID_PARAM_NAME, map_uuid_to_load, "");
523  const char* config_load_area_description_UUID = "config_load_area_description_UUID";
524  result = TangoConfig_setString(tango_config_, config_load_area_description_UUID, map_uuid_to_load.c_str());
525  if (result != TANGO_SUCCESS) {
526  LOG(ERROR) << function_name << ", TangoConfig_setString "
527  << config_load_area_description_UUID << " error: " << result;
528  return result;
529  }
530  }
531  }
532  const char* config_enable_auto_recovery = "config_enable_auto_recovery";
533  result = TangoConfig_setBool(tango_config_, config_enable_auto_recovery, true);
534  if (result != TANGO_SUCCESS) {
535  LOG(ERROR) << function_name << ", TangoConfig_setBool "
536  << config_enable_auto_recovery << " error: " << result;
537  return result;
538  }
539  const char* config_enable_depth = "config_enable_depth";
541  result = TangoConfig_setBool(tango_config_, config_enable_depth, enable_depth_);
542  if (result != TANGO_SUCCESS) {
543  LOG(ERROR) << function_name << ", TangoConfig_setBool "
544  << config_enable_depth << " error: " << result;
545  return result;
546  }
547  const char* config_depth_mode = "config_depth_mode";
548  result = TangoConfig_setInt32(tango_config_, config_depth_mode, TANGO_POINTCLOUD_XYZC);
549  if (result != TANGO_SUCCESS) {
550  LOG(ERROR) << function_name << ", TangoConfig_setInt "
551  << config_depth_mode << " error: " << result;
552  return result;
553  }
554  const char* config_enable_color_camera = "config_enable_color_camera";
556  result = TangoConfig_setBool(tango_config_, config_enable_color_camera, enable_color_camera_);
557  if (result != TANGO_SUCCESS) {
558  LOG(ERROR) << function_name << ", TangoConfig_setBool "
559  << config_enable_color_camera << " error: " << result;
560  return result;
561  }
562  std::string datasets_path;
564  const char* config_datasets_path = "config_datasets_path";
565  result = TangoConfig_setString(tango_config_, config_datasets_path, datasets_path.c_str());
566  if (result != TANGO_SUCCESS) {
567  LOG(ERROR) << function_name << ", TangoConfig_setString "
568  << config_datasets_path << " error: " << result;
569  return result;
570  }
571  std::string dataset_uuid;
572  node_handle_.param(DATASET_UUID_PARAM_NAME, dataset_uuid, std::string(""));
573  const char* config_experimental_load_dataset_UUID = "config_experimental_load_dataset_UUID";
574  result = TangoConfig_setString(tango_config_, config_experimental_load_dataset_UUID, dataset_uuid.c_str());
575  if (result != TANGO_SUCCESS) {
576  LOG(ERROR) << function_name << ", TangoConfig_setString "
577  << config_experimental_load_dataset_UUID << " error: " << result;
578  return result;
579  }
580  if (point_cloud_manager_ == nullptr) {
581  int32_t max_point_cloud_elements;
582  const char* config_max_point_cloud_elements = "max_point_cloud_elements";
583  result = TangoConfig_getInt32(tango_config_, config_max_point_cloud_elements,
584  &max_point_cloud_elements);
585  if (result != TANGO_SUCCESS) {
586  LOG(ERROR) << function_name << ", Failed to query maximum number of point cloud elements.";
587  return result;
588  }
589  result = TangoSupport_createPointCloudManager(max_point_cloud_elements, &point_cloud_manager_);
590  if (result != TANGO_SUCCESS) {
591  LOG(ERROR) << function_name << ", Failed to create point cloud manager.";
592  return result;
593  }
594  }
595  return TANGO_SUCCESS;
596 }
597 
599  const char* function_name = "TangoRosNodelet::TangoConnect()";
600 
601  TangoCoordinateFramePair pairs[2] = {
606  TangoErrorType result =
607  TangoService_connectOnPoseAvailable(2, pairs, OnPoseAvailableRouter);
608  if (result != TANGO_SUCCESS) {
609  LOG(ERROR) << function_name
610  << ", TangoService_connectOnPoseAvailable error: " << result;
611  return result;
612  }
613 
614  result = TangoService_connectOnPointCloudAvailable(OnPointCloudAvailableRouter);
615  if (result != TANGO_SUCCESS) {
616  LOG(ERROR) << function_name
617  << ", TangoService_connectOnPointCloudAvailable error: " << result;
618  return result;
619  }
620 
621  int android_api_level;
622  node_handle_.param("android_api_level", android_api_level, 0);
623  if (android_api_level < 24) {
625  TANGO_CAMERA_FISHEYE, this, OnFrameAvailableRouter);
626  if (result != TANGO_SUCCESS) {
627  LOG(ERROR) << function_name
628  << ", TangoService_connectOnFrameAvailable TANGO_CAMERA_FISHEYE error: " << result;
629  return result;
630  }
631  } else {
632  LOG(WARNING) << "Android API Level is 24 or more, Fisheye camera data is not available";
634  }
635 
637  TANGO_CAMERA_COLOR, this, OnFrameAvailableRouter);
638  if (result != TANGO_SUCCESS) {
639  LOG(ERROR) << function_name
640  << ", TangoService_connectOnFrameAvailable TANGO_CAMERA_COLOR error: " << result;
641  return result;
642  }
643 
644  result = TangoService_connect(this, tango_config_);
645  if (result != TANGO_SUCCESS) {
646  LOG(ERROR) << function_name << ", TangoService_connect error: " << result;
647  return result;
648  }
649  return TANGO_SUCCESS;
650 }
651 
653  tango_status_ = status;
654  std_msgs::Int8 tango_status_msg;
655  tango_status_msg.data = static_cast<int>(tango_status_);
656  tango_status_publisher_.publish(tango_status_msg);
657 }
658 
661  // Connecting twice to Tango results in TANGO_ERROR. Early return to avoid
662  // this.
663  LOG(WARNING) << "Already connected to Tango service.";
665  return TANGO_SUCCESS;
666  }
668 
669  TangoErrorType success;
670  // Setup config.
671  success = TangoSetupConfig();
672  // Early return if config setup failed.
673  if (success != TANGO_SUCCESS) {
675  return success;
676  }
677  // Connect to Tango.
678  success = TangoConnect();
679  // Early return if Tango connect call failed.
680  if (success != TANGO_SUCCESS) {
682  return success;
683  }
684  // Publish static transforms.
687  success = OnTangoServiceConnected();
688  if (success != TANGO_SUCCESS) {
689  return success;
690  }
691  area_description_T_start_of_service_.child_frame_id = "";
692  tango_data_available_ = true;
693  // Create publishing threads.
694  StartPublishing();
696  return success;
697 }
698 
700  StopPublishing();
701  if (tango_config_ != nullptr) {
703  tango_config_ = nullptr;
704  }
705  if (point_cloud_manager_ != nullptr) {
707  point_cloud_manager_ = nullptr;
708  }
709  if (image_buffer_manager_ != nullptr) {
711  image_buffer_manager_ = nullptr;
712  }
713  if (t3dr_context_ != nullptr) {
716  t3dr_context_ = nullptr;
717  }
720 }
721 
723  std::vector<geometry_msgs::TransformStamped> tf_transforms;
724  tf_transforms.reserve(NUMBER_OF_STATIC_TRANSFORMS);
726  TangoPoseData pose;
727 
730  TangoService_getPoseAtTime(0.0, pair, &pose);
731  geometry_msgs::TransformStamped device_T_imu;
733  pose, time_offset_,
736  &device_T_imu);
737  tf_transforms.push_back(device_T_imu);
738 
741  TangoService_getPoseAtTime(0.0, pair, &pose);
743  pose, time_offset_,
747  tf_transforms.push_back(device_T_camera_depth_);
748 
749  // According to the ROS documentation, laser scan angles are measured around
750  // the Z-axis in the laser scan frame. To follow this convention the laser
751  // scan frame has to be rotated of 90 degrees around x axis with respect to
752  // the Tango point cloud frame.
754  tf::Transform(tf::Quaternion(1 / sqrt(2), 0, 0, 1 / sqrt(2))), ros::Time::now(),
757  geometry_msgs::TransformStamped camera_depth_T_laser_message;
758  tf::transformStampedTFToMsg(camera_depth_T_laser_, camera_depth_T_laser_message);
759  tf_transforms.push_back(camera_depth_T_laser_message);
760 
763  TangoService_getPoseAtTime(0.0, pair, &pose);
765  pose, time_offset_,
769  tf_transforms.push_back(device_T_camera_fisheye_);
770 
773  TangoService_getPoseAtTime(0.0, pair, &pose);
775  pose, time_offset_,
779  tf_transforms.push_back(device_T_camera_color_);
780 
781  if (use_tf_static_) {
782  tf_static_broadcaster_.sendTransform(tf_transforms);
783  } else {
784  tf_broadcaster_.sendTransform(tf_transforms);
785  }
786 }
787 
791  if (pose->status_code == TANGO_POSE_VALID &&
798  device_pose_thread_.data_available.notify_all();
799  }
800  } else if (pose->frame.base == TANGO_COORDINATE_FRAME_AREA_DESCRIPTION &&
802  if (pose->status_code == TANGO_POSE_VALID &&
808  device_pose_thread_.data_available.notify_all();
809  }
810  }
811 }
812 
814  if (point_cloud->num_points > 0) {
818  &point_cloud_);
819  point_cloud_.header.frame_id =
822  point_cloud_thread_.data_available.notify_all();
823  }
826  laser_scan_.angle_min = LASER_SCAN_ANGLE_MIN;
827  laser_scan_.angle_max = LASER_SCAN_ANGLE_MAX;
828  laser_scan_.angle_increment = LASER_SCAN_ANGLE_INCREMENT;
829  laser_scan_.time_increment = LASER_SCAN_TIME_INCREMENT;
830  laser_scan_.scan_time = LASER_SCAN_SCAN_TIME;
833  // Determine amount of rays to create.
834  uint32_t ranges_size = std::ceil((laser_scan_.angle_max - laser_scan_.angle_min)
835  / laser_scan_.angle_increment);
836  // Laser scan rays with no obstacle data will evaluate to infinity.
837  laser_scan_.ranges.assign(ranges_size, std::numeric_limits<double>::infinity());
841  laser_scan_.header.frame_id = LASER_SCAN_FRAME_ID;
843  laser_scan_thread_.data_available.notify_all();
844  }
845 
850  TangoPoseData start_of_service_T_camera_depth;
851  TangoService_getPoseAtTime(point_cloud->timestamp, pair, &start_of_service_T_camera_depth);
852  if (start_of_service_T_camera_depth.status_code != TANGO_POSE_VALID) {
853  LOG(WARNING) << "Could not find a valid pose at time "
854  << point_cloud->timestamp << " for the depth camera.";
855  return;
856  }
857  tango_ros_conversions_helper::toTango3DR_Pose(start_of_service_T_camera_depth,
861  }
862  }
863 }
864 
869  fisheye_image_ = cv::Mat(buffer->height + buffer->height / 2, buffer->width,
870  CV_8UC1, buffer->data, buffer->stride); // No deep copy.
871  fisheye_image_header_.stamp.fromSec(buffer->timestamp + time_offset_);
872  fisheye_image_header_.seq = buffer->frame_number;
873  fisheye_image_header_.frame_id =
877  }
879  camera_id == TangoCameraId::TANGO_CAMERA_COLOR &&
881  color_image_ = cv::Mat(buffer->height + buffer->height / 2, buffer->width,
882  CV_8UC1, buffer->data, buffer->stride); // No deep copy.
883  color_image_header_.stamp.fromSec(buffer->timestamp + time_offset_);
884  color_image_header_.seq = buffer->frame_number;
885  color_image_header_.frame_id =
888  color_image_thread_.data_available.notify_all();
889  }
890 
892  camera_id == TangoCameraId::TANGO_CAMERA_COLOR &&
894  mesh_thread_.data_available_mutex.try_lock()) {
895  if (image_buffer_manager_ == nullptr) {
897  buffer->format, buffer->width, buffer->height, &image_buffer_manager_);
898  if (result != TANGO_SUCCESS) {
899  LOG(ERROR) << "Failed to create image buffer manager.";
900  return;
901  }
902  }
906  TangoPoseData start_of_service_T_camera_color;
907  TangoService_getPoseAtTime(buffer->timestamp, pair, &start_of_service_T_camera_color);
908  if (start_of_service_T_camera_color.status_code != TANGO_POSE_VALID) {
909  LOG(WARNING) << "Could not find a valid pose at time "
910  << buffer->timestamp << " for the color camera.";
911  return;
912  }
913  tango_ros_conversions_helper::toTango3DR_Pose(start_of_service_T_camera_color,
918  mesh_thread_.data_available.notify_all();
919  }
920 }
921 
923  run_threads_ = true;
925  std::thread(&TangoRosNodelet::PublishDevicePose, this);
927  std::thread(&TangoRosNodelet::PublishPointCloud, this);
929  std::thread(&TangoRosNodelet::PublishLaserScan, this);
931  std::thread(&TangoRosNodelet::PublishFisheyeImage, this);
933  std::thread(&TangoRosNodelet::PublishColorImage, this);
935  std::thread(&TangoRosNodelet::PublishMesh, this);
936  ros_spin_thread_ = std::thread(&TangoRosNodelet::RunRosSpin, this);
937 }
938 
940  if (run_threads_) {
941  run_threads_ = false;
942  if (device_pose_thread_.publish_thread.joinable()) {
943  if (!tango_data_available_) {
944  device_pose_thread_.data_available.notify_all();
945  }
947  }
948  if (point_cloud_thread_.publish_thread.joinable()) {
951  point_cloud_thread_.data_available.notify_all();
952  }
954  }
955  if (laser_scan_thread_.publish_thread.joinable()) {
958  laser_scan_thread_.data_available.notify_all();
959  }
961  }
962  if (fisheye_image_thread_.publish_thread.joinable()) {
966  }
968  }
969  if (color_image_thread_.publish_thread.joinable()) {
972  color_image_thread_.data_available.notify_all();
973  }
975  }
976  if (mesh_thread_.publish_thread.joinable()) {
979  mesh_thread_.data_available.notify_all();
980  }
982  }
983  ros_spin_thread_.join();
984  }
985 }
986 
988  while(ros::ok()) {
989  if (!run_threads_) {
990  break;
991  }
992  {
993  std::unique_lock<std::mutex> lock(device_pose_thread_.data_available_mutex);
995  if (!use_tf_static_) {
997  }
998  if (publish_pose_on_tf_) {
1000  if (area_description_T_start_of_service_.child_frame_id != "") {
1001  // This transform can be empty. Don't publish it in this case.
1003  }
1004  }
1007  }
1009  area_description_T_start_of_service_.child_frame_id != "") {
1010  // This transform can be empty. Don't publish it in this case.
1012  }
1013  }
1014  }
1015 }
1016 
1018  while(ros::ok()) {
1019  if (!run_threads_) {
1020  break;
1021  }
1022  {
1023  std::unique_lock<std::mutex> lock(point_cloud_thread_.data_available_mutex);
1027  }
1028  }
1029  }
1030 }
1031 
1033  while(ros::ok()) {
1034  if (!run_threads_) {
1035  break;
1036  }
1037  {
1038  std::unique_lock<std::mutex> lock(laser_scan_thread_.data_available_mutex);
1042  }
1043  }
1044  }
1045 }
1046 
1048  while(ros::ok()) {
1049  if (!run_threads_) {
1050  break;
1051  }
1052  {
1053  std::unique_lock<std::mutex> lock(fisheye_image_thread_.data_available_mutex);
1057  // The Tango image encoding is not supported by ROS.
1058  // We need to convert it to gray.
1059  cv::Mat fisheye_image_gray;
1060  cv::cvtColor(fisheye_image_, fisheye_image_gray, cv::COLOR_YUV420sp2GRAY);
1061  cv_bridge::CvImage cv_bridge_fisheye_image;
1062  cv_bridge_fisheye_image.header = fisheye_image_header_;
1063  cv_bridge_fisheye_image.encoding = sensor_msgs::image_encodings::MONO8;
1064  cv_bridge_fisheye_image.image = fisheye_image_gray;
1067  sensor_msgs::Image fisheye_image_msg;
1068  cv_bridge_fisheye_image.toImageMsg(fisheye_image_msg);
1070 
1072  cv::remap(fisheye_image_gray, fisheye_image_rect_, cv_warp_map_x_,
1073  cv_warp_map_y_, cv::INTER_LINEAR, cv::BORDER_CONSTANT, 0);
1074  sensor_msgs::ImagePtr image_rect = cv_bridge::CvImage(
1075  cv_bridge_fisheye_image.header, cv_bridge_fisheye_image.encoding,
1078  }
1079  }
1080  }
1081  }
1082 }
1083 
1085  while(ros::ok()) {
1086  if (!run_threads_) {
1087  break;
1088  }
1089  {
1090  std::unique_lock<std::mutex> lock(color_image_thread_.data_available_mutex);
1094  // The Tango image encoding is not supported by ROS.
1095  // We need to convert it to RGB.
1096  cv::Mat color_image_rgb;
1097  cv::cvtColor(color_image_, color_image_rgb, cv::COLOR_YUV420sp2RGBA);
1098  cv_bridge::CvImage cv_bridge_color_image;
1099  cv_bridge_color_image.header = color_image_header_;
1100  cv_bridge_color_image.encoding = sensor_msgs::image_encodings::RGBA8;
1101  cv_bridge_color_image.image = color_image_rgb;
1104  sensor_msgs::Image color_image_msg;
1105  cv_bridge_color_image.toImageMsg(color_image_msg);
1107 
1110  sensor_msgs::ImagePtr image_rect = cv_bridge::CvImage(
1111  cv_bridge_color_image.header, cv_bridge_color_image.encoding,
1114  }
1115  }
1116  }
1117  }
1118 }
1119 
1121  while(ros::ok()) {
1122  if (!run_threads_) {
1123  break;
1124  }
1126  Tango3DR_GridIndexArray t3dr_updated_indices;
1127  // Update Tango mesh with latest point cloud and color image.
1128  {
1129  std::unique_lock<std::mutex> lock(mesh_thread_.data_available_mutex);
1130  mesh_thread_.data_available.wait(lock);
1134  &t3dr_updated_indices);
1135  }
1136  // Publish Tango mesh as visualization marker.
1138  visualization_msgs::MarkerArray mesh_marker_array;
1140  t3dr_context_, t3dr_updated_indices, time_offset_,
1141  start_of_service_frame_id_, &mesh_marker_array);
1142  mesh_marker_publisher_.publish(mesh_marker_array);
1144  &t3dr_updated_indices);
1145  if (result != TANGO_3DR_SUCCESS) {
1146  LOG(ERROR) << "Tango3DR_GridIndexArray_destroy failed with error code: "
1147  << result;
1148  }
1149  if (mesh_marker_array.markers.empty()) {
1150  LOG(INFO) << "Empty mesh array!";
1151  }
1152  }
1153  // Publish Tango mesh as occupancy grid.
1155  occupancy_grid_.data.clear();
1156  // We extract the floor plan and convert it to occupancy grid even if
1157  // there is no subscriber for the occupancy grid topic. That way we
1158  // avoid saving an empty occupancy grid.
1164  }
1165  }
1166  }
1167 }
1168 
1169 void TangoRosNodelet::DynamicReconfigureCallback(PublisherConfig &config, uint32_t level) {
1170  laser_scan_max_height_ = config.laser_scan_max_height;
1171  laser_scan_min_height_ = config.laser_scan_min_height;
1172  laser_scan_min_range_ = config.laser_scan_min_range;
1173  laser_scan_max_range_ = config.laser_scan_max_range;
1174  LOG(INFO) << "laser_scan_min_height [m]: " << laser_scan_min_height_ << std::endl;
1175  LOG(INFO) << "laser_scan_max_height [m]: " << laser_scan_max_height_ << std::endl;
1176  LOG(INFO) << "laser_scan_min_range [m]: " << laser_scan_min_range_ << std::endl;
1177  LOG(INFO) << "laser_scan_max_range [m]: " << laser_scan_max_range_ << std::endl;
1178 }
1179 
1181  dynamic_reconfigure::Server<tango_ros_native::PublisherConfig> server;
1182  dynamic_reconfigure::Server<tango_ros_native::PublisherConfig>::CallbackType callback =
1183  boost::bind(&TangoRosNodelet::DynamicReconfigureCallback, this, _1, _2);
1184  server.setCallback(callback);
1185  while(ros::ok()) {
1186  if (!run_threads_) {
1187  break;
1188  }
1189  ros::spinOnce();
1190  std::this_thread::sleep_for(std::chrono::milliseconds(100));
1191  }
1192 }
1193 
1195  const tango_ros_messages::TangoConnect::Request& request,
1196  tango_ros_messages::TangoConnect::Response& response) {
1197  switch (request.request) {
1198  case tango_ros_messages::TangoConnect::Request::CONNECT:
1199  // Connect to Tango Service.
1200  response.response = ConnectToTangoAndSetUpNode();
1201  break;
1202  case tango_ros_messages::TangoConnect::Request::DISCONNECT:
1203  // Disconnect from Tango Service.
1204  TangoDisconnect();
1206  break;
1207  case tango_ros_messages::TangoConnect::Request::RECONNECT:
1208  // Disconnect and reconnect to Tango Service.
1209  TangoDisconnect();
1210  response.response = ConnectToTangoAndSetUpNode();
1211  break;
1212  default:
1213  LOG(ERROR) << "Did not understand request " << static_cast<int>(request.request)
1214  << ", valid requests are (CONNECT: "
1215  << tango_ros_messages::TangoConnect::Request::CONNECT
1216  << ", DISCONNECT: "
1217  << tango_ros_messages::TangoConnect::Request::DISCONNECT
1218  << ", RECONNECT: "
1219  << tango_ros_messages::TangoConnect::Request::RECONNECT
1220  << ")";
1221  response.message = "Did not understand request.";
1222  return true;
1223  }
1224  return true;
1225 }
1226 
1228  const tango_ros_messages::GetMapName::Request &req,
1229  tango_ros_messages::GetMapName::Response &res) {
1230  return GetMapNameFromUuid(req.map_uuid, res.map_name);
1231 }
1232 
1234  const tango_ros_messages::GetMapUuids::Request& req,
1235  tango_ros_messages::GetMapUuids::Response& res) {
1236  if (!GetAvailableMapUuidsList(res.map_uuids) ) return false;
1237 
1238  res.map_names.resize(res.map_uuids.size());
1239  auto map_uuids_it = res.map_uuids.begin();
1240  auto map_names_it = res.map_names.begin();
1241  for (; map_uuids_it != res.map_uuids.end() && map_names_it != res.map_names.end();
1242  ++map_uuids_it, ++map_names_it) {
1243  if (!GetMapNameFromUuid(*map_uuids_it, *map_names_it)) return false;
1244  }
1245  return true;
1246 }
1247 
1249  const tango_ros_messages::SaveMap::Request& req,
1250  tango_ros_messages::SaveMap::Response& res) {
1251  bool save_localization_map = req.request & tango_ros_messages::SaveMap::Request::SAVE_LOCALIZATION_MAP;
1252  bool save_occupancy_grid = req.request & tango_ros_messages::SaveMap::Request::SAVE_OCCUPANCY_GRID;
1253  res.message = "";
1254  if (save_localization_map) {
1255  res.localization_map_name = req.map_name;
1256  if (!SaveTangoAreaDescription(res.localization_map_name, res.localization_map_uuid, res.message)) {
1257  res.success = false;
1258  return true;
1259  }
1260  tango_data_available_ = false;
1261  res.message += "\nLocalization map " + res.localization_map_uuid +
1262  " successfully saved with name " + res.localization_map_name;
1263  } else if (save_occupancy_grid) {
1264  if (!GetCurrentADFUuid(tango_config_, res.localization_map_uuid)) {
1265  res.message += "\nCould not get current localization map uuid.";
1266  res.success = false;
1267  return true;
1268  }
1269  }
1270  if (save_occupancy_grid) {
1271  std::string occupancy_grid_directory;
1273  occupancy_grid_directory, OCCUPANCY_GRID_DEFAULT_DIRECTORY);
1274  res.occupancy_grid_name = req.map_name;
1275  if (!res.localization_map_uuid.empty()) {
1276  // Save the occupancy grid wrt the area description frame.
1277  geometry_msgs::TransformStamped start_of_service_T_area_description;
1278  InvertTransformStamped(area_description_T_start_of_service_, &start_of_service_T_area_description);
1279  geometry_msgs::PoseStamped stamped_origin;
1280  stamped_origin.header = occupancy_grid_.header;
1281  stamped_origin.pose = occupancy_grid_.info.origin;
1282  geometry_msgs::PoseStamped stamped_origin_in_area_description;
1283  tf2::doTransform(stamped_origin, stamped_origin_in_area_description,
1284  start_of_service_T_area_description);
1285  occupancy_grid_.info.origin = stamped_origin_in_area_description.pose;
1286  occupancy_grid_.info.origin.position.z = 0.;
1287  occupancy_grid_.header.frame_id = area_description_frame_id_;
1288  }
1290  res.occupancy_grid_name, res.localization_map_uuid, occupancy_grid_directory, occupancy_grid_)) {
1291  res.message += "\nCould not save occupancy grid " + res.occupancy_grid_name
1292  + " in directory " + occupancy_grid_directory;
1293  res.success = false;
1294  return true;
1295  }
1296  res.message += "\nOccupancy grid successfully saved with name "
1297  + res.occupancy_grid_name + " in directory " + occupancy_grid_directory;
1298  if (res.localization_map_uuid.empty()) {
1299  res.message += "\nThe occupancy grid has been saved without localization map uuid. "
1300  "This means it will not be aligned when loaded later.";
1301  }
1302  }
1303  res.success = true;
1304  return true;
1305 }
1306 
1307 bool TangoRosNodelet::LoadOccupancyGridServiceCallback(const tango_ros_messages::LoadOccupancyGrid::Request& req,
1308  tango_ros_messages::LoadOccupancyGrid::Response& res) {
1309  nav_msgs::OccupancyGrid occupancy_grid;
1310  std::string occupancy_grid_directory;
1312  occupancy_grid_directory, OCCUPANCY_GRID_DEFAULT_DIRECTORY);
1313 
1314  std::string map_uuid;
1315  res.aligned = true;
1317  req.name, occupancy_grid_directory, &occupancy_grid, &map_uuid)) {
1318  LOG(ERROR) << "Error while loading occupancy grid from file.";
1319  res.message = "Could not load occupancy grid from file " + req.name
1320  + " in directory " + occupancy_grid_directory;
1321  res.aligned = false;
1322  res.success = false;
1323  res.localization_map_uuid = "";
1324  return true;
1325  }
1326  res.localization_map_uuid = map_uuid;
1327  res.message = "Occupancy grid " + req.name + " successfully loaded from " + occupancy_grid_directory;
1328 
1329  std::string current_map_uuid;
1330  if (!GetCurrentADFUuid(tango_config_, current_map_uuid)) {
1331  res.message += "\nCould not get current localization map uuid.";
1332  res.aligned = false;
1333  res.success = false;
1334  return true;
1335  }
1336  if (current_map_uuid.empty()) {
1337  res.message += "\nThe occupancy grid is not aligned because "
1338  "no localization map is currently used.";
1339  res.aligned = false;
1340  }
1341  if (map_uuid.empty()) {
1342  res.message += "\nThe occupancy grid is not aligned because "
1343  "its localization map uuid is empty.";
1344  res.aligned = false;
1345  }
1346  if (map_uuid.compare(current_map_uuid) != 0) {
1347  res.message += "\nThe occupancy grid is not aligned because "
1348  "it does not correspond to the localization map currently used.";
1349  res.aligned = false;
1350  }
1351 
1352  res.success = true;
1353  if (map_uuid.empty()) {
1354  occupancy_grid.header.frame_id = start_of_service_frame_id_;
1355  } else {
1356  occupancy_grid.header.frame_id = area_description_frame_id_;
1357  }
1358  occupancy_grid.header.stamp = ros::Time::now();
1359  occupancy_grid.info.map_load_time = occupancy_grid.header.stamp;
1360  static_occupancy_grid_publisher_.publish(occupancy_grid);
1361  return true;
1362 }
1363 
1364 bool TangoRosNodelet::GetAvailableMapUuidsList(std::vector<std::string>& uuid_list) {
1365  char* c_uuid_list;
1367  if (result != TANGO_SUCCESS) {
1368  LOG(ERROR) << "Error while retrieving all available map UUIDs, error: " << result;
1369  return false;
1370  }
1371  if (c_uuid_list == NULL || c_uuid_list[0] == '\0') {
1372  LOG(WARNING) << "No area description file available.";
1373  return false;
1374  }
1375  LOG(INFO) << "UUID list: " << c_uuid_list;
1376  uuid_list = SplitCommaSeparatedString(std::string(c_uuid_list));
1377  return true;
1378 }
1379 
1380 bool TangoRosNodelet::GetMapNameFromUuid(const std::string& map_uuid, std::string& map_name) {
1381  size_t size = 0;
1382  char* value;
1384  TangoErrorType result = TangoService_getAreaDescriptionMetadata(map_uuid.c_str(), &metadata);
1385  if (result != TANGO_SUCCESS) {
1386  LOG(ERROR) << "Error while trying to access area description metadata, error: " << result;
1387  return false;
1388  }
1389  result = TangoAreaDescriptionMetadata_get(metadata, "name", &size, &value);
1390  if (result != TANGO_SUCCESS) {
1391  LOG(ERROR) << "Error while trying to get area description metadata, error: " << result;
1392  return false;
1393  }
1394  map_name = std::string(value);
1395  result = TangoAreaDescriptionMetadata_free(metadata);
1396  if (result != TANGO_SUCCESS) {
1397  LOG(ERROR) << "Error while trying to free area description metadata, error: " << result;
1398  }
1399  LOG(INFO) << "Successfully retrieved map name: " << map_name << " from uuid " << map_uuid;
1400  return true;
1401 }
1402 } // namespace tango_ros_native
const std::string GET_MAP_UUIDS_SERVICE_NAME
app
TANGO_INVALID
TangoErrorType TangoSupport_freeImageBufferManager(TangoSupport_ImageBufferManager *manager)
void publish(const sensor_msgs::Image &image, const sensor_msgs::CameraInfo &info) const
void ExtractMeshAndConvertToMarkerArray(const Tango3DR_ReconstructionContext &t3dr_context, const Tango3DR_GridIndexArray &t3dr_updated_indices, double time_offset, const std::string &base_frame_id, visualization_msgs::MarkerArray *mesh_marker_array)
char TangoUUID[TANGO_UUID_LEN]
bool LoadOccupancyGridFromFiles(const std::string &map_name, const std::string &map_directory, nav_msgs::OccupancyGrid *occupancy_grid, std::string *map_uuid)
TangoErrorType TangoSupport_createPointCloudManager(size_t max_points, TangoSupport_PointCloudManager **manager)
void toPointCloud2(const TangoPointCloud &tango_point_cloud, double time_offset, sensor_msgs::PointCloud2 *point_cloud)
TangoErrorType TangoService_connectOnFrameAvailable(TangoCameraId id, void *context, void(*onFrameAvailable)(void *context, TangoCameraId id, const TangoImageBuffer *buffer))
void toTango3DR_Pose(const TangoPoseData &tango_pose_data, Tango3DR_Pose *t3dr_pose)
TangoSupport_ImageBufferManager * image_buffer_manager_
int64_t frame_number
const float LASER_SCAN_ANGLE_MIN
ros::Publisher area_description_T_start_of_service_publisher_
void TangoConfig_free(TangoConfig config)
void publish(const boost::shared_ptr< M > &message) const
std::shared_ptr< image_transport::ImageTransport > image_transport_
bool SaveOccupancyGridToFiles(const std::string &map_name, const std::string &map_uuid, const std::string &map_directory, const nav_msgs::OccupancyGrid &occupancy_grid)
image_transport::Publisher fisheye_rectified_image_publisher_
TangoErrorType TangoConfig_getString(TangoConfig config, const char *key, char *value, size_t size)
image_transport::CameraPublisher fisheye_camera_publisher_
TangoErrorType TangoSupport_updatePointCloud(TangoSupport_PointCloudManager *manager, const TangoPointCloud *point_cloud)
const std::string DATASET_DIRECTORY_PARAM_NAME
bool SaveMapServiceCallback(const tango_ros_messages::SaveMap::Request &req, tango_ros_messages::SaveMap::Response &res)
const std::string AREA_DESCRIPTION_FRAME_ID_PARAM_NAME
Tango3DR_Status
uint32_t getNumSubscribers() const
TangoErrorType TangoAreaDescriptionMetadata_get(TangoAreaDescriptionMetadata metadata, const char *key, size_t *value_size, char **value)
TangoErrorType TangoService_connectOnPointCloudAvailable(void(*TangoService_onPointCloudAvailable)(void *context, const TangoPointCloud *cloud),...)
TangoErrorType
const std::string ENABLE_DEPTH_PARAM_NAME
TANGO_CAMERA_COLOR
const std::string OCCUPANCY_GRID_DIRECTORY_PARAM_NAME
const std::string LASER_SCAN_FRAME_ID
const std::string LOCALIZATION_MAP_UUID_PARAM_NAME
std::string encoding
const std::string PUBLISH_POSE_ON_TF_PARAM_NAME
TangoSupport_PointCloudManager * point_cloud_manager_
const std::string ENABLE_COLOR_CAMERA_PARAM_NAME
bool GetMapUuidsServiceCallback(const tango_ros_messages::GetMapUuids::Request &req, tango_ros_messages::GetMapUuids::Response &res)
TangoErrorType TangoService_connectOnPoseAvailable(uint32_t count, const TangoCoordinateFramePair *frames, void(*TangoService_onPoseAvailable)(void *context, const TangoPoseData *pose),...)
void toLaserScan(const TangoPointCloud &tango_point_cloud, double time_offset, double min_height, double max_height, double min_range, double max_range, const tf::Transform &point_cloud_T_laser, sensor_msgs::LaserScan *laser_scan)
Tango3DR_Status Tango3DR_GridIndexArray_destroy(Tango3DR_GridIndexArray *grid_index_array)
image_transport::Publisher color_rectified_image_publisher_
const std::string COLOR_MESH_TOPIC_NAME
const std::string TANGO_3DR_OCCUPANCY_GRID_THRESHOLD_PARAM_NAME
TANGO_ERROR
void TangoService_disconnect()
TangoCoordinateFrameType base
const std::string CONNECT_SERVICE_NAME
bool LoadOccupancyGridServiceCallback(const tango_ros_messages::LoadOccupancyGrid::Request &req, tango_ros_messages::LoadOccupancyGrid::Response &res)
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
const std::string STATIC_OCCUPANCY_GRID_TOPIC_NAME
Tango3DR_Status TangoSetup3DRConfig(const ros::NodeHandle &node_handle, double *t3dr_resolution, Tango3DR_ReconstructionContext *t3dr_context, Tango3DR_CameraCalibration *t3dr_color_camera_intrinsics)
void doTransform(const T &data_in, T &data_out, const geometry_msgs::TransformStamped &transform)
TANGO_COORDINATE_FRAME_CAMERA_COLOR
TANGO_COORDINATE_FRAME_START_OF_SERVICE
Tango3DR_Status Tango3DR_clear(Tango3DR_ReconstructionContext context)
sensor_msgs::PointCloud2 point_cloud_
uint32_t getNumSubscribers() const
#define TANGO_UUID_LEN
std::shared_ptr< camera_info_manager::CameraInfoManager > color_camera_info_manager_
const std::string SAVE_MAP_SERVICE_NAME
const std::string COLOR_IMAGE_TOPIC_NAME
ros::NodeHandle & getMTPrivateNodeHandle() const
nav_msgs::OccupancyGrid occupancy_grid_
TangoErrorType TangoService_getAreaDescriptionUUIDList(char **uuid_list)
TangoCoordinateFramePair frame
TangoCameraId
sensor_msgs::CameraInfo color_camera_info_
void rectifyImage(const cv::Mat &raw, cv::Mat &rectified, int interpolation=cv::INTER_LINEAR) const
const std::string CREATE_NEW_MAP_PARAM_NAME
TangoErrorType TangoConfig_setString(TangoConfig config, const char *key, const char *value)
TangoErrorType TangoAreaDescriptionMetadata_free(TangoAreaDescriptionMetadata metadata)
TangoErrorType TangoService_getAreaDescriptionMetadata(const TangoUUID uuid, TangoAreaDescriptionMetadata *metadata)
const std::string DATASET_DEFAULT_DIRECTORY
geometry_msgs::TransformStamped area_description_T_start_of_service_
const std::string USE_TF_STATIC_PARAM_NAME
Tango3DR_CameraCalibration t3dr_color_camera_intrinsics_
void publish(const sensor_msgs::Image &message) const
TangoErrorType TangoConfig_setBool(TangoConfig config, const char *key, bool value)
void OnPointCloudAvailable(const TangoPointCloud *point_cloud)
TangoErrorType TangoSupport_updateImageBuffer(TangoSupport_ImageBufferManager *manager, const TangoImageBuffer *image_buffer)
geometry_msgs::TransformStamped device_T_camera_depth_
void * TangoAreaDescriptionMetadata
TANGO_POSE_VALID
TANGO_3DR_SUCCESS
bool fromCameraInfo(const sensor_msgs::CameraInfo &msg)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
TANGO_COORDINATE_FRAME_AREA_DESCRIPTION
image_transport::CameraPublisher color_camera_publisher_
TANGO_COORDINATE_FRAME_CAMERA_FISHEYE
TANGO_COORDINATE_FRAME_IMU
TangoErrorType TangoService_getPoseAtTime(double timestamp, TangoCoordinateFramePair frame, TangoPoseData *pose)
TangoImageFormatType format
TANGO_COORDINATE_FRAME_CAMERA_DEPTH
void fromMsg(const A &, B &b)
TANGO_CONFIG_DEFAULT
const float LASER_SCAN_TIME_INCREMENT
double epsilon
bool ExtractFloorPlanImageAndConvertToOccupancyGrid(const Tango3DR_ReconstructionContext &t3dr_context, double time_offset, const std::string &base_frame_id, double t3dr_resolution, uint8_t threshold, nav_msgs::OccupancyGrid *occupancy_grid)
ROSCPP_DECL bool ok()
const std::string TANGO_STATUS_TOPIC_NAME
void sendTransform(const StampedTransform &transform)
Transform inverse() const
TangoErrorType TangoConfig_getInt32(TangoConfig config, const char *key, int32_t *value)
TANGO_POINTCLOUD_XYZC
std::atomic_bool new_point_cloud_available_for_t3dr_
const std::string AREA_DESCRIPTION_T_START_OF_SERVICE_TOPIC_NAME
sensor_msgs::CameraInfo fisheye_camera_info_
const std::string START_OF_SERVICE_T_DEVICE_TOPIC_NAME
void UpdateAndPublishTangoStatus(const TangoStatus &status)
void toTransformStamped(const TangoPoseData &pose, double time_offset, const std::string &base_frame_id, const std::string &target_frame_id, geometry_msgs::TransformStamped *transform)
const std::string GET_MAP_NAME_SERVICE_NAME
std::string toFrameId(const TangoCoordinateFrameType &tango_frame_type)
TangoCoordinateFrameType target
double min(double a, double b)
void OnFrameAvailable(TangoCameraId camera_id, const TangoImageBuffer *buffer)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
TANGO_COORDINATE_FRAME_DEVICE
TANGO_SUCCESS
uint32_t num_points
const float LASER_SCAN_ANGLE_MAX
Tango3DR_Status Tango3DR_ReconstructionContext_destroy(Tango3DR_ReconstructionContext context)
geometry_msgs::TransformStamped device_T_camera_fisheye_
TangoErrorType TangoService_getCameraIntrinsics(TangoCameraId camera_id, TangoCameraIntrinsics *intrinsics)
TangoPoseStatusType status_code
TangoConfig TangoService_getConfig(TangoConfigType config_type)
const std::string LASER_SCAN_TOPIC_NAME
void OnPoseAvailable(const TangoPoseData *pose)
sensor_msgs::LaserScan laser_scan_
void toCameraInfo(const TangoCameraIntrinsics &camera_intrinsics, sensor_msgs::CameraInfo *camera_info)
const std::string DATASET_UUID_PARAM_NAME
B toMsg(const A &a)
const std::string FISHEYE_RECTIFIED_IMAGE_TOPIC_NAME
TANGO_CAMERA_FISHEYE
const std::string START_OF_SERVICE_FRAME_ID_PARAM_NAME
const std::string LOCALIZATION_MODE_PARAM_NAME
const std::string ENABLE_3DR_MESH_PARAM_NAME
const std::string POINT_CLOUD_TOPIC_NAME
image_geometry::PinholeCameraModel color_camera_model_
const std::string OCCUPANCY_GRID_DEFAULT_DIRECTORY
TangoErrorType TangoAreaDescriptionMetadata_set(TangoAreaDescriptionMetadata metadata, const char *key, size_t value_size, const char *value)
void toTango3DR_CameraCalibration(const TangoCameraIntrinsics &camera_intrinsics, Tango3DR_CameraCalibration *t3dr_camera_intrinsics)
uint32_t getNumSubscribers() const
TangoErrorType TangoService_saveAreaDescription(TangoUUID *uuid)
TangoErrorType TangoService_connect(void *context, TangoConfig config)
Tango3DR_ReconstructionContext t3dr_context_
bool GetAvailableMapUuidsList(std::vector< std::string > &uuid_list)
std::condition_variable data_available
bool getParam(const std::string &key, std::string &s) const
ros::ServiceServer load_occupancy_grid_service_
ros::Publisher start_of_service_T_device_publisher_
geometry_msgs::TransformStamped device_T_camera_color_
const float LASER_SCAN_SCAN_TIME
const std::string FISHEYE_IMAGE_TOPIC_NAME
void DynamicReconfigureCallback(PublisherConfig &config, uint32_t level)
TangoErrorType TangoSupport_freePointCloudManager(TangoSupport_PointCloudManager *manager)
static Time now()
TangoErrorType TangoSupport_createImageBufferManager(TangoImageFormatType format, int width, int height, TangoSupport_ImageBufferManager **manager)
static void transformStampedTFToMsg(const StampedTransform &bt, geometry_msgs::TransformStamped &msg)
TangoErrorType TangoService_saveAreaDescriptionMetadata(const TangoUUID uuid, TangoAreaDescriptionMetadata metadata)
tf::TransformBroadcaster tf_broadcaster_
bool GetMapNameServiceCallback(const tango_ros_messages::GetMapName::Request &req, tango_ros_messages::GetMapName::Response &res)
std::shared_ptr< camera_info_manager::CameraInfoManager > fisheye_camera_info_manager_
const std::string COLOR_RECTIFIED_IMAGE_TOPIC_NAME
bool hasParam(const std::string &key) const
const std::string ENABLE_3DR_OCCUPANCY_GRID_PARAM_NAME
void UpdateMesh(const Tango3DR_ReconstructionContext &t3dr_context, TangoSupport_PointCloudManager *point_cloud_manager, TangoSupport_ImageBufferManager *image_buffer_manager, Tango3DR_Pose *last_camera_depth_pose, Tango3DR_Pose *last_camera_color_pose, Tango3DR_GridIndexArray *t3dr_updated_indices)
void sendTransform(const geometry_msgs::TransformStamped &transform)
ROSCPP_DECL void spinOnce()
const float LASER_SCAN_ANGLE_INCREMENT
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
tf::StampedTransform camera_depth_T_laser_
void * TangoConfig
geometry_msgs::TransformStamped start_of_service_T_device_
const int NUMBER_OF_STATIC_TRANSFORMS
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const
bool GetMapNameFromUuid(const std::string &map_uuid, std::string &map_name)
const std::string LOAD_OCCUPANCY_GRID_SERVICE_NAME
const std::string OCCUPANCY_GRID_TOPIC_NAME
sensor_msgs::ImagePtr toImageMsg() const
std_msgs::Header header
bool TangoConnectServiceCallback(const tango_ros_messages::TangoConnect::Request &request, tango_ros_messages::TangoConnect::Response &response)
TangoErrorType TangoConfig_setInt32(TangoConfig config, const char *key, int32_t value)
tf2_ros::StaticTransformBroadcaster tf_static_broadcaster_


tango_ros_native
Author(s):
autogenerated on Mon Jun 10 2019 15:37:51