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 #include <ros/ros.h>
00034
00035 #include <sensor_msgs/LaserScan.h>
00036 #include <sensor_msgs/PointCloud.h>
00037 #include <geometry_msgs/PoseStamped.h>
00038 #include <geometry_msgs/Polygon.h>
00039 #include <nav_msgs/Odometry.h>
00040 #include <tf/transform_listener.h>
00041
00042 #include <mrpt/version.h>
00043
00044
00045 #include <mrpt/nav/reactive/CReactiveNavigationSystem.h>
00046 #include <mrpt/maps/CSimplePointsMap.h>
00047 using namespace mrpt::nav;
00048 using mrpt::maps::CSimplePointsMap;
00049
00050 #include <mrpt/version.h>
00051 #if MRPT_VERSION >= 0x199
00052 #include <mrpt/system/CTimeLogger.h>
00053 #include <mrpt/config/CConfigFileMemory.h>
00054 #include <mrpt/config/CConfigFile.h>
00055 using namespace mrpt::system;
00056 using namespace mrpt::config;
00057 #else
00058 #include <mrpt/utils/CTimeLogger.h>
00059 #include <mrpt/utils/CConfigFileMemory.h>
00060 #include <mrpt/utils/CConfigFile.h>
00061 using namespace mrpt::utils;
00062 #endif
00063
00064 #include <mrpt/system/filesystem.h>
00065
00066 #include <mrpt_bridge/pose.h>
00067 #include <mrpt_bridge/point_cloud.h>
00068 #include <mrpt_bridge/time.h>
00069
00070 #include <mrpt/kinematics/CVehicleVelCmd_DiffDriven.h>
00071
00072 #include <mutex>
00073
00074
00075 class ReactiveNav2DNode
00076 {
00077 private:
00078 struct TAuxInitializer
00079 {
00080 TAuxInitializer(int argc, char** argv)
00081 {
00082 ros::init(argc, argv, "mrpt_reactivenav2d");
00083 }
00084 };
00085
00086 CTimeLogger m_profiler;
00087 TAuxInitializer m_auxinit;
00088 ros::NodeHandle m_nh;
00089 ros::NodeHandle m_localn;
00090
00093 ros::Subscriber m_sub_nav_goal;
00094 ros::Subscriber m_sub_local_obs;
00095 ros::Subscriber m_sub_robot_shape;
00096 ros::Publisher m_pub_cmd_vel;
00097 tf::TransformListener m_tf_listener;
00098
00100 bool m_1st_time_init;
00101 double m_target_allowed_distance;
00102 double m_nav_period;
00103
00104 std::string m_pub_topic_reactive_nav_goal;
00105 std::string m_sub_topic_local_obstacles;
00106 std::string m_sub_topic_robot_shape;
00107
00108 std::string m_frameid_reference;
00109 std::string m_frameid_robot;
00110
00111 bool m_save_nav_log;
00112
00113 ros::Timer m_timer_run_nav;
00114
00115 CSimplePointsMap m_last_obstacles;
00116 std::mutex m_last_obstacles_cs;
00117
00118 struct MyReactiveInterface :
00119
00120 public mrpt::nav::CRobot2NavInterface
00121 {
00122 ReactiveNav2DNode& m_parent;
00123
00124 MyReactiveInterface(ReactiveNav2DNode& parent) : m_parent(parent) {}
00131 bool getCurrentPoseAndSpeeds(
00132 mrpt::math::TPose2D& curPose, mrpt::math::TTwist2D& curVel,
00133 mrpt::system::TTimeStamp& timestamp,
00134 mrpt::math::TPose2D& curOdometry, std::string& frame_id) override
00135 {
00136 double curV, curW;
00137
00138 CTimeLoggerEntry tle(
00139 m_parent.m_profiler, "getCurrentPoseAndSpeeds");
00140 tf::StampedTransform txRobotPose;
00141 try
00142 {
00143 CTimeLoggerEntry tle2(
00144 m_parent.m_profiler,
00145 "getCurrentPoseAndSpeeds.lookupTransform_sensor");
00146 m_parent.m_tf_listener.lookupTransform(
00147 m_parent.m_frameid_reference, m_parent.m_frameid_robot,
00148 ros::Time(0), txRobotPose);
00149 }
00150 catch (tf::TransformException& ex)
00151 {
00152 ROS_ERROR("%s", ex.what());
00153 return false;
00154 }
00155
00156 mrpt::poses::CPose3D curRobotPose;
00157 mrpt_bridge::convert(txRobotPose, curRobotPose);
00158
00159 mrpt_bridge::convert(txRobotPose.stamp_, timestamp);
00160
00161 curPose =
00162 #if MRPT_VERSION >= 0x199
00163 mrpt::poses::CPose2D(curRobotPose).asTPose();
00164 #else
00165 mrpt::math::TPose2D(mrpt::poses::CPose2D(curRobotPose));
00166 #endif
00167 curOdometry = curPose;
00168
00169 curV = curW = 0;
00170 MRPT_TODO("Retrieve current speeds from odometry");
00171 ROS_DEBUG(
00172 "[getCurrentPoseAndSpeeds] Latest pose: %s",
00173 curPose.asString().c_str());
00174
00175 curVel.vx = curV * cos(curPose.phi);
00176 curVel.vy = curV * sin(curPose.phi);
00177 curVel.omega = curW;
00178
00179 return true;
00180 }
00181
00187 bool changeSpeeds(
00188 const mrpt::kinematics::CVehicleVelCmd& vel_cmd) override
00189 {
00190 using namespace mrpt::kinematics;
00191 const CVehicleVelCmd_DiffDriven* vel_cmd_diff_driven =
00192 dynamic_cast<const CVehicleVelCmd_DiffDriven*>(&vel_cmd);
00193 ASSERT_(vel_cmd_diff_driven);
00194
00195 const double v = vel_cmd_diff_driven->lin_vel;
00196 const double w = vel_cmd_diff_driven->ang_vel;
00197 ROS_DEBUG(
00198 "changeSpeeds: v=%7.4f m/s w=%8.3f deg/s", v,
00199 w * 180.0f / M_PI);
00200 geometry_msgs::Twist cmd;
00201 cmd.linear.x = v;
00202 cmd.angular.z = w;
00203 m_parent.m_pub_cmd_vel.publish(cmd);
00204 return true;
00205 }
00206
00207 bool stop(bool isEmergency) override
00208 {
00209 mrpt::kinematics::CVehicleVelCmd_DiffDriven vel_cmd;
00210 vel_cmd.lin_vel = 0;
00211 vel_cmd.ang_vel = 0;
00212 return changeSpeeds(vel_cmd);
00213 }
00214
00218 virtual bool startWatchdog(float T_ms) override { return true; }
00221 virtual bool stopWatchdog() override { return true; }
00224 bool senseObstacles(
00225 CSimplePointsMap& obstacles,
00226 mrpt::system::TTimeStamp& timestamp) override
00227 {
00228 timestamp = mrpt::system::now();
00229 std::lock_guard<std::mutex> csl(m_parent.m_last_obstacles_cs);
00230 obstacles = m_parent.m_last_obstacles;
00231
00232 MRPT_TODO("TODO: Check age of obstacles!");
00233 return true;
00234 }
00235
00236 mrpt::kinematics::CVehicleVelCmd::Ptr getEmergencyStopCmd() override
00237 {
00238 return getStopCmd();
00239 }
00240 mrpt::kinematics::CVehicleVelCmd::Ptr getStopCmd() override
00241 {
00242 mrpt::kinematics::CVehicleVelCmd::Ptr ret =
00243 mrpt::kinematics::CVehicleVelCmd::Ptr(
00244 new mrpt::kinematics::CVehicleVelCmd_DiffDriven);
00245 ret->setToStop();
00246 return ret;
00247 }
00248
00249 virtual void sendNavigationStartEvent() {}
00250 virtual void sendNavigationEndEvent() {}
00251 virtual void sendNavigationEndDueToErrorEvent() {}
00252 virtual void sendWaySeemsBlockedEvent() {}
00253 };
00254
00255 MyReactiveInterface m_reactive_if;
00256
00257 CReactiveNavigationSystem m_reactive_nav_engine;
00258 std::mutex m_reactive_nav_engine_cs;
00259
00260 public:
00262 ReactiveNav2DNode(int argc, char** argv)
00263 : m_auxinit(argc, argv),
00264 m_nh(),
00265 m_localn("~"),
00266 m_1st_time_init(false),
00267 m_target_allowed_distance(0.40f),
00268 m_nav_period(0.100),
00269 m_pub_topic_reactive_nav_goal("reactive_nav_goal"),
00270 m_sub_topic_local_obstacles("local_map_pointcloud"),
00271 m_sub_topic_robot_shape(""),
00272 m_frameid_reference("/map"),
00273 m_frameid_robot("base_link"),
00274 m_save_nav_log(false),
00275 m_reactive_if(*this),
00276 m_reactive_nav_engine(m_reactive_if)
00277 {
00278
00279 std::string cfg_file_reactive;
00280 m_localn.param(
00281 "cfg_file_reactive", cfg_file_reactive, cfg_file_reactive);
00282 m_localn.param(
00283 "target_allowed_distance", m_target_allowed_distance,
00284 m_target_allowed_distance);
00285 m_localn.param("nav_period", m_nav_period, m_nav_period);
00286 m_localn.param(
00287 "frameid_reference", m_frameid_reference, m_frameid_reference);
00288 m_localn.param("frameid_robot", m_frameid_robot, m_frameid_robot);
00289 m_localn.param(
00290 "topic_robot_shape", m_sub_topic_robot_shape,
00291 m_sub_topic_robot_shape);
00292 m_localn.param("save_nav_log", m_save_nav_log, m_save_nav_log);
00293
00294 ROS_ASSERT(m_nav_period > 0);
00295 ROS_ASSERT_MSG(
00296 !cfg_file_reactive.empty(),
00297 "Mandatory param 'cfg_file_reactive' is missing!");
00298 ROS_ASSERT_MSG(
00299 mrpt::system::fileExists(cfg_file_reactive),
00300 "Config file not found: '%s'", cfg_file_reactive.c_str());
00301
00302 m_reactive_nav_engine.enableLogFile(m_save_nav_log);
00303
00304
00305
00306 try
00307 {
00308 CConfigFile cfgFil(cfg_file_reactive);
00309 m_reactive_nav_engine.loadConfigFile(cfgFil);
00310 }
00311 catch (std::exception& e)
00312 {
00313 ROS_ERROR(
00314 "Exception initializing reactive navigation engine:\n%s",
00315 e.what());
00316 throw;
00317 }
00318
00319
00320
00321
00322
00323
00324
00325 if (!m_sub_topic_robot_shape.empty())
00326 {
00327 m_sub_robot_shape = m_nh.subscribe<geometry_msgs::Polygon>(
00328 m_sub_topic_robot_shape, 1,
00329 &ReactiveNav2DNode::onRosSetRobotShape, this);
00330 ROS_INFO(
00331 "Params say robot shape will arrive via topic '%s'... waiting "
00332 "3 seconds for it.",
00333 m_sub_topic_robot_shape.c_str());
00334 ros::Duration(3.0).sleep();
00335 for (size_t i = 0; i < 100; i++) ros::spinOnce();
00336 ROS_INFO("Wait done.");
00337 }
00338
00339
00340
00341 m_pub_cmd_vel = m_nh.advertise<geometry_msgs::Twist>("cmd_vel", 1);
00342
00343
00344
00345
00346
00347 m_sub_nav_goal = m_nh.subscribe<geometry_msgs::PoseStamped>(
00348 m_pub_topic_reactive_nav_goal, 1,
00349 &ReactiveNav2DNode::onRosGoalReceived, this);
00350 m_sub_local_obs = m_nh.subscribe<sensor_msgs::PointCloud>(
00351 m_sub_topic_local_obstacles, 1,
00352 &ReactiveNav2DNode::onRosLocalObstacles, this);
00353
00354
00355
00356 m_timer_run_nav = m_nh.createTimer(
00357 ros::Duration(m_nav_period), &ReactiveNav2DNode::onDoNavigation,
00358 this);
00359
00360 }
00361
00366 void navigateTo(const mrpt::math::TPose2D& target)
00367 {
00368 ROS_INFO(
00369 "[navigateTo] Starting navigation to %s",
00370 target.asString().c_str());
00371
00372 CAbstractPTGBasedReactive::TNavigationParamsPTG navParams;
00373 CAbstractNavigator::TargetInfo target_info;
00374 target_info.target_coords.x = target.x;
00375 target_info.target_coords.y = target.y;
00376 target_info.targetAllowedDistance = m_target_allowed_distance;
00377 target_info.targetIsRelative = false;
00378
00379 navParams.multiple_targets.push_back(target_info);
00380
00381
00382
00383
00384 {
00385 std::lock_guard<std::mutex> csl(m_reactive_nav_engine_cs);
00386 m_reactive_nav_engine.navigate(&navParams);
00387 }
00388 }
00389
00391 void onDoNavigation(const ros::TimerEvent&)
00392 {
00393
00394
00395 if (!m_1st_time_init)
00396 {
00397 m_1st_time_init = true;
00398 ROS_INFO(
00399 "[ReactiveNav2DNode] Initializing reactive navigation "
00400 "engine...");
00401 {
00402 std::lock_guard<std::mutex> csl(m_reactive_nav_engine_cs);
00403 m_reactive_nav_engine.initialize();
00404 }
00405 ROS_INFO(
00406 "[ReactiveNav2DNode] Reactive navigation engine init done!");
00407 }
00408
00409 CTimeLoggerEntry tle(m_profiler, "onDoNavigation");
00410
00411 m_reactive_nav_engine.navigationStep();
00412 }
00413
00414 void onRosGoalReceived(const geometry_msgs::PoseStampedConstPtr& trg_ptr)
00415 {
00416 geometry_msgs::PoseStamped trg = *trg_ptr;
00417 ROS_INFO(
00418 "Nav target received via topic sub: (%.03f,%.03f, %.03fdeg) "
00419 "[frame_id=%s]",
00420 trg.pose.position.x, trg.pose.position.y,
00421 trg.pose.orientation.z * 180.0 / M_PI, trg.header.frame_id.c_str());
00422
00423
00424 if (trg.header.frame_id != m_frameid_reference)
00425 {
00426 try
00427 {
00428 geometry_msgs::PoseStamped trg2;
00429 m_tf_listener.transformPose(m_frameid_reference, trg, trg2);
00430 trg = trg2;
00431 }
00432 catch (tf::TransformException& ex)
00433 {
00434 ROS_ERROR("%s", ex.what());
00435 return;
00436 }
00437 }
00438
00439 this->navigateTo(mrpt::math::TPose2D(
00440 trg.pose.position.x, trg.pose.position.y, trg.pose.orientation.z));
00441 }
00442
00443 void onRosLocalObstacles(const sensor_msgs::PointCloudConstPtr& obs)
00444 {
00445 std::lock_guard<std::mutex> csl(m_last_obstacles_cs);
00446 mrpt_bridge::point_cloud::ros2mrpt(*obs, m_last_obstacles);
00447
00448
00449 }
00450
00451 void onRosSetRobotShape(const geometry_msgs::PolygonConstPtr& newShape)
00452 {
00453 ROS_INFO_STREAM(
00454 "[onRosSetRobotShape] Robot shape received via topic: "
00455 << *newShape);
00456
00457 mrpt::math::CPolygon poly;
00458 poly.resize(newShape->points.size());
00459 for (size_t i = 0; i < newShape->points.size(); i++)
00460 {
00461 poly[i].x = newShape->points[i].x;
00462 poly[i].y = newShape->points[i].y;
00463 }
00464
00465 {
00466 std::lock_guard<std::mutex> csl(m_reactive_nav_engine_cs);
00467 m_reactive_nav_engine.changeRobotShape(poly);
00468 }
00469 }
00470
00471 };
00472
00473 int main(int argc, char** argv)
00474 {
00475 ReactiveNav2DNode the_node(argc, argv);
00476 ros::spin();
00477 return 0;
00478 }