canopen icon indicating copy to clipboard operation
canopen copied to clipboard

Mismatch between expected and actual data size ?

Open Polyphe opened this issue 4 years ago • 1 comments

Hello, I have an issue when I want to connect 2 nodes together, the one or the other node works very well alone as shown below (the motor turn at the correct velocity) but both, there is an error and the motor turns at the same velocity whereas the one have to turn at 1000rpm and the other at 100rpm ? Why ? Could you help me, please ?

found node 32
found node 33
node state 1) = PRE-OPERATIONAL
node state 1) = PRE-OPERATIONAL
node state 3) = PRE-OPERATIONAL
node state 3) = PRE-OPERATIONAL
Mismatch between expected and actual data size
Mismatch between expected and actual data size
node state 4) = OPERATIONAL
node state 4) = OPERATIONAL
Mismatch between expected and actual data size
Mismatch between expected and actual data size
Mismatch between expected and actual data size
Mismatch between expected and actual data size
Mismatch between expected and actual data size
Mismatch between expected and actual data size
Mismatch between expected and actual data size
Mismatch between expected and actual data size
Mismatch between expected and actual data size
Mismatch between expected and actual data size
Mismatch between expected and actual data size
Mismatch between expected and actual data size
Mismatch between expected and actual data size
Mismatch between expected and actual data size
Mismatch between expected and actual data size
Node booted up
Node 1: statusword 1: 22055
Node 1: VEL 1: 82.8955078125
Node 2: statusword 1: 22055
Node 2: VEL 1: 82.8955078125
Node 1: statusword 1: 22055
Node 1: VEL 1: 123.3251953125
Node 2: statusword 1: 22055
Node 2: VEL 1: 123.3251953125
Node 1: statusword 1: 22055
Node 1: VEL 1: 83.7744140625
Node 2: statusword 1: 22055
Node 2: VEL 1: 83.7744140625
Node 1: statusword 1: 22055
Node 1: VEL 1: 123.3251953125
Node 2: statusword 1: 22055
Node 2: VEL 1: 123.3251953125
Node 1: statusword 1: 22055
Node 1: VEL 1: 84.3603515625
Node 2: statusword 1: 22055
Node 2: VEL 1: 84.3603515625
Node 1: statusword 1: 22055
Node 1: VEL 1: 123.3251953125
Node 2: statusword 1: 22055
Node 2: VEL 1: 123.3251953125
Node 1: statusword 1: 22055
Node 1: VEL 1: 83.4814453125
Node 2: statusword 1: 22055
Node 2: VEL 1: 83.4814453125
Node 1: statusword 1: 22055
Node 1: VEL 1: 123.3251953125
Node 2: statusword 1: 22055
Node 2: VEL 1: 123.3251953125
Node 1: statusword 1: 22055
Node 1: VEL 1: 94.9072265625
Node 2: statusword 1: 17959
Node 2: VEL 1: 94.9072265625
Node 1: statusword 1: 22055
Node 1: VEL 1: 123.3251953125
Node 2: statusword 1: 22055
Node 2: VEL 1: 123.3251953125
Node 1: statusword 1: 22055
Node 1: VEL 1: 93.7353515625
Node 2: statusword 1: 17959
Node 2: VEL 1: 93.7353515625
Node 1: statusword 1: 22055
Node 1: VEL 1: 123.6181640625
Node 2: statusword 1: 22055
Node 2: VEL 1: 123.6181640625
Node 1: statusword 1: 22055
Node 1: VEL 1: 94.0283203125
Node 2: statusword 1: 17959
Node 2: VEL 1: 94.0283203125
Node 1: statusword 1: 22055
Node 1: VEL 1: 123.3251953125
Node 2: statusword 1: 22055
Node 2: VEL 1: 123.3251953125
Node 1: statusword 1: 22055
Node 1: VEL 1: 94.0283203125
Node 2: statusword 1: 17959
Node 2: VEL 1: 94.0283203125
Node 1: statusword 1: 22055
Node 1: VEL 1: 123.0322265625
Node 2: statusword 1: 22055
Node 2: VEL 1: 123.0322265625
Node 1: statusword 1: 22055
Node 1: VEL 1: 93.7353515625
Node 2: statusword 1: 17959
Node 2: VEL 1: 93.7353515625
going to exit... stoping...

Here is the code:

import canopen
import sys
import os
import traceback

import time

