mrpt_reactivenav2d_node.cpp
Go to the documentation of this file.
1 /***********************************************************************************
2  * Revised BSD License *
3  * Copyright (c) 2014-2015, Jose-Luis Blanco <jlblanco@ual.es> *
4  * All rights reserved. *
5  * *
6  * Redistribution and use in source and binary forms, with or without *
7  * modification, are permitted provided that the following conditions are met: *
8  * * Redistributions of source code must retain the above copyright *
9  * notice, this list of conditions and the following disclaimer. *
10  * * Redistributions in binary form must reproduce the above copyright *
11  * notice, this list of conditions and the following disclaimer in the *
12  * documentation and/or other materials provided with the distribution. *
13  * * Neither the name of the Vienna University of Technology nor the *
14  * names of its contributors may be used to endorse or promote products *
15  * derived from this software without specific prior written permission. *
16  * *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  *AND *
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  **
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
22  * DISCLAIMED. IN NO EVENT SHALL Markus Bader BE LIABLE FOR ANY *
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  **
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
27  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  **
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
31  ***********************************************************************************/
32 
33 #include <ros/ros.h>
34 
35 #include <sensor_msgs/LaserScan.h>
36 #include <sensor_msgs/PointCloud.h>
37 #include <geometry_msgs/PoseStamped.h>
38 #include <geometry_msgs/Polygon.h>
39 #include <nav_msgs/Odometry.h>
40 #include <tf/transform_listener.h>
41 
42 #include <mrpt/version.h>
43 
44 // Use modern headers ------------
45 #include <mrpt/nav/reactive/CReactiveNavigationSystem.h>
46 #include <mrpt/maps/CSimplePointsMap.h>
47 using namespace mrpt::nav;
48 using mrpt::maps::CSimplePointsMap;
49 
50 #include <mrpt/version.h>
51 #if MRPT_VERSION >= 0x199
52 #include <mrpt/system/CTimeLogger.h>
53 #include <mrpt/config/CConfigFileMemory.h>
54 #include <mrpt/config/CConfigFile.h>
55 using namespace mrpt::system;
56 using namespace mrpt::config;
57 #else
58 #include <mrpt/utils/CTimeLogger.h>
59 #include <mrpt/utils/CConfigFileMemory.h>
60 #include <mrpt/utils/CConfigFile.h>
61 using namespace mrpt::utils;
62 #endif
63 
64 #include <mrpt/system/filesystem.h>
65 
66 #include <mrpt_bridge/pose.h>
67 #include <mrpt_bridge/point_cloud.h>
68 #include <mrpt_bridge/time.h>
69 
70 #include <mrpt/kinematics/CVehicleVelCmd_DiffDriven.h>
71 
72 #include <mutex>
73 
74 // The ROS node
76 {
77  private:
79  {
80  TAuxInitializer(int argc, char** argv)
81  {
82  ros::init(argc, argv, "mrpt_reactivenav2d");
83  }
84  };
85 
86  CTimeLogger m_profiler;
90 
98 
102  double m_nav_period;
103 
107 
108  std::string m_frameid_reference;
109  std::string m_frameid_robot;
110 
112 
114 
115  CSimplePointsMap m_last_obstacles;
117 
119 
120  public mrpt::nav::CRobot2NavInterface
121  {
123 
124  MyReactiveInterface(ReactiveNav2DNode& parent) : m_parent(parent) {}
132  mrpt::math::TPose2D& curPose, mrpt::math::TTwist2D& curVel,
133  mrpt::system::TTimeStamp& timestamp,
134  mrpt::math::TPose2D& curOdometry, std::string& frame_id) override
135  {
136  double curV, curW;
137 
138  CTimeLoggerEntry tle(
139  m_parent.m_profiler, "getCurrentPoseAndSpeeds");
140  tf::StampedTransform txRobotPose;
141  try
142  {
143  CTimeLoggerEntry tle2(
144  m_parent.m_profiler,
145  "getCurrentPoseAndSpeeds.lookupTransform_sensor");
147  m_parent.m_frameid_reference, m_parent.m_frameid_robot,
148  ros::Time(0), txRobotPose);
149  }
150  catch (tf::TransformException& ex)
151  {
152  ROS_ERROR("%s", ex.what());
153  return false;
154  }
155 
156  mrpt::poses::CPose3D curRobotPose;
157  mrpt_bridge::convert(txRobotPose, curRobotPose);
158 
159  mrpt_bridge::convert(txRobotPose.stamp_, timestamp);
160  // Explicit 3d->2d to confirm we know we're losing information
161  curPose =
162 #if MRPT_VERSION >= 0x199
163  mrpt::poses::CPose2D(curRobotPose).asTPose();
164 #else
165  mrpt::math::TPose2D(mrpt::poses::CPose2D(curRobotPose));
166 #endif
167  curOdometry = curPose;
168 
169  curV = curW = 0;
170  MRPT_TODO("Retrieve current speeds from odometry");
171  ROS_DEBUG(
172  "[getCurrentPoseAndSpeeds] Latest pose: %s",
173  curPose.asString().c_str());
174 
175  curVel.vx = curV * cos(curPose.phi);
176  curVel.vy = curV * sin(curPose.phi);
177  curVel.omega = curW;
178 
179  return true;
180  }
181 
188  const mrpt::kinematics::CVehicleVelCmd& vel_cmd) override
189  {
190  using namespace mrpt::kinematics;
191  const CVehicleVelCmd_DiffDriven* vel_cmd_diff_driven =
192  dynamic_cast<const CVehicleVelCmd_DiffDriven*>(&vel_cmd);
193  ASSERT_(vel_cmd_diff_driven);
194 
195  const double v = vel_cmd_diff_driven->lin_vel;
196  const double w = vel_cmd_diff_driven->ang_vel;
197  ROS_DEBUG(
198  "changeSpeeds: v=%7.4f m/s w=%8.3f deg/s", v,
199  w * 180.0f / M_PI);
200  geometry_msgs::Twist cmd;
201  cmd.linear.x = v;
202  cmd.angular.z = w;
203  m_parent.m_pub_cmd_vel.publish(cmd);
204  return true;
205  }
206 
207  bool stop(bool isEmergency) override
208  {
209  mrpt::kinematics::CVehicleVelCmd_DiffDriven vel_cmd;
210  vel_cmd.lin_vel = 0;
211  vel_cmd.ang_vel = 0;
212  return changeSpeeds(vel_cmd);
213  }
214 
218  virtual bool startWatchdog(float T_ms) override { return true; }
221  virtual bool stopWatchdog() override { return true; }
225  CSimplePointsMap& obstacles,
226  mrpt::system::TTimeStamp& timestamp) override
227  {
228  timestamp = mrpt::system::now();
229  std::lock_guard<std::mutex> csl(m_parent.m_last_obstacles_cs);
230  obstacles = m_parent.m_last_obstacles;
231 
232  MRPT_TODO("TODO: Check age of obstacles!");
233  return true;
234  }
235 
236  mrpt::kinematics::CVehicleVelCmd::Ptr getEmergencyStopCmd() override
237  {
238  return getStopCmd();
239  }
240  mrpt::kinematics::CVehicleVelCmd::Ptr getStopCmd() override
241  {
242  mrpt::kinematics::CVehicleVelCmd::Ptr ret =
243  mrpt::kinematics::CVehicleVelCmd::Ptr(
244  new mrpt::kinematics::CVehicleVelCmd_DiffDriven);
245  ret->setToStop();
246  return ret;
247  }
248 
249  virtual void sendNavigationStartEvent() {}
250  virtual void sendNavigationEndEvent() {}
252  virtual void sendWaySeemsBlockedEvent() {}
253  };
254 
256 
257  CReactiveNavigationSystem m_reactive_nav_engine;
259 
260  public:
262  ReactiveNav2DNode(int argc, char** argv)
263  : m_auxinit(argc, argv),
264  m_nh(),
265  m_localn("~"),
266  m_1st_time_init(false),
267  m_target_allowed_distance(0.40f),
268  m_nav_period(0.100),
269  m_pub_topic_reactive_nav_goal("reactive_nav_goal"),
270  m_sub_topic_local_obstacles("local_map_pointcloud"),
271  m_sub_topic_robot_shape(""),
272  m_frameid_reference("/map"),
273  m_frameid_robot("base_link"),
274  m_save_nav_log(false),
275  m_reactive_if(*this),
276  m_reactive_nav_engine(m_reactive_if)
277  {
278  // Load params:
279  std::string cfg_file_reactive;
280  m_localn.param(
281  "cfg_file_reactive", cfg_file_reactive, cfg_file_reactive);
282  m_localn.param(
283  "target_allowed_distance", m_target_allowed_distance,
284  m_target_allowed_distance);
285  m_localn.param("nav_period", m_nav_period, m_nav_period);
286  m_localn.param(
287  "frameid_reference", m_frameid_reference, m_frameid_reference);
288  m_localn.param("frameid_robot", m_frameid_robot, m_frameid_robot);
289  m_localn.param(
290  "topic_robot_shape", m_sub_topic_robot_shape,
291  m_sub_topic_robot_shape);
292  m_localn.param("save_nav_log", m_save_nav_log, m_save_nav_log);
293 
294  ROS_ASSERT(m_nav_period > 0);
296  !cfg_file_reactive.empty(),
297  "Mandatory param 'cfg_file_reactive' is missing!");
299  mrpt::system::fileExists(cfg_file_reactive),
300  "Config file not found: '%s'", cfg_file_reactive.c_str());
301 
302  m_reactive_nav_engine.enableLogFile(m_save_nav_log);
303 
304  // Load reactive config:
305  // ----------------------------------------------------
306  try
307  {
308  CConfigFile cfgFil(cfg_file_reactive);
309  m_reactive_nav_engine.loadConfigFile(cfgFil);
310  }
311  catch (std::exception& e)
312  {
313  ROS_ERROR(
314  "Exception initializing reactive navigation engine:\n%s",
315  e.what());
316  throw;
317  }
318 
319  // load robot shape: (1) default, (2) via params, (3) via topic
320  // ----------------------------------------------------------------
321  // m_reactive_nav_engine.changeRobotShape();
322 
323  // Init this subscriber first so we know asap the desired robot shape,
324  // if provided via a topic:
325  if (!m_sub_topic_robot_shape.empty())
326  {
327  m_sub_robot_shape = m_nh.subscribe<geometry_msgs::Polygon>(
328  m_sub_topic_robot_shape, 1,
330  ROS_INFO(
331  "Params say robot shape will arrive via topic '%s'... waiting "
332  "3 seconds for it.",
333  m_sub_topic_robot_shape.c_str());
334  ros::Duration(3.0).sleep();
335  for (size_t i = 0; i < 100; i++) ros::spinOnce();
336  ROS_INFO("Wait done.");
337  }
338 
339  // Init ROS publishers:
340  // -----------------------
341  m_pub_cmd_vel = m_nh.advertise<geometry_msgs::Twist>("cmd_vel", 1);
342 
343  // Init ROS subs:
344  // -----------------------
345  // "/reactive_nav_goal", "/move_base_simple/goal" (
346  // geometry_msgs/PoseStamped )
347  m_sub_nav_goal = m_nh.subscribe<geometry_msgs::PoseStamped>(
348  m_pub_topic_reactive_nav_goal, 1,
350  m_sub_local_obs = m_nh.subscribe<sensor_msgs::PointCloud>(
351  m_sub_topic_local_obstacles, 1,
353 
354  // Init timers:
355  // ----------------------------------------------------
356  m_timer_run_nav = m_nh.createTimer(
358  this);
359 
360  } // end ctor
361 
366  void navigateTo(const mrpt::math::TPose2D& target)
367  {
368  ROS_INFO(
369  "[navigateTo] Starting navigation to %s",
370  target.asString().c_str());
371 
372  CAbstractPTGBasedReactive::TNavigationParamsPTG navParams;
373  CAbstractNavigator::TargetInfo target_info;
374  target_info.target_coords.x = target.x;
375  target_info.target_coords.y = target.y;
376  target_info.targetAllowedDistance = m_target_allowed_distance;
377  target_info.targetIsRelative = false;
378 
379  navParams.multiple_targets.push_back(target_info);
380 
381  // Optional: restrict the PTGs to use
382  // navParams.restrict_PTG_indices.push_back(1);
383 
384  {
385  std::lock_guard<std::mutex> csl(m_reactive_nav_engine_cs);
386  m_reactive_nav_engine.navigate(&navParams);
387  }
388  }
389 
392  {
393  // 1st time init:
394  // ----------------------------------------------------
395  if (!m_1st_time_init)
396  {
397  m_1st_time_init = true;
398  ROS_INFO(
399  "[ReactiveNav2DNode] Initializing reactive navigation "
400  "engine...");
401  {
402  std::lock_guard<std::mutex> csl(m_reactive_nav_engine_cs);
403  m_reactive_nav_engine.initialize();
404  }
405  ROS_INFO(
406  "[ReactiveNav2DNode] Reactive navigation engine init done!");
407  }
408 
409  CTimeLoggerEntry tle(m_profiler, "onDoNavigation");
410 
411  m_reactive_nav_engine.navigationStep();
412  }
413 
414  void onRosGoalReceived(const geometry_msgs::PoseStampedConstPtr& trg_ptr)
415  {
416  geometry_msgs::PoseStamped trg = *trg_ptr;
417  ROS_INFO(
418  "Nav target received via topic sub: (%.03f,%.03f, %.03fdeg) "
419  "[frame_id=%s]",
420  trg.pose.position.x, trg.pose.position.y,
421  trg.pose.orientation.z * 180.0 / M_PI, trg.header.frame_id.c_str());
422 
423  // Convert to the "m_frameid_reference" frame of coordinates:
424  if (trg.header.frame_id != m_frameid_reference)
425  {
426  try
427  {
428  geometry_msgs::PoseStamped trg2;
429  m_tf_listener.transformPose(m_frameid_reference, trg, trg2);
430  trg = trg2;
431  }
432  catch (tf::TransformException& ex)
433  {
434  ROS_ERROR("%s", ex.what());
435  return;
436  }
437  }
438 
439  this->navigateTo(mrpt::math::TPose2D(
440  trg.pose.position.x, trg.pose.position.y, trg.pose.orientation.z));
441  }
442 
443  void onRosLocalObstacles(const sensor_msgs::PointCloudConstPtr& obs)
444  {
445  std::lock_guard<std::mutex> csl(m_last_obstacles_cs);
446  mrpt_bridge::point_cloud::ros2mrpt(*obs, m_last_obstacles);
447  // ROS_DEBUG("Local obstacles received: %u points", static_cast<unsigned
448  // int>(m_last_obstacles.size()) );
449  }
450 
451  void onRosSetRobotShape(const geometry_msgs::PolygonConstPtr& newShape)
452  {
454  "[onRosSetRobotShape] Robot shape received via topic: "
455  << *newShape);
456 
457  mrpt::math::CPolygon poly;
458  poly.resize(newShape->points.size());
459  for (size_t i = 0; i < newShape->points.size(); i++)
460  {
461  poly[i].x = newShape->points[i].x;
462  poly[i].y = newShape->points[i].y;
463  }
464 
465  {
466  std::lock_guard<std::mutex> csl(m_reactive_nav_engine_cs);
467  m_reactive_nav_engine.changeRobotShape(poly);
468  }
469  }
470 
471 }; // end class
472 
473 int main(int argc, char** argv)
474 {
475  ReactiveNav2DNode the_node(argc, argv);
476  ros::spin();
477  return 0;
478 }
ros::NodeHandle m_localn
"~"
void onRosGoalReceived(const geometry_msgs::PoseStampedConstPtr &trg_ptr)
ReactiveNav2DNode(int argc, char **argv)
void publish(const boost::shared_ptr< M > &message) const
f
ros::Subscriber m_sub_robot_shape
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
virtual bool startWatchdog(float T_ms) override
MyReactiveInterface m_reactive_if
bool sleep() const
ros::Subscriber m_sub_nav_goal
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
tf::TransformListener m_tf_listener
Use to retrieve TF data.
mrpt::kinematics::CVehicleVelCmd::Ptr getStopCmd() override
void onRosLocalObstacles(const sensor_msgs::PointCloudConstPtr &obs)
void onRosSetRobotShape(const geometry_msgs::PolygonConstPtr &newShape)
ROSCPP_DECL void spin(Spinner &spinner)
ros::Subscriber m_sub_local_obs
bool senseObstacles(CSimplePointsMap &obstacles, mrpt::system::TTimeStamp &timestamp) override
bool changeSpeeds(const mrpt::kinematics::CVehicleVelCmd &vel_cmd) override
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
#define ROS_ASSERT_MSG(cond,...)
TAuxInitializer m_auxinit
Just to make sure ROS is init first.
bool m_1st_time_init
Reactive initialization done?
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
std::string m_pub_topic_reactive_nav_goal
int main(int argc, char **argv)
ros::NodeHandle m_nh
The node handle.
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, StampedTransform &transform) const
TFSIMD_FORCE_INLINE const tfScalar & w() const
mrpt::kinematics::CVehicleVelCmd::Ptr getEmergencyStopCmd() override
void onDoNavigation(const ros::TimerEvent &)
#define ROS_INFO_STREAM(args)
void transformPose(const std::string &target_frame, const geometry_msgs::PoseStamped &stamped_in, geometry_msgs::PoseStamped &stamped_out) const
bool getCurrentPoseAndSpeeds(mrpt::math::TPose2D &curPose, mrpt::math::TTwist2D &curVel, mrpt::system::TTimeStamp &timestamp, mrpt::math::TPose2D &curOdometry, std::string &frame_id) override
CSimplePointsMap m_last_obstacles
CReactiveNavigationSystem m_reactive_nav_engine
#define ROS_ASSERT(cond)
ROSCPP_DECL void spinOnce()
#define ROS_ERROR(...)
void navigateTo(const mrpt::math::TPose2D &target)
Issue a navigation command.
#define ROS_DEBUG(...)


mrpt_reactivenav2d
Author(s): Jose-Luis Blanco-Claraco
autogenerated on Thu Jun 6 2019 19:44:56