DS402Node.cpp
Go to the documentation of this file.
1 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
2 
3 // -- BEGIN LICENSE BLOCK ----------------------------------------------
4 // This file is part of the SCHUNK Canopen Driver suite.
5 //
6 // This program is free software licensed under the LGPL
7 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
8 // You can find a copy of this license in LICENSE folder in the top
9 // directory of the source code.
10 //
11 // © Copyright 2016 SCHUNK GmbH, Lauffen/Neckar Germany
12 // © Copyright 2016 FZI Forschungszentrum Informatik, Karlsruhe, Germany
13 // -- END LICENSE BLOCK ------------------------------------------------
14 
15 //----------------------------------------------------------------------
23 //----------------------------------------------------------------------
24 
25 #include "DS402Node.h"
26 
27 #include "exceptions.h"
28 #include "sync.h"
29 
30 
31 
32 namespace icl_hardware {
33 namespace canopen_schunk {
34 
35 DS402Node::DS402Node(const uint8_t node_id, const CanDevPtr& can_device, HeartBeatMonitor::Ptr heartbeat_monitor):
36  DS301Node(node_id,can_device, heartbeat_monitor),
37  m_interpolation_cycle_time_ms(20),
38  m_max_number_of_state_transitions(10),
39  m_homing_method(0),
40  m_transmission_factor(1)
41 {
42 }
43 
45 {
46  PDO::MappingConfigurationList rpdo_mappings;
47  PDO::MappingConfigurationList tpdo_mappings;
48  switch (mapping)
49  {
51  {
52  // Map control and status word to the first PDO (receive and transmit respectively)
53  rpdo_mappings.push_back(PDO::MappingConfiguration(0x6040, 0, 16, "control_word"));
54  tpdo_mappings.push_back(PDO::MappingConfiguration(0x6041, 0, 16, "status_word"));
57  break;
58  }
60  {
61  // Map control and status word to the first PDO (receive and transmit respectively)
62  rpdo_mappings.push_back(PDO::MappingConfiguration(0x6040, 0, 16, "control_word"));
63  rpdo_mappings.push_back(PDO::MappingConfiguration(0x60C1, 1, 32, "interpolation_buffer"));
64 
65  tpdo_mappings.push_back(PDO::MappingConfiguration(0x6041, 0, 16, "status_word"));
66  tpdo_mappings.push_back(PDO::MappingConfiguration(0x6064, 0, 32, "measured_position"));
67 
68  // Schunk powerballs have already mapped default PDOs. So we use a dummy mapping
71  break;
72  }
74  {
75  // Map control and status word to the first PDO (receive and transmit respectively)
76  rpdo_mappings.push_back(PDO::MappingConfiguration(0x6040, 0, 16, "control_word"));
77  rpdo_mappings.push_back(PDO::MappingConfiguration(0x607A, 0, 32, "target_position"));
78 
79  tpdo_mappings.push_back(PDO::MappingConfiguration(0x6041, 0, 16, "status_word"));
80  tpdo_mappings.push_back(PDO::MappingConfiguration(0x6064, 0, 32, "measured_position"));
81 
82  // Schunk powerballs have already mapped default PDOs. So we use a dummy mapping
85  break;
86  }
87  default:
88  {
89  break;
90  }
91  }
92 
93 }
94 
95 
96 bool DS402Node::setTarget(const float target)
97 {
98  int64_t target_ticks = m_transmission_factor * target;
99  bool success = false;
100  switch (m_op_mode)
101  {
103  {
104  success = setRPDOValue("target_position", static_cast<int32_t>(target_ticks));
105  break;
106  }
108  {
109  success = setRPDOValue("vl_target_velocity", static_cast<int16_t>(target_ticks)); //6042
110  break;
111  }
113  {
114  success = setRPDOValue("target_velocity", static_cast<int32_t>(target_ticks)); //60FF
115  break;
116  }
118  {
119  success = setRPDOValue("target_torque", static_cast<int16_t>(target_ticks)); //6071
120  break;
121  }
123  {
124  LOGGING_ERROR_C (CanOpen, DS402Node, "Homing mode does not know a target value." << endl);
125  success = false;
126  break;
127  }
129  {
130  success = setRPDOValue("interpolation_buffer", static_cast<int32_t>(target_ticks));
131  break;
132  }
134  {
135  LOGGING_WARNING_C (CanOpen, DS402Node, "Target for cyclic sync position mode is not yet supported." << endl);
136  success = false;
137  break;
138  }
140  {
141  LOGGING_WARNING_C (CanOpen, DS402Node, "Target for cyclic sync velocity mode is not yet supported." << endl);
142  success = false;
143  break;
144  }
146  {
147  LOGGING_WARNING_C (CanOpen, DS402Node, "Target for cyclic sync torque mode is not yet supported." << endl);
148  success = false;
149  break;
150  }
151  default:
152  {
153  LOGGING_ERROR_C (CanOpen, DS402Node, "No legal mode of operation is set. setTarget() is non-functional. " << endl);
154  break;
155  }
156  }
157  if (success)
158  {
159  LOGGING_DEBUG_C(CanOpen, DS402Node, "Set target " << target << " for node " << m_node_id << endl);
160 
161  }
162  return success;
163 }
164 
166 {
167  ds402::Controlword word;
168  word.all = getRPDOValue<uint16_t> ("control_word");
170  setRPDOValue ("control_word", word.all);
171  LOGGING_DEBUG_C(CanOpen, DS402Node, "Triggered motion for node " << m_node_id << endl);
172 
173 }
174 
176 {
177  ds402::Controlword word;
178  word.all = getRPDOValue<uint16_t> ("control_word");
180  setRPDOValue ("control_word", word.all);
181  LOGGING_DEBUG_C(CanOpen, DS402Node, "Accepting new targets for node " << m_node_id << endl);
182 
183 }
184 
186 {
187  int32_t feedback;
188  switch (m_op_mode)
189  {
191  {
192  feedback = getTPDOValue<int32_t>("measured_position");
193  break;
194  }
196  {
197  // TODO: implement me
198  LOGGING_ERROR (CanOpen, "GetTargetFeature is not yet implemented for velocity mode." << endl);
199  return 0;
200  }
202  {
203  // TODO: implement me
204  LOGGING_ERROR (CanOpen, "GetTargetFeature is not yet implemented for profile velocity mode." << endl);
205  return 0;
206  }
208  {
209  // TODO: implement me
210  LOGGING_ERROR (CanOpen, "GetTargetFeature is not yet implemented for profile torque mode." << endl);
211  return 0;
212  }
214  {
215  // TODO: implement me
216 // LOGGING_ERROR (CanOpen, "GetTargetFeature is not yet implemented for homing mode." << endl);
217  return 0;
218  }
220  {
221  feedback = getTPDOValue<int32_t>("measured_position");
222  break;
223  }
225  {
226  // TODO: implement me
227  LOGGING_ERROR (CanOpen, "GetTargetFeature is not yet implemented for cyclic sync position mode." << endl);
228  return 0;
229  }
231  {
232  // TODO: implement me
233  LOGGING_ERROR (CanOpen, "GetTargetFeature is not yet implemented for cyclic sync velocity mode." << endl);
234  return 0;
235  }
237  {
238  // TODO: implement me
239  LOGGING_ERROR (CanOpen, "GetTargetFeature is not yet implemented for cyclic sync torque mode." << endl);
240  return 0;
241  }
242  default:
243  {
244  LOGGING_ERROR_C (CanOpen, DS402Node, "No legal mode of operation is set. getTargetFeedback() is non-functional. " << endl);
245  return 0;
246  }
247  }
248 
249  #ifdef _IC_BUILDER_ICL_COMM_WEBSOCKET_
250  if (m_ws_broadcaster)
251  {
252  m_ws_broadcaster->robot->setJointPosition(feedback, m_node_id);
253  }
254  #endif // _IC_BUILDER_ICL_COMM_WEBSOCKET_
255 
256 
257  return static_cast<double>(feedback) / m_transmission_factor;
258 }
259 
260 
262 {
263  // TODO: implement me!
264 }
265 
267 {
269  {
270  LOGGING_INFO (CanOpen, "Quick stop of node " << m_node_id << " requested!" << endl);
271  std::string identifier = "control_word";
272  ds402::Controlword word;
273  try
274  {
275  word.all = getRPDOValue<uint16_t> (identifier);
276  word.bit.enable_voltage = 1;
277  word.bit.quick_stop = 0;
278  word.bit.reset_fault = 0;
279  word.bit.halt = 1;
280  setRPDOValue (identifier, word.all);
281  }
282  catch (const PDOException& e)
283  {
284  LOGGING_WARNING_C (CanOpen, DS402Node, "Could not find a PDO for the control word. Using slower SDO calls." << endl);
285  word.bit.enable_voltage = 1;
286  word.bit.quick_stop = 0;
287  word.bit.reset_fault = 0;
288  word.bit.halt = 1;
289 
290  m_sdo.download(false, ds402::ID_CONTROL_WORD, 0x00, word.all);
291  }
292  }
294 }
295 
297 {
298  quickStop();
299 }
300 
301 
302 void DS402Node::initDS402State (const ds402::eState& requested_state)
303 {
304  LOGGING_DEBUG (CanOpen, "State " << deviceStatusString(requested_state) << " requested for node "
305  << static_cast<int>(m_node_id) << "" << endl);
306  if (requested_state == ds402::STATE_START ||
307  requested_state == ds402::STATE_NOT_READY_TO_SWITCH_ON ||
308  requested_state == ds402::STATE_FAULT_REACTION_ACTIVE)
309  {
310  LOGGING_ERROR_C (CanOpen, DS402Node, "Illegal target state requested. Requested state was: " <<
311  ds402::deviceStatusString(requested_state) << ", however that state cannot be entered manually!" << endl);
312  return;
313  }
314 
315  // get current state
316  ds402::Statusword status_word;
317  status_word.all = getTPDOValue<uint16_t>("status_word");
318  ds402::eState current_state = ds402::stateFromStatusword(status_word);
319 
320 
321  if (current_state == ds402::STATE_FAULT)
322  {
323  bool reset_fault_successful = false;
324  for (size_t i = 0; i < 5; ++i)
325  {
326  reset_fault_successful = resetFault();
327  if (reset_fault_successful)
328  {
329  break;
330  }
331  }
332 
333  if (!reset_fault_successful)
334  {
335  LOGGING_INFO (CanOpen, "Unable to reset from fault state after 5 tries. " <<
336  "Trying to do a hard reset on the device." << endl);
337  m_nmt.stop();
338  usleep(100000);
339  m_nmt.start();
340 
341  if (!resetFault())
342  {
343  std::stringstream ss;
344  ss << "Could not perform fault reset for node "
345  << static_cast<int>(m_node_id)
346  << " after multiple tries. "
347  << "Is the device hard-disabled?"
348  << "\nOtherwise: Have you tried turning it off and on again?";
349  throw (DeviceException(ss.str()));
350  }
351  }
352 
353  m_sdo.upload(false, 0x6041, 0x0, status_word.all );
354  current_state = ds402::stateFromStatusword(status_word);
355  }
356 
357  // To prevent a deadlock if something goes wrong with state changes, the number of changes is limited
358  size_t num_transitions = 0;
359 
360  while (current_state != requested_state && num_transitions < m_max_number_of_state_transitions)
361  {
362  LOGGING_DEBUG (CanOpen, "Node " << static_cast<int>(m_node_id) << " currently in state " <<
363  deviceStatusString(current_state) << endl);
364  switch (current_state)
365  {
367  {
368  if (requested_state > ds402::STATE_SWITCH_ON_DISABLED)
369  {
372  }
373  break;
374  }
376  {
377  if (requested_state > ds402::STATE_READY_TO_SWITCH_ON)
378  {
381  }
382  else
383  {
386  }
387  break;
388  }
390  {
391  if (requested_state > ds402::STATE_SWITCHED_ON)
392  {
395  }
396  else if (requested_state == ds402::STATE_SWITCH_ON_DISABLED)
397  {
400  }
401  else
402  {
405  }
406  break;
407  }
409  {
410  if (requested_state > ds402::STATE_OPERATION_ENABLE)
411  {
414  }
415  else if (requested_state == ds402::STATE_SWITCHED_ON)
416  {
419  }
420  else if (requested_state == ds402::STATE_READY_TO_SWITCH_ON)
421  {
424  }
425  else if (requested_state == ds402::STATE_SWITCH_ON_DISABLED)
426  {
429  }
430  break;
431  }
433  {
434  // Query quick_stop option code. If it is 5,6,7 or 8, then we can perform this transition
435  // However, this is optional, so we have to check if it's possible.
436  int16_t quick_stop_option_code = 0;
437  try
438  {
439  m_sdo.download(false, 0x605a, 0, quick_stop_option_code);
440  }
441  catch (const ProtocolException& e)
442  {
443  LOGGING_WARNING (CanOpen, "Caught error while downloading quick-stop-option code. "
444  << "Probably it is not implemented, as it is optional. "
445  << "Will carry on assuming quick-stop-option-code = 0.\n"
446  << "Error was: " << e.what() << endl
447  );
448  }
449  if (quick_stop_option_code >=5 && quick_stop_option_code <=8 &&
450  requested_state == ds402::STATE_OPERATION_ENABLE)
451  {
454  }
455  else
456  {
459  }
460  break;
461  }
462  case ds402::STATE_FAULT:
463  {
464  LOGGING_ERROR_C (CanOpen, DS402Node, "Landed in FAULT state while performing transition to " <<
465  "state " << ds402::deviceStatusString(requested_state) <<
466  ". Starting all over again..." << endl);
467  break;
468  }
469  case ds402::STATE_START:
472  {
473  // nothing to do here.
474  break;
475  }
476  default:
477  {
478  // This should not happen
479  LOGGING_ERROR_C (CanOpen, DS402Node, "Landed in unknown state while performing transition to " <<
480  "state " << ds402::deviceStatusString(requested_state) <<
481  ". Aborting state transition." << endl);
482  break;
483  }
484  }
485 
486  // now update the current state via SDO
487  m_sdo.upload(false, 0x6041, 0x0, status_word.all );
488  current_state = ds402::stateFromStatusword(status_word);
489 
490  LOGGING_INFO (CanOpen, "Node " << static_cast<int>(m_node_id) << " reached state " <<
491  deviceStatusString(current_state) << endl);
492  m_current_ds402_state = current_state;
493  setTPDOValue("status_word", status_word.all);
494 
495  num_transitions++;
496  }
498 
499 }
500 
501 
503 {
504  if (m_homing_method == 0)
505  {
506  LOGGING_WARNING (CanOpen, "Homing method for node " << static_cast<int>(m_node_id) <<
507  " is not set. Aborting homing now." << endl);
508  return;
509  }
510 
511  LOGGING_INFO (CanOpen, "Starting homing for node " << static_cast<int>(m_node_id) << endl);
512 
514 
516 
517  ds402::Controlword controlword;
518  controlword.all = getRPDOValue<uint16_t>("control_word");
519 
520  // home operation start
521  controlword.bit.operation_mode_specific_0 = 1;
522  controlword.bit.halt = 0;
523 
524  // activate the homing mode
525  m_sdo.download(false, ds402::ID_CONTROL_WORD, 0x0, controlword.all);
526 
527  ds402::Statusword statusword;
528  bool homing_attained = false;
529  bool homing_error = false;
530  while (!homing_attained)
531  {
532  m_sdo.upload(false, ds402::ID_STATUS_WORD, 0, statusword.all);
533  homing_attained = statusword.bit.operation_mode_specific_0;
534  homing_error = statusword.bit.operation_mode_specific_1;
535 
536  if (homing_error)
537  {
538  std::stringstream ss;
539  ss << "Homing of node " << static_cast<int>(m_node_id) << " failed.";
540  throw DeviceException(ss.str());
541  }
542 
543  if (homing_attained)
544  {
545  // We're done homing
546  LOGGING_INFO (CanOpen, "Done homing for node " << static_cast<int>(m_node_id) << endl);
547  break;
548  }
549 
550  usleep(100000); // wait 100 ms
551  }
552 }
553 
555 {
556  ds402::Statusword statusword;
557  statusword.all = getTPDOValue<uint16_t> ("status_word");
558  ds402::eState state = stateFromStatusword(statusword);
559  std::stringstream ss;
560  ss << "Device " << static_cast<int>(m_node_id) << " status: " <<
561  binaryString(statusword.all) << "\n(state " << ds402::deviceStatusString(state)
562  << ")" << std::endl;
563  ss << "Fault: " << statusword.bit.fault << std::endl;
564  ss << "Switched on: " << statusword.bit.switched_on << std::endl;
565  ss << "Operation enabled: " << statusword.bit.operation_enabled << std::endl;
566  ss << "Voltage enabled: " << statusword.bit.voltage_enabled << std::endl;
567  ss << "Quick stop active: " << statusword.bit.quick_stop << std::endl;
568  ss << "Target reached: " << statusword.bit.target_reached << std::endl;
569 
570  // add Bits 12 and 13 which are op_mode specific
571  ss << operationModeSpecificStatus(statusword);
572 
573  LOGGING_INFO_C (CanOpen, DS402Node, ss.str() << endl);
574 }
575 
577 {
578  std::stringstream ss;
579  switch (m_op_mode)
580  {
582  {
583  ss << "Set-point acknowledge: " << statusword.bit.operation_mode_specific_0 << std::endl;
584  ss << "Following error: " << statusword.bit.operation_mode_specific_1 << std::endl;
585  break;
586  }
588  {
589  break;
590  }
592  {
593  ss << "Speed: " << statusword.bit.operation_mode_specific_0 << std::endl;
594  ss << "Max slippage error: " << statusword.bit.operation_mode_specific_1 << std::endl;
595  break;
596  }
598  {
599  break;
600  }
602  {
603  ss << "Homing attained: " << statusword.bit.operation_mode_specific_0 << std::endl;
604  ss << "Homing error: " << statusword.bit.operation_mode_specific_1 << std::endl;
605  break;
606  }
608  {
609  ss << "Interpolated position mode active: " << statusword.bit.operation_mode_specific_0 << std::endl;
610  break;
611  }
613  {
614  break;
615  }
617  {
618  break;
619  }
621  {
622  break;
623  }
624  default:
625  {
626  // do nothing
627  break;
628  }
629  }
630 
631  return ss.str();
632 }
633 
635 {
636  m_sdo.upload(false, 0x6502, 0, m_supported_modes.all);
637 }
638 
640 {
644 
645  boost::function <void()> f = boost::bind(&DS402Node::onStatusWordUpdate, this);
646  registerPDONotifyCallback("status_word", f);
647 
649 }
650 
652 {
653  int8_t mode_int = op_mode;
654  uint32_t bitmask_mode = 0x01 << (mode_int-1);
655 
656  if ((m_supported_modes.all & bitmask_mode) != bitmask_mode)
657  {
658  return false;
659  }
660 
661  return true;
662 }
663 
665 {
666  std::stringstream ss;
667  ss << "Modes of operation supported by device " << static_cast<int>(m_node_id) << std::endl;
669  {
670  ss << "Profile position mode" << std::endl;
671  }
673  {
674  ss << "Velocity mode" << std::endl;
675  }
677  {
678  ss << "Profile velocity mode" << std::endl;
679  }
681  {
682  ss << "Profile torque mode" << std::endl;
683  }
685  {
686  ss << "Homing mode" << std::endl;
687  }
689  {
690  ss << "Interpolated position mode" << std::endl;
691  }
693  {
694  ss << "Cyclic sync position mode" << std::endl;
695  }
697  {
698  ss << "Cyclic sync velocity mode" << std::endl;
699  }
701  {
702  ss << "Cyclic sync torque mode" << std::endl;
703  }
704 
705  LOGGING_INFO (CanOpen, ss.str() << endl);
706 }
707 
708 
710 {
711  // Changes of opMode are always possible. So make sure, the motor is standing while changing the opMode.
713  {
714  closeBrakes();
715  }
716 
717  if (op_mode != ds402::MOO_HOMING_MODE &&
720  )
721  {
722  LOGGING_ERROR_C (CanOpen, DS402Node, "Requested to switch to mode " <<
723  operationModeString(op_mode) << " for node " <<
724  static_cast<int>(m_node_id) << ", which is currently not supported." << endl);
725  return false;
726  }
727 
728  if (!isModeSupported(op_mode))
729  {
730  LOGGING_ERROR_C (CanOpen, DS402Node, "The requested mode: " <<
731  operationModeString(op_mode) <<
732  " is not supported by the device " <<
733  static_cast<int>(m_node_id) << "." << endl);
734  return false;
735  }
736 
738  {
740  configureInterpolationData (0, 0, 4);
741  }
742 
743  bool success = true;
744 
745  int8_t mode_int = op_mode;
746  try
747  {
748  success = m_sdo.download(false, 0x6060, 0, mode_int);
749  }
750  catch (const std::exception& e)
751  {
752  LOGGING_ERROR_C (CanOpen, DS402Node, e.what() << endl);
753  }
754  if (success)
755  {
756  m_op_mode = op_mode;
757  LOGGING_INFO (CanOpen, "Initialized mode " << ds402::operationModeString(op_mode) <<
758  " for node " << m_node_id << endl);
759  }
760 
761  return success;
762 }
763 
764 void DS402Node::configureInterpolationCycleTime (const uint8_t interpolation_cycle_time_ms)
765 {
766  if (interpolation_cycle_time_ms != 0)
767  {
768  m_interpolation_cycle_time_ms = interpolation_cycle_time_ms;
769  }
770  m_sdo.download(false, 0x60c2, 0x01, m_interpolation_cycle_time_ms);
771  int8_t magnitude = -3; // milliseconds
772  m_sdo.download(false, 0x60c2, 0x02, magnitude);
773 }
774 
776 {
778 
779 
780  // If only an acceleration parameter is given, it will be used for deceleration, as well.
781  float deceleration = config.profile_deceleration;
782  if (config.profile_deceleration == 0)
783  {
784  deceleration = config.profile_acceleration;
785  }
786 
787 
788  // Some devices don't support setting deceleration parameter. This catches that.
789  try
790  {
792  }
793  catch (const ProtocolException& e)
794  {
795  LOGGING_DEBUG (CanOpen, "Failed to set the profile deceleration for node " << m_node_id << ". " <<
796  " Some devices do not support setting this, but use the acceleration value for deceleration, as well. So you might want to ignore this message. " <<
797  "The error was: " << e.what() << endl
798  );
799  }
800 
801  // Some devices don't support setting it and 0 is the default
802  if (config.motion_profile_type != 0)
803  {
805  }
807 
808  m_ppm_config = config;
809 }
810 
812 {
815 }
816 
818 {
820 }
821 
823 {
826 }
827 
829 {
830  ds402::Statusword status_word;
831  status_word.all = getTPDOValue<uint16_t>("status_word");
832  ds402::eState current_state = ds402::stateFromStatusword(status_word);
833 
834  if (current_state != ds402::STATE_FAULT)
835  {
836  LOGGING_INFO_C (CanOpen, DS402Node, "Requested resetFault action, but device is currently " <<
837  "not in state FAULT. Instead it is in state " << deviceStatusString (current_state) <<
838  ". Not doing anything here." << endl);
839  return true;
840  }
841 
842  // clear the error register
843  m_emcy->clearErrorHistory(m_sdo);
844 
845  // enter SWITCH_ON_DISABLED state
847 
848  usleep (100000); // wait 100ms
849  status_word.all = getTPDOValue<uint16_t>("status_word");
850  current_state = ds402::stateFromStatusword(status_word);
851 
852  if (current_state != ds402::STATE_SWITCH_ON_DISABLED)
853  {
854  LOGGING_ERROR_C (CanOpen, DS402Node, "Could not perform fault reset for node " <<
855  m_node_id << ". Possibly the reason for entering the fault state still exists." <<
856  endl
857  );
858  return false;
859  }
860  return true;
861 }
862 
863 
865 {
866  m_sdo.download(false, 0x60c5, 0, acceleration);
867 
868  LOGGING_INFO_C (CanOpen, DS402Node, "Maximum acceleration for node " << m_node_id << " written." << endl);
869 }
870 
872 {
873  m_sdo.download(false, 0x60c6, 0, deceleration);
874  LOGGING_INFO_C (CanOpen, DS402Node, "Maximum deceleration for node " << m_node_id << " written." << endl);
875 }
876 
878 {
879  m_sdo.download(false, 0x6081, 0, velocity);
880  LOGGING_INFO_C (CanOpen, DS402Node, "Profile velocity for node " << m_node_id << " written with value " <<
881  velocity << "." << endl);
882 }
883 
884 
886 {
887  m_sdo.download(false, 0x6083, 0, acceleration);
888  LOGGING_INFO_C (CanOpen, DS402Node, "Profile acceleration for node " << m_node_id << " written with value " <<
889  acceleration << "." << endl);
890 }
891 
893 {
894  m_sdo.download(false, 0x6084, 0, deceleration);
895 }
896 
898 {
899  m_sdo.download(false, 0x6085, 0, deceleration);
900  LOGGING_INFO_C (CanOpen, DS402Node, "Quick Stop deceleration for node " << m_node_id << " written with value " <<
901  deceleration << "." << endl);
902 }
903 
905 {
906  m_sdo.download(false, 0x6086, 0, motion_type);
907  LOGGING_INFO_C (CanOpen, DS402Node, "Motion profile type for node " << m_node_id << " written with value " <<
908  motion_type << "." << endl);
909 }
910 
911 
912 void DS402Node::configureHomingSpeeds (const uint32_t low_speed, const uint32_t high_speed)
913 {
914  m_sdo.download(false, 0x6099, 1, high_speed);
915  m_sdo.download(false, 0x6099, 2, low_speed);
916 
917  LOGGING_INFO_C (CanOpen, DS402Node, "Homing speeds for node " << m_node_id << " written." << endl);
918 
919 }
920 
922 {
923  m_sdo.download(false, 0x609A, 0, acceleration);
924  LOGGING_INFO_C (CanOpen, DS402Node, "Homing acceleration for node " << m_node_id << " written." << endl);
925 }
926 
927 void DS402Node::configureHomingMethod (const int8_t homing_method)
928 {
929  m_sdo.download(false, 0x6098, 0, homing_method);
930  LOGGING_INFO_C (CanOpen, DS402Node, "Homing method for node " << m_node_id << " written." << endl);
931  m_homing_method = homing_method;
932 }
933 
934 void DS402Node::configureSensorSelectionCode (const int16_t sensor_selection_code)
935 {
936  m_sdo.download(false, 0x606a, 0, sensor_selection_code);
937  LOGGING_INFO_C (CanOpen, DS402Node, "Sensor selection code for node " << m_node_id << " written." << endl);
938 }
939 
940 void DS402Node::configureTorqueProfileType (const int16_t torque_profile_type)
941 {
942  m_sdo.download(false, 0x6088, 0, torque_profile_type);
943  LOGGING_INFO_C (CanOpen, DS402Node, "Torque profile type for node " << m_node_id << " written." << endl);
944 }
945 
946 void DS402Node::configureTorqueSlope (const uint32_t torque_slope)
947 {
948  m_sdo.download(false, 0x6087, 0, torque_slope);
949  LOGGING_INFO_C (CanOpen, DS402Node, "Torque slope for node " << m_node_id << " written." << endl);
950 }
951 
952 void DS402Node::configureInterpolationData (const uint8_t buffer_organization,
953  const int16_t interpolation_type,
954  const uint8_t size_of_data_record)
955 {
956  uint8_t data8 = 0;
957  // Reset the buffer
958  m_sdo.download(false, 0x60c4, 6, data8);
959 
960  // Enable the buffer again
961  data8 = 1;
962  m_sdo.download(false, 0x60c4, 6, data8);
963 
964  // set linear interpolation
965  int16_t data16 = 0;
966  m_sdo.download(false, 0x60c0, 0, data16);
967 
968  m_sdo.download(false, 0x60c4, 3, buffer_organization);
969  m_sdo.download(false, 0x60c4, 5, size_of_data_record);
970 
971  LOGGING_DEBUG_C (CanOpen, DS402Node, "Interpolation data for node " << m_node_id << " written." << endl);
972 }
973 
975 {
976  LOGGING_DEBUG_C (CanOpen, DS402Node, "Requested DS402 state transition " << transition << endl);
977  // create according control word and send it via SDO, update it in the PDO cache
978  std::string identifier = "control_word";
979  ds402::Controlword word;
980  word.all = getRPDOValue<uint16_t> (identifier);
981 
982  switch (transition)
983  {
984  case ds402::STATE_TRANS_INITIALIZE: // 1, 7, 9, 10, 12
985  {
986  word.bit.reset_fault = 0;
987  word.bit.enable_voltage = 0;
989  break;
990  }
991  case ds402::STATE_TRANS_SHUTDOWN: // 2, 6, 8
992  {
993  word.bit.reset_fault = 0;
994  word.bit.quick_stop = 1;
995  word.bit.enable_voltage = 1;
996  word.bit.switch_on = 0;
998  break;
999  }
1000  case ds402::STATE_TRANS_SWITCH_ON: // 3, 5
1001  {
1002  word.bit.reset_fault = 0;
1003  word.bit.enable_operation = 0;
1004  word.bit.quick_stop = 1;
1005  word.bit.enable_voltage = 1;
1006  word.bit.switch_on = 1;
1007  word.bit.halt = 1;
1008  break;
1009  }
1011  {
1012  word.bit.reset_fault = 0;
1013  word.bit.enable_operation = 1;
1014  word.bit.quick_stop = 1;
1015  word.bit.enable_voltage = 1;
1016  word.bit.switch_on = 1;
1017  word.bit.halt = 0;
1018  break;
1019  }
1020  case ds402::STATE_TRANS_QUICK_STOP: // 11
1021  {
1022  word.bit.reset_fault = 0;
1023  word.bit.quick_stop = 0;
1024  word.bit.enable_voltage = 1;
1025  word.bit.halt = 1;
1026  break;
1027  }
1028  case ds402::STATE_TRANS_FAULT_RESET: // 15
1029  {
1030  word.bit.reset_fault = 1;
1031  break;
1032  }
1033  default:
1034  {
1035  std::stringstream ss;
1036  ss << "Illegal DS402 state transition requested: " << transition;
1037  throw ProtocolException (ds402::ID_CONTROL_WORD, 0x00, ss.str());
1038  }
1039  }
1040 
1041  // now send the controlword to the device
1042  m_sdo.download(false, ds402::ID_CONTROL_WORD, 0x0, word.all);
1043  LOGGING_DEBUG (CanOpen, "Sent controlword " << binaryString(word.all) << endl);
1044 
1045  // copy it to the pdo cache
1046  setRPDOValue(identifier, word.all);
1047 }
1048 
1050 {
1051  m_nmt.start();
1053  {
1054  resetFault();
1055  }
1056 
1057  if (operation_mode != ds402::MOO_RESERVED_0)
1058  {
1059  setModeOfOperation(operation_mode);
1060  }
1062  // Set current position to target position to prevent jumps
1063  double feedback = getTargetFeedback();
1064  setTarget(feedback);
1065 
1066  openBrakes();
1067 }
1068 
1070 {
1072  {
1073  closeBrakes();
1074  }
1075 
1077 }
1078 
1080 {
1082  {
1083  ds402::Controlword controlword;
1084  controlword.all = getRPDOValue<uint16_t>("control_word");
1085 
1086 
1087  // If the requested mode is InterpolatedPositionMode, we enable interpolation here
1089  {
1090  controlword.bit.operation_mode_specific_0 = 1;
1091  controlword.bit.halt = 0;
1092  }
1094  {
1095  controlword.bit.operation_mode_specific_0 = 0; // Bit 4
1096 
1097  controlword.bit.operation_mode_specific_1 = !(m_ppm_config.change_set_immediately); // Bit 5: move to set point immediately
1099  controlword.bit.reserved_0 = m_ppm_config.use_blending; // Bit 9: use blending
1100  controlword.bit.halt = 0;
1101  }
1102  else
1103  {
1104  controlword.bit.operation_mode_specific_0 = 0;
1105  controlword.bit.halt = 0;
1106  }
1107  setRPDOValue("control_word", controlword.all);
1108  }
1109  else
1110  {
1111  LOGGING_ERROR (CanOpen, "OpenBrakes called while not in OPERATION_ENABLE state. Will do nothing" << endl);
1112  }
1113 }
1114 
1115 
1117 {
1119  {
1120  ds402::Controlword controlword;
1121  m_sdo.upload(false, 0x6040, 0, controlword.all);
1122  // If the requested mode is InterpolatedPositionMode, we disable interpolation here
1124  {
1125  controlword.bit.operation_mode_specific_0 = 0;
1126  }
1127  controlword.bit.halt = 1;
1128  setRPDOValue("control_word", controlword.all);
1129  }
1130  else
1131  {
1132  LOGGING_ERROR (CanOpen, "CloseBrakes called while not in OPERATION_ENABLE state. Will do nothing" << endl);
1133  }
1134 }
1135 
1137 {
1138  ds402::Statusword statusword;
1139  statusword.all = getTPDOValue<uint16_t>("status_word");
1140 
1141  // check if DS402 status matches the one from the device
1142 
1143  ds402::eState device_state = ds402::stateFromStatusword(statusword);
1144  if (m_current_ds402_state != device_state)
1145  {
1146  if (m_expected_ds402_state != device_state)
1147  {
1148  LOGGING_WARNING (CanOpen, "The device " << m_node_id <<
1149  " has switched to state " <<
1150  ds402::deviceStatusString(device_state) <<
1151  " without host request. " <<
1152  "The controller will adapt the device's status." << endl
1153  );
1154  }
1155  m_current_ds402_state = device_state;
1156  }
1157 }
1158 
1160 {
1161  ds402::Statusword statusword;
1162  statusword.all = getTPDOValue<uint16_t>("status_word");
1163 
1164  return statusword.bit.target_reached;
1165 }
1166 
1168 {
1169  ds402::Statusword word;
1170  word.all = getTPDOValue<uint16_t>("status_word");
1171  return word;
1172 }
1173 
1174 
1175 
1176 }}//end of NS
virtual void configureInterpolationData(const uint8_t buffer_organization=0, const int16_t interpolation_type=0, const uint8_t size_of_data_record=4)
Configure the buffer for the interpolated position mode.
Definition: DS402Node.cpp:952
signed int int32_t
unsigned int uint32_t
virtual void configureInterpolationCycleTime(const uint8_t interpolation_cycle_time_ms=8)
Set the interpolation cycle time in milliseconds. If no time is given the default will be used...
Definition: DS402Node.cpp:764
#define LOGGING_INFO_C(streamname, classname, arg)
void configureMotionProfileType(const int16_t motion_type)
Set the device&#39;s motion profile type through an SDO (OD 0x6086)
Definition: DS402Node.cpp:904
Configuration parameters for a Profile_Position_Mode according to CiA DSP-402 V1.1 section 12...
Definition: ds402.h:169
std::string operationModeSpecificStatus(const ds402::Statusword &statusword)
This function queries the two operation mode specific bits and turns them to a human-readable string...
Definition: DS402Node.cpp:576
virtual bool isTargetReached()
Returns whether the device has reached it&#39;s recent target.
Definition: DS402Node.cpp:1159
std::vector< MappingConfiguration > MappingConfigurationList
The MappingConfigurationList holds multiple Mapping configurations. The Mapping of a single PDO is de...
Definition: PDO.h:70
virtual void setupProfileTorqueMode(const ds402::ProfileTorqueModeConfiguration &config)
Configure the mandatory parameters for a profile torque mode.
Definition: DS402Node.cpp:822
virtual void initPDOMappingSingle(const PDO::MappingConfigurationList &config, const uint16_t pdo_nr, const PDO::eTransmissionType &transmission_type, const ePDO_TYPE &pdo_type, const bool dummy_mapping=false, const uint8_t cyclic_timeout_cycles=0)
Init PDO mapping with a given mapping configuration for a given pdo nr.
Definition: DS301Node.cpp:66
virtual void enableNode(const ds402::eModeOfOperation operation_mode=ds402::MOO_RESERVED_0)
Switches on the device and enters Operation Enabled mode with the given mode. If the requested mode i...
Definition: DS402Node.cpp:1049
f
void doDS402StateTransition(const ds402::eStateTransission transition)
Performs a state transition in the DS402 state machine.
Definition: DS402Node.cpp:974
virtual void closeBrakes()
When the device is in OperationEnabled mode, this function disable the drive motion.
Definition: DS402Node.cpp:1116
virtual void initNode()
Initializes the node. Tries to query all required data from the device.
Definition: DS402Node.cpp:639
#define LOGGING_INFO(streamname, arg)
Basic CanOpen exception that contains the Object dictionary index and subindex.
Definition: exceptions.h:37
void configureTorqueSlope(const uint32_t torque_slope)
Set the device&#39;s torque slope through an SDO (OD 0x6087)
Definition: DS402Node.cpp:946
SDO m_sdo
SDO object for specific calls.
Definition: DS301Node.h:305
void configureProfileAcceleration(const uint32_t acceleration)
Set the device&#39;s profile acceleration through an SDO (OD 0x6083)
Definition: DS402Node.cpp:885
virtual bool resetFault()
This function is used to recover from a fault state.
Definition: DS402Node.cpp:828
signed char int8_t
data union for access to DSP 402 6041 statusword,
Definition: ds402.h:136
boost::shared_ptr< icl_comm::websocket::WsBroadcaster > m_ws_broadcaster
Interface to send out diagnostics data. Only available if compiled with IC_BUILDER_ICL_COMM_WEBSOCKET...
Definition: DS301Node.h:331
#define LOGGING_DEBUG(streamname, arg)
eNMT_SubState
The NMT Substate is only used during initialization of a device. Meaning the substates are only usefu...
Definition: NMT.h:69
bool download(const bool normal_transfer, const uint16_t index, const uint8_t subindex, const std::vector< uint8_t > &usrdata)
Downloads SDO data from the master to the slave (From PC to node).
Definition: SDO.cpp:84
uint8_t m_interpolation_cycle_time_ms
Cycle time of interpolation mode.
Definition: DS402Node.h:396
Configuration parameters for a Profile_Velocity_Mode according to CiA DSP-402 V1.1 section 16...
Definition: ds402.h:246
eState stateFromStatusword(const ds402::Statusword &statusword)
Definition: ds402.h:375
std::string deviceStatusString(const eState state)
Turns a status word into a status string according to the elmo DS-402 implementation guide chapter 6...
Definition: ds402.h:276
void configureHomingAcceleration(const uint32_t acceleration)
Set the device&#39;s homing acceleration through an SDO (OD 0x609A)
Definition: DS402Node.cpp:921
bool use_blending
If set to true, the device will blend over to a new setpoint. Defaults to true.
Definition: ds402.h:213
virtual void querySupportedDeviceModes()
Uploads all supported modes of operation from the device. and stores them in the m_supported_modes me...
Definition: DS402Node.cpp:634
virtual void initDS402State(const icl_hardware::canopen_schunk::ds402::eState &requested_state)
Initializes a state of the DS402 state machine. Performs all necessary state transitions until the ta...
Definition: DS402Node.cpp:302
PDO related exceptions go here.
Definition: exceptions.h:114
int16_t motion_profile_type
Type of ramp used for accelerating and decelerating. Defaults to linear.
Definition: ds402.h:193
void printSupportedModesOfOperation()
Prints out all Modes on which the device claims to be able to operate on.
Definition: DS402Node.cpp:664
virtual void initNode()
Initializes the node.
Definition: DS301Node.cpp:47
signed __int64 int64_t
void configureProfileVelocity(const uint32_t velocity)
Set the device&#39;s profile velocity through an SDO (OD 0x6081)
Definition: DS402Node.cpp:877
#define LOGGING_WARNING_C(streamname, classname, arg)
ds402::ProfilePositionModeConfiguration m_ppm_config
Definition: DS402Node.h:391
#define LOGGING_ERROR(streamname, arg)
virtual void startPPMovement()
This sets the RPDO communication for enabling the movement after a target has been set...
Definition: DS402Node.cpp:165
static const uint16_t ID_CONTROL_WORD
Definition: ds402.h:38
uint8_t m_node_id
CANOPEN ID of the node.
Definition: DS301Node.h:315
void configureSensorSelectionCode(const int16_t sensor_selection_code)
Set the device&#39;s sensor selection code through an SDO (OD 0x606a)
Definition: DS402Node.cpp:934
void stop()
stop Stops the device by setting the NMT state to stopped
Definition: NMT.cpp:96
virtual void configureHomingSpeeds(const uint32_t low_speed, const uint32_t high_speed=0)
Set the speeds for homing through SDO 6099. Typically, a high speed is used when searching for a home...
Definition: DS402Node.cpp:912
virtual void home()
Perform homing for this node.
Definition: DS402Node.cpp:502
unsigned char uint8_t
bool use_relative_targets
This parameter influences the interpretation of new set points. If set to true, new set point positio...
Definition: ds402.h:207
virtual void openBrakes()
When the device is in OperationEnabled mode, this function enables the drive motion.
Definition: DS402Node.cpp:1079
#define LOGGING_DEBUG_C(streamname, classname, arg)
float profile_acceleration
This will be used for both acceleration ramps.
Definition: ds402.h:179
void configureMaxDeceleration(const uint32_t deceleration)
Set the device&#39;s maximum deceleration through an SDO (OD 0x60c6)
Definition: DS402Node.cpp:871
ThreadStream & endl(ThreadStream &stream)
virtual bool isModeSupported(const ds402::eModeOfOperation op_mode)
Tests whether a given mode of operation is supported by the device.
Definition: DS402Node.cpp:651
DS402Node(const uint8_t node_id, const icl_hardware::canopen_schunk::CanDevPtr &can_device, HeartBeatMonitor::Ptr heartbeat_monitor)
Definition: DS402Node.cpp:35
ds402::SupportedDriveModes m_supported_modes
supported modes of operation
Definition: DS402Node.h:383
static const uint16_t ID_STATUS_WORD
Definition: ds402.h:39
virtual void disableNode()
Puts the device into STATE_SWITCHED_ON mode. If the device was in InterpolatedPositionMode, interpolation will be stopped here, as well.
Definition: DS402Node.cpp:1069
void configureQuickStopDeceleration(const uint32_t deceleration)
Set the device&#39;s quick stop deceleration through an SDO (OD 0x6085)
Definition: DS402Node.cpp:897
bool setRPDOValue(const std::string &identifier, const T value)
Set the value of a PDO which is mapped to a given identifier.
Definition: DS301Node.h:215
virtual void setDefaultPDOMapping(const eDefaultPDOMapping mapping)
Choose one of the predefined default mappings. Please see the enum eDefaultPDOMapping for a list of a...
Definition: DS402Node.cpp:44
std::string operationModeString(const eModeOfOperation mode)
Definition: ds402.h:328
If something goes wrong with the host&#39;s CAN controller, this exception will be used.
Definition: exceptions.h:135
virtual void onStatusWordUpdate()
This will be called when a new statusword PDO comes in. If the device&#39;s state differs from the one ex...
Definition: DS402Node.cpp:1136
virtual void printStatus()
Prints a stringified version of the statusword to the logging system.
Definition: DS402Node.cpp:554
virtual void configureHomingMethod(const int8_t homing_method)
Set the device&#39;s homing method through an SDO (OD 0x6098)
Definition: DS402Node.cpp:927
#define LOGGING_WARNING(streamname, arg)
bool upload(const bool normal_transfer, const uint16_t index, const uint8_t subindex, std::vector< uint8_t > &uploaded_data)
Uploads data from a slave (node) to a master (PC).
Definition: SDO.cpp:209
bool setTPDOValue(const std::string &identifier, const T value)
Set the value of a PDO which is mapped to a given identifier.
Definition: DS301Node.h:246
virtual void stopNode()
This redefines the basic stopNode function.
Definition: DS402Node.cpp:296
Configuration parameters for a Profile_Torque_Mode according to CiA DSP-402 V1.1 section 17...
Definition: ds402.h:261
void configureTorqueProfileType(const int16_t torque_profile_type)
Set the device&#39;s torque profile type through an SDO (OD 0x6088)
Definition: DS402Node.cpp:940
virtual void acceptPPTargets()
After enabling PP movement, this enables accepting new targets again. Remember to sync all nodes and ...
Definition: DS402Node.cpp:175
signed short int16_t
std::string binaryString(const uint64_t num)
Definition: helper.cpp:53
EMCY::Ptr m_emcy
EMCY object to handle spontaneous callbacks with emergency messages.
Definition: DS301Node.h:311
virtual void setupHomingMode(const ds402::HomingModeConfiguration &config)
Configure the mandatory parameters for a homing mode.
Definition: DS402Node.cpp:811
void configureProfileDeceleration(const uint32_t deceleration)
Set the device&#39;s profile deceleration through an SDO (OD 0x6084)
Definition: DS402Node.cpp:892
eState
DS402 states as described in Figure 6.3 in ELMO DS402 implementation guide V1.000.
Definition: ds402.h:61
virtual void setupProfileVelocityMode(const ds402::ProfileVelocityModeConfiguration &config)
Configure the mandatory parameters for a profile velocity mode.
Definition: DS402Node.cpp:817
virtual const char * what() const _GLIBCXX_USE_NOEXCEPT
Definition: exceptions.h:50
void start()
start Starts the device by setting the NMT state to operational
Definition: NMT.cpp:91
virtual bool setModeOfOperation(const ds402::eModeOfOperation op_mode)
Sets and initializes a mode of operation. First it will check whether the device supports the request...
Definition: DS402Node.cpp:709
virtual void quickStop()
This sends the controlword for performing a quick_stop.
Definition: DS402Node.cpp:266
ds402::eModeOfOperation m_op_mode
The mode of operation of this device.
Definition: DS402Node.h:386
virtual void setNMTState(const NMT::eNMT_State state, const NMT::eNMT_SubState sub_state)
Definition: DS402Node.cpp:261
bool change_set_immediately
If this is set to true the device will not ramp down at a setpoint if a following one is given...
Definition: ds402.h:199
data union for access to DSP 402 6040 controlword,
Definition: ds402.h:108
eNMT_State
The NMT state indicates the behavior of the communication of a device, everything else is device spec...
Definition: NMT.h:60
void configureMaxAcceleration(const uint32_t acceleration)
Set the device&#39;s maximum acceleration through an SDO (OD 0x60c5)
Definition: DS402Node.cpp:864
virtual ds402::Statusword getStatus()
Definition: DS402Node.cpp:1167
Mapping of a PDO. This is basically a description that says where to look in the object dictionary an...
Definition: PDO.h:53
float profile_deceleration
This will be used for both acceleration ramps.
Definition: ds402.h:188
#define LOGGING_ERROR_C(streamname, classname, arg)
virtual void setupProfilePositionMode(const ds402::ProfilePositionModeConfiguration &config)
Configure the mandatory parameters for a profile position mode.
Definition: DS402Node.cpp:775
Class that holds devices according to the DS402 (drives and motion control) specification.
Definition: DS402Node.h:43
virtual double getTargetFeedback()
Depending on the mode of operation, this will return the current position, velocity or torque...
Definition: DS402Node.cpp:185
The DS301Node class Is the base class representation of canOpen devices. It is the access point to th...
Definition: DS301Node.h:67
virtual bool setTarget(const float target)
Sets the target for the motor. What that target is, depends on the selected mode of operation...
Definition: DS402Node.cpp:96
NMT m_nmt
Object to handle NMT calls and status.
Definition: DS301Node.h:303
int usleep(unsigned long useconds)
void registerPDONotifyCallback(const std::string &identifier, const boost::function< void()> &f)
This function maps a callback to a specific mapped PDO entry. This callback will be called by the PDO...
Definition: DS301Node.cpp:239
Configuration parameters for a Homing_Mode according to CiA DSP-402 V1.1 section 13.2.1.
Definition: ds402.h:229


schunk_canopen_driver
Author(s): Felix Mauch , Georg Heppner
autogenerated on Mon Jun 10 2019 15:07:49