00001
00011 #include <boost/algorithm/string.hpp>
00012 #include <carl_dynamixel/LookAtFrame.h>
00013 #include <interactive_world_tools/HighLevelActions.h>
00014 #include <ros/package.h>
00015 #include <std_srvs/Empty.h>
00016 #include <tf2_ros/transform_listener.h>
00017 #include <yaml-cpp/yaml.h>
00018
00019 using namespace std;
00020 using namespace rail::interactive_world;
00021
00022 HighLevelActions::HighLevelActions()
00023 : private_node_("~"), nav_ac_("/move_base", true), ac_wait_time_(AC_WAIT_TIME), fixed_frame_("map"),
00024 home_arm_ac_("/carl_moveit_wrapper/common_actions/arm_action", true),
00025 drive_and_search_as_(
00026 private_node_, "drive_and_search", boost::bind(&HighLevelActions::driveAndSearch, this, _1), false
00027 ),
00028 drive_to_surface_as_(
00029 private_node_, "drive_to_surface", boost::bind(&HighLevelActions::driveToSurface, this, _1), false
00030 )
00031 {
00032
00033 recognized_objects_counter_ = 0;
00034 string world_file(ros::package::getPath("interactive_world_tools") + "/config/world.yaml");
00035
00036
00037 private_node_.getParam("world_config", world_file);
00038 private_node_.getParam("fixed_frame", fixed_frame_);
00039
00040
00041 look_at_frame_srv_ = node_.serviceClient<carl_dynamixel::LookAtFrame>("/asus_controller/look_at_frame");
00042 segment_srv_ = node_.serviceClient<std_srvs::Empty>("/rail_segmentation/segment");
00043 find_surface_srv_ = private_node_.advertiseService("find_surface", &HighLevelActions::findSurfaceCallback, this);
00044 get_surfaces_srv_ = private_node_.advertiseService("get_surfaces", &HighLevelActions::getSurfacesCallback, this);
00045 transform_to_surface_frame_srv_ = private_node_.advertiseService("transform_to_surface_frame",
00046 &HighLevelActions::transformToSurfaceFrame, this);
00047 recognized_objects_sub_ = node_.subscribe("/object_recognition_listener/recognized_objects", 1,
00048 &HighLevelActions::recognizedObjectsCallback, this);
00049
00050
00051 #ifdef YAMLCPP_GT_0_5_0
00052
00053 tf2_ros::Buffer tf_buffer;
00054 tf2_ros::TransformListener tf_listener(tf_buffer);
00055
00056 sleep(tf_buffer.getCacheLength().sec / 10);
00057
00058
00059 YAML::Node world_config = YAML::LoadFile(world_file);
00060 for (size_t i = 0; i < world_config.size(); i++)
00061 {
00062
00063 YAML::Node room_config = world_config[i];
00064 Room room(room_config["name"].as<string>(), room_config["frame_id"].as<string>());
00065
00066 static_tfs_[room.getFrameID()] = tf_buffer.lookupTransform(fixed_frame_, room.getFrameID(), ros::Time(0));
00067
00068
00069 YAML::Node surfaces_config = room_config["surfaces"];
00070 for (size_t j = 0; j < surfaces_config.size(); j++)
00071 {
00072 YAML::Node surface_config = surfaces_config[j];
00073
00074 Surface surface(surface_config["name"].as<string>(), surface_config["frame_id"].as<string>(),
00075 surface_config["width"].as<double>(), surface_config["height"].as<double>());
00076
00077 static_tfs_[surface.getFrameID()] = tf_buffer.lookupTransform(fixed_frame_, surface.getFrameID(), ros::Time(0));
00078
00079
00080 YAML::Node aliases_config = surface_config["aliases"];
00081 for (size_t k = 0; k < aliases_config.size(); k++)
00082 {
00083
00084 surface.addAlias(aliases_config[k].as<string>());
00085 }
00086
00087
00088 YAML::Node placement_surfaces_config = surface_config["placement_surfaces"];
00089 for (size_t k = 0; k < placement_surfaces_config.size(); k++)
00090 {
00091
00092 YAML::Node ps_config = placement_surfaces_config[k];
00093 PlacementSurface ps(ps_config["frame_id"].as<string>(), ps_config["nav_frame_id"].as<string>());
00094 surface.addPlacementSurface(ps);
00095
00096 static_tfs_[ps.getFrameID()] = tf_buffer.lookupTransform(fixed_frame_, ps.getFrameID(), ros::Time(0));
00097 static_tfs_[ps.getNavFrameID()] = tf_buffer.lookupTransform(fixed_frame_, ps.getNavFrameID(), ros::Time(0));
00098 }
00099
00100
00101 YAML::Node pois_config = surface_config["pois"];
00102 for (size_t k = 0; k < pois_config.size(); k++)
00103 {
00104
00105 YAML::Node poi_config = pois_config[k];
00106 PointOfInterest poi(poi_config["name"].as<string>(), poi_config["frame_id"].as<string>());
00107
00108 static_tfs_[poi.getFrameID()] = tf_buffer.lookupTransform(fixed_frame_, poi.getFrameID(), ros::Time(0));
00109 surface.addPointOfInterest(poi);
00110 }
00111
00112 room.addSurface(surface);
00113 }
00114
00115
00116 world_.addRoom(room);
00117 }
00118
00119 drive_and_search_as_.start();
00120 drive_to_surface_as_.start();
00121 ROS_INFO("High Level Actions Successfully Initialized");
00122 okay_ = true;
00123 #else
00124 ROS_ERROR("Unsupported version of YAML. Config files could not be parsed.");
00125 okay_ = false;
00126 #endif
00127 }
00128
00129 bool HighLevelActions::okay() const
00130 {
00131 return okay_;
00132 }
00133
00134 bool HighLevelActions::getSurfacesCallback(interactive_world_msgs::GetSurfaces::Request & req,
00135 interactive_world_msgs::GetSurfaces::Response & resp)
00136 {
00137 for (size_t i = 0; i < world_.getNumRooms(); i++)
00138 {
00139 const Room &room = world_.getRoom(i);
00140 for (size_t j = 0; j < room.getNumSurfaces(); j++)
00141 {
00142 resp.surfaces.push_back(room.getSurface(j).getName());
00143 }
00144 }
00145
00146 return true;
00147 }
00148
00149 bool HighLevelActions::transformToSurfaceFrame(interactive_world_msgs::TransformToSurfaceFrame::Request &req,
00150 interactive_world_msgs::TransformToSurfaceFrame::Response &resp)
00151 {
00152
00153 tf2::Transform t_pose_world;
00154 if (req.pose.header.frame_id != fixed_frame_)
00155 {
00156 ROS_WARN("Find surface request not in the global fixed frame. Will wait for TF information which can take time...");
00157 tf2_ros::Buffer tf_buffer;
00158 tf2_ros::TransformListener tf_listener(tf_buffer);
00159
00160 sleep(tf_buffer.getCacheLength().sec / 10);
00161 geometry_msgs::TransformStamped tf = tf_buffer.lookupTransform(fixed_frame_, req.pose.header.frame_id,
00162 ros::Time(0));
00163
00164 tf2::Transform t_req_world = this->tfFromTFMessage(tf.transform);
00165 tf2::Transform t_pose_req = this->tfFromPoseMessage(req.pose.pose);
00166 t_pose_world = t_req_world * t_pose_req;
00167 } else
00168 {
00169 t_pose_world = this->tfFromPoseMessage(req.pose.pose);
00170 }
00171
00172
00173 vector<const Surface *> surfaces = world_.findSurfaces(req.surface);
00174 if (surfaces.empty())
00175 {
00176 ROS_WARN("Could not find surface %s.", req.surface.c_str());
00177 return false;
00178 } else
00179 {
00180 const Surface *surface = surfaces[0];
00181
00182 tf2::Transform t_surface_world = this->tfFromTFMessage(static_tfs_[surface->getFrameID()].transform);
00183 tf2::Transform t_pose_surface = t_surface_world.inverseTimes(t_pose_world);
00184
00185 resp.pose.header.frame_id = surface->getFrameID();
00186 resp.pose.pose.position.x = t_pose_surface.getOrigin().x();
00187 resp.pose.pose.position.y = t_pose_surface.getOrigin().y();
00188 resp.pose.pose.position.z = t_pose_surface.getOrigin().z();
00189 resp.pose.pose.orientation.x = t_pose_surface.getRotation().x();
00190 resp.pose.pose.orientation.y = t_pose_surface.getRotation().y();
00191 resp.pose.pose.orientation.z = t_pose_surface.getRotation().z();
00192 resp.pose.pose.orientation.w = t_pose_surface.getRotation().w();
00193
00194 return true;
00195 }
00196 }
00197
00198 bool HighLevelActions::findSurfaceCallback(interactive_world_msgs::FindSurface::Request &req,
00199 interactive_world_msgs::FindSurface::Response &resp)
00200 {
00201
00202 tf2::Transform t_pose_world;
00203 if (req.pose.header.frame_id != fixed_frame_)
00204 {
00205 ROS_WARN("Find surface request not in the global fixed frame. Will wait for TF information which can take time...");
00206 tf2_ros::Buffer tf_buffer;
00207 tf2_ros::TransformListener tf_listener(tf_buffer);
00208
00209 sleep(tf_buffer.getCacheLength().sec / 10);
00210 geometry_msgs::TransformStamped tf = tf_buffer.lookupTransform(fixed_frame_, req.pose.header.frame_id,
00211 ros::Time(0));
00212
00213 tf2::Transform t_req_world = this->tfFromTFMessage(tf.transform);
00214 tf2::Transform t_pose_req = this->tfFromPoseMessage(req.pose.pose);
00215 t_pose_world = t_req_world * t_pose_req;
00216 } else
00217 {
00218 t_pose_world = this->tfFromPoseMessage(req.pose.pose);
00219 }
00220
00221
00222 for (size_t i = 0; i < world_.getNumRooms(); i++)
00223 {
00224 const Room &room = world_.getRoom(i);
00225 for (size_t j = 0; j < room.getNumSurfaces(); j++)
00226 {
00227 const Surface &surface = room.getSurface(j);
00228
00229
00230 tf2::Transform t_surface_world = this->tfFromTFMessage(static_tfs_[surface.getFrameID()].transform);
00231 tf2::Transform t_pose_surface = t_surface_world.inverseTimes(t_pose_world);
00232
00233
00234 if ((surface.getWidth() / 2.0 >= abs(t_pose_surface.getOrigin().x()))
00235 && (surface.getHeight() / 2.0 >= abs(t_pose_surface.getOrigin().y())))
00236 {
00237
00238 double closest = numeric_limits<double>::infinity();
00239 for (size_t k = 0; k < surface.getNumPlacementSurfaces(); k++)
00240 {
00241 const PlacementSurface &ps = surface.getPlacementSurface(k);
00242
00243
00244 tf2::Transform t_ps_world = this->tfFromTFMessage(static_tfs_[ps.getFrameID()].transform);
00245 double distance = t_ps_world.getOrigin().distance(t_surface_world.getOrigin());
00246 if (distance < closest)
00247 {
00248
00249
00250
00251
00252 closest = distance;
00253 resp.placement_surface_frame_id = ps.getFrameID();
00254
00255 }
00256 }
00257
00258 if (closest < numeric_limits<double>::infinity())
00259 {
00260
00261 resp.surface = surface.getName();
00262 resp.surface_frame_id = surface.getFrameID();
00263 return true;
00264 }
00265
00266 ROS_WARN("Point was found to be inside of '%s' but not on the surface itself.", surface.getName().c_str());
00267 return true;
00268 }
00269 }
00270 }
00271
00272
00273 ROS_WARN("Point was not found to be on any surface.");
00274 return true;
00275 }
00276
00277 void HighLevelActions::driveAndSearch(const interactive_world_msgs::DriveAndSearchGoalConstPtr &goal)
00278 {
00279
00280 string item_name = boost::to_upper_copy(goal->item);
00281 string surface_name = boost::to_upper_copy(goal->surface);
00282 ROS_INFO("Searching for '%s' on the '%s'...", item_name.c_str(), surface_name.c_str());
00283
00284 interactive_world_msgs::DriveAndSearchFeedback feedback;
00285 interactive_world_msgs::DriveAndSearchResult result;
00286
00287 result.success = false;
00288
00289
00290 vector<const Surface *> surfaces = world_.findSurfaces(surface_name);
00291
00292 if (surfaces.size() == 0)
00293 {
00294 drive_and_search_as_.setSucceeded(result, "Could not locate surface.");
00295 return;
00296 }
00297
00298
00299 for (size_t i = 0; i < surfaces.size(); i++)
00300 {
00301 const Surface *cur = surfaces[i];
00302
00303 for (size_t j = 0; j < cur->getNumPlacementSurfaces(); j++)
00304 {
00305 const PlacementSurface &ps = cur->getPlacementSurface(j);
00306
00307
00308 rail_manipulation_msgs::ArmGoal arm_goal;
00309 arm_goal.action = rail_manipulation_msgs::ArmGoal::RETRACT;
00310 home_arm_ac_.sendGoal(arm_goal);
00311 bool completed = home_arm_ac_.waitForResult(ac_wait_time_);
00312 bool succeeded = (home_arm_ac_.getState() == actionlib::SimpleClientGoalState::SUCCEEDED);
00313 bool success = home_arm_ac_.getResult()->success;
00314 if (!completed || !succeeded || !success)
00315 {
00316 ROS_ERROR("Could not retract arm during search.");
00317 drive_and_search_as_.setSucceeded(result, "Could not retract arm during search.");
00318 }
00319
00320
00321 feedback.message = "Attempting to drive to " + ps.getNavFrameID();
00322 drive_and_search_as_.publishFeedback(feedback);
00323 if (!this->driveHelper(ps.getNavFrameID()))
00324 {
00325 ROS_WARN("Could not drive to %s, will continue the search elsewhere.", ps.getNavFrameID().c_str());
00326 continue;
00327 }
00328
00329
00330 feedback.message = "Attempting to look at " + ps.getFrameID();
00331 drive_and_search_as_.publishFeedback(feedback);
00332 carl_dynamixel::LookAtFrame look;
00333 look.request.frame = ps.getFrameID();
00334 if (!look_at_frame_srv_.call(look))
00335 {
00336 ROS_WARN("Could not look at %s, will continue the search elsewhere.", ps.getFrameID().c_str());
00337 continue;
00338 }
00339
00340
00341 uint32_t counter;
00342 {
00343 boost::mutex::scoped_lock lock(recognized_objects_mutex_);
00344 counter = recognized_objects_counter_;
00345 }
00346
00347
00348 feedback.message = "Attempting to segment the surface.";
00349 drive_and_search_as_.publishFeedback(feedback);
00350 std_srvs::Empty segment;
00351 if (!segment_srv_.call(segment))
00352 {
00353 ROS_WARN("Could not segment surface, will continue the search elsewhere.");
00354 continue;
00355 }
00356
00357
00358 feedback.message = "Waiting for recognition results.";
00359 drive_and_search_as_.publishFeedback(feedback);
00360 bool finished = false;
00361 while (!finished)
00362 {
00363 {
00364 boost::mutex::scoped_lock lock(recognized_objects_mutex_);
00365 finished = recognized_objects_counter_ == (counter + 2);
00366 }
00367 }
00368
00369
00370 boost::mutex::scoped_lock lock(recognized_objects_mutex_);
00371 for (size_t i = 0; i < recognized_objects_.objects.size(); i++)
00372 {
00373 if (recognized_objects_.objects[i].recognized)
00374 {
00375 string cur_name = boost::to_upper_copy(recognized_objects_.objects[i].name);
00376
00377 if (cur_name == item_name)
00378 {
00379
00380 result.success = true;
00381 result.objects.objects.push_back(recognized_objects_.objects[i]);
00382 }
00383 }
00384 }
00385
00386
00387 if (result.success)
00388 {
00389 drive_and_search_as_.setSucceeded(result, "Object located.");
00390 return;
00391 }
00392 }
00393 }
00394
00395 drive_and_search_as_.setSucceeded(result, "Could not locate object.");
00396 }
00397
00398 void HighLevelActions::driveToSurface(const interactive_world_msgs::DriveToSurfaceGoalConstPtr &goal)
00399 {
00400
00401 string surface_name = boost::to_upper_copy(goal->surface);
00402 string poi_name = boost::to_upper_copy(goal->poi);
00403 ROS_INFO("Driving to '%s'...", surface_name.c_str());
00404
00405 interactive_world_msgs::DriveToSurfaceFeedback feedback;
00406 interactive_world_msgs::DriveToSurfaceResult result;
00407
00408 result.success = false;
00409
00410
00411 vector<const Surface *> surfaces = world_.findSurfaces(surface_name);
00412
00413 if (surfaces.size() == 0)
00414 {
00415 drive_to_surface_as_.setSucceeded(result, "Could not locate surface.");
00416 return;
00417 }
00418
00419
00420 const Surface *surface = surfaces[0];
00421 const PointOfInterest *poi = NULL;
00422 if (poi_name.size() > 0)
00423 {
00424 for (size_t i = 0; i < surfaces.size() && poi == NULL; i++)
00425 {
00426
00427 const Surface *cur = surfaces[i];
00428 for (size_t j = 0; j < cur->getNumPointsOfInterest() && poi == NULL; j++)
00429 {
00430
00431 if (boost::to_upper_copy(cur->getPointOfInterest(j).getName()) == poi_name)
00432 {
00433 poi = &(cur->getPointOfInterest(j));
00434 surface = surfaces[i];
00435 }
00436 }
00437 }
00438 }
00439
00440
00441 double best_distance = numeric_limits<double>::infinity();
00442 size_t best_index = 0;
00443 if (poi != NULL)
00444 {
00445 tf2::Transform t_poi_world = this->tfFromTFMessage(static_tfs_[poi->getFrameID()].transform);
00446
00447 for (size_t i = 0; i < surface->getNumPlacementSurfaces(); i++)
00448 {
00449
00450 const PlacementSurface &pc = surface->getPlacementSurface(i);
00451 tf2::Transform t_pc_world = this->tfFromTFMessage(static_tfs_[pc.getNavFrameID()].transform);
00452
00453 double distance = t_pc_world.getOrigin().distance(t_poi_world.getOrigin());
00454 if (distance < best_distance)
00455 {
00456 best_distance = distance;
00457 best_index = i;
00458 }
00459 }
00460 } else
00461 {
00462
00463 for (size_t i = 0; i < surface->getNumPlacementSurfaces(); i++)
00464 {
00465
00466 const PlacementSurface &pc = surface->getPlacementSurface(i);
00467 tf2::Transform t_pc_world = this->tfFromTFMessage(static_tfs_[pc.getNavFrameID()].transform);
00468 tf2::Vector3 point(goal->point.x, goal->point.y, goal->point.z);
00469
00470 double distance = t_pc_world.getOrigin().distance(point);
00471 if (distance < best_distance)
00472 {
00473 best_distance = distance;
00474 best_index = i;
00475 }
00476 }
00477 }
00478
00479
00480 feedback.message = "Attempting to drive to " + surface->getPlacementSurface(best_index).getNavFrameID();
00481 drive_to_surface_as_.publishFeedback(feedback);
00482 if (this->driveHelper(surface->getPlacementSurface(best_index).getNavFrameID()))
00483 {
00484 result.success = true;
00485 drive_to_surface_as_.setSucceeded(result, "Success!");
00486 } else
00487 {
00488 drive_to_surface_as_.setSucceeded(result, "Could not navigate correctly.");
00489 }
00490 }
00491
00492 bool HighLevelActions::driveHelper(const std::string &frame_id)
00493 {
00494
00495 boost::mutex::scoped_lock lock(nav_mutex_);
00496
00497 move_base_msgs::MoveBaseGoal nav_goal;
00498
00499 nav_goal.target_pose.header.frame_id = frame_id;
00500 nav_goal.target_pose.pose.orientation.w = QUATERNION_90_ROTATE;
00501 nav_goal.target_pose.pose.orientation.z = QUATERNION_90_ROTATE;
00502 nav_ac_.sendGoal(nav_goal);
00503 bool completed = nav_ac_.waitForResult(ac_wait_time_);
00504 bool succeeded = (nav_ac_.getState() == actionlib::SimpleClientGoalState::SUCCEEDED);
00505 return completed && succeeded;
00506 }
00507
00508 tf2::Transform HighLevelActions::tfFromTFMessage(const geometry_msgs::Transform &tf)
00509 {
00510
00511 return tf2::Transform(tf2::Quaternion(tf.rotation.x, tf.rotation.y, tf.rotation.z, tf.rotation.w),
00512 tf2::Vector3(tf.translation.x, tf.translation.y, tf.translation.z));
00513 }
00514
00515 tf2::Transform HighLevelActions::tfFromPoseMessage(const geometry_msgs::Pose &pose)
00516 {
00517
00518 return tf2::Transform(tf2::Quaternion(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w),
00519 tf2::Vector3(pose.position.x, pose.position.y, pose.position.z));
00520 }
00521
00522 void HighLevelActions::recognizedObjectsCallback(const rail_manipulation_msgs::SegmentedObjectList &objects)
00523 {
00524
00525 boost::mutex::scoped_lock lock(recognized_objects_mutex_);
00526
00527 recognized_objects_ = objects;
00528 recognized_objects_counter_++;
00529 }