00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
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>
00042 #include <geometry_msgs/Twist.h>
00043 #include <roomba_500_series/Battery.h>
00044 #include <roomba_500_series/Bumper.h>
00045 #include <roomba_500_series/Buttons.h>
00046 #include <roomba_500_series/RoombaIR.h>
00047 #include <roomba_500_series/IRCharacter.h>
00048 #include <roomba_500_series/WheelDrop.h>
00049 #include <roomba_500_series/Leds.h>
00050 #include <roomba_500_series/DigitLeds.h>
00051 #include <roomba_500_series/Song.h>
00052 #include <roomba_500_series/PlaySong.h>
00053
00054 #include "roomba_500_series/OpenInterface.h"
00055
00056 #include "roomba_500_series/GoDock.h"
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
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
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207 nav_msgs::Odometry odom;
00208 odom.header.stamp = current_time;
00209 odom.header.frame_id = odom_frame_id;
00210
00211
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
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
00224 odom_pub.publish(odom);
00225
00226
00227
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
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
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
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
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
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
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