Programmatic getattr() and setattr() use

I’m trying to clean up the hacky way I’ve been using odrives for the last few years, and wanting to be able to read and set parameter values to an odrive object that is within a class definition. It seems possible (google makes me think it likely is) but I can’t read anything from within the “.axis0” chunk of the odrive object.

Here’s my code (the pertinent parts):

import odrive
from odrive.utils import *
from odrive.enums import *
...
class OdriveTester:
    def __init__(self, sn=None, drive_name='odrive', watchdog_per_s=0.5):
        # configuration
        self.drive_sn = sn
        # odrive object-related
        self._drive = None
        self._axis = None
        self.watchdog_period_s = watchdog_per_s
        self.pos = None
        self.w_vel = None
        self.w_v_lim = None
        self.w_t_est = None
        self.w_t_eff = None
      # self.i_lim_tq = None

        self.odrive_err = None
        self.w_kt = 0

        self.err = None
        self.drives_err_report = []


        self.simple_find_odrive()
        print(f'vbus_voltage: {self.get_axis_param("vbus_voltage")}')
        print(f'position: {self.get_axis_param("axis0.pos_estimate")}')

    # Odrive functions
    def simple_find_odrive(self):
        self._drive = odrive.find_any(serial_number=self.drive_sn, timeout=1)
        return self._drive 
    

    def get_axis_param(self, param_name): 
        # Get a parameter from the Odrive
        return getattr(self._drive, param_name)

I get the following output:

vbus_voltage: 47.965179443359375
Traceback (most recent call last):
File “/home/pi/Desktop/Code/odrive_tkf.py”, line 304, in
cam = OdriveTester(sn=‘345D366A3330’, drive_name=‘cam_drive’) # lookup the SN with odrivetool when the odrive is connected
File “/home/pi/Desktop/Code/odrive_tkf.py”, line 36, in init
print(f’position: {self.get_axis_param(“axis0.pos_estimate”)}')
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File “/home/pi/Desktop/Code/odrive_tkf.py”, line 57, in get_axis_param
return getattr(self._drive, param_name)
AttributeError: ‘anonymous_interface’ object has no attribute ‘axis0.pos_estimate’

The call to read odvr0.vbus_voltage works fine, but not the call to read odrv0.axis0.pos_estimate. If I switch it to just get_axis_param(“axis0”) I can get the whole axis0 object, and I suppose I could parse it locally, but that seems really unwieldy, especially at the next step when I want to set a specific parameter.

Is what I’m after actually possible?

I think you’d have to split the string on the ‘.’ and continue to traverse into the object with further getattr calls. I’m curious though, why do you want to be able to resolve the flattened parameter strings (e.g. “axis0.pos_estimate”) instead of just calling it directly (e.g. class_instance._drive.axis0.pos_estimate)?

well … that’s embarassing! I had tried the direct read from outside the class definition, and got an error. So I figured that wasn’t a viable path and I locked in on getting the getattr() and setattr() methods to work. But I must have had something else wacky, because now the direct read (and write) work fine :).

Thanks for setting me straight.

No worries!! Please let me know if there’s any other way I can help :slight_smile: