Homepage GitHub

How can I reconfig node_ID & iface after make_node()

My code looks like below, it doesn’t work.

os.environ['UAVCAN__NODE__ID'] = '108'

self.node = pyuavcan.application.make_node(info=self.node_info,
                                                   registry="registers.db",
                                                   reconfigurable_transport=True)

self.node.registry["uavcan.node.id"] = 88
self.node.start()

I don’t recommend hard-coding any parameters like you did because it makes your code essentially non-reusable and is prone to causing conflicts on the network. The reason that node configuration is sourced from environment variables is to avoid the need to modify software when integrating it into an existing network. What you certainly shouldn’t do is change the environment variables as you do via os.environ, that doesn’t make sense unless you intend to pass them over to child processes.

If you absolutely must change the node parameters in your application, the correct solution would be to instantiate a registry first using make_registry(), assign the required register values there, and then pass the registry over to make_node():

# The "register_file" is an optional argument -- registers will not persist if not provided.
# You can provide env={} to ignore environment variables, if any.
registry = pyuavcan.application.make_registry(register_file="registers.db")
# The following will override the respective environment variables if there are any.
registry["uavcan.node.id"] = 42
registry["uavcan.can.iface"] = "socketcan:can0"
registry["uavcan.can.bitrate"] = 1000000, 4000000  # (data, arbitration)
registry["uavcan.can.mtu"] = 32  # whatever
# Create a new node using the above register values.
node = pyuavcan.application.make_node(info=node_info, registry=registry)

Another important thing is that the node-ID is not expected to be changed while the node is running. There may exist odd cases where this is really necessary but whenever you do that you should really ask yourself if you are perhaps doing something weird. If you insist that the node-ID has to be changed, then you will need to reconfigure the transport manually (because the node-ID is a transport-layer property).

make_node() with reconfigurable_transport=True returns a node object whose transport is an instance of pyuavcan.transport.redundant.RedundantTransport. Said transport allows you to add and remove transport instances (they are called “inferiors”) at runtime, which you can leverage to change the node-ID. You simply remove your existing inferiors, then create a new transport instance with the desired node-ID, and register it as a new inferior.

# Initialize and start the node normally.
self.node = pyuavcan.application.make_node(info=self.node_info,
                                           registry="registers.db",
                                           reconfigurable_transport=True)
self.node.start()

# Then, if the node-ID has to be changed at any later point,
# the transport has to be reinitialized.
tr = self.node.presentation.transport
assert isinstance(tr, pyuavcan.transport.redundant.RedundantTransport), "Not reconfigurable"
while tr.inferiors:
    tr.detach_inferior(tr.inferiors[0])  # Detach all existing inferiors.
# The node remains running and configured, but is not connected to any transport.
my_new_transport = pyuavcan.transport..... # Construct your new transport (not shown).
tr.attach_inferior(my_new_transport)  # Link your existing node with the new transport.
1 Like

Instead of constructing the transport manually, you can also create a new registry and then pass it over to pyuavcan.application.make_transport():

registry = pyuavcan.application.make_registry()
registry["uavcan.node.id"] = 42
registry["uavcan.can.iface"] = "socketcan:can0"
registry["uavcan.can.bitrate"] = 1000000, 4000000  # (data, arbitration)
registry["uavcan.can.mtu"] = 32  # whatever
my_can_transport = pyuavcan.application.make_transport(registry)

Once constructed, your transport can be either added to an existing node using attach_inferior() as shown above, or you can construct an entirely new node with it:

my_node = pyuavcan.application.make_node(info=node_info, transport=my_can_transport)

Keep in mind that none of the presented examples are related to the normal usage of the library.