ScitosBase.cpp
Go to the documentation of this file.
00001 #include "ScitosBase.h"
00002 
00003 
00004 //      FEATURE_BOOL = 0,  /**< A boolean feature. */
00005 //      FEATURE_INT,       /**< A integer feature. */
00006 //      FEATURE_FLOAT,     /**< A float feature. */
00007 //      FEATURE_STRING     /**< A string feature. */
00008 
00009 template<>
00010 void ScitosBase::setFeature<bool>(std::string name, bool value) {
00011         robot_->setFeatureBool(name, value);
00012 }
00013 template<>
00014 void ScitosBase::setFeature<int>(std::string name, int value) {
00015         robot_->setFeatureInt(name, value);
00016 }
00017 template<>
00018 void ScitosBase::setFeature<float>(std::string name, float value) {
00019         robot_->setFeatureFloat(name, value);
00020 }
00021 template<>
00022 void ScitosBase::setFeature<std::string>(std::string name, std::string value) {
00023         robot_->setFeatureString(name, value);
00024 }
00025 
00026 
00027 template<>
00028 bool ScitosBase::getFeature(std::string name) {
00029         bool value;
00030         robot_->getFeatureBool(name, value);
00031         return value;
00032 }
00033 template<>
00034 int ScitosBase::getFeature(std::string name) {
00035         int value;
00036         robot_->getFeatureInt(name, value);
00037         return value;
00038 }
00039 template<>
00040 float ScitosBase::getFeature(std::string name) {
00041         float value;
00042         robot_->getFeatureFloat(name, value);
00043         return value;
00044 }
00045 template<>
00046 std::string ScitosBase::getFeature(std::string name) {
00047         MString value;
00048         robot_->getFeatureString(name, value);
00049         return value;
00050 }
00051 
00052 
00053 
00054 ScitosBase::ScitosBase(const char* config_file, int pArgc, char* pArgv[], ros::NodeHandle& nh) :
00055         node_handle_(nh),
00056         dynamic_reconfigure_server_(dynamic_reconfigure_mutex_),
00057         sonar_is_requested_(false)
00058 {
00059         using namespace MetraLabs::base;
00060         using namespace MetraLabs::robotic::base;
00061         using namespace MetraLabs::robotic::robot;
00062 
00063         Error tErr;
00064 
00066         // Initialization
00067 
00068         // Create a general application object. This will also initialize
00069         // the library MetraLabsBase with the command line arguments.
00070         app_ = new Application(pArgc, pArgv);
00071         if (app_ == NULL) {
00072                 ROS_FATAL("Can't create the application!");
00073                 exit(-1);
00074         }
00075 
00076         // Get the class factory from the application
00077         class_factory_ = app_->getClassFactory();
00078         if (class_factory_ == NULL) {
00079                 ROS_FATAL("Cannot get the ClassFactory!");
00080                 exit(-1);
00081         }
00082 
00083         // Load some parameters for the robot SCITOS-G5
00084         ParameterNode tRobotCfg("RobotCfg");
00085         if ((tErr = tRobotCfg.readFromFile(config_file)) != OK) {
00086                 ROS_FATAL("Can't read parameter file. Code: %s", getErrorString(tErr).c_str());
00087                 exit(-1);
00088         }
00089 
00091 
00092         // Get the blackboard
00093         blackboard_ = app_->getBlackboard();
00094         if (blackboard_ == NULL) {
00095                 ROS_FATAL("Cannot get the Blackboard!");
00096                 exit(-1);
00097         }
00098 
00100         // Robot creation
00101 
00102         // Create the robot interface for SCITOS-G5
00103         robot_ = createInstance<Robot>(class_factory_,
00104                         "b07fb034-83c1-446c-b2df-0dd6aa46eef6");
00105         if (robot_ == NULL) {
00106                 ROS_FATAL("Failed to create the robot.");
00107                 exit(-1);
00108         }
00109 
00110         // Pre-Initialize the robot
00111         int tries = 3;
00112         while(tries-->0 && (tErr = robot_->preInitializeClient(&tRobotCfg)) != OK) {
00113                 ROS_WARN("Failed to pre-initialize the robot. Waiting and retrying..");
00114                 sleep(2);
00115         }
00116         if (tErr != OK) {
00117                 ROS_FATAL("Failed to pre-initialize the robot. Code: %s", getErrorString(tErr).c_str());
00118                 exit(-1);
00119         }
00120 
00121         // Assign robot to blackboard
00122         robot_->setPhysicalName("Robot",                  "MyRobot");
00123         robot_->setPhysicalName("BatteryState",           "MyRobot.BatteryState");
00124         robot_->setPhysicalName("Drive.Odometry",         "MyRobot.Odometry");
00125         robot_->setPhysicalName("Drive.VelocityCmd",      "MyRobot.VelocityCmd");
00126         robot_->setPhysicalName("RangeFinder.Sonar.Data", "MyRobot.Sonar");
00127         robot_->setPhysicalName("Bumper.Bumper.Data",     "MyRobot.Bumper");
00128         robot_->setPhysicalName("Bumper.Bumper.ResetCmd", "MyRobot.BumperResetCmd");
00129         if ((tErr = robot_->assignToBlackboard(blackboard_, true)) != OK) {
00130                 ROS_FATAL("Failed to assign the robot to the blackboard. Code: %s", getErrorString(tErr).c_str());
00131                 exit(-1);
00132         }
00133 
00134         // Initialize the robot
00135         if ((tErr = robot_->initializeClient(&tRobotCfg)) != OK) {
00136                 ROS_FATAL("Failed to initialize the robot. Code: %s", getErrorString(tErr).c_str());
00137                 exit(-1);
00138         }
00139 
00141         // Blackboard data: register listeners
00142 
00143         // Odometry
00144         odometry_data_ = NULL;
00145         tErr = getDataFromBlackboard<BlackboardDataOdometry>(blackboard_,
00146                         "MyRobot.Odometry", odometry_data_);
00147         if (tErr != OK) {
00148                 ROS_FATAL("Failed to get the odometry data from the blackboard. Code: %s", getErrorString(tErr).c_str());
00149                 exit(-1);
00150         }
00151         odometry_data_->addCallback(this);
00152 
00153         // Sonar
00154         sonar_data_ = NULL;
00155         tErr = getDataFromBlackboard<BlackboardDataRange>(blackboard_,
00156                         "MyRobot.Sonar", sonar_data_);
00157         if (tErr != OK) {
00158                 ROS_FATAL("Failed to get the Sonar data from the blackboard. Is it specified in the XML config? Code: %s", getErrorString(tErr).c_str());
00159 //              exit(-1);  no, let the robot start wihtout sonar, even if it wasn't specified in the XML config.
00160         } else {
00161                 sonar_data_->addCallback(this);
00162         }
00163 
00164         // Battery
00165         battery_state_data_ = NULL;
00166         tErr = getDataFromBlackboard<BlackboardDataBatteryState>(blackboard_,
00167                         "MyRobot.BatteryState", battery_state_data_);
00168         if (tErr != OK) {
00169                 ROS_FATAL("Failed to get the battery state data from the blackboard. Code: %s", getErrorString(tErr).c_str());
00170                 exit(-1);
00171         }
00172         // battery_state_data_->addCallback(this);  // replaced with diagnostics thread fetching on demand
00173 
00174         // Bumper
00175         bumper_data_ = NULL;
00176         tErr = getDataFromBlackboard<BlackboardDataBumper>(blackboard_,
00177                         "MyRobot.Bumper", bumper_data_);
00178         if (tErr != OK) {
00179                 ROS_FATAL("Failed to get the bumper data from the blackboard. Code: %s", getErrorString(tErr).c_str());
00180                 exit(-1);
00181         }
00182         bumper_data_->addCallback(this);
00183 
00185         // Blackboard data: register publishers
00186 
00187         // Bumper reset command
00188         bumper_reset_cmd_ = NULL;
00189         tErr = getDataFromBlackboard<BlackboardDataUInt8>(blackboard_,
00190                         "MyRobot.BumperResetCmd", bumper_reset_cmd_);
00191         if (tErr != OK) {
00192                 ROS_FATAL("Failed to get the bumper reset command from the blackboard. Code: %s", getErrorString(tErr).c_str());
00193                 exit(-1);
00194         }
00195 
00196         // Velocity command
00197         velocity_cmd_ = NULL;
00198         tErr = getDataFromBlackboard<BlackboardDataVelocity>(blackboard_,
00199                         "MyRobot.VelocityCmd", velocity_cmd_);
00200         if (tErr != OK) {
00201                 ROS_FATAL("Failed to get the velocity command from the blackboard. Code: %s", getErrorString(tErr).c_str());
00202                 exit(-1);
00203         }
00204 
00205 
00207         // Activate ROS interface
00208 
00209         odom_publisher_ = node_handle_.advertise<nav_msgs::Odometry>("/odom", 20);
00210         sonar_publisher_ = node_handle_.advertise<sensor_msgs::Range>("/sonar", 50);
00211         bumper_publisher_ = node_handle_.advertise<metralabs_msgs::ScitosG5Bumper>("/bumper", 20);
00212 
00213         cmd_vel_subscriber_ = node_handle_.subscribe("/cmd_vel", 1, &ScitosBase::driveCommandCallback, this);
00214         bumper_reset_subscriber_ = node_handle_.subscribe("/bumper_reset", 1, &ScitosBase::bumperResetCallback, this);
00215 
00216         // init automatic sonar de/activatior
00217         boost::thread(&ScitosBase::checkSubscribersLoop, this, ros::Rate(1));
00218 
00219 
00221         // Activation
00222 
00223         // Start the blackboard
00224         if ((tErr = blackboard_->startBlackboard()) != OK) {
00225                 ROS_FATAL("Failed to start the blackboard. Code: %s", getErrorString(tErr).c_str());
00226                 exit(-1);
00227         }
00228 
00230         // Start the robot
00231         if ((tErr = robot_->startClient()) != OK) {
00232                 ROS_FATAL("Failed to start the robot system. Code: %s", getErrorString(tErr).c_str());
00233                 exit(-1);
00234         }
00235 
00236 
00238 
00239         ROS_INFO("Starting diagnostics...");
00240 
00241         diagnostics_publisher_ = node_handle_.advertise<diagnostic_msgs::DiagnosticArray>("/diagnostics", 50);
00242         boost::thread(&ScitosBase::diagnosticsPublishingLoop, this, ros::Rate(2));
00243 
00244 
00246 
00247         ROS_INFO("Starting dynamic_reconfigure...");
00248 
00249         // update config to current hardware state
00250         metralabs_ros::ScitosG5Config config;
00251         getFeatures(config);    // The first time the read config is totally wrong, maybe it's the previous state from rosparam
00252         ROS_INFO_STREAM("This is what the first read gives... " << config.EBC1_Enable24V);
00253 //      getFeatures(config);    // It's no timing issue as far as I tested it.          TODO fix or proof as stable..
00254 
00255         // mutex needed for dynreconf.updateConfig, see non existent manual, eh I mean source
00256         boost::recursive_mutex::scoped_lock dyn_reconf_lock(dynamic_reconfigure_mutex_);
00257 //      ROS_INFO_STREAM("Updating with current config from hardware... " << config.EBC1_Enable24V);
00258         dynamic_reconfigure_server_.updateConfig(config);
00259         dyn_reconf_lock.unlock();
00260 
00261         // init reconfigure publisher
00262         boost::thread(&ScitosBase::dynamicReconfigureUpdaterLoop, this, boost::ref(dynamic_reconfigure_server_),
00263                         boost::ref(dynamic_reconfigure_mutex_), ros::Rate(2));
00264 
00265         // init reconfigure callback
00266         dynamic_reconfigure::Server<metralabs_ros::ScitosG5Config>::CallbackType dyn_reconf_callback_ptr;
00267         dyn_reconf_callback_ptr = boost::bind(&ScitosBase::dynamicReconfigureCallback, this, _1, _2);
00268         dynamic_reconfigure_server_.setCallback(dyn_reconf_callback_ptr);
00269 
00270 }
00271 
00272 ScitosBase::~ScitosBase() {
00273         setFeature(FEATURE_SONAR, false);
00274 
00275         Error tErr;
00276         if ((tErr = blackboard_->stopBlackboard()) != OK)
00277                 ROS_ERROR("Failed to stop the blackboard. Code: %s", getErrorString(tErr).c_str());
00278 
00279         // Stop the robot.
00280         if ((tErr = robot_->stopClient()) != OK)
00281                 ROS_ERROR("Failed to stop the robot system. Code: %s", getErrorString(tErr).c_str());
00282 
00283         // Destroy the robot
00284         if ((tErr = robot_->destroyClient()) != OK)
00285                 ROS_ERROR("Failed to destroy the robot system. Code: %s", getErrorString(tErr).c_str());
00286 
00287         // Delete the application object
00288         delete app_;
00289 }
00290 
00291 
00292 void ScitosBase::dynamicReconfigureCallback(metralabs_ros::ScitosG5Config& config, uint32_t level) {
00293         // I wrote this macro because I couldn't find a way to read the configs parameters generically,
00294         // and with this macro the actual feature name only has to be named once. Improvements welcome.
00295         #define MAKRO_SET_FEATURE(NAME) \
00296                 ROS_INFO("Setting feature %s to %s", #NAME, config.NAME?"True":"False"); \
00297                 setFeature(#NAME, config.NAME)
00298 
00299         MAKRO_SET_FEATURE(EBC0_Enable5V);
00300         MAKRO_SET_FEATURE(EBC0_Enable12V);
00301         MAKRO_SET_FEATURE(EBC0_Enable24V);
00302         MAKRO_SET_FEATURE(EBC1_Enable5V);
00303         MAKRO_SET_FEATURE(EBC1_Enable12V);
00304         MAKRO_SET_FEATURE(EBC1_Enable24V);
00305         MAKRO_SET_FEATURE(FreeRunMode);
00306         MAKRO_SET_FEATURE(SonarsActive);
00307         MAKRO_SET_FEATURE(StatusDisplayKnobLock);
00308         MAKRO_SET_FEATURE(StatusDisplayLED);
00309 
00310         ROS_DEBUG("Now reading again: (why is this rubbish?)"); // TODO fix me
00311         metralabs_ros::ScitosG5Config config_read;
00312         getFeatures(config_read);
00313 }
00314 
00315 void ScitosBase::getFeatures(metralabs_ros::ScitosG5Config& config) {
00316         // I wrote this macro because I couldn't find a way to read the configs parameters generically,
00317         // and with this macro the actual feature name only has to be named once. Improvements welcome.
00318         #define MAKRO_GET_FEATURE(NAME) \
00319                 ROS_DEBUG("Current hardware feature %s is %s", #NAME, config.NAME?"True":"False"); \
00320                 config.NAME = getFeature<typeof(config.NAME)>(std::string(#NAME))
00321 
00322         MAKRO_GET_FEATURE(EBC0_Enable5V);
00323         MAKRO_GET_FEATURE(EBC0_Enable12V);
00324         MAKRO_GET_FEATURE(EBC0_Enable24V);
00325         MAKRO_GET_FEATURE(EBC1_Enable5V);
00326         MAKRO_GET_FEATURE(EBC1_Enable12V);
00327         MAKRO_GET_FEATURE(EBC1_Enable24V);
00328         MAKRO_GET_FEATURE(FreeRunMode);
00329         MAKRO_GET_FEATURE(SonarsActive);
00330         MAKRO_GET_FEATURE(StatusDisplayKnobLock);
00331         MAKRO_GET_FEATURE(StatusDisplayLED);
00332 }
00333 
00334 
00335 void ScitosBase::odometryCallbackHandler() {
00336         MTime time;
00337         Pose pose;
00338         Velocity velocity;
00339         float mileage;
00340 
00341         odometry_data_->readLock();
00342         odometry_data_->getData(pose, velocity, mileage);
00343         time = odometry_data_->getTimeStamp();
00344         odometry_data_->readUnlock();
00345 
00347         ros::Time odom_time = ros::Time().fromNSec(time.getTimeValue()*1000000);
00348         double x = pose.getX();
00349         double y = pose.getY();
00350         double th = pose.getPhi();
00351         double vx = velocity.getVelocityTranslational();
00352         double vth = velocity.getVelocityRotational();
00353 
00354         // since all odometry is 6DOF we'll need a quaternion created from yaw
00355         geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(th);
00356 
00358         geometry_msgs::TransformStamped odom_tf;
00359         odom_tf.header.stamp = odom_time;
00360         odom_tf.header.frame_id = "/odom";
00361         odom_tf.child_frame_id = "/base_link";
00362 
00363         odom_tf.transform.translation.x = x;
00364         odom_tf.transform.translation.y = y;
00365         odom_tf.transform.rotation = odom_quat;
00366 
00367         // publish the transform
00368         tf_broadcaster_.sendTransform(odom_tf);
00369 
00371         nav_msgs::Odometry odom_msg;
00372         odom_msg.header.stamp = odom_time;
00373         odom_msg.header.frame_id = "/odom";
00374         odom_msg.child_frame_id = "/base_link";
00375 
00376         // set the position
00377         odom_msg.pose.pose.position.x = x;
00378         odom_msg.pose.pose.position.y = y;
00379         odom_msg.pose.pose.orientation = odom_quat;
00380 
00381         // set the velocity
00382         odom_msg.twist.twist.linear.x = vx;
00383         odom_msg.twist.twist.angular.z = vth;
00384 
00385         // publish the message
00386         odom_publisher_.publish(odom_msg);
00387 }
00388 
00389 void ScitosBase::sonarCallbackHandler() {
00390         static const RangeData::Config* sonar_config = NULL;
00391 
00392         sonar_data_->readLock();
00393         MTime timestamp = odometry_data_->getTimeStamp();
00394         const RangeData::Vector& sonar_data = sonar_data_->getRangeData();
00395         if (sonar_config == NULL)
00396                 sonar_config = sonar_data_->getConfig();
00397         sonar_data_->readUnlock();
00398 
00399         const std::vector<RangeData::Measurement> measurements = sonar_data;
00400         ros::Time sonar_time = ros::Time().fromNSec(timestamp.getTimeValue()*1000000);
00401 
00402 
00403         if(!sonar_is_requested_) {
00404                 setFeature(FEATURE_SONAR, false);
00405         } else {
00406                 if (sonar_config == NULL) {
00407                         ROS_WARN_THROTTLE(0.5, "Could not yet read sonar config.");
00408                 } else {
00409                         // if config is loaded, proceed..
00410                         const RangeData::ConfigCircularArc* sonar_config_circular =
00411                                         dynamic_cast<const RangeData::ConfigCircularArc*>(sonar_config);
00412 
00414 
00415                         // calculate transforms (once)
00416                         static std::vector<tf::Transform> sonar_transforms;
00417                         static bool sonar_transforms_calculated = false;
00418 
00419                         if(!sonar_transforms_calculated) {
00420                                 sonar_transforms_calculated = true;
00421                                 float angle = sonar_config_circular->first_sensor_angle;
00422                                 for (unsigned int i = 0; i < sonar_config_circular->sensor_cnt; ++i) {
00423                                         float x = sonar_config_circular->offset_from_center * std::cos(angle) -0.075;
00424                                         float y = sonar_config_circular->offset_from_center * std::sin(angle);
00425                                         tf::Quaternion quat;
00426                                         quat.setEuler(0, 0, angle);
00427                                         tf::Transform* transform = new tf::Transform(quat, tf::Vector3(x, y, 0.25));
00428                                         sonar_transforms.push_back(*transform);
00429                                         angle += sonar_config_circular->sensor_angle_dist;
00430                                 }
00431                                 // broadcast all transforms once
00432                                 std::vector<tf::Transform>::iterator it = sonar_transforms.begin();
00433                                 for (int i = 0; it != sonar_transforms.end(); ++it) {
00434                                         char targetframe[20];
00435                                         sprintf(targetframe, "/sonar/sonar_%02d", i++);
00436                                         tf_broadcaster_.sendTransform(
00437                                                         tf::StampedTransform(*it, sonar_time, "/base_link", targetframe)
00438                                                 );
00439                                 }
00440                         }
00441 
00443 
00444                         sensor_msgs::Range sonar_msg;
00445                         sonar_msg.header.stamp = sonar_time;
00446                         sonar_msg.radiation_type = sensor_msgs::Range::ULTRASOUND;
00447                         sonar_msg.field_of_view = sonar_config_circular->cone_angle;  // DEG_TO_RAD(15);        // from manual
00448                         sonar_msg.min_range = 0.2;      // from manual
00449                         sonar_msg.max_range = 3;        // from manual
00450 
00451                         // each time send only one sonar data and one transform to reduce repeating messages
00452                         {
00453                                 static int next_sonar_to_send = 0;
00454                                 char next_sonar_frame[20];
00455                                 sprintf(next_sonar_frame, "/sonar/sonar_%02d", next_sonar_to_send);
00456 
00457                                 // range data
00458                         //      ROS_DEBUG("Sonar #%d: value: %1.3f status: %d", next_sonar_to_send, measurements.at(next_sonar_to_send).range, measurements.at(next_sonar_to_send).err.std);
00459                                 switch(measurements.at(next_sonar_to_send).err.std) {
00460                                         case RangeData::RANGE_OKAY:
00461                                         case RangeData::RANGE_OBJECT_SOMEWHERE_IN_RANGE:
00462                                         case RangeData::RANGE_PROBABLY_OKAY:
00463                                         case RangeData::RANGE_PROBABLY_OBJECT_SOMEWHERE_IN_RANGE:
00464                                                 sonar_msg.range = measurements.at(next_sonar_to_send).range;
00465                                                 break;
00466                                         case RangeData::RANGE_NO_OBJECT_WITHIN_RANGE:
00467                                         case RangeData::RANGE_PROBABLY_NO_OBJECT_WITHIN_RANGE:
00468                                         case RangeData::RANGE_INVALID_MEASUREMENT:
00469                                         case RangeData::RANGE_ERR_SENSOR_BROKEN:
00470                                         case RangeData::RANGE_MASKED:
00471                                         default:
00472                                                 ;// TODO maybe send a zero-range message to make the old value obsolete, if that isn't useful
00473                                                 sonar_msg.range = 0;
00474                                 }
00475                                 sonar_msg.header.frame_id = next_sonar_frame;
00476                                 sonar_publisher_.publish(sonar_msg);
00477 
00478                                 // resend also one transform (the according, why not)
00479                                 tf_broadcaster_.sendTransform( tf::StampedTransform(
00480                                                 sonar_transforms.at(next_sonar_to_send), ros::Time::now(), "/base_link", next_sonar_frame ) );
00481 
00482                                 ++next_sonar_to_send %= measurements.size();
00483                         }
00484 
00485 //              this is code to send all sonar measurements at one time
00486 //                      std::vector<RangeData::Measurement>::iterator itM = measurements.begin();
00487 //                      for(int i=0; itM != measurements.end(); ++itM) {
00489 //
00490 //                              char targetframe[20];
00491 //                              sprintf(targetframe, "/sonar/sonar_%2d", i++);
00492 //                              sonar.header.frame_id = targetframe;
00493 //                              sonar.range = itM->range+1;
00494 //
00495 //                              //publish the message
00496 //                              sonar_publisher_.publish(sonar);
00497 //                      }
00498 
00499                 } // if sonar config loaded
00500         } // if sonar active
00501 }
00502 
00503 void ScitosBase::bumperDataCallbackHandler() {
00504         bumper_data_->readLock();
00505         BumperData::Vector bumper_values = bumper_data_->getBumperData();
00506         MTime timestamp = odometry_data_->getTimeStamp();
00507         bumper_data_->readUnlock();
00508 
00509         bool bumper_pressed = false;
00510         bool motor_stop = false;
00511 
00512 #define BUMPER_CODE_PUSHED 0x12
00513 #define BUMPER_CODE_LOCKED 0x02
00514 
00515         for (BumperData::Vector::const_iterator it = bumper_values.begin(); it != bumper_values.end(); ++it) {
00516                 if (*it == BUMPER_CODE_PUSHED) {
00517                         bumper_pressed = true;
00518                         motor_stop = true;
00519                         break;  // no next bumper part would change any value
00520                 }
00521                 else if (*it == BUMPER_CODE_LOCKED) {
00522                         motor_stop = true;
00523                 }
00524                 ROS_DEBUG("BumperData was: %X bumper_pressed: %d motor_stop: %d", *it, bumper_pressed, motor_stop);
00525         }
00526 
00527         metralabs_msgs::ScitosG5Bumper bumper_msg;
00528         bumper_msg.header.stamp = ros::Time().fromNSec(timestamp.getTimeValue()*1000000);
00529         bumper_msg.bumper_pressed = bumper_pressed;
00530         bumper_msg.motor_stop = motor_stop;
00531 
00532         bumper_publisher_.publish(bumper_msg);
00533 }
00534 
00535 void ScitosBase::diagnosticsPublishingLoop(ros::Rate loop_rate) {
00536         // send diagnostics message for battery state but with lower frequency
00537         // robot itself publishes with 10 Hz into Blackboard
00538         while (node_handle_.ok()) {
00539                 battery_state_data_->readLock();
00540                 MString name = static_cast<BatteryState*>(battery_state_data_)->getName();
00541                 float voltage = battery_state_data_->getVoltage();
00542                 float current = battery_state_data_->getCurrent();
00543                 int16_t charge_state = battery_state_data_->getChargeState();
00544                 int16_t remaining_time = battery_state_data_->getRemainingTime();
00545                 int16_t charger_status= battery_state_data_->getChargerStatus();
00546                 MTime timestamp = battery_state_data_->getTimeStamp();
00547                 battery_state_data_->readUnlock();
00548 
00549                 diagnostic_msgs::DiagnosticStatus battery_status;
00550                 battery_status.name = "Scitos G5: Battery";
00551                 battery_status.message = "undefined";
00552                 battery_status.hardware_id = name;
00553 
00554 // TODO do me parameters
00555 #define         VOLTAGE_ERROR_LEVEL     23              // and below
00556 #define         VOLTAGE_WARN_LEVEL      24              // and below
00557 #define         VOLTAGE_MID_LEVEL       26              // and below // above means HIGH_LEVEL
00558 #define         VOLTAGE_FULL_LEVEL      28.8    // and above
00559 #define         CHARGER_PLUGGED         1
00560 
00561                 if(voltage < VOLTAGE_ERROR_LEVEL && charger_status != CHARGER_PLUGGED)
00562                         battery_status.level = diagnostic_msgs::DiagnosticStatus::ERROR;
00563                 else if(voltage < VOLTAGE_WARN_LEVEL && charger_status != CHARGER_PLUGGED)
00564                         battery_status.level = diagnostic_msgs::DiagnosticStatus::WARN;
00565                 else
00566                         battery_status.level = diagnostic_msgs::DiagnosticStatus::OK;
00567 
00568                 // build text message
00569                 battery_status.message = "High";
00570                 if(voltage < VOLTAGE_MID_LEVEL)
00571                         battery_status.message = "Mid";
00572                 if(voltage < VOLTAGE_WARN_LEVEL)
00573                         battery_status.message = "Low";
00574                 if(voltage < VOLTAGE_ERROR_LEVEL)
00575                         battery_status.message = "Depleted";
00576                 battery_status.message += charger_status == CHARGER_PLUGGED ? ", charging" : ", discharging";
00577                 if(voltage >= VOLTAGE_FULL_LEVEL)
00578                         battery_status.message = "Fully charged";
00579 
00580                 // set values
00581                 battery_status.values.resize(5);
00582                 std::stringstream ss;
00583                 battery_status.values[0].key = "Voltage";
00584                 ss << voltage << " V";
00585                 battery_status.values[0].value = ss.str();
00586 
00587                 ss.str("");
00588                 battery_status.values[1].key = "Current";
00589                 ss << current << " A";
00590                 battery_status.values[1].value = ss.str();
00591 
00592                 ss.str("");
00593                 battery_status.values[2].key = "ChargeState";
00594                 ss << charge_state << " %";
00595                 battery_status.values[2].value = ss.str();
00596 
00597                 ss.str("");
00598                 battery_status.values[3].key = "RemainingTime";
00599                 ss << remaining_time << " min";
00600                 battery_status.values[3].value = ss.str();
00601 
00602                 battery_status.values[4].key = "ChargerStatus";
00603                 battery_status.values[4].value = charger_status == CHARGER_PLUGGED ? "plugged" : "unplugged";
00604 
00606                 diagnostic_msgs::DiagnosticArray diag_array;
00607                 diag_array.header.stamp = ros::Time().fromNSec(timestamp.getTimeValue()*1000000);
00608                 diag_array.status.push_back(battery_status);
00609                 diagnostics_publisher_.publish(diag_array);
00610 
00611                 // This will adjust as needed per iteration
00612                 loop_rate.sleep();
00613         }
00614 }
00615 
00616 void ScitosBase::checkSubscribersLoop(ros::Rate loop_rate) {
00617         // set state variable and hardware to same state
00618         sonar_is_requested_ = false;
00619         setFeature(FEATURE_SONAR, false);
00620         while (node_handle_.ok()) {
00622                 bool sonar_had_been_requested = sonar_is_requested_;
00623                 sonar_is_requested_ = sonar_publisher_.getNumSubscribers() != 0;
00624                 // this check allows to override sonar state via dynamic reconfigure and avoids overhead
00625                 if(sonar_is_requested_ != sonar_had_been_requested) {
00626                         setFeature(FEATURE_SONAR, sonar_is_requested_);
00627                         ROS_INFO_STREAM("Switching sonar feature to: " << (sonar_is_requested_ ? "enabled" : "disabled"));
00628                 }
00629                 loop_rate.sleep();
00630         }
00631 }
00632 
00633 void ScitosBase::dynamicReconfigureUpdaterLoop(
00634                 dynamic_reconfigure::Server<metralabs_ros::ScitosG5Config> &dynamic_reconfigure_server,
00635                 boost::recursive_mutex &mutex, ros::Rate loop_rate) {
00636         metralabs_ros::ScitosG5Config config;
00637         while (node_handle_.ok()) {
00638                 getFeatures(config);// update config to current hardware state
00639                 boost::recursive_mutex::scoped_lock lock(mutex);
00640                 dynamic_reconfigure_server.updateConfig(config);
00641                 lock.unlock();
00642                 loop_rate.sleep();
00643         }
00644 }


metralabs_ros
Author(s): Yianni Gatsoulis and Chris Burbridge and Lorenzo Riano and Felix Kolbe
autogenerated on Tue Jan 7 2014 11:38:56