Repository navigation
Description
The example uses the RemoteNode.load_configuration() API to send ParameterValue settings given in the sample EDS file to the device. This used to work in conjunction with PdoBase.read() to synchronize the locally cached PDO configuration and mapping info. Calling that method (on any PDO) was therefore not really necessary, as it was implied as a final step in load_configuration().
But #427 changed this and made load_configuration() apply the PDO configuration through calls to PdoBase.save() instead. Thus the need to read it back was eliminated.
In any case, the example goes on to call BaseNode402.setup_402_state_machine(), which then reads back the PDO configuration again. Here it would help to pass read_pdos=False since we know that the configuration was just saved, skipping the unnecessary upload.
That convenience method also checks whether needed values like the status and control words are configured in the respective PDOs. Which should succeed because of the initialization values in the sample EDS (haven't tested).
But then the example code continues with re-mapping the PDOs, which (probably?) invalidates the rpdo_pointers and tpdo_pointers entries pointing at the previous PDO mapping's PdoVariable objects. This should be done before setup_402_state_machine() to avoid this error. In addition, the example first uses node.tpdo.read() and node.rpdo.read() before adjusting the mappings, which, again, is unnecessary after load_configuration().
Furthermore, before the PDO re-mapping, it tries to change the node.state attribute, but there is no prior change of node.nmt.state = 'OPERATIONAL', thus the exchanges of control and status words cannot work. There is a fallback to SDO implemented if no PDO maps the required objects, but that is not triggered because they are in fact mapped. The problem is that in PRE-OPERATIONAL state, the node's PDOs simply do not function. Re-mapping them after the previous PdoVariable objects have been cached (see above) doesn't make this any better.
These are some observations from trying to understand the sample code, showing that it is mostly broken for actual usage and suggests wrong or inefficient patterns of the library API usage. There may be more problems hidden, which could be revealed after testing with actual hardware. Maybe that was done at some point, but probably not after the library API has evolved and some functionality (especially regarding profile CiA402) moved around.
We should discuss how to make this example actually useful again, or at the very minimum, document that it serves only as a demonstration of the API and will not work with real hardware unless the user takes care of the issues with their hopefully firm CANopen background themselves.
Activity
erlend-aasland commentedon Jul 5, 2024
FWIW, I think it would make sense to convert it to a full-fledged tutorial, alternatively a more concise how-to.
sveinse commentedon Jul 6, 2024
The way a user needs to setup any node is highly dependent on the node capabilities.
.load_configuration().pdo.read(from_od=True))..pdo.read(from_od=False)).I think the examples should highlight these three use cases
erlend-aasland commentedon Jul 6, 2024
This sounds like a series of How-to guides to me.
romainreignier commentedon Oct 2, 2024
I wanted to try the 402 example and faced the same issue. Do you guys have a working example for 402?
acolomb commentedon Oct 2, 2024
Sorry, nobody has taken the time to revamp this example yet. I do not have any off-the-shelf working script for CiA 402 operation.
My advice currently is to understand the spec, figure out what configuration you actually want to achieve and then pick out the API calls necessary to achieve that. It should be rather simple with the convenience methods provided, but you probably need to figure out a sensible PDO mapping first. Or see what the device manufacturer has as a default mapping, that usually works quite well if the device advertises 402 compliance.
Of course I understand that a ready-to-run generic example will be helpful as a starting point. Maybe you can come up with such a simple script after figuring it out for yourself? Then we could integrate that here. It's always better to write "beginner's" documentation after actually working with someone less experienced. If I were to write a beginner's tutorial, I'd need to pretend not knowing what I do know, which often misses the goal.
romainreignier commentedon Oct 2, 2024
Thank you for your reply.
I have managed to make my motor move with the base
canopen.RemoteNodeand writing to the ControlWord0x6040.When I try to use the example, I keep having this log:
I have tried to both modify the EDS to set the mapping and set the mapping in the code for the warning is still here.
I the code, I have written this, following the PDO documentation:
Does this look ok for you?
acolomb commentedon Oct 2, 2024
Shouldn't the
Modes of operationobject be mapped to an RPDO? Better to use numeric references here, as we don't know what your EDS files names each parameter. If you are in fact not calling any code related to RPDO, then those will have your device's default mappings. Check and see what those are as well.In general, you need to call the
setup_402_state_machine()method after configuring and saving you PDO mappings. If you've saved them via the code above (and not just store the config in the device's persistent memory), then you can passread_pdos=Falseto that method, to skip reading back (uploading) everything you just happened to save (download).Heideachim commentedon Jun 24, 2025
Thanks guys for your comment within this thread - without them I never would gotten my 402 running.
What helped my was checking my PDO configuration:
But then, also check if the library has digested all of your efforts:
The output should contain the same objects as your PDO listing!
As stated above,
setup_402_state_machine()must be called after you made you configuration, otherwise it will fail.Heideachim commentedon Jun 24, 2025
Another beast was to turn the drive on: For me, the wonderful
node.state = 'READY TO SWITCH ONsimply did not work. It did not send anything and after a timeout aborted with an exception.So here is how I managed to use the PDOs I configured. It's the example project, modified for a drive that uses variable PDO mapping. I mapped everything into TxPDO4 and RxPDO4.
The SYNC impulse from the master lets the drive send every 10ms its TxPDOs. In this case, it is only one PDO, TxPDO4.
When setting variables, I do this manually. First, assign one value or more, then send the RxPDO. Then, it is neccessary to wait until the drive has processed your RxPDO with the next SYNC impulse. You know this has happend, when you received your TxPDO from the drive. ecause then, it just has received a SYNC impulse and also must have processed your RxPDO.
(Yes, there is a race condition here: If the RxPDO is sent just after a SYNC, the slave will send its TxPDO response, but will not have processed the RxPDO. Until now, I did not notice this. If you want to be sure, insert
network.sync.transmit()bevore eachwait_for_reception).acolomb commentedon Jun 24, 2025
Your alternative approach of manually sending RxPDOs and waiting for TxPDOs in between is ... uncommon. PDOs are for cyclic exchange of process data. You must subscribe to the TxPDO (happens during
.save()or.read(), or manually via.subscribe()) so the state machine is updated when a new PDO frame arrives. That automatically happens with the call tosetup_402_state_machine()though.The RxPDO for the drive is usually sent in a cycle as well, by calling
.start()on it. Just as you do with the cyclic SYNC. If you don't start it before setting up the state machine, you must at least set its.periodattribute, so the machinery recognizes that it needs not be transmitted manually with each change. That can also be the case when you have some other loop or cycle running which schedules the cyclic transmission.Once you have that set up, you can use the
.stateand.op_modeproperties regularly. They do wait for confirmation through the cyclic PDOs before returning from the setter functions. Other changes like setting a new speed target value can be done by simply modifying the PDO content, without manually dealing with transmission.Hope that makes it clearer. Happy to see more of your testing code, but maybe better in a new discussion, not in this issue.