00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "cartographer_rviz/submaps_display.h"
00018
00019 #include "OgreResourceGroupManager.h"
00020 #include "absl/memory/memory.h"
00021 #include "absl/synchronization/mutex.h"
00022 #include "cartographer/mapping/id.h"
00023 #include "cartographer_ros_msgs/SubmapList.h"
00024 #include "cartographer_ros_msgs/SubmapQuery.h"
00025 #include "geometry_msgs/TransformStamped.h"
00026 #include "pluginlib/class_list_macros.h"
00027 #include "ros/package.h"
00028 #include "ros/ros.h"
00029 #include "rviz/display_context.h"
00030 #include "rviz/frame_manager.h"
00031 #include "rviz/properties/bool_property.h"
00032 #include "rviz/properties/string_property.h"
00033
00034 namespace cartographer_rviz {
00035
00036 namespace {
00037
00038 constexpr int kMaxOnGoingRequestsPerTrajectory = 6;
00039 constexpr char kMaterialsDirectory[] = "/ogre_media/materials";
00040 constexpr char kGlsl120Directory[] = "/glsl120";
00041 constexpr char kScriptsDirectory[] = "/scripts";
00042 constexpr char kDefaultTrackingFrame[] = "base_link";
00043 constexpr char kDefaultSubmapQueryServiceName[] = "/submap_query";
00044
00045 }
00046
00047 SubmapsDisplay::SubmapsDisplay() : tf_listener_(tf_buffer_) {
00048 submap_query_service_property_ = new ::rviz::StringProperty(
00049 "Submap query service", kDefaultSubmapQueryServiceName,
00050 "Submap query service to connect to.", this, SLOT(Reset()));
00051 tracking_frame_property_ = new ::rviz::StringProperty(
00052 "Tracking frame", kDefaultTrackingFrame,
00053 "Tracking frame, used for fading out submaps.", this);
00054 slice_high_resolution_enabled_ = new ::rviz::BoolProperty(
00055 "High Resolution", true, "Display high resolution slices.", this,
00056 SLOT(ResolutionToggled()), this);
00057 slice_low_resolution_enabled_ = new ::rviz::BoolProperty(
00058 "Low Resolution", false, "Display low resolution slices.", this,
00059 SLOT(ResolutionToggled()), this);
00060 client_ = update_nh_.serviceClient<::cartographer_ros_msgs::SubmapQuery>("");
00061 trajectories_category_ = new ::rviz::Property(
00062 "Submaps", QVariant(), "List of all submaps, organized by trajectories.",
00063 this);
00064 visibility_all_enabled_ = new ::rviz::BoolProperty(
00065 "All", true,
00066 "Whether submaps from all trajectories should be displayed or not.",
00067 trajectories_category_, SLOT(AllEnabledToggled()), this);
00068 pose_markers_all_enabled_ = new ::rviz::BoolProperty(
00069 "All Submap Pose Markers", true,
00070 "Whether submap pose markers should be displayed or not.",
00071 trajectories_category_, SLOT(PoseMarkersEnabledToggled()), this);
00072 fade_out_start_distance_in_meters_ =
00073 new ::rviz::FloatProperty("Fade-out distance", 1.f,
00074 "Distance in meters in z-direction beyond "
00075 "which submaps will start to fade out.",
00076 this);
00077 const std::string package_path = ::ros::package::getPath(ROS_PACKAGE_NAME);
00078 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
00079 package_path + kMaterialsDirectory, "FileSystem", ROS_PACKAGE_NAME);
00080 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
00081 package_path + kMaterialsDirectory + kGlsl120Directory, "FileSystem",
00082 ROS_PACKAGE_NAME);
00083 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
00084 package_path + kMaterialsDirectory + kScriptsDirectory, "FileSystem",
00085 ROS_PACKAGE_NAME);
00086 Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
00087 }
00088
00089 SubmapsDisplay::~SubmapsDisplay() {
00090 client_.shutdown();
00091 trajectories_.clear();
00092 scene_manager_->destroySceneNode(map_node_);
00093 }
00094
00095 void SubmapsDisplay::Reset() { reset(); }
00096
00097 void SubmapsDisplay::CreateClient() {
00098 client_ = update_nh_.serviceClient<::cartographer_ros_msgs::SubmapQuery>(
00099 submap_query_service_property_->getStdString());
00100 }
00101
00102 void SubmapsDisplay::onInitialize() {
00103 MFDClass::onInitialize();
00104 map_node_ = scene_manager_->getRootSceneNode()->createChildSceneNode();
00105 CreateClient();
00106 }
00107
00108 void SubmapsDisplay::reset() {
00109 MFDClass::reset();
00110 absl::MutexLock locker(&mutex_);
00111 client_.shutdown();
00112 trajectories_.clear();
00113 CreateClient();
00114 }
00115
00116 void SubmapsDisplay::processMessage(
00117 const ::cartographer_ros_msgs::SubmapList::ConstPtr& msg) {
00118 absl::MutexLock locker(&mutex_);
00119 map_frame_ = absl::make_unique<std::string>(msg->header.frame_id);
00120
00121
00122 for (const ::cartographer_ros_msgs::SubmapEntry& submap_entry : msg->submap) {
00123 const size_t trajectory_id = submap_entry.trajectory_id;
00124 if (trajectories_.count(trajectory_id) == 0) {
00125 continue;
00126 }
00127 const auto& trajectory_submaps = trajectories_[trajectory_id]->submaps;
00128 const auto it = trajectory_submaps.find(submap_entry.submap_index);
00129 if (it != trajectory_submaps.end() &&
00130 it->second->version() > submap_entry.submap_version) {
00131
00132 trajectories_.clear();
00133 break;
00134 }
00135 }
00136 using ::cartographer::mapping::SubmapId;
00137 std::set<SubmapId> listed_submaps;
00138 std::set<int> listed_trajectories;
00139 for (const ::cartographer_ros_msgs::SubmapEntry& submap_entry : msg->submap) {
00140 const SubmapId id{submap_entry.trajectory_id, submap_entry.submap_index};
00141 listed_submaps.insert(id);
00142 listed_trajectories.insert(submap_entry.trajectory_id);
00143 if (trajectories_.count(id.trajectory_id) == 0) {
00144 trajectories_.insert(std::make_pair(
00145 id.trajectory_id,
00146 absl::make_unique<Trajectory>(
00147 absl::make_unique<::rviz::BoolProperty>(
00148 QString("Trajectory %1").arg(id.trajectory_id),
00149 visibility_all_enabled_->getBool(),
00150 QString(
00151 "List of all submaps in Trajectory %1. The checkbox "
00152 "controls whether all submaps in this trajectory should "
00153 "be displayed or not.")
00154 .arg(id.trajectory_id),
00155 trajectories_category_),
00156 pose_markers_all_enabled_->getBool())));
00157 }
00158 auto& trajectory_visibility = trajectories_[id.trajectory_id]->visibility;
00159 auto& trajectory_submaps = trajectories_[id.trajectory_id]->submaps;
00160 auto& pose_markers_visibility =
00161 trajectories_[id.trajectory_id]->pose_markers_visibility;
00162 if (trajectory_submaps.count(id.submap_index) == 0) {
00163
00164 constexpr float kSubmapPoseAxesLength = 0.3f;
00165 constexpr float kSubmapPoseAxesRadius = 0.06f;
00166 trajectory_submaps.emplace(
00167 id.submap_index,
00168 absl::make_unique<DrawableSubmap>(
00169 id, context_, map_node_, trajectory_visibility.get(),
00170 trajectory_visibility->getBool(),
00171 pose_markers_visibility->getBool(), kSubmapPoseAxesLength,
00172 kSubmapPoseAxesRadius));
00173 trajectory_submaps.at(id.submap_index)
00174 ->SetSliceVisibility(0, slice_high_resolution_enabled_->getBool());
00175 trajectory_submaps.at(id.submap_index)
00176 ->SetSliceVisibility(1, slice_low_resolution_enabled_->getBool());
00177 }
00178 trajectory_submaps.at(id.submap_index)->Update(msg->header, submap_entry);
00179 }
00180
00181 for (auto it = trajectories_.begin(); it != trajectories_.end();) {
00182 if (listed_trajectories.count(it->first) == 0) {
00183 it = trajectories_.erase(it);
00184 } else {
00185 ++it;
00186 }
00187 }
00188
00189 for (const auto& trajectory_by_id : trajectories_) {
00190 const int trajectory_id = trajectory_by_id.first;
00191 auto& trajectory_submaps = trajectory_by_id.second->submaps;
00192 for (auto it = trajectory_submaps.begin();
00193 it != trajectory_submaps.end();) {
00194 if (listed_submaps.count(
00195 SubmapId{static_cast<int>(trajectory_id), it->first}) == 0) {
00196 it = trajectory_submaps.erase(it);
00197 } else {
00198 ++it;
00199 }
00200 }
00201 }
00202 }
00203
00204 void SubmapsDisplay::update(const float wall_dt, const float ros_dt) {
00205 absl::MutexLock locker(&mutex_);
00206
00207 for (const auto& trajectory_by_id : trajectories_) {
00208 int num_ongoing_requests = 0;
00209 for (const auto& submap_entry : trajectory_by_id.second->submaps) {
00210 if (submap_entry.second->QueryInProgress()) {
00211 ++num_ongoing_requests;
00212 }
00213 }
00214 for (auto it = trajectory_by_id.second->submaps.rbegin();
00215 it != trajectory_by_id.second->submaps.rend() &&
00216 num_ongoing_requests < kMaxOnGoingRequestsPerTrajectory;
00217 ++it) {
00218 if (it->second->MaybeFetchTexture(&client_)) {
00219 ++num_ongoing_requests;
00220 }
00221 }
00222 }
00223 if (map_frame_ == nullptr) {
00224 return;
00225 }
00226
00227 const ros::Time kLatest(0);
00228 try {
00229 const ::geometry_msgs::TransformStamped transform_stamped =
00230 tf_buffer_.lookupTransform(
00231 *map_frame_, tracking_frame_property_->getStdString(), kLatest);
00232 for (auto& trajectory_by_id : trajectories_) {
00233 for (auto& submap_entry : trajectory_by_id.second->submaps) {
00234 submap_entry.second->SetAlpha(
00235 transform_stamped.transform.translation.z,
00236 fade_out_start_distance_in_meters_->getFloat());
00237 }
00238 }
00239 } catch (const tf2::TransformException& ex) {
00240 ROS_WARN_THROTTLE(1., "Could not compute submap fading: %s", ex.what());
00241 }
00242
00243 Ogre::Vector3 position;
00244 Ogre::Quaternion orientation;
00245 if (context_->getFrameManager()->getTransform(*map_frame_, kLatest, position,
00246 orientation)) {
00247 map_node_->setPosition(position);
00248 map_node_->setOrientation(orientation);
00249 context_->queueRender();
00250 }
00251 }
00252
00253 void SubmapsDisplay::AllEnabledToggled() {
00254 absl::MutexLock locker(&mutex_);
00255 const bool visible = visibility_all_enabled_->getBool();
00256 for (auto& trajectory_by_id : trajectories_) {
00257 trajectory_by_id.second->visibility->setBool(visible);
00258 }
00259 }
00260
00261 void SubmapsDisplay::PoseMarkersEnabledToggled() {
00262 absl::MutexLock locker(&mutex_);
00263 const bool visible = pose_markers_all_enabled_->getBool();
00264 for (auto& trajectory_by_id : trajectories_) {
00265 trajectory_by_id.second->pose_markers_visibility->setBool(visible);
00266 }
00267 }
00268
00269 void SubmapsDisplay::ResolutionToggled() {
00270 absl::MutexLock locker(&mutex_);
00271 for (auto& trajectory_by_id : trajectories_) {
00272 for (auto& submap_entry : trajectory_by_id.second->submaps) {
00273 submap_entry.second->SetSliceVisibility(
00274 0, slice_high_resolution_enabled_->getBool());
00275 submap_entry.second->SetSliceVisibility(
00276 1, slice_low_resolution_enabled_->getBool());
00277 }
00278 }
00279 }
00280
00281 void Trajectory::AllEnabledToggled() {
00282 const bool visible = visibility->getBool();
00283 for (auto& submap_entry : submaps) {
00284 submap_entry.second->set_visibility(visible);
00285 }
00286 }
00287
00288 void Trajectory::PoseMarkersEnabledToggled() {
00289 const bool visible = pose_markers_visibility->getBool();
00290 for (auto& submap_entry : submaps) {
00291 submap_entry.second->set_pose_markers_visibility(visible);
00292 }
00293 }
00294
00295 Trajectory::Trajectory(std::unique_ptr<::rviz::BoolProperty> property,
00296 const bool pose_markers_enabled)
00297 : visibility(std::move(property)) {
00298 ::QObject::connect(visibility.get(), SIGNAL(changed()), this,
00299 SLOT(AllEnabledToggled()));
00300
00301
00302 pose_markers_visibility = absl::make_unique<::rviz::BoolProperty>(
00303 QString("Submap Pose Markers"), pose_markers_enabled,
00304 QString("Toggles the submap pose markers of this trajectory."),
00305 visibility.get());
00306 ::QObject::connect(pose_markers_visibility.get(), SIGNAL(changed()), this,
00307 SLOT(PoseMarkersEnabledToggled()));
00308 }
00309
00310 }
00311
00312 PLUGINLIB_EXPORT_CLASS(cartographer_rviz::SubmapsDisplay, ::rviz::Display)