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 <actionlib/server/simple_action_server.h>
00046
00047 #include "moveit/robot_model/robot_model.h"
00048 #include <moveit/robot_model/joint_model_group.h>
00049 #include <moveit/robot_model_loader/robot_model_loader.h>
00050
00051 #include <visualization_msgs/MarkerArray.h>
00052
00053 #include <manipulation_msgs/GraspPlanning.h>
00054 #include <manipulation_msgs/GraspPlanningAction.h>
00055
00056 #include "household_objects_database/objects_database.h"
00057 #include <household_objects_database_msgs/TranslateRecognitionId.h>
00058 #include <household_objects_database_msgs/GetModelList.h>
00059
00060 #include <tf/transform_datatypes.h>
00061
00062 const std::string GRASP_PLANNING_SERVICE_NAME = "database_grasp_planning";
00063 const std::string GET_MODELS_SERVICE_NAME = "get_model_list";
00064 const std::string VISUALIZE_GRASPS = "visualize_grasps";
00065
00066 using namespace household_objects_database_msgs;
00067 using namespace household_objects_database;
00068 using namespace manipulation_msgs;
00069
00070 geometry_msgs::Vector3 negate(const geometry_msgs::Vector3 &vec)
00071 {
00072 geometry_msgs::Vector3 v;
00073 v.x = - vec.x;
00074 v.y = - vec.y;
00075 v.z = - vec.z;
00076 return v;
00077 }
00078
00079 bool greaterScaledQuality(const boost::shared_ptr<DatabaseGrasp> &grasp1,
00080 const boost::shared_ptr<DatabaseGrasp> &grasp2)
00081 {
00082 if (grasp1->scaled_quality_.data() > grasp2->scaled_quality_.data()) return true;
00083 return false;
00084 }
00085
00087
00089 class ObjectsDatabaseNode
00090 {
00091 private:
00093 ros::NodeHandle priv_nh_;
00094
00096 ros::NodeHandle root_nh_;
00097
00099 ros::ServiceServer grasp_planning_srv_;
00100
00101 ros::Publisher visualize_grasps_publisher_;
00102
00104 ObjectsDatabase *database_;
00105
00106 std::map<std::string, geometry_msgs::Vector3> approach_direction_;
00107
00108 std::map<std::string, std::string> database_hand_ids_;
00109
00111
00112
00114
00115 std::string grasp_ordering_method_;
00116
00117 const robot_model::RobotModelConstPtr &robot_model_;
00118
00120 bool getModelsCB(GetModelList::Request &request,
00121 GetModelList::Response &response)
00122 {
00123 if (!database_)
00124 {
00125 response.return_code.code = response.return_code.DATABASE_NOT_CONNECTED;
00126 return true;
00127 }
00128 std::vector< boost::shared_ptr<DatabaseScaledModel> > models;
00129 if (!database_->getScaledModelsBySet(models, request.model_set))
00130 {
00131 response.return_code.code = response.return_code.DATABASE_QUERY_ERROR;
00132 return true;
00133 }
00134 for (size_t i=0; i<models.size(); i++)
00135 {
00136 response.model_ids.push_back( models[i]->id_.data() );
00137 }
00138 response.return_code.code = response.return_code.SUCCESS;
00139 return true;
00140 }
00141
00142 inline std::vector<double> getVectorDoubleParam(const std::string &name)
00143 {
00144 std::vector<double> values;
00145 XmlRpc::XmlRpcValue list;
00146 if (!root_nh_.getParamCached(name, list))
00147 {
00148 ROS_ERROR("Could not find parameter %s", name.c_str());
00149 return values;
00150 }
00151 if (list.getType() != XmlRpc::XmlRpcValue::TypeArray)
00152 {
00153 ROS_ERROR("Bad parameter type %s", name.c_str());
00154 return values;
00155 }
00156 for (int32_t i=0; i<list.size(); i++)
00157 {
00158 if (list[i].getType() != XmlRpc::XmlRpcValue::TypeDouble)
00159 {
00160 ROS_ERROR("Bad parameter %s", name.c_str());
00161 }
00162 values.push_back( static_cast<double>(list[i]) );
00163 }
00164 return values;
00165 }
00166
00167 inline geometry_msgs::Vector3 approachDirection(const std::string &name, bool &found)
00168 {
00169 geometry_msgs::Vector3 app;
00170 std::vector<double> values = getVectorDoubleParam(name);
00171 if ( values.size() != 3 )
00172 {
00173 ROS_ERROR("Bad parameter name %s", name.c_str());
00174 found = false;
00175 return app;
00176 }
00177 double length = sqrt( values[0]*values[0] + values[1]*values[1] + values[2]*values[2] );
00178 if ( fabs(length) < 1.0e-5 )
00179 {
00180 ROS_ERROR("Bad parameter name %s", name.c_str());
00181 found = false;
00182 return app;
00183 }
00184 app.x = values[0] / length;
00185 app.y = values[1] / length;
00186 app.z = values[2] / length;
00187 found = true;
00188 return app;
00189 }
00190
00191 geometry_msgs::Pose multiplyPoses(const geometry_msgs::Pose &p1,
00192 const geometry_msgs::Pose &p2)
00193 {
00194 tf::Transform t1;
00195 tf::poseMsgToTF(p1, t1);
00196 tf::Transform t2;
00197 tf::poseMsgToTF(p2, t2);
00198 t2 = t1 * t2;
00199 geometry_msgs::Pose out_pose;
00200 tf::poseTFToMsg(t2, out_pose);
00201 return out_pose;
00202 }
00203
00204 bool translateIdCB(TranslateRecognitionId::Request &request, TranslateRecognitionId::Response &response)
00205 {
00206 std::vector<boost::shared_ptr<DatabaseScaledModel> > models;
00207 if (!database_)
00208 {
00209 ROS_ERROR("Database not connected");
00210 response.result = response.DATABASE_ERROR;
00211 return true;
00212 }
00213 if (!database_->getScaledModelsByRecognitionId(models, request.recognition_id))
00214 {
00215 ROS_ERROR("Query failed");
00216 response.result = response.DATABASE_ERROR;
00217 return true;
00218 }
00219 if (models.empty())
00220 {
00221 ROS_ERROR("Recognition id %s not found", request.recognition_id.c_str());
00222 response.result = response.ID_NOT_FOUND;
00223 return true;
00224 }
00225 response.household_objects_id = models[0]->id_.data();
00226 if (models.size() > 1) ROS_WARN("Multiple matches found for recognition id %s. Returning the first one.",
00227 request.recognition_id.c_str());
00228 response.result = response.SUCCESS;
00229 return true;
00230 }
00231
00232 void visualizeGrasps(const std::vector<Grasp> &grasps)
00233 {
00234 visualization_msgs::MarkerArray marker;
00235 for(std::size_t i=0; i < grasps.size(); ++i)
00236 {
00237 visualization_msgs::Marker m;
00238 m.action = m.ADD;
00239 m.type = m.ARROW;
00240 m.ns = "grasps";
00241 m.id = i;
00242 m.pose = grasps[i].grasp_pose.pose;
00243 m.header = grasps[i].grasp_pose.header;
00244 marker.markers.push_back(m);
00245
00246 m.scale.x = 0.05;
00247 m.scale.y = 0.01;
00248 m.scale.z = 0.01;
00249
00250 m.color.r = 1.0;
00251 m.color.g = 0.0;
00252 m.color.b = 0.0;
00253 m.color.a = 1.0;
00254
00255 marker.markers.push_back(m);
00256 }
00257 visualize_grasps_publisher_.publish(marker);
00258 }
00259
00260
00261 bool getGrasps(const GraspableObject &target, const std::string &arm_name,
00262 std::vector<Grasp> &grasps, GraspPlanningErrorCode &error_code)
00263 {
00264 if (!database_)
00265 {
00266 ROS_ERROR("Database grasp planning: database not connected");
00267 error_code.value = error_code.OTHER_ERROR;
00268 return false;
00269 }
00270 std::vector< boost::shared_ptr<DatabaseScaledModel> > models;
00271
00272
00273
00274
00275
00276
00277
00278
00279 if (target.potential_models.empty())
00280 {
00281 ROS_ERROR("Database grasp planning: no potential model information in grasp planning target");
00282 error_code.value = error_code.OTHER_ERROR;
00283 return false;
00284 }
00285
00286 if (target.potential_models.size() > 1)
00287 {
00288 ROS_WARN("Database grasp planning: target has more than one potential models. "
00289 "Returning grasps for first model only");
00290 }
00291
00292
00293
00294 int model_id = target.potential_models[0].model_id;
00295 if (!target.potential_models[0].type.key.empty())
00296 {
00297 if (model_id == 0)
00298 {
00299 TranslateRecognitionId translate;
00300 translate.request.recognition_id = target.potential_models[0].type.key;
00301 translateIdCB(translate.request, translate.response);
00302 if (translate.response.result == translate.response.SUCCESS)
00303 {
00304 model_id = translate.response.household_objects_id;
00305 ROS_DEBUG_STREAM("Grasp planning: translated ORK key " << target.potential_models[0].type.key <<
00306 " into model_id " << model_id);
00307 }
00308 else
00309 {
00310 ROS_ERROR("Failed to translate ORK key into household model_id");
00311 error_code.value = error_code.OTHER_ERROR;
00312 return false;
00313 }
00314 }
00315 else
00316 {
00317 ROS_DEBUG("Grasp planning: both model_id and ORK key specified in GraspableObject; using model_id and ignoring ORK key");
00318 }
00319 }
00320
00321 std::vector<std::string> hand_ids = robot_model_->getJointModelGroup(arm_name)->getAttachedEndEffectorNames();
00322
00323 for(std::size_t i=0; i < hand_ids.size(); ++i)
00324 {
00325 std::map<std::string, std::string>::const_iterator database_hand_id
00326 = database_hand_ids_.find(hand_ids[i]);
00327
00328 if(database_hand_id == database_hand_ids_.end())
00329 {
00330 ROS_INFO("Could not find database hand id for %s", hand_ids[i].c_str());
00331 return false;
00332 }
00333
00334 std::map<std::string, geometry_msgs::Vector3>::const_iterator approach_direction =
00335 approach_direction_.find(hand_ids[i]);
00336
00337 if(approach_direction == approach_direction_.end())
00338 {
00339 ROS_INFO("Could not find database hand id for %s", hand_ids[i].c_str());
00340 return false;
00341 }
00342
00343 const std::pair<std::string, std::string>& end_effector_parent =
00344 robot_model_->getEndEffector(hand_ids[i])->getEndEffectorParentGroup();
00345
00346
00347 std::vector< boost::shared_ptr<DatabaseGrasp> > db_grasps;
00348 if (!database_->getClusterRepGrasps(model_id, database_hand_id->second, db_grasps))
00349 {
00350 ROS_ERROR("Database grasp planning: database query error");
00351 error_code.value = error_code.OTHER_ERROR;
00352 return false;
00353 }
00354 ROS_INFO("Database object node: retrieved %u grasps from database", (unsigned int)db_grasps.size());
00355
00356
00357 if (grasp_ordering_method_ == "random")
00358 {
00359 ROS_INFO("Randomizing grasps");
00360 std::random_shuffle(db_grasps.begin(), db_grasps.end());
00361 }
00362 else if (grasp_ordering_method_ == "quality")
00363 {
00364 ROS_INFO("Sorting grasps by scaled quality");
00365 std::sort(db_grasps.begin(), db_grasps.end(), greaterScaledQuality);
00366 }
00367 else
00368 {
00369 ROS_WARN("Unknown grasp ordering method requested -- randomizing grasp order");
00370 std::random_shuffle(db_grasps.begin(), db_grasps.end());
00371 }
00372
00373
00374 std::vector< boost::shared_ptr<DatabaseGrasp> >::iterator it;
00375 for (it = db_grasps.begin(); it != db_grasps.end(); it++)
00376 {
00377 ROS_ASSERT( (*it)->final_grasp_posture_.get().joint_angles_.size() ==
00378 (*it)->pre_grasp_posture_.get().joint_angles_.size() );
00379 Grasp grasp;
00380 std::vector<std::string> joint_names = robot_model_->getEndEffector(hand_ids[i])->getJointModelNames();
00381 if (database_hand_id->second != "WILLOW_GRIPPER_2010")
00382 {
00383
00384
00385 if (joint_names.size() != (*it)->final_grasp_posture_.get().joint_angles_.size())
00386 {
00387 ROS_ERROR("Database grasp specification does not match ROS description of hand. "
00388 "Hand is expected to have %d joints, but database grasp specifies %d values",
00389 (int)joint_names.size(), (int)(*it)->final_grasp_posture_.get().joint_angles_.size());
00390 continue;
00391 }
00392
00393
00394 grasp.pre_grasp_posture.name = joint_names;
00395 grasp.grasp_posture.name = joint_names;
00396 grasp.pre_grasp_posture.position = (*it)->pre_grasp_posture_.get().joint_angles_;
00397 grasp.grasp_posture.position = (*it)->final_grasp_posture_.get().joint_angles_;
00398 }
00399 else
00400 {
00401
00402
00403
00404
00405
00406
00407
00408 grasp.pre_grasp_posture.name = joint_names;
00409 grasp.grasp_posture.name = joint_names;
00410
00411 grasp.pre_grasp_posture.position.resize( joint_names.size(),
00412 (*it)->pre_grasp_posture_.get().joint_angles_.at(0));
00413 grasp.grasp_posture.position.resize( joint_names.size(),
00414 (*it)->final_grasp_posture_.get().joint_angles_.at(0));
00415 }
00416
00417
00418 grasp.grasp_posture.effort.resize(joint_names.size(), 50);
00419 grasp.pre_grasp_posture.effort.resize(joint_names.size(), 100);
00420
00421
00422
00423 grasp.approach.direction.header.stamp = ros::Time::now();
00424 grasp.approach.direction.header.frame_id = end_effector_parent.second;
00425 grasp.approach.direction.vector = approach_direction->second;
00426 grasp.retreat.direction.header.stamp = ros::Time::now();
00427 grasp.retreat.direction.header.frame_id = end_effector_parent.second;
00428 grasp.retreat.direction.vector = negate( approach_direction->second );
00429
00430 grasp.approach.desired_distance = 0.10;
00431 grasp.approach.min_distance = 0.05;
00432 grasp.retreat.desired_distance = 0.10;
00433 grasp.retreat.min_distance = 0.05;
00434
00435 geometry_msgs::Pose grasp_pose = (*it)->final_grasp_pose_.get().pose_;
00436
00437 grasp_pose = multiplyPoses(target.potential_models[0].pose.pose, grasp_pose);
00438
00439 grasp.grasp_quality = (*it)->scaled_quality_.get();
00440 grasp.grasp_pose.pose = grasp_pose;
00441 grasp.grasp_pose.header.frame_id = target.reference_frame_id;
00442 grasp.grasp_pose.header.stamp = ros::Time::now();
00443
00444
00445 grasps.push_back(grasp);
00446 }
00447 visualizeGrasps(grasps);
00448 ROS_INFO("Database grasp planner: returning %u grasps for end-effector %s"
00449 , (unsigned int) grasps.size(), hand_ids[i].c_str());
00450 }
00451 error_code.value = error_code.SUCCESS;
00452 return true;
00453 }
00454
00456 bool graspPlanningCB(GraspPlanning::Request &request, GraspPlanning::Response &response)
00457 {
00458 getGrasps(request.target, request.arm_name, response.grasps, response.error_code);
00459 return true;
00460 }
00461
00462 public:
00463 ObjectsDatabaseNode(const robot_model::RobotModelConstPtr &robot_model) : priv_nh_("~"), root_nh_(""), robot_model_(robot_model)
00464 {
00465
00466 ROS_INFO("Starting up");
00467 std::string database_host, database_port, database_user, database_pass, database_name;
00468 root_nh_.param<std::string>("/household_objects_database/database_host", database_host, "");
00469 int port_int;
00470 root_nh_.param<int>("/household_objects_database/database_port", port_int, -1);
00471 std::stringstream ss; ss << port_int; database_port = ss.str();
00472 root_nh_.param<std::string>("/household_objects_database/database_user", database_user, "");
00473 root_nh_.param<std::string>("/household_objects_database/database_pass", database_pass, "");
00474 root_nh_.param<std::string>("/household_objects_database/database_name", database_name, "");
00475
00476 visualize_grasps_publisher_ = root_nh_.advertise<visualization_msgs::MarkerArray>("visualize_grasps", 20);
00477
00478 database_ = new ObjectsDatabase(database_host, database_port, database_user, database_pass, database_name);
00479 if (!database_->isConnected())
00480 {
00481 ROS_ERROR("ObjectsDatabaseNode: failed to open model database on host "
00482 "%s, port %s, user %s with password %s, database %s. Unable to do grasp "
00483 "planning on database recognized objects. Exiting.",
00484 database_host.c_str(), database_port.c_str(),
00485 database_user.c_str(), database_pass.c_str(), database_name.c_str());
00486 delete database_; database_ = NULL;
00487 }
00488
00489
00490 grasp_planning_srv_ = root_nh_.advertiseService(GRASP_PLANNING_SERVICE_NAME,
00491 &ObjectsDatabaseNode::graspPlanningCB, this);
00492
00493 priv_nh_.param<std::string>("grasp_ordering_method", grasp_ordering_method_, "random");
00494 ROS_INFO("Database connected");
00495 for(std::size_t i=0; i < robot_model_->getJointModelGroupNames().size(); ++i)
00496 {
00497 ROS_INFO("%d %s", (int)i, robot_model_->getJointModelGroupNames()[i].c_str());
00498 geometry_msgs::Vector3 default_approach_direction;
00499 default_approach_direction.x = 1.0;
00500 default_approach_direction.y = 0.0;
00501 default_approach_direction.z = 0.0;
00502 const robot_model::JointModelGroup* jmg = robot_model_->getJointModelGroup(robot_model_->getJointModelGroupNames()[i]);
00503 if(jmg && jmg->isEndEffector())
00504 {
00505 std::string database_id;
00506 root_nh_.param<std::string>(jmg->getEndEffectorName()+"/database_id", database_id, "");
00507 if(!database_id.empty())
00508 {
00509 database_hand_ids_[jmg->getEndEffectorName()] = database_id;
00510 ROS_INFO("Found database id: %s for %s", database_id.c_str(), jmg->getEndEffectorName().c_str());
00511 }
00512 bool found = false;
00513 geometry_msgs::Vector3 approach_direction =
00514 approachDirection(jmg->getEndEffectorName()+"/approach_direction", found);
00515 if(found)
00516 {
00517 approach_direction_[jmg->getEndEffectorName()] = approach_direction;
00518 ROS_INFO("Found approach directions for %s: %f %f %f",
00519 jmg->getEndEffectorName().c_str(),
00520 approach_direction.x,
00521 approach_direction.y,
00522 approach_direction.z);
00523 }
00524
00525
00526 }
00527 }
00528 }
00529
00530 ~ObjectsDatabaseNode()
00531 {
00532 delete database_;
00533 }
00534 };
00535
00536 int main(int argc, char **argv)
00537 {
00538 ros::init(argc, argv, "objects_database_node");
00539
00540 ros::AsyncSpinner spinner(1);
00541 spinner.start();
00542
00543
00544 robot_model_loader::RobotModelLoader robot_model_loader("robot_description");
00545
00546 ROS_INFO("Loaded robot model");
00547
00548 robot_model::RobotModelPtr robot_model = robot_model_loader.getModel();
00549 ROS_INFO("Loaded robot model");
00550
00551 ObjectsDatabaseNode node(robot_model);
00552
00553 ros::waitForShutdown();
00554 return 0;
00555 }