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 #include "diagnostics_display.h"
00037 #include <boost/algorithm/string/predicate.hpp>
00038 #include <boost/lexical_cast.hpp>
00039
00040 namespace jsk_rviz_plugins
00041 {
00042
00043 DiagnosticsDisplay::DiagnosticsDisplay()
00044 : rviz::Display(), msg_(0)
00045 {
00046 ros_topic_property_
00047 = new rviz::RosTopicProperty(
00048 "Topic", "/diagnostics_agg",
00049 ros::message_traits::datatype<diagnostic_msgs::DiagnosticArray>(),
00050 "diagnostic_msgs::DiagnosticArray topic to subscribe to.",
00051 this, SLOT( updateRosTopic() ));
00052 frame_id_property_ = new rviz::TfFrameProperty(
00053 "frame_id", rviz::TfFrameProperty::FIXED_FRAME_STRING,
00054 "the parent frame_id to visualize diagnostics",
00055 this, 0, true);
00056 diagnostics_namespace_property_ = new rviz::EditableEnumProperty(
00057 "diagnostics namespace", "/",
00058 "diagnostics namespace to visualize diagnostics",
00059 this, SLOT(updateDiagnosticsNamespace()));
00060 radius_property_ = new rviz::FloatProperty(
00061 "radius", 1.0,
00062 "radius of diagnostics circle",
00063 this, SLOT(updateRadius()));
00064 line_width_property_ = new rviz::FloatProperty(
00065 "line width", 0.03,
00066 "line width",
00067 this, SLOT(updateLineWidth()));
00068 axis_property_ = new rviz::EnumProperty(
00069 "axis", "x",
00070 "axis",
00071 this, SLOT(updateAxis()));
00072 axis_property_->addOption("x", 0);
00073 axis_property_->addOption("y", 1);
00074 axis_property_->addOption("z", 2);
00075 font_size_property_ = new rviz::FloatProperty(
00076 "font size", 0.05,
00077 "font size",
00078 this, SLOT(updateFontSize()));
00079 }
00080
00081 DiagnosticsDisplay::~DiagnosticsDisplay()
00082 {
00083 delete ros_topic_property_;
00084 delete frame_id_property_;
00085 delete diagnostics_namespace_property_;
00086 delete radius_property_;
00087 delete line_width_property_;
00088 delete axis_property_;
00089 delete line_;
00090 delete msg_;
00091 delete font_size_property_;
00092 }
00093
00094 void DiagnosticsDisplay::update(float wall_dt, float ros_dt)
00095 {
00096 if (line_update_required_) {
00097 updateLine();
00098 }
00099
00100 if (!isEnabled()) {
00101 return;
00102 }
00103
00104 msg_->setCharacterHeight(font_size_);
00105
00106 const float round_trip = 10.0;
00107 Ogre::Quaternion orientation;
00108 Ogre::Vector3 position;
00109 std::string frame_id = frame_id_property_->getFrame().toStdString();
00110 if( !context_->getFrameManager()->getTransform( frame_id,
00111 ros::Time(0.0),
00112 position, orientation ))
00113 {
00114 ROS_WARN( "Error transforming from frame '%s' to frame '%s'",
00115 frame_id.c_str(), qPrintable( fixed_frame_ ));
00116 return;
00117 }
00118 scene_node_->setPosition(position);
00119 scene_node_->setOrientation(orientation);
00120 Ogre::Vector3 orbit_position;
00121 orbit_theta_ = ros_dt / round_trip * M_PI * 2.0 + orbit_theta_;
00122 while (orbit_theta_ > M_PI * 2) {
00123 orbit_theta_ -= M_PI*2;
00124 }
00125 if (axis_ == 0) {
00126 orbit_position.x = radius_ * cos(orbit_theta_);
00127 orbit_position.y = radius_ * sin(orbit_theta_);
00128 orbit_position.z = 0;
00129 }
00130 else if (axis_ == 1) {
00131 orbit_position.y = radius_ * cos(orbit_theta_);
00132 orbit_position.z = radius_ * sin(orbit_theta_);
00133 orbit_position.x = 0;
00134 }
00135 else if (axis_ == 2) {
00136 orbit_position.z = radius_ * cos(orbit_theta_);
00137 orbit_position.x = radius_ * sin(orbit_theta_);
00138 orbit_position.y = 0;
00139 }
00140
00141 orbit_node_->setPosition(orbit_position);
00142 if (!isEnabled()) {
00143 return;
00144 }
00145 context_->queueRender();
00146 }
00147
00148 void DiagnosticsDisplay::onInitialize()
00149 {
00150 static int counter = 0;
00151 scene_node_ = scene_manager_->getRootSceneNode()->createChildSceneNode();
00152 orbit_node_ = scene_node_->createChildSceneNode();
00153 line_ = new rviz::BillboardLine(context_->getSceneManager(), scene_node_);
00154 msg_ = new rviz::MovableText("not initialized", "Arial", 0.05);
00155 msg_->setTextAlignment(rviz::MovableText::H_CENTER,
00156 rviz::MovableText::V_ABOVE);
00157 frame_id_property_->setFrameManager(context_->getFrameManager());
00158 orbit_node_->attachObject(msg_);
00159 msg_->setVisible(false);
00160 orbit_theta_ = M_PI * 2.0 / 6 * counter++;
00161 updateLineWidth();
00162 updateAxis();
00163 updateDiagnosticsNamespace();
00164 updateRadius();
00165 updateRosTopic();
00166 updateFontSize();
00167 }
00168
00169 void DiagnosticsDisplay::processMessage
00170 (const diagnostic_msgs::DiagnosticArray::ConstPtr& msg)
00171 {
00172 if (!isEnabled()) {
00173 return;
00174 }
00175
00176
00177 std::set<std::string> new_namespaces;
00178 for (size_t i = 0; i < msg->status.size(); i++) {
00179 new_namespaces.insert(msg->status[i].name);
00180 }
00181
00182 std::set<std::string> difference_namespaces;
00183 std::set_difference(namespaces_.begin(), namespaces_.end(),
00184 new_namespaces.begin(), new_namespaces.end(),
00185 std::inserter(difference_namespaces,
00186 difference_namespaces.end()));
00187 if (difference_namespaces.size() != 0) {
00188 namespaces_ = new_namespaces;
00189 fillNamespaceList();
00190 }
00191 else {
00192 difference_namespaces.clear();
00193 std::set_difference(new_namespaces.begin(), new_namespaces.end(),
00194 namespaces_.begin(), namespaces_.end(),
00195 std::inserter(difference_namespaces,
00196 difference_namespaces.end()));
00197 if (difference_namespaces.size() != 0) {
00198 namespaces_ = new_namespaces;
00199 fillNamespaceList();
00200 }
00201 }
00202
00203 if (diagnostics_namespace_.length() == 0) {
00204 return;
00205 }
00206
00207 const float alpha = 0.8;
00208 const Ogre::ColourValue OK(0.3568627450980392, 0.7529411764705882, 0.8705882352941177, alpha);
00209 const Ogre::ColourValue WARN(0.9411764705882353, 0.6784313725490196, 0.3058823529411765, alpha);
00210 const Ogre::ColourValue ERROR(0.8509803921568627, 0.3254901960784314, 0.30980392156862746, 0.5);
00211 const Ogre::ColourValue UNKNOWN(0.2, 0.2, 0.2, 0.5);
00212 Ogre::ColourValue color;
00213 std::string message;
00214 bool foundp = false;
00215 for (size_t i = 0; i < msg->status.size(); i++) {
00216 diagnostic_msgs::DiagnosticStatus status = msg->status[i];
00217 if (status.name == diagnostics_namespace_) {
00218 if (status.level == diagnostic_msgs::DiagnosticStatus::OK) {
00219 color = OK;
00220 message = status.message;
00221 }
00222 else if (status.level == diagnostic_msgs::DiagnosticStatus::WARN) {
00223 color = WARN;
00224 message = status.message;
00225 }
00226 else if (status.level == diagnostic_msgs::DiagnosticStatus::ERROR) {
00227 color = ERROR;
00228 message = status.message;
00229 }
00230 else {
00231
00232 color = UNKNOWN;
00233 message = "unknown";
00234 }
00235 foundp = true;
00236 break;
00237 }
00238 }
00239
00240 if (!foundp) {
00241 color = UNKNOWN;
00242 message = "stall";
00243 }
00244
00245 line_->setColor(color.r, color.g, color.b, color.a);
00246 Ogre::ColourValue font_color(color);
00247 font_color.a = 1.0;
00248 msg_->setColor(font_color);
00249 msg_->setCaption(diagnostics_namespace_ + "\n" + message);
00250 context_->queueRender();
00251 }
00252
00253 void DiagnosticsDisplay::updateLine()
00254 {
00255 line_->clear();
00256 line_->setLineWidth(line_width_);
00257 line_->setNumLines(1);
00258 line_->setMaxPointsPerLine(1024);
00259 for (size_t i = 0; i < 128 + 1; i++) {
00260 Ogre::Vector3 step_position;
00261 const double theta = M_PI * 2.0 / 128 * i;
00262 if (axis_ == 0) {
00263 step_position.x = radius_ * cos(theta);
00264 step_position.y = radius_ * sin(theta);
00265 step_position.z = 0.0;
00266 }
00267 else if (axis_ == 1) {
00268 step_position.y = radius_ * cos(theta);
00269 step_position.z = radius_ * sin(theta);
00270 step_position.x = 0;
00271 }
00272 else if (axis_ == 2) {
00273 step_position.z = radius_ * cos(theta);
00274 step_position.x = radius_ * sin(theta);
00275 step_position.y = 0;
00276 }
00277 line_->addPoint(step_position);
00278 }
00279 line_update_required_ = false;
00280 }
00281
00282 void DiagnosticsDisplay::onEnable()
00283 {
00284 line_update_required_ = true;
00285 msg_->setVisible(true);
00286 }
00287
00288 void DiagnosticsDisplay::onDisable()
00289 {
00290 unsubscribe();
00291 line_->clear();
00292 msg_->setVisible(false);
00293 }
00294
00295 void DiagnosticsDisplay::unsubscribe()
00296 {
00297 sub_.shutdown();
00298 }
00299
00300 void DiagnosticsDisplay::subscribe()
00301 {
00302 ros::NodeHandle n;
00303 sub_ = n.subscribe(ros_topic_property_->getTopicStd(),
00304 1,
00305 &DiagnosticsDisplay::processMessage,
00306 this);
00307 }
00308
00309 void DiagnosticsDisplay::updateRosTopic()
00310 {
00311 unsubscribe();
00312 subscribe();
00313 }
00314
00315 void DiagnosticsDisplay::updateDiagnosticsNamespace()
00316 {
00317 diagnostics_namespace_ = diagnostics_namespace_property_->getStdString();
00318 }
00319
00320 void DiagnosticsDisplay::updateRadius()
00321 {
00322 radius_ = radius_property_->getFloat();
00323 line_update_required_ = true;
00324 }
00325
00326 void DiagnosticsDisplay::updateLineWidth()
00327 {
00328 line_width_ = line_width_property_->getFloat();
00329 line_update_required_ = true;
00330 }
00331
00332
00333 void DiagnosticsDisplay::updateAxis()
00334 {
00335 axis_ = axis_property_->getOptionInt();
00336 line_update_required_ = true;
00337 }
00338
00339 void DiagnosticsDisplay::fillNamespaceList()
00340 {
00341
00342 diagnostics_namespace_property_->clearOptions();
00343 for (std::set<std::string>::iterator it = namespaces_.begin();
00344 it != namespaces_.end();
00345 it++) {
00346 diagnostics_namespace_property_->addOptionStd(*it);
00347 }
00348 diagnostics_namespace_property_->sortOptions();
00349 }
00350
00351 void DiagnosticsDisplay::updateFontSize()
00352 {
00353 font_size_ = font_size_property_->getFloat();
00354 }
00355
00356 }
00357
00358 #include <pluginlib/class_list_macros.h>
00359 PLUGINLIB_EXPORT_CLASS( jsk_rviz_plugins::DiagnosticsDisplay, rviz::Display )