mvsim_node.cpp
Go to the documentation of this file.
1 
5 #include <rapidxml_utils.hpp>
6 #include <iostream>
7 
8 #include <mrpt/system/os.h> // kbhit()
10 
11 #include <mrpt_bridge/laser_scan.h>
12 #include <mrpt_bridge/map.h>
13 #include <mrpt_bridge/pose.h>
14 
15 #include <nav_msgs/MapMetaData.h>
16 #include <nav_msgs/GetMap.h>
17 #include <geometry_msgs/PoseWithCovarianceStamped.h>
18 #include <geometry_msgs/PoseArray.h>
19 #include <geometry_msgs/Polygon.h>
20 #include <sensor_msgs/LaserScan.h>
21 
22 #include <nav_msgs/Odometry.h>
24 
25 /*------------------------------------------------------------------------------
26  * MVSimNode()
27  * Constructor.
28  *----------------------------------------------------------------------------*/
30  : mvsim_world_(*this),
31  realtime_factor_(1.0),
32  gui_refresh_period_ms_(75),
33  m_show_gui(true),
34  m_do_fake_localization(true),
35  m_transform_tolerance(0.1),
36  m_n(n),
37  m_localn("~"),
38  m_tf_br(),
39  m_tfIdentity(tf::createIdentityQuaternion(), tf::Point(0, 0, 0)),
40  t_old_(-1),
41  world_init_ok_(false),
42  m_period_ms_publish_tf(20),
43  m_period_ms_teleop_refresh(100),
44  m_teleop_idx_veh(0)
45 {
46  // Launch GUI thread:
47  thread_params_.obj = this;
48  thGUI_ =
49  std::thread(&MVSimNode::thread_update_GUI, std::ref(thread_params_));
50 
51  // Init ROS publishers:
52  m_pub_clock = m_n.advertise<rosgraph_msgs::Clock>("/clock", 10);
53 
55  "simul_map", 1 /*queue len*/, true /*latch*/);
56  m_pub_map_metadata = m_n.advertise<nav_msgs::MapMetaData>(
57  "simul_map_metadata", 1 /*queue len*/, true /*latch*/);
58 
59  m_sim_time.fromSec(0.0);
61 
62  // Node parameters:
63  double t;
64  if (!m_localn.getParam("base_watchdog_timeout", t)) t = 0.2;
66 
67  m_localn.param("realtime_factor", realtime_factor_, 1.0);
69  "gui_refresh_period", gui_refresh_period_ms_, gui_refresh_period_ms_);
70  m_localn.param("show_gui", m_show_gui, m_show_gui);
72  "period_ms_publish_tf", m_period_ms_publish_tf, m_period_ms_publish_tf);
74  "do_fake_localization", m_do_fake_localization, m_do_fake_localization);
75 
76  // In case the user didn't set it:
77  m_n.setParam("/use_sim_time", true);
78 }
79 
80 void MVSimNode::loadWorldModel(const std::string& world_xml_file)
81 {
82  ROS_INFO("[MVSimNode] Loading world file: %s", world_xml_file.c_str());
84  mrpt::system::fileExists(world_xml_file),
85  "[MVSimNode::loadWorldModel] File does not exist!: '%s'",
86  world_xml_file.c_str());
87 
88  // Load from XML:
89  rapidxml::file<> fil_xml(world_xml_file.c_str());
90  mvsim_world_.load_from_XML(fil_xml.data(), world_xml_file);
91 
92  ROS_INFO("[MVSimNode] World file load done.");
93  world_init_ok_ = true;
94 
95  // Notify the ROS system about the good news:
97 }
98 
99 /*------------------------------------------------------------------------------
100  * ~MVSimNode()
101  * Destructor.
102  *----------------------------------------------------------------------------*/
104 {
105  thread_params_.closing = true;
106  thGUI_.join();
107 }
108 
109 /*------------------------------------------------------------------------------
110  * configCallback()
111  * Callback function for dynamic reconfigure server.
112  *----------------------------------------------------------------------------*/
113 void MVSimNode::configCallback(mvsim::mvsimNodeConfig& config, uint32_t level)
114 {
115  // Set class variables to new values. They should match what is input at the
116  // dynamic reconfigure GUI.
117  // message = config.message.c_str();
118  ROS_INFO("MVSimNode::configCallback() called.");
119 
120  if (mvsim_world_.is_GUI_open() && !config.show_gui)
122 }
123 
124 // Process pending msgs, run real-time simulation, etc.
126 {
127  using namespace mvsim;
128 
129  // Do simulation itself:
130  // ========================================================================
131  // Handle 1st iter:
132  if (t_old_ < 0) t_old_ = realtime_tictac_.Tac();
133  // Compute how much time has passed to simulate in real-time:
134  double t_new = realtime_tictac_.Tac();
135  double incr_time = realtime_factor_ * (t_new - t_old_);
136 
137  if (incr_time < mvsim_world_.get_simul_timestep()) // Just in case the
138  // computer is *really
139  // fast*...
140  return;
141 
142  // Simulate:
143  mvsim_world_.run_simulation(incr_time);
144 
145  // t_old_simul = world.get_simul_time();
146  t_old_ = t_new;
147 
148  const World::TListVehicles& vehs = mvsim_world_.getListOfVehicles();
149 
150  // Publish new state to ROS
151  // ========================================================================
152  this->spinNotifyROS();
153 
154  // GUI msgs, teleop, etc.
155  // ========================================================================
157  {
158  m_tim_teleop_refresh.Tic();
159 
160  std::string txt2gui_tmp;
162 
163  // Global keys:
164  switch (keyevent.keycode)
165  {
166  // case 27: do_exit=true; break;
167  case '1':
168  case '2':
169  case '3':
170  case '4':
171  case '5':
172  case '6':
173  m_teleop_idx_veh = keyevent.keycode - '1';
174  break;
175  };
176 
177  { // Test: Differential drive: Control raw forces
178  txt2gui_tmp += mrpt::format(
179  "Selected vehicle: %u/%u\n",
180  static_cast<unsigned>(m_teleop_idx_veh + 1),
181  static_cast<unsigned>(vehs.size()));
182  if (vehs.size() > m_teleop_idx_veh)
183  {
184  // Get iterator to selected vehicle:
185  World::TListVehicles::const_iterator it_veh = vehs.begin();
186  std::advance(it_veh, m_teleop_idx_veh);
187 
188  // Get speed: ground truth
189  {
190  const vec3& vel = it_veh->second->getVelocityLocal();
191  txt2gui_tmp += mrpt::format(
192  "gt. vel: lx=%7.03f, ly=%7.03f, w= %7.03fdeg/s\n",
193  vel.vals[0], vel.vals[1],
194  RAD2DEG(vel.vals[2]));
195  }
196  // Get speed: ground truth
197  {
198  const vec3& vel =
199  it_veh->second->getVelocityLocalOdoEstimate();
200  txt2gui_tmp += mrpt::format(
201  "odo vel: lx=%7.03f, ly=%7.03f, w= %7.03fdeg/s\n",
202  vel.vals[0], vel.vals[1],
203  RAD2DEG(vel.vals[2]));
204  }
205 
206  // Generic teleoperation interface for any controller that
207  // supports it:
208  {
209  ControllerBaseInterface* controller =
210  it_veh->second->getControllerInterface();
213  teleop_in.keycode = keyevent.keycode;
214  controller->teleop_interface(teleop_in, teleop_out);
215  txt2gui_tmp += teleop_out.append_gui_lines;
216  }
217  }
218  }
219 
220  m_msg2gui = txt2gui_tmp; // send txt msgs to show in the GUI
221 
222  // Clear the keystroke buffer
223  if (keyevent.keycode != 0) m_gui_key_events = World::TGUIKeyEvent();
224 
225  } // end refresh teleop stuff
226 }
227 
228 /*------------------------------------------------------------------------------
229  * thread_update_GUI()
230  *----------------------------------------------------------------------------*/
232 {
233  using namespace mvsim;
234 
235  MVSimNode* obj = thread_params.obj;
236 
237  while (!thread_params.closing)
238  {
239  if (obj->world_init_ok_ && obj->m_show_gui)
240  {
241  World::TUpdateGUIParams guiparams;
242  guiparams.msg_lines = obj->m_msg2gui;
243 
244  obj->mvsim_world_.update_GUI(&guiparams);
245 
246  // Send key-strokes to the main thread:
247  if (guiparams.keyevent.keycode != 0)
248  obj->m_gui_key_events = guiparams.keyevent;
249  }
250  std::this_thread::sleep_for(
251  std::chrono::milliseconds(obj->gui_refresh_period_ms_));
252  }
253 }
254 
255 // Visitor: Vehicles
256 // ----------------------------------------
259 {
260 } // end visit(Vehicles)
261 
262 // Visitor: World elements
263 // ----------------------------------------
266 {
267  // GridMaps --------------
268  if (dynamic_cast<mvsim::OccupancyGridMap*>(obj))
269  {
271  dynamic_cast<mvsim::OccupancyGridMap*>(obj);
272 
273  nav_msgs::OccupancyGrid ros_map;
274  mrpt_bridge::convert(grid->getOccGrid(), ros_map);
275 
276  static size_t loop_count = 0;
277  ros_map.header.stamp = ros::Time::now();
278  ros_map.header.seq = loop_count++;
279 
280  m_parent.m_pub_map_ros.publish(ros_map);
281  m_parent.m_pub_map_metadata.publish(ros_map.info);
282 
283  } // end gridmap
284 
285 } // end visit(World Elements)
286 
287 // ROS: Publish grid map for visualization purposes:
289 {
290  MVSimVisitor_notifyROSWorldIsUpdated myvisitor(*this);
291 
294 
295  // Create subscribers & publishers for each vehicle's stuff:
296  // ----------------------------------------------------
297  mvsim::World::TListVehicles& vehs = mvsim_world_.getListOfVehicles();
298  m_pubsub_vehicles.clear();
299  m_pubsub_vehicles.resize(vehs.size());
300  size_t idx = 0;
301  for (mvsim::World::TListVehicles::iterator it = vehs.begin();
302  it != vehs.end(); ++it, ++idx)
303  {
304  mvsim::VehicleBase* veh = it->second;
305  initPubSubs(m_pubsub_vehicles[idx], veh);
306  }
307 
308  // Publish the static transform /world -> /map
309  sendStaticTF("/world", "/map", m_tfIdentity, m_sim_time);
310 }
311 
313  const std::string& frame_id, const std::string& child_frame_id,
314  const tf::Transform& txf, const ros::Time& stamp)
315 {
316  geometry_msgs::TransformStamped tx;
317  tx.header.frame_id = frame_id;
318  tx.child_frame_id = child_frame_id;
319  tx.header.stamp = stamp;
320  tf::transformTFToMsg(txf, tx.transform);
322 }
323 
327 {
328  // sub: <VEH>/cmd_vel
329  pubsubs.sub_cmd_vel = m_n.subscribe<geometry_msgs::Twist>(
330  vehVarName("cmd_vel", veh), 10,
331  boost::bind(&MVSimNode::onROSMsgCmdVel, this, _1, veh));
332 
333  // pub: <VEH>/odom
334  pubsubs.pub_odom =
335  m_n.advertise<nav_msgs::Odometry>(vehVarName("odom", veh), 10);
336 
337  // pub: <VEH>/base_pose_ground_truth
338  pubsubs.pub_ground_truth = m_n.advertise<nav_msgs::Odometry>(
339  vehVarName("base_pose_ground_truth", veh), 10);
340 
341  // pub: <VEH>/chassis_markers
342  {
343  pubsubs.pub_chassis_markers =
344  m_n.advertise<visualization_msgs::MarkerArray>(
345  vehVarName("chassis_markers", veh), 5, true /*latch*/);
346  const mrpt::math::TPolygon2D& poly = veh->getChassisShape();
347 
348  // Create one "ROS marker" for each wheel + 1 for the chassis:
349  visualization_msgs::MarkerArray& msg_shapes = pubsubs.chassis_shape_msg;
350  msg_shapes.markers.resize(1 + veh->getNumWheels());
351 
352  // [0] Chassis shape:
353  visualization_msgs::Marker& chassis_shape_msg = msg_shapes.markers[0];
354 
355  chassis_shape_msg.action = visualization_msgs::Marker::MODIFY;
356  chassis_shape_msg.type = visualization_msgs::Marker::LINE_STRIP;
357  chassis_shape_msg.header.frame_id = vehVarName("base_link", veh);
358  chassis_shape_msg.ns = "mvsim.chassis_shape";
359  chassis_shape_msg.id = veh->getVehicleIndex();
360  chassis_shape_msg.scale.x = 0.05;
361  chassis_shape_msg.scale.y = 0.05;
362  chassis_shape_msg.scale.z = 0.02;
363  chassis_shape_msg.points.resize(poly.size() + 1);
364  for (size_t i = 0; i <= poly.size(); i++)
365  {
366  size_t k = i % poly.size();
367  chassis_shape_msg.points[i].x = poly[k].x;
368  chassis_shape_msg.points[i].y = poly[k].y;
369  chassis_shape_msg.points[i].z = 0;
370  }
371  chassis_shape_msg.color.a = 0.9;
372  chassis_shape_msg.color.r = 0.9;
373  chassis_shape_msg.color.g = 0.9;
374  chassis_shape_msg.color.b = 0.9;
375  chassis_shape_msg.frame_locked = true;
376 
377  // [1:N] Wheel shapes
378  for (size_t i = 0; i < veh->getNumWheels(); i++)
379  {
380  visualization_msgs::Marker& wheel_shape_msg =
381  msg_shapes.markers[1 + i];
382  const mvsim::Wheel& w = veh->getWheelInfo(i);
383 
384  const double lx = w.diameter * 0.5, ly = w.width * 0.5;
385  wheel_shape_msg = chassis_shape_msg; // Init values
386  chassis_shape_msg.ns = mrpt::format(
387  "mvsim.chassis_shape.wheel%u", static_cast<unsigned int>(i));
388  wheel_shape_msg.points.resize(5);
389  wheel_shape_msg.points[0].x = lx;
390  wheel_shape_msg.points[0].y = ly;
391  wheel_shape_msg.points[0].z = 0;
392  wheel_shape_msg.points[1].x = lx;
393  wheel_shape_msg.points[1].y = -ly;
394  wheel_shape_msg.points[1].z = 0;
395  wheel_shape_msg.points[2].x = -lx;
396  wheel_shape_msg.points[2].y = -ly;
397  wheel_shape_msg.points[2].z = 0;
398  wheel_shape_msg.points[3].x = -lx;
399  wheel_shape_msg.points[3].y = ly;
400  wheel_shape_msg.points[3].z = 0;
401  wheel_shape_msg.points[4] = wheel_shape_msg.points[0];
402 
403  wheel_shape_msg.color.r = w.color.R / 255.0;
404  wheel_shape_msg.color.g = w.color.G / 255.0;
405  wheel_shape_msg.color.b = w.color.B / 255.0;
406 
407  // Set local pose of the wheel wrt the vehicle:
408  tf::Matrix3x3 rot;
409  rot.setEulerYPR(w.yaw, 0, 0);
411  tf::Transform(rot, tf::Vector3(w.x, w.y, 0)),
412  wheel_shape_msg.pose);
413  } // end for each wheel
414 
415  // Publish Initial pose
416  pubsubs.pub_chassis_markers.publish(msg_shapes);
417  }
418 
419  // pub: <VEH>/chassis_polygon
420  {
421  pubsubs.pub_chassis_shape = m_n.advertise<geometry_msgs::Polygon>(
422  vehVarName("chassis_polygon", veh), 1, true /*latch*/);
423 
424  // Do the first (and unique) publish:
425  geometry_msgs::Polygon poly_msg;
426  const mrpt::math::TPolygon2D& poly = veh->getChassisShape();
427  poly_msg.points.resize(poly.size());
428  for (size_t i = 0; i < poly.size(); i++)
429  {
430  poly_msg.points[i].x = poly[i].x;
431  poly_msg.points[i].y = poly[i].y;
432  poly_msg.points[i].z = 0;
433  }
434  pubsubs.pub_chassis_shape.publish(poly_msg);
435  }
436 
438  {
439  // pub: <VEH>/amcl_pose
440  pubsubs.pub_amcl_pose =
441  m_n.advertise<geometry_msgs::PoseWithCovarianceStamped>(
442  vehVarName("amcl_pose", veh), 1);
443  // pub: <VEH>/particlecloud
444  pubsubs.pub_particlecloud = m_n.advertise<geometry_msgs::PoseArray>(
445  vehVarName("particlecloud", veh), 1);
446  }
447 
448  // STATIC Identity transform <VEH>/base_link -> <VEH>/base_footprint
449  sendStaticTF(
450  vehVarName("base_link", veh), vehVarName("base_footprint", veh),
452 }
453 
455  const geometry_msgs::Twist::ConstPtr& cmd, mvsim::VehicleBase* veh)
456 {
458 
459  const bool ctrlAcceptTwist =
460  controller->setTwistCommand(cmd->linear.x, cmd->angular.z);
461 
462  if (!ctrlAcceptTwist)
463  {
465  5.0,
466  "*Warning* Vehicle's controller ['%s'] refuses Twist commands!",
467  veh->getName().c_str());
468  }
469 }
470 
473 {
474  using namespace mvsim;
475  const World::TListVehicles& vehs = mvsim_world_.getListOfVehicles();
476 
477  // Get current simulation time (for messages) and publish "/clock"
478  // ----------------------------------------------------------------
480  m_clockMsg.clock = m_sim_time;
482 
483  // Publish all TFs for each vehicle:
484  // ---------------------------------------------------------------------
485  if (m_tim_publish_tf.Tac() > m_period_ms_publish_tf * 1e-3)
486  {
487  m_tim_publish_tf.Tic();
488 
489  size_t i = 0;
490  ROS_ASSERT(m_pubsub_vehicles.size() == vehs.size());
491 
492  for (World::TListVehicles::const_iterator it = vehs.begin();
493  it != vehs.end(); ++it, ++i)
494  {
495  const VehicleBase* veh = it->second;
496 
497  const std::string sOdomName = vehVarName("odom", veh);
498  const std::string sBaseLinkFrame = vehVarName("base_link", veh);
499 
500  // 1) Ground-truth pose and velocity
501  // --------------------------------------------
502  const mrpt::math::TPose3D& gh_veh_pose = veh->getPose();
503  const mvsim::vec3& gh_veh_vel =
504  veh->getVelocity(); // [vx,vy,w] in global frame
505 
506  {
507  nav_msgs::Odometry gtOdoMsg;
508 
509  gtOdoMsg.pose.pose.position.x = gh_veh_pose.x;
510  gtOdoMsg.pose.pose.position.y = gh_veh_pose.y;
511  gtOdoMsg.pose.pose.position.z = gh_veh_pose.z;
512 
513  tf::Quaternion quat;
514  quat.setEuler(
515  gh_veh_pose.roll, gh_veh_pose.pitch, gh_veh_pose.yaw);
516 
517  gtOdoMsg.pose.pose.orientation.x = quat.x();
518  gtOdoMsg.pose.pose.orientation.y = quat.y();
519  gtOdoMsg.pose.pose.orientation.z = quat.z();
520  gtOdoMsg.pose.pose.orientation.w = quat.w();
521  gtOdoMsg.twist.twist.linear.x = gh_veh_vel.vals[0];
522  gtOdoMsg.twist.twist.linear.y = gh_veh_vel.vals[1];
523  gtOdoMsg.twist.twist.linear.z = 0;
524  gtOdoMsg.twist.twist.angular.z = gh_veh_vel.vals[2];
525 
526  gtOdoMsg.header.stamp = m_sim_time;
527  gtOdoMsg.header.frame_id = sOdomName;
528  gtOdoMsg.child_frame_id = sBaseLinkFrame;
529 
530  m_pubsub_vehicles[i].pub_ground_truth.publish(gtOdoMsg);
531 
533  {
534  geometry_msgs::PoseWithCovarianceStamped currentPos;
535  geometry_msgs::PoseArray particleCloud;
536 
537  // topic: <Ri>/particlecloud
538  if (m_pubsub_vehicles[i]
539  .pub_particlecloud.getNumSubscribers() > 0)
540  {
541  particleCloud.header.stamp = m_sim_time;
542  particleCloud.header.frame_id = "/map";
543  particleCloud.poses.resize(1);
544  particleCloud.poses[0] = gtOdoMsg.pose.pose;
545  m_pubsub_vehicles[i].pub_particlecloud.publish(
546  particleCloud);
547  }
548 
549  // topic: <Ri>/amcl_pose
550  if (m_pubsub_vehicles[i].pub_amcl_pose.getNumSubscribers() >
551  0)
552  {
553  currentPos.header = gtOdoMsg.header;
554  currentPos.pose.pose = gtOdoMsg.pose.pose;
555  m_pubsub_vehicles[i].pub_amcl_pose.publish(currentPos);
556  }
557 
558  // TF: /map -> <Ri>/odom
559  {
560  MRPT_TODO(
561  "Save initial pose for each vehicle, set odometry "
562  "from that pose");
563  const tf::Transform tr(
565  tf::Vector3(0, 0, 0));
568  tr, m_sim_time, "/map", sOdomName));
569  }
570  }
571  }
572 
573  // 2) Chassis markers (for rviz visualization)
574  // --------------------------------------------
575  // pub: <VEH>/chassis_markers
576  if (m_pubsub_vehicles[i].pub_chassis_markers.getNumSubscribers() >
577  0)
578  {
579  visualization_msgs::MarkerArray& msg_shapes =
580  m_pubsub_vehicles[i].chassis_shape_msg;
581  ROS_ASSERT(
582  msg_shapes.markers.size() == (1 + veh->getNumWheels()));
583 
584  // [0] Chassis shape: static no need to update.
585  // [1:N] Wheel shapes: may move
586  for (size_t j = 0; j < veh->getNumWheels(); j++)
587  {
588  visualization_msgs::Marker& wheel_shape_msg =
589  msg_shapes.markers[1 + j];
590  const mvsim::Wheel& w = veh->getWheelInfo(j);
591 
592  // Set local pose of the wheel wrt the vehicle:
593  tf::Matrix3x3 rot;
594  rot.setEulerYPR(w.yaw, 0, 0);
596  tf::Transform(rot, tf::Vector3(w.x, w.y, 0)),
597  wheel_shape_msg.pose);
598  } // end for each wheel
599 
600  // Publish Initial pose
601  m_pubsub_vehicles[i].pub_chassis_markers.publish(msg_shapes);
602  }
603 
604  // 3) odometry transform
605  // --------------------------------------------
606  {
607  const mrpt::math::TPose3D odo_pose = gh_veh_pose;
608 
609  {
610  tf::Matrix3x3 rot;
611  rot.setEulerYPR(
612  odo_pose.yaw, odo_pose.pitch, odo_pose.roll);
613  const tf::Transform tr(
614  rot, tf::Vector3(odo_pose.x, odo_pose.y, odo_pose.z));
615 
618  tr, m_sim_time, sOdomName, sBaseLinkFrame));
619  }
620 
621  // Apart from TF, publish to the "odom" topic as well
622  if (m_pubsub_vehicles[i].pub_odom.getNumSubscribers() > 0)
623  {
624  nav_msgs::Odometry odoMsg;
625 
626  odoMsg.pose.pose.position.x = odo_pose.x;
627  odoMsg.pose.pose.position.y = odo_pose.y;
628  odoMsg.pose.pose.position.z = odo_pose.z;
629 
630  tf::Quaternion quat;
631  quat.setEuler(odo_pose.roll, odo_pose.pitch, odo_pose.yaw);
632 
633  odoMsg.pose.pose.orientation.x = quat.x();
634  odoMsg.pose.pose.orientation.y = quat.y();
635  odoMsg.pose.pose.orientation.z = quat.z();
636  odoMsg.pose.pose.orientation.w = quat.w();
637 
638  // first, we'll populate the header for the odometry msg
639  odoMsg.header.stamp = m_sim_time;
640  odoMsg.header.frame_id = sOdomName;
641  odoMsg.child_frame_id = sBaseLinkFrame;
642 
643  // publish:
644  m_pubsub_vehicles[i].pub_odom.publish(odoMsg);
645  }
646  }
647 
648  } // end for each vehicle
649 
650  } // end publish tf
651 
652 } // end spinNotifyROS()
653 
655  const mvsim::VehicleBase& veh,
656 #if MRPT_VERSION >= 0x130
657  const mrpt::obs::CObservation* obs
658 #else
659  const mrpt::slam::CObservation* obs
660 #endif
661  )
662 {
663  ROS_ASSERT(obs);
664  ROS_ASSERT(!obs->sensorLabel.empty());
665 
666  TPubSubPerVehicle& pubs = m_parent.m_pubsub_vehicles[veh.getVehicleIndex()];
667 
668  // Create the publisher the first time an observation arrives:
669  const bool is_1st_pub =
670  pubs.pub_sensors.find(obs->sensorLabel) == pubs.pub_sensors.end();
671  ros::Publisher& pub = pubs.pub_sensors[obs->sensorLabel];
672 
673  // Observation: 2d laser scans
674  // -----------------------------
675  if (dynamic_cast<const CObservation2DRangeScan*>(obs))
676  {
677  if (is_1st_pub)
678  pub = m_parent.m_n.advertise<sensor_msgs::LaserScan>(
679  m_parent.vehVarName(obs->sensorLabel, &veh), 10);
680 
681  const CObservation2DRangeScan* o =
682  dynamic_cast<const CObservation2DRangeScan*>(obs);
683  const std::string sSensorFrameId =
684  m_parent.vehVarName(obs->sensorLabel, &veh);
685 
686  // Send TF:
687  mrpt::poses::CPose3D pose_laser;
689  o->getSensorPose(pose_laser);
690  mrpt_bridge::convert(pose_laser, transform);
691 
692  m_parent.m_tf_br.sendTransform(
694  transform, m_parent.m_sim_time,
695  m_parent.vehVarName("base_link", &veh), // parent frame
696  sSensorFrameId));
697 
698  // Send observation:
699  if (is_1st_pub || pub.getNumSubscribers() > 0)
700  {
701  // Convert observation MRPT -> ROS
702  geometry_msgs::Pose msg_pose_laser;
703  sensor_msgs::LaserScan msg_laser;
704  mrpt_bridge::convert(*o, msg_laser, msg_pose_laser);
705 
706  // Force usage of simulation time:
707  msg_laser.header.stamp = m_parent.m_sim_time;
708  msg_laser.header.frame_id = sSensorFrameId;
709 
710  pub.publish(msg_laser);
711  }
712  }
713  else
714  {
715  // Don't know how to emit this observation to ROS!
716  }
717 
718 } // end of onNewObservation()
719 
723  const std::string& sVarName, const mvsim::VehicleBase* veh) const
724 {
725  if (mvsim_world_.getListOfVehicles().size() == 1)
726  {
727  return std::string("/") + sVarName;
728  }
729  else
730  {
731  return std::string("/") + veh->getName() + std::string("/") + sVarName;
732  }
733 }
ros::Publisher pub_ground_truth
Publisher of "base_pose_ground_truth" topic.
static void thread_update_GUI(TThreadParams &thread_params)
Definition: mvsim_node.cpp:231
std::string vehVarName(const std::string &sVarName, const mvsim::VehicleBase *veh) const
Definition: mvsim_node.cpp:722
double width
Definition: Wheel.h:39
const mrpt::maps::COccupancyGridMap2D & getOccGrid() const
mrpt::system::CTicTac m_tim_publish_tf
TF transforms & /*/odom topics (In ms)
double m_period_ms_teleop_refresh
ros::NodeHandle m_localn
void publish(const boost::shared_ptr< M > &message) const
Represents data loaded from a file.
ros::Subscriber sub_cmd_vel
Subscribers for each vehicle&#39;s "cmd_vel" topic.
virtual void teleop_interface(const TeleopInput &in, TeleopOutput &out)
const VehicleList & getListOfVehicles() const
Definition: World.h:195
std::string m_msg2gui
#define ROS_DEBUG_THROTTLE(rate,...)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
mrpt::system::CTicTac realtime_tictac_
GLubyte GLubyte GLubyte GLubyte w
GLdouble GLdouble t
bool BASE_IMPEXP fileExists(const std::string &fileName)
void runVisitorOnWorldElements(const world_element_visitor_t &v)
Definition: World.cpp:199
ros::Time m_base_last_cmd
Last time we received a vel_cmd (for watchdog)
ros::Publisher m_pub_map_ros
void setEulerYPR(tfScalar eulerZ, tfScalar eulerY, tfScalar eulerX)
mrpt::math::TPose3D getPose() const
Definition: Simulable.h:55
mrpt::img::TColor color
Definition: Wheel.h:47
virtual void onNewObservation(const mvsim::VehicleBase &veh, const CObservation *obs)
Definition: mvsim_node.cpp:654
unsigned int uint32_t
rosgraph_msgs::Clock m_clockMsg
static tf::Quaternion createIdentityQuaternion()
mvsim::World::TGUIKeyEvent m_gui_key_events
"focused" vehicle)
Time & fromSec(double t)
GLuint GLenum GLenum transform
const mrpt::math::TPolygon2D & getChassisShape() const
Definition: VehicleBase.h:113
MRPT_TODO("Modify ping to run on Windows + Test this")
mrpt::system::CTicTac m_tim_teleop_refresh
ros::Duration m_base_watchdog_timeout
TGUIKeyEvent keyevent
Keystrokes in the window are returned here.
Definition: World.h:114
const tf::Transform m_tfIdentity
Unit transform (const, created only once)
double x
Definition: Wheel.h:36
double get_simul_timestep() const
Simulation fixed-time interval for numerical integration.
Definition: World.h:73
void onROSMsgCmdVel(const geometry_msgs::Twist::ConstPtr &cmd, mvsim::VehicleBase *veh)
Definition: mvsim_node.cpp:454
tf::TransformBroadcaster m_tf_br
Use to send data to TF.
bool world_init_ok_
GLsizei n
size_t getNumWheels() const
Definition: VehicleBase.h:83
void loadWorldModel(const std::string &world_xml_file)
Definition: mvsim_node.cpp:80
void spin()
Process pending msgs, run real-time simulation, etc.
Definition: mvsim_node.cpp:125
const std::string & getName() const
Definition: Simulable.h:95
void configCallback(mvsim::mvsimNodeConfig &config, uint32_t level)
Definition: mvsim_node.cpp:113
obs
int gui_refresh_period_ms_
Default:25.
bool is_GUI_open() const
Forces closing the GUI window, if any.
Definition: World_gui.cpp:42
double y
Definition: Wheel.h:36
Duration & fromSec(double t)
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
size_t m_teleop_idx_veh
GLhandleARB obj
#define ROS_INFO(...)
tf2_ros::StaticTransformBroadcaster m_static_tf_br
For sending STATIC tf.
bool param(const std::string &param_name, T &param_val, const T &default_val) const
size_t getVehicleIndex() const
Definition: VehicleBase.h:121
void spinNotifyROS()
Definition: mvsim_node.cpp:472
#define ROS_ASSERT_MSG(cond,...)
double m_period_ms_publish_tf
loadWorldModel()
std::string msg_lines
Messages to show.
Definition: World.h:115
double diameter
Definition: Wheel.h:39
void sendTransform(const StampedTransform &transform)
virtual ControllerBaseInterface * getControllerInterface()=0
ros::Publisher pub_chassis_shape
"<VEH>/chassis_shape"
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ros::NodeHandle & m_n
published TFs
const Wheel & getWheelInfo(const size_t idx) const
Definition: VehicleBase.h:84
double yaw
Definition: Wheel.h:36
void sendStaticTF(const std::string &frame_id, const std::string &child_frame_id, const tf::Transform &tx, const ros::Time &stamp)
Definition: mvsim_node.cpp:312
void load_from_XML(const std::string &xml_text, const std::string &fileNameForPath=std::string("."))
ros::Publisher pub_chassis_markers
"<VEH>/chassis_markers"
TThreadParams thread_params_
GLint level
void setEuler(const tfScalar &yaw, const tfScalar &pitch, const tfScalar &roll)
TCLAP::CmdLine cmd("mvsim", ' ',"version", false)
virtual bool setTwistCommand(const double vx, const double wz)
void convert(const ros::Time &src, mrpt::system::TTimeStamp &des)
ros::Publisher pub_particlecloud
Publishers for "fake_localization" topics.
ros::Publisher pub_odom
Publisher of "odom" topic.
uint32_t getNumSubscribers() const
void runVisitorOnVehicles(const vehicle_visitor_t &v)
Definition: World.cpp:192
std::thread thGUI_
static void poseTFToMsg(const Pose &bt, geometry_msgs::Pose &msg)
void initPubSubs(TPubSubPerVehicle &out_pubsubs, mvsim::VehicleBase *veh)
Definition: mvsim_node.cpp:326
const mrpt::math::TTwist2D & getVelocity() const
Definition: Simulable.h:92
bool getParam(const std::string &key, std::string &s) const
ros::Publisher m_pub_clock
std::vector< TPubSubPerVehicle > m_pubsub_vehicles
double RAD2DEG(const double x)
MVSimNode(ros::NodeHandle &n)
Definition: mvsim_node.cpp:29
static Time now()
std::map< std::string, ros::Publisher > pub_sensors
Map <sensor_label> => publisher.
void run_simulation(double dt)
Definition: World.cpp:71
void notifyROSWorldIsUpdated()
Definition: mvsim_node.cpp:288
bool m_show_gui
Default= true.
ros::Time m_sim_time
Current simulation time.
#define ROS_ASSERT(cond)
void sendTransform(const geometry_msgs::TransformStamped &transform)
MyWorld mvsim_world_
void update_GUI(TUpdateGUIParams *params=nullptr)
Definition: World_gui.cpp:633
bool m_do_fake_localization
double get_simul_time() const
Simulation wall-clock time.
Definition: World.h:68
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const
visualization_msgs::MarkerArray chassis_shape_msg
static void transformTFToMsg(const Transform &bt, geometry_msgs::Transform &msg)
int keycode
0=no Key. Otherwise, ASCII code.
Definition: World.h:103
double realtime_factor_
everything: vehicles, obstacles, etc.)
void close_GUI()
a previous call to update_GUI()
Definition: World_gui.cpp:44
ros::Publisher m_pub_map_metadata
used for simul_map publication


mvsim
Author(s):
autogenerated on Fri May 7 2021 03:05:51