stdr_robot.cpp
Go to the documentation of this file.
00001 /******************************************************************************
00002    STDR Simulator - Simple Two DImensional Robot Simulator
00003    Copyright (C) 2013 STDR Simulator
00004    This program is free software; you can redistribute it and/or modify
00005    it under the terms of the GNU General Public License as published by
00006    the Free Software Foundation; either version 3 of the License, or
00007    (at your option) any later version.
00008    This program is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011    GNU General Public License for more details.
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software Foundation,
00014    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 
00016    Authors :
00017    * Manos Tsardoulias, etsardou@gmail.com
00018    * Aris Thallas, aris.thallas@gmail.com
00019    * Chris Zalidis, zalidis@gmail.com
00020 ******************************************************************************/
00021 
00022 #include <stdr_robot/stdr_robot.h>
00023 #include <nodelet/NodeletUnload.h>
00024 #include <pluginlib/class_list_macros.h>
00025 
00026 PLUGINLIB_EXPORT_CLASS(stdr_robot::Robot, nodelet::Nodelet)
00027 
00028 namespace stdr_robot
00029 {
00034   Robot::Robot(void)
00035   {
00036 
00037   }
00038 
00043   void Robot::onInit()
00044   {
00045     ros::NodeHandle n = getMTNodeHandle();
00046 
00047     _odomPublisher = n.advertise<nav_msgs::Odometry>(getName() + "/odom", 10);
00048 
00049     _registerClientPtr.reset(
00050       new RegisterRobotClient(n, "stdr_server/register_robot", true) );
00051 
00052     _registerClientPtr->waitForServer();
00053 
00054     stdr_msgs::RegisterRobotGoal goal;
00055     goal.name = getName();
00056     _registerClientPtr->sendGoal(goal,
00057       boost::bind(&Robot::initializeRobot, this, _1, _2));
00058 
00059     _mapSubscriber = n.subscribe("map", 1, &Robot::mapCallback, this);
00060     _moveRobotService = n.advertiseService(
00061       getName() + "/replace", &Robot::moveRobotCallback, this);
00062 
00063     //we should not start the timer, until we hame a motion controller
00064     _tfTimer = n.createTimer(
00065       ros::Duration(0.1), &Robot::publishTransforms, this, false, false);
00066   }
00067 
00074   void Robot::initializeRobot(
00075     const actionlib::SimpleClientGoalState& state,
00076     const stdr_msgs::RegisterRobotResultConstPtr result)
00077   {
00078 
00079     if (state == state.ABORTED) {
00080       NODELET_ERROR("Something really bad happened...");
00081       return;
00082     }
00083 
00084     NODELET_INFO("Loaded new robot, %s", getName().c_str());
00085     ros::NodeHandle n = getMTNodeHandle();
00086 
00087     _currentPose = result->description.initialPose;
00088 
00089     _previousPose = _currentPose;
00090 
00091     for ( unsigned int laserIter = 0;
00092       laserIter < result->description.laserSensors.size(); laserIter++ )
00093     {
00094       _sensors.push_back( SensorPtr(
00095         new Laser( _map,
00096           result->description.laserSensors[laserIter], getName(), n ) ) );
00097     }
00098     for ( unsigned int sonarIter = 0;
00099       sonarIter < result->description.sonarSensors.size(); sonarIter++ )
00100     {
00101       _sensors.push_back( SensorPtr(
00102         new Sonar( _map,
00103           result->description.sonarSensors[sonarIter], getName(), n ) ) );
00104     }
00105     for ( unsigned int rfidReaderIter = 0;
00106       rfidReaderIter < result->description.rfidSensors.size(); 
00107         rfidReaderIter++ )
00108     {
00109       _sensors.push_back( SensorPtr(
00110         new RfidReader( _map,
00111           result->description.rfidSensors[rfidReaderIter], getName(), n ) ) );
00112     }
00113     for ( unsigned int co2SensorIter = 0;
00114       co2SensorIter < result->description.co2Sensors.size(); 
00115         co2SensorIter++ )
00116     {
00117       _sensors.push_back( SensorPtr(
00118         new CO2Sensor( _map,
00119           result->description.co2Sensors[co2SensorIter], getName(), n ) ) );
00120     }
00121     for ( unsigned int thermalSensorIter = 0;
00122       thermalSensorIter < result->description.thermalSensors.size(); 
00123         thermalSensorIter++ )
00124     {
00125       _sensors.push_back( SensorPtr(
00126         new ThermalSensor( _map,
00127           result->description.thermalSensors[thermalSensorIter], getName(), n ) ) );
00128     }
00129     for ( unsigned int soundSensorIter = 0;
00130       soundSensorIter < result->description.soundSensors.size(); 
00131         soundSensorIter++ )
00132     {
00133       _sensors.push_back( SensorPtr(
00134         new SoundSensor( _map,
00135           result->description.soundSensors[soundSensorIter], getName(), n ) ) );
00136     }
00137 
00138     if( result->description.footprint.points.size() == 0 ) {
00139       float radius = result->description.footprint.radius;
00140       for(unsigned int i = 0 ; i < 360 ; i++)
00141       {
00142         float x = cos(i * 3.14159265359 / 180.0) * radius;
00143         float y = sin(i * 3.14159265359 / 180.0) * radius;
00144         _footprint.push_back( std::pair<float,float>(x,y));
00145       }
00146     } else {
00147       for( unsigned int i = 0 ;
00148           i < result->description.footprint.points.size() ; 
00149           i++ ) {
00150         geometry_msgs::Point p = result->description.footprint.points[i];
00151         _footprint.push_back( std::pair<float,float>(p.x, p.y));
00152       }
00153     }
00154 
00155     _motionControllerPtr.reset(
00156       new IdealMotionController(_currentPose, _tfBroadcaster, n, getName()));
00157 
00158     _tfTimer.start();
00159   }
00160 
00166   void Robot::mapCallback(const nav_msgs::OccupancyGridConstPtr& msg)
00167   {
00168     _map = *msg;
00169   }
00170 
00177   bool Robot::moveRobotCallback(stdr_msgs::MoveRobot::Request& req,
00178                 stdr_msgs::MoveRobot::Response& res)
00179   {
00180     if( collisionExistsNoPath(req.newPose) ||
00181         checkUnknownOccupancy(req.newPose) )
00182     {
00183       return false;
00184     }
00185     
00186     _currentPose = req.newPose;
00187 
00188     _previousPose = _currentPose;
00189 
00190     _motionControllerPtr->setPose(_previousPose);
00191     return true;
00192   }
00193 
00198   bool Robot::collisionExistsNoPath(
00199     const geometry_msgs::Pose2D& newPose)
00200   {
00201     if(_map.info.width == 0 || _map.info.height == 0)
00202     {
00203       return false;
00204     }
00205 
00206     int xMap = newPose.x / _map.info.resolution;
00207     int yMap = newPose.y / _map.info.resolution;
00208 
00209     for(unsigned int i = 0 ; i < _footprint.size() ; i++)
00210     {
00211       double x = _footprint[i].first * cos(newPose.theta) -
00212                  _footprint[i].second * sin(newPose.theta);
00213       double y = _footprint[i].first * sin(newPose.theta) +
00214                  _footprint[i].second * cos(newPose.theta);
00215                  
00216       int xx = xMap + (int)(x / _map.info.resolution);
00217       int yy = yMap + (int)(y / _map.info.resolution);
00218 
00219       if(_map.data[ yy * _map.info.width + xx ] > 70)
00220       {
00221         return true;
00222       }
00223     }
00224     return false;
00225   }
00226 
00232   bool Robot::checkUnknownOccupancy(
00233     const geometry_msgs::Pose2D& newPose)
00234   {
00235     if(_map.info.width == 0 || _map.info.height == 0)
00236     {
00237       return false;
00238     }
00239 
00240     int xMap = newPose.x / _map.info.resolution;
00241     int yMap = newPose.y / _map.info.resolution;
00242 
00243     if( _map.data[ yMap * _map.info.width + xMap ] == -1 )
00244     {
00245       return true;
00246     }
00247 
00248     return false;
00249   }
00250   
00259   std::vector<std::pair<int,int> > Robot::getPointsBetween(
00260     int x1, int y1, int x2, int y2) 
00261   {
00262     std::vector<std::pair<int,int> > points;
00263     
00264     float angle = atan2(y2 - y1, x2 - x1);
00265     float dist = sqrt( pow(x2 - x1, 2) + pow(y2 - y1, 2));
00266     
00267     int d = 0;
00268 
00269     while(d < dist)
00270     {
00271       int x = x1 + d * cos(angle);
00272       int y = y1 + d * sin(angle);
00273       points.push_back(std::pair<int,int>(x,y));
00274       d++;
00275     }
00276     
00277     return points;
00278   }
00279 
00284   bool Robot::collisionExists(
00285     const geometry_msgs::Pose2D& newPose,
00286     const geometry_msgs::Pose2D& previousPose)
00287   {
00288     if(_map.info.width == 0 || _map.info.height == 0)
00289       return false;
00290 
00291     int xMapPrev, xMap, yMapPrev, yMap;
00292     bool movingForward, movingUpward;
00293 
00294     //Check robot's previous direction to prevent getting stuck when colliding
00295     movingForward = _previousMovementXAxis? false: true;
00296     if ( fabs(previousPose.x - newPose.x) > 0.001)
00297     {
00298       movingForward = (previousPose.x > newPose.x)? false: true;
00299       _previousMovementXAxis = movingForward;
00300     }
00301     movingUpward = _previousMovementYAxis? false: true;
00302     if ( fabs(previousPose.y - newPose.y) > 0.001)
00303     {
00304       movingUpward = (previousPose.y > newPose.y)? false: true;
00305       _previousMovementYAxis = movingUpward;
00306     }
00307 
00308     xMapPrev = movingForward? (int)( previousPose.x / _map.info.resolution ):
00309                               ceil( previousPose.x / _map.info.resolution );
00310     xMap = movingForward? ceil( newPose.x / _map.info.resolution ):
00311                           (int)( newPose.x / _map.info.resolution );
00312 
00313     yMapPrev = movingUpward? (int)( previousPose.y / _map.info.resolution ):
00314                               ceil( previousPose.y / _map.info.resolution );
00315     yMap = movingUpward? ceil( newPose.y / _map.info.resolution ):
00316                         (int)( newPose.y / _map.info.resolution );
00317 
00318     float angle = atan2(yMap - yMapPrev, xMap - xMapPrev);
00319     int x = xMapPrev;
00320     int y = yMapPrev;
00321     int d = 2;
00322 
00323     while(pow(xMap - x,2) + pow(yMap - y,2) > 1)
00324     {
00325       x = xMapPrev +
00326         ( movingForward? ceil( cos(angle) * d ): (int)( cos(angle) * d ) );
00327       y = yMapPrev +
00328         ( movingUpward? ceil( sin(angle) * d ): (int)( sin(angle) * d ) );
00329       //Check all footprint points
00330       for(unsigned int i = 0 ; i < _footprint.size() ; i++)
00331       {
00332         int index_1 = i;
00333         int index_2 = (i + 1) % _footprint.size();
00334         
00335         // Get two consecutive footprint points
00336         double footprint_x_1 = _footprint[index_1].first * cos(newPose.theta) -
00337                    _footprint[index_1].second * sin(newPose.theta);
00338         double footprint_y_1 = _footprint[index_1].first * sin(newPose.theta) +
00339                    _footprint[index_1].second * cos(newPose.theta);
00340 
00341         int xx1 = x + footprint_x_1 / _map.info.resolution;
00342         int yy1 = y + footprint_y_1 / _map.info.resolution;
00343         
00344         double footprint_x_2 = _footprint[index_2].first * cos(newPose.theta) -
00345                    _footprint[index_2].second * sin(newPose.theta);
00346         double footprint_y_2 = _footprint[index_2].first * sin(newPose.theta) +
00347                    _footprint[index_2].second * cos(newPose.theta);
00348 
00349         int xx2 = x + footprint_x_2 / _map.info.resolution;
00350         int yy2 = y + footprint_y_2 / _map.info.resolution;
00351         
00352         //Here check all the points between the vertexes
00353         std::vector<std::pair<int,int> > pts = 
00354           getPointsBetween(xx1,yy1,xx2,yy2);
00355         
00356         for(unsigned int j = 0 ; j < pts.size() ; j++)
00357         {
00358           static int OF = 1;
00359           if(
00360             _map.data[ (pts[j].second - OF) * 
00361               _map.info.width + pts[j].first - OF ] > 70 ||
00362             _map.data[ (pts[j].second - OF) * 
00363               _map.info.width + pts[j].first ] > 70 ||
00364             _map.data[ (pts[j].second - OF) *  
00365               _map.info.width + pts[j].first + OF ] > 70 ||
00366             _map.data[ (pts[j].second) * 
00367               _map.info.width + pts[j].first - OF ] > 70 ||
00368             _map.data[ (pts[j].second) * 
00369               _map.info.width + pts[j].first + OF ] > 70 ||
00370             _map.data[ (pts[j].second + OF) * 
00371               _map.info.width + pts[j].first - OF ] > 70 ||
00372             _map.data[ (pts[j].second + OF) * 
00373               _map.info.width + pts[j].first ] > 70 ||
00374             _map.data[ (pts[j].second + OF) * 
00375               _map.info.width + pts[j].first + OF ] > 70
00376           )
00377           {
00378             return true;
00379           }
00380         }
00381       }
00382       if ( (movingForward && xMap < x) || (movingUpward && yMap < y) ||
00383           (!movingForward && xMap > x) || (!movingUpward && yMap > y) )
00384       {
00385         break;
00386       }
00387       d++;
00388     }
00389     return false;
00390   }
00391 
00396   void Robot::publishTransforms(const ros::TimerEvent&)
00397   {
00398     geometry_msgs::Pose2D pose = _motionControllerPtr->getPose();
00399     if( ! collisionExists(pose, _previousPose) )
00400     {
00401       _previousPose = pose;
00402     }
00403     else
00404     {
00405       _motionControllerPtr->setPose(_previousPose);
00406     }
00408     tf::Vector3 translation(_previousPose.x, _previousPose.y, 0);
00409     tf::Quaternion rotation;
00410     rotation.setRPY(0, 0, _previousPose.theta);
00411 
00412     tf::Transform mapToRobot(rotation, translation);
00413 
00414     _tfBroadcaster.sendTransform(tf::StampedTransform(
00415       mapToRobot, ros::Time::now(), "map_static", getName()));
00416 
00418     nav_msgs::Odometry odom;
00419     odom.header.stamp = ros::Time::now();
00420     odom.header.frame_id = "map_static";
00421     odom.child_frame_id = getName();
00422     odom.pose.pose.position.x = _previousPose.x;
00423     odom.pose.pose.position.y = _previousPose.y;
00424     odom.pose.pose.orientation = tf::createQuaternionMsgFromYaw(
00425         _previousPose.theta);
00426     odom.twist.twist = _motionControllerPtr->getVelocity();
00427 
00428     _odomPublisher.publish(odom);
00429 
00431     for (int i = 0; i < _sensors.size(); i++) {
00432       geometry_msgs::Pose2D sensorPose = _sensors[i]->getSensorPose();
00433 
00434       tf::Vector3 trans(sensorPose.x, sensorPose.y, 0);
00435       tf::Quaternion rot;
00436       rot.setRPY(0, 0, sensorPose.theta);
00437 
00438       tf::Transform robotToSensor(rot, trans);
00439 
00440       _tfBroadcaster.sendTransform(
00441         tf::StampedTransform(
00442           robotToSensor,
00443           ros::Time::now(),
00444           getName(),
00445           _sensors[i]->getFrameId()));
00446     }
00447   }
00448 
00453   Robot::~Robot()
00454   {
00456   }
00457 
00458 }  // namespace stdr_robot


stdr_robot
Author(s): Manos Tsardoulias, Chris Zalidis, Aris Thallas
autogenerated on Wed Sep 2 2015 03:36:25