From 3bce8015be0db11bbfc3a8c75c2fb10794089ea7 Mon Sep 17 00:00:00 2001 From: rbudai Date: Mon, 21 Oct 2024 10:23:50 +0300 Subject: [PATCH] Add support for adis1550 and adis16550w Signed-off-by: rbudai --- adi/__init__.py | 1 + adi/adis16550.py | 464 ++++++++++++++++++++++++++++++++++ examples/adis16550_example.py | 63 +++++ 3 files changed, 528 insertions(+) create mode 100644 adi/adis16550.py create mode 100644 examples/adis16550_example.py diff --git a/adi/__init__.py b/adi/__init__.py index bf1f21657..57dfd9ce8 100644 --- a/adi/__init__.py +++ b/adi/__init__.py @@ -73,6 +73,7 @@ adis16547, ) from adi.adis16507 import adis16507 +from adi.adis16550 import adis16550 from adi.adl5240 import adl5240 from adi.adl5960 import adl5960 from adi.admv8818 import admv8818 diff --git a/adi/adis16550.py b/adi/adis16550.py new file mode 100644 index 000000000..96fb7e75b --- /dev/null +++ b/adi/adis16550.py @@ -0,0 +1,464 @@ +# Copyright (C) 2019-2024 Analog Devices, Inc. +# +# SPDX short identifier: ADIBSD + +from abc import ABC, abstractmethod + +from adi.attribute import attribute +from adi.context_manager import context_manager +from adi.rx_tx import rx + + +class adis16550(rx, context_manager, ABC): + + _complex_data = False + + _rx_channel_names = [ + "anglvel_x", + "anglvel_y", + "anglvel_z", + "accel_x", + "accel_y", + "accel_z", + "temp0", + ] + + _device_name = "" + + """Disable mapping of trigger to RX device.""" + disable_trigger = False + + # @property + @abstractmethod + def compatible_parts(self): + raise NotImplementedError + + def __init__(self, uri="", device_name=None, trigger_name=None): + context_manager.__init__(self, uri, self._device_name) + + if not device_name: + device_name = self.compatible_parts[0] + + if device_name not in self.compatible_parts: + raise Exception( + "Not a compatible device:" + + str(device_name) + + ".Please select from:" + + str(self.compatible_parts) + ) + else: + self._ctrl = self._ctx.find_device(device_name) + self._rxadc = self._ctx.find_device(device_name) + if not trigger_name: + trigger_name = device_name + "-dev0" + + if self._ctrl is None: + print( + "No device found with device_name = " + + device_name + + ". Searching for a device found in the compatible list." + ) + for i in self.compatible_parts: + self._ctrl = self._ctx.find_device(i) + self._rxadc = self._ctx.find_device(i) + if self._ctrl is not None: + print("Fond device = " + i + ". Will use this device instead.") + break + if self._ctrl is None: + raise Exception("No compatible device found") + + self.anglvel_x = self._anglvel_accel_channels(self._ctrl, "anglvel_x") + self.anglvel_y = self._anglvel_accel_channels(self._ctrl, "anglvel_y") + self.anglvel_z = self._anglvel_accel_channels(self._ctrl, "anglvel_z") + self.accel_x = self._anglvel_accel_channels(self._ctrl, "accel_x") + self.accel_y = self._anglvel_accel_channels(self._ctrl, "accel_y") + self.accel_z = self._anglvel_accel_channels(self._ctrl, "accel_z") + self.temp = self._temp_channel(self._ctrl, "temp0") + self.deltaangl_x = self._delta_channels(self._ctrl, "deltaangl_x") + self.deltaangl_y = self._delta_channels(self._ctrl, "deltaangl_y") + self.deltaangl_z = self._delta_channels(self._ctrl, "deltaangl_z") + self.deltavelocity_x = self._delta_channels(self._ctrl, "deltavelocity_x") + self.deltavelocity_y = self._delta_channels(self._ctrl, "deltavelocity_y") + self.deltavelocity_z = self._delta_channels(self._ctrl, "deltavelocity_z") + + # Set default trigger + if not self.disable_trigger: + self._trigger = self._ctx.find_device(trigger_name) + self._rxadc._set_trigger(self._trigger) + + rx.__init__(self) + self.rx_buffer_size = 16 # Make default buffer smaller + + def __get_scaled_sensor(self, channel_name: str) -> float: + raw = self._get_iio_attr(channel_name, "raw", False) + scale = self._get_iio_attr(channel_name, "scale", False) + + return raw * scale + + def __get_scaled_sensor_temp(self, channel_name: str) -> float: + raw = self._get_iio_attr(channel_name, "raw", False) + scale = self._get_iio_attr(channel_name, "scale", False) + offset = self._get_iio_attr(channel_name, "offset", False) + + return (raw + offset) * scale + + def get_anglvel_x(self): + """Value returned in radians per second.""" + return self.__get_scaled_sensor("anglvel_x") + + anglvel_x_conv = property(get_anglvel_x, None) + + def get_anglvel_y(self): + """Value returned in radians per second.""" + return self.__get_scaled_sensor("anglvel_y") + + anglvel_y_conv = property(get_anglvel_y, None) + + def get_anglvel_z(self): + """Value returned in radians per second.""" + return self.__get_scaled_sensor("anglvel_z") + + anglvel_z_conv = property(get_anglvel_z, None) + + def get_accel_x(self): + """Value returned in meters per squared second.""" + return self.__get_scaled_sensor("accel_x") + + accel_x_conv = property(get_accel_x, None) + + def get_accel_y(self): + """Value returned in meters per squared second.""" + return self.__get_scaled_sensor("accel_y") + + accel_y_conv = property(get_accel_y, None) + + def get_accel_z(self): + """Value returned in meters per squared second.""" + return self.__get_scaled_sensor("accel_z") + + accel_z_conv = property(get_accel_z, None) + + def get_temp(self): + """Value returned in millidegrees Celsius.""" + return self.__get_scaled_sensor_temp("temp0") + + temp_conv = property(get_temp, None) + + def get_deltaangl_x(self): + """Value returned in radians.""" + return self.__get_scaled_sensor("deltaangl_x") + + deltaangl_x_conv = property(get_deltaangl_x, None) + + def get_deltaangl_y(self): + """Value returned in radians.""" + return self.__get_scaled_sensor("deltaangl_y") + + deltaangl_y_conv = property(get_deltaangl_y, None) + + def get_deltaangl_z(self): + """Value returned in radians.""" + return self.__get_scaled_sensor("deltaangl_z") + + deltaangl_z_conv = property(get_deltaangl_z, None) + + def get_deltavelocity_x(self): + """Value returned in meters per second.""" + return self.__get_scaled_sensor("deltavelocity_x") + + deltavelocity_x_conv = property(get_deltavelocity_x, None) + + def get_deltavelocity_y(self): + """Value returned in meters per second.""" + return self.__get_scaled_sensor("deltavelocity_y") + + deltavelocity_y_conv = property(get_deltavelocity_y, None) + + def get_deltavelocity_z(self): + """Value returned in meters per second.""" + return self.__get_scaled_sensor("deltavelocity_z") + + deltavelocity_z_conv = property(get_deltavelocity_z, None) + + @property + def sample_rate(self): + """sample_rate: Sample rate in samples per second""" + return self._get_iio_dev_attr("sampling_frequency") + + @sample_rate.setter + def sample_rate(self, value): + self._set_iio_dev_attr_str("sampling_frequency", value) + + @property + def current_timestamp_clock(self): + """current_timestamp_clock: Source clock for timestamps""" + return self._get_iio_dev_attr("current_timestamp_clock") + + @current_timestamp_clock.setter + def current_timestamp_clock(self, value): + self._set_iio_dev_attr_str("current_timestamp_clock", value) + + @property + def anglvel_x_calibbias(self): + """User calibration offset for gyroscope for the x-axis.""" + return self._get_iio_attr("anglvel_x", "calibbias", False) + + @anglvel_x_calibbias.setter + def anglvel_x_calibbias(self, value): + self._set_iio_attr("anglvel_x", "calibbias", False, value) + + @property + def anglvel_y_calibbias(self): + """User calibration offset for gyroscope for the y-axis.""" + return self._get_iio_attr("anglvel_y", "calibbias", False) + + @anglvel_y_calibbias.setter + def anglvel_y_calibbias(self, value): + self._set_iio_attr("anglvel_y", "calibbias", False, value) + + @property + def anglvel_z_calibbias(self): + """User calibration offset for gyroscope for the z-axis.""" + return self._get_iio_attr("anglvel_z", "calibbias", False) + + @anglvel_z_calibbias.setter + def anglvel_z_calibbias(self, value): + self._set_iio_attr("anglvel_z", "calibbias", False, value) + + @property + def accel_x_calibbias(self): + """User calibration offset for accelerometer for the x-axis.""" + return self._get_iio_attr("accel_x", "calibbias", False) + + @accel_x_calibbias.setter + def accel_x_calibbias(self, value): + self._set_iio_attr("accel_x", "calibbias", False, value) + + @property + def accel_y_calibbias(self): + """User calibration offset for accelerometer for the y-axis.""" + return self._get_iio_attr("accel_y", "calibbias", False) + + @accel_y_calibbias.setter + def accel_y_calibbias(self, value): + self._set_iio_attr("accel_y", "calibbias", False, value) + + @property + def accel_z_calibbias(self): + """User calibration offset for accelerometer for the z-axis.""" + return self._get_iio_attr("accel_z", "calibbias", False) + + @accel_z_calibbias.setter + def accel_z_calibbias(self, value): + self._set_iio_attr("accel_z", "calibbias", False, value) + + @property + def anglvel_x_calibscale(self): + """Calibscale value for gyroscope for the x-axis.""" + return self._get_iio_attr("anglvel_x", "calibscale", False) + + @anglvel_x_calibscale.setter + def anglvel_x_calibscale(self, value): + self._set_iio_attr("anglvel_x", "calibscale", False, value) + + @property + def anglvel_y_calibscale(self): + """Calibscale value for gyroscope for the y-axis.""" + return self._get_iio_attr("anglvel_y", "calibscale", False) + + @anglvel_y_calibscale.setter + def anglvel_y_calibscale(self, value): + self._set_iio_attr("anglvel_y", "calibscale", False, value) + + @property + def anglvel_z_calibscale(self): + """Calibscale value for gyroscope for the z-axis.""" + return self._get_iio_attr("anglvel_z", "calibscale", False) + + @anglvel_z_calibscale.setter + def anglvel_z_calibscale(self, value): + self._set_iio_attr("anglvel_z", "calibscale", False, value) + + @property + def accel_x_calibscale(self): + """Calibscale value for accelerometer for the x-axis.""" + return self._get_iio_attr("accel_x", "calibscale", False) + + @accel_x_calibscale.setter + def accel_x_calibscale(self, value): + self._set_iio_attr("accel_x", "calibscale", False, value) + + @property + def accel_y_calibscale(self): + """Calibcale value for accelerometer for the y-axis.""" + return self._get_iio_attr("accel_y", "calibscale", False) + + @accel_y_calibscale.setter + def accel_y_calibscale(self, value): + self._set_iio_attr("accel_y", "calibscale", False, value) + + @property + def accel_z_calibscale(self): + """Calibscale for accelerometer for the z-axis.""" + return self._get_iio_attr("accel_z", "calibscale", False) + + @accel_z_calibscale.setter + def accel_z_calibscale(self, value): + self._set_iio_attr("accel_z", "calibscale", False, value) + + @property + def anglvel_x_filter_low_pass_3db_frequency(self): + """Bandwidth for gyroscope for the x-axis.""" + return self._get_iio_attr("anglvel_x", "filter_low_pass_3db_frequency", False) + + @anglvel_x_filter_low_pass_3db_frequency.setter + def anglvel_x_filter_low_pass_3db_frequency(self, value): + self._set_iio_attr("anglvel_x", "filter_low_pass_3db_frequency", False, value) + + @property + def anglvel_y_filter_low_pass_3db_frequency(self): + """Bandwidth for gyroscope for the y-axis.""" + return self._get_iio_attr("anglvel_y", "filter_low_pass_3db_frequency", False) + + @anglvel_y_filter_low_pass_3db_frequency.setter + def anglvel_y_filter_low_pass_3db_frequency(self, value): + self._set_iio_attr("anglvel_y", "filter_low_pass_3db_frequency", False, value) + + @property + def anglvel_z_filter_low_pass_3db_frequency(self): + """Bandwidth for gyroscope for the z-axis.""" + return self._get_iio_attr("anglvel_z", "filter_low_pass_3db_frequency", False) + + @anglvel_z_filter_low_pass_3db_frequency.setter + def anglvel_z_filter_low_pass_3db_frequency(self, value): + self._set_iio_attr("anglvel_z", "filter_low_pass_3db_frequency", False, value) + + @property + def accel_x_filter_low_pass_3db_frequency(self): + """Bandwidth for accelerometer for the x-axis.""" + return self._get_iio_attr("accel_x", "filter_low_pass_3db_frequency", False) + + @accel_x_filter_low_pass_3db_frequency.setter + def accel_x_filter_low_pass_3db_frequency(self, value): + self._set_iio_attr("accel_x", "filter_low_pass_3db_frequency", False, value) + + @property + def accel_y_filter_low_pass_3db_frequency(self): + """Bandwidth for accelerometer for the y-axis.""" + return self._get_iio_attr("accel_y", "filter_low_pass_3db_frequency", False) + + @accel_y_filter_low_pass_3db_frequency.setter + def accel_y_filter_low_pass_3db_frequency(self, value): + self._set_iio_attr("accel_y", "filter_low_pass_3db_frequency", False, value) + + @property + def accel_z_filter_low_pass_3db_frequency(self): + """Bandwidth for accelerometer for the z-axis.""" + return self._get_iio_attr("accel_z", "filter_low_pass_3db_frequency", False) + + @accel_z_filter_low_pass_3db_frequency.setter + def accel_z_filter_low_pass_3db_frequency(self, value): + self._set_iio_attr("accel_z", "filter_low_pass_3db_frequency", False, value) + + class _temp_channel(attribute): + """ADIS16550 temperature channel.""" + + def __init__(self, ctrl, channel_name): + self.name = channel_name + self._ctrl = ctrl + + @property + def raw(self): + """ADIS16550 raw value""" + return self._get_iio_attr(self.name, "raw", False) + + @property + def scale(self): + """ADIS16550 scale value""" + return self._get_iio_attr(self.name, "scale", False) + + @property + def offset(self): + """ADIS16550 offset value""" + return self._get_iio_attr(self.name, "offset", False) + + class _simple_channel(attribute): + """ADIS16550 basic channel, only scale an raw values""" + + def __init__(self, ctrl, channel_name): + self.name = channel_name + self._ctrl = ctrl + + @property + def raw(self): + """ADIS16550 raw value""" + return self._get_iio_attr(self.name, "raw", False) + + @property + def scale(self): + """ADIS16550 scale value""" + return self._get_iio_attr(self.name, "scale", False) + + class _extended_channel(_simple_channel): + """ADIS16550 pressure channel.""" + + def __init__(self, ctrl, channel_name): + self.name = channel_name + self._ctrl = ctrl + + @property + def calibbias(self): + """ADIS16550 calibration offset""" + return self._get_iio_attr(self.name, "calibbias", False) + + @calibbias.setter + def calibbias(self, value): + self._set_iio_attr(self.name, "calibbias", False, value) + + @property + def calibscale(self): + """ADIS16550 calibration scale""" + return self._get_iio_attr(self.name, "calibscale", False) + + @calibscale.setter + def calibscale(self, value): + self._set_iio_attr(self.name, "calibscale", False, value) + + @property + def filter_low_pass_3db_frequency(self): + """ADIS16550 channel bandwidth""" + return self._get_iio_attr(self.name, "filter_low_pass_3db_frequency", False) + + @filter_low_pass_3db_frequency.setter + def filter_low_pass_3db_frequency(self, value): + self._set_iio_attr(self.name, "filter_low_pass_3db_frequency", False, value) + + class _anglvel_accel_channels(_extended_channel): + """ADIS16550 gyro and accelerometer channels.""" + + def __init__(self, ctrl, channel_name): + self.name = channel_name + self._ctrl = ctrl + + class _delta_channels(_simple_channel): + """ADIS16550 delta angle and delta velocity channels.""" + + def __init__(self, ctrl, channel_name): + self.name = channel_name + self._ctrl = ctrl + + +class adis16550(adis16550): + """ADIS1655X Six Degrees of Freedom Inertial Sensor + + This class is compatible with the following parts: + - ADIS16550 + - ADIS16550W + + Args: + uri: URI of IIO context with ADIS16550 device + device_name: Name of the device in the IIO context. Default is adis16550 + trigger_name: Name of the trigger in the IIO context. Default is adis16550-dev0 + """ + + compatible_parts = ["adis16550", "adis16550w"] diff --git a/examples/adis16550_example.py b/examples/adis16550_example.py new file mode 100644 index 000000000..0aaf3541d --- /dev/null +++ b/examples/adis16550_example.py @@ -0,0 +1,63 @@ +# Copyright (C) 2024 Analog Devices, Inc. +# +# SPDX short identifier: ADIBSD +import sys + +import adi +import matplotlib.pyplot as plt + +# Set up ADIS16550 +my_dev_name = sys.argv[1] +my_uri = sys.argv[2] + +dev = adi.adis16550(device_name=my_dev_name, uri=my_uri) + +dev.rx_output_type = "raw" +dev.rx_enabled_channels = [0, 1, 2, 3, 4, 5] +dev.sample_rate = 10 +dev.rx_buffer_size = 10 + +print("Product id: " + str(dev.product_id)) +print("Serial number: " + dev.serial_number) +print("Firmware revision: " + dev.firmware_revision) +print("Firmware date: " + dev.firmware_date) + +print("\nX acceleration: " + str(dev.accel_x_conv) + " m/s^2") +print("Y acceleration: " + str(dev.accel_y_conv) + " m/s^2") +print("Z acceleration: " + str(dev.accel_z_conv) + " m/s^2") + +print("\nX angular velocity: " + str(dev.anglvel_x_conv) + " rad/s") +print("Y angular velocity: " + str(dev.anglvel_y_conv) + " rad/s") +print("Z angular velocity: " + str(dev.anglvel_z_conv) + " rad/s") + +print("\nX delta velocity: " + str(dev.deltavelocity_x_conv) + " m/s") +print("Y delta velocity: " + str(dev.deltavelocity_y_conv) + " m/s") +print("Z delta velocity: " + str(dev.deltavelocity_z_conv) + " m/s") + +print("\nX delta angle: " + str(dev.deltaangl_x_conv) + " rad") +print("Y delta angle: " + str(dev.deltaangl_y_conv) + " rad") +print("Z delta angle: " + str(dev.deltaangl_z_conv) + " rad") + +dev.sample_rate = 2000 +dev.magn_x_filter_low_pass_3db_frequency = 100 +dev.anglvel_y_calibscale = 30 +dev.anglvel_x_calibbias = 100 + +print("\nSampling frequency: " + str(dev.sample_rate)) + +print("Temperature raw value: " + str(dev.temp.raw)) +print("Temperature scale value: " + str(dev.temp.scale)) +print("Temperature offset value: " + str(dev.temp.offset)) + +print("X-axis gyro channel calibbias value: " + str(dev.anglvel_x_calibbias)) +print("X-axis gyro channel calibscale value: " + str(dev.anglvel_y_calibscale)) +print("X-axis magnetometer bandwidth: " + str(dev.magn_x_filter_low_pass_3db_frequency)) + +for _ in range(100): + data = dev.rx() + plt.clf() + for i, d in enumerate(data): + plt.plot(d, label=dev._rx_channel_names[dev.rx_enabled_channels[i]]) + plt.legend() + plt.show(block=False) + plt.pause(0.1)