00001 #include <tf/transform_datatypes.h>
00002 #include "create_driver/create_driver.h"
00003
00004 CreateDriver::CreateDriver(ros::NodeHandle& nh)
00005 : nh_(nh),
00006 priv_nh_("~"),
00007 diagnostics_(),
00008 model_(create::RobotModel::CREATE_2),
00009 is_running_slowly_(false)
00010 {
00011 bool create_one;
00012 std::string robot_model_name;
00013 priv_nh_.param<std::string>("dev", dev_, "/dev/ttyUSB0");
00014 priv_nh_.param<std::string>("robot_model", robot_model_name, "CREATE_2");
00015 priv_nh_.param<std::string>("base_frame", base_frame_, "base_footprint");
00016 priv_nh_.param<std::string>("odom_frame", odom_frame_, "odom");
00017 priv_nh_.param<double>("latch_cmd_duration", latch_duration_, 0.2);
00018 priv_nh_.param<double>("loop_hz", loop_hz_, 10.0);
00019 priv_nh_.param<bool>("publish_tf", publish_tf_, true);
00020
00021 if (robot_model_name == "ROOMBA_400")
00022 {
00023 model_ = create::RobotModel::ROOMBA_400;
00024 }
00025 else if (robot_model_name == "CREATE_1")
00026 {
00027 model_ = create::RobotModel::CREATE_1;
00028 }
00029 else if (robot_model_name == "CREATE_2")
00030 {
00031 model_ = create::RobotModel::CREATE_2;
00032 }
00033 else
00034 {
00035 ROS_FATAL_STREAM("[CREATE] Robot model \"" + robot_model_name + "\" is not known.");
00036 ros::shutdown();
00037 return;
00038 }
00039
00040 ROS_INFO_STREAM("[CREATE] \"" << robot_model_name << "\" selected");
00041
00042 priv_nh_.param<int>("baud", baud_, model_.getBaud());
00043
00044 robot_ = new create::Create(model_);
00045
00046 if (!robot_->connect(dev_, baud_))
00047 {
00048 ROS_FATAL("[CREATE] Failed to establish serial connection with Create.");
00049 ros::shutdown();
00050 }
00051
00052 ROS_INFO("[CREATE] Connection established.");
00053
00054
00055 robot_->setMode(create::MODE_FULL);
00056
00057
00058 ROS_INFO("[CREATE] Battery level %.2f %%", (robot_->getBatteryCharge() / robot_->getBatteryCapacity()) * 100.0);
00059
00060
00061 mode_msg_.header.frame_id = base_frame_;
00062 bumper_msg_.header.frame_id = base_frame_;
00063 charging_state_msg_.header.frame_id = base_frame_;
00064 tf_odom_.header.frame_id = odom_frame_;
00065 tf_odom_.child_frame_id = base_frame_;
00066 odom_msg_.header.frame_id = odom_frame_;
00067 odom_msg_.child_frame_id = base_frame_;
00068 joint_state_msg_.name.resize(2);
00069 joint_state_msg_.position.resize(2);
00070 joint_state_msg_.velocity.resize(2);
00071 joint_state_msg_.effort.resize(2);
00072 joint_state_msg_.name[0] = "left_wheel_joint";
00073 joint_state_msg_.name[1] = "right_wheel_joint";
00074
00075
00076 for (int i = 0; i < 36; i++)
00077 {
00078 odom_msg_.pose.covariance[i] = COVARIANCE[i];
00079 odom_msg_.twist.covariance[i] = COVARIANCE[i];
00080 }
00081
00082
00083 cmd_vel_sub_ = nh.subscribe("cmd_vel", 1, &CreateDriver::cmdVelCallback, this);
00084 debris_led_sub_ = nh.subscribe("debris_led", 10, &CreateDriver::debrisLEDCallback, this);
00085 spot_led_sub_ = nh.subscribe("spot_led", 10, &CreateDriver::spotLEDCallback, this);
00086 dock_led_sub_ = nh.subscribe("dock_led", 10, &CreateDriver::dockLEDCallback, this);
00087 check_led_sub_ = nh.subscribe("check_led", 10, &CreateDriver::checkLEDCallback, this);
00088 power_led_sub_ = nh.subscribe("power_led", 10, &CreateDriver::powerLEDCallback, this);
00089 set_ascii_sub_ = nh.subscribe("set_ascii", 10, &CreateDriver::setASCIICallback, this);
00090 dock_sub_ = nh.subscribe("dock", 10, &CreateDriver::dockCallback, this);
00091 undock_sub_ = nh.subscribe("undock", 10, &CreateDriver::undockCallback, this);
00092 define_song_sub_ = nh.subscribe("define_song", 10, &CreateDriver::defineSongCallback, this);
00093 play_song_sub_ = nh.subscribe("play_song", 10, &CreateDriver::playSongCallback, this);
00094
00095
00096 odom_pub_ = nh.advertise<nav_msgs::Odometry>("odom", 30);
00097 clean_btn_pub_ = nh.advertise<std_msgs::Empty>("clean_button", 30);
00098 day_btn_pub_ = nh.advertise<std_msgs::Empty>("day_button", 30);
00099 hour_btn_pub_ = nh.advertise<std_msgs::Empty>("hour_button", 30);
00100 min_btn_pub_ = nh.advertise<std_msgs::Empty>("minute_button", 30);
00101 dock_btn_pub_ = nh.advertise<std_msgs::Empty>("dock_button", 30);
00102 spot_btn_pub_ = nh.advertise<std_msgs::Empty>("spot_button", 30);
00103 voltage_pub_ = nh.advertise<std_msgs::Float32>("battery/voltage", 30);
00104 current_pub_ = nh.advertise<std_msgs::Float32>("battery/current", 30);
00105 charge_pub_ = nh.advertise<std_msgs::Float32>("battery/charge", 30);
00106 charge_ratio_pub_ = nh.advertise<std_msgs::Float32>("battery/charge_ratio", 30);
00107 capacity_pub_ = nh.advertise<std_msgs::Float32>("battery/capacity", 30);
00108 temperature_pub_ = nh.advertise<std_msgs::Int16>("battery/temperature", 30);
00109 charging_state_pub_ = nh.advertise<ca_msgs::ChargingState>("battery/charging_state", 30);
00110 omni_char_pub_ = nh.advertise<std_msgs::UInt16>("ir_omni", 30);
00111 mode_pub_ = nh.advertise<ca_msgs::Mode>("mode", 30);
00112 bumper_pub_ = nh.advertise<ca_msgs::Bumper>("bumper", 30);
00113 wheeldrop_pub_ = nh.advertise<std_msgs::Empty>("wheeldrop", 30);
00114 wheel_joint_pub_ = nh.advertise<sensor_msgs::JointState>("joint_states", 10);
00115
00116
00117 diagnostics_.add("Battery Status", this, &CreateDriver::updateBatteryDiagnostics);
00118 diagnostics_.add("Safety Status", this, &CreateDriver::updateSafetyDiagnostics);
00119 diagnostics_.add("Serial Status", this, &CreateDriver::updateSerialDiagnostics);
00120 diagnostics_.add("Base Mode", this, &CreateDriver::updateModeDiagnostics);
00121 diagnostics_.add("Driver Status", this, &CreateDriver::updateDriverDiagnostics);
00122
00123 diagnostics_.setHardwareID(robot_model_name);
00124
00125 ROS_INFO("[CREATE] Ready.");
00126 }
00127
00128 CreateDriver::~CreateDriver()
00129 {
00130 ROS_INFO("[CREATE] Destruct sequence initiated.");
00131 robot_->disconnect();
00132 delete robot_;
00133 }
00134
00135 void CreateDriver::cmdVelCallback(const geometry_msgs::TwistConstPtr& msg)
00136 {
00137 robot_->drive(msg->linear.x, msg->angular.z);
00138 last_cmd_vel_time_ = ros::Time::now();
00139 }
00140
00141 void CreateDriver::debrisLEDCallback(const std_msgs::BoolConstPtr& msg)
00142 {
00143 robot_->enableDebrisLED(msg->data);
00144 }
00145
00146 void CreateDriver::spotLEDCallback(const std_msgs::BoolConstPtr& msg)
00147 {
00148 robot_->enableSpotLED(msg->data);
00149 }
00150
00151 void CreateDriver::dockLEDCallback(const std_msgs::BoolConstPtr& msg)
00152 {
00153 robot_->enableDockLED(msg->data);
00154 }
00155
00156 void CreateDriver::checkLEDCallback(const std_msgs::BoolConstPtr& msg)
00157 {
00158 robot_->enableCheckRobotLED(msg->data);
00159 }
00160
00161 void CreateDriver::powerLEDCallback(const std_msgs::UInt8MultiArrayConstPtr& msg)
00162 {
00163 if (msg->data.size() < 1)
00164 {
00165 ROS_ERROR("[CREATE] No values provided to set power LED");
00166 }
00167 else
00168 {
00169 if (msg->data.size() < 2)
00170 {
00171 robot_->setPowerLED(msg->data[0]);
00172 }
00173 else
00174 {
00175 robot_->setPowerLED(msg->data[0], msg->data[1]);
00176 }
00177 }
00178 }
00179
00180 void CreateDriver::setASCIICallback(const std_msgs::UInt8MultiArrayConstPtr& msg)
00181 {
00182 bool result;
00183 if (msg->data.size() < 1)
00184 {
00185 ROS_ERROR("[CREATE] No ASCII digits provided");
00186 }
00187 else if (msg->data.size() < 2)
00188 {
00189 result = robot_->setDigitsASCII(msg->data[0], ' ', ' ', ' ');
00190 }
00191 else if (msg->data.size() < 3)
00192 {
00193 result = robot_->setDigitsASCII(msg->data[0], msg->data[1], ' ', ' ');
00194 }
00195 else if (msg->data.size() < 4)
00196 {
00197 result = robot_->setDigitsASCII(msg->data[0], msg->data[1], msg->data[2], ' ');
00198 }
00199 else
00200 {
00201 result = robot_->setDigitsASCII(msg->data[0], msg->data[1], msg->data[2], msg->data[3]);
00202 }
00203
00204 if (!result)
00205 {
00206 ROS_ERROR("[CREATE] ASCII character out of range [32, 126]");
00207 }
00208 }
00209
00210 void CreateDriver::dockCallback(const std_msgs::EmptyConstPtr& msg)
00211 {
00212 robot_->setMode(create::MODE_PASSIVE);
00213
00214 if (model_.getVersion() <= create::V_2)
00215 usleep(1000000);
00216
00217
00218 robot_->dock();
00219 }
00220
00221 void CreateDriver::undockCallback(const std_msgs::EmptyConstPtr& msg)
00222 {
00223
00224 robot_->setMode(create::MODE_FULL);
00225 }
00226
00227 void CreateDriver::defineSongCallback(const ca_msgs::DefineSongConstPtr& msg)
00228 {
00229 if (!robot_->defineSong(msg->song, msg->length, &(msg->notes.front()), &(msg->durations.front())))
00230 {
00231 ROS_ERROR_STREAM("[CREATE] Failed to define song " << msg->song << " of length " << msg->length);
00232 }
00233 }
00234
00235 void CreateDriver::playSongCallback(const ca_msgs::PlaySongConstPtr& msg)
00236 {
00237 if (!robot_->playSong(msg->song))
00238 {
00239 ROS_ERROR_STREAM("[CREATE] Failed to play song " << msg->song);
00240 }
00241 }
00242
00243 bool CreateDriver::update()
00244 {
00245 publishOdom();
00246 publishJointState();
00247 publishBatteryInfo();
00248 publishButtonPresses();
00249 publishOmniChar();
00250 publishMode();
00251 publishBumperInfo();
00252 publishWheeldrop();
00253
00254
00255 if (ros::Time::now() - last_cmd_vel_time_ >= ros::Duration(latch_duration_))
00256 {
00257 robot_->drive(0, 0);
00258 }
00259
00260 return true;
00261 }
00262
00263 void CreateDriver::updateBatteryDiagnostics(diagnostic_updater::DiagnosticStatusWrapper& stat)
00264 {
00265 const float charge = robot_->getBatteryCharge();
00266 const float capacity = robot_->getBatteryCapacity();
00267 const create::ChargingState charging_state = robot_->getChargingState();
00268 const float charge_ratio = charge / capacity;
00269
00270 if (charging_state == create::CHARGE_FAULT)
00271 {
00272 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Charging fault reported by base");
00273 }
00274 else if (charge_ratio == 0)
00275 {
00276 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Battery reports no charge");
00277 }
00278 else if (charge_ratio < 0.1)
00279 {
00280 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Battery reports less than 10% charge");
00281 }
00282 else
00283 {
00284 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Battery is OK");
00285 }
00286
00287 stat.add("Charge (Ah)", charge);
00288 stat.add("Capacity (Ah)", capacity);
00289 stat.add("Temperature (Celsius)", robot_->getTemperature());
00290 stat.add("Current (A)", robot_->getCurrent());
00291 stat.add("Voltage (V)", robot_->getVoltage());
00292
00293 switch (charging_state)
00294 {
00295 case create::CHARGE_NONE:
00296 stat.add("Charging state", "Not charging");
00297 break;
00298 case create::CHARGE_RECONDITION:
00299 stat.add("Charging state", "Reconditioning");
00300 break;
00301 case create::CHARGE_FULL:
00302 stat.add("Charging state", "Full charge");
00303 break;
00304 case create::CHARGE_TRICKLE:
00305 stat.add("Charging state", "Trickle charging");
00306 break;
00307 case create::CHARGE_WAITING:
00308 stat.add("Charging state", "Waiting");
00309 break;
00310 case create::CHARGE_FAULT:
00311 stat.add("Charging state", "Fault");
00312 break;
00313 }
00314 }
00315
00316 void CreateDriver::updateSafetyDiagnostics(diagnostic_updater::DiagnosticStatusWrapper& stat)
00317 {
00318 const bool is_wheeldrop = robot_->isWheeldrop();
00319 const bool is_cliff = robot_->isCliff();
00320 if (is_wheeldrop)
00321 {
00322 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Wheeldrop detected");
00323 }
00324 else if (is_cliff)
00325 {
00326 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Cliff detected");
00327 }
00328 else
00329 {
00330 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "No safety issues detected");
00331 }
00332
00333 stat.add("Wheeldrop", is_wheeldrop);
00334 stat.add("Cliff", is_cliff);
00335 }
00336
00337 void CreateDriver::updateSerialDiagnostics(diagnostic_updater::DiagnosticStatusWrapper& stat)
00338 {
00339 const bool is_connected = robot_->connected();
00340 const uint64_t corrupt_packets = robot_->getNumCorruptPackets();
00341 const uint64_t total_packets = robot_->getTotalPackets();
00342
00343 if (!is_connected)
00344 {
00345 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Serial port to base not open");
00346 }
00347 else if (corrupt_packets)
00348 {
00349 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN,
00350 "Corrupt packets detected. If the number of corrupt packets is increasing, data may be unreliable");
00351 }
00352 else
00353 {
00354 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Serial connection is good");
00355 }
00356
00357 stat.add("Corrupt packets", corrupt_packets);
00358 stat.add("Total packets", total_packets);
00359 }
00360
00361 void CreateDriver::updateModeDiagnostics(diagnostic_updater::DiagnosticStatusWrapper& stat)
00362 {
00363 const create::CreateMode mode = robot_->getMode();
00364 switch (mode)
00365 {
00366 case create::MODE_UNAVAILABLE:
00367 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Unknown mode of operation");
00368 break;
00369 case create::MODE_OFF:
00370 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Mode is set to OFF");
00371 break;
00372 case create::MODE_PASSIVE:
00373 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Mode is set to PASSIVE");
00374 break;
00375 case create::MODE_SAFE:
00376 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Mode is set to SAFE");
00377 break;
00378 case create::MODE_FULL:
00379 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Mode is set to FULL");
00380 break;
00381 }
00382 }
00383
00384 void CreateDriver::updateDriverDiagnostics(diagnostic_updater::DiagnosticStatusWrapper& stat)
00385 {
00386 if (is_running_slowly_)
00387 {
00388 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Internal loop running slowly");
00389 }
00390 else
00391 {
00392 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Maintaining loop frequency");
00393 }
00394 }
00395
00396 void CreateDriver::publishOdom()
00397 {
00398 create::Pose pose = robot_->getPose();
00399 create::Vel vel = robot_->getVel();
00400
00401
00402 geometry_msgs::Quaternion quat = tf::createQuaternionMsgFromRollPitchYaw(0, 0, pose.yaw);
00403 odom_msg_.header.stamp = ros::Time::now();
00404 odom_msg_.pose.pose.position.x = pose.x;
00405 odom_msg_.pose.pose.position.y = pose.y;
00406 odom_msg_.pose.pose.orientation = quat;
00407
00408
00409 odom_msg_.twist.twist.linear.x = vel.x;
00410 odom_msg_.twist.twist.linear.y = vel.y;
00411 odom_msg_.twist.twist.angular.z = vel.yaw;
00412
00413
00414 odom_msg_.pose.covariance[0] = (double) pose.covariance[0];
00415 odom_msg_.pose.covariance[1] = pose.covariance[1];
00416 odom_msg_.pose.covariance[5] = pose.covariance[2];
00417 odom_msg_.pose.covariance[6] = pose.covariance[3];
00418 odom_msg_.pose.covariance[7] = pose.covariance[4];
00419 odom_msg_.pose.covariance[11] = pose.covariance[5];
00420 odom_msg_.pose.covariance[30] = pose.covariance[6];
00421 odom_msg_.pose.covariance[31] = pose.covariance[7];
00422 odom_msg_.pose.covariance[35] = pose.covariance[8];
00423 odom_msg_.twist.covariance[0] = vel.covariance[0];
00424 odom_msg_.twist.covariance[1] = vel.covariance[1];
00425 odom_msg_.twist.covariance[5] = vel.covariance[2];
00426 odom_msg_.twist.covariance[6] = vel.covariance[3];
00427 odom_msg_.twist.covariance[7] = vel.covariance[4];
00428 odom_msg_.twist.covariance[11] = vel.covariance[5];
00429 odom_msg_.twist.covariance[30] = vel.covariance[6];
00430 odom_msg_.twist.covariance[31] = vel.covariance[7];
00431 odom_msg_.twist.covariance[35] = vel.covariance[8];
00432
00433 if (publish_tf_)
00434 {
00435 tf_odom_.header.stamp = ros::Time::now();
00436 tf_odom_.transform.translation.x = pose.x;
00437 tf_odom_.transform.translation.y = pose.y;
00438 tf_odom_.transform.rotation = quat;
00439 tf_broadcaster_.sendTransform(tf_odom_);
00440 }
00441
00442 odom_pub_.publish(odom_msg_);
00443 }
00444
00445 void CreateDriver::publishJointState() {
00446
00447 float wheelRadius = model_.getWheelDiameter() / 2.0;
00448
00449 joint_state_msg_.header.stamp = ros::Time::now();
00450 joint_state_msg_.position[0] = robot_->getLeftWheelDistance() / wheelRadius;
00451 joint_state_msg_.position[1] = robot_->getRightWheelDistance() / wheelRadius;
00452 joint_state_msg_.velocity[0] = robot_->getRequestedLeftWheelVel() / wheelRadius;
00453 joint_state_msg_.velocity[1] = robot_->getRequestedRightWheelVel() / wheelRadius;
00454 wheel_joint_pub_.publish(joint_state_msg_);
00455 }
00456
00457 void CreateDriver::publishBatteryInfo()
00458 {
00459 float32_msg_.data = robot_->getVoltage();
00460 voltage_pub_.publish(float32_msg_);
00461 float32_msg_.data = robot_->getCurrent();
00462 current_pub_.publish(float32_msg_);
00463 float32_msg_.data = robot_->getBatteryCharge();
00464 charge_pub_.publish(float32_msg_);
00465 float32_msg_.data = robot_->getBatteryCapacity();
00466 capacity_pub_.publish(float32_msg_);
00467 int16_msg_.data = robot_->getTemperature();
00468 temperature_pub_.publish(int16_msg_);
00469 float32_msg_.data = robot_->getBatteryCharge() / robot_->getBatteryCapacity();
00470 charge_ratio_pub_.publish(float32_msg_);
00471
00472 const create::ChargingState charging_state = robot_->getChargingState();
00473 charging_state_msg_.header.stamp = ros::Time::now();
00474 switch (charging_state)
00475 {
00476 case create::CHARGE_NONE:
00477 charging_state_msg_.state = charging_state_msg_.CHARGE_NONE;
00478 break;
00479 case create::CHARGE_RECONDITION:
00480 charging_state_msg_.state = charging_state_msg_.CHARGE_RECONDITION;
00481 break;
00482
00483 case create::CHARGE_FULL:
00484 charging_state_msg_.state = charging_state_msg_.CHARGE_FULL;
00485 break;
00486
00487 case create::CHARGE_TRICKLE:
00488 charging_state_msg_.state = charging_state_msg_.CHARGE_TRICKLE;
00489 break;
00490
00491 case create::CHARGE_WAITING:
00492 charging_state_msg_.state = charging_state_msg_.CHARGE_WAITING;
00493 break;
00494
00495 case create::CHARGE_FAULT:
00496 charging_state_msg_.state = charging_state_msg_.CHARGE_FAULT;
00497 break;
00498 }
00499 charging_state_pub_.publish(charging_state_msg_);
00500 }
00501
00502 void CreateDriver::publishButtonPresses() const
00503 {
00504 if (robot_->isCleanButtonPressed())
00505 {
00506 clean_btn_pub_.publish(empty_msg_);
00507 }
00508 if (robot_->isDayButtonPressed())
00509 {
00510 day_btn_pub_.publish(empty_msg_);
00511 }
00512 if (robot_->isHourButtonPressed())
00513 {
00514 hour_btn_pub_.publish(empty_msg_);
00515 }
00516 if (robot_->isMinButtonPressed())
00517 {
00518 min_btn_pub_.publish(empty_msg_);
00519 }
00520 if (robot_->isDockButtonPressed())
00521 {
00522 dock_btn_pub_.publish(empty_msg_);
00523 }
00524 if (robot_->isSpotButtonPressed())
00525 {
00526 spot_btn_pub_.publish(empty_msg_);
00527 }
00528 }
00529
00530 void CreateDriver::publishOmniChar()
00531 {
00532 uint8_t ir_char = robot_->getIROmni();
00533 uint16_msg_.data = ir_char;
00534 omni_char_pub_.publish(uint16_msg_);
00535
00536 }
00537
00538 void CreateDriver::publishMode()
00539 {
00540 const create::CreateMode mode = robot_->getMode();
00541 mode_msg_.header.stamp = ros::Time::now();
00542 switch (mode)
00543 {
00544 case create::MODE_OFF:
00545 mode_msg_.mode = mode_msg_.MODE_OFF;
00546 break;
00547 case create::MODE_PASSIVE:
00548 mode_msg_.mode = mode_msg_.MODE_PASSIVE;
00549 break;
00550 case create::MODE_SAFE:
00551 mode_msg_.mode = mode_msg_.MODE_SAFE;
00552 break;
00553 case create::MODE_FULL:
00554 mode_msg_.mode = mode_msg_.MODE_FULL;
00555 break;
00556 default:
00557 ROS_ERROR("[CREATE] Unknown mode detected");
00558 break;
00559 }
00560 mode_pub_.publish(mode_msg_);
00561 }
00562
00563 void CreateDriver::publishBumperInfo()
00564 {
00565 bumper_msg_.header.stamp = ros::Time::now();
00566 bumper_msg_.is_left_pressed = robot_->isLeftBumper();
00567 bumper_msg_.is_right_pressed = robot_->isRightBumper();
00568
00569 if (model_.getVersion() >= create::V_3)
00570 {
00571 bumper_msg_.is_light_left = robot_->isLightBumperLeft();
00572 bumper_msg_.is_light_front_left = robot_->isLightBumperFrontLeft();
00573 bumper_msg_.is_light_center_left = robot_->isLightBumperCenterLeft();
00574 bumper_msg_.is_light_right = robot_->isLightBumperRight();
00575 bumper_msg_.is_light_front_right = robot_->isLightBumperFrontRight();
00576 bumper_msg_.is_light_center_right = robot_->isLightBumperCenterRight();
00577
00578 bumper_msg_.light_signal_left = robot_->getLightSignalLeft();
00579 bumper_msg_.light_signal_front_left = robot_->getLightSignalFrontLeft();
00580 bumper_msg_.light_signal_center_left = robot_->getLightSignalCenterLeft();
00581 bumper_msg_.light_signal_right = robot_->getLightSignalRight();
00582 bumper_msg_.light_signal_front_right = robot_->getLightSignalFrontRight();
00583 bumper_msg_.light_signal_center_right = robot_->getLightSignalCenterRight();
00584 }
00585
00586 bumper_pub_.publish(bumper_msg_);
00587 }
00588
00589 void CreateDriver::publishWheeldrop()
00590 {
00591 if (robot_->isWheeldrop())
00592 wheeldrop_pub_.publish(empty_msg_);
00593 }
00594
00595 void CreateDriver::spinOnce()
00596 {
00597 update();
00598 diagnostics_.update();
00599 ros::spinOnce();
00600 }
00601
00602 void CreateDriver::spin()
00603 {
00604 ros::Rate rate(loop_hz_);
00605 while (ros::ok())
00606 {
00607 spinOnce();
00608
00609 is_running_slowly_ = !rate.sleep();
00610 if (is_running_slowly_)
00611 {
00612 ROS_WARN("[CREATE] Loop running slowly.");
00613 }
00614 }
00615 }
00616
00617 int main(int argc, char** argv)
00618 {
00619 ros::init(argc, argv, "ca_driver");
00620 ros::NodeHandle nh;
00621
00622 CreateDriver create_driver(nh);
00623
00624 try
00625 {
00626 create_driver.spin();
00627 }
00628 catch (std::runtime_error& ex)
00629 {
00630 ROS_FATAL_STREAM("[CREATE] Runtime error: " << ex.what());
00631 return 1;
00632 }
00633 return 0;
00634 }