00001
00034 #include <string>
00035 #include <sys/types.h>
00036 #include <ifaddrs.h>
00037
00038 #include "boost/algorithm/string/predicate.hpp"
00039 #include "diagnostic_updater/update_functions.h"
00040 #include "jackal_base/jackal_diagnostic_updater.h"
00041
00042
00043 namespace jackal_base
00044 {
00045
00046 JackalDiagnosticUpdater::JackalDiagnosticUpdater()
00047 {
00048 setHardwareID("unknown");
00049
00050 add("General", this, &JackalDiagnosticUpdater::generalDiagnostics);
00051 add("Battery", this, &JackalDiagnosticUpdater::batteryDiagnostics);
00052 add("User voltage supplies", this, &JackalDiagnosticUpdater::voltageDiagnostics);
00053 add("Current consumption", this, &JackalDiagnosticUpdater::currentDiagnostics);
00054 add("Power consumption", this, &JackalDiagnosticUpdater::powerDiagnostics);
00055
00056
00057 status_sub_ = nh_.subscribe("status", 5, &JackalDiagnosticUpdater::statusCallback, this);
00058
00059
00060 ros::param::param("~expected_imu_frequency", expected_imu_frequency_, 50.0);
00061 imu_diagnostic_ = new diagnostic_updater::TopicDiagnostic("/imu/data_raw", *this,
00062 diagnostic_updater::FrequencyStatusParam(&expected_imu_frequency_, &expected_imu_frequency_, 0.15),
00063 diagnostic_updater::TimeStampStatusParam(-1, 1.0));
00064 imu_sub_ = nh_.subscribe("/imu/data_raw", 5, &JackalDiagnosticUpdater::imuCallback, this);
00065
00066 ros::param::param("~expected_navsat_frequency", expected_navsat_frequency_, 10.0);
00067 ros::param::param<std::string>("~navsat_frequency_sentence", navsat_frequency_sentence_, "$GPRMC");
00068 navsat_diagnostic_ = new diagnostic_updater::TopicDiagnostic("/navsat/nmea_sentence", *this,
00069 diagnostic_updater::FrequencyStatusParam(&expected_navsat_frequency_, &expected_navsat_frequency_, 0.1),
00070 diagnostic_updater::TimeStampStatusParam(-1, 1.0));
00071 navsat_sub_ = nh_.subscribe("/navsat/nmea_sentence", 5, &JackalDiagnosticUpdater::navsatCallback, this);
00072
00073
00074 ros::param::param<std::string>("~wireless_interface", wireless_interface_, "wlan0");
00075 ROS_INFO_STREAM("Checking for wireless connectivity on interface: " << wireless_interface_);
00076 wifi_connected_pub_ = nh_.advertise<std_msgs::Bool>("wifi_connected", 1);
00077 wireless_monitor_timer_ = nh_.createTimer(ros::Duration(1.0),
00078 &JackalDiagnosticUpdater::wirelessMonitorCallback, this);
00079 }
00080
00081 void JackalDiagnosticUpdater::generalDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
00082 {
00083 stat.add("MCU uptime (s)", last_status_->mcu_uptime.toSec());
00084 stat.addf("Motor drivers energized", "%s", last_status_->drivers_active ? "true" : "false");
00085
00086 if (last_status_->driver_external_stop_present)
00087 {
00088 if (last_status_->driver_external_stop_stopped)
00089 {
00090 stat.add("External stop", "Present, asserting stop");
00091 }
00092 else
00093 {
00094 stat.add("External stop", "Present, not asserting stop");
00095 }
00096 }
00097 else
00098 {
00099 stat.add("External stop", "Absent");
00100 }
00101
00102 if (last_status_->driver_external_stop_stopped)
00103 {
00104 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "External stop device asserting motor stop.");
00105 }
00106 else if (!last_status_->drivers_active)
00107 {
00108 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Motor drivers not energized.");
00109 }
00110 else
00111 {
00112 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "System OK.");
00113 }
00114 }
00115
00116 void JackalDiagnosticUpdater::batteryDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
00117 {
00118 stat.add("Battery Voltage (V)", last_status_->measured_battery);
00119
00120 if (last_status_->measured_battery > 30.0)
00121 {
00122 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Battery overvoltage.");
00123 }
00124 else if (last_status_->measured_battery < 1.0)
00125 {
00126 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Battery voltage not detected, check BATT fuse.");
00127 }
00128 else if (last_status_->measured_battery < 20.0)
00129 {
00130 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Battery critically under voltage.");
00131 }
00132 else if (last_status_->measured_battery < 24.0)
00133 {
00134 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Battery low voltage.");
00135 }
00136 else
00137 {
00138 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Battery OK.");
00139 }
00140 }
00141
00142 void JackalDiagnosticUpdater::voltageDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
00143 {
00144 stat.add("12V Supply (V)", last_status_->measured_12v);
00145 stat.add("5V Supply (V)", last_status_->measured_5v);
00146
00147 if (last_status_->measured_12v > 12.5 || last_status_->measured_5v > 5.5)
00148 {
00149 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR,
00150 "User supply overvoltage. Accessories may be damaged.");
00151 }
00152 else if (last_status_->measured_12v < 1.0 || last_status_->measured_5v < 1.0)
00153 {
00154 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "User supplies absent. Check tray fuses.");
00155 }
00156 else if (last_status_->measured_12v < 11.0 || last_status_->measured_5v < 4.0)
00157 {
00158 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Voltage supplies undervoltage. Check loading levels.");
00159 }
00160 else
00161 {
00162 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "User supplies OK.");
00163 }
00164 }
00165
00166 void JackalDiagnosticUpdater::currentDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
00167 {
00168 stat.add("Drive current (A)", last_status_->drive_current);
00169 stat.add("User current (A)", last_status_->user_current);
00170 stat.add("Computer current (A)", last_status_->computer_current);
00171 stat.add("Total current (A)", last_status_->total_current);
00172
00173 if (last_status_->total_current > 32.0)
00174 {
00175 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Current draw critical.");
00176 }
00177 else if (last_status_->total_current > 20.0)
00178 {
00179 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Current draw warning.");
00180 }
00181 else if (last_status_->total_current > 10.0)
00182 {
00183 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Current draw requires monitoring.");
00184 }
00185 else
00186 {
00187 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Current draw nominal.");
00188 }
00189 }
00190
00191 void JackalDiagnosticUpdater::powerDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
00192 {
00193 stat.add("Total power consumption (Wh)", last_status_->total_power_consumed);
00194
00195 if (last_status_->total_power_consumed > 260.0)
00196 {
00197 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Power consumed exceeds capacity of standard battery.");
00198 }
00199 else if (last_status_->total_power_consumed > 220.0)
00200 {
00201 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Power consumed approaches capacity of standard battery.");
00202 }
00203 else
00204 {
00205 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Battery OK.");
00206 }
00207 }
00208
00209 void JackalDiagnosticUpdater::statusCallback(const jackal_msgs::Status::ConstPtr& status)
00210 {
00211
00212 last_status_ = status;
00213 setHardwareID(last_status_->hardware_id);
00214 update();
00215 }
00216
00217 void JackalDiagnosticUpdater::imuCallback(const sensor_msgs::Imu::ConstPtr& msg)
00218 {
00219 imu_diagnostic_->tick(msg->header.stamp);
00220 }
00221
00222 void JackalDiagnosticUpdater::navsatCallback(const nmea_msgs::Sentence::ConstPtr& msg)
00223 {
00224 if (boost::starts_with(msg->sentence, navsat_frequency_sentence_))
00225 {
00226 navsat_diagnostic_->tick(msg->header.stamp);
00227 }
00228 }
00229
00230 void JackalDiagnosticUpdater::wirelessMonitorCallback(const ros::TimerEvent& te)
00231 {
00232 std_msgs::Bool wifi_connected_msg;
00233 wifi_connected_msg.data = false;
00234
00235
00236 struct ifaddrs* ifa_head;
00237 if (getifaddrs(&ifa_head) != 0)
00238 {
00239 ROS_WARN("System call getifaddrs returned error code. Unable to detect network interfaces.");
00240 return;
00241 }
00242
00243
00244 struct ifaddrs* ifa_current = ifa_head;
00245 while (ifa_current != NULL)
00246 {
00247 if (strcmp(ifa_current->ifa_name, wireless_interface_.c_str()) == 0)
00248 {
00249 int family = ifa_current->ifa_addr->sa_family;
00250 if (family == AF_INET || family == AF_INET6)
00251 {
00252 wifi_connected_msg.data = true;
00253 break;
00254 }
00255 }
00256
00257 ifa_current = ifa_current->ifa_next;
00258 }
00259
00260
00261 freeifaddrs(ifa_head);
00262 wifi_connected_pub_.publish(wifi_connected_msg);
00263 }
00264
00265 }