00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00023
00024
00025 #include "DS402Node.h"
00026
00027 #include "exceptions.h"
00028 #include "sync.h"
00029
00030
00031
00032 namespace icl_hardware {
00033 namespace canopen_schunk {
00034
00035 DS402Node::DS402Node(const uint8_t node_id, const CanDevPtr& can_device, HeartBeatMonitor::Ptr heartbeat_monitor):
00036 DS301Node(node_id,can_device, heartbeat_monitor),
00037 m_interpolation_cycle_time_ms(20),
00038 m_max_number_of_state_transitions(10),
00039 m_homing_method(0),
00040 m_transmission_factor(1)
00041 {
00042 }
00043
00044 void DS402Node::setDefaultPDOMapping (const DS402Node::eDefaultPDOMapping mapping)
00045 {
00046 PDO::MappingConfigurationList rpdo_mappings;
00047 PDO::MappingConfigurationList tpdo_mappings;
00048 switch (mapping)
00049 {
00050 case PDO_MAPPING_CONTROLWORD_STATUSWORD:
00051 {
00052
00053 rpdo_mappings.push_back(PDO::MappingConfiguration(0x6040, 0, 16, "control_word"));
00054 tpdo_mappings.push_back(PDO::MappingConfiguration(0x6041, 0, 16, "status_word"));
00055 initPDOMappingSingle (rpdo_mappings, 0, PDO::SYNCHRONOUS_CYCLIC, DS301Node::RECEIVE_PDO);
00056 initPDOMappingSingle (tpdo_mappings, 0, PDO::SYNCHRONOUS_CYCLIC, DS301Node::TRANSMIT_PDO);
00057 break;
00058 }
00059 case PDO_MAPPING_INTERPOLATED_POSITION_MODE:
00060 {
00061
00062 rpdo_mappings.push_back(PDO::MappingConfiguration(0x6040, 0, 16, "control_word"));
00063 rpdo_mappings.push_back(PDO::MappingConfiguration(0x60C1, 1, 32, "interpolation_buffer"));
00064
00065 tpdo_mappings.push_back(PDO::MappingConfiguration(0x6041, 0, 16, "status_word"));
00066 tpdo_mappings.push_back(PDO::MappingConfiguration(0x6064, 0, 32, "measured_position"));
00067
00068
00069 initPDOMappingSingle (rpdo_mappings, 0, PDO::SYNCHRONOUS_CYCLIC, DS301Node::RECEIVE_PDO);
00070 initPDOMappingSingle (tpdo_mappings, 0, PDO::SYNCHRONOUS_CYCLIC, DS301Node::TRANSMIT_PDO);
00071 break;
00072 }
00073 case PDO_MAPPING_PROFILE_POSITION_MODE:
00074 {
00075
00076 rpdo_mappings.push_back(PDO::MappingConfiguration(0x6040, 0, 16, "control_word"));
00077 rpdo_mappings.push_back(PDO::MappingConfiguration(0x607A, 0, 32, "target_position"));
00078
00079 tpdo_mappings.push_back(PDO::MappingConfiguration(0x6041, 0, 16, "status_word"));
00080 tpdo_mappings.push_back(PDO::MappingConfiguration(0x6064, 0, 32, "measured_position"));
00081
00082
00083 initPDOMappingSingle (rpdo_mappings, 0, PDO::SYNCHRONOUS_CYCLIC, DS301Node::RECEIVE_PDO);
00084 initPDOMappingSingle (tpdo_mappings, 0, PDO::SYNCHRONOUS_CYCLIC, DS301Node::TRANSMIT_PDO);
00085 break;
00086 }
00087 default:
00088 {
00089 break;
00090 }
00091 }
00092
00093 }
00094
00095
00096 bool DS402Node::setTarget(const float target)
00097 {
00098 int64_t target_ticks = m_transmission_factor * target;
00099 bool success = false;
00100 switch (m_op_mode)
00101 {
00102 case ds402::MOO_PROFILE_POSITION_MODE:
00103 {
00104 success = setRPDOValue("target_position", static_cast<int32_t>(target_ticks));
00105 break;
00106 }
00107 case ds402::MOO_VELOCITY_MODE:
00108 {
00109 success = setRPDOValue("vl_target_velocity", static_cast<int16_t>(target_ticks));
00110 break;
00111 }
00112 case ds402::MOO_PROFILE_VELOCITY_MODE:
00113 {
00114 success = setRPDOValue("target_velocity", static_cast<int32_t>(target_ticks));
00115 break;
00116 }
00117 case ds402::MOO_PROFILE_TORQUE_MODE:
00118 {
00119 success = setRPDOValue("target_torque", static_cast<int16_t>(target_ticks));
00120 break;
00121 }
00122 case ds402::MOO_HOMING_MODE:
00123 {
00124 LOGGING_ERROR_C (CanOpen, DS402Node, "Homing mode does not know a target value." << endl);
00125 success = false;
00126 break;
00127 }
00128 case ds402::MOO_INTERPOLATED_POSITION_MODE:
00129 {
00130 success = setRPDOValue("interpolation_buffer", static_cast<int32_t>(target_ticks));
00131 break;
00132 }
00133 case ds402::MOO_CYCLIC_SYNC_POSITION_MODE:
00134 {
00135 LOGGING_WARNING_C (CanOpen, DS402Node, "Target for cyclic sync position mode is not yet supported." << endl);
00136 success = false;
00137 break;
00138 }
00139 case ds402::MOO_CYCLIC_SYNC_VELOCITY_MODE:
00140 {
00141 LOGGING_WARNING_C (CanOpen, DS402Node, "Target for cyclic sync velocity mode is not yet supported." << endl);
00142 success = false;
00143 break;
00144 }
00145 case ds402::MOO_CYCLIC_SYNC_TORQUE_MODE:
00146 {
00147 LOGGING_WARNING_C (CanOpen, DS402Node, "Target for cyclic sync torque mode is not yet supported." << endl);
00148 success = false;
00149 break;
00150 }
00151 default:
00152 {
00153 LOGGING_ERROR_C (CanOpen, DS402Node, "No legal mode of operation is set. setTarget() is non-functional. " << endl);
00154 break;
00155 }
00156 }
00157 if (success)
00158 {
00159 LOGGING_DEBUG_C(CanOpen, DS402Node, "Set target " << target << " for node " << m_node_id << endl);
00160
00161 }
00162 return success;
00163 }
00164
00165 void DS402Node::startPPMovement()
00166 {
00167 ds402::Controlword word;
00168 word.all = getRPDOValue<uint16_t> ("control_word");
00169 word.bit.operation_mode_specific_0 = 1;
00170 setRPDOValue ("control_word", word.all);
00171 LOGGING_DEBUG_C(CanOpen, DS402Node, "Triggered motion for node " << m_node_id << endl);
00172
00173 }
00174
00175 void DS402Node::acceptPPTargets ()
00176 {
00177 ds402::Controlword word;
00178 word.all = getRPDOValue<uint16_t> ("control_word");
00179 word.bit.operation_mode_specific_0 = 0;
00180 setRPDOValue ("control_word", word.all);
00181 LOGGING_DEBUG_C(CanOpen, DS402Node, "Accepting new targets for node " << m_node_id << endl);
00182
00183 }
00184
00185 double DS402Node::getTargetFeedback()
00186 {
00187 int32_t feedback;
00188 switch (m_op_mode)
00189 {
00190 case ds402::MOO_PROFILE_POSITION_MODE:
00191 {
00192 feedback = getTPDOValue<int32_t>("measured_position");
00193 break;
00194 }
00195 case ds402::MOO_VELOCITY_MODE:
00196 {
00197
00198 LOGGING_ERROR (CanOpen, "GetTargetFeature is not yet implemented for velocity mode." << endl);
00199 return 0;
00200 }
00201 case ds402::MOO_PROFILE_VELOCITY_MODE:
00202 {
00203
00204 LOGGING_ERROR (CanOpen, "GetTargetFeature is not yet implemented for profile velocity mode." << endl);
00205 return 0;
00206 }
00207 case ds402::MOO_PROFILE_TORQUE_MODE:
00208 {
00209
00210 LOGGING_ERROR (CanOpen, "GetTargetFeature is not yet implemented for profile torque mode." << endl);
00211 return 0;
00212 }
00213 case ds402::MOO_HOMING_MODE:
00214 {
00215
00216
00217 return 0;
00218 }
00219 case ds402::MOO_INTERPOLATED_POSITION_MODE:
00220 {
00221 feedback = getTPDOValue<int32_t>("measured_position");
00222 break;
00223 }
00224 case ds402::MOO_CYCLIC_SYNC_POSITION_MODE:
00225 {
00226
00227 LOGGING_ERROR (CanOpen, "GetTargetFeature is not yet implemented for cyclic sync position mode." << endl);
00228 return 0;
00229 }
00230 case ds402::MOO_CYCLIC_SYNC_VELOCITY_MODE:
00231 {
00232
00233 LOGGING_ERROR (CanOpen, "GetTargetFeature is not yet implemented for cyclic sync velocity mode." << endl);
00234 return 0;
00235 }
00236 case ds402::MOO_CYCLIC_SYNC_TORQUE_MODE:
00237 {
00238
00239 LOGGING_ERROR (CanOpen, "GetTargetFeature is not yet implemented for cyclic sync torque mode." << endl);
00240 return 0;
00241 }
00242 default:
00243 {
00244 LOGGING_ERROR_C (CanOpen, DS402Node, "No legal mode of operation is set. getTargetFeedback() is non-functional. " << endl);
00245 return 0;
00246 }
00247 }
00248
00249 #ifdef _IC_BUILDER_ICL_COMM_WEBSOCKET_
00250 if (m_ws_broadcaster)
00251 {
00252 m_ws_broadcaster->robot->setJointPosition(feedback, m_node_id);
00253 }
00254 #endif // _IC_BUILDER_ICL_COMM_WEBSOCKET_
00255
00256
00257 return static_cast<double>(feedback) / m_transmission_factor;
00258 }
00259
00260
00261 void DS402Node::setNMTState(const NMT::eNMT_State state, const NMT::eNMT_SubState sub_state)
00262 {
00263
00264 }
00265
00266 void DS402Node::quickStop()
00267 {
00268 if (m_current_ds402_state == ds402::STATE_OPERATION_ENABLE)
00269 {
00270 LOGGING_INFO (CanOpen, "Quick stop of node " << m_node_id << " requested!" << endl);
00271 std::string identifier = "control_word";
00272 ds402::Controlword word;
00273 try
00274 {
00275 word.all = getRPDOValue<uint16_t> (identifier);
00276 word.bit.enable_voltage = 1;
00277 word.bit.quick_stop = 0;
00278 word.bit.reset_fault = 0;
00279 word.bit.halt = 1;
00280 setRPDOValue (identifier, word.all);
00281 }
00282 catch (const PDOException& e)
00283 {
00284 LOGGING_WARNING_C (CanOpen, DS402Node, "Could not find a PDO for the control word. Using slower SDO calls." << endl);
00285 word.bit.enable_voltage = 1;
00286 word.bit.quick_stop = 0;
00287 word.bit.reset_fault = 0;
00288 word.bit.halt = 1;
00289
00290 m_sdo.download(false, ds402::ID_CONTROL_WORD, 0x00, word.all);
00291 }
00292 }
00293 m_expected_ds402_state = ds402::STATE_QUICKSTOP_ACTIVE;
00294 }
00295
00296 void DS402Node::stopNode()
00297 {
00298 quickStop();
00299 }
00300
00301
00302 void DS402Node::initDS402State (const ds402::eState& requested_state)
00303 {
00304 LOGGING_DEBUG (CanOpen, "State " << deviceStatusString(requested_state) << " requested for node "
00305 << static_cast<int>(m_node_id) << "" << endl);
00306 if (requested_state == ds402::STATE_START ||
00307 requested_state == ds402::STATE_NOT_READY_TO_SWITCH_ON ||
00308 requested_state == ds402::STATE_FAULT_REACTION_ACTIVE)
00309 {
00310 LOGGING_ERROR_C (CanOpen, DS402Node, "Illegal target state requested. Requested state was: " <<
00311 ds402::deviceStatusString(requested_state) << ", however that state cannot be entered manually!" << endl);
00312 return;
00313 }
00314
00315
00316 ds402::Statusword status_word;
00317 status_word.all = getTPDOValue<uint16_t>("status_word");
00318 ds402::eState current_state = ds402::stateFromStatusword(status_word);
00319
00320
00321 if (current_state == ds402::STATE_FAULT)
00322 {
00323 bool reset_fault_successful = false;
00324 for (size_t i = 0; i < 5; ++i)
00325 {
00326 reset_fault_successful = resetFault();
00327 if (reset_fault_successful)
00328 {
00329 break;
00330 }
00331 }
00332
00333 if (!reset_fault_successful)
00334 {
00335 LOGGING_INFO (CanOpen, "Unable to reset from fault state after 5 tries. " <<
00336 "Trying to do a hard reset on the device." << endl);
00337 m_nmt.stop();
00338 usleep(100000);
00339 m_nmt.start();
00340
00341 if (!resetFault())
00342 {
00343 std::stringstream ss;
00344 ss << "Could not perform fault reset for node "
00345 << static_cast<int>(m_node_id)
00346 << " after multiple tries. "
00347 << "Is the device hard-disabled?"
00348 << "\nOtherwise: Have you tried turning it off and on again?";
00349 throw (DeviceException(ss.str()));
00350 }
00351 }
00352
00353 m_sdo.upload(false, 0x6041, 0x0, status_word.all );
00354 current_state = ds402::stateFromStatusword(status_word);
00355 }
00356
00357
00358 size_t num_transitions = 0;
00359
00360 while (current_state != requested_state && num_transitions < m_max_number_of_state_transitions)
00361 {
00362 LOGGING_DEBUG (CanOpen, "Node " << static_cast<int>(m_node_id) << " currently in state " <<
00363 deviceStatusString(current_state) << endl);
00364 switch (current_state)
00365 {
00366 case ds402::STATE_SWITCH_ON_DISABLED:
00367 {
00368 if (requested_state > ds402::STATE_SWITCH_ON_DISABLED)
00369 {
00370 doDS402StateTransition(ds402::STATE_TRANS_SHUTDOWN);
00371 m_expected_ds402_state = ds402::STATE_READY_TO_SWITCH_ON;
00372 }
00373 break;
00374 }
00375 case ds402::STATE_READY_TO_SWITCH_ON:
00376 {
00377 if (requested_state > ds402::STATE_READY_TO_SWITCH_ON)
00378 {
00379 doDS402StateTransition(ds402::STATE_TRANS_SWITCH_ON);
00380 m_expected_ds402_state = ds402::STATE_SWITCHED_ON;
00381 }
00382 else
00383 {
00384 doDS402StateTransition(ds402::STATE_TRANS_QUICK_STOP);
00385 m_expected_ds402_state = ds402::STATE_SWITCH_ON_DISABLED;
00386 }
00387 break;
00388 }
00389 case ds402::STATE_SWITCHED_ON:
00390 {
00391 if (requested_state > ds402::STATE_SWITCHED_ON)
00392 {
00393 doDS402StateTransition(ds402::STATE_TRANS_ENABLE_OPERATION);
00394 m_expected_ds402_state = ds402::STATE_OPERATION_ENABLE;
00395 }
00396 else if (requested_state == ds402::STATE_SWITCH_ON_DISABLED)
00397 {
00398 doDS402StateTransition(ds402::STATE_TRANS_INITIALIZE);
00399 m_expected_ds402_state = ds402::STATE_SWITCH_ON_DISABLED;
00400 }
00401 else
00402 {
00403 doDS402StateTransition(ds402::STATE_TRANS_SHUTDOWN);
00404 m_expected_ds402_state = ds402::STATE_READY_TO_SWITCH_ON;
00405 }
00406 break;
00407 }
00408 case ds402::STATE_OPERATION_ENABLE:
00409 {
00410 if (requested_state > ds402::STATE_OPERATION_ENABLE)
00411 {
00412 doDS402StateTransition(ds402::STATE_TRANS_QUICK_STOP);
00413 m_expected_ds402_state = ds402::STATE_QUICKSTOP_ACTIVE;
00414 }
00415 else if (requested_state == ds402::STATE_SWITCHED_ON)
00416 {
00417 doDS402StateTransition(ds402::STATE_TRANS_SWITCH_ON);
00418 m_expected_ds402_state = ds402::STATE_SWITCHED_ON;
00419 }
00420 else if (requested_state == ds402::STATE_READY_TO_SWITCH_ON)
00421 {
00422 doDS402StateTransition(ds402::STATE_TRANS_SHUTDOWN);
00423 m_expected_ds402_state = ds402::STATE_READY_TO_SWITCH_ON;
00424 }
00425 else if (requested_state == ds402::STATE_SWITCH_ON_DISABLED)
00426 {
00427 doDS402StateTransition(ds402::STATE_TRANS_INITIALIZE);
00428 m_expected_ds402_state = ds402::STATE_SWITCH_ON_DISABLED;
00429 }
00430 break;
00431 }
00432 case ds402::STATE_QUICKSTOP_ACTIVE:
00433 {
00434
00435
00436 int16_t quick_stop_option_code = 0;
00437 try
00438 {
00439 m_sdo.download(false, 0x605a, 0, quick_stop_option_code);
00440 }
00441 catch (const ProtocolException& e)
00442 {
00443 LOGGING_WARNING (CanOpen, "Caught error while downloading quick-stop-option code. "
00444 << "Probably it is not implemented, as it is optional. "
00445 << "Will carry on assuming quick-stop-option-code = 0.\n"
00446 << "Error was: " << e.what() << endl
00447 );
00448 }
00449 if (quick_stop_option_code >=5 && quick_stop_option_code <=8 &&
00450 requested_state == ds402::STATE_OPERATION_ENABLE)
00451 {
00452 doDS402StateTransition(ds402::STATE_TRANS_ENABLE_OPERATION);
00453 m_expected_ds402_state = ds402::STATE_OPERATION_ENABLE;
00454 }
00455 else
00456 {
00457 doDS402StateTransition(ds402::STATE_TRANS_INITIALIZE);
00458 m_expected_ds402_state = ds402::STATE_SWITCH_ON_DISABLED;
00459 }
00460 break;
00461 }
00462 case ds402::STATE_FAULT:
00463 {
00464 LOGGING_ERROR_C (CanOpen, DS402Node, "Landed in FAULT state while performing transition to " <<
00465 "state " << ds402::deviceStatusString(requested_state) <<
00466 ". Starting all over again..." << endl);
00467 break;
00468 }
00469 case ds402::STATE_START:
00470 case ds402::STATE_FAULT_REACTION_ACTIVE:
00471 case ds402::STATE_NOT_READY_TO_SWITCH_ON:
00472 {
00473
00474 break;
00475 }
00476 default:
00477 {
00478
00479 LOGGING_ERROR_C (CanOpen, DS402Node, "Landed in unknown state while performing transition to " <<
00480 "state " << ds402::deviceStatusString(requested_state) <<
00481 ". Aborting state transition." << endl);
00482 break;
00483 }
00484 }
00485
00486
00487 m_sdo.upload(false, 0x6041, 0x0, status_word.all );
00488 current_state = ds402::stateFromStatusword(status_word);
00489
00490 LOGGING_INFO (CanOpen, "Node " << static_cast<int>(m_node_id) << " reached state " <<
00491 deviceStatusString(current_state) << endl);
00492 m_current_ds402_state = current_state;
00493 setTPDOValue("status_word", status_word.all);
00494
00495 num_transitions++;
00496 }
00497 m_expected_ds402_state = m_current_ds402_state;
00498
00499 }
00500
00501
00502 void DS402Node::home()
00503 {
00504 if (m_homing_method == 0)
00505 {
00506 LOGGING_WARNING (CanOpen, "Homing method for node " << static_cast<int>(m_node_id) <<
00507 " is not set. Aborting homing now." << endl);
00508 return;
00509 }
00510
00511 LOGGING_INFO (CanOpen, "Starting homing for node " << static_cast<int>(m_node_id) << endl);
00512
00513 setModeOfOperation(ds402::MOO_HOMING_MODE);
00514
00515 initDS402State(ds402::STATE_OPERATION_ENABLE);
00516
00517 ds402::Controlword controlword;
00518 controlword.all = getRPDOValue<uint16_t>("control_word");
00519
00520
00521 controlword.bit.operation_mode_specific_0 = 1;
00522 controlword.bit.halt = 0;
00523
00524
00525 m_sdo.download(false, ds402::ID_CONTROL_WORD, 0x0, controlword.all);
00526
00527 ds402::Statusword statusword;
00528 bool homing_attained = false;
00529 bool homing_error = false;
00530 while (!homing_attained)
00531 {
00532 m_sdo.upload(false, ds402::ID_STATUS_WORD, 0, statusword.all);
00533 homing_attained = statusword.bit.operation_mode_specific_0;
00534 homing_error = statusword.bit.operation_mode_specific_1;
00535
00536 if (homing_error)
00537 {
00538 std::stringstream ss;
00539 ss << "Homing of node " << static_cast<int>(m_node_id) << " failed.";
00540 throw DeviceException(ss.str());
00541 }
00542
00543 if (homing_attained)
00544 {
00545
00546 LOGGING_INFO (CanOpen, "Done homing for node " << static_cast<int>(m_node_id) << endl);
00547 break;
00548 }
00549
00550 usleep(100000);
00551 }
00552 }
00553
00554 void DS402Node::printStatus()
00555 {
00556 ds402::Statusword statusword;
00557 statusword.all = getTPDOValue<uint16_t> ("status_word");
00558 ds402::eState state = stateFromStatusword(statusword);
00559 std::stringstream ss;
00560 ss << "Device " << static_cast<int>(m_node_id) << " status: " <<
00561 binaryString(statusword.all) << "\n(state " << ds402::deviceStatusString(state)
00562 << ")" << std::endl;
00563 ss << "Fault: " << statusword.bit.fault << std::endl;
00564 ss << "Switched on: " << statusword.bit.switched_on << std::endl;
00565 ss << "Operation enabled: " << statusword.bit.operation_enabled << std::endl;
00566 ss << "Voltage enabled: " << statusword.bit.voltage_enabled << std::endl;
00567 ss << "Quick stop active: " << statusword.bit.quick_stop << std::endl;
00568 ss << "Target reached: " << statusword.bit.target_reached << std::endl;
00569
00570
00571 ss << operationModeSpecificStatus(statusword);
00572
00573 LOGGING_INFO_C (CanOpen, DS402Node, ss.str() << endl);
00574 }
00575
00576 std::string DS402Node::operationModeSpecificStatus (const ds402::Statusword& statusword)
00577 {
00578 std::stringstream ss;
00579 switch (m_op_mode)
00580 {
00581 case ds402::MOO_PROFILE_POSITION_MODE:
00582 {
00583 ss << "Set-point acknowledge: " << statusword.bit.operation_mode_specific_0 << std::endl;
00584 ss << "Following error: " << statusword.bit.operation_mode_specific_1 << std::endl;
00585 break;
00586 }
00587 case ds402::MOO_VELOCITY_MODE:
00588 {
00589 break;
00590 }
00591 case ds402::MOO_PROFILE_VELOCITY_MODE:
00592 {
00593 ss << "Speed: " << statusword.bit.operation_mode_specific_0 << std::endl;
00594 ss << "Max slippage error: " << statusword.bit.operation_mode_specific_1 << std::endl;
00595 break;
00596 }
00597 case ds402::MOO_PROFILE_TORQUE_MODE:
00598 {
00599 break;
00600 }
00601 case ds402::MOO_HOMING_MODE:
00602 {
00603 ss << "Homing attained: " << statusword.bit.operation_mode_specific_0 << std::endl;
00604 ss << "Homing error: " << statusword.bit.operation_mode_specific_1 << std::endl;
00605 break;
00606 }
00607 case ds402::MOO_INTERPOLATED_POSITION_MODE:
00608 {
00609 ss << "Interpolated position mode active: " << statusword.bit.operation_mode_specific_0 << std::endl;
00610 break;
00611 }
00612 case ds402::MOO_CYCLIC_SYNC_POSITION_MODE:
00613 {
00614 break;
00615 }
00616 case ds402::MOO_CYCLIC_SYNC_VELOCITY_MODE:
00617 {
00618 break;
00619 }
00620 case ds402::MOO_CYCLIC_SYNC_TORQUE_MODE:
00621 {
00622 break;
00623 }
00624 default:
00625 {
00626
00627 break;
00628 }
00629 }
00630
00631 return ss.str();
00632 }
00633
00634 void DS402Node::querySupportedDeviceModes()
00635 {
00636 m_sdo.upload(false, 0x6502, 0, m_supported_modes.all);
00637 }
00638
00639 void DS402Node::initNode()
00640 {
00641 setDefaultPDOMapping(PDO_MAPPING_PROFILE_POSITION_MODE);
00642 DS301Node::initNode();
00643 querySupportedDeviceModes();
00644
00645 boost::function <void()> f = boost::bind(&DS402Node::onStatusWordUpdate, this);
00646 registerPDONotifyCallback("status_word", f);
00647
00648 setModeOfOperation(ds402::MOO_PROFILE_POSITION_MODE);
00649 }
00650
00651 bool DS402Node::isModeSupported (const ds402::eModeOfOperation op_mode)
00652 {
00653 int8_t mode_int = op_mode;
00654 uint32_t bitmask_mode = 0x01 << (mode_int-1);
00655
00656 if ((m_supported_modes.all & bitmask_mode) != bitmask_mode)
00657 {
00658 return false;
00659 }
00660
00661 return true;
00662 }
00663
00664 void DS402Node::printSupportedModesOfOperation()
00665 {
00666 std::stringstream ss;
00667 ss << "Modes of operation supported by device " << static_cast<int>(m_node_id) << std::endl;
00668 if (m_supported_modes.bit.profile_position_mode)
00669 {
00670 ss << "Profile position mode" << std::endl;
00671 }
00672 if (m_supported_modes.bit.velocity_mode)
00673 {
00674 ss << "Velocity mode" << std::endl;
00675 }
00676 if (m_supported_modes.bit.profile_velocity_mode)
00677 {
00678 ss << "Profile velocity mode" << std::endl;
00679 }
00680 if (m_supported_modes.bit.profile_torque_mode)
00681 {
00682 ss << "Profile torque mode" << std::endl;
00683 }
00684 if (m_supported_modes.bit.homing_mode)
00685 {
00686 ss << "Homing mode" << std::endl;
00687 }
00688 if (m_supported_modes.bit.interpolated_position_mode)
00689 {
00690 ss << "Interpolated position mode" << std::endl;
00691 }
00692 if (m_supported_modes.bit.cyclic_sync_position_mode)
00693 {
00694 ss << "Cyclic sync position mode" << std::endl;
00695 }
00696 if (m_supported_modes.bit.cyclic_sync_velocity_mode)
00697 {
00698 ss << "Cyclic sync velocity mode" << std::endl;
00699 }
00700 if (m_supported_modes.bit.cyclic_sync_torque_mode)
00701 {
00702 ss << "Cyclic sync torque mode" << std::endl;
00703 }
00704
00705 LOGGING_INFO (CanOpen, ss.str() << endl);
00706 }
00707
00708
00709 bool DS402Node::setModeOfOperation (const ds402::eModeOfOperation op_mode)
00710 {
00711
00712 if (m_current_ds402_state == ds402::STATE_OPERATION_ENABLE)
00713 {
00714 closeBrakes();
00715 }
00716
00717 if (op_mode != ds402::MOO_HOMING_MODE &&
00718 op_mode != ds402::MOO_INTERPOLATED_POSITION_MODE &&
00719 op_mode != ds402::MOO_PROFILE_POSITION_MODE
00720 )
00721 {
00722 LOGGING_ERROR_C (CanOpen, DS402Node, "Requested to switch to mode " <<
00723 operationModeString(op_mode) << " for node " <<
00724 static_cast<int>(m_node_id) << ", which is currently not supported." << endl);
00725 return false;
00726 }
00727
00728 if (!isModeSupported(op_mode))
00729 {
00730 LOGGING_ERROR_C (CanOpen, DS402Node, "The requested mode: " <<
00731 operationModeString(op_mode) <<
00732 " is not supported by the device " <<
00733 static_cast<int>(m_node_id) << "." << endl);
00734 return false;
00735 }
00736
00737 if (op_mode == ds402::MOO_INTERPOLATED_POSITION_MODE)
00738 {
00739 configureInterpolationCycleTime();
00740 configureInterpolationData (0, 0, 4);
00741 }
00742
00743 bool success = true;
00744
00745 int8_t mode_int = op_mode;
00746 try
00747 {
00748 success = m_sdo.download(false, 0x6060, 0, mode_int);
00749 }
00750 catch (const std::exception& e)
00751 {
00752 LOGGING_ERROR_C (CanOpen, DS402Node, e.what() << endl);
00753 }
00754 if (success)
00755 {
00756 m_op_mode = op_mode;
00757 LOGGING_INFO (CanOpen, "Initialized mode " << ds402::operationModeString(op_mode) <<
00758 " for node " << m_node_id << endl);
00759 }
00760
00761 return success;
00762 }
00763
00764 void DS402Node::configureInterpolationCycleTime (const uint8_t interpolation_cycle_time_ms)
00765 {
00766 if (interpolation_cycle_time_ms != 0)
00767 {
00768 m_interpolation_cycle_time_ms = interpolation_cycle_time_ms;
00769 }
00770 m_sdo.download(false, 0x60c2, 0x01, m_interpolation_cycle_time_ms);
00771 int8_t magnitude = -3;
00772 m_sdo.download(false, 0x60c2, 0x02, magnitude);
00773 }
00774
00775 void DS402Node::setupProfilePositionMode (const ds402::ProfilePositionModeConfiguration& config)
00776 {
00777 configureProfileAcceleration(config.profile_acceleration * m_transmission_factor);
00778
00779
00780
00781 float deceleration = config.profile_deceleration;
00782 if (config.profile_deceleration == 0)
00783 {
00784 deceleration = config.profile_acceleration;
00785 }
00786
00787
00788
00789 try
00790 {
00791 configureProfileDeceleration(deceleration * m_transmission_factor);
00792 }
00793 catch (const ProtocolException& e)
00794 {
00795 LOGGING_DEBUG (CanOpen, "Failed to set the profile deceleration for node " << m_node_id << ". " <<
00796 " Some devices do not support setting this, but use the acceleration value for deceleration, as well. So you might want to ignore this message. " <<
00797 "The error was: " << e.what() << endl
00798 );
00799 }
00800
00801
00802 if (config.motion_profile_type != 0)
00803 {
00804 configureMotionProfileType(config.motion_profile_type * m_transmission_factor);
00805 }
00806 configureProfileVelocity(config.profile_velocity * m_transmission_factor);
00807
00808 m_ppm_config = config;
00809 }
00810
00811 void DS402Node::setupHomingMode (const ds402::HomingModeConfiguration& config)
00812 {
00813 configureHomingSpeeds (config.homing_speed_low, config.homing_speed_high);
00814 configureHomingMethod (config.homing_method);
00815 }
00816
00817 void DS402Node::setupProfileVelocityMode (const ds402::ProfileVelocityModeConfiguration& config)
00818 {
00819 configureSensorSelectionCode (config.sensor_selection_code);
00820 }
00821
00822 void DS402Node::setupProfileTorqueMode (const ds402::ProfileTorqueModeConfiguration& config)
00823 {
00824 configureTorqueSlope (config.torque_slope);
00825 configureTorqueProfileType (config.torque_profile_type);
00826 }
00827
00828 bool DS402Node::resetFault ()
00829 {
00830 ds402::Statusword status_word;
00831 status_word.all = getTPDOValue<uint16_t>("status_word");
00832 ds402::eState current_state = ds402::stateFromStatusword(status_word);
00833
00834 if (current_state != ds402::STATE_FAULT)
00835 {
00836 LOGGING_INFO_C (CanOpen, DS402Node, "Requested resetFault action, but device is currently " <<
00837 "not in state FAULT. Instead it is in state " << deviceStatusString (current_state) <<
00838 ". Not doing anything here." << endl);
00839 return true;
00840 }
00841
00842
00843 m_emcy->clearErrorHistory(m_sdo);
00844
00845
00846 doDS402StateTransition(ds402::STATE_TRANS_FAULT_RESET);
00847
00848 usleep (100000);
00849 status_word.all = getTPDOValue<uint16_t>("status_word");
00850 current_state = ds402::stateFromStatusword(status_word);
00851
00852 if (current_state != ds402::STATE_SWITCH_ON_DISABLED)
00853 {
00854 LOGGING_ERROR_C (CanOpen, DS402Node, "Could not perform fault reset for node " <<
00855 m_node_id << ". Possibly the reason for entering the fault state still exists." <<
00856 endl
00857 );
00858 return false;
00859 }
00860 return true;
00861 }
00862
00863
00864 void DS402Node::configureMaxAcceleration (const uint32_t acceleration)
00865 {
00866 m_sdo.download(false, 0x60c5, 0, acceleration);
00867
00868 LOGGING_INFO_C (CanOpen, DS402Node, "Maximum acceleration for node " << m_node_id << " written." << endl);
00869 }
00870
00871 void DS402Node::configureMaxDeceleration (const uint32_t deceleration)
00872 {
00873 m_sdo.download(false, 0x60c6, 0, deceleration);
00874 LOGGING_INFO_C (CanOpen, DS402Node, "Maximum deceleration for node " << m_node_id << " written." << endl);
00875 }
00876
00877 void DS402Node::configureProfileVelocity (const uint32_t velocity)
00878 {
00879 m_sdo.download(false, 0x6081, 0, velocity);
00880 LOGGING_INFO_C (CanOpen, DS402Node, "Profile velocity for node " << m_node_id << " written with value " <<
00881 velocity << "." << endl);
00882 }
00883
00884
00885 void DS402Node::configureProfileAcceleration (const uint32_t acceleration)
00886 {
00887 m_sdo.download(false, 0x6083, 0, acceleration);
00888 LOGGING_INFO_C (CanOpen, DS402Node, "Profile acceleration for node " << m_node_id << " written with value " <<
00889 acceleration << "." << endl);
00890 }
00891
00892 void DS402Node::configureProfileDeceleration (const uint32_t deceleration)
00893 {
00894 m_sdo.download(false, 0x6084, 0, deceleration);
00895 }
00896
00897 void DS402Node::configureQuickStopDeceleration (const uint32_t deceleration)
00898 {
00899 m_sdo.download(false, 0x6085, 0, deceleration);
00900 LOGGING_INFO_C (CanOpen, DS402Node, "Quick Stop deceleration for node " << m_node_id << " written with value " <<
00901 deceleration << "." << endl);
00902 }
00903
00904 void DS402Node::configureMotionProfileType (const int16_t motion_type)
00905 {
00906 m_sdo.download(false, 0x6086, 0, motion_type);
00907 LOGGING_INFO_C (CanOpen, DS402Node, "Motion profile type for node " << m_node_id << " written with value " <<
00908 motion_type << "." << endl);
00909 }
00910
00911
00912 void DS402Node::configureHomingSpeeds (const uint32_t low_speed, const uint32_t high_speed)
00913 {
00914 m_sdo.download(false, 0x6099, 1, high_speed);
00915 m_sdo.download(false, 0x6099, 2, low_speed);
00916
00917 LOGGING_INFO_C (CanOpen, DS402Node, "Homing speeds for node " << m_node_id << " written." << endl);
00918
00919 }
00920
00921 void DS402Node::configureHomingAcceleration (const uint32_t acceleration)
00922 {
00923 m_sdo.download(false, 0x609A, 0, acceleration);
00924 LOGGING_INFO_C (CanOpen, DS402Node, "Homing acceleration for node " << m_node_id << " written." << endl);
00925 }
00926
00927 void DS402Node::configureHomingMethod (const int8_t homing_method)
00928 {
00929 m_sdo.download(false, 0x6098, 0, homing_method);
00930 LOGGING_INFO_C (CanOpen, DS402Node, "Homing method for node " << m_node_id << " written." << endl);
00931 m_homing_method = homing_method;
00932 }
00933
00934 void DS402Node::configureSensorSelectionCode (const int16_t sensor_selection_code)
00935 {
00936 m_sdo.download(false, 0x606a, 0, sensor_selection_code);
00937 LOGGING_INFO_C (CanOpen, DS402Node, "Sensor selection code for node " << m_node_id << " written." << endl);
00938 }
00939
00940 void DS402Node::configureTorqueProfileType (const int16_t torque_profile_type)
00941 {
00942 m_sdo.download(false, 0x6088, 0, torque_profile_type);
00943 LOGGING_INFO_C (CanOpen, DS402Node, "Torque profile type for node " << m_node_id << " written." << endl);
00944 }
00945
00946 void DS402Node::configureTorqueSlope (const uint32_t torque_slope)
00947 {
00948 m_sdo.download(false, 0x6087, 0, torque_slope);
00949 LOGGING_INFO_C (CanOpen, DS402Node, "Torque slope for node " << m_node_id << " written." << endl);
00950 }
00951
00952 void DS402Node::configureInterpolationData (const uint8_t buffer_organization,
00953 const int16_t interpolation_type,
00954 const uint8_t size_of_data_record)
00955 {
00956 uint8_t data8 = 0;
00957
00958 m_sdo.download(false, 0x60c4, 6, data8);
00959
00960
00961 data8 = 1;
00962 m_sdo.download(false, 0x60c4, 6, data8);
00963
00964
00965 int16_t data16 = 0;
00966 m_sdo.download(false, 0x60c0, 0, data16);
00967
00968 m_sdo.download(false, 0x60c4, 3, buffer_organization);
00969 m_sdo.download(false, 0x60c4, 5, size_of_data_record);
00970
00971 LOGGING_DEBUG_C (CanOpen, DS402Node, "Interpolation data for node " << m_node_id << " written." << endl);
00972 }
00973
00974 void DS402Node::doDS402StateTransition (const ds402::eStateTransission transition)
00975 {
00976 LOGGING_DEBUG_C (CanOpen, DS402Node, "Requested DS402 state transition " << transition << endl);
00977
00978 std::string identifier = "control_word";
00979 ds402::Controlword word;
00980 word.all = getRPDOValue<uint16_t> (identifier);
00981
00982 switch (transition)
00983 {
00984 case ds402::STATE_TRANS_INITIALIZE:
00985 {
00986 word.bit.reset_fault = 0;
00987 word.bit.enable_voltage = 0;
00988 word.bit.operation_mode_specific_0 = 0;
00989 break;
00990 }
00991 case ds402::STATE_TRANS_SHUTDOWN:
00992 {
00993 word.bit.reset_fault = 0;
00994 word.bit.quick_stop = 1;
00995 word.bit.enable_voltage = 1;
00996 word.bit.switch_on = 0;
00997 word.bit.operation_mode_specific_0 = 0;
00998 break;
00999 }
01000 case ds402::STATE_TRANS_SWITCH_ON:
01001 {
01002 word.bit.reset_fault = 0;
01003 word.bit.enable_operation = 0;
01004 word.bit.quick_stop = 1;
01005 word.bit.enable_voltage = 1;
01006 word.bit.switch_on = 1;
01007 word.bit.halt = 1;
01008 break;
01009 }
01010 case ds402::STATE_TRANS_ENABLE_OPERATION:
01011 {
01012 word.bit.reset_fault = 0;
01013 word.bit.enable_operation = 1;
01014 word.bit.quick_stop = 1;
01015 word.bit.enable_voltage = 1;
01016 word.bit.switch_on = 1;
01017 word.bit.halt = 0;
01018 break;
01019 }
01020 case ds402::STATE_TRANS_QUICK_STOP:
01021 {
01022 word.bit.reset_fault = 0;
01023 word.bit.quick_stop = 0;
01024 word.bit.enable_voltage = 1;
01025 word.bit.halt = 1;
01026 break;
01027 }
01028 case ds402::STATE_TRANS_FAULT_RESET:
01029 {
01030 word.bit.reset_fault = 1;
01031 break;
01032 }
01033 default:
01034 {
01035 std::stringstream ss;
01036 ss << "Illegal DS402 state transition requested: " << transition;
01037 throw ProtocolException (ds402::ID_CONTROL_WORD, 0x00, ss.str());
01038 }
01039 }
01040
01041
01042 m_sdo.download(false, ds402::ID_CONTROL_WORD, 0x0, word.all);
01043 LOGGING_DEBUG (CanOpen, "Sent controlword " << binaryString(word.all) << endl);
01044
01045
01046 setRPDOValue(identifier, word.all);
01047 }
01048
01049 void DS402Node::enableNode (const ds402::eModeOfOperation operation_mode)
01050 {
01051 m_nmt.start();
01052 if (m_current_ds402_state == ds402::STATE_FAULT)
01053 {
01054 resetFault();
01055 }
01056
01057 if (operation_mode != ds402::MOO_RESERVED_0)
01058 {
01059 setModeOfOperation(operation_mode);
01060 }
01061 initDS402State(ds402::STATE_OPERATION_ENABLE);
01062
01063 double feedback = getTargetFeedback();
01064 setTarget(feedback);
01065
01066 openBrakes();
01067 }
01068
01069 void DS402Node::disableNode()
01070 {
01071 if (m_current_ds402_state == ds402::STATE_OPERATION_ENABLE)
01072 {
01073 closeBrakes();
01074 }
01075
01076 initDS402State(ds402::STATE_SWITCHED_ON);
01077 }
01078
01079 void DS402Node::openBrakes()
01080 {
01081 if (m_current_ds402_state == ds402::STATE_OPERATION_ENABLE)
01082 {
01083 ds402::Controlword controlword;
01084 controlword.all = getRPDOValue<uint16_t>("control_word");
01085
01086
01087
01088 if (m_op_mode == ds402::MOO_INTERPOLATED_POSITION_MODE)
01089 {
01090 controlword.bit.operation_mode_specific_0 = 1;
01091 controlword.bit.halt = 0;
01092 }
01093 else if (m_op_mode == ds402::MOO_PROFILE_POSITION_MODE)
01094 {
01095 controlword.bit.operation_mode_specific_0 = 0;
01096
01097 controlword.bit.operation_mode_specific_1 = !(m_ppm_config.change_set_immediately);
01098 controlword.bit.operation_mode_specific_2 = m_ppm_config.use_relative_targets;
01099 controlword.bit.reserved_0 = m_ppm_config.use_blending;
01100 controlword.bit.halt = 0;
01101 }
01102 else
01103 {
01104 controlword.bit.operation_mode_specific_0 = 0;
01105 controlword.bit.halt = 0;
01106 }
01107 setRPDOValue("control_word", controlword.all);
01108 }
01109 else
01110 {
01111 LOGGING_ERROR (CanOpen, "OpenBrakes called while not in OPERATION_ENABLE state. Will do nothing" << endl);
01112 }
01113 }
01114
01115
01116 void DS402Node::closeBrakes()
01117 {
01118 if (m_current_ds402_state == ds402::STATE_OPERATION_ENABLE)
01119 {
01120 ds402::Controlword controlword;
01121 m_sdo.upload(false, 0x6040, 0, controlword.all);
01122
01123 if (m_op_mode == ds402::MOO_INTERPOLATED_POSITION_MODE)
01124 {
01125 controlword.bit.operation_mode_specific_0 = 0;
01126 }
01127 controlword.bit.halt = 1;
01128 setRPDOValue("control_word", controlword.all);
01129 }
01130 else
01131 {
01132 LOGGING_ERROR (CanOpen, "CloseBrakes called while not in OPERATION_ENABLE state. Will do nothing" << endl);
01133 }
01134 }
01135
01136 void DS402Node::onStatusWordUpdate()
01137 {
01138 ds402::Statusword statusword;
01139 statusword.all = getTPDOValue<uint16_t>("status_word");
01140
01141
01142
01143 ds402::eState device_state = ds402::stateFromStatusword(statusword);
01144 if (m_current_ds402_state != device_state)
01145 {
01146 if (m_expected_ds402_state != device_state)
01147 {
01148 LOGGING_WARNING (CanOpen, "The device " << m_node_id <<
01149 " has switched to state " <<
01150 ds402::deviceStatusString(device_state) <<
01151 " without host request. " <<
01152 "The controller will adapt the device's status." << endl
01153 );
01154 }
01155 m_current_ds402_state = device_state;
01156 }
01157 }
01158
01159 bool DS402Node::isTargetReached()
01160 {
01161 ds402::Statusword statusword;
01162 statusword.all = getTPDOValue<uint16_t>("status_word");
01163
01164 return statusword.bit.target_reached;
01165 }
01166
01167 ds402::Statusword DS402Node::getStatus()
01168 {
01169 ds402::Statusword word;
01170 word.all = getTPDOValue<uint16_t>("status_word");
01171 return word;
01172 }
01173
01174
01175
01176 }}