mrpt_reactivenav2d_node.cpp
Go to the documentation of this file.
00001 /***********************************************************************************
00002  * Revised BSD License *
00003  * Copyright (c) 2014-2015, Jose-Luis Blanco <jlblanco@ual.es> *
00004  * All rights reserved. *
00005  *                                                                                 *
00006  * Redistribution and use in source and binary forms, with or without *
00007  * modification, are permitted provided that the following conditions are met: *
00008  *     * Redistributions of source code must retain the above copyright *
00009  *       notice, this list of conditions and the following disclaimer. *
00010  *     * Redistributions in binary form must reproduce the above copyright *
00011  *       notice, this list of conditions and the following disclaimer in the *
00012  *       documentation and/or other materials provided with the distribution. *
00013  *     * Neither the name of the Vienna University of Technology nor the *
00014  *       names of its contributors may be used to endorse or promote products *
00015  *       derived from this software without specific prior written permission. *
00016  *                                                                                 *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  *AND *
00019  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00020  **
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
00022  * DISCLAIMED. IN NO EVENT SHALL Markus Bader BE LIABLE FOR ANY *
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  **
00026  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
00027  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
00028  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00029  **
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
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 // Use modern headers ------------
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 // The ROS node
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                         // Explicit 3d->2d to confirm we know we're losing information
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                 // Load params:
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                 // Load reactive config:
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                 // load robot shape: (1) default, (2) via params, (3) via topic
00320                 // ----------------------------------------------------------------
00321                 // m_reactive_nav_engine.changeRobotShape();
00322 
00323                 // Init this subscriber first so we know asap the desired robot shape,
00324                 // if provided via a topic:
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                 // Init ROS publishers:
00340                 // -----------------------
00341                 m_pub_cmd_vel = m_nh.advertise<geometry_msgs::Twist>("cmd_vel", 1);
00342 
00343                 // Init ROS subs:
00344                 // -----------------------
00345                 // "/reactive_nav_goal", "/move_base_simple/goal" (
00346                 // geometry_msgs/PoseStamped )
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                 // Init timers:
00355                 // ----------------------------------------------------
00356                 m_timer_run_nav = m_nh.createTimer(
00357                         ros::Duration(m_nav_period), &ReactiveNav2DNode::onDoNavigation,
00358                         this);
00359 
00360         }  // end ctor
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                 // Optional: restrict the PTGs to use
00382                 // navParams.restrict_PTG_indices.push_back(1);
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                 // 1st time init:
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                 // Convert to the "m_frameid_reference" frame of coordinates:
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                 // ROS_DEBUG("Local obstacles received: %u points", static_cast<unsigned
00448                 // int>(m_last_obstacles.size()) );
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 };  // end class
00472 
00473 int main(int argc, char** argv)
00474 {
00475         ReactiveNav2DNode the_node(argc, argv);
00476         ros::spin();
00477         return 0;
00478 }


mrpt_reactivenav2d
Author(s): Jose-Luis Blanco-Claraco
autogenerated on Thu Jun 6 2019 21:53:26