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 <arm_navigation_msgs/CollisionObject.h>
00043 #include <arm_navigation_msgs/AttachedCollisionObject.h>
00044
00045 #include <object_manipulation_msgs/FindClusterBoundingBox.h>
00046 #include <object_manipulation_msgs/FindClusterBoundingBox2.h>
00047
00048 #include <household_objects_database_msgs/DatabaseModelPose.h>
00049 #include <household_objects_database_msgs/GetModelMesh.h>
00050
00051 #include <object_manipulator/tools/msg_helpers.h>
00052
00053 namespace tabletop_collision_map_processing {
00054
00055 static const std::string CLUSTER_BOUNDING_BOX_NAME = "find_cluster_bounding_box";
00056 static const std::string CLUSTER_BOUNDING_BOX2_NAME = "find_cluster_bounding_box2";
00057 static const std::string CLUSTER_BOUNDING_BOX_3D_NAME = "find_cluster_bounding_box_3d";
00058 static const std::string CLUSTER_BOUNDING_BOX2_3D_NAME = "find_cluster_bounding_box2_3d";
00059
00060 CollisionMapInterface::CollisionMapInterface() :
00061 root_nh_(""),
00062 priv_nh_("~"),
00063 connections_established_(false),
00064 collision_object_current_id_(0)
00065 {
00066 collision_object_pub_ = root_nh_.advertise<arm_navigation_msgs::CollisionObject>("collision_object", 10);
00067 attached_object_pub_ = root_nh_.advertise<arm_navigation_msgs::AttachedCollisionObject>("attached_collision_object", 10);
00068 }
00069
00070 void CollisionMapInterface::connectServices()
00071 {
00072 cluster_bounding_box_client_ = root_nh_.serviceClient<object_manipulation_msgs::FindClusterBoundingBox>
00073 (CLUSTER_BOUNDING_BOX_NAME, true);
00074 cluster_bounding_box2_client_ = root_nh_.serviceClient<object_manipulation_msgs::FindClusterBoundingBox2>
00075 (CLUSTER_BOUNDING_BOX2_NAME, true);
00076 cluster_bounding_box_3d_client_ = root_nh_.serviceClient<object_manipulation_msgs::FindClusterBoundingBox>
00077 (CLUSTER_BOUNDING_BOX_3D_NAME, true);
00078 cluster_bounding_box2_3d_client_ = root_nh_.serviceClient<object_manipulation_msgs::FindClusterBoundingBox2>
00079 (CLUSTER_BOUNDING_BOX2_3D_NAME, true);
00080 priv_nh_.param<int>("point_skip_num", point_skip_num_, 1);
00081 priv_nh_.param<int>("collision_box_size", collision_box_size_, 0.003);
00082 priv_nh_.param<double>("table_thickness", table_thickness_, 0.);
00083 }
00084
00085 bool CollisionMapInterface::connectionsPresent()
00086 {
00087 if ( !ros::service::exists(CLUSTER_BOUNDING_BOX_NAME, true) ) return false;
00088 if ( !ros::service::exists(CLUSTER_BOUNDING_BOX2_NAME, true) ) return false;
00089 return true;
00090 }
00091
00092 bool CollisionMapInterface::connectionsEstablished(ros::Duration timeout)
00093 {
00094 if (connections_established_) return true;
00095 ros::Time start_time = ros::Time::now();
00096 ros::Duration ping_time = ros::Duration(1.0);
00097 if (timeout >= ros::Duration(0) && ping_time > timeout) ping_time = timeout;
00098 while (!connectionsPresent())
00099 {
00100 ping_time.sleep();
00101 if (!root_nh_.ok()) return false;
00102 if (timeout >= ros::Duration(0) &&
00103 ros::Time::now() - start_time >= timeout) return false;
00104 }
00105 connectServices();
00106 connections_established_ = true;
00107 return true;
00108 }
00109
00110 void CollisionMapInterface::removeCollisionModel(std::string collision_name)
00111 {
00112 arm_navigation_msgs::CollisionObject reset_object;
00113 reset_object.operation.operation = arm_navigation_msgs::CollisionObjectOperation::REMOVE;
00114 reset_object.header.frame_id = "base_link";
00115 reset_object.header.stamp = ros::Time::now();
00116 reset_object.id = collision_name;
00117 collision_object_pub_.publish(reset_object);
00118 }
00119
00120 void CollisionMapInterface::resetCollisionModels()
00121 {
00122 arm_navigation_msgs::CollisionObject reset_object;
00123 reset_object.operation.operation = arm_navigation_msgs::CollisionObjectOperation::REMOVE;
00124 reset_object.header.frame_id = "base_link";
00125 reset_object.header.stamp = ros::Time::now();
00126 reset_object.id = "all";
00127 collision_object_pub_.publish(reset_object);
00128
00129 }
00130
00131 void CollisionMapInterface::resetAttachedModels()
00132 {
00133 arm_navigation_msgs::CollisionObject reset_object;
00134 reset_object.operation.operation = arm_navigation_msgs::CollisionObjectOperation::REMOVE;
00135 reset_object.header.frame_id = "base_link";
00136 reset_object.header.stamp = ros::Time::now();
00137 reset_object.id = "all";
00138 arm_navigation_msgs::AttachedCollisionObject reset_attached_objects;
00139 reset_attached_objects.object.header.frame_id = "base_link";
00140 reset_attached_objects.object.header.stamp = ros::Time::now();
00141 reset_attached_objects.link_name = "all";
00142 reset_attached_objects.object = reset_object;
00143 attached_object_pub_.publish(reset_attached_objects);
00144 }
00145
00146 std::string CollisionMapInterface::getNextObjectName()
00147 {
00148 std::ostringstream iss;
00149 iss << collision_object_current_id_++;
00150 if (collision_object_current_id_ > 10000) collision_object_current_id_ = 0;
00151 return "graspable_object_" + iss.str();
00152 }
00153
00154 void CollisionMapInterface::processCollisionGeometryForTable(const tabletop_object_detector::Table &table,
00155 std::string table_collision_name)
00156 {
00157 arm_navigation_msgs::CollisionObject table_object;
00158 table_object.operation.operation = arm_navigation_msgs::CollisionObjectOperation::ADD;
00159 table_object.header.frame_id = table.pose.header.frame_id;
00160 table_object.header.stamp = ros::Time::now();
00161 table_object.shapes.resize(1);
00162 table_object.poses.resize(1);
00163
00164
00165 if(table.convex_hull.triangles.size() != 0)
00166 {
00167 ROS_INFO("using convex hull mesh for table collision geometry");
00168 arm_navigation_msgs::Shape table_shape;
00169 table_shape.type = table_shape.MESH;
00170 table_shape.vertices = table.convex_hull.vertices;
00171 for (size_t i=0; i<table.convex_hull.triangles.size(); i++)
00172 {
00173 table_shape.triangles.push_back( table.convex_hull.triangles.at(i).vertex_indices.at(0) );
00174 table_shape.triangles.push_back( table.convex_hull.triangles.at(i).vertex_indices.at(1) );
00175 table_shape.triangles.push_back( table.convex_hull.triangles.at(i).vertex_indices.at(2) );
00176 }
00177 table_object.shapes[0] = table_shape;
00178 table_object.poses[0] = table.pose.pose;
00179 if(table_thickness_)
00180 {
00181 ROS_INFO("using table_thickness of %.3f", table_thickness_);
00182 tf::Transform T, P;
00183 tf::poseMsgToTF(table.pose.pose, P);
00184 geometry_msgs::Pose shifted_table_pose;
00185 geometry_msgs::Pose shifted_table_offset = object_manipulator::msg::createPoseMsg(tf::Pose(tf::Quaternion::getIdentity(), tf::Vector3(0,0,-table_thickness_)));
00186 tf::poseMsgToTF(shifted_table_offset, T);
00187 tf::poseTFToMsg( P*T, shifted_table_pose);
00188 table_object.shapes.push_back(table_shape);
00189 table_object.poses.push_back(shifted_table_pose);
00190 }
00191 }
00192
00193
00194 else
00195 {
00196 ROS_INFO("using box table collision geometry");
00197 table_object.shapes[0].type = arm_navigation_msgs::Shape::BOX;
00198 table_object.shapes[0].dimensions.resize(3);
00199 table_object.shapes[0].dimensions[0] = fabs(table.x_max-table.x_min);
00200 table_object.shapes[0].dimensions[1] = fabs(table.y_max-table.y_min);
00201 if(table_thickness_) table_object.shapes[0].dimensions[2] = table_thickness_;
00202 else table_object.shapes[0].dimensions[2] = 0.01;
00203
00204
00205 tf::Transform table_trans;
00206 tf::poseMsgToTF(table.pose.pose, table_trans);
00207 tf::Transform table_translation;
00208 table_translation.setIdentity();
00209 table_translation.setOrigin( tf::Vector3( (table.x_min + table.x_max)/2.0, (table.y_min + table.y_max)/2.0, 0.0) );
00210 table_trans = table_trans * table_translation;
00211 tf::poseTFToMsg(table_trans, table_object.poses[0]);
00212 }
00213
00214 table_object.id = table_collision_name;
00215 collision_object_pub_.publish(table_object);
00216 }
00217
00218 void CollisionMapInterface::processCollisionGeometryForObject
00219 (const household_objects_database_msgs::DatabaseModelPose &model_pose,
00220 std::string &collision_name)
00221 {
00222 arm_navigation_msgs::CollisionObject collision_object;
00223 collision_object.shapes.resize(1);
00224
00225 if (!getMeshFromDatabasePose(model_pose, collision_object.shapes[0]))
00226 {
00227 throw CollisionMapException("Loading mesh for database object failed");
00228 }
00229 collision_object.header.frame_id = model_pose.pose.header.frame_id;
00230 collision_object.header.stamp = ros::Time::now();
00231 collision_object.poses.push_back(model_pose.pose.pose);
00232
00233 collision_object.shapes[0].type = arm_navigation_msgs::Shape::MESH;
00234 collision_object.operation.operation = arm_navigation_msgs::CollisionObjectOperation::ADD;
00235 collision_name = getNextObjectName();
00236 collision_object.id = collision_name;
00237 collision_object_pub_.publish(collision_object);
00238 }
00239
00240
00241 void CollisionMapInterface::processCollisionGeometryForObjectAsBoundingBox
00242 (const household_objects_database_msgs::DatabaseModelPose &model_pose,
00243 std::string &collision_name)
00244 {
00245 arm_navigation_msgs::Shape model_shape;
00246 if (!getMeshFromDatabasePose(model_pose, model_shape))
00247 {
00248 throw CollisionMapException("Loading mesh for database object failed");
00249 }
00250 sensor_msgs::PointCloud cluster;
00251 cluster.header = model_pose.pose.header;
00252 for (size_t i=0; i<model_shape.vertices.size(); i++)
00253 {
00254 geometry_msgs::Point32 point;
00255 point.x = model_shape.vertices[i].x;
00256 point.y = model_shape.vertices[i].y;
00257 point.z = model_shape.vertices[i].z;
00258 cluster.points.push_back(point);
00259 }
00260 object_manipulation_msgs::ClusterBoundingBox box;
00261 getClusterBoundingBox(cluster, box.pose_stamped, box.dimensions);
00262
00263 arm_navigation_msgs::CollisionObject collision_object;
00264 collision_object.operation.operation = arm_navigation_msgs::CollisionObjectOperation::ADD;
00265
00266 collision_name = getNextObjectName();
00267 collision_object.id = collision_name;
00268
00269 collision_object.header.frame_id = model_pose.pose.header.frame_id;
00270 collision_object.header.stamp = ros::Time::now();
00271
00272 arm_navigation_msgs::Shape shape;
00273 shape.type = arm_navigation_msgs::Shape::BOX;
00274 shape.dimensions.resize(3);
00275 shape.dimensions[0] = box.dimensions.x;
00276 shape.dimensions[1] = box.dimensions.y;
00277 shape.dimensions[2] = box.dimensions.z;
00278 collision_object.shapes.push_back(shape);
00279
00280
00281 tf::Transform model_trans;
00282 tf::poseMsgToTF(model_pose.pose.pose, model_trans);
00283 tf::Transform box_trans;
00284 tf::poseMsgToTF(box.pose_stamped.pose, box_trans);
00285 tf::Transform total_trans = model_trans * box_trans;
00286
00287 geometry_msgs::Pose total_pose;
00288 tf::poseTFToMsg(total_trans, total_pose);
00289 collision_object.poses.push_back(total_pose);
00290
00291 collision_object_pub_.publish(collision_object);
00292 }
00293
00294 void
00295 CollisionMapInterface::processCollisionGeometryForBoundingBox(const object_manipulation_msgs::ClusterBoundingBox &box,
00296 std::string &collision_name)
00297 {
00298 ROS_INFO("Adding bounding box with dimensions %f %f %f to collision map",
00299 box.dimensions.x, box.dimensions.y, box.dimensions.z);
00300
00301 arm_navigation_msgs::CollisionObject collision_object;
00302 collision_object.operation.operation = arm_navigation_msgs::CollisionObjectOperation::ADD;
00303
00304 collision_name = getNextObjectName();
00305 collision_object.id = collision_name;
00306
00307 collision_object.header.frame_id = box.pose_stamped.header.frame_id;
00308 collision_object.header.stamp = ros::Time::now();
00309
00310 arm_navigation_msgs::Shape shape;
00311 shape.type = arm_navigation_msgs::Shape::BOX;
00312 shape.dimensions.resize(3);
00313 shape.dimensions[0] = box.dimensions.x;
00314 shape.dimensions[1] = box.dimensions.y;
00315 shape.dimensions[2] = box.dimensions.z;
00316 collision_object.shapes.push_back(shape);
00317 collision_object.poses.push_back(box.pose_stamped.pose);
00318
00319 collision_object_pub_.publish(collision_object);
00320 }
00321
00322 void CollisionMapInterface::processCollisionGeometryForCluster(const sensor_msgs::PointCloud &cluster,
00323 std::string &collision_name, float collision_size)
00324 {
00325 ROS_INFO("Adding cluster with %u points to collision map", (unsigned int)cluster.points.size());
00326
00327 arm_navigation_msgs::CollisionObject many_boxes;
00328 many_boxes.operation.operation = arm_navigation_msgs::CollisionObjectOperation::ADD;
00329 many_boxes.header = cluster.header;
00330 many_boxes.header.stamp = ros::Time::now();
00331 unsigned int num_to_use = (unsigned int)(cluster.points.size()/point_skip_num_);
00332 many_boxes.shapes.resize(num_to_use);
00333 many_boxes.poses.resize(num_to_use);
00334
00335 if(collision_size < 0)
00336 collision_size = collision_box_size_;
00337
00338 for(unsigned int i = 0; i < num_to_use; i++) {
00339 arm_navigation_msgs::Shape shape;
00340 shape.type = arm_navigation_msgs::Shape::BOX;
00341 shape.dimensions.resize(3);
00342 shape.dimensions[0] = collision_size;
00343 shape.dimensions[1] = collision_size;
00344 shape.dimensions[2] = collision_size;
00345 many_boxes.shapes[i]=shape;
00346 geometry_msgs::Pose pose;
00347 pose.position.x = cluster.points[i*point_skip_num_].x;
00348 pose.position.y = cluster.points[i*point_skip_num_].y;
00349 pose.position.z = cluster.points[i*point_skip_num_].z;
00350 pose.orientation.x = 0;
00351 pose.orientation.y = 0;
00352 pose.orientation.z = 0;
00353 pose.orientation.w = 1;
00354 many_boxes.poses[i] = pose;
00355 }
00356
00357 collision_name = getNextObjectName();
00358
00359 many_boxes.id = collision_name;
00360 collision_object_pub_.publish(many_boxes);
00361 }
00362
00363 bool CollisionMapInterface::getMeshFromDatabasePose(const household_objects_database_msgs::DatabaseModelPose &model_pose,
00364 arm_navigation_msgs::Shape& mesh)
00365 {
00366 static bool service_initialized = false;
00367 if (!service_initialized)
00368 {
00369 std::string get_model_mesh_srv_name;
00370 priv_nh_.param<std::string>("get_model_mesh_srv", get_model_mesh_srv_name, "get_model_mesh_srv");
00371 ros::Time start_time = ros::Time::now();
00372 while ( !ros::service::waitForService(get_model_mesh_srv_name, ros::Duration(2.0)) )
00373 {
00374 ROS_INFO("Waiting for %s service to come up", get_model_mesh_srv_name.c_str());
00375 if (!root_nh_.ok() || ros::Time::now() - start_time >= ros::Duration(5.0))
00376 {
00377 return false;
00378 }
00379 }
00380 get_model_mesh_srv_ = root_nh_.serviceClient<household_objects_database_msgs::GetModelMesh>
00381 (get_model_mesh_srv_name, false);
00382 service_initialized = true;
00383 }
00384 household_objects_database_msgs::GetModelMesh get_mesh;
00385 get_mesh.request.model_id = model_pose.model_id;
00386 if ( !get_model_mesh_srv_.call(get_mesh) )
00387 {
00388 ROS_ERROR("Get model mesh service service call failed altogether");
00389 return false;
00390 }
00391 else if (get_mesh.response.return_code.code != get_mesh.response.return_code.SUCCESS )
00392 {
00393 ROS_ERROR("Get model mesh service returned an error");
00394 return false;
00395 }
00396
00397 mesh.vertices = get_mesh.response.mesh.vertices;
00398 mesh.triangles.clear();
00399 for (size_t i=0; i<get_mesh.response.mesh.triangles.size(); i++)
00400 {
00401 mesh.triangles.push_back( get_mesh.response.mesh.triangles.at(i).vertex_indices.at(0) );
00402 mesh.triangles.push_back( get_mesh.response.mesh.triangles.at(i).vertex_indices.at(1) );
00403 mesh.triangles.push_back( get_mesh.response.mesh.triangles.at(i).vertex_indices.at(2) );
00404 }
00405 return true;
00406 }
00407
00408 void CollisionMapInterface::getClusterBoundingBox(const sensor_msgs::PointCloud &cluster,
00409 geometry_msgs::PoseStamped &pose_stamped,
00410 geometry_msgs::Vector3 &dimensions)
00411 {
00412 object_manipulation_msgs::FindClusterBoundingBox srv;
00413 srv.request.cluster = cluster;
00414 if (!cluster_bounding_box_client_.call(srv.request, srv.response))
00415 {
00416 ROS_ERROR("Failed to call cluster bounding box client");
00417 throw CollisionMapException("Failed to call cluster bounding box client");
00418 }
00419 pose_stamped = srv.response.pose;
00420 dimensions = srv.response.box_dims;
00421 if (dimensions.x == 0.0 && dimensions.y == 0.0 && dimensions.z == 0.0)
00422 {
00423 ROS_ERROR("Cluster bounding box client returned an error (0.0 bounding box)");
00424 throw CollisionMapException("Bounding box computation failed");
00425 }
00426 }
00427
00428 void CollisionMapInterface::getClusterBoundingBox(const sensor_msgs::PointCloud2 &cluster,
00429 geometry_msgs::PoseStamped &pose_stamped,
00430 geometry_msgs::Vector3 &dimensions)
00431 {
00432 object_manipulation_msgs::FindClusterBoundingBox2 srv;
00433 srv.request.cluster = cluster;
00434 if (!cluster_bounding_box2_client_.call(srv.request, srv.response))
00435 {
00436 ROS_ERROR("Failed to call cluster bounding box client");
00437 throw CollisionMapException("Failed to call cluster bounding box client");
00438 }
00439 pose_stamped = srv.response.pose;
00440 dimensions = srv.response.box_dims;
00441 if (dimensions.x == 0.0 && dimensions.y == 0.0 && dimensions.z == 0.0)
00442 {
00443 ROS_ERROR("Cluster bounding box 2 client returned an error (0.0 bounding box)");
00444 throw CollisionMapException("Bounding box computation failed");
00445 }
00446 }
00447
00448 void CollisionMapInterface::getClusterBoundingBox3D(const sensor_msgs::PointCloud &cluster,
00449 geometry_msgs::PoseStamped &pose_stamped,
00450 geometry_msgs::Vector3 &dimensions)
00451 {
00452 object_manipulation_msgs::FindClusterBoundingBox srv;
00453 srv.request.cluster = cluster;
00454 if (!cluster_bounding_box_3d_client_.call(srv.request, srv.response))
00455 {
00456 ROS_ERROR("Failed to call cluster bounding box client");
00457 throw CollisionMapException("Failed to call cluster bounding box client");
00458 }
00459 pose_stamped = srv.response.pose;
00460 dimensions = srv.response.box_dims;
00461 if (dimensions.x == 0.0 && dimensions.y == 0.0 && dimensions.z == 0.0)
00462 {
00463 ROS_ERROR("Cluster bounding box 3d client returned an error (0.0 bounding box)");
00464 throw CollisionMapException("Bounding box computation failed");
00465 }
00466 }
00467
00468 void CollisionMapInterface::getClusterBoundingBox3D(const sensor_msgs::PointCloud2 &cluster,
00469 geometry_msgs::PoseStamped &pose_stamped,
00470 geometry_msgs::Vector3 &dimensions)
00471 {
00472 object_manipulation_msgs::FindClusterBoundingBox2 srv;
00473 srv.request.cluster = cluster;
00474 if (!cluster_bounding_box2_3d_client_.call(srv.request, srv.response))
00475 {
00476 ROS_ERROR("Failed to call cluster bounding box client");
00477 throw CollisionMapException("Failed to call cluster bounding box client");
00478 }
00479 pose_stamped = srv.response.pose;
00480 dimensions = srv.response.box_dims;
00481 if (dimensions.x == 0.0 && dimensions.y == 0.0 && dimensions.z == 0.0)
00482 {
00483 ROS_ERROR("Cluster bounding box 2 3d client returned an error (0.0 bounding box)");
00484 throw CollisionMapException("Bounding box computation failed");
00485 }
00486 }
00487
00488
00490 bool CollisionMapInterface::extendBoundingBoxZToTable(const tabletop_object_detector::Table &table,
00491 geometry_msgs::PoseStamped &pose_stamped,
00492 geometry_msgs::Vector3 &dimensions)
00493 {
00494 if (table.pose.header.frame_id != pose_stamped.header.frame_id)
00495 {
00496 ROS_INFO("cannot extend bbox to table, they are not in the same frame");
00497 return false;
00498 }
00499
00500
00501 tf::Vector3 table_location(table.pose.pose.position.x,
00502 table.pose.pose.position.y,
00503 table.pose.pose.position.z);
00504 tf::Vector3 bbox_location(pose_stamped.pose.position.x,
00505 pose_stamped.pose.position.y,
00506 pose_stamped.pose.position.z);
00507 tf::Vector3 table_to_bbox = bbox_location - table_location;
00508 tf::Transform table_trans;
00509 tf::poseMsgToTF(table.pose.pose, table_trans);
00510 tf::Vector3 table_z = table_trans.getBasis().getColumn(2);
00511 ROS_INFO("Table z: %f %f %f in frame %s",
00512 table_z.getX(), table_z.getY(), table_z.getZ(), table.pose.header.frame_id.c_str());
00513 double box_to_table_distance = table_to_bbox.dot(table_z);
00514 ROS_INFO("Table distance: %f", box_to_table_distance);
00515
00516
00517
00518 tf::Transform bbox_trans;
00519 tf::poseMsgToTF(pose_stamped.pose, bbox_trans);
00520 tf::Vector3 bbox_z = bbox_trans.getBasis().getColumn(2);
00521 if (fabs(bbox_z.dot(table_z)) < 0.9848)
00522 {
00523 ROS_INFO("cannot extend bbox to table; z axes do not coincide");
00524 return false;
00525 }
00526
00527 double z_to_table = box_to_table_distance;
00528 ROS_INFO("z_to_table: %f", z_to_table);
00529 if ( z_to_table < 0.005 || z_to_table > 0.3)
00530 {
00531 ROS_INFO("cannot extend bbox to table; getting z equal to %f", z_to_table);
00532 return false;
00533 }
00534 ROS_INFO("Old z: %f", dimensions.z);
00535 double new_z = dimensions.z/2.0 + z_to_table;
00536 ROS_INFO("New z: %f", new_z);
00537 pose_stamped.pose.position.z = pose_stamped.pose.position.z + (dimensions.z/2.0) - (new_z/2.0);
00538 dimensions.z = new_z;
00539 return true;
00540 }
00541
00542
00543 }