christiansandberg / canopen

CANopen for Python
http://canopen.readthedocs.io/
MIT License
444 stars 196 forks source link

Support multiple motors in CiA 402 CANopen device profile #179

Open trinamic-jm opened 4 years ago

trinamic-jm commented 4 years ago

Hello,

Currently the ds402 implementation only supports one motor. We would like to extend this to multiple motors as specified by ds402.

We working with a multi-axis board each using CiA 402. We want to be able to control all motors independently of each other.

The CiA 402 standard specifies how to implement multiple motors: Each motor has its own state machine and all the relevant parameters (e.g. Controlword, Statusword). For each subsequent motor the indices are offset by 0x0800. For example, the Controlword of the first motor is 0x6040, the Controlword of the second motor is 0x6840.

Currently the canopen library implements the ds402 state transitions like this:

BaseNode402.state = "OPERATIONAL"

In order for multiple axes to be supported, this could be changed to the following:

BaseNode402.state[0] = "OPERATIONAL"

However, (afaik) there is no good way to implement the latter without breaking the backwards compatibility to the former. As an alternative, we could have the BaseNode402.state property for supporting a single axis (the first one) and have a different property for supporting multi-axes implementations:

# Set axes 0 and 1 to operational using the new property
BaseNode402.states[0] = "OPERATIONAL
BaseNode402.states[1] = "OPERATIONAL

# Read the state axis 0 using the old backwards compatible property
print(BaseNode402.state) # Should print "OPERATIONAL"

Would you be interested in an implementation of this for this library?

af-silva commented 4 years ago

Hi @trinamic-jm ,

I don't think I completely understood you situation, you want to be able to control the state machine of each individual motor independently, is that it?

The current implementation supports Multiple motors, since each motor has a unique address inside the CANBus network ( COB-ID ) you can control (e.g., using the controlword and statusword) individually, that is, control the motor and listen for different parameters like velocity, temperature and other. Also, the library provides the NMT protocol implementation, that allows you to control the State Machine of each individual motor ...

    # Add some nodes with corresponding Object Dictionaries
    node1 = canopen.BaseNode402(35, '/home/andre/Code/test/jupiter.eds')
    network.add_node(node1)
    node2 = canopen.BaseNode402(34, '/home/andre/Code/test/jupiter.eds')
    network.add_node(node2)

    node1.nmt.state = 'OPERATIONAL'
    node2.nmt.state = 'OPERATIONAL' 

Am I missing something here??? Again, I have a robot with 8 independent motors all running with this library and I'm able to control them independently. Moreover, I can control using the EMCY service what do do if any given motor fails.

If you could please provide a better example or explain a bit better what you want to accomplish I would appreciate, since I don't fully understand or am missing something like a said.

If you want to contribute with code please do so, you can make a pull request and we will discuss it later also with @christiansandberg . Thanks ;)

christiansandberg commented 4 years ago

I don’t have the 402 standard, but it sounds like it allows a single logical node to control multiple motors. I understand that it could be possible with a single SDO server by using different indices but I don’t understand how it would work with the NMT state machine since there can only be one per node.

trinamic-jm commented 4 years ago

@af-silva It sounds like your setup has multiple nodes each controlling a single motor. In our case, we have a module which is a single node controlling multiple motors. @christiansandberg The NMT state machine is per-node, so there is still only one state machine for said module. For the 402 state machine however, all parameters are duplicated for each motor. Each motor als has a separate 402 state machine.

For reference, a snippet from our documentation:

On a multi-axis module like the TMCM-6212 each object in the manufacturer area and each object in the profile specific area is available for each motor. In this manual, only the object indices for motor #0 are shown. The objects for the other motors can be accessed by adding offsets to the object indices: • Add an offset of motor_number * 200h to the index of a manufacturer specific object to get its index for other motors. • *Add an offset of motor_number 800h to the index of a profile specific object to get its index for other motors. For example, the control word for motor 1 would be 6840h (instead of 6040h for motor 0)**, and the microstep resolution of motor 1 would be 2200h for motor 1 (instead of 2000h for motor 0).

See Section 2.4.1 of our module's firmware manual. (I'd like to quote the standard, but I do not know whether that would violate copyright. The linked documentation by us does reflect the standard definition of using multiple motors with CiA 402)

af-silva commented 4 years ago

Hi @trinamic-jm,

Ok now is clear to me, sorry for not understanding at first, i'm not aware of the full ds402 specification, I have implemented only the parts that I needed for my requirements and didn't extended further and also since I don't have direct access to the ds402 full specification. That being said, I think, in my opinion, that providing a full ds402 implementations through this library would be neat, so I will help as much as I can. If you already have some functional code you can contribute we can create a new branch for this functionality and test it.

So, in resume each node has it's own NMT state machine, provided by the class LocalNode(BaseNode) and class RemoteNode(BaseNode):. On the other hand, the class class BaseNode402(RemoteNode): has the RemoteNode as base class and implements the ds402 state machine.

So, to support multiple ds402 state machines, this must be done inside this class and stored in an array, being the default behavior to access the first position. The existence of more than one device per-node is configured where ??? In the manufacturer reserved area of the Object Dictionary ?? How can we know if more than one device is configured (aka available) for each node ? The library should be manufacture agnostic, and so we need to provided the base same functionality to all device manufacturers and implement ways to resolve this.

Like I said, if you have already something done regarding this and you are willing to contribute to thsi project please share that and I can create a new branch for us to test it.

Thanks ;)

Martin-Wuertemberg commented 4 years ago

The existence of more than one device per-node is configured where ??? In the manufacturer reserved area of the Object Dictionary ?? How can we know if more than one device is configured (aka available) for each node ?

The "multiple logical device" is described in CiA301, Object 0x1000 "Device Type". In case of a multiple device, the upper 16 bits are 0xFFFF. The lower 16 bits (device profile number) is the device profile of the first logical device, in this case 402. For more details see CiA301. With this one CANopen node can contain multiple devices which can be of different types e.g. a drive (device profile 402) combined with Digital IO (device profile 401).