4343#include < boost/thread/mutex.hpp>
4444#include < boost/thread/thread.hpp>
4545#include < sensor_msgs/LaserScan.h>
46+ #include < sensor_msgs/Range.h>
4647#include < sensor_msgs/Image.h>
4748#include < sensor_msgs/image_encodings.h>
4849#include < sensor_msgs/CameraInfo.h>
6061#define CAMERA_INFO " camera_info"
6162#define ODOM " odom"
6263#define BASE_SCAN " base_scan"
64+ #define SONAR " sonar/range" // should later change to just "sonar" and add "/range" in later naming
6365#define BASE_POSE_GROUND_TRUTH " base_pose_ground_truth"
6466#define CMD_VEL " cmd_vel"
6567
@@ -76,16 +78,20 @@ class StageNode
7678
7779 // The models that we're interested in
7880 std::vector<Stg::ModelCamera *> cameramodels;
79- std::vector<Stg::ModelRanger *> lasermodels ;
81+ std::vector<Stg::ModelRanger *> rangermodels ;
8082 std::vector<Stg::ModelPosition *> positionmodels;
83+ std::vector<Stg::ModelRanger *> lasermodels;
84+ std::vector<Stg::ModelRanger *> sonarmodels;
8185
8286 // a structure representing a robot inthe simulator
8387 struct StageRobot
8488 {
8589 // stage related models
8690 Stg::ModelPosition* positionmodel; // one position
8791 std::vector<Stg::ModelCamera *> cameramodels; // multiple cameras per position
88- std::vector<Stg::ModelRanger *> lasermodels; // multiple rangers per position
92+ std::vector<Stg::ModelRanger *> rangermodels; // multiple rangers per position, contains lasers and sonars
93+ std::vector<Stg::ModelRanger *> lasermodels; // multiple lasers per position
94+ std::vector<Stg::ModelRanger *> sonarmodels; // multiple sonars per position
8995
9096 // ros publishers
9197 ros::Publisher odom_pub; // one odom
@@ -95,6 +101,7 @@ class StageNode
95101 std::vector<ros::Publisher> depth_pubs; // multiple depths
96102 std::vector<ros::Publisher> camera_pubs; // multiple cameras
97103 std::vector<ros::Publisher> laser_pubs; // multiple lasers
104+ std::vector<ros::Publisher> sonar_pubs; // multiple sonars
98105
99106 ros::Subscriber cmdvel_sub; // one cmd_vel subscriber
100107 };
@@ -364,6 +371,44 @@ StageNode::SubscribeModels()
364371 new_robot->ground_truth_pub = n_.advertise <nav_msgs::Odometry>(mapName (BASE_POSE_GROUND_TRUTH, r, static_cast <Stg::Model*>(new_robot->positionmodel )), 10 );
365372 new_robot->cmdvel_sub = n_.subscribe <geometry_msgs::Twist>(mapName (CMD_VEL, r, static_cast <Stg::Model*>(new_robot->positionmodel )), 10 , boost::bind (&StageNode::cmdvelReceived, this , r, _1));
366373
374+ // break rangermodes -> lasermdoels + sonarmodels
375+ int num_lasers = 0 ;
376+ int num_sonars = 0 ;
377+ for (size_t s = 0 ; s < new_robot->rangermodels .size (); s++)
378+ {
379+ // assumed only one sensor per ranger, as Stage currently only supports this
380+ // sonar is sample_count == 1
381+ if (rangermodels[s]->GetSensors ()[0 ].sample_count == 1 )
382+ {
383+ new_robot->sonarmodels .push_back (rangermodels[s]);
384+ num_sonars++;
385+ }
386+ else
387+ {
388+ new_robot->lasermodels .push_back (rangermodels[s]);
389+ num_lasers++;
390+ }
391+ }
392+
393+ // create publishers for lasers and sonars with correct labelling
394+ // add number label on each topic with more than one device
395+ if (num_lasers == 1 )
396+ new_robot->laser_pubs .push_back (n_.advertise <sensor_msgs::LaserScan>(mapName (BASE_SCAN, r, static_cast <Stg::Model*>(new_robot->positionmodel )), 10 ));
397+ else
398+ {
399+ for (size_t s = 0 ; s < num_lasers; ++s)
400+ new_robot->laser_pubs .push_back (n_.advertise <sensor_msgs::LaserScan>(mapName (BASE_SCAN, r, s, static_cast <Stg::Model*>(new_robot->positionmodel )), 10 ));
401+ }
402+
403+ // add "/range" at end of name, need to change mapName to return string
404+ if (num_sonars == 1 )
405+ new_robot->sonar_pubs .push_back (n_.advertise <sensor_msgs::Range>(mapName (SONAR, r, static_cast <Stg::Model*>(new_robot->positionmodel )), 10 ));
406+ else
407+ {
408+ for (size_t s = 0 ; s < num_sonars; ++s)
409+ new_robot->sonar_pubs .push_back (n_.advertise <sensor_msgs::Range>(mapName (SONAR, r, s, static_cast <Stg::Model*>(new_robot->positionmodel )), 10 ));
410+ }
411+
367412 for (size_t s = 0 ; s < new_robot->lasermodels .size (); ++s)
368413 {
369414 if (new_robot->lasermodels .size () == 1 )
@@ -444,14 +489,14 @@ StageNode::WorldCallback()
444489 {
445490 StageRobot const * robotmodel = this ->robotmodels_ [r];
446491
447- // loop on the laser devices for the current robot
492+ // loop on the laser devices for the current robot
448493 for (size_t s = 0 ; s < robotmodel->lasermodels .size (); ++s)
449494 {
450495 Stg::ModelRanger const * lasermodel = robotmodel->lasermodels [s];
451496 const std::vector<Stg::ModelRanger::Sensor>& sensors = lasermodel->GetSensors ();
452497
453498 if ( sensors.size () > 1 )
454- ROS_WARN ( " ROS Stage currently supports rangers with 1 sensor only." );
499+ ROS_WARN_ONCE ( " ROS Stage currently supports rangers with 1 sensor only." );
455500
456501 // for now we access only the zeroth sensor of the ranger - good
457502 // enough for most laser models that have a single beam origin
@@ -501,6 +546,57 @@ StageNode::WorldCallback()
501546 mapName (" base_laser_link" , r, static_cast <Stg::Model*>(robotmodel->positionmodel ))));
502547 }
503548
549+ // loop on the sonar devices for the current robot
550+ for (size_t s = 0 ; s < robotmodel->sonarmodels .size (); ++s)
551+ {
552+ Stg::ModelRanger const * sonarmodel = robotmodel->sonarmodels [s];
553+ const std::vector<Stg::ModelRanger::Sensor>& sensors = sonarmodel->GetSensors ();
554+
555+ if (sensors.size () > 1 )
556+ ROS_WARN (" ROS Stage currently supports sonars with 1 sensor only." );
557+
558+ // for now we access only the zeroth sensor of the sonar - good
559+ // enough for most sonar models that have a single beam origin
560+ const Stg::ModelRanger::Sensor& sensor = sensors[0 ];
561+
562+ if (sensor.ranges .size ())
563+ {
564+ // Translate into ROS message format and publish
565+ sensor_msgs::Range msg;
566+ msg.field_of_view = sensor.fov ;
567+ msg.min_range = sensor.range .min ;
568+ msg.max_range = sensor.range .max ;
569+ msg.range = sensor.ranges [0 ];
570+
571+ // assume all are sonar, not infrared. This choice not currently in Stage
572+ msg.radiation_type = sensor_msgs::Range::ULTRASOUND;
573+
574+ if (robotmodel->sonarmodels .size () > 1 )
575+ msg.header .frame_id = mapName (" base_sonar_link" , r, s, static_cast <Stg::Model*>(robotmodel->positionmodel ));
576+ else
577+ msg.header .frame_id = mapName (" base_sonar_link" , r, static_cast <Stg::Model*>(robotmodel->positionmodel ));
578+
579+ msg.header .stamp = sim_time;
580+ robotmodel->sonar_pubs [s].publish (msg);
581+ }
582+
583+ // Also publish the base->sonar_link Tx. This could eventually move
584+ // into being retrieved from the param server as a static Tx.
585+ Stg::Pose lp = sonarmodel->GetPose ();
586+ tf::Quaternion sonarQ;
587+ sonarQ.setRPY (0.0 , 0.0 , lp.a );
588+ tf::Transform txSonar = tf::Transform (sonarQ, tf::Point (lp.x , lp.y , robotmodel->positionmodel ->GetGeom ().size .z + lp.z ));
589+
590+ if (robotmodel->sonarmodels .size () > 1 )
591+ tf.sendTransform (tf::StampedTransform (txSonar, sim_time,
592+ mapName (" base_link" , r, static_cast <Stg::Model*>(robotmodel->positionmodel )),
593+ mapName (" base_sonar_link" , r, s, static_cast <Stg::Model*>(robotmodel->positionmodel ))));
594+ else
595+ tf.sendTransform (tf::StampedTransform (txSonar, sim_time,
596+ mapName (" base_link" , r, static_cast <Stg::Model*>(robotmodel->positionmodel )),
597+ mapName (" base_sonar_link" , r, static_cast <Stg::Model*>(robotmodel->positionmodel ))));
598+ }
599+
504600 // the position of the robot
505601 tf.sendTransform (tf::StampedTransform (tf::Transform::getIdentity (),
506602 sim_time,
0 commit comments