annotations_server.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2013, Yujin Robot.
00003  *
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *
00009  *     * Redistributions of source code must retain the above copyright
00010  *       notice, this list of conditions and the following disclaimer.
00011  *     * Redistributions in binary form must reproduce the above copyright
00012  *       notice, this list of conditions and the following disclaimer in the
00013  *       documentation and/or other materials provided with the distribution.
00014  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00015  *       contributors may be used to endorse or promote products derived from
00016  *       this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028  * POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00031 /*
00032  * Based on map_store, but adapted to publish/store semantic information (annotations)
00033 behavior:
00034  - sets up connection to warehouse
00035  - tells warehouse to publish latest annotations of any session (this is commented by now; can be misleading)
00036  - spins, handling service calls
00037 
00038 service calls:
00039  - publish_map(map uuid) returns true if annotations were found for the given map
00040    - queries warehouse for annotations associated to the given map
00041    - publishes the annotations on markers, tables, columns, walls topics
00042    - publishes visualization markers for all the annotations
00043    - sets map uuid as the current map, so we can update published annotations if needed
00044  - rename_map(map uuid, new name) returns void
00045    - renames the associated map identified by map_uuid on annotations database
00046  - delete_map(map uuid) returns true if annotations were found for the given map
00047    - deletes the annotations associated to the given map
00048    - if current map is set, calls publish_annotations to reflect changes
00049  - save_map(map uuid, map name, session id) returns error message if any
00050    - saves currently published annotations as associated to the given map
00051    - if current map is set, calls publish_annotations to reflect changes
00052 
00053  NOT IMPLEMENTED, and not useful by now
00054  - list_maps() returns list of map metadata: {id, name, timestamp, maybe thumbnail}
00055    - query for all annotations.
00056  - dynamic_map() returns nav_msgs/OccupancyGrid
00057    - returns the dynamic map
00058  */
00059 
00060 #include <mongo_ros/message_collection.h>
00061 #include <ros/ros.h>
00062 #include <visualization_msgs/MarkerArray.h>
00063 #include <world_canvas_msgs/Annotation.h>
00064 #include <world_canvas_msgs/AnnotationData.h>
00065 
00066 #include <world_canvas_msgs/LoadAnnotationsData.h>
00067 #include <world_canvas_msgs/SaveAnnotationsData.h>
00068 
00069 #include <string>
00070 #include <sstream>
00071 #include <exception>
00072 #include <uuid/uuid.h>
00073 
00074 namespace mr=mongo_ros;
00075 
00076 mr::MessageCollection<world_canvas_msgs::Annotation>     *anns_collection;
00077 mr::MessageCollection<world_canvas_msgs::AnnotationData> *data_collection;
00078 
00079 ros::Publisher map_pub;
00080 ros::Publisher markers_pub;
00081 
00082 visualization_msgs::MarkerArray markers_array;
00083 
00084 //world_canvas_msgs::SemanticMap map_msg;
00085 
00086 typedef std::vector<mr::MessageWithMetadata<world_canvas_msgs::Annotation>::ConstPtr>     AnnsVector;
00087 typedef std::vector<mr::MessageWithMetadata<world_canvas_msgs::AnnotationData>::ConstPtr> DataVector;
00088 
00089 std::string uuid2str(unsigned char* pUuid) {
00090   uuid_t uuid;
00091   memcpy(uuid, pUuid, sizeof(uuid_t));
00092   char uuid_string[37]; // UUID prints into 36 bytes + NULL terminator
00093   uuid_unparse_lower(uuid, uuid_string);
00094   return std::string(uuid_string);
00095 }
00096 
00097 //
00098 //void onMapReceived(const world_canvas_msgs::SemanticMap::ConstPtr& msg)
00099 //{
00100 //  map_msg = *msg;
00101 //}
00102 
00103 void clearMarkers()
00104 {
00105   for (int i = 0; i < markers_array.markers.size(); ++i)
00106   {
00107     markers_array.markers[i].action = visualization_msgs::Marker::DELETE;
00108   }
00109 
00110   if (markers_array.markers.size() > 0)
00111   {
00112     markers_pub.publish(markers_array);
00113     markers_array.markers.clear();
00114   }
00115 }
00116 
00117 visualization_msgs::Marker makeMarker(int id, const world_canvas_msgs::Annotation& ann)
00118 {
00119   std::stringstream name; name << ann.type << '/' << ann.name;
00120 
00121   visualization_msgs::Marker marker;
00122   marker.header.frame_id = ann.pose.header.frame_id;
00123   marker.header.stamp = ros::Time::now();
00124   marker.scale = ann.size;
00125   marker.color = ann.color;
00126   marker.ns = name.str();
00127   marker.id = id;
00128   marker.pose = ann.pose.pose.pose;
00129   marker.type = ann.shape;
00130   marker.action = visualization_msgs::Marker::ADD;
00131 
00132   // Make z-coordinate the lowest point of markers, so they appear to lay in the floor if they
00133   // have zero z. This is wrong for AR markers, but doesn't matter as they are rather small.
00134   marker.pose.position.z += marker.scale.z/2.0;
00135 
00136   return marker;
00137 }
00138 
00139 visualization_msgs::Marker makeLabel(const visualization_msgs::Marker& marker)
00140 {
00141   visualization_msgs::Marker label = marker;
00142   label.id = marker.id + 1000000;  // marker id must be unique
00143   label.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
00144   label.pose.position.z = marker.pose.position.z + marker.scale.z/2.0 + 0.1; // just above the visual
00145   label.text = marker.ns;
00146   label.scale.x = label.scale.y = label.scale.z = 0.12;
00147   // label.color.r = label.color.g = label.color.b = 0.0; label.color.a = 1.0; // make solid black
00148 
00149   return label;
00150 }
00151 
00152 //bool publishMap(world_canvas_msgs::PublishMap::Request &request,
00153 //                world_canvas_msgs::PublishMap::Response &response)
00154 //{
00155 //  ROS_INFO("Publish semantic map '%s'", request.map_uuid.c_str());
00156 //
00160 //
00161 //  try
00162 //  {
00163 //    // remove from visualization tools and delete visualization markers
00164 //    clearMarkers();
00165 //
00166 //    MapsVector matching_maps =
00167 //        maps_collection->pullAllResults(mr::Query("map_uuid", request.map_uuid));
00168 //
00169 //    if (matching_maps.size() == 0)
00170 //    {
00171 //      ROS_WARN("No semantic map found for id '%s'; we don't consider this an error",
00172 //               request.map_uuid.c_str());
00173 //      response.found = false;
00174 //      return true;  // we don't consider this an error
00175 //    }
00176 //    else if (matching_maps.size() > 1)
00177 //    {
00178 //      // Extra sanity checking
00179 //      ROS_WARN("More than one (%lu) semantic maps found for id '%s'; we consider only the first one",
00180 //               matching_maps.size(), request.map_uuid.c_str());
00181 //    }
00182 //
00183 //    // At least one map found; publish it
00184 //    response.found = true;
00185 //
00186 //    ROS_INFO("Semantic map fetched containing %lu annotations",
00187 //             matching_maps[0]->annotations.size());
00188 //    map_pub.publish(world_canvas_msgs::SemanticMapConstPtr(matching_maps[0]));
00189 //
00190 //    // compose and publish visualization markers
00191 //    for (int i = 0; i < matching_maps[0]->annotations.size(); ++i)
00192 //    {
00193 //      world_canvas_msgs::Annotation ann = matching_maps[0]->annotations[i];
00194 //      markers_array.markers.push_back(makeMarker(i, ann));
00195 //      markers_array.markers.push_back(makeLabel(markers_array.markers.back()));
00196 //    }
00197 //
00198 //    if (markers_array.markers.size() > 0)
00199 //      markers_pub.publish(markers_array);
00200 //
00201 //    // Keep track of currently published annotations to republish if we receive updated data
00202 //    pub_map_id = request.map_uuid;
00203 //    return true;
00204 //  }
00205 //  catch(const std::exception &e) {
00206 //    ROS_ERROR("Error during query: %s", e.what());
00207 //    return false;
00208 //  }
00209 //
00210 //  return true;
00211 //}
00212 
00213 bool loadAnnotationsData(world_canvas_msgs::LoadAnnotationsData::Request &request,
00214                          world_canvas_msgs::LoadAnnotationsData::Response &response)
00215 {
00216   try
00217   {
00218     AnnsVector matching_anns =
00219         anns_collection->pullAllResults(mr::Query("map_uuid", request.map_uuid));
00220 
00221     if (matching_anns.size() == 0)
00222     {
00223       ROS_INFO("No annotations found for map '%s'; we don't consider this an error",
00224                 request.map_uuid.c_str());
00225       response.result = true;
00226       return true;  // we don't consider this an error
00227     }
00228 
00229     DataVector matching_data =
00230         data_collection->pullAllResults(mr::Query("map_uuid", request.map_uuid));
00231 
00232     if (matching_anns.size() != matching_data.size())
00233     {
00234       // we consider this an error by now, as we assume a 1 to 1 relationship;
00235       // but in future implementations this will change, probably, to a N to 1 relationship
00236       ROS_ERROR("Pulled annotations and associated data don't match (%lu != %lu)",
00237                matching_anns.size(), matching_data.size());
00238       response.message = "Pulled annotations and associated data don't match";
00239       response.result = false;
00240       return false;
00241     }
00242 
00243     response.annotations.reserve(matching_anns.size());
00244     response.data.reserve(matching_data.size());
00245     for (int i = 0; i < matching_anns.size(); ++i)
00246     {
00247       response.annotations.push_back(*matching_anns[i]);
00248       response.data.push_back(*matching_data[i]);
00249     }
00250 
00251     ROS_INFO("%lu annotations loaded", matching_anns.size());
00252     response.result = true;
00253     return true;
00254   }
00255   catch(const std::exception &e) {
00256     ROS_ERROR("Error during query: %s", e.what());
00257     response.message = e.what();
00258     response.result = false;
00259     return false;
00260   }
00261 }
00262 
00263 bool saveAnnotationsData(world_canvas_msgs::SaveAnnotationsData::Request &request,
00264                          world_canvas_msgs::SaveAnnotationsData::Response &response)
00265 {
00266   for (int i = 0; i < request.annotations.size(); ++i)
00267   {
00268     world_canvas_msgs::Annotation annotation = request.annotations[i];
00269     world_canvas_msgs::AnnotationData data = request.data[i];
00271     std::string annotation_id = uuid2str(annotation.id.uuid.c_array());
00272     mr::Metadata metadata = mr::Metadata("map_uuid", annotation.map_uuid,
00274                                          "id",       annotation_id);
00275 //    mr::Metadata metadata = mr::Metadata("timestamp",   request.map_name,
00276 //                                         "map_uuid",   request.map_uuid,
00277 //                                         "world_id", request.session_id,
00278 //                                         "id",   request.map_uuid,
00279 //                                         "name", request.session_id,
00280 //                                         "type", request.session_id);
00281 
00282     ROS_DEBUG("Saving annotation %s for map %s", annotation_id.c_str(), annotation.map_uuid.c_str());
00283     try
00284     {
00286       anns_collection->removeMessages(mr::Query("id", annotation_id));
00287       anns_collection->insert(annotation, metadata);
00288       data_collection->removeMessages(mr::Query("id", annotation_id));
00289       data_collection->insert(data, metadata);
00290     }
00291     catch (mongo::DBException& e)
00292     {
00293       ROS_ERROR("Error during saving: %s", e.what());
00294       response.message = e.what();
00295       response.result = false;
00296       return false;
00297     }
00298   }
00299 
00300   ROS_INFO("%lu annotations saved", request.annotations.size());
00301   response.result = true;
00302   return true;
00303 }
00304 
00305 
00306 int main (int argc, char** argv)
00307 {
00308   ros::init(argc, argv, "annotations_server");
00309   ros::NodeHandle nh;
00310 
00311   anns_collection = new mr::MessageCollection<world_canvas_msgs::Annotation> ("world_canvas", "annotations");
00312   anns_collection->ensureIndex("id");
00313 
00314   data_collection = new mr::MessageCollection<world_canvas_msgs::AnnotationData> ("world_canvas", "annotations_data");
00315   data_collection->ensureIndex("id");
00316 
00317 //  map_pub = nh.advertise<world_canvas_msgs::SemanticMap> ("semantics_out", 1, true);
00318   markers_pub = nh.advertise<visualization_msgs::MarkerArray>  ("visual_markers", 1, true);
00319 //  if (last_map != "")
00320 //  {
00321 //    nav_msgs::OccupancyGridConstPtr map;
00322 //    if (lookupMap(last_map, map))
00323 //    {
00324 //      try {
00325 //      map_publisher.publish(map);
00326 //      } catch(...) {
00327 //      ROS_ERROR("Error publishing map");
00328 //      }
00329 //    }
00330 //    else
00331 //    {
00332 //      ROS_ERROR("Invalid last_map_id");
00333 //    }
00334 //  }
00335 
00336 //  ros::Subscriber map_sub = nh.subscribe("semantics_in", 1, onMapReceived);
00337 
00338 //  ros::ServiceServer publish_map_srv = nh.advertiseService("publish_map", publishMap);
00339 //  ros::ServiceServer delete_map_srv  = nh.advertiseService("delete_map",  deleteMap);
00340 //  ros::ServiceServer rename_map_srv  = nh.advertiseService("rename_map",  renameMap);
00341   ros::ServiceServer load_data_srv = nh.advertiseService("load_annotations_data", loadAnnotationsData);
00342   ros::ServiceServer save_data_srv = nh.advertiseService("save_annotations_data", saveAnnotationsData);
00343 
00344 //  NOT IMPLEMENTED, and not useful by now
00345 //  ros::ServiceServer list_map_srv    = nh.advertiseService("list_maps",    listMap);
00346 //  ros::ServiceServer dynamic_map_srv = nh.advertiseService("dynamic_map", dynamicMap);
00347 
00348   ROS_DEBUG("Annotations server running");
00349 
00350   ros::spin();
00351 
00352   delete anns_collection;
00353   delete data_collection;
00354 
00355   return 0;
00356 }


world_canvas_server
Author(s): Jorge Santos Simón
autogenerated on Thu Jun 6 2019 21:25:06