00001 #include "planner_modules_pr2/putdown_modules.h"
00002 #include "planner_modules_pr2/module_param_cache.h"
00003
00004
00005 #include "planner_modules_pr2/tidyup_planning_scene_updater.h"
00006 #include "tidyup_utils/planning_scene_interface.h"
00007
00008 #include <ros/ros.h>
00009 #include <geometry_msgs/PoseStamped.h>
00010 #include <map>
00011 #include <set>
00012 using std::set;
00013 using std::map;
00014 #include <utility>
00015 using std::pair; using std::make_pair;
00016
00017
00018
00019
00020
00021
00022 #include <sys/times.h>
00023
00024
00025 #include <arm_navigation_msgs/ArmNavigationErrorCodes.h>
00026 #include <arm_navigation_msgs/convert_messages.h>
00027
00028
00029 #include <tidyup_msgs/GetPutdownPose.h>
00030 #include <sstream>
00031 #include "tidyup_utils/stringutil.h"
00032
00033 VERIFY_CONDITIONCHECKER_DEF(canPutdown);
00034 VERIFY_APPLYEFFECT_DEF(updatePutdownPose);
00035
00036 string g_WorldFrame;
00037 ros::NodeHandle* g_NodeHandle = NULL;
00038 ros::ServiceClient g_GetPutdownPose;
00039
00040 ModuleParamCacheString paramCache;
00041 string separator = " ";
00042
00043 string logName;
00044 geometry_msgs::Pose defaultAttachPose;
00045
00046
00047 void putdown_init(int argc, char** argv)
00048 {
00049 ROS_ASSERT(argc == 2);
00050 logName = "[putdownModule]";
00051
00052 g_NodeHandle = new ros::NodeHandle();
00053 string service_name = "/tidyup/request_putdown_pose";
00054
00055 while (!ros::service::waitForService(service_name, ros::Duration(3.0)))
00056 {
00057 ROS_ERROR("%s Service %s not available - waiting.", logName.c_str(), service_name.c_str());
00058 }
00059
00060 g_GetPutdownPose = g_NodeHandle->serviceClient<tidyup_msgs::GetPutdownPose>(service_name, true);
00061 if (!g_GetPutdownPose)
00062 {
00063 ROS_FATAL("%s Could not initialize get putdown service from %s (client name: %s)", logName.c_str(), service_name.c_str(), g_GetPutdownPose.getService().c_str());
00064 }
00065
00066
00067 paramCache.initialize("putdown", g_NodeHandle);
00068
00069 defaultAttachPose.position.x = 0.032;
00070 defaultAttachPose.position.y = 0.015;
00071 defaultAttachPose.position.z = 0.0;
00072 defaultAttachPose.orientation.x = 0.707;
00073 defaultAttachPose.orientation.y = -0.106;
00074 defaultAttachPose.orientation.z = -0.690;
00075 defaultAttachPose.orientation.w = 0.105;
00076
00077 ROS_INFO("%s Initialized Putdown Module.\n", logName.c_str());
00078 }
00079
00080 bool callFindPutdownPoseService(tidyup_msgs::GetPutdownPose & srv)
00081 {
00082 if (!g_GetPutdownPose)
00083 {
00084 ROS_ERROR("%s Persistent service connection to %s failed.", logName.c_str(), g_GetPutdownPose.getService().c_str());
00085
00086 return false;
00087 }
00088
00089
00090 static double plannerCalls = 0;
00091 static ros::Duration totalCallsTime = ros::Duration(0.0);
00092 plannerCalls += 1.0;
00093 ros::Time callStartTime = ros::Time::now();
00094
00095
00096 if (! g_GetPutdownPose.call(srv))
00097 {
00098 ROS_ERROR("%s Failed to call service %s.", logName.c_str(), g_GetPutdownPose.getService().c_str());
00099 return false;
00100 }
00101 if (g_Debug)
00102 {
00103 ros::Time callEndTime = ros::Time::now();
00104 ros::Duration dt = callEndTime - callStartTime;
00105 totalCallsTime += dt;
00106 ROS_DEBUG("%s ServiceCall took: %f, avg: %f (num %f).", logName.c_str(),
00107 dt.toSec(), totalCallsTime.toSec()/plannerCalls, plannerCalls);
00108 }
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 return true;
00120 }
00121
00122 string writePoseToString(const geometry_msgs::Pose& pose)
00123 {
00124 std::stringstream stream;
00125 stream.precision(0);
00126 stream << std::fixed;
00127 stream << pose.position.x << separator;
00128 stream << pose.position.y << separator;
00129 stream << pose.position.z << separator;
00130 stream << pose.orientation.x << separator;
00131 stream << pose.orientation.y << separator;
00132 stream << pose.orientation.z << separator;
00133 stream << pose.orientation.w << separator;
00134 return stream.str();
00135 }
00136
00137 bool readPoseFromString(const string cacheValue, geometry_msgs::Pose& pose)
00138 {
00139 std::stringstream stream;
00140 stream << cacheValue;
00141 vector<double> coordinates;
00142 coordinates.resize(7);
00143 for(size_t i = 0; ! stream.eof() && i < coordinates.size(); i++)
00144 {
00145 stream >> coordinates[i];
00146 }
00147 if (!stream.good())
00148 return false;
00149 pose.position.x = coordinates[0];
00150 pose.position.y = coordinates[1];
00151 pose.position.z = coordinates[2];
00152 pose.orientation.x = coordinates[3];
00153 pose.orientation.y = coordinates[4];
00154 pose.orientation.z = coordinates[5];
00155 pose.orientation.w = coordinates[6];
00156 return true;
00157 }
00158
00159 string createCacheKey(const string& putdownObject,
00160 const string& arm,
00161 const string& staticObject,
00162 const map<string, geometry_msgs::Pose>& movableObjects,
00163 const map<string, string>& objectsOnStatic)
00164 {
00165 ROS_DEBUG("%s createCacheKey %s %s %s", logName.c_str(), putdownObject.c_str(), arm.c_str(), staticObject.c_str());
00166 std::stringstream stream;
00167 stream.precision(0);
00168 stream << std::fixed << putdownObject << arm << staticObject;
00169 for (map<string, string>::const_iterator objectIt = objectsOnStatic.begin(); objectIt != objectsOnStatic.end(); objectIt++)
00170 {
00171 ROS_DEBUG("%s object %s on %s", logName.c_str(), objectIt->first.c_str(), objectIt->second.c_str());
00172 if (objectIt->second == staticObject)
00173 {
00174 const geometry_msgs::Pose& pose = movableObjects.find(objectIt->first)->second;
00175
00176
00177 std::string poseParamString = createPoseParamString(pose);
00178 stream << poseParamString;
00179 }
00180 }
00181 return stream.str();
00182 }
00183
00184 bool findPutdownPose(const ParameterList & parameterList,
00185 predicateCallbackType predicateCallback,
00186 numericalFluentCallbackType numericalFluentCallback,
00187 geometry_msgs::Pose& putdown_pose)
00188 {
00189
00190 ROS_ASSERT(parameterList.size() == 4);
00191 Parameter putdown_object = parameterList[0];
00192 Parameter arm = parameterList[1];
00193 Parameter static_object = parameterList[2];
00194 Parameter robot_location = parameterList[3];
00195
00196
00197 geometry_msgs::Pose robotPose;
00198 map<string, geometry_msgs::Pose> movableObjects;
00199 map<string, string> graspedObjects;
00200 map<string, string> objectsOnStatic;
00201 set<string> openDoors;
00202 arm_navigation_msgs::PlanningScene world = PlanningSceneInterface::instance()->getCurrentScene();
00203 if (! TidyupPlanningSceneUpdater::readState(robot_location.value, predicateCallback, numericalFluentCallback, robotPose, movableObjects, graspedObjects, objectsOnStatic, openDoors))
00204 {
00205 ROS_ERROR("%s read state failed.", logName.c_str());
00206 return false;
00207 }
00208
00209 tidyup_msgs::GetPutdownPose srv;
00210 srv.request.static_object = static_object.value;
00211 srv.request.putdown_object = putdown_object.value;
00212 srv.request.arm = arm.value;
00213 ROS_INFO("%s putdown request: %s, %s, %s, %s", logName.c_str(), parameterList[0].value.c_str(), parameterList[1].value.c_str(), parameterList[2].value.c_str(), parameterList[3].value.c_str());
00214
00215 string cacheKey = createCacheKey(srv.request.putdown_object, srv.request.arm, srv.request.static_object, movableObjects, objectsOnStatic);
00216 ROS_DEBUG("%s cacheKey: %s", logName.c_str(), cacheKey.c_str());
00217
00218 string cacheValue;
00219 if (paramCache.get(cacheKey, cacheValue))
00220 {
00221
00222 if (cacheValue == "impossible")
00223 {
00224 ROS_DEBUG("%s cache hit: impossible", logName.c_str());
00225 return false;
00226 }
00227 else
00228 {
00229 if (! readPoseFromString(cacheValue, putdown_pose))
00230 {
00231 ROS_ERROR("%s could not read cached value. cache may be corrupt.", logName.c_str());
00232 return false;
00233 }
00234 ROS_DEBUG("%s cache hit: pose from cache", logName.c_str());
00235 return true;
00236 }
00237 }
00238
00239
00240 PlanningSceneInterface::instance()->resetPlanningScene();
00241 ROS_DEBUG("%s set planning scene", logName.c_str());
00242 if (! TidyupPlanningSceneUpdater::update(robotPose, movableObjects, graspedObjects, openDoors))
00243 {
00244 ROS_ERROR("%s update planning scene failed.", logName.c_str());
00245 return false;
00246 }
00247
00248
00249 srv.request.planning_scene = PlanningSceneInterface::instance()->getCurrentScene();
00250
00251
00252 ROS_INFO("%s call putdown service", logName.c_str());
00253 if (! callFindPutdownPoseService(srv))
00254 {
00255 ROS_ERROR("%s service call failed", logName.c_str());
00256 return false;
00257 }
00258 if (srv.response.error_code.val == srv.response.error_code.PLANNING_FAILED)
00259 {
00260 ROS_INFO("%s service returned: impossible", logName.c_str());
00261 paramCache.set(cacheKey, "impossible", true);
00262 return false;
00263 }
00264 if (srv.response.error_code.val == srv.response.error_code.SUCCESS)
00265 {
00266
00267 ROS_INFO("%s service returned: pose found, adding to cache", logName.c_str());
00268 putdown_pose = srv.response.putdown_pose.pose;
00269 paramCache.set(cacheKey, writePoseToString(putdown_pose), true);
00270 return true;
00271 }
00272
00273 ROS_ERROR("%s GetPutdownPose failed. Reason: %s (%d)", logName.c_str(),
00274 arm_navigation_msgs::armNavigationErrorCodeToString(srv.response.error_code).c_str(),
00275 srv.response.error_code.val);
00276 return false;
00277 }
00278
00279
00280 double canPutdown(const ParameterList & parameterList,
00281 predicateCallbackType predicateCallback,
00282 numericalFluentCallbackType numericalFluentCallback,
00283 int relaxed)
00284 {
00285 if (relaxed != 0)
00286 {
00287
00288 return 0;
00289 }
00290 if (g_Debug)
00291 {
00292
00293 static unsigned int calls = 0;
00294 calls++;
00295 if (calls % 10000 == 0)
00296 {
00297 ROS_DEBUG("%s Got %d putdown module calls.\n", logName.c_str(), calls);
00298 }
00299 }
00300
00301 geometry_msgs::Pose putdownPose;
00302 if (! findPutdownPose(parameterList, predicateCallback, numericalFluentCallback, putdownPose))
00303 {
00304 return INFINITE_COST;
00305 }
00306 return 0;
00307 }
00308
00309 int updatePutdownPose(const ParameterList & parameterList, predicateCallbackType predicateCallback,
00310 numericalFluentCallbackType numericalFluentCallback, std::vector<double> & writtenVars)
00311 {
00312 geometry_msgs::Pose putdownPose;
00313 if (! findPutdownPose(parameterList, predicateCallback, numericalFluentCallback, putdownPose))
00314 {
00315 return 1;
00316 }
00317
00318 writtenVars[0] = putdownPose.position.x;
00319 writtenVars[1] = putdownPose.position.y;
00320 writtenVars[2] = putdownPose.position.z;
00321 writtenVars[3] = putdownPose.orientation.x;
00322 writtenVars[4] = putdownPose.orientation.y;
00323 writtenVars[5] = putdownPose.orientation.z;
00324 writtenVars[6] = putdownPose.orientation.w;
00325 return 0;
00326 }
00327