00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "tabletop_collision_map_processing/collision_map_interface.h"
00037
00038 #include <tf/transform_datatypes.h>
00039
00040 #include <std_srvs/Empty.h>
00041
00042 #include <mapping_msgs/CollisionObject.h>
00043 #include <mapping_msgs/AttachedCollisionObject.h>
00044
00045 #include <object_manipulation_msgs/FindClusterBoundingBox.h>
00046
00047 #include <household_objects_database_msgs/DatabaseModelPose.h>
00048 #include <household_objects_database_msgs/GetModelMesh.h>
00049
00050 namespace tabletop_collision_map_processing {
00051
00052 static const std::string RESET_COLLISION_MAP_NAME = "collision_map_self_occ_node/reset";
00053 static const std::string MAKE_STATIC_COLLISION_MAP_ACTION_NAME = "make_static_collision_map";
00054 static const std::string CLUSTER_BOUNDING_BOX_NAME = "find_cluster_bounding_box";
00055
00056 CollisionMapInterface::CollisionMapInterface() :
00057 root_nh_(""),
00058 priv_nh_("~"),
00059 connections_established_(false),
00060 collision_object_current_id_(0),
00061 make_static_collision_map_client_(root_nh_, MAKE_STATIC_COLLISION_MAP_ACTION_NAME, true)
00062 {
00063 collision_object_pub_ = root_nh_.advertise<mapping_msgs::CollisionObject>("collision_object", 10);
00064 attached_object_pub_ = root_nh_.advertise<mapping_msgs::AttachedCollisionObject>("attached_collision_object", 10);
00065 }
00066
00067 void CollisionMapInterface::connectServices()
00068 {
00069 collision_map_reset_client_ = root_nh_.serviceClient<std_srvs::Empty>(RESET_COLLISION_MAP_NAME, true);
00070 cluster_bounding_box_client_ = root_nh_.serviceClient<object_manipulation_msgs::FindClusterBoundingBox>
00071 (CLUSTER_BOUNDING_BOX_NAME, true);
00072 priv_nh_.param<std::string>("static_map_cloud_name", static_map_cloud_name_, "full_cloud_filtered");
00073 priv_nh_.param<int>("point_skip_num", point_skip_num_, 1);
00074 priv_nh_.param<int>("collision_box_size", collision_box_size_, 0.003);
00075 }
00076
00077 bool CollisionMapInterface::connectionsPresent()
00078 {
00079 if ( !ros::service::exists(RESET_COLLISION_MAP_NAME, true) ) return false;
00080 if ( !ros::service::exists(CLUSTER_BOUNDING_BOX_NAME, true) ) return false;
00081 if (!make_static_collision_map_client_.waitForServer(ros::Duration(0.1)) )
00082 {
00083 ROS_INFO("Make static collision map action server is not connected");
00084 return false;
00085 }
00086 return true;
00087 }
00088
00089 bool CollisionMapInterface::connectionsEstablished(ros::Duration timeout)
00090 {
00091 if (connections_established_) return true;
00092 ros::Time start_time = ros::Time::now();
00093 ros::Duration ping_time = ros::Duration(1.0);
00094 if (timeout >= ros::Duration(0) && ping_time > timeout) ping_time = timeout;
00095 while (!connectionsPresent())
00096 {
00097 ping_time.sleep();
00098 if (!root_nh_.ok()) return false;
00099 if (timeout >= ros::Duration(0) &&
00100 ros::Time::now() - start_time >= timeout) return false;
00101 }
00102 connectServices();
00103 connections_established_ = true;
00104 return true;
00105 }
00106
00107 void CollisionMapInterface::resetCollisionModels()
00108 {
00109 ROS_WARN("CollisionMapInterface::resetCollisionModels");
00110 mapping_msgs::CollisionObject reset_object;
00111 reset_object.operation.operation = mapping_msgs::CollisionObjectOperation::REMOVE;
00112 reset_object.header.frame_id = "katana_base_link";
00113 reset_object.header.stamp = ros::Time::now();
00114 reset_object.id = "all";
00115 collision_object_pub_.publish(reset_object);
00116 collision_object_current_id_ = 0;
00117
00118 }
00119
00120 void CollisionMapInterface::resetAttachedModels()
00121 {
00122 ROS_WARN("CollisionMapInterface::resetAttachedModels");
00123 mapping_msgs::CollisionObject reset_object;
00124 reset_object.operation.operation = mapping_msgs::CollisionObjectOperation::REMOVE;
00125 reset_object.header.frame_id = "katana_base_link";
00126 reset_object.header.stamp = ros::Time::now();
00127 reset_object.id = "all";
00128 mapping_msgs::AttachedCollisionObject reset_attached_objects;
00129 reset_attached_objects.object.header.frame_id = "katana_base_link";
00130 reset_attached_objects.object.header.stamp = ros::Time::now();
00131 reset_attached_objects.link_name = "all";
00132 reset_attached_objects.object = reset_object;
00133 attached_object_pub_.publish(reset_attached_objects);
00134 }
00135
00136 void CollisionMapInterface::resetStaticMap()
00137 {
00138 ROS_WARN("CollisionMapInterface::resetStaticMap");
00139 std_srvs::Empty srv;
00140 if (!collision_map_reset_client_.call(srv))
00141 {
00142 ROS_ERROR("Collision map reset call failed");
00143 throw CollisionMapException("reset failed");
00144 }
00145 }
00146
00147 std::string CollisionMapInterface::getNextObjectName()
00148 {
00149 ROS_WARN("CollisionMapInterface::getNextObjectName");
00150 std::ostringstream iss;
00151 iss << collision_object_current_id_++;
00152 if (collision_object_current_id_ > 10000) collision_object_current_id_ = 0;
00153 return "graspable_object_" + iss.str();
00154 }
00155
00156 void CollisionMapInterface::takeStaticMap()
00157 {
00158 ROS_WARN("CollisionMapInterface::takeStaticMap");
00159 collision_environment_msgs::MakeStaticCollisionMapGoal static_map_goal;
00160 static_map_goal.cloud_source = static_map_cloud_name_;
00161 static_map_goal.number_of_clouds = 2;
00162
00163 make_static_collision_map_client_.sendGoal(static_map_goal);
00164
00165 if ( !make_static_collision_map_client_.waitForResult(ros::Duration(30.0)) )
00166 {
00167 ROS_ERROR("Collision map was not formed in allowed time");
00168 throw CollisionMapException("static make was not formed in allowed time");
00169 }
00170
00171 if(make_static_collision_map_client_.getState() != actionlib::SimpleClientGoalState::SUCCEEDED)
00172 {
00173 ROS_ERROR("Some non-success state was reached for static collision map. Proceed with caution");
00174 throw CollisionMapException(" static collision map failed");
00175 }
00176 }
00177
00178 void CollisionMapInterface::processCollisionGeometryForTable(const tabletop_object_detector::Table &table,
00179 std::string table_collision_name)
00180 {
00181 ROS_WARN("CollisionMapInterface::processCollisionGeometryForTable");
00182 mapping_msgs::CollisionObject table_object;
00183 table_object.operation.operation = mapping_msgs::CollisionObjectOperation::ADD;
00184 table_object.header.frame_id = table.pose.header.frame_id;
00185 table_object.header.stamp = ros::Time::now();
00186 table_object.shapes.resize(1);
00187 table_object.shapes[0].type = geometric_shapes_msgs::Shape::BOX;
00188 table_object.shapes[0].dimensions.resize(3);
00189 table_object.shapes[0].dimensions[0] = fabs(table.x_max-table.x_min);
00190 table_object.shapes[0].dimensions[1] = fabs(table.y_max-table.y_min);
00191 table_object.shapes[0].dimensions[2] = 0.01;
00192
00193 ROS_INFO("Adding table with dimensions %f %f %f to collision map",
00194 table_object.shapes[0].dimensions[0], table_object.shapes[0].dimensions[1], table_object.shapes[0].dimensions[2]);
00195
00196
00197
00198 tf::Transform table_trans;
00199 tf::poseMsgToTF(table.pose.pose, table_trans);
00200 tf::Transform table_translation;
00201 table_translation.setIdentity();
00202 table_translation.setOrigin( btVector3( (table.x_min + table.x_max)/2.0, (table.y_min + table.y_max)/2.0, 0.0) );
00203 table_trans = table_trans * table_translation;
00204 table_object.poses.resize(1);
00205 tf::poseTFToMsg(table_trans, table_object.poses[0]);
00206
00207 table_object.id = table_collision_name;
00208 collision_object_pub_.publish(table_object);
00209 }
00210
00211 void CollisionMapInterface::processCollisionGeometryForObject
00212 (const household_objects_database_msgs::DatabaseModelPose &model_pose,
00213 std::string &collision_name)
00214 {
00215 ROS_WARN("CollisionMapInterface::processCollisionGeometryForObject");
00216 mapping_msgs::CollisionObject collision_object;
00217 collision_object.shapes.resize(1);
00218
00219 if (!getMeshFromDatabasePose(model_pose, collision_object.shapes[0]))
00220 {
00221 throw CollisionMapException("Loading mesh for database object failed");
00222 }
00223 collision_object.header.frame_id = model_pose.pose.header.frame_id;
00224 collision_object.header.stamp = ros::Time::now();
00225 collision_object.poses.push_back(model_pose.pose.pose);
00226
00227 collision_object.shapes[0].type = geometric_shapes_msgs::Shape::MESH;
00228 collision_object.operation.operation = mapping_msgs::CollisionObjectOperation::ADD;
00229 collision_name = getNextObjectName();
00230 collision_object.id = collision_name;
00231 collision_object_pub_.publish(collision_object);
00232 }
00233
00234 void
00235 CollisionMapInterface::processCollisionGeometryForBoundingBox(const object_manipulation_msgs::ClusterBoundingBox &box,
00236 std::string &collision_name)
00237 {
00238 ROS_WARN("CollisionMapInterface::processCollisionGeometryForBoundingBox");
00239 ROS_INFO("Adding bounding box with dimensions %f %f %f to collision map",
00240 box.dimensions.x, box.dimensions.y, box.dimensions.z);
00241
00242 mapping_msgs::CollisionObject collision_object;
00243 collision_object.operation.operation = mapping_msgs::CollisionObjectOperation::ADD;
00244 collision_name = getNextObjectName();
00245 collision_object.id = collision_name;
00246
00247 collision_object.header.frame_id = "katana_base_link";
00248 collision_object.header.stamp = ros::Time::now();
00249
00250 geometric_shapes_msgs::Shape shape;
00251 shape.type = geometric_shapes_msgs::Shape::BOX;
00252 shape.dimensions.resize(3);
00253 shape.dimensions[0] = box.dimensions.x;
00254 shape.dimensions[1] = box.dimensions.y;
00255 shape.dimensions[2] = box.dimensions.z;
00256 collision_object.shapes.push_back(shape);
00257 collision_object.poses.push_back(box.pose_stamped.pose);
00258 ROS_WARN("so long ");
00259 collision_object_pub_.publish(collision_object);
00260 }
00261
00262 void CollisionMapInterface::processCollisionGeometryForCluster(const sensor_msgs::PointCloud &cluster,
00263 std::string &collision_name, float collision_size)
00264 {
00265 ROS_WARN("CollisionMapInterface::processCollisionGeometryForCluster");
00266 ROS_INFO("Adding cluster with %u points to collision map", (unsigned int)cluster.points.size());
00267
00268 mapping_msgs::CollisionObject many_boxes;
00269 many_boxes.operation.operation = mapping_msgs::CollisionObjectOperation::ADD;
00270 many_boxes.header = cluster.header;
00271 many_boxes.header.stamp = ros::Time::now();
00272 unsigned int num_to_use = (unsigned int)(cluster.points.size()/point_skip_num_);
00273 many_boxes.shapes.resize(num_to_use);
00274 many_boxes.poses.resize(num_to_use);
00275
00276 if(collision_size < 0)
00277 collision_size = collision_box_size_;
00278
00279 for(unsigned int i = 0; i < num_to_use; i++) {
00280 geometric_shapes_msgs::Shape shape;
00281 shape.type = geometric_shapes_msgs::Shape::BOX;
00282 shape.dimensions.resize(3);
00283 shape.dimensions[0] = collision_size;
00284 shape.dimensions[1] = collision_size;
00285 shape.dimensions[2] = collision_size;
00286 many_boxes.shapes[i]=shape;
00287 geometry_msgs::Pose pose;
00288 pose.position.x = cluster.points[i*point_skip_num_].x;
00289 pose.position.y = cluster.points[i*point_skip_num_].y;
00290 pose.position.z = cluster.points[i*point_skip_num_].z;
00291 pose.orientation.x = 0;
00292 pose.orientation.y = 0;
00293 pose.orientation.z = 0;
00294 pose.orientation.w = 1;
00295 many_boxes.poses[i] = pose;
00296 }
00297
00298 collision_name = getNextObjectName();
00299
00300 many_boxes.id = collision_name;
00301 collision_object_pub_.publish(many_boxes);
00302 }
00303
00304 bool CollisionMapInterface::getMeshFromDatabasePose(const household_objects_database_msgs::DatabaseModelPose &model_pose,
00305 geometric_shapes_msgs::Shape& mesh)
00306 {
00307
00308 ROS_WARN("CollisionMapInterface::getMeshFromDatabasePose");
00309
00310 static bool service_initialized = false;
00311 if (!service_initialized)
00312 {
00313 std::string get_model_mesh_srv_name;
00314 priv_nh_.param<std::string>("get_model_mesh_srv", get_model_mesh_srv_name, "get_model_mesh_srv");
00315 while ( !ros::service::waitForService(get_model_mesh_srv_name, ros::Duration(2.0)) && root_nh_.ok() )
00316 {
00317 ROS_INFO("Waiting for %s service to come up", get_model_mesh_srv_name.c_str());
00318 }
00319 if (!root_nh_.ok()) return false;
00320 get_model_mesh_srv_ = root_nh_.serviceClient<household_objects_database_msgs::GetModelMesh>
00321 (get_model_mesh_srv_name, true);
00322 service_initialized = true;
00323 }
00324 household_objects_database_msgs::GetModelMesh get_mesh;
00325 get_mesh.request.model_id = model_pose.model_id;
00326 if ( !get_model_mesh_srv_.call(get_mesh) ||
00327 get_mesh.response.return_code.code != get_mesh.response.return_code.SUCCESS )
00328 {
00329 return false;
00330 }
00331 mesh = get_mesh.response.mesh;
00332 return true;
00333 }
00334
00335 void CollisionMapInterface::getClusterBoundingBox(const sensor_msgs::PointCloud &cluster,
00336 geometry_msgs::PoseStamped &pose_stamped,
00337 geometry_msgs::Vector3 &dimensions)
00338 {
00339 ROS_WARN("CollisionMapInterface::getClusterBoundingBox");
00340
00341 object_manipulation_msgs::FindClusterBoundingBox srv;
00342 srv.request.cluster = cluster;
00343 if (!cluster_bounding_box_client_.call(srv.request, srv.response))
00344 {
00345 ROS_ERROR("Failed to call cluster bounding box client");
00346 throw CollisionMapException("Failed to call cluster bounding box client");
00347 }
00348 pose_stamped = srv.response.pose;
00349 dimensions = srv.response.box_dims;
00350 if (dimensions.x == 0.0 && dimensions.y == 0.0 && dimensions.z == 0.0)
00351 {
00352 ROS_ERROR("Cluster bounding box client returned an error (0.0 bounding box)");
00353 throw CollisionMapException("Bounding box computation failed");
00354 }
00355 }
00356
00358 bool CollisionMapInterface::extendBoundingBoxZToTable(const tabletop_object_detector::Table &table,
00359 geometry_msgs::PoseStamped &pose_stamped,
00360 geometry_msgs::Vector3 &dimensions)
00361 {
00362
00363 ROS_WARN("CollisionMapInterface::extendBoundingBoxZToTable");
00364
00365 if (table.pose.header.frame_id != pose_stamped.header.frame_id)
00366 {
00367 ROS_INFO("cannot extend bbox to table, they are not in the same frame");
00368 ROS_INFO("table frame: %s vs. pose_stamped frame: %s",table.pose.header.frame_id.c_str(), pose_stamped.header.frame_id.c_str());
00369 return false;
00370 }
00371
00372
00373 btVector3 table_location(table.pose.pose.position.x,
00374 table.pose.pose.position.y,
00375 table.pose.pose.position.z);
00376 btVector3 bbox_location(pose_stamped.pose.position.x,
00377 pose_stamped.pose.position.y,
00378 pose_stamped.pose.position.z);
00379 btVector3 table_to_bbox = bbox_location - table_location;
00380 btTransform table_trans;
00381 tf::poseMsgToTF(table.pose.pose, table_trans);
00382 btVector3 table_z = table_trans.getBasis().getColumn(2);
00383 ROS_INFO("Table z: %f %f %f in frame %s", table_z.getX(), table_z.getY(), table_z.getZ(), table.pose.header.frame_id.c_str());
00384 double box_to_table_distance = table_to_bbox.dot(table_z);
00385 ROS_INFO("Table distance: %f", box_to_table_distance);
00386
00387
00388
00389 btTransform bbox_trans;
00390 tf::poseMsgToTF(pose_stamped.pose, bbox_trans);
00391 btVector3 bbox_z = bbox_trans.getBasis().getColumn(2);
00392 if (fabs(bbox_z.dot(table_z)) < 0.9848)
00393 {
00394 ROS_INFO("cannot extend bbox to table; z axes do not coincide");
00395 return false;
00396 }
00397
00398 double z_to_table = box_to_table_distance;
00399 ROS_INFO("z_to_table: %f", z_to_table);
00400 if ( z_to_table < 0.005 || z_to_table > 0.3)
00401 {
00402 ROS_INFO("cannot extend bbox to table; getting z equal to %f", z_to_table);
00403 return false;
00404 }
00405 ROS_INFO("Old z: %f", dimensions.z);
00406 double new_z = dimensions.z/2.0 + z_to_table;
00407 ROS_INFO("New z: %f", new_z);
00408 pose_stamped.pose.position.z = pose_stamped.pose.position.z + (dimensions.z/2.0) - (new_z/2.0);
00409 dimensions.z = new_z;
00410 return true;
00411 }
00412
00413
00414 }