00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "tango_ros_native/occupancy_grid_file_io.h"
00015 #include "tango_ros_native/tango_3d_reconstruction_helper.h"
00016 #include "tango_ros_native/tango_ros_conversions_helper.h"
00017 #include "tango_ros_native/tango_ros_nodelet.h"
00018
00019 #include <cmath>
00020 #include <ctime>
00021 #include <iostream>
00022 #include <vector>
00023 #include <sstream>
00024
00025 #include <glog/logging.h>
00026
00027 #include <dynamic_reconfigure/config_tools.h>
00028 #include <dynamic_reconfigure/server.h>
00029 #include <geometry_msgs/PoseStamped.h>
00030 #include <pluginlib/class_list_macros.h>
00031 #include <sensor_msgs/image_encodings.h>
00032 #include <std_msgs/Int8.h>
00033 #include <tf2_geometry_msgs/tf2_geometry_msgs.h>
00034
00035 PLUGINLIB_EXPORT_CLASS(tango_ros_native::TangoRosNodelet, nodelet::Nodelet)
00036
00037 namespace {
00038 std::vector<std::string> SplitCommaSeparatedString(const std::string& comma_separated_string) {
00039 std::vector<std::string> output;
00040 std::stringstream ss(comma_separated_string);
00041
00042 std::string string_element;
00043 while (std::getline(ss, string_element, ',')) {
00044 output.push_back(string_element);
00045 }
00046 return output;
00047 }
00048
00049
00050
00051
00052
00053 void OnPoseAvailableRouter(void* context, const TangoPoseData* pose) {
00054 tango_ros_native::TangoRosNodelet* app =
00055 static_cast<tango_ros_native::TangoRosNodelet*>(context);
00056 app->OnPoseAvailable(pose);
00057 }
00058
00059
00060
00061
00062
00063
00064 void OnPointCloudAvailableRouter(void* context,
00065 const TangoPointCloud* point_cloud) {
00066 tango_ros_native::TangoRosNodelet* app =
00067 static_cast<tango_ros_native::TangoRosNodelet*>(context);
00068 app->OnPointCloudAvailable(point_cloud);
00069 }
00070
00071
00072
00073
00074
00075
00076
00077 void OnFrameAvailableRouter(void* context, TangoCameraId camera_id,
00078 const TangoImageBuffer* buffer) {
00079 tango_ros_native::TangoRosNodelet* app =
00080 static_cast<tango_ros_native::TangoRosNodelet*>(context);
00081 app->OnFrameAvailable(camera_id, buffer);
00082 }
00083
00084
00085
00086
00087
00088 void ApplyFovModel(
00089 double xu, double yu, double w, double w_inverse, double two_tan_w_div_two,
00090 double* xd, double* yd) {
00091 double ru = sqrt(xu * xu + yu * yu);
00092 constexpr double epsilon = 1e-7;
00093 if (w < epsilon || ru < epsilon) {
00094 *xd = xu;
00095 *yd = yu ;
00096 } else {
00097 double rd_div_ru = std::atan(ru * two_tan_w_div_two) * w_inverse / ru;
00098 *xd = xu * rd_div_ru;
00099 *yd = yu * rd_div_ru;
00100 }
00101 }
00102
00103
00104
00105
00106
00107
00108 void ComputeWarpMapsToRectifyFisheyeImage(
00109 const sensor_msgs::CameraInfo& fisheye_camera_info,
00110 cv::Mat* cv_warp_map_x, cv::Mat* cv_warp_map_y) {
00111 const double fx = fisheye_camera_info.K[0];
00112 const double fy = fisheye_camera_info.K[4];
00113 const double cx = fisheye_camera_info.K[2];
00114 const double cy = fisheye_camera_info.K[5];
00115 const double w = fisheye_camera_info.D[0];
00116
00117 const double fy_inverse = 1.0 / fy;
00118 const double fx_inverse = 1.0 / fx;
00119 const double w_inverse = 1 / w;
00120 const double two_tan_w_div_two = 2.0 * std::tan(w * 0.5);
00121
00122
00123
00124 for(int iu = 0; iu < fisheye_camera_info.height; ++iu) {
00125 for (int ju = 0; ju < fisheye_camera_info.width; ++ju) {
00126 double xu = (ju - cx) * fx_inverse;
00127 double yu = (iu - cy) * fy_inverse;
00128 double xd, yd;
00129 ApplyFovModel(xu, yu, w, w_inverse, two_tan_w_div_two, &xd, &yd);
00130 double jd = cx + xd * fx;
00131 double id = cy + yd * fy;
00132 cv_warp_map_x->at<float>(iu, ju) = jd;
00133 cv_warp_map_y->at<float>(iu, ju) = id;
00134 }
00135 }
00136 }
00137
00138
00139 std::string GetCurrentDateAndTime() {
00140 std::time_t currentTime;
00141 struct tm* currentDateTime;
00142 std::time(¤tTime);
00143 currentDateTime = std::localtime(¤tTime);
00144 int day = currentDateTime->tm_mday;
00145 int month = currentDateTime->tm_mon + 1;
00146 int year = currentDateTime->tm_year + 1900;
00147 int hour = currentDateTime->tm_hour;
00148 int min = currentDateTime->tm_min;
00149 int sec = currentDateTime->tm_sec;
00150 std::ostringstream oss;
00151 oss << year << "-" << month << "-" << day << "_" << hour << "-" << min << "-" << sec;
00152 return oss.str();
00153 }
00154
00155 double GetBootTimeInSecond() {
00156 struct timespec res_boot;
00157 clock_gettime(CLOCK_BOOTTIME, &res_boot);
00158 return res_boot.tv_sec + (double) res_boot.tv_nsec / 1e9;
00159 }
00160
00161
00162
00163
00164
00165 bool SaveTangoAreaDescription(const std::string& map_name,
00166 std::string& map_uuid, std::string& message) {
00167 TangoErrorType result;
00168 TangoUUID map_tango_uuid;
00169 result = TangoService_saveAreaDescription(&map_tango_uuid);
00170 if (result != TANGO_SUCCESS) {
00171 LOG(ERROR) << "Error while saving area description, error: " << result;
00172 message = "Could not save the map. "
00173 "Did you allow the app to use area learning?";
00174 return false;
00175 }
00176 TangoAreaDescriptionMetadata metadata;
00177 result = TangoService_getAreaDescriptionMetadata(map_tango_uuid, &metadata);
00178 if (result != TANGO_SUCCESS) {
00179 LOG(ERROR) << "Error while trying to access area description metadata, error: " << result;
00180 message = "Could not access map metadata";
00181 return false;
00182 }
00183 result = TangoAreaDescriptionMetadata_set(metadata, "name", map_name.capacity(), map_name.c_str());
00184 if (result != TANGO_SUCCESS) {
00185 LOG(ERROR) << "Error while trying to change area description metadata, error: " << result;
00186 message = "Could not set the name of the map";
00187 return false;
00188 }
00189 result = TangoService_saveAreaDescriptionMetadata(map_tango_uuid, metadata);
00190 if (result != TANGO_SUCCESS) {
00191 LOG(ERROR) << "Error while saving new area description metadata, error: " << result;
00192 message = "Could not save map metadata";
00193 return false;
00194 }
00195 result = TangoAreaDescriptionMetadata_free(metadata);
00196 if (result != TANGO_SUCCESS) {
00197 LOG(ERROR) << "Error while trying to free area description metadata, error: " << result;
00198 message = "Could not free map metadata";
00199 return false;
00200 }
00201 map_uuid = static_cast<std::string>(map_tango_uuid);
00202 return true;
00203 }
00204
00205
00206
00207
00208 bool GetCurrentADFUuid(const TangoConfig& tango_config, std::string& adf_uuid) {
00209 char current_adf_uuid[TANGO_UUID_LEN];
00210 const char* config_load_area_description_UUID = "config_load_area_description_UUID";
00211 TangoErrorType result = TangoConfig_getString(
00212 tango_config, config_load_area_description_UUID, current_adf_uuid,
00213 TANGO_UUID_LEN);
00214 if (result != TANGO_SUCCESS) {
00215 LOG(ERROR) << "TangoConfig_getString "
00216 << config_load_area_description_UUID << " error: " << result;
00217 return false;
00218 }
00219 adf_uuid = std::string(current_adf_uuid);
00220 return true;
00221 }
00222
00223 template<typename T>
00224 void SetDefaultValueIfParamDoesNotExist(
00225 const ros::NodeHandle& node_handle, const std::string& param_name,
00226 T default_value) {
00227 if (!node_handle.hasParam(param_name)) {
00228 node_handle.setParam(param_name, default_value);
00229 }
00230 }
00231 template<typename T>
00232 void GetParamValueAndSetDefaultValueIfParamDoesNotExist(
00233 const ros::NodeHandle& node_handle, const std::string& param_name,
00234 T default_value, T& param_value) {
00235 if (node_handle.hasParam(param_name)) {
00236 node_handle.getParam(param_name, param_value);
00237 } else {
00238 param_value = default_value;
00239 node_handle.setParam(param_name, default_value);
00240 }
00241 }
00242
00243 void InvertTransformStamped(const geometry_msgs::TransformStamped& a_T_b,
00244 geometry_msgs::TransformStamped* b_T_a) {
00245 geometry_msgs::Transform a_T_b_msg = a_T_b.transform;
00246 tf2::Transform a_T_b_tf;
00247 tf2::fromMsg(a_T_b_msg, a_T_b_tf);
00248 tf2::Transform b_T_a_tf = a_T_b_tf.inverse();
00249 geometry_msgs::Transform b_T_a_msg = tf2::toMsg(b_T_a_tf);
00250 b_T_a->transform = b_T_a_msg;
00251 b_T_a->header = a_T_b.header;
00252 b_T_a->header.frame_id = a_T_b.child_frame_id;
00253 b_T_a->child_frame_id = a_T_b.header.frame_id;
00254 }
00255 }
00256
00257 namespace tango_ros_native {
00258 TangoRosNodelet::TangoRosNodelet() : run_threads_(false), tango_config_(nullptr),
00259 t3dr_context_(nullptr), point_cloud_manager_(nullptr),
00260 image_buffer_manager_(nullptr), new_point_cloud_available_for_t3dr_(false) {}
00261
00262 void TangoRosNodelet::onInit() {
00263 node_handle_ = getMTPrivateNodeHandle();
00264 const uint32_t queue_size = 1;
00265 const bool latching = true;
00266 tango_status_publisher_ =
00267 node_handle_.advertise<std_msgs::Int8>(TANGO_STATUS_TOPIC_NAME,
00268 queue_size, latching);
00269 start_of_service_T_device_publisher_ =
00270 node_handle_.advertise<geometry_msgs::TransformStamped>(
00271 START_OF_SERVICE_T_DEVICE_TOPIC_NAME, queue_size, latching);
00272 area_description_T_start_of_service_publisher_ =
00273 node_handle_.advertise<geometry_msgs::TransformStamped>(
00274 AREA_DESCRIPTION_T_START_OF_SERVICE_TOPIC_NAME, queue_size, latching);
00275
00276 image_transport_.reset(new image_transport::ImageTransport(node_handle_));
00277
00278 static_occupancy_grid_publisher_ = node_handle_.advertise<nav_msgs::OccupancyGrid>(
00279 STATIC_OCCUPANCY_GRID_TOPIC_NAME, queue_size, latching);
00280
00281 get_map_name_service_ = node_handle_.advertiseService<tango_ros_messages::GetMapName::Request,
00282 tango_ros_messages::GetMapName::Response>(GET_MAP_NAME_SERVICE_NAME,
00283 boost::bind(&TangoRosNodelet::GetMapNameServiceCallback, this, _1, _2));
00284
00285 get_map_uuids_service_ = node_handle_.advertiseService<tango_ros_messages::GetMapUuids::Request,
00286 tango_ros_messages::GetMapUuids::Response>(GET_MAP_UUIDS_SERVICE_NAME,
00287 boost::bind(&TangoRosNodelet::GetMapUuidsServiceCallback, this, _1, _2));
00288
00289 save_map_service_ = node_handle_.advertiseService<tango_ros_messages::SaveMap::Request,
00290 tango_ros_messages::SaveMap::Response>(SAVE_MAP_SERVICE_NAME,
00291 boost::bind(&TangoRosNodelet::SaveMapServiceCallback, this, _1, _2));
00292 load_occupancy_grid_service_ = node_handle_.advertiseService<tango_ros_messages::LoadOccupancyGrid::Request,
00293 tango_ros_messages::LoadOccupancyGrid::Response>(LOAD_OCCUPANCY_GRID_SERVICE_NAME,
00294 boost::bind(&TangoRosNodelet::LoadOccupancyGridServiceCallback, this, _1, _2));
00295
00296 tango_connect_service_ = node_handle_.advertiseService<tango_ros_messages::TangoConnect::Request,
00297 tango_ros_messages::TangoConnect::Response>(
00298 CONNECT_SERVICE_NAME, boost::bind(
00299 &TangoRosNodelet::TangoConnectServiceCallback, this, _1, _2));
00300
00301 tango_status_ = TangoStatus::UNKNOWN;
00302
00303 SetDefaultValueIfParamDoesNotExist(
00304 node_handle_, CREATE_NEW_MAP_PARAM_NAME, false);
00305 SetDefaultValueIfParamDoesNotExist(
00306 node_handle_, LOCALIZATION_MODE_PARAM_NAME, 2);
00307 SetDefaultValueIfParamDoesNotExist(
00308 node_handle_, LOCALIZATION_MAP_UUID_PARAM_NAME, "");
00309 SetDefaultValueIfParamDoesNotExist(
00310 node_handle_, OCCUPANCY_GRID_DIRECTORY_PARAM_NAME,
00311 OCCUPANCY_GRID_DEFAULT_DIRECTORY);
00312 SetDefaultValueIfParamDoesNotExist(
00313 node_handle_, DATASET_DIRECTORY_PARAM_NAME, DATASET_DEFAULT_DIRECTORY);
00314 SetDefaultValueIfParamDoesNotExist(
00315 node_handle_, DATASET_UUID_PARAM_NAME, "");
00316 SetDefaultValueIfParamDoesNotExist(node_handle_,
00317 tango_3d_reconstruction_helper::TANGO_3DR_RESOLUTION_PARAM_NAME,
00318 tango_3d_reconstruction_helper::TANGO_3DR_DEFAULT_RESOLUTION);
00319 SetDefaultValueIfParamDoesNotExist(node_handle_,
00320 tango_3d_reconstruction_helper::TANGO_3DR_USE_SPACE_CLEARING_PARAM_NAME,
00321 tango_3d_reconstruction_helper::TANGO_3DR_DEFAULT_USE_SPACE_CLEARING);
00322 SetDefaultValueIfParamDoesNotExist(node_handle_,
00323 tango_3d_reconstruction_helper::TANGO_3DR_MIN_NUM_VERTICES_PARAM_NAME,
00324 tango_3d_reconstruction_helper::TANGO_3DR_DEFAULT_MIN_NUM_VERTICES);
00325 SetDefaultValueIfParamDoesNotExist(node_handle_,
00326 tango_3d_reconstruction_helper::TANGO_3DR_UPDATE_METHOD_PARAM_NAME,
00327 tango_3d_reconstruction_helper::TANGO_3DR_DEFAULT_UPDATE_METHOD);
00328 SetDefaultValueIfParamDoesNotExist(node_handle_,
00329 tango_3d_reconstruction_helper::TANGO_3DR_MAX_VOXEL_WEIGHT_PARAM_NAME,
00330 tango_3d_reconstruction_helper::TANGO_3DR_DEFAULT_MAX_VOXEL_WEIGHT);
00331 SetDefaultValueIfParamDoesNotExist(node_handle_,
00332 tango_3d_reconstruction_helper::TANGO_3DR_FLOORPLAN_MAX_ERROR_PARAM_NAME,
00333 tango_3d_reconstruction_helper::TANGO_3DR_DEFAULT_FLOORPLAN_MAX_ERROR);
00334 SetDefaultValueIfParamDoesNotExist(
00335 node_handle_, USE_TF_STATIC_PARAM_NAME, true);
00336 GetParamValueAndSetDefaultValueIfParamDoesNotExist(
00337 node_handle_, PUBLISH_POSE_ON_TF_PARAM_NAME, true, publish_pose_on_tf_);
00338 GetParamValueAndSetDefaultValueIfParamDoesNotExist(
00339 node_handle_, ENABLE_DEPTH_PARAM_NAME, true, enable_depth_);
00340 GetParamValueAndSetDefaultValueIfParamDoesNotExist(
00341 node_handle_, ENABLE_COLOR_CAMERA_PARAM_NAME, true, enable_color_camera_);
00342 GetParamValueAndSetDefaultValueIfParamDoesNotExist(
00343 node_handle_, ENABLE_3DR_MESH_PARAM_NAME, true, enable_3dr_mesh_);
00344 GetParamValueAndSetDefaultValueIfParamDoesNotExist(
00345 node_handle_, ENABLE_3DR_OCCUPANCY_GRID_PARAM_NAME, true, enable_3dr_occupancy_grid_);
00346 int t3dr_occupancy_grid_threshold =
00347 tango_3d_reconstruction_helper::TANGO_3DR_OCCUPANCY_GRID_DEFAULT_THRESHOLD;
00348 GetParamValueAndSetDefaultValueIfParamDoesNotExist(node_handle_,
00349 tango_3d_reconstruction_helper::TANGO_3DR_OCCUPANCY_GRID_THRESHOLD_PARAM_NAME,
00350 static_cast<int>(
00351 tango_3d_reconstruction_helper::TANGO_3DR_OCCUPANCY_GRID_DEFAULT_THRESHOLD),
00352 t3dr_occupancy_grid_threshold);
00353 t3dr_occupancy_grid_threshold_ = t3dr_occupancy_grid_threshold;
00354 GetParamValueAndSetDefaultValueIfParamDoesNotExist(
00355 node_handle_, START_OF_SERVICE_FRAME_ID_PARAM_NAME,
00356 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_START_OF_SERVICE),
00357 start_of_service_frame_id_);
00358 GetParamValueAndSetDefaultValueIfParamDoesNotExist(
00359 node_handle_, AREA_DESCRIPTION_FRAME_ID_PARAM_NAME,
00360 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_AREA_DESCRIPTION),
00361 area_description_frame_id_);
00362 }
00363
00364 TangoRosNodelet::~TangoRosNodelet() {
00365 TangoDisconnect();
00366 }
00367
00368 TangoErrorType TangoRosNodelet::OnTangoServiceConnected() {
00369 const uint32_t queue_size = 1;
00370 const bool latching = true;
00371
00372 if (enable_depth_) {
00373 point_cloud_publisher_ =
00374 node_handle_.advertise<sensor_msgs::PointCloud2>(
00375 POINT_CLOUD_TOPIC_NAME, queue_size, latching);
00376 laser_scan_publisher_ =
00377 node_handle_.advertise<sensor_msgs::LaserScan>(
00378 LASER_SCAN_TOPIC_NAME, queue_size, latching);
00379 } else {
00380 point_cloud_publisher_.shutdown();
00381 laser_scan_publisher_.shutdown();
00382 }
00383 if (enable_color_camera_) {
00384 try {
00385 color_camera_publisher_ =
00386 image_transport_->advertiseCamera(COLOR_IMAGE_TOPIC_NAME,
00387 queue_size, latching);
00388 color_rectified_image_publisher_ =
00389 image_transport_->advertise(COLOR_RECTIFIED_IMAGE_TOPIC_NAME,
00390 queue_size, latching);
00391 } catch (const image_transport::Exception& e) {
00392 LOG(ERROR) << "Error while creating color image transport publishers" << e.what();
00393 return TANGO_ERROR;
00394 }
00395 } else {
00396 color_camera_publisher_.shutdown();
00397 color_rectified_image_publisher_.shutdown();
00398 }
00399 node_handle_.param<bool>(ENABLE_3DR_MESH_PARAM_NAME, enable_3dr_mesh_, true);
00400 if (enable_depth_ && enable_color_camera_ && enable_3dr_mesh_) {
00401 mesh_marker_publisher_ =
00402 node_handle_.advertise<visualization_msgs::MarkerArray>(
00403 COLOR_MESH_TOPIC_NAME, queue_size, latching);
00404 } else {
00405 mesh_marker_publisher_.shutdown();
00406 }
00407 node_handle_.param<bool>(ENABLE_3DR_OCCUPANCY_GRID_PARAM_NAME, enable_3dr_occupancy_grid_, true);
00408 if (enable_depth_ && enable_color_camera_ && enable_3dr_occupancy_grid_){
00409 occupancy_grid_publisher_ = node_handle_.advertise<nav_msgs::OccupancyGrid>(
00410 OCCUPANCY_GRID_TOPIC_NAME, queue_size, latching);
00411 } else {
00412 occupancy_grid_publisher_.shutdown();
00413 }
00414 if (fisheye_camera_available_) {
00415 try {
00416 fisheye_camera_publisher_ =
00417 image_transport_->advertiseCamera(FISHEYE_IMAGE_TOPIC_NAME,
00418 queue_size, latching);
00419 fisheye_rectified_image_publisher_ =
00420 image_transport_->advertise(FISHEYE_RECTIFIED_IMAGE_TOPIC_NAME,
00421 queue_size, latching);
00422 } catch (const image_transport::Exception& e) {
00423 LOG(ERROR) << "Error while creating fisheye image transport publishers" << e.what();
00424 return TANGO_ERROR;
00425 }
00426 } else {
00427 fisheye_camera_publisher_.shutdown();
00428 fisheye_rectified_image_publisher_.shutdown();
00429 }
00430
00431 TangoCoordinateFramePair pair;
00432 pair.base = TANGO_COORDINATE_FRAME_START_OF_SERVICE;
00433 pair.target = TANGO_COORDINATE_FRAME_DEVICE;
00434 TangoPoseData pose;
00435 time_t current_time = time(NULL);
00436 time_t end = current_time + 10;
00437 while (current_time < end) {
00438 TangoService_getPoseAtTime(0.0, pair, &pose);
00439 if (pose.status_code == TANGO_POSE_VALID) {
00440 break;
00441 }
00442 sleep(1);
00443 current_time = time(NULL);
00444 }
00445 if (pose.status_code != TANGO_POSE_VALID) {
00446 LOG(ERROR) << "Error, could not get a first valid pose.";
00447 UpdateAndPublishTangoStatus(TangoStatus::NO_FIRST_VALID_POSE);
00448 return TANGO_INVALID;
00449 }
00450 time_offset_ = ros::Time::now().toSec() - GetBootTimeInSecond();
00451
00452 TangoCameraIntrinsics tango_camera_intrinsics;
00453 TangoService_getCameraIntrinsics(TANGO_CAMERA_FISHEYE, &tango_camera_intrinsics);
00454 tango_ros_conversions_helper::toCameraInfo(tango_camera_intrinsics, &fisheye_camera_info_);
00455 fisheye_camera_info_manager_.reset(new camera_info_manager::CameraInfoManager(node_handle_));
00456 fisheye_camera_info_manager_->setCameraName("fisheye_1");
00457
00458 cv_warp_map_x_.create(fisheye_camera_info_.height, fisheye_camera_info_.width, CV_32FC1);
00459 cv_warp_map_y_.create(fisheye_camera_info_.height, fisheye_camera_info_.width, CV_32FC1);
00460 ComputeWarpMapsToRectifyFisheyeImage(fisheye_camera_info_, &cv_warp_map_x_, &cv_warp_map_y_);
00461 fisheye_image_rect_.create(fisheye_camera_info_.height, fisheye_camera_info_.width, CV_8UC1);
00462
00463 TangoService_getCameraIntrinsics(TANGO_CAMERA_COLOR, &tango_camera_intrinsics);
00464 tango_ros_conversions_helper::toCameraInfo(tango_camera_intrinsics, &color_camera_info_);
00465 color_camera_info_manager_.reset(new camera_info_manager::CameraInfoManager(node_handle_));
00466 color_camera_info_manager_->setCameraName("color_1");
00467
00468 color_camera_model_.fromCameraInfo(color_camera_info_);
00469
00470 if (enable_3dr_mesh_ || enable_3dr_occupancy_grid_) {
00471 tango_ros_conversions_helper::toTango3DR_CameraCalibration(
00472 tango_camera_intrinsics, &t3dr_color_camera_intrinsics_);
00473 tango_3d_reconstruction_helper::TangoSetup3DRConfig(
00474 node_handle_, &t3dr_resolution_, &t3dr_context_, &t3dr_color_camera_intrinsics_);
00475 }
00476 return TANGO_SUCCESS;
00477 }
00478
00479 TangoErrorType TangoRosNodelet::TangoSetupConfig() {
00480 const char* function_name = "TangoRosNodelet::TangoSetupConfig()";
00481
00482 tango_config_ = TangoService_getConfig(TANGO_CONFIG_DEFAULT);
00483 if (tango_config_ == nullptr) {
00484 LOG(ERROR) << function_name << ", TangoService_getConfig error.";
00485 return TANGO_ERROR;
00486 }
00487
00488 TangoErrorType result;
00489 const char* config_enable_motion_tracking = "config_enable_motion_tracking";
00490 result = TangoConfig_setBool(tango_config_, config_enable_motion_tracking, true);
00491 if(result != TANGO_SUCCESS) {
00492 LOG(ERROR) << function_name << ", TangoConfig_setBool "
00493 << config_enable_motion_tracking << " error: " << result;
00494 return result;
00495 }
00496 bool create_new_map;
00497 node_handle_.param(CREATE_NEW_MAP_PARAM_NAME, create_new_map, false);
00498 const char* config_enable_learning_mode = "config_enable_learning_mode";
00499 result = TangoConfig_setBool(tango_config_, config_enable_learning_mode, create_new_map);
00500 if (result != TANGO_SUCCESS) {
00501 LOG(ERROR) << function_name << ", TangoConfig_setBool "
00502 << config_enable_learning_mode << " error: " << result;
00503 return result;
00504 }
00505 if (!create_new_map) {
00506 bool enable_drift_correction = false;
00507 int localization_mode;
00508 node_handle_.param(LOCALIZATION_MODE_PARAM_NAME, localization_mode,
00509 (int)LocalizationMode::ONLINE_SLAM);
00510 if (localization_mode == LocalizationMode::ONLINE_SLAM) {
00511 enable_drift_correction = true;
00512 }
00513 const char* config_enable_drift_correction = "config_enable_drift_correction";
00514 result = TangoConfig_setBool(tango_config_, config_enable_drift_correction, enable_drift_correction);
00515 if (result != TANGO_SUCCESS) {
00516 LOG(ERROR) << function_name << ", TangoConfig_setBool "
00517 << config_enable_drift_correction << " error: " << result;
00518 return result;
00519 }
00520 if (localization_mode == LocalizationMode::LOCALIZATION) {
00521 std::string map_uuid_to_load = "";
00522 node_handle_.param<std::string>(LOCALIZATION_MAP_UUID_PARAM_NAME, map_uuid_to_load, "");
00523 const char* config_load_area_description_UUID = "config_load_area_description_UUID";
00524 result = TangoConfig_setString(tango_config_, config_load_area_description_UUID, map_uuid_to_load.c_str());
00525 if (result != TANGO_SUCCESS) {
00526 LOG(ERROR) << function_name << ", TangoConfig_setString "
00527 << config_load_area_description_UUID << " error: " << result;
00528 return result;
00529 }
00530 }
00531 }
00532 const char* config_enable_auto_recovery = "config_enable_auto_recovery";
00533 result = TangoConfig_setBool(tango_config_, config_enable_auto_recovery, true);
00534 if (result != TANGO_SUCCESS) {
00535 LOG(ERROR) << function_name << ", TangoConfig_setBool "
00536 << config_enable_auto_recovery << " error: " << result;
00537 return result;
00538 }
00539 const char* config_enable_depth = "config_enable_depth";
00540 node_handle_.param<bool>(ENABLE_DEPTH_PARAM_NAME, enable_depth_, true);
00541 result = TangoConfig_setBool(tango_config_, config_enable_depth, enable_depth_);
00542 if (result != TANGO_SUCCESS) {
00543 LOG(ERROR) << function_name << ", TangoConfig_setBool "
00544 << config_enable_depth << " error: " << result;
00545 return result;
00546 }
00547 const char* config_depth_mode = "config_depth_mode";
00548 result = TangoConfig_setInt32(tango_config_, config_depth_mode, TANGO_POINTCLOUD_XYZC);
00549 if (result != TANGO_SUCCESS) {
00550 LOG(ERROR) << function_name << ", TangoConfig_setInt "
00551 << config_depth_mode << " error: " << result;
00552 return result;
00553 }
00554 const char* config_enable_color_camera = "config_enable_color_camera";
00555 node_handle_.param<bool>(ENABLE_COLOR_CAMERA_PARAM_NAME, enable_color_camera_, true);
00556 result = TangoConfig_setBool(tango_config_, config_enable_color_camera, enable_color_camera_);
00557 if (result != TANGO_SUCCESS) {
00558 LOG(ERROR) << function_name << ", TangoConfig_setBool "
00559 << config_enable_color_camera << " error: " << result;
00560 return result;
00561 }
00562 std::string datasets_path;
00563 node_handle_.param(DATASET_DIRECTORY_PARAM_NAME, datasets_path, DATASET_DEFAULT_DIRECTORY);
00564 const char* config_datasets_path = "config_datasets_path";
00565 result = TangoConfig_setString(tango_config_, config_datasets_path, datasets_path.c_str());
00566 if (result != TANGO_SUCCESS) {
00567 LOG(ERROR) << function_name << ", TangoConfig_setString "
00568 << config_datasets_path << " error: " << result;
00569 return result;
00570 }
00571 std::string dataset_uuid;
00572 node_handle_.param(DATASET_UUID_PARAM_NAME, dataset_uuid, std::string(""));
00573 const char* config_experimental_load_dataset_UUID = "config_experimental_load_dataset_UUID";
00574 result = TangoConfig_setString(tango_config_, config_experimental_load_dataset_UUID, dataset_uuid.c_str());
00575 if (result != TANGO_SUCCESS) {
00576 LOG(ERROR) << function_name << ", TangoConfig_setString "
00577 << config_experimental_load_dataset_UUID << " error: " << result;
00578 return result;
00579 }
00580 if (point_cloud_manager_ == nullptr) {
00581 int32_t max_point_cloud_elements;
00582 const char* config_max_point_cloud_elements = "max_point_cloud_elements";
00583 result = TangoConfig_getInt32(tango_config_, config_max_point_cloud_elements,
00584 &max_point_cloud_elements);
00585 if (result != TANGO_SUCCESS) {
00586 LOG(ERROR) << function_name << ", Failed to query maximum number of point cloud elements.";
00587 return result;
00588 }
00589 result = TangoSupport_createPointCloudManager(max_point_cloud_elements, &point_cloud_manager_);
00590 if (result != TANGO_SUCCESS) {
00591 LOG(ERROR) << function_name << ", Failed to create point cloud manager.";
00592 return result;
00593 }
00594 }
00595 return TANGO_SUCCESS;
00596 }
00597
00598 TangoErrorType TangoRosNodelet::TangoConnect() {
00599 const char* function_name = "TangoRosNodelet::TangoConnect()";
00600
00601 TangoCoordinateFramePair pairs[2] = {
00602 {TANGO_COORDINATE_FRAME_START_OF_SERVICE,
00603 TANGO_COORDINATE_FRAME_DEVICE},
00604 {TANGO_COORDINATE_FRAME_AREA_DESCRIPTION,
00605 TANGO_COORDINATE_FRAME_START_OF_SERVICE}};
00606 TangoErrorType result =
00607 TangoService_connectOnPoseAvailable(2, pairs, OnPoseAvailableRouter);
00608 if (result != TANGO_SUCCESS) {
00609 LOG(ERROR) << function_name
00610 << ", TangoService_connectOnPoseAvailable error: " << result;
00611 return result;
00612 }
00613
00614 result = TangoService_connectOnPointCloudAvailable(OnPointCloudAvailableRouter);
00615 if (result != TANGO_SUCCESS) {
00616 LOG(ERROR) << function_name
00617 << ", TangoService_connectOnPointCloudAvailable error: " << result;
00618 return result;
00619 }
00620
00621 int android_api_level;
00622 node_handle_.param("android_api_level", android_api_level, 0);
00623 if (android_api_level < 24) {
00624 result = TangoService_connectOnFrameAvailable(
00625 TANGO_CAMERA_FISHEYE, this, OnFrameAvailableRouter);
00626 if (result != TANGO_SUCCESS) {
00627 LOG(ERROR) << function_name
00628 << ", TangoService_connectOnFrameAvailable TANGO_CAMERA_FISHEYE error: " << result;
00629 return result;
00630 }
00631 } else {
00632 LOG(WARNING) << "Android API Level is 24 or more, Fisheye camera data is not available";
00633 fisheye_camera_available_ = false;
00634 }
00635
00636 result = TangoService_connectOnFrameAvailable(
00637 TANGO_CAMERA_COLOR, this, OnFrameAvailableRouter);
00638 if (result != TANGO_SUCCESS) {
00639 LOG(ERROR) << function_name
00640 << ", TangoService_connectOnFrameAvailable TANGO_CAMERA_COLOR error: " << result;
00641 return result;
00642 }
00643
00644 result = TangoService_connect(this, tango_config_);
00645 if (result != TANGO_SUCCESS) {
00646 LOG(ERROR) << function_name << ", TangoService_connect error: " << result;
00647 return result;
00648 }
00649 return TANGO_SUCCESS;
00650 }
00651
00652 void TangoRosNodelet::UpdateAndPublishTangoStatus(const TangoStatus& status) {
00653 tango_status_ = status;
00654 std_msgs::Int8 tango_status_msg;
00655 tango_status_msg.data = static_cast<int>(tango_status_);
00656 tango_status_publisher_.publish(tango_status_msg);
00657 }
00658
00659 TangoErrorType TangoRosNodelet::ConnectToTangoAndSetUpNode() {
00660 if (tango_status_ == TangoStatus::SERVICE_CONNECTED) {
00661
00662
00663 LOG(WARNING) << "Already connected to Tango service.";
00664 UpdateAndPublishTangoStatus(TangoStatus::SERVICE_CONNECTED);
00665 return TANGO_SUCCESS;
00666 }
00667 UpdateAndPublishTangoStatus(TangoStatus::UNKNOWN);
00668
00669 TangoErrorType success;
00670
00671 success = TangoSetupConfig();
00672
00673 if (success != TANGO_SUCCESS) {
00674 UpdateAndPublishTangoStatus(TangoStatus::SERVICE_NOT_CONNECTED);
00675 return success;
00676 }
00677
00678 success = TangoConnect();
00679
00680 if (success != TANGO_SUCCESS) {
00681 UpdateAndPublishTangoStatus(TangoStatus::SERVICE_NOT_CONNECTED);
00682 return success;
00683 }
00684
00685 node_handle_.param(USE_TF_STATIC_PARAM_NAME, use_tf_static_, true);
00686 PublishStaticTransforms();
00687 success = OnTangoServiceConnected();
00688 if (success != TANGO_SUCCESS) {
00689 return success;
00690 }
00691 area_description_T_start_of_service_.child_frame_id = "";
00692 tango_data_available_ = true;
00693
00694 StartPublishing();
00695 UpdateAndPublishTangoStatus(TangoStatus::SERVICE_CONNECTED);
00696 return success;
00697 }
00698
00699 void TangoRosNodelet::TangoDisconnect() {
00700 StopPublishing();
00701 if (tango_config_ != nullptr) {
00702 TangoConfig_free(tango_config_);
00703 tango_config_ = nullptr;
00704 }
00705 if (point_cloud_manager_ != nullptr) {
00706 TangoSupport_freePointCloudManager(point_cloud_manager_);
00707 point_cloud_manager_ = nullptr;
00708 }
00709 if (image_buffer_manager_ != nullptr) {
00710 TangoSupport_freeImageBufferManager(image_buffer_manager_);
00711 image_buffer_manager_ = nullptr;
00712 }
00713 if (t3dr_context_ != nullptr) {
00714 Tango3DR_clear(t3dr_context_);
00715 Tango3DR_ReconstructionContext_destroy(t3dr_context_);
00716 t3dr_context_ = nullptr;
00717 }
00718 TangoService_disconnect();
00719 UpdateAndPublishTangoStatus(TangoStatus::SERVICE_NOT_CONNECTED);
00720 }
00721
00722 void TangoRosNodelet::PublishStaticTransforms() {
00723 std::vector<geometry_msgs::TransformStamped> tf_transforms;
00724 tf_transforms.reserve(NUMBER_OF_STATIC_TRANSFORMS);
00725 TangoCoordinateFramePair pair;
00726 TangoPoseData pose;
00727
00728 pair.base = TANGO_COORDINATE_FRAME_DEVICE;
00729 pair.target = TANGO_COORDINATE_FRAME_IMU;
00730 TangoService_getPoseAtTime(0.0, pair, &pose);
00731 geometry_msgs::TransformStamped device_T_imu;
00732 tango_ros_conversions_helper::toTransformStamped(
00733 pose, time_offset_,
00734 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_DEVICE),
00735 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_IMU),
00736 &device_T_imu);
00737 tf_transforms.push_back(device_T_imu);
00738
00739 pair.base = TANGO_COORDINATE_FRAME_DEVICE;
00740 pair.target = TANGO_COORDINATE_FRAME_CAMERA_DEPTH;
00741 TangoService_getPoseAtTime(0.0, pair, &pose);
00742 tango_ros_conversions_helper::toTransformStamped(
00743 pose, time_offset_,
00744 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_DEVICE),
00745 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_CAMERA_DEPTH),
00746 &device_T_camera_depth_);
00747 tf_transforms.push_back(device_T_camera_depth_);
00748
00749
00750
00751
00752
00753 camera_depth_T_laser_ = tf::StampedTransform(
00754 tf::Transform(tf::Quaternion(1 / sqrt(2), 0, 0, 1 / sqrt(2))), ros::Time::now(),
00755 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_CAMERA_DEPTH),
00756 LASER_SCAN_FRAME_ID);
00757 geometry_msgs::TransformStamped camera_depth_T_laser_message;
00758 tf::transformStampedTFToMsg(camera_depth_T_laser_, camera_depth_T_laser_message);
00759 tf_transforms.push_back(camera_depth_T_laser_message);
00760
00761 pair.base = TANGO_COORDINATE_FRAME_DEVICE;
00762 pair.target = TANGO_COORDINATE_FRAME_CAMERA_FISHEYE;
00763 TangoService_getPoseAtTime(0.0, pair, &pose);
00764 tango_ros_conversions_helper::toTransformStamped(
00765 pose, time_offset_,
00766 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_DEVICE),
00767 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_CAMERA_FISHEYE),
00768 &device_T_camera_fisheye_);
00769 tf_transforms.push_back(device_T_camera_fisheye_);
00770
00771 pair.base = TANGO_COORDINATE_FRAME_DEVICE;
00772 pair.target = TANGO_COORDINATE_FRAME_CAMERA_COLOR;
00773 TangoService_getPoseAtTime(0.0, pair, &pose);
00774 tango_ros_conversions_helper::toTransformStamped(
00775 pose, time_offset_,
00776 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_DEVICE),
00777 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_CAMERA_COLOR),
00778 &device_T_camera_color_);
00779 tf_transforms.push_back(device_T_camera_color_);
00780
00781 if (use_tf_static_) {
00782 tf_static_broadcaster_.sendTransform(tf_transforms);
00783 } else {
00784 tf_broadcaster_.sendTransform(tf_transforms);
00785 }
00786 }
00787
00788 void TangoRosNodelet::OnPoseAvailable(const TangoPoseData* pose) {
00789 if (pose->frame.base == TANGO_COORDINATE_FRAME_START_OF_SERVICE &&
00790 pose->frame.target == TANGO_COORDINATE_FRAME_DEVICE) {
00791 if (pose->status_code == TANGO_POSE_VALID &&
00792 device_pose_thread_.data_available_mutex.try_lock()) {
00793 tango_ros_conversions_helper::toTransformStamped(
00794 *pose, time_offset_, start_of_service_frame_id_,
00795 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_DEVICE),
00796 &start_of_service_T_device_);
00797 device_pose_thread_.data_available_mutex.unlock();
00798 device_pose_thread_.data_available.notify_all();
00799 }
00800 } else if (pose->frame.base == TANGO_COORDINATE_FRAME_AREA_DESCRIPTION &&
00801 pose->frame.target == TANGO_COORDINATE_FRAME_START_OF_SERVICE) {
00802 if (pose->status_code == TANGO_POSE_VALID &&
00803 device_pose_thread_.data_available_mutex.try_lock()) {
00804 tango_ros_conversions_helper::toTransformStamped(
00805 *pose, time_offset_, area_description_frame_id_,
00806 start_of_service_frame_id_, &area_description_T_start_of_service_);
00807 device_pose_thread_.data_available_mutex.unlock();
00808 device_pose_thread_.data_available.notify_all();
00809 }
00810 }
00811 }
00812
00813 void TangoRosNodelet::OnPointCloudAvailable(const TangoPointCloud* point_cloud) {
00814 if (point_cloud->num_points > 0) {
00815 if (point_cloud_publisher_.getNumSubscribers() > 0 &&
00816 point_cloud_thread_.data_available_mutex.try_lock()) {
00817 tango_ros_conversions_helper::toPointCloud2(*point_cloud, time_offset_,
00818 &point_cloud_);
00819 point_cloud_.header.frame_id =
00820 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_CAMERA_DEPTH);
00821 point_cloud_thread_.data_available_mutex.unlock();
00822 point_cloud_thread_.data_available.notify_all();
00823 }
00824 if (laser_scan_publisher_.getNumSubscribers() > 0 &&
00825 laser_scan_thread_.data_available_mutex.try_lock()) {
00826 laser_scan_.angle_min = LASER_SCAN_ANGLE_MIN;
00827 laser_scan_.angle_max = LASER_SCAN_ANGLE_MAX;
00828 laser_scan_.angle_increment = LASER_SCAN_ANGLE_INCREMENT;
00829 laser_scan_.time_increment = LASER_SCAN_TIME_INCREMENT;
00830 laser_scan_.scan_time = LASER_SCAN_SCAN_TIME;
00831 laser_scan_.range_min = laser_scan_min_range_;
00832 laser_scan_.range_max = laser_scan_max_range_;
00833
00834 uint32_t ranges_size = std::ceil((laser_scan_.angle_max - laser_scan_.angle_min)
00835 / laser_scan_.angle_increment);
00836
00837 laser_scan_.ranges.assign(ranges_size, std::numeric_limits<double>::infinity());
00838 tango_ros_conversions_helper::toLaserScan(*point_cloud, time_offset_,
00839 laser_scan_min_height_, laser_scan_max_height_, laser_scan_min_range_,
00840 laser_scan_max_range_, camera_depth_T_laser_, &laser_scan_);
00841 laser_scan_.header.frame_id = LASER_SCAN_FRAME_ID;
00842 laser_scan_thread_.data_available_mutex.unlock();
00843 laser_scan_thread_.data_available.notify_all();
00844 }
00845
00846 if (enable_3dr_mesh_ || enable_3dr_occupancy_grid_) {
00847 TangoCoordinateFramePair pair;
00848 pair.base = TANGO_COORDINATE_FRAME_START_OF_SERVICE;
00849 pair.target = TANGO_COORDINATE_FRAME_CAMERA_DEPTH;
00850 TangoPoseData start_of_service_T_camera_depth;
00851 TangoService_getPoseAtTime(point_cloud->timestamp, pair, &start_of_service_T_camera_depth);
00852 if (start_of_service_T_camera_depth.status_code != TANGO_POSE_VALID) {
00853 LOG(WARNING) << "Could not find a valid pose at time "
00854 << point_cloud->timestamp << " for the depth camera.";
00855 return;
00856 }
00857 tango_ros_conversions_helper::toTango3DR_Pose(start_of_service_T_camera_depth,
00858 &last_camera_depth_pose_);
00859 TangoSupport_updatePointCloud(point_cloud_manager_, point_cloud);
00860 new_point_cloud_available_for_t3dr_ = true;
00861 }
00862 }
00863 }
00864
00865 void TangoRosNodelet::OnFrameAvailable(TangoCameraId camera_id, const TangoImageBuffer* buffer) {
00866 if (fisheye_camera_publisher_.getNumSubscribers() > 0 &&
00867 camera_id == TangoCameraId::TANGO_CAMERA_FISHEYE &&
00868 fisheye_image_thread_.data_available_mutex.try_lock()) {
00869 fisheye_image_ = cv::Mat(buffer->height + buffer->height / 2, buffer->width,
00870 CV_8UC1, buffer->data, buffer->stride);
00871 fisheye_image_header_.stamp.fromSec(buffer->timestamp + time_offset_);
00872 fisheye_image_header_.seq = buffer->frame_number;
00873 fisheye_image_header_.frame_id =
00874 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_CAMERA_FISHEYE);
00875 fisheye_image_thread_.data_available_mutex.unlock();
00876 fisheye_image_thread_.data_available.notify_all();
00877 }
00878 if (color_camera_publisher_.getNumSubscribers() > 0 &&
00879 camera_id == TangoCameraId::TANGO_CAMERA_COLOR &&
00880 color_image_thread_.data_available_mutex.try_lock()) {
00881 color_image_ = cv::Mat(buffer->height + buffer->height / 2, buffer->width,
00882 CV_8UC1, buffer->data, buffer->stride);
00883 color_image_header_.stamp.fromSec(buffer->timestamp + time_offset_);
00884 color_image_header_.seq = buffer->frame_number;
00885 color_image_header_.frame_id =
00886 tango_ros_conversions_helper::toFrameId(TANGO_COORDINATE_FRAME_CAMERA_COLOR);
00887 color_image_thread_.data_available_mutex.unlock();
00888 color_image_thread_.data_available.notify_all();
00889 }
00890
00891 if ((enable_3dr_mesh_ || enable_3dr_occupancy_grid_) &&
00892 camera_id == TangoCameraId::TANGO_CAMERA_COLOR &&
00893 new_point_cloud_available_for_t3dr_ &&
00894 mesh_thread_.data_available_mutex.try_lock()) {
00895 if (image_buffer_manager_ == nullptr) {
00896 TangoErrorType result = TangoSupport_createImageBufferManager(
00897 buffer->format, buffer->width, buffer->height, &image_buffer_manager_);
00898 if (result != TANGO_SUCCESS) {
00899 LOG(ERROR) << "Failed to create image buffer manager.";
00900 return;
00901 }
00902 }
00903 TangoCoordinateFramePair pair;
00904 pair.base = TANGO_COORDINATE_FRAME_START_OF_SERVICE;
00905 pair.target = TANGO_COORDINATE_FRAME_CAMERA_COLOR;
00906 TangoPoseData start_of_service_T_camera_color;
00907 TangoService_getPoseAtTime(buffer->timestamp, pair, &start_of_service_T_camera_color);
00908 if (start_of_service_T_camera_color.status_code != TANGO_POSE_VALID) {
00909 LOG(WARNING) << "Could not find a valid pose at time "
00910 << buffer->timestamp << " for the color camera.";
00911 return;
00912 }
00913 tango_ros_conversions_helper::toTango3DR_Pose(start_of_service_T_camera_color,
00914 &last_camera_color_pose_);
00915 TangoSupport_updateImageBuffer(image_buffer_manager_, buffer);
00916 new_point_cloud_available_for_t3dr_ = false;
00917 mesh_thread_.data_available_mutex.unlock();
00918 mesh_thread_.data_available.notify_all();
00919 }
00920 }
00921
00922 void TangoRosNodelet::StartPublishing() {
00923 run_threads_ = true;
00924 device_pose_thread_.publish_thread =
00925 std::thread(&TangoRosNodelet::PublishDevicePose, this);
00926 point_cloud_thread_.publish_thread =
00927 std::thread(&TangoRosNodelet::PublishPointCloud, this);
00928 laser_scan_thread_.publish_thread =
00929 std::thread(&TangoRosNodelet::PublishLaserScan, this);
00930 fisheye_image_thread_.publish_thread =
00931 std::thread(&TangoRosNodelet::PublishFisheyeImage, this);
00932 color_image_thread_.publish_thread =
00933 std::thread(&TangoRosNodelet::PublishColorImage, this);
00934 mesh_thread_.publish_thread =
00935 std::thread(&TangoRosNodelet::PublishMesh, this);
00936 ros_spin_thread_ = std::thread(&TangoRosNodelet::RunRosSpin, this);
00937 }
00938
00939 void TangoRosNodelet::StopPublishing() {
00940 if (run_threads_) {
00941 run_threads_ = false;
00942 if (device_pose_thread_.publish_thread.joinable()) {
00943 if (!tango_data_available_) {
00944 device_pose_thread_.data_available.notify_all();
00945 }
00946 device_pose_thread_.publish_thread.join();
00947 }
00948 if (point_cloud_thread_.publish_thread.joinable()) {
00949 if (!tango_data_available_ || !enable_depth_ ||
00950 point_cloud_publisher_.getNumSubscribers() <= 0) {
00951 point_cloud_thread_.data_available.notify_all();
00952 }
00953 point_cloud_thread_.publish_thread.join();
00954 }
00955 if (laser_scan_thread_.publish_thread.joinable()) {
00956 if (!tango_data_available_ || !enable_depth_ ||
00957 laser_scan_publisher_.getNumSubscribers() <= 0) {
00958 laser_scan_thread_.data_available.notify_all();
00959 }
00960 laser_scan_thread_.publish_thread.join();
00961 }
00962 if (fisheye_image_thread_.publish_thread.joinable()) {
00963 if (!tango_data_available_ || !fisheye_camera_available_ ||
00964 fisheye_camera_publisher_.getNumSubscribers() <= 0) {
00965 fisheye_image_thread_.data_available.notify_all();
00966 }
00967 fisheye_image_thread_.publish_thread.join();
00968 }
00969 if (color_image_thread_.publish_thread.joinable()) {
00970 if (!tango_data_available_ || !enable_color_camera_ ||
00971 color_camera_publisher_.getNumSubscribers() <= 0) {
00972 color_image_thread_.data_available.notify_all();
00973 }
00974 color_image_thread_.publish_thread.join();
00975 }
00976 if (mesh_thread_.publish_thread.joinable()) {
00977 if (!tango_data_available_ || !enable_depth_ || !enable_color_camera_ ||
00978 (!enable_3dr_mesh_ && !enable_3dr_occupancy_grid_)) {
00979 mesh_thread_.data_available.notify_all();
00980 }
00981 mesh_thread_.publish_thread.join();
00982 }
00983 ros_spin_thread_.join();
00984 }
00985 }
00986
00987 void TangoRosNodelet::PublishDevicePose() {
00988 while(ros::ok()) {
00989 if (!run_threads_) {
00990 break;
00991 }
00992 {
00993 std::unique_lock<std::mutex> lock(device_pose_thread_.data_available_mutex);
00994 device_pose_thread_.data_available.wait(lock);
00995 if (!use_tf_static_) {
00996 PublishStaticTransforms();
00997 }
00998 if (publish_pose_on_tf_) {
00999 tf_broadcaster_.sendTransform(start_of_service_T_device_);
01000 if (area_description_T_start_of_service_.child_frame_id != "") {
01001
01002 tf_static_broadcaster_.sendTransform(area_description_T_start_of_service_);
01003 }
01004 }
01005 if (start_of_service_T_device_publisher_.getNumSubscribers() > 0) {
01006 start_of_service_T_device_publisher_.publish(start_of_service_T_device_);
01007 }
01008 if (area_description_T_start_of_service_publisher_.getNumSubscribers() > 0 &&
01009 area_description_T_start_of_service_.child_frame_id != "") {
01010
01011 area_description_T_start_of_service_publisher_.publish(area_description_T_start_of_service_);
01012 }
01013 }
01014 }
01015 }
01016
01017 void TangoRosNodelet::PublishPointCloud() {
01018 while(ros::ok()) {
01019 if (!run_threads_) {
01020 break;
01021 }
01022 {
01023 std::unique_lock<std::mutex> lock(point_cloud_thread_.data_available_mutex);
01024 point_cloud_thread_.data_available.wait(lock);
01025 if (point_cloud_publisher_.getNumSubscribers() > 0) {
01026 point_cloud_publisher_.publish(point_cloud_);
01027 }
01028 }
01029 }
01030 }
01031
01032 void TangoRosNodelet::PublishLaserScan() {
01033 while(ros::ok()) {
01034 if (!run_threads_) {
01035 break;
01036 }
01037 {
01038 std::unique_lock<std::mutex> lock(laser_scan_thread_.data_available_mutex);
01039 laser_scan_thread_.data_available.wait(lock);
01040 if (laser_scan_publisher_.getNumSubscribers() > 0) {
01041 laser_scan_publisher_.publish(laser_scan_);
01042 }
01043 }
01044 }
01045 }
01046
01047 void TangoRosNodelet::PublishFisheyeImage() {
01048 while(ros::ok()) {
01049 if (!run_threads_) {
01050 break;
01051 }
01052 {
01053 std::unique_lock<std::mutex> lock(fisheye_image_thread_.data_available_mutex);
01054 fisheye_image_thread_.data_available.wait(lock);
01055 if (fisheye_camera_publisher_.getNumSubscribers() > 0 ||
01056 fisheye_rectified_image_publisher_.getNumSubscribers() > 0) {
01057
01058
01059 cv::Mat fisheye_image_gray;
01060 cv::cvtColor(fisheye_image_, fisheye_image_gray, cv::COLOR_YUV420sp2GRAY);
01061 cv_bridge::CvImage cv_bridge_fisheye_image;
01062 cv_bridge_fisheye_image.header = fisheye_image_header_;
01063 cv_bridge_fisheye_image.encoding = sensor_msgs::image_encodings::MONO8;
01064 cv_bridge_fisheye_image.image = fisheye_image_gray;
01065 fisheye_camera_info_.header = fisheye_image_header_;
01066 fisheye_camera_info_manager_->setCameraInfo(fisheye_camera_info_);
01067 sensor_msgs::Image fisheye_image_msg;
01068 cv_bridge_fisheye_image.toImageMsg(fisheye_image_msg);
01069 fisheye_camera_publisher_.publish(fisheye_image_msg, fisheye_camera_info_);
01070
01071 if (fisheye_rectified_image_publisher_.getNumSubscribers() > 0) {
01072 cv::remap(fisheye_image_gray, fisheye_image_rect_, cv_warp_map_x_,
01073 cv_warp_map_y_, cv::INTER_LINEAR, cv::BORDER_CONSTANT, 0);
01074 sensor_msgs::ImagePtr image_rect = cv_bridge::CvImage(
01075 cv_bridge_fisheye_image.header, cv_bridge_fisheye_image.encoding,
01076 fisheye_image_rect_).toImageMsg();
01077 fisheye_rectified_image_publisher_.publish(image_rect);
01078 }
01079 }
01080 }
01081 }
01082 }
01083
01084 void TangoRosNodelet::PublishColorImage() {
01085 while(ros::ok()) {
01086 if (!run_threads_) {
01087 break;
01088 }
01089 {
01090 std::unique_lock<std::mutex> lock(color_image_thread_.data_available_mutex);
01091 color_image_thread_.data_available.wait(lock);
01092 if (color_camera_publisher_.getNumSubscribers() > 0 ||
01093 color_rectified_image_publisher_.getNumSubscribers() > 0) {
01094
01095
01096 cv::Mat color_image_rgb;
01097 cv::cvtColor(color_image_, color_image_rgb, cv::COLOR_YUV420sp2RGBA);
01098 cv_bridge::CvImage cv_bridge_color_image;
01099 cv_bridge_color_image.header = color_image_header_;
01100 cv_bridge_color_image.encoding = sensor_msgs::image_encodings::RGBA8;
01101 cv_bridge_color_image.image = color_image_rgb;
01102 color_camera_info_.header = color_image_header_;
01103 color_camera_info_manager_->setCameraInfo(color_camera_info_);
01104 sensor_msgs::Image color_image_msg;
01105 cv_bridge_color_image.toImageMsg(color_image_msg);
01106 color_camera_publisher_.publish(color_image_msg, color_camera_info_);
01107
01108 if (color_rectified_image_publisher_.getNumSubscribers() > 0) {
01109 color_camera_model_.rectifyImage(color_image_rgb, color_image_rect_);
01110 sensor_msgs::ImagePtr image_rect = cv_bridge::CvImage(
01111 cv_bridge_color_image.header, cv_bridge_color_image.encoding,
01112 color_image_rect_).toImageMsg();
01113 color_rectified_image_publisher_.publish(image_rect);
01114 }
01115 }
01116 }
01117 }
01118 }
01119
01120 void TangoRosNodelet::PublishMesh() {
01121 while(ros::ok()) {
01122 if (!run_threads_) {
01123 break;
01124 }
01125 if (enable_3dr_mesh_ || enable_3dr_occupancy_grid_) {
01126 Tango3DR_GridIndexArray t3dr_updated_indices;
01127
01128 {
01129 std::unique_lock<std::mutex> lock(mesh_thread_.data_available_mutex);
01130 mesh_thread_.data_available.wait(lock);
01131 tango_3d_reconstruction_helper::UpdateMesh(
01132 t3dr_context_, point_cloud_manager_, image_buffer_manager_,
01133 &last_camera_depth_pose_, &last_camera_color_pose_,
01134 &t3dr_updated_indices);
01135 }
01136
01137 if (enable_3dr_mesh_ && mesh_marker_publisher_.getNumSubscribers() > 0) {
01138 visualization_msgs::MarkerArray mesh_marker_array;
01139 tango_3d_reconstruction_helper::ExtractMeshAndConvertToMarkerArray(
01140 t3dr_context_, t3dr_updated_indices, time_offset_,
01141 start_of_service_frame_id_, &mesh_marker_array);
01142 mesh_marker_publisher_.publish(mesh_marker_array);
01143 Tango3DR_Status result = Tango3DR_GridIndexArray_destroy(
01144 &t3dr_updated_indices);
01145 if (result != TANGO_3DR_SUCCESS) {
01146 LOG(ERROR) << "Tango3DR_GridIndexArray_destroy failed with error code: "
01147 << result;
01148 }
01149 if (mesh_marker_array.markers.empty()) {
01150 LOG(INFO) << "Empty mesh array!";
01151 }
01152 }
01153
01154 if (enable_3dr_occupancy_grid_) {
01155 occupancy_grid_.data.clear();
01156
01157
01158
01159 if (tango_3d_reconstruction_helper::ExtractFloorPlanImageAndConvertToOccupancyGrid(
01160 t3dr_context_, time_offset_, start_of_service_frame_id_,
01161 t3dr_resolution_, t3dr_occupancy_grid_threshold_, &occupancy_grid_) &&
01162 occupancy_grid_publisher_.getNumSubscribers() > 0)
01163 occupancy_grid_publisher_.publish(occupancy_grid_);
01164 }
01165 }
01166 }
01167 }
01168
01169 void TangoRosNodelet::DynamicReconfigureCallback(PublisherConfig &config, uint32_t level) {
01170 laser_scan_max_height_ = config.laser_scan_max_height;
01171 laser_scan_min_height_ = config.laser_scan_min_height;
01172 laser_scan_min_range_ = config.laser_scan_min_range;
01173 laser_scan_max_range_ = config.laser_scan_max_range;
01174 LOG(INFO) << "laser_scan_min_height [m]: " << laser_scan_min_height_ << std::endl;
01175 LOG(INFO) << "laser_scan_max_height [m]: " << laser_scan_max_height_ << std::endl;
01176 LOG(INFO) << "laser_scan_min_range [m]: " << laser_scan_min_range_ << std::endl;
01177 LOG(INFO) << "laser_scan_max_range [m]: " << laser_scan_max_range_ << std::endl;
01178 }
01179
01180 void TangoRosNodelet::RunRosSpin() {
01181 dynamic_reconfigure::Server<tango_ros_native::PublisherConfig> server;
01182 dynamic_reconfigure::Server<tango_ros_native::PublisherConfig>::CallbackType callback =
01183 boost::bind(&TangoRosNodelet::DynamicReconfigureCallback, this, _1, _2);
01184 server.setCallback(callback);
01185 while(ros::ok()) {
01186 if (!run_threads_) {
01187 break;
01188 }
01189 ros::spinOnce();
01190 std::this_thread::sleep_for(std::chrono::milliseconds(100));
01191 }
01192 }
01193
01194 bool TangoRosNodelet::TangoConnectServiceCallback(
01195 const tango_ros_messages::TangoConnect::Request& request,
01196 tango_ros_messages::TangoConnect::Response& response) {
01197 switch (request.request) {
01198 case tango_ros_messages::TangoConnect::Request::CONNECT:
01199
01200 response.response = ConnectToTangoAndSetUpNode();
01201 break;
01202 case tango_ros_messages::TangoConnect::Request::DISCONNECT:
01203
01204 TangoDisconnect();
01205 response.response = tango_ros_messages::TangoConnect::Response::TANGO_SUCCESS;
01206 break;
01207 case tango_ros_messages::TangoConnect::Request::RECONNECT:
01208
01209 TangoDisconnect();
01210 response.response = ConnectToTangoAndSetUpNode();
01211 break;
01212 default:
01213 LOG(ERROR) << "Did not understand request " << static_cast<int>(request.request)
01214 << ", valid requests are (CONNECT: "
01215 << tango_ros_messages::TangoConnect::Request::CONNECT
01216 << ", DISCONNECT: "
01217 << tango_ros_messages::TangoConnect::Request::DISCONNECT
01218 << ", RECONNECT: "
01219 << tango_ros_messages::TangoConnect::Request::RECONNECT
01220 << ")";
01221 response.message = "Did not understand request.";
01222 return true;
01223 }
01224 return true;
01225 }
01226
01227 bool TangoRosNodelet::GetMapNameServiceCallback(
01228 const tango_ros_messages::GetMapName::Request &req,
01229 tango_ros_messages::GetMapName::Response &res) {
01230 return GetMapNameFromUuid(req.map_uuid, res.map_name);
01231 }
01232
01233 bool TangoRosNodelet::GetMapUuidsServiceCallback(
01234 const tango_ros_messages::GetMapUuids::Request& req,
01235 tango_ros_messages::GetMapUuids::Response& res) {
01236 if (!GetAvailableMapUuidsList(res.map_uuids) ) return false;
01237
01238 res.map_names.resize(res.map_uuids.size());
01239 auto map_uuids_it = res.map_uuids.begin();
01240 auto map_names_it = res.map_names.begin();
01241 for (; map_uuids_it != res.map_uuids.end() && map_names_it != res.map_names.end();
01242 ++map_uuids_it, ++map_names_it) {
01243 if (!GetMapNameFromUuid(*map_uuids_it, *map_names_it)) return false;
01244 }
01245 return true;
01246 }
01247
01248 bool TangoRosNodelet::SaveMapServiceCallback(
01249 const tango_ros_messages::SaveMap::Request& req,
01250 tango_ros_messages::SaveMap::Response& res) {
01251 bool save_localization_map = req.request & tango_ros_messages::SaveMap::Request::SAVE_LOCALIZATION_MAP;
01252 bool save_occupancy_grid = req.request & tango_ros_messages::SaveMap::Request::SAVE_OCCUPANCY_GRID;
01253 res.message = "";
01254 if (save_localization_map) {
01255 res.localization_map_name = req.map_name;
01256 if (!SaveTangoAreaDescription(res.localization_map_name, res.localization_map_uuid, res.message)) {
01257 res.success = false;
01258 return true;
01259 }
01260 tango_data_available_ = false;
01261 res.message += "\nLocalization map " + res.localization_map_uuid +
01262 " successfully saved with name " + res.localization_map_name;
01263 } else if (save_occupancy_grid) {
01264 if (!GetCurrentADFUuid(tango_config_, res.localization_map_uuid)) {
01265 res.message += "\nCould not get current localization map uuid.";
01266 res.success = false;
01267 return true;
01268 }
01269 }
01270 if (save_occupancy_grid) {
01271 std::string occupancy_grid_directory;
01272 node_handle_.param(OCCUPANCY_GRID_DIRECTORY_PARAM_NAME,
01273 occupancy_grid_directory, OCCUPANCY_GRID_DEFAULT_DIRECTORY);
01274 res.occupancy_grid_name = req.map_name;
01275 if (!res.localization_map_uuid.empty()) {
01276
01277 geometry_msgs::TransformStamped start_of_service_T_area_description;
01278 InvertTransformStamped(area_description_T_start_of_service_, &start_of_service_T_area_description);
01279 geometry_msgs::PoseStamped stamped_origin;
01280 stamped_origin.header = occupancy_grid_.header;
01281 stamped_origin.pose = occupancy_grid_.info.origin;
01282 geometry_msgs::PoseStamped stamped_origin_in_area_description;
01283 tf2::doTransform(stamped_origin, stamped_origin_in_area_description,
01284 start_of_service_T_area_description);
01285 occupancy_grid_.info.origin = stamped_origin_in_area_description.pose;
01286 occupancy_grid_.info.origin.position.z = 0.;
01287 occupancy_grid_.header.frame_id = area_description_frame_id_;
01288 }
01289 if (!occupancy_grid_file_io::SaveOccupancyGridToFiles(
01290 res.occupancy_grid_name, res.localization_map_uuid, occupancy_grid_directory, occupancy_grid_)) {
01291 res.message += "\nCould not save occupancy grid " + res.occupancy_grid_name
01292 + " in directory " + occupancy_grid_directory;
01293 res.success = false;
01294 return true;
01295 }
01296 res.message += "\nOccupancy grid successfully saved with name "
01297 + res.occupancy_grid_name + " in directory " + occupancy_grid_directory;
01298 if (res.localization_map_uuid.empty()) {
01299 res.message += "\nThe occupancy grid has been saved without localization map uuid. "
01300 "This means it will not be aligned when loaded later.";
01301 }
01302 }
01303 res.success = true;
01304 return true;
01305 }
01306
01307 bool TangoRosNodelet::LoadOccupancyGridServiceCallback(const tango_ros_messages::LoadOccupancyGrid::Request& req,
01308 tango_ros_messages::LoadOccupancyGrid::Response& res) {
01309 nav_msgs::OccupancyGrid occupancy_grid;
01310 std::string occupancy_grid_directory;
01311 node_handle_.param(OCCUPANCY_GRID_DIRECTORY_PARAM_NAME,
01312 occupancy_grid_directory, OCCUPANCY_GRID_DEFAULT_DIRECTORY);
01313
01314 std::string map_uuid;
01315 res.aligned = true;
01316 if(!occupancy_grid_file_io::LoadOccupancyGridFromFiles(
01317 req.name, occupancy_grid_directory, &occupancy_grid, &map_uuid)) {
01318 LOG(ERROR) << "Error while loading occupancy grid from file.";
01319 res.message = "Could not load occupancy grid from file " + req.name
01320 + " in directory " + occupancy_grid_directory;
01321 res.aligned = false;
01322 res.success = false;
01323 res.localization_map_uuid = "";
01324 return true;
01325 }
01326 res.localization_map_uuid = map_uuid;
01327 res.message = "Occupancy grid " + req.name + " successfully loaded from " + occupancy_grid_directory;
01328
01329 std::string current_map_uuid;
01330 if (!GetCurrentADFUuid(tango_config_, current_map_uuid)) {
01331 res.message += "\nCould not get current localization map uuid.";
01332 res.aligned = false;
01333 res.success = false;
01334 return true;
01335 }
01336 if (current_map_uuid.empty()) {
01337 res.message += "\nThe occupancy grid is not aligned because "
01338 "no localization map is currently used.";
01339 res.aligned = false;
01340 }
01341 if (map_uuid.empty()) {
01342 res.message += "\nThe occupancy grid is not aligned because "
01343 "its localization map uuid is empty.";
01344 res.aligned = false;
01345 }
01346 if (map_uuid.compare(current_map_uuid) != 0) {
01347 res.message += "\nThe occupancy grid is not aligned because "
01348 "it does not correspond to the localization map currently used.";
01349 res.aligned = false;
01350 }
01351
01352 res.success = true;
01353 if (map_uuid.empty()) {
01354 occupancy_grid.header.frame_id = start_of_service_frame_id_;
01355 } else {
01356 occupancy_grid.header.frame_id = area_description_frame_id_;
01357 }
01358 occupancy_grid.header.stamp = ros::Time::now();
01359 occupancy_grid.info.map_load_time = occupancy_grid.header.stamp;
01360 static_occupancy_grid_publisher_.publish(occupancy_grid);
01361 return true;
01362 }
01363
01364 bool TangoRosNodelet::GetAvailableMapUuidsList(std::vector<std::string>& uuid_list) {
01365 char* c_uuid_list;
01366 TangoErrorType result = TangoService_getAreaDescriptionUUIDList(&c_uuid_list);
01367 if (result != TANGO_SUCCESS) {
01368 LOG(ERROR) << "Error while retrieving all available map UUIDs, error: " << result;
01369 return false;
01370 }
01371 if (c_uuid_list == NULL || c_uuid_list[0] == '\0') {
01372 LOG(WARNING) << "No area description file available.";
01373 return false;
01374 }
01375 LOG(INFO) << "UUID list: " << c_uuid_list;
01376 uuid_list = SplitCommaSeparatedString(std::string(c_uuid_list));
01377 return true;
01378 }
01379
01380 bool TangoRosNodelet::GetMapNameFromUuid(const std::string& map_uuid, std::string& map_name) {
01381 size_t size = 0;
01382 char* value;
01383 TangoAreaDescriptionMetadata metadata;
01384 TangoErrorType result = TangoService_getAreaDescriptionMetadata(map_uuid.c_str(), &metadata);
01385 if (result != TANGO_SUCCESS) {
01386 LOG(ERROR) << "Error while trying to access area description metadata, error: " << result;
01387 return false;
01388 }
01389 result = TangoAreaDescriptionMetadata_get(metadata, "name", &size, &value);
01390 if (result != TANGO_SUCCESS) {
01391 LOG(ERROR) << "Error while trying to get area description metadata, error: " << result;
01392 return false;
01393 }
01394 map_name = std::string(value);
01395 result = TangoAreaDescriptionMetadata_free(metadata);
01396 if (result != TANGO_SUCCESS) {
01397 LOG(ERROR) << "Error while trying to free area description metadata, error: " << result;
01398 }
01399 LOG(INFO) << "Successfully retrieved map name: " << map_name << " from uuid " << map_uuid;
01400 return true;
01401 }
01402 }