try:
    
    # Start with creating a network representing one CAN bus
    network = canopen.Network()

    # Connect to the CAN bus
    #network.connect(bustype='kvaser', channel=0, bitrate=1000000)
    network.connect(bustype='pcan', channel='PCAN_USBBUS1', bitrate=1000000)
    network.check()

    # Search all the node attached to the network
    network.scanner.search()
    time.sleep(0.05)
    for node_id in network.scanner.nodes:
        print("found node %d" % node_id)


    # Add some nodes with corresponding Object Dictionaries
    node1 = canopen.BaseNode402(0x20, '0x3842_0x3F8_0x131.eds')
    network.add_node(node1)
    # Add some nodes with corresponding Object Dictionaries
    node2 = canopen.BaseNode402(0x21, '0x3842_0x3F8_0x131.eds')
    network.add_node(node2)
    
    # Reset network
    node2.nmt.state = 'RESET COMMUNICATION'
    node1.nmt.state = 'RESET COMMUNICATION'
    
    node2.nmt.wait_for_bootup(15)
    node1.nmt.wait_for_bootup(15)
    
 
    print('node state 1) = {0}'.format(node1.nmt.state))
    print('node state 1) = {0}'.format(node2.nmt.state))

   
    # Write a variable using SDO
    node2.sdo[0x1006].raw = 0#1
    node2.sdo[0x100c].raw = 0#100
    node2.sdo[0x100d].raw = 0#3
    node2.sdo[0x1014].raw = 0xC3#163
    
    # Write a variable using SDO
    node1.sdo[0x1006].raw = 0#1
    node1.sdo[0x100c].raw = 0#100
    node1.sdo[0x100d].raw = 0#3
    node1.sdo[0x1014].raw = 0xC3#163
    

    node1.sdo[0x1003][0].raw = 0
    node2.sdo[0x1003][0].raw = 0
    
    # Transmit SYNC every 100 ms
    #network.sync.start(0.15)
    node2.load_configuration()
    node1.load_configuration()
   
    node2.sdo[0x1017].raw = 400#Slave
    node1.sdo[0x1017].raw = 600#Slave
    
    print('node state 3) = {0}'.format(node2.nmt.state))
    print('node state 3) = {0}'.format(node1.nmt.state))
    
    
    node2.setup_402_state_machine()
    node1.setup_402_state_machine()
    
    
    print('node state 4) = {0}'.format(node2.nmt.state))
    print('node state 4) = {0}'.format(node1.nmt.state))
    #network.nmt.state = 'OPERATIONAL'
    
    
    node2.state = 'SWITCH ON DISABLED'
    node1.state = 'SWITCH ON DISABLED'
    
    
    # Init Velocity Profile at 0 rpm  
    node1.sdo[0x60FF].raw = 0
    node1.sdo[0x6060].raw = 3
    
    # Init Velocity Profile at 0 rpm  
    node2.sdo[0x60FF].raw = 0
    node2.sdo[0x6060].raw = 3
    
    # PDO NODE 1
    # Read PDO configuration from node
    node1.tpdo.read()
    # Re-map TxPDO1
    node1.tpdo[1].clear()
    node1.tpdo[1].add_variable(0x6041)#'Statusword')
    node1.tpdo[1].add_variable(0x606C)#'Velocity actual value')
    node1.tpdo[1].trans_type = 0xFF
    node1.tpdo[1].event_timer = 0x64
    node1.tpdo[1].enabled = True
    
    node1.tpdo[2].enabled = False
    node1.tpdo[3].enabled = False
    node1.tpdo[4].enabled = False
    # Save new PDO configuration to node
    node1.tpdo.save()
    
    # Re-map RxPDO1 
    node1.rpdo.read()
    node1.rpdo[1].clear()
    node1.rpdo[1].add_variable(0x6040) #Controlword
    node1.rpdo[1].add_variable(0x60FF) #Velocity
    node1.rpdo[1].enabled = True
    
    node1.rpdo[2].enabled = False
    node1.rpdo[3].enabled = False
    node1.rpdo[4].enabled = False
    # Save new configuration (node must be in pre-operational)
    node1.rpdo.save()
 
   #PDO NODE 2
   # Read PDO configuration from node
    node2.tpdo.read()
    # Re-map TxPDO1
    node2.tpdo[1].clear()
    node2.tpdo[1].add_variable(0x6041)#'Statusword')
    node2.tpdo[1].add_variable(0x606C)#'Velocity actual value')
    node2.tpdo[1].trans_type = 0xFF
    node2.tpdo[1].event_timer = 0x64
    node2.tpdo[1].enabled = True
    
    node2.tpdo[2].enabled = False
    node2.tpdo[3].enabled = False
    node2.tpdo[4].enabled = False
    # Save new PDO configuration to node
    node2.tpdo.save()
    
    # Re-map RxPDO1 
    node2.rpdo.read()
    node2.rpdo[1].clear()
    node2.rpdo[1].add_variable(0x6040) #Controlword
    node2.rpdo[1].add_variable(0x60FF) #Velocity
    node2.rpdo[1].enabled = True
    
    node2.rpdo[2].enabled = False
    node2.rpdo[3].enabled = False
    node2.rpdo[4].enabled = False
    # Save new configuration (node must be in pre-operational)
    node2.rpdo.save()
    
    
    # ----------------------------------OPERATIONAL MODE  ## USE ONLY PDO HERE--------------------------------------

    print('Node booted up')
	
	# enable NODE 1
	#Reset previous fault 
    node1.rpdo[1]['Controlword'].raw = 0x80
    node1.rpdo[1].transmit()
    node1.rpdo[1]['Controlword'].raw = 0x81
    node1.rpdo[1].transmit()
    
    
    #Enable motor (state machine 402)
    timeout = time.time() + 15
    node1.state = 'READY TO SWITCH ON'
    while node1.state != 'READY TO SWITCH ON':
        if time.time() > timeout:
            raise Exception('Timeout when trying to change state')
        time.sleep(0.001)

    timeout = time.time() + 15
    node1.state = 'SWITCHED ON'
    while node1.state != 'SWITCHED ON':
        if time.time() > timeout:
            raise Exception('Timeout when trying to change state')
        time.sleep(0.001)

    timeout = time.time() + 15
    node1.state = 'OPERATION ENABLED'
    while node1.state != 'OPERATION ENABLED':
        if time.time() > timeout:
            raise Exception('Timeout when trying to change state')
        time.sleep(0.001)

    # Start velocity 1000 rpm 
    node1.rpdo[1][0x60FF].phys = 1000*4096/60
    node1.rpdo[1].transmit()
    
    
    
    # enable NODE 2
	#Reset previous fault 
    node2.rpdo[1]['Controlword'].raw = 0x80
    node2.rpdo[1].transmit()
    node2.rpdo[1]['Controlword'].raw = 0x81
    node2.rpdo[1].transmit()
    
    
    #Enable motor (state machine 402)
    timeout = time.time() + 15
    node2.state = 'READY TO SWITCH ON'
    while node2.state != 'READY TO SWITCH ON':
        if time.time() > timeout:
            raise Exception('Timeout when trying to change state')
        time.sleep(0.001)

    timeout = time.time() + 15
    node2.state = 'SWITCHED ON'
    while node2.state != 'SWITCHED ON':
        if time.time() > timeout:
            raise Exception('Timeout when trying to change state')
        time.sleep(0.001)

    timeout = time.time() + 15
    node2.state = 'OPERATION ENABLED'
    while node2.state != 'OPERATION ENABLED':
        if time.time() > timeout:
            raise Exception('Timeout when trying to change state')
        time.sleep(0.001)

    # Start velocity 1000 rpm 
    node2.rpdo[1][0x60FF].phys = 100*4096/60
    node2.rpdo[1].transmit()
    
    start = time.time()
    #node.nmt.start_node_guarding(0.5)
    while True:
        try:
            network.check()
        except Exception:
            break
        end = time.time()
        if end > start + 10 :
            break
		
        # Read a value from TxPDO1
        node1.tpdo[1].wait_for_reception()
        speed = node1.tpdo[1]['Velocity actual value'].phys
        time.sleep(0.01)
        
        # Read a value from TxPDO1
        node2.tpdo[1].wait_for_reception()
        speed = node2.tpdo[1]['Velocity actual value'].phys
        time.sleep(0.01)
        
        # Read the state of the Statusword
        statusword = node1.sdo[0x6041].raw
        print('Node 1: statusword 1: {0}'.format(statusword))
        print('Node 1: VEL 1: {0}'.format(speed*60/4096))
        
        # Read the state of the Statusword
        statusword = node2.sdo[0x6041].raw
        print('Node 2: statusword 1: {0}'.format(statusword))
        print('Node 2: VEL 1: {0}'.format(speed*60/4096))
        
        node1.nmt.wait_for_heartbeat()
        node2.nmt.wait_for_heartbeat()
       
    """
    # Iterate over arrays or records
    error_log = node1.sdo[0x1003]
    for error in error_log.values():
        print("Error {0} was found in the log".format(error.raw))
   
    time.sleep(5)
    """
    
    # Switch off Node 1
    node1.rpdo[1]['Controlword'].phys = 0
    # reset Velocity at 0 rpm
    node1.rpdo[1][0x60FF].phys = 0
    node1.rpdo[1].transmit()
    
    # Switch off Node 2
    node2.rpdo[1]['Controlword'].phys = 0
    # reset Velocity at 0 rpm
    node2.rpdo[1][0x60FF].phys = 0
    node2.rpdo[1].transmit()
    
   

