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
00039 #include <occupancy_grid_utils/geometry.h>
00040 #include <occupancy_grid_utils/shortest_path.h>
00041 #include <ros/ros.h>
00042 #include <actionlib/client/simple_action_client.h>
00043 #include <move_base_msgs/MoveBaseAction.h>
00044 #include <visualization_msgs/Marker.h>
00045 #include <tf/transform_listener.h>
00046 #include <boost/foreach.hpp>
00047 #include <boost/math/constants/constants.hpp>
00048 #include <geometry_msgs/PolygonStamped.h>
00049
00050 namespace semanticmodel
00051 {
00052 namespace gu=occupancy_grid_utils;
00053 namespace nm=nav_msgs;
00054 namespace vm=visualization_msgs;
00055 namespace gm=geometry_msgs;
00056 namespace al=actionlib;
00057 namespace mbm=move_base_msgs;
00058
00059 using std::set;
00060 using std::vector;
00061 using boost::optional;
00062 using std::cerr;
00063 using std::endl;
00064
00065 typedef boost::mutex::scoped_lock Lock;
00066 typedef std::set<gu::Cell> Cells;
00067
00068
00069 class Node
00070 {
00071 public:
00072
00073 Node ();
00074
00075
00076 void mapCB (const nm::OccupancyGrid& map);
00077
00078
00079 void run ();
00080
00081
00082 void visualize(const ros::WallTimerEvent& e);
00083
00084
00085 void updateSeen(const ros::TimerEvent&e = ros::TimerEvent());
00086
00087 private:
00088
00089 gm::Pose getCurrentPose ();
00090
00091 gm::Polygon getVisibleRegion (const gm::Pose& p) const;
00092
00093 optional<size_t> getNextGoal();
00094
00095 bool navigateWaypoint (size_t i);
00096
00097 optional<size_t> getViewpoint(size_t target);
00098
00099 ros::NodeHandle nh_;
00100 boost::mutex mutex_;
00101
00102 const float robot_radius_;
00103
00104
00105 boost::optional<nm::OccupancyGrid> map_;
00106
00107
00108 vector<gu::Cell> targets_;
00109
00110
00111 set<size_t> seen_, unseen_;
00112
00113
00114 vector<gm::Pose> view_poses_;
00115
00116
00117 vector<vector<bool> > is_visible_;
00118
00119
00120
00121 set<size_t> forbidden_;
00122
00123
00124 bool initialized_;
00125
00126
00127 al::SimpleActionClient<mbm::MoveBaseAction> mb_client_;
00128 ros::Publisher vis_pub_;
00129 ros::Publisher visible_poly_pub_;
00130 ros::Subscriber map_sub_;
00131 ros::WallTimer vis_timer_;
00132 ros::Timer update_timer_;
00133 tf::TransformListener tf_;
00134 };
00135
00136 Node::Node () :
00137 robot_radius_(0.7), mb_client_("move_base", true),
00138 vis_pub_(nh_.advertise<vm::Marker>("visualization_marker", 100)),
00139 visible_poly_pub_(nh_.advertise<gm::PolygonStamped>("visible_polygon", 100)),
00140 map_sub_(nh_.subscribe("/map", 10, &Node::mapCB, this)),
00141 vis_timer_(nh_.createWallTimer(ros::WallDuration(1.0), &Node::visualize,
00142 this)),
00143 update_timer_(nh_.createTimer(ros::Duration(0.3), &Node::updateSeen, this))
00144 {}
00145
00146
00147 void Node::mapCB (const nm::OccupancyGrid& map)
00148 {
00149 Lock l(mutex_);
00150 map_ = map;
00151 ROS_INFO ("Map received");
00152 }
00153
00154
00155 struct CheckReachable
00156 {
00157 CheckReachable (const nm::MapMetaData& info, gu::ResultPtr navfn,
00158 float max_dist) :
00159 info(info), navfn(navfn), max_dist(max_dist)
00160 {}
00161
00162 bool operator() (const gu::Cell& c) const
00163 {
00164 boost::optional<double> dist = gu::distanceTo(navfn, c);
00165 return (dist && (*dist < max_dist));
00166 }
00167
00168 nm::MapMetaData info;
00169 gu::ResultPtr navfn;
00170 float max_dist;
00171
00172 };
00173
00174 void Node::run ()
00175 {
00176
00177 while (ros::ok())
00178 {
00179 ros::WallDuration(1.0).sleep();
00180 Lock l(mutex_);
00181 if (map_)
00182 break;
00183 ROS_INFO ("Waiting for map");
00184 }
00185 ROS_INFO("Generating targets and viewpoints");
00186
00187
00188 const gm::Pose pose = getCurrentPose();
00189 const gu::Cell current_cell = gu::pointCell(map_->info, pose.position);
00190
00191
00192 nm::OccupancyGrid::Ptr inflated = gu::inflateObstacles(*map_, robot_radius_);
00193 gu::ResultPtr nav = gu::singleSourceShortestPaths(*inflated, current_cell);
00194 Cells view_positions = gu::tileCells(map_->info, 0.5,
00195 CheckReachable(map_->info, nav, 7));
00196
00197
00198 gu::ResultPtr nav2 = gu::singleSourceShortestPaths(*map_, current_cell);
00199 Cells target_set = gu::tileCells(map_->info, 0.3,
00200 CheckReachable(map_->info, nav2, 7));
00201
00202 {
00203
00204 Lock l(mutex_);
00205 targets_.insert(targets_.end(), target_set.begin(), target_set.end());
00206
00207
00208 for (size_t i=0; i<targets_.size(); i++)
00209 unseen_.insert(i);
00210
00211
00212 const float pi = boost::math::constants::pi<float>();
00213 BOOST_FOREACH (const gu::Cell& pos, view_positions)
00214 {
00215 for (float yaw=0; yaw < 2*pi; yaw+=pi/2)
00216 {
00217 gm::Pose view_pose;
00218 view_pose.position = cellCenter(map_->info, pos);
00219 view_pose.orientation = tf::createQuaternionMsgFromYaw(yaw);
00220 view_poses_.push_back(view_pose);
00221 }
00222 }
00223
00224
00225 ROS_INFO ("Computing visibility relation");
00226 is_visible_.resize(view_poses_.size());
00227 for (size_t i=0; i<view_poses_.size(); i++)
00228 {
00229 const gm::Polygon poly = getVisibleRegion(view_poses_[i]);
00230 is_visible_[i].resize(targets_.size());
00231 Cells visible_positions = gu::cellsInConvexPolygon(map_->info, poly);
00232 for (size_t j=0; j<targets_.size(); j++)
00233 {
00234 if (visible_positions.find(targets_[j])!=visible_positions.end())
00235 {
00236 is_visible_[i][j] = true;
00237 }
00238 }
00239 }
00240
00241 ROS_INFO ("Targets generated");
00242 initialized_ = true;
00243 }
00244
00245
00246
00247 while (ros::ok())
00248 {
00249 boost::optional<size_t> next_goal;
00250 {
00251 Lock l(mutex_);
00252 next_goal = getNextGoal();
00253 if (!next_goal)
00254 {
00255 ROS_INFO ("No more valid goals; terminating");
00256 break;
00257 }
00258 }
00259 ROS_INFO ("Navigating to %zu", *next_goal);
00260 const bool success = navigateWaypoint(*next_goal);
00261 if (success)
00262 ROS_INFO("Navigation succeeded");
00263 else
00264 ROS_INFO("Navigation failed");
00265 forbidden_.insert(*next_goal);
00266 }
00267 }
00268
00269
00270 optional<size_t> Node::getViewpoint (const size_t target)
00271 {
00272 for (size_t i=0; i<view_poses_.size(); i++)
00273 {
00274 if (forbidden_.find(i)==forbidden_.end())
00275 {
00276 if (is_visible_[i][target])
00277 return i;
00278 }
00279 }
00280 return optional<size_t>();
00281 }
00282
00283 optional<size_t> Node::getNextGoal ()
00284 {
00285 optional<size_t> g;
00286 BOOST_FOREACH (const size_t target, unseen_)
00287 {
00288
00289 g = getViewpoint(target);
00290 if (g)
00291 break;
00292 }
00293 return g;
00294 }
00295
00296 bool Node::navigateWaypoint (const size_t wp)
00297 {
00298 mbm::MoveBaseGoal goal;
00299 goal.target_pose.header.frame_id = "/map";
00300 goal.target_pose.header.stamp = ros::Time::now();
00301 goal.target_pose.pose = view_poses_[wp];
00302
00303 al::SimpleClientGoalState state =
00304 mb_client_.sendGoalAndWait(goal, ros::Duration(30.0));
00305 return (state == al::SimpleClientGoalState::StateEnum::SUCCEEDED);
00306 }
00307
00308 gm::Pose Node::getCurrentPose ()
00309 {
00310 while (ros::ok())
00311 {
00312 if (tf_.waitForTransform("map", "base_footprint", ros::Time(),
00313 ros::Duration(1.0)))
00314 break;
00315 ROS_INFO ("Waiting for robot pose");
00316 }
00317 tf::StampedTransform base_transform;
00318 tf_.lookupTransform("map", "base_footprint", ros::Time(), base_transform);
00319 gm::Pose pose;
00320 tf::poseTFToMsg(base_transform, pose);
00321 return pose;
00322
00323 }
00324
00325 gm::Polygon Node::getVisibleRegion (const gm::Pose& p) const
00326 {
00327 vector<btVector3> poly(3);
00328 poly[0] = btVector3(0.5, 1.0, 0.0);
00329 poly[1] = btVector3(2.0, 0.0, 0.0);
00330 poly[2] = btVector3(0.5, -1.0, 0.0);
00331
00332 tf::Pose trans;
00333 tf::poseMsgToTF(p, trans);
00334
00335 gm::Polygon polygon;
00336 BOOST_FOREACH (const btVector3& p, poly)
00337 {
00338 btVector3 p2 = (trans*p).asBt();
00339 gm::Point32 pt;
00340 pt.x = p2.x();
00341 pt.y = p2.y();
00342 pt.z = p2.z();
00343 polygon.points.push_back(pt);
00344 }
00345 return polygon;
00346 }
00347
00348 void Node::updateSeen (const ros::TimerEvent& e)
00349 {
00350 if (!initialized_)
00351 return;
00352
00353 const gm::Pose pose = getCurrentPose();
00354 gm::PolygonStamped visible_region;
00355 visible_region.polygon = getVisibleRegion(pose);
00356 auto visible_cells = gu::cellsInConvexPolygon(map_->info,
00357 visible_region.polygon);
00358 visible_region.header.frame_id = "/map";
00359 visible_region.header.stamp = ros::Time::now();
00360 visible_poly_pub_.publish(visible_region);
00361 Lock l(mutex_);
00362 set<size_t> now_seen;
00363 BOOST_FOREACH (const size_t i, unseen_)
00364 {
00365 if (visible_cells.find(targets_[i])!=visible_cells.end())
00366 now_seen.insert(i);
00367 }
00368
00369 BOOST_FOREACH (const size_t i, now_seen)
00370 {
00371 unseen_.erase(i);
00372 seen_.insert(i);
00373 }
00374 }
00375
00376
00377 void Node::visualize (const ros::WallTimerEvent& e)
00378 {
00379 Lock l(mutex_);
00380 int id=0;
00381 if (targets_.size()==0)
00382 return;
00383
00384 vm::Marker seen;
00385 seen.ns = "search_planes";
00386 seen.header.frame_id = "/map";
00387 seen.id = id++;
00388 seen.type = vm::Marker::SPHERE_LIST;
00389 seen.scale.x = seen.scale.y = seen.scale.z = 0.04;
00390 seen.color.b = seen.color.a = 1.0;
00391
00392 vm::Marker unseen = seen;
00393 unseen.id = id++;
00394 unseen.color.r = 1.0;
00395 unseen.color.b = 0.0;
00396
00397 BOOST_FOREACH (const size_t i, seen_)
00398 seen.points.push_back(cellCenter(map_->info, targets_[i]));
00399 vis_pub_.publish(seen);
00400
00401 BOOST_FOREACH (const size_t i, unseen_)
00402 unseen.points.push_back(cellCenter(map_->info, targets_[i]));
00403 vis_pub_.publish(unseen);
00404
00405
00406 for (size_t i=0; i<view_poses_.size(); i++)
00407 {
00408 if (forbidden_.find(i)!=forbidden_.end())
00409 continue;
00410
00411 vm::Marker m;
00412 m.ns = "search_planes";
00413 m.header.frame_id = "/map";
00414 m.id = id++;
00415 m.type = vm::Marker::ARROW;
00416 m.scale.x = 0.7;
00417 m.scale.z = m.scale.z = 0.5;
00418 m.color.g = m.color.a = 1.0;
00419 m.pose = view_poses_[i];
00420 vis_pub_.publish(m);
00421 }
00422 }
00423
00424
00425 }
00426
00427 int main (int argc, char** argv)
00428 {
00429 ros::init(argc, argv, "search_for_planes");
00430 semanticmodel::Node node;
00431 ros::AsyncSpinner spinner(2);
00432 spinner.start();
00433 node.run();
00434 return 0;
00435 }