@@ -87,9 +87,11 @@ class State402(object):
87
87
88
88
@staticmethod
89
89
def next_state_for_enabling (_from ):
90
- """Returns the next state needed for reach the state Operation Enabled
91
- :param string target: Target state
92
- :return string: Next target to chagne
90
+ """Return the next state needed for reach the state Operation Enabled.
91
+
92
+ :param string target: Target state.
93
+ :return: Next target to change.
94
+ :rtype: str
93
95
"""
94
96
for cond , next_state in State402 .NEXTSTATE2ENABLE .items ():
95
97
if _from in cond :
@@ -209,10 +211,10 @@ def __init__(self, node_id, object_dictionary):
209
211
self .rpdo_pointers = dict () # { index: RPDO_pointer }
210
212
211
213
def setup_402_state_machine (self ):
212
- """Configure the state machine by searching for a TPDO that has the
213
- StatusWord mapped.
214
- :raise ValueError: If the the node can't find a Statusword configured
215
- in the any of the TPDOs
214
+ """Configure the state machine by searching for a TPDO that has the StatusWord mapped.
215
+
216
+ :raises ValueError:
217
+ If the the node can't find a Statusword configured in the any of the TPDOs.
216
218
"""
217
219
self .nmt .state = 'PRE-OPERATIONAL' # Why is this necessary?
218
220
self .setup_pdos ()
@@ -258,8 +260,7 @@ def _check_statusword_configured(self):
258
260
self .id ))
259
261
260
262
def reset_from_fault (self ):
261
- """Reset node from fault and set it to Operation Enable state
262
- """
263
+ """Reset node from fault and set it to Operation Enable state."""
263
264
if self .state == 'FAULT' :
264
265
# Resets the Fault Reset bit (rising edge 0 -> 1)
265
266
self .controlword = State402 .CW_DISABLE_VOLTAGE
@@ -275,7 +276,12 @@ def is_faulted(self):
275
276
return self .statusword & bitmask == bits
276
277
277
278
def is_homed (self , restore_op_mode = False ):
278
- """Switch to homing mode and determine its status."""
279
+ """Switch to homing mode and determine its status.
280
+
281
+ :param bool restore_op_mode: Switch back to the previous operation mode when done.
282
+ :return: If the status indicates successful homing.
283
+ :rtype: bool
284
+ """
279
285
previous_op_mode = self .op_mode
280
286
if previous_op_mode != 'HOMING' :
281
287
logger .info ('Switch to HOMING from %s' , previous_op_mode )
@@ -290,11 +296,13 @@ def is_homed(self, restore_op_mode=False):
290
296
return homingstatus in ('TARGET REACHED' , 'ATTAINED' )
291
297
292
298
def homing (self , timeout = TIMEOUT_HOMING_DEFAULT , set_new_home = True ):
293
- """Function to execute the configured Homing Method on the node
294
- :param int timeout: Timeout value (default: 30)
295
- :param bool set_new_home: Defines if the node should set the home offset
296
- object (0x607C) to the current position after the homing procedure (default: true)
297
- :return: If the homing was complete with success
299
+ """Execute the configured Homing method on the node.
300
+
301
+ :param int timeout: Timeout value (default: 30).
302
+ :param bool set_new_home:
303
+ Defines if the node should set the home offset object (0x607C) to the current
304
+ position after the homing procedure (default: true).
305
+ :return: If the homing was complete with success.
298
306
:rtype: bool
299
307
"""
300
308
previus_op_mode = self .op_mode
@@ -333,18 +341,11 @@ def homing(self, timeout=TIMEOUT_HOMING_DEFAULT, set_new_home=True):
333
341
334
342
@property
335
343
def op_mode (self ):
336
- """
337
- :return: Return the operation mode stored in the object 0x6061 through SDO
338
- :rtype: int
339
- """
340
- return OperationMode .CODE2NAME [self .sdo [0x6061 ].raw ]
344
+ """The node's Operation Mode stored in the object 0x6061.
341
345
342
- @op_mode .setter
343
- def op_mode (self , mode ):
344
- """Function to define the operation mode of the node
345
- :param string mode: Mode to define.
346
+ Uses SDO to access the current value. The modes are passed as one of the
347
+ following strings:
346
348
347
- The modes can be:
348
349
- 'NO MODE'
349
350
- 'PROFILED POSITION'
350
351
- 'VELOCITY'
@@ -357,7 +358,14 @@ def op_mode(self, mode):
357
358
- 'CYCLIC SYNCHRONOUS TORQUE'
358
359
- 'OPEN LOOP SCALAR MODE'
359
360
- 'OPEN LOOP VECTOR MODE'
361
+
362
+ :raises TypeError: When setting a mode not advertised as supported by the node.
363
+ :raises RuntimeError: If the switch is not confirmed within the configured timeout.
360
364
"""
365
+ return OperationMode .CODE2NAME [self .sdo [0x6061 ].raw ]
366
+
367
+ @op_mode .setter
368
+ def op_mode (self , mode ):
361
369
try :
362
370
if not self .is_op_mode_supported (mode ):
363
371
raise TypeError (
@@ -394,9 +402,13 @@ def _clear_target_values(self):
394
402
self .sdo [target_index ].raw = 0
395
403
396
404
def is_op_mode_supported (self , mode ):
397
- """Function to check if the operation mode is supported by the node
398
- :param int mode: Operation mode
399
- :return: If the operation mode is supported
405
+ """Check if the operation mode is supported by the node.
406
+
407
+ The object listing the supported modes is retrieved once using SDO, then cached
408
+ for later checks.
409
+
410
+ :param str mode: Same format as the :attr:`op_mode` property.
411
+ :return: If the operation mode is supported.
400
412
:rtype: bool
401
413
"""
402
414
if not hasattr (self , '_op_mode_support' ):
@@ -408,18 +420,20 @@ def is_op_mode_supported(self, mode):
408
420
return self ._op_mode_support & bits == bits
409
421
410
422
def on_TPDOs_update_callback (self , mapobject ):
411
- """This function receives a map object.
412
- this map object is then used for changing the
413
- :param mapobject: :class: `canopen.objectdictionary.Variable`
423
+ """Cache updated values from a TPDO received from this node.
424
+
425
+ :param mapobject: The received PDO message.
426
+ :type mapobject: canopen.pdo.Map
414
427
"""
415
428
for obj in mapobject :
416
429
self .tpdo_values [obj .index ] = obj .raw
417
430
418
431
@property
419
432
def statusword (self ):
420
- """Returns the last read value of the Statusword (0x6041) from the device.
421
- If the the object 0x6041 is not configured in any TPDO it will fallback to the SDO mechanism
422
- and try to tget the value.
433
+ """Return the last read value of the Statusword (0x6041) from the device.
434
+
435
+ If the the object 0x6041 is not configured in any TPDO it will fall back to the
436
+ SDO mechanism and try to get the value.
423
437
"""
424
438
try :
425
439
return self .tpdo_values [0x6041 ]
@@ -429,13 +443,15 @@ def statusword(self):
429
443
430
444
@property
431
445
def controlword (self ):
446
+ """Send a state change command using PDO or SDO.
447
+
448
+ :param int value: Controlword value to set.
449
+ :raises RuntimeError: Read access to the controlword is not intended.
450
+ """
432
451
raise RuntimeError ('The Controlword is write-only.' )
433
452
434
453
@controlword .setter
435
454
def controlword (self , value ):
436
- """Send the state using PDO or SDO objects.
437
- :param int value: State value to send in the message
438
- """
439
455
if 0x6040 in self .rpdo_pointers :
440
456
self .rpdo_pointers [0x6040 ].raw = value
441
457
self .rpdo_pointers [0x6040 ].pdo_parent .transmit ()
@@ -444,16 +460,24 @@ def controlword(self, value):
444
460
445
461
@property
446
462
def state (self ):
447
- """Attribute to get or set node's state as a string for the DS402 State Machine.
448
- States of the node can be one of:
449
- - 'NOT READY TO SWITCH ON'
463
+ """Manipulate current state of the DS402 State Machine on the node.
464
+
465
+ Uses the last received Statusword value for read access, and manipulates the
466
+ :attr:`controlword` for changing states. The states are passed as one of the
467
+ following strings:
468
+
469
+ - 'NOT READY TO SWITCH ON' (cannot be switched to deliberately)
450
470
- 'SWITCH ON DISABLED'
451
471
- 'READY TO SWITCH ON'
452
472
- 'SWITCHED ON'
453
473
- 'OPERATION ENABLED'
454
- - 'FAULT'
455
- - 'FAULT REACTION ACTIVE'
474
+ - 'FAULT' (cannot be switched to deliberately)
475
+ - 'FAULT REACTION ACTIVE' (cannot be switched to deliberately)
456
476
- 'QUICK STOP ACTIVE'
477
+ - 'DISABLE VOLTAGE' (only as a command when writing)
478
+
479
+ :raises RuntimeError: If the switch is not confirmed within the configured timeout.
480
+ :raises ValueError: Trying to execute a illegal transition in the state machine.
457
481
"""
458
482
for state , mask_val_pair in State402 .SW_MASK .items ():
459
483
bitmask , bits = mask_val_pair
@@ -463,18 +487,6 @@ def state(self):
463
487
464
488
@state .setter
465
489
def state (self , target_state ):
466
- """ Defines the state for the DS402 state machine
467
- States to switch to can be one of:
468
- - 'SWITCH ON DISABLED'
469
- - 'DISABLE VOLTAGE'
470
- - 'READY TO SWITCH ON'
471
- - 'SWITCHED ON'
472
- - 'OPERATION ENABLED'
473
- - 'QUICK STOP ACTIVE'
474
- :param string target_state: Target state
475
- :raise RuntimeError: Occurs when the time defined to change the state is reached
476
- :raise ValueError: Occurs when trying to execute a ilegal transition in the sate machine
477
- """
478
490
timeout = time .monotonic () + self .TIMEOUT_SWITCH_STATE_FINAL
479
491
while self .state != target_state :
480
492
next_state = self ._next_state (target_state )
0 commit comments