1 #include <nav2d_operator/cmd.h> 2 #include <nav_msgs/GridCells.h> 3 #include <visualization_msgs/Marker.h> 21 std::string serviceName;
22 robotNode.
param(
"map_service", serviceName, std::string(
"get_map"));
23 mGetMapClient = robotNode.
serviceClient<nav_msgs::GetMap>(serviceName);
25 mCommandPublisher = robotNode.
advertise<nav2d_operator::cmd>(
"cmd", 1);
31 mPlanPublisher = navigatorNode.
advertise<nav_msgs::GridCells>(
"plan", 1);
32 mMarkerPublisher = navigatorNode.
advertise<visualization_msgs::Marker>(
"markers", 1,
true);
35 navigatorNode.
param(
"map_inflation_radius", mInflationRadius, 1.0);
36 navigatorNode.
param(
"robot_radius", mRobotRadius, 0.3);
37 navigatorNode.
param(
"exploration_strategy", mExplorationStrategy, std::string(
"NearestFrontierPlanner"));
38 navigatorNode.
param(
"navigation_goal_distance", mNavigationGoalDistance, 1.0);
39 navigatorNode.
param(
"navigation_goal_angle", mNavigationGoalAngle, 1.0);
40 navigatorNode.
param(
"exploration_goal_distance", mExplorationGoalDistance, 3.0);
41 navigatorNode.
param(
"navigation_homing_distance", mNavigationHomingDistance, 3.0);
42 navigatorNode.
param(
"min_replanning_period", mMinReplanningPeriod, 3.0);
43 navigatorNode.
param(
"max_replanning_period", mMaxReplanningPeriod, 1.0);
45 mCostLethal = (1.0 - (mRobotRadius / mInflationRadius)) * (double)mCostObstacle;
47 robotNode.
param(
"map_frame", mMapFrame, std::string(
"map"));
48 robotNode.
param(
"robot_frame", mRobotFrame, std::string(
"robot"));
49 robotNode.
param(
"robot_id", mRobotID, 1);
56 mRobotFrame = mTfListener.resolve(mRobotFrame);
57 mMapFrame = mTfListener.resolve(mMapFrame);
61 mPlanLoader =
new PlanLoader(
"nav2d_navigator",
"ExplorationPlanner");
62 mExplorationPlanner = mPlanLoader->createInstance(mExplorationStrategy);
63 ROS_INFO(
"Successfully loaded exploration strategy [%s].", mExplorationStrategy.c_str());
66 mExploreActionServer->start();
70 ROS_ERROR(
"Failed to load exploration plugin! Error: %s", ex.what());
71 mExploreActionServer = NULL;
77 mMoveActionServer->start();
80 mLocalizeActionServer->start();
85 mGetMapActionServer->start();
88 mGetMapActionServer = NULL;
95 mCellInflationRadius = 0;
100 delete[] mCurrentPlan;
101 delete mMoveActionServer;
102 delete mExploreActionServer;
103 delete mGetMapActionServer;
104 mExplorationPlanner.reset();
110 if(mHasNewMap)
return true;
112 if(!mGetMapClient.isValid())
118 nav_msgs::GetMap srv;
119 if(!mGetMapClient.call(srv))
124 mCurrentMap.update(srv.response.map);
126 if(mCurrentPlan)
delete[] mCurrentPlan;
127 mCurrentPlan =
new double[mCurrentMap.getSize()];
129 if(mCellInflationRadius == 0)
131 ROS_INFO(
"Navigator is now initialized.");
132 mCellInflationRadius = mInflationRadius / mCurrentMap.getResolution();
133 mCellRobotRadius = mRobotRadius / mCurrentMap.getResolution();
134 mInflationTool.computeCaches(mCellInflationRadius);
135 mCurrentMap.setLethalCost(mCostLethal);
146 res.message =
"Navigator received stop signal.";
156 res.message =
"Navigator continues.";
160 nav2d_operator::cmd stopMsg;
162 stopMsg.Velocity = 0;
163 mCommandPublisher.publish(stopMsg);
165 res.message =
"Navigator pauses.";
170 typedef std::multimap<double,unsigned int>
Queue;
171 typedef std::pair<double,unsigned int>
Entry;
178 if(mCellInflationRadius == 0)
return false;
179 ROS_WARN(
"Could not get a new map, trying to go with the old one...");
183 if(!setCurrentPosition())
return false;
186 unsigned int x = 0,
y = 0;
187 if(mCurrentMap.getCoordinates(x,
y, mStartPoint))
188 for(
int i = -mCellRobotRadius; i < (int)mCellRobotRadius; i++)
189 for(
int j = -mCellRobotRadius; j < (int)mCellRobotRadius; j++)
190 mCurrentMap.setData(x+i,
y+j, 0);
192 mInflationTool.inflateMap(&mCurrentMap);
198 ROS_DEBUG(
"Map-Value of goal point is %d, lethal threshold is %d.", mCurrentMap.getData(mGoalPoint), mCostLethal);
200 unsigned int goal_x = 0, goal_y = 0;
201 if(mCurrentMap.getCoordinates(goal_x,goal_y,mGoalPoint))
203 visualization_msgs::Marker marker;
204 marker.header.frame_id =
"/map";
207 marker.type = visualization_msgs::Marker::CYLINDER;
208 marker.action = visualization_msgs::Marker::ADD;
209 marker.pose.position.x = mCurrentMap.getOriginX() + (((double)goal_x+0.5) * mCurrentMap.getResolution());
210 marker.pose.position.y = mCurrentMap.getOriginY() + (((double)goal_y+0.5) * mCurrentMap.getResolution());
211 marker.pose.position.z = 0.5;
212 marker.pose.orientation.x = 0.0;
213 marker.pose.orientation.y = 0.0;
214 marker.pose.orientation.z = 0.0;
215 marker.pose.orientation.w = 1.0;
216 marker.scale.x = mCurrentMap.getResolution() * 3.0;
217 marker.scale.y = mCurrentMap.getResolution() * 3.0;
218 marker.scale.z = 1.0;
219 marker.color.a = 1.0;
220 marker.color.r = 1.0;
221 marker.color.g = 0.0;
222 marker.color.b = 0.0;
223 mMarkerPublisher.publish(marker);
226 ROS_ERROR(
"Couldn't ressolve goal point coordinates!");
232 int mapSize = mCurrentMap.getSize();
233 for(
int i = 0; i < mapSize; i++)
235 mCurrentPlan[i] = -1;
238 if(mCurrentMap.isFree(mGoalPoint))
240 queue.insert(
Entry(0.0, mGoalPoint));
241 mCurrentPlan[mGoalPoint] = 0;
245 int reach = mCellRobotRadius + (1.0 / mCurrentMap.getResolution());
246 std::vector<unsigned int> neighbors = mCurrentMap.getFreeNeighbors(mGoalPoint, reach);
247 for(
unsigned int i = 0; i < neighbors.size(); i++)
249 queue.insert(
Entry(0.0, neighbors[i]));
250 mCurrentPlan[neighbors[i]] = 0;
254 Queue::iterator next;
256 unsigned int x,
y, index;
257 double linear = mCurrentMap.getResolution();
258 double diagonal = std::sqrt(2.0) * linear;
261 while(!queue.empty())
264 next = queue.begin();
265 distance = next->first;
266 index = next->second;
269 if(mCurrentPlan[index] >= 0 && mCurrentPlan[index] < distance)
continue;
274 if(!mCurrentMap.getCoordinates(x, y, index))
continue;
275 std::vector<unsigned int> ind;
276 ind.push_back(index - 1);
277 ind.push_back(index + 1);
278 ind.push_back(index - mCurrentMap.getWidth());
279 ind.push_back(index + mCurrentMap.getWidth());
280 ind.push_back(index - mCurrentMap.getWidth() - 1);
281 ind.push_back(index - mCurrentMap.getWidth() + 1);
282 ind.push_back(index + mCurrentMap.getWidth() - 1);
283 ind.push_back(index + mCurrentMap.getWidth() + 1);
285 for(
unsigned int it = 0; it < ind.size(); it++)
287 unsigned int i = ind[it];
288 if(mCurrentMap.isFree(i))
290 double delta = (it < 4) ? linear : diagonal;
291 double newDistance = distance + delta + (10 * delta * (double)mCurrentMap.getData(i) / (double)mCostObstacle);
292 if(mCurrentPlan[i] == -1 || newDistance < mCurrentPlan[i])
294 queue.insert(
Entry(newDistance, i));
295 mCurrentPlan[i] = newDistance;
301 if(mCurrentPlan[mStartPoint] < 0)
303 ROS_ERROR(
"No way between robot and goal!");
313 nav_msgs::GridCells plan_msg;
314 plan_msg.header.frame_id = mMapFrame.c_str();
317 plan_msg.cell_width = mCurrentMap.getResolution();
318 plan_msg.cell_height = mCurrentMap.getResolution();
320 unsigned int index = mStartPoint;
321 std::vector<std::pair<double, double> > points;
324 unsigned int x = 0,
y = 0;
325 if(mCurrentMap.getCoordinates(x,
y,index))
326 points.push_back(std::pair<double, double>(
327 ((x+0.5) * mCurrentMap.getResolution()) + mCurrentMap.getOriginX(),
328 ((
y+0.5) * mCurrentMap.getResolution()) + mCurrentMap.getOriginY()
331 if(mCurrentPlan[index] == 0)
break;
333 unsigned int next_index = index;
335 std::vector<unsigned int> neighbors = mCurrentMap.getFreeNeighbors(index);
336 for(
unsigned int i = 0; i < neighbors.size(); i++)
338 if(mCurrentPlan[neighbors[i]] >= 0 && mCurrentPlan[neighbors[i]] < mCurrentPlan[next_index])
339 next_index = neighbors[i];
342 if(index == next_index)
break;
346 plan_msg.cells.resize(points.size());
347 for(
unsigned int i = 0; i < points.size(); i++)
349 plan_msg.cells[i].x = points[i].first;
350 plan_msg.cells[i].y = points[i].second;
351 plan_msg.cells[i].z = 0.0;
353 mPlanPublisher.publish(plan_msg);
359 int mapSize = mCurrentMap.getSize();
360 for(
int i = 0; i < mapSize; i++)
362 mCurrentPlan[i] = -1;
367 Entry goal(0.0, mGoalPoint);
369 mCurrentPlan[mGoalPoint] = 0;
371 Queue::iterator next;
372 double linear = mCurrentMap.getResolution();
375 while(!queue.empty())
378 next = queue.begin();
380 unsigned int index = next->second;
383 if(mCurrentPlan[index] >= 0 && mCurrentPlan[index] < distance)
continue;
386 std::vector<unsigned int> neighbors = mCurrentMap.getNeighbors(index);
387 for(
unsigned int i = 0; i < neighbors.size(); i++)
389 if(mCurrentMap.isFree(neighbors[i]))
391 mGoalPoint = neighbors[i];
395 double newDistance = distance + linear;
396 if(mCurrentPlan[neighbors[i]] == -1)
398 queue.insert(
Entry(newDistance, neighbors[i]));
399 mCurrentPlan[neighbors[i]] = newDistance;
409 nav2d_operator::cmd stopMsg;
411 stopMsg.Velocity = 0;
412 mCommandPublisher.publish(stopMsg);
429 ROS_WARN_THROTTLE(1.0,
"Navigator has status %d when generateCommand() was called!", mStatus);
434 unsigned int current_x = 0, current_y = 0;
435 if(!mCurrentMap.getCoordinates(current_x, current_y, mStartPoint))
437 ROS_ERROR(
"Plan execution failed, robot not in map!");
441 unsigned int target = mStartPoint;
442 int steps = 1.0 / mCurrentMap.getResolution();
443 for(
int i = 0; i < steps; i++)
445 unsigned int bestPoint = target;
446 std::vector<unsigned int> neighbors = mCurrentMap.getFreeNeighbors(target);
447 for(
unsigned int i = 0; i < neighbors.size(); i++)
449 if(mCurrentPlan[neighbors[i]] >= (
unsigned int)0 && mCurrentPlan[neighbors[i]] < mCurrentPlan[bestPoint])
450 bestPoint = neighbors[i];
456 unsigned int x = 0,
y = 0;
457 if(!mCurrentMap.getCoordinates(x,
y, target))
459 ROS_ERROR(
"Plan execution failed, target pose not in map!");
462 double map_angle = atan2((
double)
y - current_y, (
double)x - current_x);
464 double angle = map_angle - mCurrentDirection;
465 if(angle < -
PI) angle += 2*
PI;
466 if(angle >
PI) angle -= 2*
PI;
469 nav2d_operator::cmd msg;
470 msg.Turn = -2.0 * angle /
PI;
471 if(msg.Turn < -1) msg.Turn = -1;
472 if(msg.Turn > 1) msg.Turn = 1;
474 if(mCurrentPlan[mStartPoint] > mNavigationHomingDistance || mStatus ==
NAV_ST_EXPLORING)
479 if(mCurrentPlan[mStartPoint] > 1.0 || mCurrentPlan[mStartPoint] < 0)
484 msg.Velocity = 0.5 + (mCurrentPlan[mStartPoint] / 2.0);
486 mCommandPublisher.publish(msg);
495 mGetMapActionServer->setAborted();
501 nav2d_operator::cmd msg;
506 nav2d_navigator::GetFirstMapFeedback
f;
509 unsigned int cycles = 0;
512 if(!
ok() || mGetMapActionServer->isPreemptRequested() || mIsStopped)
514 ROS_INFO(
"GetFirstMap has been preempted externally.");
515 mGetMapActionServer->setPreempted();
523 mGetMapActionServer->publishFeedback(f);
524 mCommandPublisher.publish(msg);
529 if(!getMap() || !setCurrentPosition())
531 mGetMapActionServer->setAborted();
539 double lastDirection = mCurrentDirection;
543 if(!
ok() || mGetMapActionServer->isPreemptRequested() || mIsStopped)
545 ROS_INFO(
"GetFirstMap has been preempted externally.");
546 mGetMapActionServer->setPreempted();
551 setCurrentPosition();
552 double deltaTheta = mCurrentDirection - lastDirection;
553 while(deltaTheta < -
PI) deltaTheta += 2*
PI;
554 while(deltaTheta >
PI) deltaTheta -= 2*
PI;
556 lastDirection = mCurrentDirection;
557 if(turn > 2*
PI || turn < -2*
PI)
562 mGetMapActionServer->publishFeedback(f);
563 mCommandPublisher.publish(msg);
571 if(getMap() && setCurrentPosition())
573 mGetMapActionServer->setSucceeded();
576 ROS_WARN(
"Navigator could not be initialized!");
577 mGetMapActionServer->setAborted();
585 ROS_WARN(
"[Localize] Action aborted, Navigator is busy!");
586 mGetMapActionServer->setAborted();
592 nav2d_operator::cmd msg;
594 msg.Velocity = goal->velocity;
597 nav2d_navigator::LocalizeFeedback
f;
604 if(!
ok() || mLocalizeActionServer->isPreemptRequested() || mIsStopped)
606 ROS_INFO(
"[Localize] Action has been preempted externally.");
607 mLocalizeActionServer->setPreempted();
614 mCommandPublisher.publish(msg);
623 ROS_INFO(
"[Localize] Action succeeded.");
624 mLocalizeActionServer->setSucceeded();
629 mLocalizeActionServer->publishFeedback(f);
640 mMoveActionServer->setAborted();
644 ROS_DEBUG(
"Received Goal: %.2f, %.2f (in frame '%s')", goal->target_pose.x, goal->target_pose.y, goal->header.frame_id.c_str());
648 unsigned int cycle = 0;
649 bool reached =
false;
650 int recheckCycles = mMinReplanningPeriod *
FREQUENCY;
652 double targetDistance = (goal->target_distance > 0) ? goal->target_distance : mNavigationGoalDistance;
653 double targetAngle = (goal->target_angle > 0) ? goal->target_angle : mNavigationGoalAngle;
658 if(!
ok() || mMoveActionServer->isPreemptRequested() || mIsStopped)
660 ROS_INFO(
"Navigation has been preempted externally.");
661 mMoveActionServer->setPreempted();
667 if(cycle % recheckCycles == 0)
677 mMoveActionServer->setAborted();
682 int mapX = (double)(goal->target_pose.x - mCurrentMap.getOriginX()) / mCurrentMap.getResolution();
683 int mapY = (double)(goal->target_pose.y - mCurrentMap.getOriginY()) / mCurrentMap.getResolution();
684 if(mapX < 0) mapX = 0;
685 if(mapX >= (
int)mCurrentMap.getWidth()) mapX = mCurrentMap.getWidth() - 1;
686 if(mapY < 0) mapY = 0;
687 if(mapY >= (
int)mCurrentMap.getHeight()) mapY = mCurrentMap.getHeight() - 1;
689 bool success =
false;
690 if(mCurrentMap.getIndex(mapX, mapY, mGoalPoint))
691 success = createPlan();
695 if(correctGoalPose())
696 success = createPlan();
702 mMoveActionServer->setAborted();
709 ROS_INFO(
"Path planning took %.09f seconds, distance is %.2f m.", d.
toSec(), mCurrentPlan[mStartPoint]);
714 if(!setCurrentPosition())
716 ROS_ERROR(
"Navigation failed, could not get current position.");
717 mMoveActionServer->setAborted();
723 if(!reached && mCurrentPlan[mStartPoint] <= targetDistance && mCurrentPlan[mStartPoint] >= 0)
725 ROS_INFO(
"Reached target, now turning to desired direction.");
732 double deltaTheta = mCurrentDirection - goal->target_pose.theta;
733 while(deltaTheta < -
PI) deltaTheta += 2*
PI;
734 while(deltaTheta >
PI) deltaTheta -= 2*
PI;
736 double diff = (deltaTheta > 0) ? deltaTheta : -deltaTheta;
737 ROS_INFO_THROTTLE(1.0,
"Heading: %.2f / Desired: %.2f / Difference: %.2f / Tolerance: %.2f", mCurrentDirection, goal->target_pose.theta, diff, targetAngle);
738 if(diff <= targetAngle)
740 ROS_INFO(
"Final Heading: %.2f / Desired: %.2f / Difference: %.2f / Tolerance: %.2f", mCurrentDirection, goal->target_pose.theta, diff, targetAngle);
744 nav2d_operator::cmd msg;
748 msg.Velocity = deltaTheta;
752 msg.Velocity = -deltaTheta;
754 if(msg.Velocity > 1) msg.Velocity = 1;
757 mCommandPublisher.publish(msg);
766 nav2d_navigator::MoveToPosition2DFeedback fb;
767 fb.distance = mCurrentPlan[mStartPoint];
768 mMoveActionServer->publishFeedback(fb);
776 ROS_WARN(
"Missed desired rate of %.2fHz! Loop actually took %.4f seconds!",FREQUENCY, loopRate.cycleTime().toSec());
781 nav2d_navigator::MoveToPosition2DResult r;
782 r.final_pose.x = mCurrentPositionX;
783 r.final_pose.y = mCurrentPositionY;
784 r.final_pose.theta = mCurrentDirection;
785 r.final_distance = mCurrentPlan[mStartPoint];
786 mMoveActionServer->setSucceeded(r);
796 mExploreActionServer->setAborted();
801 unsigned int cycle = 0;
802 unsigned int lastCheck = 0;
803 unsigned int recheckCycles = mMinReplanningPeriod *
FREQUENCY;
804 unsigned int recheckThrottle = mMaxReplanningPeriod *
FREQUENCY;
807 Rate loopRate(FREQUENCY);
811 if(!
ok() || mExploreActionServer->isPreemptRequested() || mIsStopped)
813 ROS_INFO(
"Exploration has been preempted externally.");
814 mExploreActionServer->setPreempted();
821 if(!setCurrentPosition())
823 ROS_ERROR(
"Exploration failed, could not get current position.");
824 mExploreActionServer->setAborted();
831 bool reCheck = lastCheck == 0 || cycle - lastCheck > recheckCycles;
832 bool planOk = mCurrentPlan && mCurrentPlan[mStartPoint] >= 0;
833 bool nearGoal = planOk && ((cycle - lastCheck) > recheckThrottle && mCurrentPlan[mStartPoint] <= mExplorationGoalDistance);
835 if(reCheck || nearGoal)
840 bool success =
false;
843 int result = mExplorationPlanner->findExplorationTarget(&mCurrentMap, mStartPoint, mGoalPoint);
847 success = createPlan();
852 nav2d_navigator::ExploreResult r;
853 r.final_pose.x = mCurrentPositionX;
854 r.final_pose.y = mCurrentPositionY;
855 r.final_pose.theta = mCurrentDirection;
856 mExploreActionServer->setSucceeded(r);
859 ROS_INFO(
"Exploration has finished.");
864 nav2d_operator::cmd stopMsg;
866 stopMsg.Velocity = 0;
867 mCommandPublisher.publish(stopMsg);
869 ROS_INFO(
"Exploration is waiting.");
874 ROS_ERROR(
"Exploration planner returned invalid status code: %d!", result);
884 ROS_DEBUG(
"Exploration planning took %.09f seconds, distance is %.2f m.", d.
toSec(), mCurrentPlan[mStartPoint]);
887 mExploreActionServer->setAborted();
889 ROS_WARN(
"Exploration has failed!");
900 nav2d_navigator::ExploreFeedback fb;
901 fb.distance = mCurrentPlan[mStartPoint];
902 fb.robot_pose.x = mCurrentPositionX;
903 fb.robot_pose.y = mCurrentPositionY;
904 fb.robot_pose.theta = mCurrentDirection;
905 mExploreActionServer->publishFeedback(fb);
916 ROS_WARN(
"Missed desired rate of %.2fHz! Loop actually took %.4f seconds!",FREQUENCY, loopRate.
cycleTime().
toSec());
922 return mTfListener.waitForTransform(mMapFrame, mRobotFrame,
Time::now(),
Duration(0.1));
930 mTfListener.lookupTransform(mMapFrame, mRobotFrame,
Time(0), transform);
933 ROS_ERROR(
"Could not get robot position: %s", ex.what());
940 unsigned int current_x = (world_x - mCurrentMap.getOriginX()) / mCurrentMap.getResolution();
941 unsigned int current_y = (world_y - mCurrentMap.getOriginY()) / mCurrentMap.getResolution();
944 if(!mCurrentMap.getIndex(current_x, current_y, i))
946 if(mHasNewMap || !getMap() || !mCurrentMap.getIndex(current_x, current_y, i))
948 ROS_ERROR(
"Is the robot out of the map?");
953 mCurrentDirection = world_theta;
954 mCurrentPositionX = world_x;
955 mCurrentPositionY = world_y;
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
bool receiveStop(std_srvs::Trigger::Request &req, std_srvs::Trigger::Response &res)
#define NAV_PAUSE_SERVICE
#define ROS_WARN_THROTTLE(rate,...)
void receiveExploreGoal(const nav2d_navigator::ExploreGoal::ConstPtr &goal)
std::pair< double, unsigned int > Entry
Duration cycleTime() const
#define NAV_ST_NAVIGATING
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
TFSIMD_FORCE_INLINE const tfScalar & y() const
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
#define NAV_LOCALIZE_ACTION
std::multimap< double, unsigned int > Queue
TFSIMD_FORCE_INLINE const tfScalar & x() const
pluginlib::ClassLoader< ExplorationPlanner > PlanLoader
bool setCurrentPosition()
double distance(double x0, double y0, double x1, double y1)
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
actionlib::SimpleActionServer< nav2d_navigator::ExploreAction > ExploreActionServer
void receiveGetMapGoal(const nav2d_navigator::GetFirstMapGoal::ConstPtr &goal)
#define NAV_GETMAP_ACTION
TFSIMD_FORCE_INLINE const tfScalar & y() const
TFSIMD_FORCE_INLINE const tfScalar & x() const
double getYaw(const tf2::Quaternion &q)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void receiveLocalizeGoal(const nav2d_navigator::LocalizeGoal::ConstPtr &goal)
void receiveMoveGoal(const nav2d_navigator::MoveToPosition2DGoal::ConstPtr &goal)
actionlib::SimpleActionServer< nav2d_navigator::GetFirstMapAction > GetMapActionServer
double diff(double v1, double v2)
#define ROS_INFO_THROTTLE(rate,...)
#define NAV_ST_RECOVERING
bool receivePause(std_srvs::Trigger::Request &req, std_srvs::Trigger::Response &res)
actionlib::SimpleActionServer< nav2d_navigator::LocalizeAction > LocalizeActionServer
ROSCPP_DECL void spinOnce()
actionlib::SimpleActionServer< nav2d_navigator::MoveToPosition2DAction > MoveActionServer
#define NAV_EXPLORE_ACTION