RosAria.cpp
Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <math.h>
00003 #include <Aria.h>
00004 
00005 #include "ros/ros.h"
00006 #include "geometry_msgs/Twist.h"
00007 #include "geometry_msgs/Pose.h"
00008 #include "geometry_msgs/PoseStamped.h"
00009 #include <sensor_msgs/PointCloud.h>     //for sonar data
00010 #include "nav_msgs/Odometry.h"
00011 #include "ROSARIA/BumperState.h"
00012 #include "tf/tf.h"
00013 #include "tf/transform_listener.h"      //for tf::getPrefixParam
00014 #include <tf/transform_broadcaster.h>
00015 #include "tf/transform_datatypes.h"
00016 
00017 #include <sstream>
00018 
00019 class ActionPause : public ArAction
00020 {
00021 public:
00022   // constructor, sets myMaxSpeed and myStopDistance
00023   ActionPause(double time);
00024   // destructor. does not need to do anything
00025   virtual ~ActionPause(void) {};
00026   // called by the action resolver to obtain this action's requested behavior
00027   virtual ArActionDesired *fire(ArActionDesired currentDesired);
00028 protected:
00029   double pauseTime;
00030   ArActionDesired myDesired;
00031 };
00032 
00033 ActionPause::ActionPause(double time) :
00034   ArAction("Pause")
00035 {
00036   pauseTime = time;
00037   myDesired.reset();
00038 }
00039 
00040 ArActionDesired *ActionPause::fire(ArActionDesired currentDesired)
00041 {
00042   ros::Duration(pauseTime).sleep();
00043   return &myDesired;
00044 }
00045 
00046 
00047 class RosAriaNode
00048 {
00049   public:
00050     RosAriaNode(ros::NodeHandle n);
00051     virtual ~RosAriaNode();
00052     
00053   public:
00054     int Setup();
00055     void cmdvel_cb( const geometry_msgs::TwistConstPtr &);
00056     void spin();
00057     void publish();
00058     void sonarConnectCb();
00059 
00060   protected:
00061     ros::NodeHandle n;
00062     ros::Publisher pose_pub;
00063     ros::Publisher bumpers_pub;
00064     ros::Publisher sonar_pub;
00065     ros::Subscriber cmdvel_sub;
00066                 
00067     ros::Time veltime;
00068 
00069     std::string serial_port;
00070 
00071     ArSimpleConnector *conn;
00072     ArRobot *robot;
00073     ActionPause *pause;
00074     nav_msgs::Odometry position;
00075     ROSARIA::BumperState bumpers;
00076     ArPose pos;
00077     ArFunctorC<RosAriaNode> myPublishCB;
00078                 
00079                 //for odom->base_link transform
00080                 tf::TransformBroadcaster odom_broadcaster;
00081                 geometry_msgs::TransformStamped odom_trans;
00082     //for resolving tf names.
00083     std::string tf_prefix;
00084     std::string frame_id_odom;
00085     std::string frame_id_base_link;
00086     std::string frame_id_bumper;
00087     std::string frame_id_sonar;
00088 
00089     //Sonar support
00090     bool use_sonar;             // enable and publish sonars
00091 };
00092 
00093 void RosAriaNode::sonarConnectCb()
00094 {
00095   if (sonar_pub.getNumSubscribers() == 0)
00096   {
00097     robot->disableSonar();
00098     use_sonar = false;
00099   }
00100   else
00101   {
00102     robot->enableSonar();
00103     use_sonar = true;
00104   }
00105 }
00106 
00107 RosAriaNode::RosAriaNode(ros::NodeHandle nh) : 
00108   myPublishCB(this, &RosAriaNode::publish), use_sonar(false)
00109 {
00110   // read in config options
00111   n = nh;
00112 
00113   // !!! port !!!
00114   n.param( "port", serial_port, std::string("/dev/ttyUSB0") );
00115   ROS_INFO( "using port: [%s]", serial_port.c_str() );
00116 
00117   /*
00118    * Figure out what frame_id's to use. if a tf_prefix param is specified,
00119    * it will be added to the beginning of the frame_ids.
00120    *
00121    * e.g. rosrun ... _tf_prefix:=MyRobot (or equivalently using <param>s in
00122    * roslaunch files)
00123    * will result in the frame_ids being set to /MyRobot/odom etc,
00124    * rather than /odom. This is useful for Multi Robot Systems.
00125    * See ROS Wiki for further details.
00126    */
00127   tf_prefix = tf::getPrefixParam(n);
00128   frame_id_odom = tf::resolve(tf_prefix, "odom");
00129   frame_id_base_link = tf::resolve(tf_prefix, "base_link");
00130   frame_id_bumper = tf::resolve(tf_prefix, "bumpers_frame");
00131   frame_id_sonar = tf::resolve(tf_prefix, "sonar_frame");
00132 
00133   // advertise services
00134   pose_pub = n.advertise<nav_msgs::Odometry>("pose",1000);
00135   bumpers_pub = n.advertise<ROSARIA::BumperState>("bumper_state",1000);
00136   sonar_pub = n.advertise<sensor_msgs::PointCloud>("sonar", 50, boost::bind(&RosAriaNode::sonarConnectCb, this),
00137     boost::bind(&RosAriaNode::sonarConnectCb, this));
00138   
00139   // subscribe to services
00140   cmdvel_sub = n.subscribe( "cmd_vel", 1, (boost::function < void(const geometry_msgs::TwistConstPtr&)>) boost::bind( &RosAriaNode::cmdvel_cb, this, _1 ));
00141   
00142   veltime = ros::Time::now();
00143 }
00144 
00145 RosAriaNode::~RosAriaNode()
00146 {
00147   //disable motors and sonar.
00148   robot->disableMotors();
00149   robot->disableSonar();
00150 
00151   robot->stopRunning();
00152   robot->waitForRunExit();
00153   Aria::shutdown();
00154 }
00155 
00156 int RosAriaNode::Setup()
00157 {
00158   ArArgumentBuilder *args;
00159   args = new ArArgumentBuilder();
00160 
00161   size_t colon_pos = serial_port.find(":");
00162   if (colon_pos != std::string::npos)
00163   {
00164     args->add("-rh"); //pass robot's hostname/IP address to Aria
00165     args->add(serial_port.substr(0, colon_pos).c_str());
00166     args->add("-rrtp"); //pass robot's TCP port to Aria
00167     args->add(serial_port.substr(colon_pos+1).c_str());
00168   }
00169   else
00170   {
00171     args->add("-rp"); //pass robot's serial port to Aria
00172     args->add(serial_port.c_str());
00173   }
00174   
00175   args->add("-rlpr"); //log received packets
00176   args->add("-rlps"); //log sent packets
00177   args->add("-rlvr"); //log received velocities
00178   conn = new ArSimpleConnector(args);
00179 
00180   robot = new ArRobot();
00181   pause = new ActionPause(4e-3);
00182 
00183   ArLog::init(ArLog::File, ArLog::Verbose, "aria.log", true);
00184 
00185   // Connect to the robot
00186   if (!conn->connectRobot(robot)) {
00187     ArLog::log(ArLog::Terse, "rotate: Could not connect to robot! Exiting.");
00188     return 1;
00189   }
00190 
00191   // Enable the motors
00192   robot->enableMotors();
00193 
00194   // disable sonars on startup
00195   robot->disableSonar();
00196 
00197   robot->addSensorInterpTask("PublishingTask", 100, &myPublishCB);
00198 //  robot->addAction(pause, 10);
00199   robot->runAsync(true);
00200 
00201   // Initialize bumpers with robot number of bumpers
00202   bumpers.front_bumpers.resize(robot->getNumFrontBumpers());
00203   bumpers.rear_bumpers.resize(robot->getNumRearBumpers());
00204 
00205   return 0;
00206 }
00207 
00208 void RosAriaNode::spin()
00209 {
00210   ros::spin();
00211 }
00212 
00213 void RosAriaNode::publish()
00214 {
00215 //  robot->lock();
00216   pos = robot->getPose();
00217 //  robot->unlock();
00218   tf::poseTFToMsg(tf::Transform(tf::createQuaternionFromYaw(pos.getTh()*M_PI/180), tf::Vector3(pos.getX()/1000, pos.getY()/1000, 0)), position.pose.pose); //Aria returns pose in mm.
00219   position.twist.twist.linear.x = robot->getVel()/1000; //Aria returns velocity in mm/s.
00220   position.twist.twist.angular.z = robot->getRotVel()*M_PI/180;
00221   
00222   position.header.frame_id = frame_id_odom;
00223   position.child_frame_id = frame_id_base_link;
00224   position.header.stamp = ros::Time::now();
00225   pose_pub.publish(position);
00226   ROS_INFO("rcv: %f %f %f", position.header.stamp.toSec(), (double) position.twist.twist.linear.x, (double) position.twist.twist.angular.z);
00227         
00228         // publishing transform odom->base_link
00229         odom_trans.header.stamp = ros::Time::now();
00230         odom_trans.header.frame_id = frame_id_odom;
00231         odom_trans.child_frame_id = frame_id_base_link;
00232         
00233         odom_trans.transform.translation.x = pos.getX()/1000;
00234         odom_trans.transform.translation.y = pos.getY()/1000;
00235         odom_trans.transform.translation.z = 0.0;
00236         odom_trans.transform.rotation = tf::createQuaternionMsgFromYaw(pos.getTh()*M_PI/180);
00237         
00238         odom_broadcaster.sendTransform(odom_trans);
00239         
00240   // getStallValue returns 2 bytes with stall bit and bumper bits, packed as (00 00 FrontBumpers RearBumpers)
00241   int stall = robot->getStallValue();
00242   unsigned char front_bumpers = (unsigned char)(stall >> 8);
00243   unsigned char rear_bumpers = (unsigned char)(stall);
00244 
00245   bumpers.header.frame_id = frame_id_bumper;
00246   bumpers.header.stamp = ros::Time::now();
00247 
00248   std::stringstream bumper_info(std::stringstream::out);
00249   // Bit 0 is for stall, next bits are for bumpers (leftmost is LSB)
00250   for (unsigned int i=0; i<robot->getNumFrontBumpers(); i++)
00251   {
00252     bumpers.front_bumpers[i] = (front_bumpers & (1 << (i+1))) == 0 ? 0 : 1;
00253     bumper_info << " " << (front_bumpers & (1 << (i+1)));
00254   }
00255   ROS_INFO("Front bumpers:%s", bumper_info.str().c_str());
00256 
00257   bumper_info.str("");
00258   // Rear bumpers have reverse order (rightmost is LSB)
00259   unsigned int numRearBumpers = robot->getNumRearBumpers();
00260   for (unsigned int i=0; i<numRearBumpers; i++)
00261   {
00262     bumpers.rear_bumpers[i] = (rear_bumpers & (1 << (numRearBumpers-i))) == 0 ? 0 : 1;
00263     bumper_info << " " << (rear_bumpers & (1 << (numRearBumpers-i)));
00264   }
00265   ROS_INFO("Rear bumpers:%s", bumper_info.str().c_str());
00266   
00267   bumpers_pub.publish(bumpers);
00268 
00269   /*
00270    * Publish sonar information, if necessary.
00271    */
00272   if (use_sonar) {
00273     sensor_msgs::PointCloud cloud;      //sonar readings.
00274     cloud.header.stamp = position.header.stamp; //copy time.
00275     //sonar sensors relative to base_link
00276     cloud.header.frame_id = frame_id_sonar;
00277     
00278     std::stringstream sonar_debug_info;
00279     sonar_debug_info << "Sonar readings: ";
00280     for (int i = 0; i < robot->getNumSonar(); i++) {
00281       ArSensorReading* reading = NULL;
00282       reading = robot->getSonarReading(i);
00283       if(!reading) {
00284               ROS_WARN("Did not receive a sonar reading.");
00285               continue;
00286       }
00287       
00288       //getRange() will return an integer between 0 and 5000 (5m)
00289       sonar_debug_info << reading->getRange() << " ";
00290 
00291       /*
00292        * local (x,y). Appears to be from the centre of the robot, since values may
00293        * exceed 5000. This is good, since it means we only need 1 transform.
00294        * x & y seem to be swapped though, i.e. if the robot is driving north
00295        * x is north/south and y is east/west.
00296        */
00297       //ArPose sensor = reading->getSensorPosition();   //position of sensor.
00298       // sonar_debug_info << "(" << reading->getLocalX() 
00299       //                  << ", " << reading->getLocalY()
00300       //                  << ") from (" << sensor.getX() << ", " 
00301       //                  << sensor.getY() << ") ;; " ;
00302       
00303       //add to cloud
00304       geometry_msgs::Point32 p;
00305       p.x = reading->getLocalX() / 1000.0;
00306       p.y = reading->getLocalY() / 1000.0;
00307       p.z = 0.0;
00308       cloud.points.push_back(p);
00309     }
00310     ROS_DEBUG_STREAM(sonar_debug_info.str());
00311     
00312     sonar_pub.publish(cloud);
00313   }
00314 
00315   ros::Duration(1e-3).sleep();
00316 }
00317 
00318 void
00319 RosAriaNode::cmdvel_cb( const geometry_msgs::TwistConstPtr &msg)
00320 {
00321   veltime = ros::Time::now();
00322   ROS_INFO( "new speed: [%0.2f,%0.2f](%0.3f)", msg->linear.x*1e3, msg->angular.z, veltime.toSec() );
00323 
00324 //  robot->lock();
00325   robot->setVel(msg->linear.x*1e3);
00326   robot->setRotVel(msg->angular.z*180/M_PI);
00327 //  robot->unlock();
00328   ROS_INFO("snd: %f %f %f", veltime.toSec(), (double) msg->linear.x, (double) msg->angular.z);
00329 }
00330 
00331 
00332 int main( int argc, char** argv )
00333 {
00334   ros::init(argc,argv, "RosAria");
00335   ros::NodeHandle n(std::string("~"));
00336   Aria::init();
00337 
00338   RosAriaNode *node = new RosAriaNode(n);
00339 
00340   if( node->Setup() != 0 )
00341   {
00342     printf( "setup failed... \n" );
00343     return -1;
00344   }
00345 
00346   node->spin();
00347 
00348   delete node;
00349 
00350   printf( "\nQuitting... \n" );
00351   return 0;
00352   
00353 }


ROSARIA
Author(s): Srećko Jurić-Kavelj
autogenerated on Tue Jan 7 2014 11:02:14