Go to the documentation of this file.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 #ifndef DIAGNOSTICUPDATER_HH
00036 #define DIAGNOSTICUPDATER_HH
00037
00038 #include <stdexcept>
00039 #include <vector>
00040 #include <string>
00041
00042 #include "ros/node_handle.h"
00043 #include "ros/this_node.h"
00044
00045 #include "diagnostic_msgs/DiagnosticArray.h"
00046 #include "diagnostic_updater/DiagnosticStatusWrapper.h"
00047
00048 #include <boost/thread.hpp>
00049
00050 namespace diagnostic_updater
00051 {
00052
00053 typedef boost::function<void(DiagnosticStatusWrapper&)> TaskFunction;
00054 typedef boost::function<void(diagnostic_msgs::DiagnosticStatus&)> UnwrappedTaskFunction;
00055
00065 class DiagnosticTask
00066 {
00067 public:
00071 DiagnosticTask(const std::string name) : name_(name)
00072 {}
00073
00077 const std::string &getName()
00078 {
00079 return name_;
00080 }
00081
00085 virtual void run(diagnostic_updater::DiagnosticStatusWrapper &stat) = 0;
00086
00090 virtual ~DiagnosticTask()
00091 {}
00092
00093 private:
00094 const std::string name_;
00095 };
00096
00106 template <class T>
00107 class GenericFunctionDiagnosticTask : public DiagnosticTask
00108 {
00109 public:
00118 GenericFunctionDiagnosticTask(const std::string &name, boost::function<void(T&)> fn) :
00119 DiagnosticTask(name), fn_(fn)
00120 {}
00121
00122 virtual void run(DiagnosticStatusWrapper &stat)
00123 {
00124 fn_(stat);
00125 }
00126
00127 private:
00128 const std::string name_;
00129 const TaskFunction fn_;
00130 };
00131
00132 typedef GenericFunctionDiagnosticTask<diagnostic_msgs::DiagnosticStatus> UnwrappedFunctionDiagnosticTask;
00133 typedef GenericFunctionDiagnosticTask<DiagnosticStatusWrapper> FunctionDiagnosticTask;
00134
00146 class CompositeDiagnosticTask : public DiagnosticTask
00147 {
00148 public:
00152 CompositeDiagnosticTask(const std::string name) : DiagnosticTask(name)
00153 {}
00154
00158 virtual void run(DiagnosticStatusWrapper &stat)
00159 {
00160 DiagnosticStatusWrapper combined_summary;
00161 DiagnosticStatusWrapper original_summary;
00162
00163 original_summary.summary(stat);
00164
00165 for (std::vector<DiagnosticTask *>::iterator i = tasks_.begin();
00166 i != tasks_.end(); i++)
00167 {
00168
00169 stat.summary(original_summary);
00170
00171 (*i)->run(stat);
00172
00173 combined_summary.mergeSummary(stat);
00174 }
00175
00176
00177 stat.summary(combined_summary);
00178 }
00179
00186 void addTask(DiagnosticTask *t)
00187 {
00188 tasks_.push_back(t);
00189 }
00190
00191 private:
00192 std::vector<DiagnosticTask *> tasks_;
00193 };
00194
00203 class DiagnosticTaskVector
00204 {
00205 protected:
00210 class DiagnosticTaskInternal
00211 {
00212 public:
00213 DiagnosticTaskInternal(const std::string name, TaskFunction f) :
00214 name_(name), fn_(f)
00215 {}
00216
00217 void run(diagnostic_updater::DiagnosticStatusWrapper &stat) const
00218 {
00219 stat.name = name_;
00220 fn_(stat);
00221 }
00222
00223 const std::string &getName() const
00224 {
00225 return name_;
00226 }
00227
00228 private:
00229 std::string name_;
00230 TaskFunction fn_;
00231 };
00232
00233 boost::mutex lock_;
00234
00238 const std::vector<DiagnosticTaskInternal> &getTasks()
00239 {
00240 return tasks_;
00241 }
00242
00243 public:
00256 void add(const std::string &name, TaskFunction f)
00257 {
00258 DiagnosticTaskInternal int_task(name, f);
00259 addInternal(int_task);
00260 }
00261
00270 void add(DiagnosticTask &task)
00271 {
00272 TaskFunction f = boost::bind(&DiagnosticTask::run, &task, _1);
00273 add(task.getName(), f);
00274 }
00275
00289 template <class T>
00290 void add(const std::string name, T *c, void (T::*f)(diagnostic_updater::DiagnosticStatusWrapper&))
00291 {
00292 DiagnosticTaskInternal int_task(name, boost::bind(f, c, _1));
00293 addInternal(int_task);
00294 }
00295
00296
00308 bool removeByName(const std::string name)
00309 {
00310 boost::mutex::scoped_lock lock(lock_);
00311 for (std::vector<DiagnosticTaskInternal>::iterator iter = tasks_.begin();
00312 iter != tasks_.end(); iter++)
00313 {
00314 if (iter->getName() == name)
00315 {
00316 tasks_.erase(iter);
00317 return true;
00318 }
00319
00320 diagnostic_updater::DiagnosticStatusWrapper status;
00321 }
00322 return false;
00323 }
00324
00325 private:
00331 virtual void addedTaskCallback(DiagnosticTaskInternal &)
00332 {}
00333 std::vector<DiagnosticTaskInternal> tasks_;
00334
00335 protected:
00339 void addInternal(DiagnosticTaskInternal &task)
00340 {
00341 boost::mutex::scoped_lock lock(lock_);
00342 tasks_.push_back(task);
00343 addedTaskCallback(task);
00344 }
00345 };
00346
00362 class Updater : public DiagnosticTaskVector
00363 {
00364 public:
00365 bool verbose_;
00366
00373 Updater()
00374 {
00375 setup();
00376 }
00377
00382 void update()
00383 {
00384 ros::Time now_time = ros::Time::now();
00385 if (now_time < next_time_) {
00386
00387 return;
00388 }
00389
00390 force_update();
00391 }
00392
00399 void force_update()
00400 {
00401 update_diagnostic_period();
00402
00403 next_time_ = ros::Time::now() + ros::Duration().fromSec(period_);
00404
00405 if (node_handle_.ok())
00406 {
00407 bool warn_nohwid = hwid_.empty();
00408
00409 std::vector<diagnostic_msgs::DiagnosticStatus> status_vec;
00410
00411 boost::mutex::scoped_lock lock(lock_);
00412 const std::vector<DiagnosticTaskInternal> &tasks = getTasks();
00413 for (std::vector<DiagnosticTaskInternal>::const_iterator iter = tasks.begin();
00414 iter != tasks.end(); iter++)
00415 {
00416 diagnostic_updater::DiagnosticStatusWrapper status;
00417
00418 status.name = iter->getName();
00419 status.level = 2;
00420 status.message = "No message was set";
00421 status.hardware_id = hwid_;
00422
00423 iter->run(status);
00424
00425 status_vec.push_back(status);
00426
00427 if (status.level)
00428 warn_nohwid = false;
00429
00430 if (verbose_ && status.level)
00431 ROS_WARN("Non-zero diagnostic status. Name: '%s', status %i: '%s'", status.name.c_str(), status.level, status.message.c_str());
00432 }
00433
00434 if (warn_nohwid && !warn_nohwid_done_)
00435 {
00436 ROS_WARN("diagnostic_updater: No HW_ID was set. This is probably a bug. Please report it. For devices that do not have a HW_ID, set this value to 'none'. This warning only occurs once all diagnostics are OK so it is okay to wait until the device is open before calling setHardwareID.");
00437 warn_nohwid_done_ = true;
00438 }
00439
00440 publish(status_vec);
00441 }
00442 }
00443
00448 double getPeriod()
00449 {
00450 return period_;
00451 }
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00476 void broadcast(int lvl, const std::string msg)
00477 {
00478 std::vector<diagnostic_msgs::DiagnosticStatus> status_vec;
00479
00480 const std::vector<DiagnosticTaskInternal> &tasks = getTasks();
00481 for (std::vector<DiagnosticTaskInternal>::const_iterator iter = tasks.begin();
00482 iter != tasks.end(); iter++)
00483 {
00484 diagnostic_updater::DiagnosticStatusWrapper status;
00485
00486 status.name = iter->getName();
00487 status.summary(lvl, msg);
00488
00489 status_vec.push_back(status);
00490 }
00491
00492 publish(status_vec);
00493 }
00494
00495 void setHardwareIDf(const char *format, ...)
00496 {
00497 va_list va;
00498 char buff[1000];
00499 va_start(va, format);
00500 if (vsnprintf(buff, 1000, format, va) >= 1000)
00501 ROS_DEBUG("Really long string in diagnostic_updater::setHardwareIDf.");
00502 hwid_ = std::string(buff);
00503 va_end(va);
00504 }
00505
00506 void setHardwareID(const std::string &hwid)
00507 {
00508 hwid_ = hwid;
00509 }
00510
00511 private:
00516 void update_diagnostic_period()
00517 {
00518 double old_period = period_;
00519 private_node_handle_.getParamCached("diagnostic_period", period_);
00520 next_time_ += ros::Duration(period_ - old_period);
00521 }
00522
00526 void publish(diagnostic_msgs::DiagnosticStatus &stat)
00527 {
00528 std::vector<diagnostic_msgs::DiagnosticStatus> status_vec;
00529 status_vec.push_back(stat);
00530 publish(status_vec);
00531 }
00532
00536 void publish(std::vector<diagnostic_msgs::DiagnosticStatus> &status_vec)
00537 {
00538 for (std::vector<diagnostic_msgs::DiagnosticStatus>::iterator
00539 iter = status_vec.begin(); iter != status_vec.end(); iter++)
00540 {
00541 iter->name =
00542 ros::this_node::getName().substr(1) + std::string(": ") + iter->name;
00543 }
00544 diagnostic_msgs::DiagnosticArray msg;
00545 msg.status = status_vec;
00546 msg.header.stamp = ros::Time::now();
00547 publisher_.publish(msg);
00548 }
00549
00553 void setup()
00554 {
00555 publisher_ = node_handle_.advertise<diagnostic_msgs::DiagnosticArray>("/diagnostics", 1);
00556 private_node_handle_ = ros::NodeHandle("~");
00557
00558 period_ = 1.0;
00559 update_diagnostic_period();
00560 next_time_ = ros::Time::now();
00561
00562 verbose_ = false;
00563 warn_nohwid_done_ = false;
00564 }
00565
00570 virtual void addedTaskCallback(DiagnosticTaskInternal &task)
00571 {
00572 DiagnosticStatusWrapper stat;
00573 stat.name = task.getName();
00574 stat.summary(0, "Node starting up");
00575 publish(stat);
00576 }
00577
00578 ros::NodeHandle private_node_handle_;
00579 ros::NodeHandle node_handle_;
00580 ros::Publisher publisher_;
00581
00582 ros::Time next_time_;
00583
00584 double period_;
00585 std::string hwid_;
00586 bool warn_nohwid_done_;
00587 };
00588
00589 };
00590
00591 #endif