roomba560.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 *
00003 * Software License Agreement (BSD License)
00004 *
00005 *  Copyright (c) 2010, 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 05/10/2010
00036 *********************************************************************/
00037 #define NODE_VERSION 2.01
00038 
00039 #include <ros/ros.h>
00040 #include <tf/transform_broadcaster.h>
00041 #include <nav_msgs/Odometry.h>                          // odom
00042 #include <geometry_msgs/Twist.h>                        // cmd_vel
00043 #include <roomba_500_series/Battery.h>          // battery
00044 #include <roomba_500_series/Bumper.h>           // bumper
00045 #include <roomba_500_series/Buttons.h>          // buttons
00046 #include <roomba_500_series/RoombaIR.h>         // ir_bumper cliff
00047 #include <roomba_500_series/IRCharacter.h>      // ir_character
00048 #include <roomba_500_series/WheelDrop.h>        // wheel_drop
00049 #include <roomba_500_series/Leds.h>                     // leds
00050 #include <roomba_500_series/DigitLeds.h>        // digit_leds
00051 #include <roomba_500_series/Song.h>                     // song
00052 #include <roomba_500_series/PlaySong.h>         // play_song
00053 
00054 #include "roomba_500_series/OpenInterface.h"
00055 
00056 #include "roomba_500_series/GoDock.h"   // GoDock action
00057 
00058 #include <string>
00059 
00060 std::string port;
00061 irobot::OpenInterface * roomba;
00062 
00063 std::string prefixTopic(std::string prefix, char * name)
00064 {
00065         std::string topic_name = prefix;
00066         topic_name.append(name);
00067         
00068         return topic_name;
00069 }
00070 
00071 void cmdVelReceived(const geometry_msgs::Twist::ConstPtr& cmd_vel)
00072 {
00073         roomba->drive(cmd_vel->linear.x, cmd_vel->angular.z);
00074 }
00075 
00076 void ledsReceived(const roomba_500_series::Leds::ConstPtr& leds)
00077 {
00078         roomba->setLeds(leds->warning, leds->dock, leds->spot, leds->dirt_detect, leds->clean_color, leds->clean_intensity);
00079 }
00080 
00081 void digitLedsReceived(const roomba_500_series::DigitLeds::ConstPtr& leds)
00082 {
00083         if(leds->digits.size()!=4) return;
00084 
00085         roomba->setDigitLeds(leds->digits[3], leds->digits[2], leds->digits[1], leds->digits[0]);
00086 }
00087 
00088 void songReceived(const roomba_500_series::Song::ConstPtr& song)
00089 {
00090         unsigned char notes[song->notes.size()];
00091         unsigned char lengths[song->notes.size()];
00092 
00093         for(int i=0 ; i<song->notes.size() ; i++)
00094         {
00095                 notes[i] = song->notes[i].note;
00096                 lengths[i] = song->notes[i].length;
00097         }
00098 
00099         roomba->setSong(song->song_number, song->notes.size(), notes, lengths);
00100 }
00101 
00102 void playSongReceived(const roomba_500_series::PlaySong::ConstPtr& song)
00103 {
00104         roomba->playSong(song->song_number);
00105 }
00106 
00107 
00108 int main(int argc, char** argv)
00109 {
00110         ros::init(argc, argv, "roomba560_node");
00111 
00112         ROS_INFO("Roomba for ROS %.2f", NODE_VERSION);
00113         
00114         double last_x, last_y, last_yaw;
00115         double vel_x, vel_y, vel_yaw;
00116         double dt;
00117         float last_charge = 0.0;
00118         int time_remaining = -1;
00119         
00120         ros::NodeHandle n;
00121         ros::NodeHandle pn("~");
00122         
00123         pn.param<std::string>("port", port, "/dev/ttyUSB0");
00124         
00125         std::string base_frame_id;
00126         std::string odom_frame_id;
00127         pn.param<std::string>("base_frame_id", base_frame_id, "base_link");
00128         pn.param<std::string>("odom_frame_id", odom_frame_id, "odom");
00129         
00130         roomba = new irobot::OpenInterface(port.c_str());
00131 
00132         ros::Publisher odom_pub = n.advertise<nav_msgs::Odometry>("/odom", 50);
00133         ros::Publisher battery_pub = n.advertise<roomba_500_series::Battery>("/battery", 50);
00134         ros::Publisher bumper_pub = n.advertise<roomba_500_series::Bumper>("/bumper", 50);
00135         ros::Publisher buttons_pub = n.advertise<roomba_500_series::Buttons>("/buttons", 50);
00136         ros::Publisher cliff_pub = n.advertise<roomba_500_series::RoombaIR>("/cliff", 50);
00137         ros::Publisher irbumper_pub = n.advertise<roomba_500_series::RoombaIR>("/ir_bumper", 50);
00138         ros::Publisher irchar_pub = n.advertise<roomba_500_series::IRCharacter>("/ir_character", 50);
00139         ros::Publisher wheeldrop_pub = n.advertise<roomba_500_series::WheelDrop>("/wheel_drop", 50);
00140 
00141         tf::TransformBroadcaster tf_broadcaster;
00142         
00143         ros::Subscriber cmd_vel_sub  = n.subscribe<geometry_msgs::Twist>("/cmd_vel", 1, cmdVelReceived);
00144         ros::Subscriber leds_sub  = n.subscribe<roomba_500_series::Leds>("/leds", 1, ledsReceived);
00145         ros::Subscriber digitleds_sub  = n.subscribe<roomba_500_series::DigitLeds>("/digit_leds", 1, digitLedsReceived);
00146         ros::Subscriber song_sub  = n.subscribe<roomba_500_series::Song>("/song", 1, songReceived);
00147         ros::Subscriber playsong_sub  = n.subscribe<roomba_500_series::PlaySong>("/play_song", 1, playSongReceived);
00148         
00149         irobot::OI_Packet_ID sensor_packets[1] = {irobot::OI_PACKET_GROUP_100};
00150         roomba->setSensorPackets(sensor_packets, 1, OI_PACKET_GROUP_100_SIZE);
00151 
00152         if( roomba->openSerialPort(true) == 0) ROS_INFO("Connected to Roomba.");
00153         else
00154         {
00155                 ROS_FATAL("Could not connect to Roomba.");
00156                 ROS_BREAK();
00157         }
00158         
00159         GoDockAction go_dock("/godock");
00160 
00161         ros::Time current_time, last_time;
00162         current_time = ros::Time::now();
00163         last_time = ros::Time::now();
00164 
00165         ros::Rate r(10.0);
00166         while(n.ok())
00167         {
00168                 current_time = ros::Time::now();
00169                 
00170                 last_x = roomba->odometry_x_;
00171                 last_y = roomba->odometry_y_;
00172                 last_yaw = roomba->odometry_yaw_;
00173                 
00174                 if( roomba->getSensorPackets(100) == -1) ROS_ERROR("Could not retrieve sensor packets.");
00175                 else roomba->calculateOdometry();
00176                 
00177                 dt = (current_time - last_time).toSec();
00178                 vel_x = (roomba->odometry_x_ - last_x)/dt;
00179                 vel_y = (roomba->odometry_y_ - last_y)/dt;
00180                 vel_yaw = (roomba->odometry_yaw_ - last_yaw)/dt;
00181                 
00182                 // ******************************************************************************************
00183                 //first, we'll publish the transforms over tf
00184                 geometry_msgs::TransformStamped odom_trans;
00185                 odom_trans.header.stamp = current_time;
00186                 odom_trans.header.frame_id = odom_frame_id;
00187                 odom_trans.child_frame_id = base_frame_id;
00188                 odom_trans.transform.translation.x = roomba->odometry_x_;
00189                 odom_trans.transform.translation.y = roomba->odometry_y_;
00190                 odom_trans.transform.translation.z = 0.0;
00191                 odom_trans.transform.rotation = tf::createQuaternionMsgFromYaw(roomba->odometry_yaw_);
00192                 tf_broadcaster.sendTransform(odom_trans);
00193                 
00194                 //TODO: Finish brodcasting the tf for all the ir sensors on the Roomba
00195                 /*geometry_msgs::TransformStamped cliff_left_trans;
00196                 cliff_left_trans.header.stamp = current_time;
00197                 cliff_left_trans.header.frame_id = "base_link";
00198                 cliff_left_trans.child_frame_id = "base_cliff_left";
00199                 cliff_left_trans.transform.translation.x = 0.0;
00200                 cliff_left_trans.transform.translation.y = 0.0;
00201                 cliff_left_trans.transform.translation.z = 0.0;
00202                 cliff_left_trans.transform.rotation = ;
00203                 tf_broadcaster.sendTransform(cliff_left_trans); */
00204 
00205                 // ******************************************************************************************
00206                 //next, we'll publish the odometry message over ROS
00207                 nav_msgs::Odometry odom;
00208                 odom.header.stamp = current_time;
00209                 odom.header.frame_id = odom_frame_id;
00210                 
00211                 //set the position
00212                 odom.pose.pose.position.x = roomba->odometry_x_;
00213                 odom.pose.pose.position.y = roomba->odometry_y_;
00214                 odom.pose.pose.position.z = 0.0;
00215                 odom.pose.pose.orientation = tf::createQuaternionMsgFromYaw(roomba->odometry_yaw_);
00216                 
00217                 //set the velocity
00218                 odom.child_frame_id = base_frame_id;
00219                 odom.twist.twist.linear.x = vel_x;
00220                 odom.twist.twist.linear.y = vel_y;
00221                 odom.twist.twist.angular.z = vel_yaw;
00222                 
00223                 //publish the message
00224                 odom_pub.publish(odom);
00225 
00226                 // ******************************************************************************************
00227                 //publish battery
00228                 roomba_500_series::Battery battery;
00229                 battery.header.stamp = current_time;
00230                 battery.power_cord = roomba->power_cord_;
00231                 battery.dock = roomba->dock_;
00232                 battery.level = 100.0*(roomba->charge_/roomba->capacity_);
00233                 if(last_charge > roomba->charge_) time_remaining = (int)(battery.level/((last_charge-roomba->charge_)/roomba->capacity_)/dt)/60;
00234                 last_charge = roomba->charge_;
00235                 battery.time_remaining = time_remaining;
00236                 battery_pub.publish(battery);
00237         
00238                 // ******************************************************************************************   
00239                 //publish bumpers
00240                 roomba_500_series::Bumper bumper;
00241                 bumper.left.header.stamp = current_time;
00242                 bumper.left.state = roomba->bumper_[LEFT];
00243                 bumper.right.header.stamp = current_time;
00244                 bumper.right.state = roomba->bumper_[RIGHT];
00245                 bumper_pub.publish(bumper);
00246         
00247                 // ******************************************************************************************   
00248                 //publish buttons
00249                 roomba_500_series::Buttons buttons;
00250                 buttons.header.stamp = current_time;
00251                 buttons.clean = roomba->buttons_[BUTTON_CLEAN];
00252                 buttons.spot = roomba->buttons_[BUTTON_SPOT];
00253                 buttons.dock = roomba->buttons_[BUTTON_DOCK];
00254                 buttons.day = roomba->buttons_[BUTTON_DAY];
00255                 buttons.hour = roomba->buttons_[BUTTON_HOUR];
00256                 buttons.minute = roomba->buttons_[BUTTON_MINUTE];
00257                 buttons.schedule = roomba->buttons_[BUTTON_SCHEDULE];
00258                 buttons.clock = roomba->buttons_[BUTTON_CLOCK];
00259                 buttons_pub.publish(buttons);
00260 
00261                 // ******************************************************************************************
00262                 //publish cliff
00263                 roomba_500_series::RoombaIR cliff;
00264                 cliff.header.stamp = current_time;
00265 
00266                 cliff.header.frame_id = "base_cliff_left";
00267                 cliff.state = roomba->cliff_[LEFT];
00268                 cliff.signal = roomba->cliff_signal_[LEFT];
00269                 cliff_pub.publish(cliff);
00270 
00271                 cliff.header.frame_id = "base_cliff_front_left";
00272                 cliff.state = roomba->cliff_[FRONT_LEFT];
00273                 cliff.signal = roomba->cliff_signal_[FRONT_LEFT];
00274                 cliff_pub.publish(cliff);
00275 
00276                 cliff.header.frame_id = "base_cliff_front_right";
00277                 cliff.state = roomba->cliff_[FRONT_RIGHT];
00278                 cliff.signal = roomba->cliff_signal_[FRONT_RIGHT];
00279                 cliff_pub.publish(cliff);
00280 
00281                 cliff.header.frame_id = "base_cliff_right";
00282                 cliff.state = roomba->cliff_[RIGHT];
00283                 cliff.signal = roomba->cliff_signal_[RIGHT];
00284                 cliff_pub.publish(cliff);
00285 
00286                 // ******************************************************************************************
00287                 //publish irbumper
00288                 roomba_500_series::RoombaIR irbumper;
00289                 irbumper.header.stamp = current_time;
00290 
00291                 irbumper.header.frame_id = "base_irbumper_left";
00292                 irbumper.state = roomba->ir_bumper_[LEFT];
00293                 irbumper.signal = roomba->ir_bumper_signal_[LEFT];
00294                 irbumper_pub.publish(irbumper);
00295 
00296                 irbumper.header.frame_id = "base_irbumper_front_left";
00297                 irbumper.state = roomba->ir_bumper_[FRONT_LEFT];
00298                 irbumper.signal = roomba->ir_bumper_signal_[FRONT_LEFT];
00299                 irbumper_pub.publish(irbumper);
00300 
00301                 irbumper.header.frame_id = "base_irbumper_center_left";
00302                 irbumper.state = roomba->ir_bumper_[CENTER_LEFT];
00303                 irbumper.signal = roomba->ir_bumper_signal_[CENTER_LEFT];
00304                 irbumper_pub.publish(irbumper);
00305 
00306                 irbumper.header.frame_id = "base_irbumper_center_right";
00307                 irbumper.state = roomba->ir_bumper_[CENTER_RIGHT];
00308                 irbumper.signal = roomba->ir_bumper_signal_[CENTER_RIGHT];
00309                 irbumper_pub.publish(irbumper);
00310 
00311                 irbumper.header.frame_id = "base_irbumper_front_right";
00312                 irbumper.state = roomba->ir_bumper_[FRONT_RIGHT];
00313                 irbumper.signal = roomba->ir_bumper_signal_[FRONT_RIGHT];
00314                 irbumper_pub.publish(irbumper);
00315 
00316                 irbumper.header.frame_id = "base_irbumper_right";
00317                 irbumper.state = roomba->ir_bumper_[RIGHT];
00318                 irbumper.signal = roomba->ir_bumper_signal_[RIGHT];
00319                 irbumper_pub.publish(irbumper);
00320 
00321                 // ******************************************************************************************
00322                 //publish irchar
00323                 roomba_500_series::IRCharacter irchar;
00324                 irchar.header.stamp = current_time;
00325                 irchar.omni = roomba->ir_char_[OMNI];
00326                 irchar.left = roomba->ir_char_[LEFT];
00327                 irchar.right = roomba->ir_char_[RIGHT];
00328                 irchar_pub.publish(irchar);
00329 
00330                 // ******************************************************************************************
00331                 //publish wheeldrop
00332                 roomba_500_series::WheelDrop wheeldrop;
00333                 wheeldrop.left.header.stamp = current_time;
00334                 wheeldrop.left.state = roomba->wheel_drop_[LEFT];
00335                 wheeldrop.right.header.stamp = current_time;
00336                 wheeldrop.right.state = roomba->wheel_drop_[RIGHT];
00337                 wheeldrop_pub.publish(wheeldrop);
00338                 
00339                 ros::spinOnce();
00340                 r.sleep();
00341         }
00342         
00343         roomba->powerDown();
00344         roomba->closeSerialPort();
00345 }
00346 
00347 // EOF


roomba_500_series
Author(s): Gonçalo Cabrita
autogenerated on Mon Jan 6 2014 11:26:40