00001
00002 #include <iostream>
00003 #include <vector>
00004 #include <unistd.h>
00005 #include <stdlib.h>
00006 #include <time.h>
00007 #include <boost/shared_ptr.hpp>
00008 #include <boost/bind.hpp>
00009 #include <boost/ref.hpp>
00010 #include <boost/program_options.hpp>
00011 #include <boost/thread/thread.hpp>
00012
00013 #include <log4cxx/logger.h>
00014
00015 #include "ocean.h"
00016 #include "ros/ros.h"
00017 #include "diagnostic_msgs/DiagnosticArray.h"
00018 #include "diagnostic_msgs/DiagnosticStatus.h"
00019 #include "diagnostic_updater/DiagnosticStatusWrapper.h"
00020 #include "rosconsole/macros_generated.h"
00021 #include "pr2_msgs/BatteryServer.h"
00022
00023 using namespace std;
00024 using namespace ros;
00025 using namespace willowgarage::ocean;
00026 namespace po = boost::program_options;
00027
00028 static const float BATTERY_TEMP_WARN = 50.0;
00029
00030 float toFloat(const int &value)
00031 {
00032 int tmp = value;
00033 if(tmp & 0x8000)
00034 tmp = tmp - 65536;
00035 float result = tmp / 1000.0;
00036 return result;
00037 }
00038
00039 float tempToCelcius(const int &iKelvin)
00040 {
00041 float fKelvin = (float) (iKelvin * 0.1);
00042 return (fKelvin - (float) 273.15);
00043 }
00044
00045 class server
00046 {
00047 public:
00048
00049 server( const int &majorID, const std::string &dev, const int debug_level = 0 ) :
00050 majorID(majorID), debug_level(debug_level), serial_device("/dev/ttyUSB0"), stopRequest(false),
00051 has_warned_temp_alarm_(false), has_warned_no_good_(false)
00052 {
00053 std::stringstream ss;
00054
00055 ros::NodeHandle private_handle("~");
00056
00057 if(dev.empty())
00058 {
00059 string tmp_device;
00060 ss.str("");
00061 ss << "/dev/ttyUSB" << majorID;
00062 serial_device = ss.str();
00063
00064 ss.str("");
00065 ss << "port" << majorID;
00066 bool result = private_handle.getParam( ss.str(), tmp_device );
00067 if(result == true)
00068 {
00069 ROS_INFO("Using %s from getParam.\n", ss.str().c_str());
00070 serial_device = tmp_device;
00071 }
00072 else
00073 ROS_INFO("Defaulting to: %s", serial_device.c_str());
00074
00075 }
00076 else
00077 {
00078 ROS_INFO("Overriding device with argument: %s", dev.c_str() );
00079 serial_device = dev;
00080 }
00081
00082 private_handle.param("lag_timeout", lag_timeout_, 60);
00083 private_handle.param("stale_timeout", stale_timeout_, 120);
00084
00085
00086
00087
00088
00089 }
00090
00091 void start()
00092 {
00093 myThread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&server::run, this)));
00094 }
00095
00096
00097 void stop()
00098 {
00099 stopRequest = true;
00100 myThread->join();
00101 }
00102
00103 private:
00104
00105 ros::NodeHandle handle;
00106 int majorID;
00107 int debug_level;
00108 std::string serial_device;
00109 volatile bool stopRequest;
00110 boost::shared_ptr<boost::thread> myThread;
00111 int lag_timeout_, stale_timeout_;
00112 bool has_warned_temp_alarm_, has_warned_no_good_;
00113
00114 void run()
00115 {
00116 std::stringstream ss;
00117
00118
00119
00120
00121
00122 ros::Publisher pub = handle.advertise<diagnostic_msgs::DiagnosticArray>("/diagnostics", 10);
00123 ros::Publisher bs2 = handle.advertise<pr2_msgs::BatteryServer2>("battery/server2", 10);
00124 ros::Publisher bs = handle.advertise<pr2_msgs::BatteryServer>("battery/server", 10);
00125
00126 ros::Rate rate(100);
00127 diagnostic_msgs::DiagnosticArray msg_out;
00128 diagnostic_updater::DiagnosticStatusWrapper stat;
00129 Time lastTime, currentTime, startTime;
00130 Duration MESSAGE_TIME(2,0);
00131 ocean os( majorID, debug_level);
00132 os.initialize(serial_device.c_str());
00133
00134
00135 pr2_msgs::BatteryServer oldserver;
00136 oldserver.battery.resize(4);
00137
00138 lastTime = Time::now();
00139 startTime = Time::now();
00140
00141 while(handle.ok() && (stopRequest == false))
00142 {
00143 rate.sleep();
00144
00145 currentTime = Time::now();
00146
00147 if((os.run() > 0) && ((currentTime - lastTime) > MESSAGE_TIME))
00148 {
00149
00150
00151 os.server.header.stamp = ros::Time::now();
00152 bs2.publish(os.server);
00153
00154 oldserver.id = os.server.id;
00155 oldserver.lastTimeSystem = os.server.last_system_update.sec;
00156 oldserver.timeLeft = os.server.time_left.toSec()/60;
00157 oldserver.averageCharge = os.server.average_charge;
00158 oldserver.message = os.server.message;
00159 oldserver.lastTimeController = os.server.last_controller_update.sec;
00160 oldserver.present = os.server.battery[0].present * 1 + os.server.battery[1].present * 2 + os.server.battery[2].present * 4 + os.server.battery[3].present * 8;
00161 oldserver.charging = os.server.battery[0].charging * 1 + os.server.battery[1].charging * 2 + os.server.battery[2].charging * 4 + os.server.battery[3].charging * 8;
00162 oldserver.discharging = os.server.battery[0].discharging * 1 + os.server.battery[1].discharging * 2 + os.server.battery[2].discharging * 4 + os.server.battery[3].discharging * 8;
00163
00164 oldserver.powerPresent = os.server.battery[0].power_present * 1 + os.server.battery[1].power_present * 2 + os.server.battery[2].power_present * 4 + os.server.battery[3].power_present * 8;
00165 oldserver.powerNG = os.server.battery[0].power_no_good * 1 + os.server.battery[1].power_no_good * 2 + os.server.battery[2].power_no_good * 4 + os.server.battery[3].power_no_good * 8;
00166 oldserver.inhibited = os.server.battery[0].inhibited * 1 + os.server.battery[1].inhibited * 2 + os.server.battery[2].inhibited * 4 + os.server.battery[3].inhibited * 8;
00167
00168 for(int xx = 0; xx < os.server.MAX_BAT_COUNT; ++xx)
00169 {
00170 oldserver.battery[xx].lastTimeBattery = os.server.battery[xx].last_battery_update.sec;
00171 for(unsigned int yy = 0; yy < os.regListLength; ++yy)
00172 {
00173 oldserver.battery[xx].batReg[yy] = os.server.battery[xx].battery_register[yy];
00174 oldserver.battery[xx].batRegFlag[yy] = os.server.battery[xx].battery_update_flag[yy];
00175 oldserver.battery[xx].batRegTime[yy] = os.server.battery[xx].battery_register_update[yy].sec;
00176 }
00177 }
00178
00179 oldserver.header.stamp = ros::Time::now();
00180 bs.publish(oldserver);
00181
00182 lastTime = currentTime;
00183
00184 stat.values.clear();
00185
00186 ss.str("");
00187 ss << "IBPS " << majorID;
00188 stat.name = ss.str();
00189 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
00190 stat.message = "OK";
00191
00192 stat.add("Time Remaining (min)", (os.server.time_left.toSec()/60));
00193 stat.add("Average charge (percent)", os.server.average_charge );
00194 Duration elapsed = currentTime - os.server.last_system_update;
00195 stat.add("Time since update (s)", elapsed.toSec());
00196
00197 msg_out.header.stamp = ros::Time::now();
00198 msg_out.status.push_back(stat);
00199
00200 for(int xx = 0; xx < os.server.MAX_BAT_COUNT; ++xx)
00201 {
00202 stat.values.clear();
00203
00204 ss.str("");
00205 ss << "Smart Battery " << majorID << "." << xx;
00206 stat.name = ss.str();
00207 stat.level = diagnostic_msgs::DiagnosticStatus::OK;
00208 stat.message = "OK";
00209
00210 if(!os.server.battery[xx].present)
00211 {
00212 stat.add("Battery Present", "False");
00213 stat.level = diagnostic_msgs::DiagnosticStatus::ERROR;
00214 stat.message = "Not present";
00215 }
00216 else
00217 {
00218 stat.add("Battery Present", "True");
00219 stat.add("Charging", (os.server.battery[xx].charging) ? "True":"False");
00220 stat.add("Discharging", (os.server.battery[xx].discharging) ? "True":"False");
00221 stat.add("Power Present", (os.server.battery[xx].power_present) ? "True":"False");
00222 stat.add("No Good", (os.server.battery[xx].power_no_good) ? "True":"False");
00223 stat.add("Charge Inhibited", (os.server.battery[xx].inhibited) ? "True":"False");
00224
00225 int16_t voltage = -1;
00226 int16_t design_voltage = -1;
00227 int16_t relative_charge = -1;
00228 int16_t absolute_charge = -1;
00229
00230 for(unsigned int yy = 0; yy < os.regListLength; ++yy)
00231 {
00232 unsigned addr = os.regList[yy].address;
00233 if(os.server.battery[xx].battery_update_flag[addr])
00234 {
00235 ss.str("");
00236 if(os.regList[yy].unit != "")
00237 ss << os.regList[yy].name << " (" << os.regList[yy].unit << ")";
00238 else
00239 ss << os.regList[yy].name;
00240
00241 switch(addr) {
00242 case 0x1b:
00243 {
00244 std::stringstream date;
00245 date.str("");
00246
00247 unsigned int day = os.server.battery[xx].battery_register[addr] & 0x1F;
00248 unsigned int month = (os.server.battery[xx].battery_register[addr] >> 5) & 0xF;
00249 unsigned int year = (os.server.battery[xx].battery_register[addr] >> 9) + 1980;
00250 date << month << "/" << day << "/" << year;
00251
00252 stat.add("Manufacture Date (MDY)", date.str());
00253 }
00254 break;
00255 case 0x8:
00256 {
00257 float celsius = tempToCelcius(os.server.battery[xx].battery_register[addr]);
00258 if(celsius > BATTERY_TEMP_WARN)
00259 {
00260 ostringstream warn;
00261 warn << "High Temperature Warning > " << BATTERY_TEMP_WARN << "C";
00262 stat.mergeSummary(diagnostic_msgs::DiagnosticStatus::WARN, warn.str());
00263 }
00264
00265 stat.add("Temperature (C)", celsius);
00266 }
00267 break;
00268 case 0x1c:
00269 {
00270 stat.add("Serial Number", os.server.battery[xx].battery_register[addr]);
00271
00272 std::stringstream hw_id;
00273 hw_id << os.server.battery[xx].battery_register[addr];
00274
00275 stat.hardware_id = hw_id.str();
00276 }
00277 break;
00278 case 0x09:
00279 voltage = os.server.battery[xx].battery_register[addr];
00280 stat.add( ss.str(), os.server.battery[xx].battery_register[addr]);
00281 break;
00282 case 0x19:
00283 design_voltage = os.server.battery[xx].battery_register[addr];
00284 stat.add( ss.str(), os.server.battery[xx].battery_register[addr]);
00285 break;
00286 case 0x0d:
00287 relative_charge = os.server.battery[xx].battery_register[addr];
00288 stat.add( ss.str(), os.server.battery[xx].battery_register[addr]);
00289 break;
00290 case 0x0e:
00291 absolute_charge = os.server.battery[xx].battery_register[addr];
00292 stat.add( ss.str(), os.server.battery[xx].battery_register[addr]);
00293 break;
00294 default:
00295 stat.add( ss.str(), os.server.battery[xx].battery_register[addr]);
00296 break;
00297 }
00298 }
00299 }
00300
00301 elapsed = currentTime - os.server.battery[xx].last_battery_update;
00302 if (os.server.battery[xx].last_battery_update >= Time(1))
00303 stat.add("Time since update (s)", elapsed.toSec());
00304 else
00305 stat.add("Time since update (s)", "N/A");
00306
00307 if ( absolute_charge >= 0 && relative_charge >= 0 ) {
00308 if( absolute_charge < relative_charge/2 ) {
00309 stat.mergeSummary(diagnostic_msgs::DiagnosticStatus::WARN, "Battery capacity low, please replace.");
00310 }
00311 }
00312
00313 if ( voltage >= 0 && design_voltage >= 0 ) {
00314 if( voltage < design_voltage/2 ) {
00315 stat.mergeSummary(diagnostic_msgs::DiagnosticStatus::WARN, "Battery voltage too low, please replace.");
00316 }
00317 }
00318
00319
00320
00321 bool updateGracePeriod = (currentTime - startTime).toSec() < stale_timeout_;
00322 if (os.server.battery[xx].last_battery_update <= Time(1) && updateGracePeriod)
00323 stat.mergeSummary(diagnostic_msgs::DiagnosticStatus::WARN, "Waiting for battery update");
00324 else if (stale_timeout_ > 0 && elapsed.toSec() > stale_timeout_)
00325 stat.mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "No updates");
00326 else if (lag_timeout_ > 0 && elapsed.toSec() > lag_timeout_)
00327 stat.mergeSummary(diagnostic_msgs::DiagnosticStatus::WARN, "Stale updates");
00328
00329
00330
00331
00332
00333 if (os.server.battery[xx].power_present && !os.server.battery[xx].charging
00334 && os.server.battery[xx].battery_register[0x0d] < 90
00335 && tempToCelcius(os.server.battery[xx].battery_register[0x8]) > 46.0)
00336 {
00337 stat.mergeSummary(diagnostic_msgs::DiagnosticStatus::WARN, "Charge Inhibited, High Temperature");
00338 if (!has_warned_temp_alarm_)
00339 {
00340 ROS_WARN("Over temperature alarm found on battery %d. Battery will not charge.", xx);
00341 has_warned_temp_alarm_ = true;
00342 }
00343 }
00344
00345
00346 if (os.server.battery[xx].battery_register[0x16] & 0x1000)
00347 stat.mergeSummary(diagnostic_msgs::DiagnosticStatus::WARN, "Over Temp Alarm");
00348
00349
00350
00351 if (os.server.battery[xx].power_no_good && !has_warned_no_good_)
00352 {
00353 ROS_WARN("Battery %d reports \"No Good\".", xx);
00354 has_warned_no_good_ = true;
00355 }
00356
00357 msg_out.status.push_back(stat);
00358 }
00359 }
00360
00361 pub.publish(msg_out);
00362 msg_out.status.clear();
00363
00364 }
00365 }
00366 }
00367
00368 };
00369
00370 int main(int argc, char** argv)
00371 {
00372 string tmp_device;
00373 int debug_level;
00374 int max_ports;
00375
00376 po::options_description desc("Allowed options");
00377 desc.add_options()
00378 ("help", "this help message")
00379 ("debug", po::value<int>(&debug_level)->default_value(0), "debug level")
00380 ("count", po::value<int>(&max_ports)->default_value(4), "number of ports to monitor")
00381 ("dev", po::value<string>(&tmp_device), "serial device to open");
00382
00383 po::variables_map vm;
00384 po::store(po::parse_command_line( argc, argv, desc), vm);
00385 po::notify(vm);
00386
00387 if( vm.count("help"))
00388 {
00389 cout << desc << "\n";
00390 return 1;
00391 }
00392
00393 ros::init(argc, argv, "ocean_server");
00394 ros::NodeHandle handle;
00395 ros::NodeHandle private_handle("~");
00396
00397
00398
00399 ROSCONSOLE_AUTOINIT;
00400 log4cxx::LoggerPtr my_logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME);
00401 fprintf(stderr, "Logger Name: %s\n", ROSCONSOLE_DEFAULT_NAME);
00402
00403 if( my_logger->getLevel() == 0 )
00404 {
00405
00406 my_logger->setLevel(ros::console::g_level_lookup[ros::console::levels::Info]);
00407 }
00408
00409 private_handle.getParam( "number_of_ports", max_ports );
00410 ROS_INFO("number_of_ports=%d", max_ports);
00411 private_handle.getParam( "debug_level", debug_level );
00412 ROS_DEBUG("debug_level=%d", debug_level);
00413
00414 vector<server> server_list;
00415
00416 for(int xx = 0; xx < max_ports; ++xx)
00417 server_list.push_back(server( xx, tmp_device, debug_level));
00418
00419 for(int xx = 0; xx < max_ports; ++xx)
00420 server_list[xx].start();
00421
00422 ros::spin();
00423
00424
00425 for(int xx = 0; xx < max_ports; ++xx)
00426 server_list[xx].stop();
00427
00428 }