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 #include <stdio.h>
00031 #include <stdint.h>
00032 #include <string.h>
00033 #include <unistd.h>
00034 #include <stdlib.h>
00035 #include <sys/select.h>
00036 #include <sys/types.h>
00037 #include <assert.h>
00038 #include <errno.h>
00039 #include <signal.h>
00040 #include <vector>
00041 #include <sstream>
00042 #include <iostream>
00043 #include <boost/thread/thread.hpp>
00044 #include <boost/program_options.hpp>
00045
00046
00047 #include <sys/types.h>
00048 #include <sys/socket.h>
00049 #include <netinet/in.h>
00050 #include <arpa/inet.h>
00051 #include <sys/socket.h>
00052 #include <net/if.h>
00053 #include <sys/ioctl.h>
00054
00055 #include <log4cxx/logger.h>
00056
00057 #include "power_comm.h"
00058 #include "power_node2.h"
00059 #include "diagnostic_msgs/DiagnosticArray.h"
00060 #include "diagnostic_updater/DiagnosticStatusWrapper.h"
00061 #include "pr2_msgs/PowerBoardState.h"
00062 #include "rosconsole/macros_generated.h"
00063 #include "ros/ros.h"
00064
00065 #define TEMP_WARN 60
00066
00067 using namespace std;
00068 namespace po = boost::program_options;
00069
00070
00071
00072 static Device *devicePtr;
00073 static Interface *SendInterface;
00074 static Interface *ReceiveInterface;
00075 static PowerBoard *myBoard;
00076
00077 static const ros::Duration TIMEOUT = ros::Duration(1,0);
00078
00079
00080 void Device::setTransitionMessage(const TransitionMessage &newtmsg)
00081 {
00082 if (tmsgset)
00083 {
00084 #define PRINT_IF_CHANGED(val) \
00085 for (int counter = 0; counter < 3; counter++) \
00086 { \
00087 if (tmsg.cb[counter].val##_count != newtmsg.cb[counter].val##_count) \
00088 { \
00089 ROS_INFO("Power board: CB%i "#val" event count changed to %i.", counter, newtmsg.cb[counter].val##_count);\
00090 } \
00091 }
00092
00093 PRINT_IF_CHANGED(stop);
00094 PRINT_IF_CHANGED(estop);
00095 PRINT_IF_CHANGED(trip);
00096 PRINT_IF_CHANGED(fail_18V);
00097 PRINT_IF_CHANGED(disable);
00098 PRINT_IF_CHANGED(start);
00099 PRINT_IF_CHANGED(pump_fail);
00100 PRINT_IF_CHANGED(reset);
00101
00102 #undef PRINT_IF_CHANGED
00103 }
00104 else
00105 tmsgset = 1;
00106
00107 tmsg = newtmsg;
00108 }
00109
00110 void Device::setPowerMessage(const PowerMessage &newpmsg)
00111 {
00112 if (pmsgset)
00113 {
00114 #define PRINT_IF_CHANGED(val) \
00115 if (pmsg.status.val##_status != newpmsg.status.val##_status) \
00116 { \
00117 ROS_INFO("Power board: status of "#val" changed to %i.", newpmsg.status.val##_status); \
00118 }
00119
00120 PRINT_IF_CHANGED(CB0);
00121 PRINT_IF_CHANGED(CB1);
00122 PRINT_IF_CHANGED(CB2);
00123 PRINT_IF_CHANGED(estop_button);
00124 PRINT_IF_CHANGED(estop);
00125
00126 #undef PRINT_IF_CHANGED
00127 }
00128 else
00129 pmsgset = 1;
00130
00131 if(newpmsg.header.message_revision == 2)
00132 {
00133 memcpy( &pmsg.header, &newpmsg.header, sizeof(MessageHeader));
00134
00135
00136 memcpy( &pmsg.status, &newpmsg.status, sizeof(StatusStruct_Rev2));
00137 }
00138 else
00139 pmsg = newpmsg;
00140
00141 }
00142
00143 Interface::Interface() : recv_sock(-1), send_sock(-1)
00144 {
00145
00146 }
00147
00148
00149 void Interface::Close() {
00150 if (recv_sock != -1) {
00151 close(recv_sock);
00152 recv_sock = -1;
00153 }
00154 if (send_sock != -1) {
00155 close(send_sock);
00156 send_sock = -1;
00157 }
00158 }
00159
00160
00161 int Interface::InitReceive(const std::string &address_str)
00162 {
00163
00164 recv_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
00165 if (recv_sock == -1) {
00166 perror("Couldn't create recv socket");
00167 return -1;
00168 }
00169
00170
00171 int opt = 1;
00172 if (setsockopt(recv_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
00173 perror("Couldn't set reuse addr on recv socket\n");
00174 Close();
00175 return -1;
00176 }
00177
00178 #if 0
00179
00180 opt = 1;
00181 if (setsockopt(recv_sock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt))) {
00182 perror("Setting broadcast option on recv");
00183 Close();
00184 return -1;
00185 }
00186 #endif
00187
00188
00189 struct sockaddr_in sin;
00190 memset(&sin, 0, sizeof(sin));
00191 sin.sin_family = AF_INET;
00192 sin.sin_port = htons(POWER_PORT);
00193 sin.sin_addr.s_addr = (INADDR_ANY);
00194
00195
00196 if (bind(recv_sock, (struct sockaddr*)&sin, sizeof(sin))) {
00197 perror("Couldn't Bind socket to port");
00198 Close();
00199 return -1;
00200 }
00201
00202 return 0;
00203 }
00204
00205 int Interface::Init( const std::string &address_str)
00206 {
00207
00208 send_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
00209 if (send_sock == -1) {
00210 Close();
00211 perror("Couldn't create send socket");
00212 return -1;
00213 }
00214
00215
00216 int opt;
00217
00218
00219 opt = 1;
00220 if (setsockopt(send_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
00221 perror("Error allowing socket reuse");
00222 Close();
00223 return -1;
00224 }
00225
00226 struct sockaddr_in sin;
00227 memset(&sin, 0, sizeof(sin));
00228 sin.sin_family = AF_INET;
00229
00230 sin.sin_port = htons(POWER_PORT);
00231
00232 inet_pton( AF_INET, address_str.c_str(), &sin.sin_addr);
00233 if (connect(send_sock, (struct sockaddr*)&sin, sizeof(sin))) {
00234 perror("Connect'ing socket failed");
00235 Close();
00236 return -1;
00237 }
00238
00239 return 0;
00240 }
00241
00242 void Interface::AddToReadSet(fd_set &set, int &max_sock) const {
00243 FD_SET(recv_sock,&set);
00244 if (recv_sock > max_sock)
00245 max_sock = recv_sock;
00246 }
00247
00248 bool Interface::IsReadSet(fd_set set) const {
00249 return FD_ISSET(recv_sock,&set);
00250 }
00251
00252 int PowerBoard::send_command( int circuit_breaker, const std::string &command, unsigned flags)
00253 {
00254 assert(devicePtr != NULL);
00255
00256
00257 CommandMessage cmdmsg;
00258 memset(&cmdmsg, 0, sizeof(cmdmsg));
00259 cmdmsg.header.message_revision = COMMAND_MESSAGE_REVISION;
00260 cmdmsg.header.message_id = MESSAGE_ID_COMMAND;
00261 cmdmsg.header.serial_num = devicePtr->getPowerMessage().header.serial_num;
00262
00263 strncpy(cmdmsg.header.text, "power command message", sizeof(cmdmsg.header.text));
00264
00265 if(command == "fan")
00266 {
00267
00268
00269
00270 if((circuit_breaker > 3) || (circuit_breaker < 0))
00271 {
00272 fprintf(stderr, "Fan must be between 0 and 3\n" );
00273 return -1;
00274 }
00275
00276 switch(circuit_breaker)
00277 {
00278 default:
00279 case 0:
00280 cmdmsg.command.fan0_command = flags;
00281 break;
00282 case 1:
00283 cmdmsg.command.fan1_command = flags;
00284 break;
00285 case 2:
00286 cmdmsg.command.fan2_command = flags;
00287 break;
00288 case 3:
00289 cmdmsg.command.fan3_command = flags;
00290 break;
00291 }
00292
00293 ROS_DEBUG("Set fan %d to %d%% output", circuit_breaker, flags);
00294 }
00295 else
00296 {
00297 if ((circuit_breaker < 0) || (circuit_breaker >= pr2_power_board::PowerBoardCommand2::Request::NUMBER_OF_CIRCUITS)) {
00298 fprintf(stderr, "Circuit breaker number must be between 0 and %d\n", pr2_power_board::PowerBoardCommand2::Request::NUMBER_OF_CIRCUITS);
00299 return -1;
00300 }
00301
00302 ROS_DEBUG("circuit=%d command=%s flags=%x\n", circuit_breaker, command.c_str(), flags);
00303
00304
00305 cmdmsg.command.fan0_command = getFanDuty();
00306
00307
00308 char command_enum = NONE;
00309 if (command == "start") {
00310 command_enum = COMMAND_START;
00311 }
00312 else if (command == "stop") {
00313 command_enum = COMMAND_STOP;
00314 }
00315 else if (command == "reset") {
00316 command_enum = COMMAND_RESET;
00317 }
00318 else if (command == "disable") {
00319 command_enum = COMMAND_DISABLE;
00320 }
00321 else if (command == "none") {
00322 command_enum = NONE;
00323 }
00324 else {
00325 ROS_ERROR("invalid command '%s'", command.c_str());
00326 return -1;
00327 }
00328
00329
00330
00331 if (circuit_breaker==0) {
00332 cmdmsg.command.CB0_command = command_enum;
00333 }
00334 else if (circuit_breaker==1) {
00335 cmdmsg.command.CB1_command = command_enum;
00336 }
00337 else if (circuit_breaker==2) {
00338 cmdmsg.command.CB2_command = command_enum;
00339 }
00340 else if (circuit_breaker==-1) {
00341 cmdmsg.command.CB0_command = command_enum;
00342 cmdmsg.command.CB1_command = command_enum;
00343 cmdmsg.command.CB2_command = command_enum;
00344 }
00345
00346 cmdmsg.command.flags = flags;
00347 ROS_DEBUG("Sent command %s(%d), circuit %d", command.c_str(), command_enum, circuit_breaker);
00348
00349 }
00350
00351
00352
00353 errno = 0;
00354
00355 int result = send(SendInterface->send_sock, &cmdmsg, sizeof(cmdmsg), 0);
00356 if (result == -1) {
00357 ROS_ERROR("Error sending");
00358 return -1;
00359 } else if (result != sizeof(cmdmsg)) {
00360 ROS_WARN("Error sending : send only took %d of %lu bytes\n",
00361 result, sizeof(cmdmsg));
00362 }
00363
00364 ROS_DEBUG("Send to Serial=%u, revision=%u", cmdmsg.header.serial_num, cmdmsg.header.message_revision);
00365
00366
00367 return 0;
00368 }
00369
00370
00371 const char* PowerBoard::cb_state_to_str(char state)
00372 {
00373
00374 switch(state) {
00375 case STATE_NOPOWER:
00376 return "no-power";
00377 case STATE_STANDBY:
00378 return "Standby";
00379 case STATE_PUMPING:
00380 return "pumping";
00381 case STATE_ON:
00382 return "Enabled";
00383 case STATE_DISABLED:
00384 return "Disabled";
00385 }
00386 return "???";
00387 }
00388
00389 const char* PowerBoard::master_state_to_str(char state)
00390 {
00391
00392 switch(state) {
00393 case MASTER_NOPOWER:
00394 return "no-power";
00395 case MASTER_STANDBY:
00396 return "stand-by";
00397 case MASTER_ON:
00398 return "on";
00399 case MASTER_OFF:
00400 return "off";
00401 case MASTER_SHUTDOWN:
00402 return "shutdown";
00403 }
00404 return "???";
00405 }
00406
00407
00408
00409
00410
00411 int PowerBoard::process_message(const PowerMessage *msg, int len)
00412 {
00413 if ((msg->header.message_revision > CURRENT_MESSAGE_REVISION) || (msg->header.message_revision < MINIMUM_MESSAGE_REVISION)) {
00414 ROS_WARN("Got message with incorrect message revision %u\n", msg->header.message_revision);
00415 return -1;
00416 }
00417
00418 if ((msg->header.message_revision == CURRENT_MESSAGE_REVISION) && (len != CURRENT_MESSAGE_SIZE))
00419 ROS_ERROR("received message of incorrect size %d for rev=%d\n", len, msg->header.message_revision);
00420
00421 if ((msg->header.message_revision == MINIMUM_MESSAGE_REVISION) && (len != REVISION_2_MESSAGE_SIZE))
00422 ROS_ERROR("received message of incorrect size %d for rev=%d\n", len, msg->header.message_revision);
00423
00424
00425 {
00426 boost::mutex::scoped_lock(library_lock_);
00427 devicePtr->message_time = ros::Time::now();
00428 devicePtr->setPowerMessage(*msg);
00429 }
00430
00431 return 0;
00432 }
00433
00434 int PowerBoard::process_transition_message(const TransitionMessage *msg, int len)
00435 {
00436 if (msg->header.message_revision != TRANSITION_MESSAGE_REVISION) {
00437 ROS_WARN("Got message with incorrect message revision %u\n", msg->header.message_revision);
00438 return -1;
00439 }
00440
00441 if (len != sizeof(TransitionMessage)) {
00442 ROS_ERROR("received message of incorrect size %d\n", len);
00443 return -2;
00444 }
00445
00446 {
00447 boost::mutex::scoped_lock(library_lock_);
00448 devicePtr->message_time = ros::Time::now();
00449 devicePtr->setTransitionMessage(*msg);
00450 }
00451
00452 return 0;
00453 }
00454
00455
00456
00457 int PowerBoard::collect_messages()
00458 {
00459 PowerMessage *power_msg;
00460 TransitionMessage *transition_msg;
00461 char tmp_buf[256];
00462
00463
00464
00465
00466 timeval timeout;
00467 timeout.tv_sec = 1;
00468 timeout.tv_usec = 0;
00469
00470 while (1)
00471 {
00472
00473 fd_set read_set;
00474 int max_sock = -1;
00475 FD_ZERO(&read_set);
00476
00477 ReceiveInterface->AddToReadSet(read_set,max_sock);
00478
00479 int result = select(max_sock+1, &read_set, NULL, NULL, &timeout);
00480
00481
00482
00483 if (result == -1) {
00484 perror("Select");
00485 return -1;
00486 }
00487 else if (result == 0) {
00488 return 0;
00489 }
00490 else if (result >= 1) {
00491 Interface *recvInterface = ReceiveInterface;
00492
00493 struct sockaddr_in crap;
00494 socklen_t sock_len = sizeof(crap);
00495
00496
00497 int len = recvfrom(recvInterface->recv_sock, tmp_buf, sizeof(tmp_buf), 0, (sockaddr*)&crap, &sock_len);
00498 if (len == -1) {
00499 ROS_ERROR("Error recieving on socket");
00500 return -1;
00501 }
00502 else if (len < (int)sizeof(MessageHeader)) {
00503 ROS_ERROR("received message of incorrect size %d\n", len);
00504 }
00505
00506 #if 0
00507 char str[INET_ADDRSTRLEN];
00508 inet_ntop(AF_INET, &(crap.sin_addr), str, INET_ADDRSTRLEN);
00509 ROS_DEBUG("received from = %s", str);
00510 #endif
00511
00512 if(crap.sin_addr.s_addr == ip_address )
00513 {
00514 MessageHeader *header;
00515 header = (MessageHeader*)tmp_buf;
00516
00517
00518 if(header->message_id == MESSAGE_ID_POWER)
00519 {
00520 power_msg = (PowerMessage*)tmp_buf;
00521 if (len == -1) {
00522 ROS_ERROR("Error recieving on socket");
00523 return -1;
00524 }
00525
00526
00527
00528
00529
00530 else {
00531 if (process_message(power_msg, len))
00532 return -1;
00533 }
00534 }
00535 else if(header->message_id == MESSAGE_ID_TRANSITION)
00536 {
00537 transition_msg = (TransitionMessage *)tmp_buf;
00538 if (len == -1) {
00539 ROS_ERROR("Error recieving on socket");
00540 return -1;
00541 }
00542 else {
00543 if (process_transition_message(transition_msg, len))
00544 return -1;
00545 }
00546 }
00547 else
00548 {
00549 ROS_DEBUG("Discard message len=%d", len);
00550 }
00551 }
00552 }
00553 else {
00554 ROS_ERROR("Unexpected select result %d\n", result);
00555 return -1;
00556 }
00557 }
00558
00559 return 0;
00560 }
00561
00562 PowerBoard::PowerBoard( const ros::NodeHandle node_handle, const std::string &address_str ) :
00563 node_handle(node_handle),
00564 fan_high_(false)
00565 {
00566 ROSCONSOLE_AUTOINIT;
00567 log4cxx::LoggerPtr my_logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME);
00568 fprintf(stderr, "Logger Name: %s\n", ROSCONSOLE_DEFAULT_NAME);
00569
00570 if( my_logger->getLevel() == 0 )
00571 {
00572
00573 my_logger->setLevel(ros::console::g_level_lookup[ros::console::levels::Info]);
00574 }
00575
00576 sockaddr_in sin;
00577 inet_pton( AF_INET, address_str.c_str(), &sin.sin_addr);
00578 ip_address = sin.sin_addr.s_addr;
00579
00580 }
00581
00582 void PowerBoard::init()
00583 {
00584 devicePtr = new Device();
00585
00586 service = node_handle.advertiseService("control", &PowerBoard::commandCallback, this);
00587 service2 = node_handle.advertiseService("control2", &PowerBoard::commandCallback2, this);
00588
00589 diags_pub = node_handle.advertise<diagnostic_msgs::DiagnosticArray>("/diagnostics", 2);
00590 state_pub = node_handle.advertise<pr2_msgs::PowerBoardState>("state", 2, true);
00591
00592 ros::NodeHandle main_handle;
00593 battery_sub_ = main_handle.subscribe("battery/server2", 10, &PowerBoard::batteryCB, this);
00594 }
00595
00596 void PowerBoard::batteryCB(const pr2_msgs::BatteryServer2::ConstPtr &msgPtr)
00597 {
00598 float max_temp = -1.0f;
00599
00600 std::vector<pr2_msgs::BatteryState2>::const_iterator it;
00601 for (it = msgPtr->battery.begin(); it != msgPtr->battery.end(); ++it)
00602 {
00603
00604 float batt_temp = ((float) it->battery_register[0x08]) / 10.0f - 273.15;
00605
00606 max_temp = max(max_temp, batt_temp);
00607 }
00608
00609 ROS_DEBUG("Logging battery server %d with temperature %f", msgPtr->id, max_temp);
00610 battery_temps_[msgPtr->id] = max_temp;
00611 }
00612
00613 int PowerBoard::getFanDuty()
00614 {
00615
00616 float max_temp = -1.0f;
00617
00618 std::map<int, float>::const_iterator it;
00619 for (it = battery_temps_.begin(); it != battery_temps_.end(); ++it)
00620 max_temp = max(max_temp, it->second);
00621
00622
00623
00624 int battDuty = 0;
00625 if (max_temp > 46.0f)
00626 battDuty = 100;
00627 else if (max_temp > 44.0f && fan_high_)
00628 battDuty = 100;
00629 else
00630 battDuty = 0;
00631
00632 fan_high_ = battDuty > 0;
00633
00634 ROS_DEBUG("Fan duty cycle based on battery temperature: %d, Battery temp: %.1f", battDuty, max_temp);
00635 return battDuty;
00636 }
00637
00638 void PowerBoard::checkFanSpeed()
00639 {
00640 send_command(0, "fan", getFanDuty());
00641 }
00642
00643 bool PowerBoard::commandCallback(pr2_power_board::PowerBoardCommand::Request &req_,
00644 pr2_power_board::PowerBoardCommand::Response &res_)
00645 {
00646 res_.retval = send_command( req_.breaker_number, req_.command, req_.flags);
00647 requestMessage(MESSAGE_ID_POWER);
00648 requestMessage(MESSAGE_ID_TRANSITION);
00649
00650 return true;
00651 }
00652
00653 bool PowerBoard::commandCallback2(pr2_power_board::PowerBoardCommand2::Request &req_,
00654 pr2_power_board::PowerBoardCommand2::Response &res_)
00655 {
00656
00657 unsigned flags = 0;
00658 if(req_.reset_stats)
00659 flags |= 0x1;
00660 if(req_.reset_circuits)
00661 flags |= 0x2;
00662
00663 res_.success = send_command( req_.circuit, req_.command, flags);
00664 requestMessage(MESSAGE_ID_POWER);
00665 requestMessage(MESSAGE_ID_TRANSITION);
00666
00667 return true;
00668 }
00669
00670 void PowerBoard::collectMessages()
00671 {
00672 while(node_handle.ok())
00673 {
00674 collect_messages();
00675
00676 }
00677 }
00678
00679 void PowerBoard::sendMessages()
00680 {
00681 ros::Rate r(5);
00682 r.sleep();
00683 r = 1;
00684 r.reset();
00685
00686 while(node_handle.ok())
00687 {
00688 r.sleep();
00689
00690 boost::mutex::scoped_lock(library_lock_);
00691
00692 {
00693 diagnostic_msgs::DiagnosticArray msg_out;
00694 diagnostic_updater::DiagnosticStatusWrapper stat;
00695
00696 const PowerMessage *pmesg = &devicePtr->getPowerMessage();
00697
00698 ostringstream ss, ss2;
00699 ss << "Power board " << pmesg->header.serial_num;
00700 ss2 << "68050070" << pmesg->header.serial_num;
00701 stat.name = ss.str();
00702 stat.hardware_id = ss2.str();
00703
00704 if( (ros::Time::now() - devicePtr->message_time) > TIMEOUT )
00705 {
00706 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "No Updates");
00707 }
00708 else
00709 {
00710 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Running");
00711 }
00712 const StatusStruct *status = &pmesg->status;
00713
00714 if (status->fan0_speed == 0)
00715 {
00716 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Base Fan Off");
00717 }
00718
00719
00720
00721
00722 stat.add("Serial Number", pmesg->header.serial_num);
00723
00724
00725 stat.add("Input Current", status->input_current);
00726
00727
00728
00729 stat.add("Input Voltage", status->input_voltage);
00730
00731
00732 stat.add("DCDC 12V aux", status->DCDC_12V_aux);
00733
00734
00735 stat.add("DCDC 12V c1", status->DCDC_12V_cpu0);
00736
00737
00738 stat.add("Breaker 0 Voltage", status->CB0_voltage);
00739
00740
00741 stat.add("Breaker 1 Voltage", status->CB1_voltage);
00742
00743
00744 stat.add("Breaker 2 Voltage", status->CB2_voltage);
00745
00746
00747 stat.add("Board Temperature", status->ambient_temp);
00748
00749 if (status->ambient_temp > TEMP_WARN)
00750 {
00751 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "High Temp");
00752 }
00753
00754
00755
00756 stat.add("Base Fan Speed", status->fan0_speed);
00757
00758
00759 stat.add("Expansion Fan 1 Speed", status->fan1_speed);
00760
00761
00762 stat.add("Expansion Fan 2 Speed", status->fan2_speed);
00763
00764
00765 stat.add("Expansion Fan 3 Speed", status->fan3_speed);
00766
00767
00768
00769 stat.add("Breaker 0 (Left Arm) State", cb_state_to_str(status->CB0_state));
00770
00771
00772 stat.add("Breaker 1 (Base/Body) State", cb_state_to_str(status->CB1_state));
00773
00774
00775 stat.add("Breaker 2 (Right Arm) State", cb_state_to_str(status->CB2_state));
00776
00777
00778 stat.add("DCDC state", master_state_to_str(status->DCDC_state));
00779
00780
00781
00782 stat.add("RunStop Button Status", (status->estop_button_status ? "True":"False"));
00783
00784
00785 stat.add("RunStop Wireless Status", (status->estop_status ? "True":"False"));
00786
00787
00788
00789 stat.add("Circuit assembly revision", status->pca_rev);
00790
00791
00792 stat.add("Circuit board revision", status->pcb_rev);
00793
00794
00795 stat.add("Major Revision", status->major_rev);
00796
00797
00798 stat.add("Minor Revision", status->minor_rev);
00799
00800 stat.add("Min Voltage", status->min_input_voltage);
00801 stat.add("Max Current", status->max_input_current);
00802
00803
00804 stat.add("DCDC 12V c2", status->DCDC_12V_cpu1);
00805
00806
00807 stat.add("DCDC 12V user", status->DCDC_12V_user);
00808
00809 for( int xx = 0; xx < 4; ++xx)
00810 {
00811
00812 ss.str("");
00813 ss << "Battery " << xx << " voltage=";
00814 stat.add(ss.str(), status->battery_voltage[xx]);
00815 }
00816
00817
00818 const TransitionMessage *tmsg = &devicePtr->getTransitionMessage();
00819 for(int cb_index=0; cb_index < 3; ++cb_index)
00820 {
00821 const TransitionCount *trans = &tmsg->cb[cb_index];
00822
00823 ss.str("");
00824 ss << "CB" << cb_index << " Stop Count";
00825 stat.add(ss.str(), (int)trans->stop_count);
00827
00828 ss.str("");
00829 ss << "CB" << cb_index << " E-Stop Count";
00830 stat.add(ss.str(), (int)trans->estop_count);
00831
00832 ss.str("");
00833 ss << "CB" << cb_index << " Trip Count";
00834 stat.add(ss.str(), (int)trans->trip_count);
00835
00836 ss.str("");
00837 ss << "CB" << cb_index << " 18V Fail Count";
00838 stat.add(ss.str(), (int)trans->fail_18V_count);
00839
00840 ss.str("");
00841 ss << "CB" << cb_index << " Disable Count";
00842 stat.add(ss.str(), (int)trans->disable_count);
00843
00844 ss.str("");
00845 ss << "CB" << cb_index << " Start Count";
00846 stat.add(ss.str(), (int)trans->start_count);
00847
00848 ss.str("");
00849 ss << "CB" << cb_index << " Pump Fail Count";
00850 stat.add(ss.str(), (int)trans->pump_fail_count);
00851
00852 ss.str("");
00853 ss << "CB" << cb_index << " Reset Count";
00854 stat.add(ss.str(), (int)trans->reset_count);
00855 }
00856
00857 msg_out.status.push_back(stat);
00858 msg_out.header.stamp = ros::Time::now();
00859
00860 diags_pub.publish(msg_out);
00861
00862
00863 if ((ros::Time::now() - devicePtr->message_time) < TIMEOUT )
00864 {
00865 pr2_msgs::PowerBoardState state_msg;
00866 state_msg.name = stat.name;
00867 state_msg.serial_num = pmesg->header.serial_num;
00868 state_msg.input_voltage = status->input_voltage;
00869 state_msg.circuit_voltage[0] = status->CB0_voltage;
00870 state_msg.circuit_voltage[1] = status->CB1_voltage;
00871 state_msg.circuit_voltage[2] = status->CB2_voltage;
00872 state_msg.master_state = status->DCDC_state;
00873 state_msg.circuit_state[0] = status->CB0_state;
00874 state_msg.circuit_state[1] = status->CB1_state;
00875 state_msg.circuit_state[2] = status->CB2_state;
00876 state_msg.run_stop = status->estop_status;
00877 state_msg.wireless_stop = status->estop_button_status;
00878 state_msg.header.stamp = ros::Time::now();
00879 state_pub.publish(state_msg);
00880 }
00881 }
00882 }
00883 }
00884
00885 int PowerBoard::requestMessage(const unsigned int message)
00886 {
00887
00888 GetMessage cmdmsg;
00889 memset(&cmdmsg, 0, sizeof(cmdmsg));
00890 cmdmsg.header.message_revision = STATUS_MESSAGE_REVISION;
00891 cmdmsg.header.message_id = MESSAGE_ID_STATUS;
00892 cmdmsg.header.serial_num = devicePtr->getPowerMessage().header.serial_num;
00893 strncpy(cmdmsg.header.text, "power status message", sizeof(cmdmsg.header.text));
00894
00895 cmdmsg.message_to_get = message;
00896
00897 errno = 0;
00898 int result = send(SendInterface->send_sock, &cmdmsg, sizeof(cmdmsg), 0);
00899 if (result == -1) {
00900 ROS_ERROR("Error sending");
00901 return -1;
00902 } else if (result != sizeof(cmdmsg)) {
00903 ROS_WARN("Error sending : send only took %d of %lu bytes\n", result, sizeof(cmdmsg));
00904 }
00905
00906 ROS_DEBUG("requestMessage: to Serial=%u, revision=%u", cmdmsg.header.serial_num, cmdmsg.header.message_revision);
00907 return 0;
00908 }
00909
00910
00911 void getMessages()
00912 {
00913 myBoard->collectMessages();
00914 }
00915
00916 void sendMessages()
00917 {
00918 myBoard->sendMessages();
00919 }
00920
00921
00922 void CloseAllInterfaces(void)
00923 {
00924
00925 delete SendInterface;
00926 delete ReceiveInterface;
00927 }
00928
00929 void CloseAllDevices(void)
00930 {
00931 delete devicePtr;
00932 }
00933
00934
00935
00936 int CreateAllInterfaces(const std::string &address_str)
00937 {
00938
00939 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
00940 if (sock == -1) {
00941 ROS_ERROR("Couldn't create socket for ioctl requests");
00942 return -1;
00943 }
00944
00945 SendInterface = new Interface();
00946 if (SendInterface->Init(address_str))
00947 {
00948 ROS_ERROR("Error initializing interface");
00949 delete SendInterface;
00950 SendInterface = NULL;
00951 }
00952
00953
00954 ReceiveInterface = new Interface();
00955 ReceiveInterface->InitReceive(address_str);
00956
00957 return 0;
00958 }
00959
00960 int main(int argc, char** argv)
00961 {
00962 ros::init(argc, argv, "power_board");
00963
00964 std::string address_str;
00965 po::options_description desc("Allowed options");
00966 desc.add_options()
00967 ("help", "this help message")
00968 ("address", po::value<std::string>(&address_str), "IP address for specific Power Board");
00969
00970 po::variables_map vm;
00971 po::store(po::parse_command_line( argc, argv, desc), vm);
00972 po::notify(vm);
00973
00974 if( vm.count("help"))
00975 {
00976 cout << desc << "\n";
00977 return 1;
00978 }
00979
00980 if( vm.count("address") == 0 )
00981 {
00982 ROS_ERROR("PowerNode: Error you did not specify the IP address, use --address= to specify the address of the power board.");
00983 exit(-1);
00984 }
00985
00986 ROS_INFO("PowerNode:Using Address=%s", address_str.c_str());
00987
00988
00989 CreateAllInterfaces(address_str);
00990
00991 ros::NodeHandle private_handle("~");
00992 myBoard = new PowerBoard(private_handle, address_str );
00993 myBoard->init();
00994
00995 boost::thread getThread( &getMessages );
00996 boost::thread sendThread( &sendMessages );
00997
00998 double sample_frequency = 10;
00999 double transition_frequency = 0.1;
01000 private_handle.getParam( "sample_frequency", sample_frequency );
01001 ROS_INFO("Using sampling frequency %fHz", sample_frequency);
01002 private_handle.getParam( "transition_frequency", transition_frequency );
01003 ROS_INFO("Using transition frequency %fHz", transition_frequency);
01004
01005 ros::Time last_msg( 0, 0);
01006 ros::Time last_transition( 0, 0);
01007 ros::Time last_batt_check(0, 0);
01008
01009 double ros_rate = 10;
01010
01011 if(sample_frequency > ros_rate)
01012 ros_rate = sample_frequency;
01013
01014 ros::Rate r(ros_rate);
01015 const ros::Duration MSG_RATE(1/sample_frequency);
01016 const ros::Duration TRANSITION_RATE(1/transition_frequency);
01017 const ros::Duration BATT_CHECK_RATE(1 / 0.1);
01018
01019 while(private_handle.ok())
01020 {
01021 r.sleep();
01022 if( (ros::Time::now() - last_msg) > MSG_RATE )
01023 {
01024 myBoard->requestMessage(MESSAGE_ID_POWER);
01025
01026 last_msg = ros::Time::now();
01027 }
01028
01029 if( (ros::Time::now() - last_transition) > TRANSITION_RATE )
01030 {
01031 myBoard->requestMessage(MESSAGE_ID_TRANSITION);
01032 last_transition = ros::Time::now();
01033 }
01034
01035 if (ros::Time::now() - last_batt_check > BATT_CHECK_RATE)
01036 {
01037 last_batt_check = ros::Time::now();
01038 myBoard->checkFanSpeed();
01039 }
01040
01041 ros::spinOnce();
01042 }
01043
01044 sendThread.join();
01045 getThread.join();
01046
01047 CloseAllDevices();
01048 CloseAllInterfaces();
01049
01050
01051 delete myBoard;
01052 return 0;
01053
01054 }
01055
01056 Device::Device(): message_time(0,0)
01057 {
01058 pmsgset = false;
01059 tmsgset = false;
01060 memset( &pmsg, 0, sizeof(PowerMessage));
01061 memset( &tmsg, 0, sizeof(TransitionMessage));
01062 };