christiansandberg / canopen

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

RPDO Read fails when not all implemented #201

Closed nhayes-me closed 4 months ago

nhayes-me commented 4 years ago

I have several motors that have DCF files from the configuration software. For whatever reason, neither the EDS or DCF files are completely filled out as the module demands. For example, the DCF file has TPDO 22 configure and only that, so 0x1A00 is not in the DCF. This throws an error when creating a BaseNode402 object or when trying to read RPDO/TPDO if the node is created with network.add_node().

The error given is as expected: canopen.sdo.exceptions.SdoAbortedError: Code 0x06020000, Object does not exist

I believe this is because certain SDOs are hard-coded in the module for the TPDO/RPDOs instead of reading from the [OptionalObjects] section in the DCF/EDS. I don't know the module well enough to make a pull request and I may also be incorrect in my assumption. Any suggestions on addressing?

af-silva commented 4 years ago

Hi @Rokmonkey,

You can tinker with the code of the BaseNode402 to handle your specific case, it's the only file related to the implementation of the profile DS402 for controlling actuators.

So, here are some assumptions made when writing the code provided by BaseNode402:

So, in respect to the hard coded SDO these is it, regarding reading the OptionalObjects you are right, i don't read this section of the DCF/EDS files. If you have the opportunity you can implement this, in your opinion how should this work?? if i have the time i can try to figure how this needs to be implemented but non the less, I don't think your error is related to this.

You should try to see what object is trying to be set and returning that error. That is a generic CAN error 0602 0000hObject does not exist in the object dictionary, so my advice would be to sniff the CAN Network to figure out what is happening, if you can provide more info would be nice for me to better help you.

Hope this helps ;)

nhayes-me commented 4 years ago

I found the snag, but neglected to show what I found. The problem exists as soon as the node is created.

The kicker of the hardcoding is here in /pdo/ini.py and in the other classes in this file where self.map expects to start at 0x1A00 and go up. If it's not in the EDS file it fails even if CiA402 says they can exist. For some unknown reason the EDS and DCF files for my motors only have the TPDOs that are actually assigned, in my case 0x1a19. I'd modify the code to not try that, but I am fuzzy on where this PDO class gets the expectation of which TPDOs we can access. It must not be from reading the EDS, as they don't show up anywhere.

class PDO(PdoBase):
    """PDO Class for backwards compatibility
    :param rpdo: RPDO object holding the Receive PDO mappings
    :param tpdo: TPDO object holding the Transmit PDO mappings
    """

    def __init__(self, node, rpdo, tpdo):
        super(PDO, self).__init__(node)
        self.rx = rpdo.map
        self.tx = tpdo.map

        self.map = {}
        # the object 0x1A00 equals to key '1' so we remove 1 from the key
        for key, value in self.rx.items():
            self.map[0x1A00 + (key - 1)] = value
        for key, value in self.tx.items():
            self.map[0x1600 + (key - 1)] = value

for reference, the fill stack trace is here:

>>> node.load_configuration()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/pi/.local/lib/python3.7/site-packages/canopen/node/remote.py", line 154, in load_configuration
    self.pdo.read()  # reads the new configuration from the driver
  File "/home/pi/.local/lib/python3.7/site-packages/canopen/pdo/base.py", line 55, in read
    pdo_map.read()
  File "/home/pi/.local/lib/python3.7/site-packages/canopen/pdo/base.py", line 289, in read
    cob_id = self.com_record[1].raw
  File "/home/pi/.local/lib/python3.7/site-packages/canopen/variable.py", line 74, in raw
    value = self.od.decode_raw(self.data)
  File "/home/pi/.local/lib/python3.7/site-packages/canopen/variable.py", line 36, in data
    return self.get_data()
  File "/home/pi/.local/lib/python3.7/site-packages/canopen/sdo/base.py", line 108, in get_data
    return self.sdo_node.upload(self.od.index, self.od.subindex)
  File "/home/pi/.local/lib/python3.7/site-packages/canopen/sdo/client.py", line 117, in upload
    fp = self.open(index, subindex, buffering=0)
  File "/home/pi/.local/lib/python3.7/site-packages/canopen/sdo/client.py", line 197, in open
    raw_stream = ReadableStream(self, index, subindex)
  File "/home/pi/.local/lib/python3.7/site-packages/canopen/sdo/client.py", line 243, in __init__
    response = sdo_client.request_response(request)
  File "/home/pi/.local/lib/python3.7/site-packages/canopen/sdo/client.py", line 85, in request_response
    return self.read_response()
  File "/home/pi/.local/lib/python3.7/site-packages/canopen/sdo/client.py", line 73, in read_response
    raise SdoAbortedError(abort_code)
canopen.sdo.exceptions.SdoAbortedError: Code 0x06020000, Object does not exist
af-silva commented 4 years ago

Hi @Rokmonkey ,

It must not be from reading the EDS, as they don't show up anywhere.

It seems you are reading the configuration from the driver itself and not from the EDS DCF file, self.pdo.read() # reads the new configuration from the driver.

And I don't think your problem is related to the TPDO's and RDPO's configuration .... I think you are having problem when uploading the configuration to the driver return self.sdo_node.upload(self.od.index, self.od.subindex), so if you can please check what is happening when this is being fired, and see what is passing in the canbus network.

Double check if you are tying to read the configuration from the driver? (if you do not pass the OD it will try to read from the remote note it's connecting to)

nhayes-me commented 4 years ago

Ahh, perhaps that's it. However, that self.pdo.read() happens automatically when creating a node with BaseNode402, there isn't anything I can do with the library as is. I am passing a DCF/EDS file. Is that a specific object dictionary that needs to be created first?

What is the proper way to read the PDO's from a DCF?

af-silva commented 4 years ago

Hi @Rokmonkey,

The pdo.read() from the driver should only happen if you don't provide a ObjectDictionary, if you provide the OD then the code will try to send it to the driver and then read it to make sure the configurations have been set on the driver (configuration of the remote nodes). Try the below code, if this not resolve your issue try to sniff the canbus network to see what is being sent and what is causing the return of the Object does not exist error, namely which Object is returning this.

vnode = VNode("10", "path_to_eds")
self.network.add_node(vnode)
vnode.nmt.state = 'RESET COMMUNICATION'  # Reset network
vnode .load_configuration

or, in the signature of the class instance constructor you have the flag to load the configuration (by default is false) def __init__(self, node_id, object_dictionary, load_od=False): so:

node = BaseNode402("10", "path_to_eds", true)
af-silva commented 4 years ago

Hi @Rokmonkey, did you manage to solve the problem? Can I close this ticket?

friederschueler commented 4 months ago

Closing for inactivity.