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
00039
00040 #include <vector>
00041 #include <boost/shared_ptr.hpp>
00042
00043 #include <ros/ros.h>
00044
00045 #include <tf/transform_datatypes.h>
00046 #include <tf/transform_listener.h>
00047
00048 #include <object_manipulation_msgs/GraspPlanning.h>
00049
00050 #include <household_objects_database_msgs/GetModelList.h>
00051 #include <household_objects_database_msgs/GetModelMesh.h>
00052 #include <household_objects_database_msgs/GetModelDescription.h>
00053 #include <household_objects_database_msgs/GetModelScans.h>
00054 #include <household_objects_database_msgs/DatabaseScan.h>
00055 #include <household_objects_database_msgs/SaveScan.h>
00056
00057 #include "household_objects_database/objects_database.h"
00058
00059 const std::string GET_MODELS_SERVICE_NAME = "get_model_list";
00060 const std::string GET_MESH_SERVICE_NAME = "get_model_mesh";
00061 const std::string GET_DESCRIPTION_SERVICE_NAME = "get_model_description";
00062 const std::string GRASP_PLANNING_SERVICE_NAME = "database_grasp_planning";
00063 const std::string GET_SCANS_SERVICE_NAME = "get_model_scans";
00064 const std::string SAVE_SCAN_SERVICE_NAME = "save_model_scan";
00065
00066 using namespace household_objects_database_msgs;
00067 using namespace household_objects_database;
00068 using namespace object_manipulation_msgs;
00069
00071
00072 class HandDescription
00073 {
00074 private:
00076 ros::NodeHandle root_nh_;
00077
00078 inline std::string getStringParam(std::string name)
00079 {
00080 std::string value;
00081 if (!root_nh_.getParamCached(name, value))
00082 {
00083 ROS_ERROR("Hand description: could not find parameter %s", name.c_str());
00084 }
00085
00086 return value;
00087 }
00088
00089 inline std::vector<std::string> getVectorParam(std::string name)
00090 {
00091 std::vector<std::string> values;
00092 XmlRpc::XmlRpcValue list;
00093 if (!root_nh_.getParamCached(name, list))
00094 {
00095 ROS_ERROR("Hand description: could not find parameter %s", name.c_str());
00096 }
00097 if (list.getType() != XmlRpc::XmlRpcValue::TypeArray)
00098 {
00099 ROS_ERROR("Hand description: bad parameter %s", name.c_str());
00100 }
00101
00102 for (int32_t i=0; i<list.size(); i++)
00103 {
00104 if (list[i].getType() != XmlRpc::XmlRpcValue::TypeString)
00105 {
00106 ROS_ERROR("Hand description: bad parameter %s", name.c_str());
00107 }
00108 values.push_back( static_cast<std::string>(list[i]) );
00109
00110 }
00111 return values;
00112 }
00113
00114 public:
00115 HandDescription() : root_nh_("~") {}
00116
00117 inline std::string handDatabaseName(std::string arm_name)
00118 {
00119 return getStringParam("/hand_description/" + arm_name + "/hand_database_name");
00120 }
00121
00122 inline std::vector<std::string> handJointNames(std::string arm_name)
00123 {
00124 return getVectorParam("/hand_description/" + arm_name + "/hand_joints");
00125 }
00126
00127 };
00128
00130
00132 class ObjectsDatabaseNode
00133 {
00134 private:
00136 ros::NodeHandle priv_nh_;
00137
00139 ros::NodeHandle root_nh_;
00140
00142 ros::ServiceServer get_models_srv_;
00143
00145 ros::ServiceServer get_mesh_srv_;
00146
00148 ros::ServiceServer get_description_srv_;
00149
00151 ros::ServiceServer grasp_planning_srv_;
00152
00154 ros::ServiceServer get_scans_srv_;
00155
00157 ros::ServiceServer save_scan_srv_;
00158
00160 ObjectsDatabase *database_;
00161
00163 tf::TransformListener listener_;
00164
00166 double prune_gripper_opening_;
00167
00169 double prune_table_clearance_;
00170
00172 bool getModelsCB(GetModelList::Request &request, GetModelList::Response &response)
00173 {
00174 if (!database_)
00175 {
00176 response.return_code.code = response.return_code.DATABASE_NOT_CONNECTED;
00177 return true;
00178 }
00179 std::vector< boost::shared_ptr<DatabaseScaledModel> > models;
00180 if (!database_->getScaledModelsBySet(models, request.model_set))
00181 {
00182 response.return_code.code = response.return_code.DATABASE_QUERY_ERROR;
00183 return true;
00184 }
00185 for (size_t i=0; i<models.size(); i++)
00186 {
00187 response.model_ids.push_back( models[i]->id_.data() );
00188 }
00189 response.return_code.code = response.return_code.SUCCESS;
00190 return true;
00191 }
00192
00194 bool getMeshCB(GetModelMesh::Request &request, GetModelMesh::Response &response)
00195 {
00196 if (!database_)
00197 {
00198 response.return_code.code = response.return_code.DATABASE_NOT_CONNECTED;
00199 return true;
00200 }
00201 if ( !database_->getScaledModelMesh(request.model_id, response.mesh) )
00202 {
00203 response.return_code.code = response.return_code.DATABASE_QUERY_ERROR;
00204 return true;
00205 }
00206 response.return_code.code = response.return_code.SUCCESS;
00207 return true;
00208 }
00209
00211 bool getDescriptionCB(GetModelDescription::Request &request, GetModelDescription::Response &response)
00212 {
00213 if (!database_)
00214 {
00215 response.return_code.code = response.return_code.DATABASE_NOT_CONNECTED;
00216 return true;
00217 }
00218 std::vector< boost::shared_ptr<DatabaseScaledModel> > models;
00219
00220 std::stringstream id;
00221 id << request.model_id;
00222 std::string where_clause("scaled_model_id=" + id.str());
00223 if (!database_->getList(models, where_clause) || models.size() != 1)
00224 {
00225 response.return_code.code = response.return_code.DATABASE_QUERY_ERROR;
00226 return true;
00227 }
00228 response.tags = models[0]->tags_.data();
00229 response.name = models[0]->model_.data();
00230 response.maker = models[0]->maker_.data();
00231 response.return_code.code = response.return_code.SUCCESS;
00232 return true;
00233 }
00234
00235 bool getScansCB(GetModelScans::Request &request, GetModelScans::Response &response)
00236 {
00237 if (!database_)
00238 {
00239 ROS_ERROR("GetModelScan: database not connected");
00240 response.return_code.code = DatabaseReturnCode::DATABASE_NOT_CONNECTED;
00241 return true;
00242 }
00243
00244 database_->getModelScans(request.model_id, request.scan_source,response.matching_scans);
00245 response.return_code.code = DatabaseReturnCode::SUCCESS;
00246 return true;
00247 }
00248
00249 bool saveScanCB(SaveScan::Request &request, SaveScan::Response &response)
00250 {
00251 if (!database_)
00252 {
00253 ROS_ERROR("SaveScan: database not connected");
00254 response.return_code.code = DatabaseReturnCode::DATABASE_NOT_CONNECTED;
00255 return true;
00256 }
00257 household_objects_database::DatabaseScan scan;
00258 scan.frame_id_.get() = request.ground_truth_pose.header.frame_id;
00259 scan.cloud_topic_.get() = request.cloud_topic;
00260 scan.object_pose_.get().pose_ = request.ground_truth_pose.pose;
00261 scan.scaled_model_id_.get() = request.scaled_model_id;
00262 scan.scan_bagfile_location_.get() = request.bagfile_location;
00263 scan.scan_source_.get() = request.scan_source;
00264 database_->insertIntoDatabase(&scan);
00265 response.return_code.code = DatabaseReturnCode::SUCCESS;
00266 return true;
00267 }
00268
00270
00273 virtual void pruneGraspList(std::vector< boost::shared_ptr<DatabaseGrasp> > &grasps,
00274 double gripper_threshold,
00275 double table_clearance_threshold)
00276 {
00277 std::vector< boost::shared_ptr<DatabaseGrasp> >::iterator prune_it = grasps.begin();
00278 int pruned = 0;
00279 while ( prune_it != grasps.end() )
00280 {
00281
00282 if ((*prune_it)->final_grasp_posture_.get().joint_angles_[0] > gripper_threshold ||
00283 (table_clearance_threshold >= 0.0 && (*prune_it)->table_clearance_.get() < table_clearance_threshold*1.0e3) )
00284 {
00285 prune_it = grasps.erase(prune_it);
00286 pruned++;
00287 }
00288 else
00289 {
00290 prune_it++;
00291 }
00292 }
00293 ROS_INFO("Database grasp planner: pruned %d grasps for table collision or gripper angle above threshold", pruned);
00294 }
00295
00296 geometry_msgs::Pose multiplyPoses(const geometry_msgs::Pose &p1,
00297 const geometry_msgs::Pose &p2)
00298 {
00299 tf::Transform t1;
00300 tf::poseMsgToTF(p1, t1);
00301 tf::Transform t2;
00302 tf::poseMsgToTF(p2, t2);
00303 t2 = t1 * t2;
00304 geometry_msgs::Pose out_pose;
00305 tf::poseTFToMsg(t2, out_pose);
00306 return out_pose;
00307 }
00308
00310 bool graspPlanningCB(GraspPlanning::Request &request, GraspPlanning::Response &response)
00311 {
00312 if (!database_)
00313 {
00314 ROS_ERROR("Database grasp planning: database not connected");
00315 response.error_code.value = response.error_code.OTHER_ERROR;
00316 return true;
00317 }
00318
00319 if (request.target.potential_models.empty())
00320 {
00321 ROS_ERROR("Database grasp planning: no potential model information in grasp planning target");
00322 response.error_code.value = response.error_code.OTHER_ERROR;
00323 return true;
00324 }
00325
00326 if (request.target.potential_models.size() > 1)
00327 {
00328 ROS_WARN("Database grasp planning: target has more than one potential models. "
00329 "Returning grasps for first model only");
00330 }
00331
00332 HandDescription hd;
00333 int model_id = request.target.potential_models[0].model_id;
00334 std::string hand_id = hd.handDatabaseName(request.arm_name);
00335
00336
00337 std::vector< boost::shared_ptr<DatabaseGrasp> > grasps;
00338 if (!database_->getClusterRepGrasps(model_id, hand_id, grasps))
00339 {
00340 ROS_ERROR("Database grasp planning: database query error");
00341 response.error_code.value = response.error_code.OTHER_ERROR;
00342 return true;
00343 }
00344 ROS_INFO("Database object node: retrieved %u grasps from database", (unsigned int)grasps.size());
00345
00346
00347 pruneGraspList(grasps, prune_gripper_opening_, prune_table_clearance_);
00348
00349
00350 std::vector< boost::shared_ptr<DatabaseGrasp> >::iterator it;
00351 for (it = grasps.begin(); it != grasps.end(); it++)
00352 {
00353 ROS_ASSERT( (*it)->final_grasp_posture_.get().joint_angles_.size() ==
00354 (*it)->pre_grasp_posture_.get().joint_angles_.size() );
00355 Grasp grasp;
00356 std::vector<std::string> joint_names = hd.handJointNames(request.arm_name);
00357
00358 if (hand_id != "WILLOW_GRIPPER_2010")
00359 {
00360
00361
00362 if (joint_names.size() != (*it)->final_grasp_posture_.get().joint_angles_.size())
00363 {
00364 ROS_ERROR("Database grasp specification does not match ROS description of hand. "
00365 "Hand is expected to have %d joints, but database grasp specifies %d values",
00366 (int)joint_names.size(), (int)(*it)->final_grasp_posture_.get().joint_angles_.size());
00367 continue;
00368 }
00369
00370
00371 grasp.pre_grasp_posture.name = joint_names;
00372 grasp.grasp_posture.name = joint_names;
00373 grasp.pre_grasp_posture.position = (*it)->pre_grasp_posture_.get().joint_angles_;
00374 grasp.grasp_posture.position = (*it)->final_grasp_posture_.get().joint_angles_;
00375 }
00376 else
00377 {
00378
00379
00380 if ( joint_names.size() != 4 || (*it)->final_grasp_posture_.get().joint_angles_.size() != 1)
00381 {
00382 ROS_ERROR("PR2 gripper specs and database grasp specs do not match expected values");
00383 continue;
00384 }
00385 grasp.pre_grasp_posture.name = joint_names;
00386 grasp.grasp_posture.name = joint_names;
00387
00388 grasp.pre_grasp_posture.position.resize( joint_names.size(),
00389 (*it)->pre_grasp_posture_.get().joint_angles_.at(0));
00390 grasp.grasp_posture.position.resize( joint_names.size(),
00391 (*it)->final_grasp_posture_.get().joint_angles_.at(0));
00392 }
00393
00394
00395 grasp.grasp_posture.effort.resize(joint_names.size(), 10000);
00396 grasp.pre_grasp_posture.effort.resize(joint_names.size(), 10000);
00397
00398 grasp.grasp_pose = (*it)->final_grasp_pose_.get().pose_;
00399
00400 grasp.grasp_pose = multiplyPoses(request.target.potential_models[0].pose.pose, grasp.grasp_pose);
00401
00402 if (request.target.potential_models[0].pose.header.frame_id !=
00403 request.target.reference_frame_id)
00404 {
00405 tf::StampedTransform ref_trans;
00406 try
00407 {
00408 listener_.lookupTransform(request.target.reference_frame_id,
00409 request.target.potential_models[0].pose.header.frame_id,
00410 ros::Time(0), ref_trans);
00411 }
00412 catch (tf::TransformException ex)
00413 {
00414 ROS_ERROR("Grasp planner: failed to get transform from %s to %s; exception: %s",
00415 request.target.reference_frame_id.c_str(),
00416 request.target.potential_models[0].pose.header.frame_id.c_str(), ex.what());
00417 response.error_code.value = response.error_code.OTHER_ERROR;
00418 return true;
00419 }
00420 geometry_msgs::Pose ref_pose;
00421 tf::poseTFToMsg(ref_trans, ref_pose);
00422 grasp.grasp_pose = multiplyPoses(ref_pose, grasp.grasp_pose);
00423 }
00424
00425 grasp.success_probability = (*it)->scaled_quality_.get();
00426
00427
00428 response.grasps.push_back(grasp);
00429 }
00430
00431 ROS_INFO("Database grasp planner: returning %u grasps", (unsigned int)response.grasps.size());
00432 response.error_code.value = response.error_code.SUCCESS;
00433 return true;
00434 }
00435
00436 public:
00437 ObjectsDatabaseNode() : priv_nh_("~"), root_nh_("")
00438 {
00439
00440 std::string database_host, database_port, database_user, database_pass, database_name;
00441 root_nh_.param<std::string>("/household_objects_database/database_host", database_host, "");
00442 int port_int;
00443 root_nh_.param<int>("/household_objects_database/database_port", port_int, -1);
00444 std::stringstream ss; ss << port_int; database_port = ss.str();
00445 root_nh_.param<std::string>("/household_objects_database/database_user", database_user, "");
00446 root_nh_.param<std::string>("/household_objects_database/database_pass", database_pass, "");
00447 root_nh_.param<std::string>("/household_objects_database/database_name", database_name, "");
00448 database_ = new ObjectsDatabase(database_host, database_port, database_user, database_pass, database_name);
00449 if (!database_->isConnected())
00450 {
00451 ROS_ERROR("ObjectsDatabaseNode: failed to open model database on host "
00452 "%s, port %s, user %s with password %s, database %s. Unable to do grasp "
00453 "planning on database recognized objects. Exiting.",
00454 database_host.c_str(), database_port.c_str(),
00455 database_user.c_str(), database_pass.c_str(), database_name.c_str());
00456 delete database_; database_ = NULL;
00457 }
00458
00459
00460 get_models_srv_ = priv_nh_.advertiseService(GET_MODELS_SERVICE_NAME, &ObjectsDatabaseNode::getModelsCB, this);
00461 get_mesh_srv_ = priv_nh_.advertiseService(GET_MESH_SERVICE_NAME, &ObjectsDatabaseNode::getMeshCB, this);
00462 get_description_srv_ = priv_nh_.advertiseService(GET_DESCRIPTION_SERVICE_NAME,
00463 &ObjectsDatabaseNode::getDescriptionCB, this);
00464 grasp_planning_srv_ = priv_nh_.advertiseService(GRASP_PLANNING_SERVICE_NAME,
00465 &ObjectsDatabaseNode::graspPlanningCB, this);
00466
00467 get_scans_srv_ = priv_nh_.advertiseService(GET_SCANS_SERVICE_NAME,
00468 &ObjectsDatabaseNode::getScansCB, this);
00469 save_scan_srv_ = priv_nh_.advertiseService(SAVE_SCAN_SERVICE_NAME,
00470 &ObjectsDatabaseNode::saveScanCB, this);
00471
00472 priv_nh_.param<double>("prune_gripper_opening", prune_gripper_opening_, 0.5);
00473 priv_nh_.param<double>("prune_table_clearance", prune_table_clearance_, 0.0);
00474 }
00475
00476 ~ObjectsDatabaseNode()
00477 {
00478 delete database_;
00479 }
00480 };
00481
00482 int main(int argc, char **argv)
00483 {
00484 ros::init(argc, argv, "objects_database_node");
00485 ObjectsDatabaseNode node;
00486 ros::spin();
00487 return 0;
00488 }