except KeyboardInterrupt:
    pass
except Exception as e:
    exc_type, exc_obj, exc_tb = sys.exc_info()
    fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
    print(exc_type, fname, exc_tb.tb_lineno)
    traceback.print_exc()
finally:
    # Disconnect from CAN bus
    print('going to exit... stoping...')
    if network:

        for node_id in network:
            node = network[node_id]
            node1.nmt.state = 'PRE-OPERATIONAL'
            node2.nmt.state = 'PRE-OPERATIONAL'
            #node.nmt.stop_node_guarding()
            
        network.sync.stop()
        network.disconnect()

Thank you in advance.

Best Greetings for 2021 with good health despite Covid 19.

Polyphe avatar Jan 04 '21 13:01 Polyphe

Hi @Polyphe,

So the motors were moving at the desired velocities?? You mean the "Mismatch between expected and actual data size", I believe this is due to the value you are trying to read does not match the type set for that object in the object dictionary... double check the objectdictionary .EDS file .

Node 1: statusword 1: 22055 Node 1: VEL 1: 123.0322265625 Node 2: statusword 1: 22055 Node 2: VEL 1: 123.0322265625 Node 1: statusword 1: 22055 Node 1: VEL 1: 93.7353515625 Node 2: statusword 1: 17959 Node 2: VEL 1: 93.7353515625

