multi_miniq_node.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 *
00003 * Software License Agreement (BSD License)
00004 *
00005 *  Copyright (c) 2012, ISR University of Coimbra.
00006 *  All rights reserved.
00007 *
00008 *  Redistribution and use in source and binary forms, with or without
00009 *  modification, are permitted provided that the following conditions
00010 *  are met:
00011 *
00012 *   * Redistributions of source code must retain the above copyright
00013 *     notice, this list of conditions and the following disclaimer.
00014 *   * Redistributions in binary form must reproduce the above
00015 *     copyright notice, this list of conditions and the following
00016 *     disclaimer in the documentation and/or other materials provided
00017 *     with the distribution.
00018 *   * Neither the name of the ISR University of Coimbra nor the names of its
00019 *     contributors may be used to endorse or promote products derived
00020 *     from this software without specific prior written permission.
00021 *
00022 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033 *  POSSIBILITY OF SUCH DAMAGE.
00034 *
00035 * Author: Gonçalo Cabrita on 03/09/2012
00036 *********************************************************************/
00037 
00038 #include <ros/ros.h>
00039 #include <tf/transform_broadcaster.h>
00040 #include <nav_msgs/Odometry.h>                  // odom
00041 #include <geometry_msgs/Twist.h>                // cmd_vel
00042 #include <lse_sensor_msgs/Nostril.h>            // nose
00043 
00044 #include "miniQ.h"
00045 
00046 // Robot data structure
00047 class Robot
00048 {
00049     public:
00050     Robot(int id) : robot(), odom_pub(), cmd_vel_sub(), prefix(), nose_pub()
00051     {
00052         robot.setId(id);
00053 
00054         prefix = "/robot_";
00055         prefix.append<int>(1, 48+id);
00056     };
00057     
00058     Robot(const Robot& r) : robot(), odom_pub(), cmd_vel_sub(), prefix(), nose_pub()
00059     {
00060         robot = r.robot;
00061 
00062         odom_pub = r.odom_pub;
00063         cmd_vel_sub = r.cmd_vel_sub;
00064         prefix = r.prefix;
00065         nose_pub = r.nose_pub;
00066     };
00067     
00068     // Robot
00069     miniQ robot;
00070     
00071     ros::Publisher odom_pub;
00072     ros::Subscriber cmd_vel_sub;
00073 
00074     ros::Publisher nose_pub;
00075 
00076     std::string prefix;
00077 };
00078 
00079 // The group of miniQs!!!
00080 std::vector<Robot> miniqs;
00081 
00082 
00083 void cmdVelReceived(int index, const geometry_msgs::Twist::ConstPtr& cmd_vel)
00084 {
00085     miniqs[index].robot.setVelocities(cmd_vel->linear.x, cmd_vel->angular.z);
00086 }
00087 
00088 
00089 int main(int argc, char** argv)
00090 {
00091         ros::init(argc, argv, "miniq_node");
00092 
00093         ROS_INFO("miniQ for ROS - Multi robot version.");
00094 
00095         ros::NodeHandle n;
00096         ros::NodeHandle pn("~");
00097     
00098         std::string port;
00099         pn.param<std::string>("port", port, "/dev/ttyUSB0");
00100         int baudrate;
00101         pn.param("baudrate", baudrate, 57600);
00102 
00103         if(!miniQ::openPort((char*)port.c_str(), baudrate))
00104         {
00105                 ROS_FATAL("miniQ -- Failed to open serial port %s at %d baud!", port.c_str(), baudrate);
00106                 ROS_BREAK();
00107         }
00108         ROS_INFO("miniQ -- Successfully connected to the miniQ!");
00109 
00110         std::vector<int> ids;
00111         
00112         // Lets load the list of robot ids...
00113         XmlRpc::XmlRpcValue list_of_ids;
00114         if( n.getParam("/list_of_ids", list_of_ids) )
00115         {   
00116                 ROS_ASSERT(list_of_ids.getType() == XmlRpc::XmlRpcValue::TypeArray);
00117         
00118                 for(int i=0 ; i<list_of_ids.size() ; ++i) 
00119                 {
00120                     ROS_ASSERT(list_of_ids[i].getType() == XmlRpc::XmlRpcValue::TypeInt);
00121                     ids.push_back(static_cast<int>(list_of_ids[i]));
00122                 }
00123         }
00124         else
00125         // If a list of ids is not defined scan for robots...
00126         {
00127                 ROS_INFO("miniQ -- A list of IDs was not provided, scanning for robots...");
00128         
00129                 for(int i=0 ; i<=10 ; i++)
00130                 {
00131                     int id = miniQ::scanForId(i);
00132                     if(id>0)
00133                     {
00134                                 ids.push_back(id);
00135                                 ROS_INFO("miniQ -- Found id %d", id);
00136                     }  
00137                 }
00138         }
00139         if(ids.size() == 0)
00140         {
00141                 ROS_FATAL("miniQ -- Could not find any miniQs!!!");
00142                 ROS_BREAK();
00143         }
00144         ROS_INFO("miniQ -- Finished scanning for robots!");
00145             
00146         for(int i=0 ; i<ids.size() ; ++i) 
00147         {
00148                 miniqs.push_back(Robot(ids[i]));
00149 
00150                 std::string odom_topic = miniqs[i].prefix;
00151                 odom_topic.append("/odom");
00152                 miniqs[i].odom_pub = n.advertise<nav_msgs::Odometry>(odom_topic, 50);
00153 
00154                 std::string cmd_vel_topic = miniqs[i].prefix;
00155                 cmd_vel_topic.append("/cmd_vel");
00156                 miniqs[i].cmd_vel_sub = n.subscribe<geometry_msgs::Twist>(cmd_vel_topic, 10, boost::bind(cmdVelReceived, i, _1) );
00157 
00158                 std::string nose_topic = miniqs[i].prefix;
00159                 nose_topic.append("/nose");
00160                 miniqs[i].nose_pub = n.advertise<lse_sensor_msgs::Nostril>(nose_topic, 20);
00161         }
00162 
00163         tf::TransformBroadcaster odom_broadcaster;
00164     
00165         ros::Time current_time;
00166 
00167         std::string frame_id;
00168         
00169         ros::Rate r(MINIQ_RATE);
00170         while(n.ok())
00171         {
00172                 current_time = ros::Time::now();
00173         
00174                 for(int i=0 ; i<miniqs.size() ; i++)
00175                 {
00176                         ros::Time start_time = ros::Time::now();
00177                         if(!miniqs[i].robot.update()) ROS_WARN("miniQ -- Failed to update the data for robot %d!!!", miniqs[i].robot.getID());
00178 
00179                         ros::Duration elapsed_time = ros::Time::now() - start_time;
00180                         //ROS_INFO("Getting the odometry for robot %d took %lf sec.", miniqs[i].robot.getID(), elapsed_time.toSec());
00181                         
00182                         double odom_x = miniqs[i].robot.getX();
00183                         double odom_y = miniqs[i].robot.getY();
00184                         double odom_yaw = miniqs[i].robot.getYaw();
00185 
00186                         //ROS_INFO("Publishing data... %lf %lf %lf", odom_x, odom_y, odom_yaw);
00187         
00188                         // Since all odometry is 6DOF we'll need a quaternion created from yaw
00189                         geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(odom_yaw);
00190         
00191                         // First, we'll publish the transform over tf
00192                         tf::Transform new_tf(tf::createQuaternionFromYaw(odom_yaw), tf::Vector3(odom_x, odom_y, 0.0));
00193                         ros::Time transform_expiration = current_time + ros::Duration(1/(MINIQ_RATE)*2.0);
00194                         std::string odom_frame_id = miniqs[i].prefix;
00195                         odom_frame_id.append("/odom");
00196                         std::string base_frame_id = miniqs[i].prefix;
00197                         base_frame_id.append("/base_link");
00198                         tf::StampedTransform odom_trans(new_tf, transform_expiration, odom_frame_id, base_frame_id);
00199         
00200                         // Send the transform
00201                         odom_broadcaster.sendTransform(odom_trans);
00202         
00203                         // Next, we'll publish the odometry message over ROS
00204                         nav_msgs::Odometry odom;
00205                         odom.header.stamp = current_time;
00206                         frame_id = miniqs[i].prefix;
00207                         frame_id.append("/odom");
00208                         odom.header.frame_id = frame_id;
00209         
00210                         // Set the position
00211                         odom.pose.pose.position.x = odom_x;
00212                         odom.pose.pose.position.y = odom_y;
00213                         odom.pose.pose.orientation = odom_quat;
00214         
00215                         // Set the velocity
00216                         frame_id = miniqs[i].prefix;
00217                         frame_id.append("/base_link");
00218                         odom.child_frame_id = frame_id;
00219                         odom.twist.twist.linear.x = miniqs[i].robot.getLinearVelocity();
00220                         odom.twist.twist.angular.z = miniqs[i].robot.getAngularVelocity();
00221         
00222                         // Publish the message
00223                         miniqs[i].odom_pub.publish(odom);
00224 
00225                         // Nose data...
00226                         lse_sensor_msgs::Nostril nose_msg; 
00227         
00228                         nose_msg.header.stamp = current_time;
00229                         nose_msg.header.frame_id = frame_id;
00230 
00231                         nose_msg.sensor_model = "e2v MiCS 5524";
00232                         nose_msg.reading = miniqs[i].robot.getGas();
00233                         nose_msg.min_reading = 0.0;
00234                         nose_msg.max_reading = 1.0;
00235                         nose_msg.clean_air = 0.0;
00236                         nose_msg.raw_data = miniqs[i].robot.getRawGas();
00237 
00238                         miniqs[i].nose_pub.publish(nose_msg);
00239 
00240                         ros::Duration((1/MINIQ_RATE)/(double)(miniqs.size())-elapsed_time.toSec()*2.0).sleep();
00241                 }
00242                 ros::spinOnce();
00243                 r.sleep();
00244         }
00245         return 0;
00246 }
00247 
00248 // EOF


lse_miniq_driver
Author(s): Gonçalo Cabrita
autogenerated on Mon Jan 6 2014 11:25:52