$search
00001 00002 #include "riq_hand_ethercat_hardware/riq_hand.h" 00003 #include "riq_hand_ethercat_hardware/riq_hand_state.h" 00004 #include "riq_hand_ethercat_hardware/riq_hand_command.h" 00005 00006 #include <iomanip> 00007 00008 #include <boost/static_assert.hpp> 00009 00010 #include <ros/console.h> 00011 00012 #include <math.h> 00013 #include <algorithm> 00014 00015 // Product code = 11 00016 PLUGINLIB_REGISTER_CLASS(11, riq_hand_ethercat_hardware::RIQHand, EthercatDevice); 00017 00018 namespace riq_hand_ethercat_hardware 00019 { 00020 00021 RIQHandDiagnostics::RIQHandDiagnostics() : 00022 al_status_good_(false) 00023 { 00024 // empty 00025 } 00026 00027 void RIQHand::sizeAssert() 00028 { 00029 BOOST_STATIC_ASSERT(sizeof(RIQHandStateEcat) == STATUS_SIZE); 00030 BOOST_STATIC_ASSERT(sizeof(RIQHandCommandEcat) == COMMAND_SIZE); 00031 } 00032 00033 RIQHand::RIQHand() : 00034 state_cycle_count_(0), 00035 should_publish_(true), 00036 needs_watchdog_reset_(true), 00037 needs_reset_(false), 00038 needs_reset_countdown_(0), 00039 latched_fault_code_(RIQHandStateEcat::NO_FAULT), 00040 after_reset_countdown_(0), 00041 after_watchdog_reset_countdown_(0), 00042 halted_(false) 00043 { 00044 //empty 00045 } 00046 00047 RIQHand::~RIQHand() 00048 { 00049 delete sh_->get_fmmu_config(); 00050 delete sh_->get_pd_config(); 00051 } 00052 00053 void RIQHand::construct(EtherCAT_SlaveHandler *sh, int &start_address) 00054 { 00055 EthercatDevice::construct(sh, start_address); 00056 00057 command_size_ = COMMAND_SIZE; 00058 status_size_ = STATUS_SIZE; 00059 00060 EtherCAT_FMMU_Config *fmmu = new EtherCAT_FMMU_Config(2); 00061 (*fmmu)[0] = EC_FMMU(start_address, // Logical start address 00062 command_size_, // Logical length 00063 0x00, // Logical StartBit 00064 0x07, // Logical EndBit 00065 COMMAND_PHY_ADDR, // Physical Start address 00066 0x00, // Physical StartBit 00067 false, // Read Enable 00068 true, // Write Enable 00069 true); // Enable 00070 00071 start_address += command_size_; 00072 00073 (*fmmu)[1] = EC_FMMU(start_address, // Logical start address 00074 status_size_, // Logical length 00075 0x00, // Logical StartBit 00076 0x07, // Logical EndBit 00077 STATUS_PHY_ADDR, // Physical Start address 00078 0x00, // Physical StartBit 00079 true, // Read Enable 00080 false, // Write Enable 00081 true); // Enable 00082 00083 start_address += status_size_; 00084 00085 sh->set_fmmu_config(fmmu); 00086 00087 00088 EtherCAT_PD_Config *pd = new EtherCAT_PD_Config(2); 00089 00090 // Sync manager for command data - SyncMan Control Register 00091 // <Sm MinSize="0" MaxSize="1024" DefaultSize="200" StartAddress="#x1100" ControlByte="#x74" Enable="1">Outputs</Sm> 00092 (*pd)[0] = 00093 EC_SyncMan ( 00094 COMMAND_PHY_ADDR, // 0-1 Physical Addr - 00095 command_size_, // 2-3 Length - 00096 EC_BUFFERED, // 4.1:0 Buffer type - Operation Mode (Buffered/Mailbox) 00097 EC_WRITTEN_FROM_MASTER, // 4.3:2 Direction - 00098 // Read: ECAT read, PDI write or 00099 // Write: ECAT write, PDI read 00100 true, // 4.5 AL event enable - Interrupt ECAT Event Request 00101 true, // 4.6 Watchdog enable - Watchdog Trigger Enable 00102 false, // 5.0 Write event - Interrupt Write 00103 false, // 5.1 Read event - Interrupt Read 00104 false, // 5.2 Watchdog trigger - ?? Reserved ?? 00105 false, // 5.5:3 Queued state - Mailbox empty/full 00106 EC_FIRST_BUFFER, // 5.5:4 BufferedState - Last written buffer 00107 true); // 7.0 Channel Enable - 00108 (*pd)[0].ECATEventEnable = 1; 00109 00110 00111 // Sync manager for status data - SyncMan Control Register = 0x20 00112 // <Sm MinSize="0" MaxSize="1024" DefaultSize="200" StartAddress="#x1D00" ControlByte="#x30" Enable="1">Inputs</Sm> 00113 (*pd)[1] = 00114 EC_SyncMan ( 00115 STATUS_PHY_ADDR, // 0-1 Physical Addr - 00116 status_size_, // 2-3 Length - 00117 EC_BUFFERED, // 4.1:0 Buffer type - Operation Mode (Buffered/Mailbox) 00118 EC_READ_FROM_MASTER, // 4.3:2 Direction - 00119 // Read: ECAT read, PDI write or 00120 // Write: ECAT write, PDI read 00121 true, // 4.5 AL event enable - Interrupt ECAT Event Request 00122 false, // 4.6 Watchdog enable - Watchdog Trigger Enable 00123 false, // 5.0 Write event - Interrupt Write 00124 false, // 5.1 Read event - Interrupt Read 00125 false, // 5.2 Watchdog trigger - ?? Reserved ?? 00126 false, // 5.5:3 Queued state - Mailbox empty/full 00127 EC_FIRST_BUFFER, // 5.5:4 BufferedState - Last written buffer 00128 true); // 7.0 Channel Enable - 00129 (*pd)[1].ECATEventEnable = 1; 00130 00131 sh->set_pd_config(pd); 00132 00133 00134 EtherCAT_MbxConfig *mbx = new EtherCAT_MbxConfig; 00135 00136 // Sync manager for Master->Slave Mailbox - SyncMan Control Register = 0x26 00137 mbx->SM0 = 00138 EC_SyncMan( 00139 MBX_COMMAND_PHY_ADDR, 00140 MBX_COMMAND_SIZE, 00141 EC_QUEUED, // 00142 EC_WRITTEN_FROM_MASTER, // 00143 true, // Trigger AL interupt (to uC/FPGA slave) when buffer is writen by master 00144 false, // no watchdog 00145 false, // (ro) 00146 false, // (ro) 00147 false, // (ro) 00148 false, // (ro) 00149 EC_FIRST_BUFFER, // (ro) which buffer was last written 00150 true); // enable syncmanager 00151 mbx->SM0.ECATEventEnable = 1; 00152 00153 // Sync manager for Slave->Master Mailbox - SyncMan Control Register = 0x22 00154 mbx->SM1 = 00155 EC_SyncMan( 00156 MBX_STATUS_PHY_ADDR, 00157 MBX_STATUS_SIZE, 00158 EC_QUEUED, // 00159 EC_READ_FROM_MASTER, // 00160 true, // Don't AL interupt (to uC/FPGA slave) when buffer is read by master 00161 false, // no watchdog 00162 false, // (ro) 00163 false, // (ro) 00164 false, // (ro) 00165 false, // (ro) 00166 EC_FIRST_BUFFER, // which buffer was last written (ro) 00167 true); 00168 //mbx->SM1.ECATEventEnable = 1; 00169 00170 sh->set_mbx_config(mbx); 00171 00172 // Disable watchdog as early as possible (may not be needed any more) 00173 // disableWatchdog(sh); 00174 } 00175 00176 int RIQHand::initialize(pr2_hardware_interface::HardwareInterface *, bool) 00177 { 00178 ROS_DEBUG("Device #%02d: RIQ Hand (%#08x)", sh_->get_ring_position(), sh_->get_product_code()); 00179 00180 if (use_ros_) 00181 { 00182 ros::NodeHandle nh; 00183 00184 // Register ROS subscriber for hand command 00185 commandSubscriber_ = nh.subscribe("riq_hand_command", 2, &RIQHand::commandCallback, this); 00186 00187 // Intialize realtime publisher 00188 publisher_.init(nh, "riq_hand_state", 1); 00189 } 00190 00191 return 0; 00192 } 00193 00194 void RIQHand::commandCallback(const riq_msgs::RIQHandCommand::ConstPtr& msg) 00195 { 00196 command_mutex_.lock(); 00197 new_command_ = *msg; 00198 command_mutex_.unlock(); 00199 } 00200 00201 00202 unsigned RIQHand::scaleAndSaturate255(double value) 00203 { 00204 value = double(value)*255.0; 00205 value = roundf(value); 00206 value = std::max(0.0, std::min( 255.0, value ) ); 00207 return unsigned(value); 00208 } 00209 00210 void RIQHand::packCommand(unsigned char *buffer, bool halt, bool reset) 00211 { 00212 // Get newest command data (if possible) 00213 if (command_mutex_.try_lock()) 00214 { 00215 command_ = new_command_; 00216 command_mutex_.unlock(); 00217 } 00218 00219 // Request watch reset (by needs to be done by non-realtime thread) 00220 if (reset) 00221 { 00222 needs_watchdog_reset_ = true; 00223 latched_fault_code_ = 0; 00224 if (needs_reset_) 00225 { 00226 // When device need reset (re initialization) keep reset bit low for a couple of cycles 00227 needs_reset_countdown_ = 10; 00228 needs_reset_ = false; 00229 } 00230 } 00231 00232 RIQHandCommandEcat *command = (RIQHandCommandEcat *)(buffer); 00233 RIQActionRequest &action_request(command->action_request_); 00234 00235 command->zero(); 00236 00237 if (needs_reset_countdown_ > 0) 00238 { 00239 --needs_reset_countdown_; 00240 action_request.initialize_ = 0; 00241 } 00242 else 00243 { 00244 action_request.initialize_ = 1; 00245 } 00246 00247 switch(command_.action) 00248 { 00249 case riq_msgs::RIQHandCommand::OPEN : 00250 action_request.grip_ = RIQActionRequest::GRIP_OPEN; 00251 break; 00252 case riq_msgs::RIQHandCommand::CLOSE : 00253 action_request.grip_ = RIQActionRequest::GRIP_CLOSE; 00254 break; 00255 case riq_msgs::RIQHandCommand::STOP : 00256 action_request.grip_ = RIQActionRequest::GRIP_STOP; 00257 break; 00258 default: 00259 action_request.grip_ = RIQActionRequest::GRIP_STOP; 00260 } 00261 00262 switch(command_.mode) 00263 { 00264 case riq_msgs::RIQHandCommand::CYLINDRICAL: 00265 action_request.mode_ = RIQActionRequest::CYLINDRICAL_MODE; 00266 break; 00267 case riq_msgs::RIQHandCommand::PINCH: 00268 action_request.mode_ = RIQActionRequest::PINCH_MODE; 00269 break; 00270 case riq_msgs::RIQHandCommand::SPHERIOD: 00271 action_request.mode_ = RIQActionRequest::SPHERIOD_MODE; 00272 break; 00273 case riq_msgs::RIQHandCommand::SCISSORS: 00274 action_request.mode_ = RIQActionRequest::SCISSORS_MODE; 00275 break; 00276 } 00277 00278 command->force_ = scaleAndSaturate255(command_.force); 00279 command->velocity_ = scaleAndSaturate255(command_.velocity); 00280 00281 if (halt) 00282 { 00283 action_request.grip_ = RIQActionRequest::GRIP_STOP; 00284 } 00285 halted_ = halt; 00286 00287 command->safety_shutdown_.timeout_ = RIQSafetyShutdown::SHUTDOWN_TIMEOUT_10240ms; 00288 } 00289 00290 00291 bool RIQHand::unpackState(unsigned char *this_buffer, unsigned char *prev_buffer) 00292 { 00293 // Nothing for now 00294 const RIQHandStateEcat *state = (const RIQHandStateEcat *)(this_buffer + command_size_); 00295 const RIQHandStateEcat *prev_state = (const RIQHandStateEcat *)(prev_buffer + command_size_); 00296 const RIQGripperStatus &gripper_status(state->gripper_status_); 00297 const RIQObjectStatus &object_status(state->object_status_); 00298 00299 if (++state_cycle_count_ >= STATE_PUBLISH_PERIOD) 00300 { 00301 state_cycle_count_ = 0; 00302 should_publish_ = true; 00303 } 00304 00305 if (should_publish_ && use_ros_ && publisher_.trylock()) 00306 { 00307 should_publish_ = false; 00308 00309 riq_msgs::RIQHandState &msg(publisher_.msg_); 00310 riq_msgs::RIQActuatorState &thumb(msg.thumb); 00311 riq_msgs::RIQActuatorState &right(msg.right_finger); 00312 riq_msgs::RIQActuatorState &left(msg.left_finger); 00313 riq_msgs::RIQActuatorState &scissors(msg.scissors); 00314 00315 msg.operational = 00316 (gripper_status.initialization_ == 1) && 00317 (state->fault_status_ == RIQHandStateEcat::NO_FAULT) && 00318 !halted_; 00319 00320 // status, mode, and object field constants are defined to be the same as EtherCAT interface values 00321 msg.status = gripper_status.status_; 00322 msg.mode = gripper_status.mode_; 00323 msg.grip = gripper_status.grip_; 00324 msg.object = object_status.detected_; 00325 00326 thumb.object_detected = object_status.thumb_detected_; 00327 right.object_detected = object_status.right_finger_detected_; 00328 left.object_detected = object_status.left_finger_detected_; 00329 scissors.object_detected = object_status.scissors_detected_; 00330 00331 thumb.position = RIQHandStateEcat::convertPosition(state->thumb_position_); 00332 right.position = RIQHandStateEcat::convertPosition(state->right_finger_position_); 00333 left.position = RIQHandStateEcat::convertPosition(state->left_finger_position_); 00334 scissors.position = RIQHandStateEcat::convertPosition(state->scissors_position_); 00335 00336 thumb.current = RIQHandStateEcat::convertCurrent(state->thumb_current_); 00337 right.current = RIQHandStateEcat::convertCurrent(state->right_finger_current_); 00338 left.current = RIQHandStateEcat::convertCurrent(state->left_finger_current_); 00339 scissors.current = RIQHandStateEcat::convertCurrent(state->scissors_current_); 00340 00341 publisher_.unlockAndPublish(); 00342 } 00343 00344 bool rv = true; 00345 00346 if (needs_watchdog_reset_) 00347 { 00348 after_watchdog_reset_countdown_ = 100; 00349 } 00350 else if (after_watchdog_reset_countdown_ > 0) 00351 { 00352 --after_watchdog_reset_countdown_; 00353 if ((prev_state->fault_status_ == RIQHandStateEcat::FAULT_COMMUNICATION_TIMEOUT) && 00354 (state->fault_status_ == RIQHandStateEcat::NO_FAULT)) 00355 { 00356 ROS_INFO("Communication fault cleared at %d", after_watchdog_reset_countdown_); 00357 } 00358 } 00359 00360 if (needs_reset_countdown_ > 0) 00361 { 00362 after_reset_countdown_ = 100; 00363 } 00364 else if (after_reset_countdown_ > 0) 00365 { 00366 --after_reset_countdown_; 00367 bool was_major_fault = 00368 (prev_state->fault_status_ == RIQHandStateEcat::FAULT_MAJOR_SCISSORS_DISPLACEMENT) || 00369 (prev_state->fault_status_ == RIQHandStateEcat::FAULT_MAJOR_SCISSORS_DISPLACEMENT); 00370 if (was_major_fault && (state->fault_status_ == RIQHandStateEcat::NO_FAULT)) 00371 { 00372 ROS_INFO("Major fault cleared at %d", after_reset_countdown_); 00373 } 00374 } 00375 00376 // When certain faults occur, halt motors and save fault code 00377 if (!halted_ && (state->fault_status_ != RIQHandStateEcat::NO_FAULT)) 00378 { 00379 switch (state->fault_status_) 00380 { 00381 case RIQHandStateEcat::FAULT_COMMUNICATION_TIMEOUT: 00382 // Ignore this error, for a few cycles after has been cleared 00383 if (after_watchdog_reset_countdown_ == 0) 00384 { 00385 rv = false; 00386 latched_fault_code_ = state->fault_status_; 00387 ROS_ERROR("Watchdog"); 00388 } 00389 break; 00390 case RIQHandStateEcat::FAULT_INSUFFICIENT_SUPPLY_VOLTAGE: 00391 rv = false; 00392 latched_fault_code_ = state->fault_status_; 00393 break; 00394 case RIQHandStateEcat::FAULT_MAJOR_SCISSORS_DISPLACEMENT: 00395 case RIQHandStateEcat::FAULT_MAJOR_FINGER_DISPLACEMENT: 00396 // Ignore these errors for a while after resetting 00397 if (after_reset_countdown_ == 0) 00398 { 00399 needs_reset_ = true; 00400 rv = false; 00401 latched_fault_code_ = state->fault_status_; 00402 } 00403 break; 00404 default: 00405 // Do nothing for other fault codes 00406 break; 00407 } 00408 } 00409 00410 return rv; 00411 } 00412 00413 00414 00415 void RIQHand::disableWatchdog(EtherCAT_SlaveHandler *sh) 00416 { 00417 // The ethercat process data watchdog timeout on set to 100ms after reset. 00418 // This disables watchdog by change timeout to special value of 0. 00419 EthercatDirectCom com(EtherCAT_DataLinkLayer::instance()); 00420 static const unsigned WATCHDOG_TIME_PDI_ADDR = 0x410; 00421 static const unsigned WATCHDOG_TIME_PROCESS_DATA_ADDR = 0x420; 00422 uint16_t timeout = 0; 00423 if (writeData(&com, sh, WATCHDOG_TIME_PDI_ADDR, &timeout, 2, FIXED_ADDR) != 0) 00424 { 00425 ROS_ERROR("Error disabling PDI watchdog\n"); 00426 } 00427 timeout = 0; 00428 if (writeData(&com, sh, WATCHDOG_TIME_PROCESS_DATA_ADDR, &timeout, 2, FIXED_ADDR) != 0) 00429 { 00430 ROS_ERROR("Error disabling process data watchdog\n"); 00431 } 00432 } 00433 00434 00435 void RIQHand::collectDiagnostics(EthercatCom *com) 00436 { 00437 EthercatDevice::collectDiagnostics(com); 00438 00439 ECatALStatusAll al_status; 00440 bool al_status_good = al_status.readData(com,sh_); 00441 00442 { boost::unique_lock<boost::mutex> lock(diagnostics_mutex_); 00443 collect_diagnostics_.al_status_good_ = al_status_good; 00444 collect_diagnostics_.al_status_ = al_status; 00445 } 00446 00447 // Use diagnostics collection thread to clear watchdog timeout error (when requested by reset_motors) 00448 // When the EtherCAT master does not update slave process data every 100ms, the watchdog times out. 00449 // When this occcurs the device automatically goes into the SAFE-OP state. 00450 // To get device operational again, the AL error is acknowledged, 00451 // and the device is put back into the OPerational state 00452 if (needs_watchdog_reset_) 00453 { 00454 if (!al_status_good) 00455 { 00456 // Without status data, it is not possible to determine if 00457 // watchdog error does indeed need to cleared. 00458 //ROS_WARN("Cannot reset watchdog, no status data"); 00459 } 00460 else if (al_status.status_code_.error_code_ == ECatALStatusCode::SYNC_MANAGER_WATCHDOG) 00461 { 00462 // reset error code and move back into operational state 00463 ECatALControl al_control; 00464 al_control.raw_ = 0; 00465 al_control.ack_error_ = 1; 00466 al_control.state_ = ECatStates::OP; 00467 if (al_control.writeData(com, sh_)) 00468 { 00469 // watchdog error has been cleared 00470 //ROS_WARN("Watchdog reset"); 00471 needs_watchdog_reset_ = false; 00472 } 00473 else 00474 { 00475 //ROS_WARN("Watchdog reset failed"); 00476 } 00477 } 00478 else 00479 { 00480 // No watchdog error to clear 00481 //ROS_WARN("Watchdog reset uneeded"); 00482 needs_watchdog_reset_ = false; 00483 } 00484 } 00485 } 00486 00487 00488 void RIQHand::diagnostics(diagnostic_updater::DiagnosticStatusWrapper &d, unsigned char *buffer) 00489 { 00490 const RIQHandStateEcat *status = (const RIQHandStateEcat *)(buffer + command_size_); 00491 const RIQHandCommandEcat *command = (const RIQHandCommandEcat *)(buffer); 00492 00493 // Get copy of diagnostics data collected with another thread 00494 if (diagnostics_mutex_.try_lock()) 00495 { 00496 publish_diagnostics_ = collect_diagnostics_; 00497 diagnostics_mutex_.unlock(); 00498 } 00499 00500 stringstream str; 00501 str << "EtherCAT Device #" << setw(2) << setfill('0') << sh_->get_ring_position() << " (RIQHand)"; 00502 d.name = str.str(); 00503 d.summary(d.OK, "OK"); 00504 char serial[32]; 00505 snprintf(serial, sizeof(serial), "%05d-%05d", sh_->get_product_code(), sh_->get_serial()); 00506 d.hardware_id = serial; 00507 00508 d.clear(); 00509 d.addf("Product code", "RIQ Hand (%d), Revision %d", 00510 sh_->get_product_code(), sh_->get_revision()); 00511 d.addf("Serial Number", "%s", serial); 00512 00513 const RIQGripperStatus &gripper_status(status->gripper_status_); 00514 d.addf("Initialization", "%s (%d)", (gripper_status.initialization_ ? "Initialized" : "Reset"), 00515 int(gripper_status.initialization_) ); 00516 d.addf("Gripper Mode", "%s (%d)", gripper_status.modeString(), gripper_status.mode_); 00517 d.addf("Gripper Status", "%s (%d)", gripper_status.statusString(), gripper_status.status_); 00518 bool in_scissors_mode = gripper_status.inScissorsMode(); 00519 00520 const RIQObjectStatus &object_status(status->object_status_); 00521 d.addf("Object Detected", "%s (%d)", 00522 object_status.detectedString(in_scissors_mode), 00523 object_status.detected_); 00524 00525 d.addf("Fault", "%s (%d)", status->faultString(), int(status->fault_status_)); 00526 00527 if (latched_fault_code_ != 0) 00528 { 00529 // If fault was latched, it is error that requires motor reset 00530 // Examples : communication timeout, undervoltage 00531 d.mergeSummary(d.ERROR, RIQHandStateEcat::faultString(latched_fault_code_)); 00532 } 00533 else if (status->fault_status_ != status->NO_FAULT) 00534 { 00535 // If fault was not latched 00536 d.mergeSummary(d.WARN, status->faultString()); 00537 } 00538 00539 d.addf("Thumb position", "%f (%u)", 00540 status->convertPosition(status->thumb_position_), 00541 unsigned(status->thumb_position_)); 00542 d.addf("Thumb position", "%fmA (%u)", 00543 1000.0 * status->convertCurrent(status->thumb_current_), 00544 unsigned(status->thumb_current_)); 00545 00546 d.addf("Right finger position", "%f (%u)", 00547 status->convertPosition(status->right_finger_position_), 00548 unsigned(status->right_finger_position_)); 00549 d.addf("Right finger current", "%fmA (%u)", 00550 1000.0 * status->convertCurrent(status->right_finger_current_), 00551 unsigned(status->right_finger_current_)); 00552 00553 d.addf("Left finger position", "%f (%u)", 00554 status->convertPosition(status->left_finger_position_), 00555 unsigned(status->left_finger_position_)); 00556 d.addf("Left finger current", "%fmA (%u)", 00557 1000.0 * status->convertCurrent(status->left_finger_current_), 00558 unsigned(status->left_finger_current_)); 00559 00560 d.addf("Scissors position", "%f (%u)", 00561 status->convertPosition(status->scissors_position_), 00562 unsigned(status->scissors_position_)); 00563 d.addf("Scissors current", "%fmA (%u)", 00564 1000.0 * status->convertCurrent(status->scissors_current_), 00565 unsigned(status->scissors_current_)); 00566 00567 00568 const RIQActionRequest &action_request(command->action_request_); 00569 00570 d.addf("Initialization request", "%s (%d)", 00571 (action_request.initialize_ ? "Initialize" : "Reset"), 00572 unsigned(action_request.initialize_)); 00573 d.addf("Mode request", "%s (%d)", action_request.modeString(), 00574 unsigned(action_request.mode_)); 00575 d.addf("Grip request", "%s (%d)", action_request.gripString(), 00576 unsigned(action_request.grip_)); 00577 d.addf("Force", "%f (%d)", (double(command->force_)/255.0), 00578 unsigned(command->force_)); 00579 d.addf("Velocity", "%f (%d)", (double(command->velocity_)/255.0), 00580 unsigned(command->velocity_)); 00581 00582 00583 if (publish_diagnostics_.al_status_good_) 00584 { 00585 const ECatALStatusAll &al_status(publish_diagnostics_.al_status_); 00586 d.addf("AL Status", "%s : %s", 00587 (al_status.status_.error_?"Error":"Good"), 00588 al_status.status_code_.errorCodeString()); 00589 d.addf("AL State", "%s (%d)", 00590 al_status.status_.stateString(), 00591 al_status.status_.state_); 00592 } 00593 else 00594 { 00595 d.addf("AL Status", "INVALID"); 00596 } 00597 00598 // TODO : RIQHand RX error counters do not seem to work. 00599 // Get EtherCAT support document to figure out what slave device registers are supported 00600 EthercatDevice::ethercatDiagnostics(d, 1); // RIQHand has only a single port 00601 } 00602 00603 00604 }; //namespace riq_hand_ethercat_hardware