Try this:

        # Read a value from TxPDO1
        node1.tpdo[1].wait_for_reception()
        node1_speed = node1.tpdo[1]['Velocity actual value'].phys
        time.sleep(0.01)
        
        # Read a value from TxPDO1
        node2.tpdo[1].wait_for_reception()
        node2_speed = node2.tpdo[1]['Velocity actual value'].phys
        time.sleep(0.01)
        
        # Read the state of the Statusword
        statusword = node1.sdo[0x6041].raw
        print('Node 1: statusword 1: {0}'.format(statusword))
        print('Node 1: VEL 1: {0}'.format(node1_speed *60/4096))
        
        # Read the state of the Statusword
        statusword = node2.sdo[0x6041].raw
        print('Node 2: statusword 1: {0}'.format(statusword))
        print('Node 2: VEL 1: {0}'.format(node2_speed *60/4096))

The speed variable is overwritten the second time you call it, so yo are seeing the same velocity (Node 2 velocity) in the two prints.

Some questions: Also which safeguard are you using NodeGuard? Your program (script) should act as a Master. Why the self.network.sync.start(0.01) is commented, this should be used to sync the motors action, they will only be actuated when receiving the sync message.

Some advice's: Configure StatusWord to a PDO for faster reads. Add a callback for the emcy message -> self.emcy.add_callback(self.handle_emcy) Make sure the ID for the drivers is not configured in the EDS file, they should have different id's.

Try clean a bit your code:


...

for id in self.network.nodes:
  node = self.network[id]
  # Load the configuration read from the EDS file to all the nodes
  node.load_configuration()
  # Start the internal DS402 State Machine
  node.setup_402_state_machine()
  # Start the node guarding mechanism
  node.nmt.start_node_guarding(0.01)
  try:
      # the internal state machine will try to reach this state, and throw exception if it can't
      # you really don't need to wait the state to change, i have to update the example
      node.state = 'OPERATION ENABLED'
  except RuntimeError as e:
      print('Unable to power up the node {0:#06x}. Please try manualy or restart the node.'.format(node.id))

...

(Sorry for editing your post, i just fixed the code fix the way the code is display for better reading, nothing else) (updated my answer @Polyphe)

af-silva avatar Jan 05 '21 18:01 af-silva