From 9c55fd0edae67adb5795476a5ffb1b2a41bd89b0 Mon Sep 17 00:00:00 2001 From: Florian Rohrer Date: Sat, 14 Dec 2024 17:11:30 +0100 Subject: [PATCH] docs --- README.md | 4 +-- docs/source/conf.py | 4 +-- docs/source/index.rst | 10 ++++---- examples/edu/ADXL345.py | 4 +-- examples/edu/L3GD20H.py | 4 +-- examples/edu/all_sensors.py | 4 +-- pyproject.toml | 2 +- src/sts1_sensors/edu/ADXL345.py | 10 +++++++- src/sts1_sensors/edu/BME688.py | 43 ++++++++++++++++++++++++++++++--- src/sts1_sensors/edu/BMM150.py | 25 +++++++++++++++++-- src/sts1_sensors/edu/L3GD20H.py | 21 ++++++++++++++-- src/sts1_sensors/edu/TMP112.py | 7 ++++++ src/sts1_sensors/utils/utils.py | 6 +++++ tests/test_L3GD20H.py | 4 +-- 14 files changed, 121 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index a53d737..a4d48a5 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,8 @@ print(f"Heading: {mag.get_heading():.2f}°") # Gyroscope gyro = L3GD20H() -x, y, z = gyro.get_position() -print(f"{x=:.2f} dpfs, {y=:.2f} dpfs, {z=:.2f} dpfs") +x, y, z = gyro.get_dps() +print(f"{x=:.2f} dps, {y=:.2f} dps, {z=:.2f} dps") # Temperature sensor temp = TMP112() diff --git a/docs/source/conf.py b/docs/source/conf.py index 7280827..485a824 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -13,7 +13,7 @@ project = 'sts1-sensors' copyright = '2024, Simon Köfinger, Florian Rohrer' author = 'Simon Köfinger, Florian Rohrer' -release = 'v0.4.0' +release = 'v0.4.1' # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration @@ -53,7 +53,7 @@ def skip_member_variables(app, what, name, obj, skip, options): if what == "attribute": skip = True - elif what == "module" and "Abstract" in name: + elif what == "module" and "Abstract" in name or "PatchedSMBus" in name: skip = True return skip diff --git a/docs/source/index.rst b/docs/source/index.rst index efcf59b..8fb5cd5 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,12 +3,12 @@ Main -.. toctree:: - :hidden: - :maxdepth: 2 - :caption: Contents +.. .. toctree:: +.. :hidden: +.. :maxdepth: 2 +.. :caption: Contents - ADXL345 +.. ADXL345 .. include:: ../../README.md :parser: myst_parser.sphinx_ diff --git a/examples/edu/ADXL345.py b/examples/edu/ADXL345.py index d5b8305..047d08d 100644 --- a/examples/edu/ADXL345.py +++ b/examples/edu/ADXL345.py @@ -10,5 +10,5 @@ while True: x, y, z = accel.get_g() - log.info(f"X: {x:.2f}g, Y: {y:.2f}g, Z: {z:.2f}g") - time.sleep(.2) + log.info(f"{x=:.2f} g, {y=:.2f} g, {z=:.2f} g") + time.sleep(.2) \ No newline at end of file diff --git a/examples/edu/L3GD20H.py b/examples/edu/L3GD20H.py index dfca814..2e30c47 100644 --- a/examples/edu/L3GD20H.py +++ b/examples/edu/L3GD20H.py @@ -7,6 +7,6 @@ gyro = L3GD20H(range=245, datarate=12.5) while True: - x, y, z = gyro.get_position() - log.info(f"X: {x:.2f}dpfs, Y: {y:.2f}dpfs, Z: {z:.2f}dpfs") + x, y, z = gyro.get_dps() + log.info(f"X: {x:.2f}dps, Y: {y:.2f}dps, Z: {z:.2f}dps") time.sleep(.25) diff --git a/examples/edu/all_sensors.py b/examples/edu/all_sensors.py index a5416c3..5b91ecc 100644 --- a/examples/edu/all_sensors.py +++ b/examples/edu/all_sensors.py @@ -19,8 +19,8 @@ s += f", {mx=:.2f} µT, {my=:.2f} µT, {mz=:.2f} µT" s += f", Heading: {mag.get_heading():.2f}°" - px, py, pz = gyro.get_position() - s += f", {px=:.2f} dpfs, {py=:.2f} dpfs, {pz=:.2f} dpfs" + px, py, pz = gyro.get_dps() + s += f", {px=:.2f} dps, {py=:.2f} dps, {pz=:.2f} dps" t1 = temp.get_temp() s += f", temp1 {t1:.2f} °C" diff --git a/pyproject.toml b/pyproject.toml index c30c5cb..234e27e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "sts1_sensors" -version = "0.4.0" +version = "0.4.1" description = "A sensor library for the CubeSat STS1 (TU Wien Space Team)." readme = "README.md" requires-python = ">=3.11,<3.12" diff --git a/src/sts1_sensors/edu/ADXL345.py b/src/sts1_sensors/edu/ADXL345.py index 4606c2e..05fda95 100644 --- a/src/sts1_sensors/edu/ADXL345.py +++ b/src/sts1_sensors/edu/ADXL345.py @@ -12,12 +12,20 @@ def __init__(self, range=2, datarate=50, x_offset=0, y_offset=0, z_offset=0, add """Digital accelerometer. :param int range: How many gs the sensor should be able measure. Allowed values: `[2, 4, 8, 16]`. Defaults to 2. - :param int datarate: How often the sensor should measure in Hz. Allowed values: `[0.10, 0.20, 0.39, 0.78, 1.56, 3.13, 6.25, 12.5, 25, 50, 100, 200, 400, 800, 1600, 3200]`. Defaults to 50. + :param int datarate: Number of measurements per second [Hz]. Allowed values: `[0.10, 0.20, 0.39, 0.78, 1.56, 3.13, 6.25, 12.5, 25, 50, 100, 200, 400, 800, 1600, 3200]`. Defaults to 50. :param int x_offset: x-axis offset, defaults to 0. :param int y_offset: y-axis offset, defaults to 0. :param int z_offset: z-axis offset, defaults to 0. :param hexadecimal address: Physical address of the sensor on the board (see `i2cdetect` command). Allowed values: `[0x1D, 0x3A, 0x3B, 0x53]`. If None, the environment variable `STS1_SENSOR_ADDRESS_AVXL345` will be used. If environment variable is not found, 0x53 will be used. :param SMBus bus: A SMBus object. If None, this class will generate its own, defaults to None. + + Example: + + .. code-block:: python + + accel = ADXL345(range=2, datarate=50) + x, y, z = accel.get_g() + print(f"{x=:.2f} g, {y=:.2f} g, {z=:.2f} g") """ super().__init__(possible_addresses=[0x1D, 0x3A, 0x3B, 0x53], bus=bus) diff --git a/src/sts1_sensors/edu/BME688.py b/src/sts1_sensors/edu/BME688.py index 54d9310..9a023e0 100644 --- a/src/sts1_sensors/edu/BME688.py +++ b/src/sts1_sensors/edu/BME688.py @@ -18,6 +18,33 @@ def __init__(self, temperature_osr=8, humidity_osr=2, pressure_osr=4, iir_filter temperature_offset=0, enable_gas_measurements=False, gas_heater_temperature=320, gas_heater_duration=150, address=None, bus=None): + """Pressure, humidity, temperature and gas sensor. + + Builds on top of the library `bme680 `_. + + :param int temperature_osr: Temperature oversampling rate. Allowed values: `[None, 1, 2, 4, 8, 16]`. A higher oversampling value means more stable sensor readings with less noise and jitter However each step of oversampling adds about 2ms to the latency, causing a slower response time to fast transients. Defaults to 8. + :param int humidity_osr: Humidity oversampling rate. Allowed values: `[None, 1, 2, 4, 8, 16]`. A higher oversampling value means more stable sensor readings with less noise and jitter However each step of oversampling adds about 2ms to the latency, causing a slower response time to fast transients. Defaults to 2. + :param int pressure_osr: Pressure oversampling rate. Allowed values: `[None, 1, 2, 4, 8, 16]`. A higher oversampling value means more stable sensor readings with less noise and jitter However each step of oversampling adds about 2ms to the latency, causing a slower response time to fast transients. Defaults to 4. + :param int iir_filter_size: Number of infinite impulse response filter coefficients. Allowed values: `[0, 1, 3, 7, 15, 31, 63, 127]`. It removes short term fluctuations from the temperature and pressure readings (not humidity), increasing their resolution but reducing their bandwidth. Defaults to 3. + :param int temperature_offset: Temperature offset, defaults to 0. + :param bool enable_gas_measurements: Enable gas measurements, defaults to False. + :param int gas_heater_temperature: Set temperature of gas sensor heater [°C], between 200 and 400, defaults to 320. + :param int gas_heater_duration: Set duration of gas sensor heater [ms], between 1 and 4032. Approximately 20-30 ms are necessary for the heater to reach the intended target temperature. Defaults to 150. + :param hexadecimal address: Physical address of the sensor on the board (see `i2cdetect` command). Allowed values: `[0x76, 0x77]`. If None, the environment variable `STS1_SENSOR_ADDRESS_BME688` will be used. If environment variable is not found, 0x76 will be used. + :param SMBus bus: A SMBus object. If None, this class will generate its own, defaults to None. + + Example: + + .. code-block:: python + + sensor = BME688(temperature_osr=8, humidity_osr=2, pressure_osr=4, enable_gas_measurements=True) + t = sensor.get_temperature() + p = sensor.get_pressure() + h = sensor.get_humidity() + heat = sensor.get_heat_stable() + res = sensor.get_gas_resistance() + print(f"{t:.2f} °C, {p:.2f} hPa, {h:.2f} %RH, {heat=}, {res:.2f} Ohms") + """ super().__init__(possible_addresses=[0x76, 0x77], bus=bus) self.address = address or int(os.environ.get("STS1_SENSOR_ADDRESS_BME688", "0x76"), 16) @@ -126,6 +153,8 @@ def gas_heater_duration(self, gas_heater_duration): self.bme680.set_gas_heater_duration(gas_heater_duration) def get_all_data(self): + """Returns all sensor data. Calling this method after less than 10 ms will return the same (cached) result. + """ curr_time_ms = round(time.time() * 1000) if curr_time_ms - self.last_query_time_ms >= 10: self.bme680.get_sensor_data() @@ -133,21 +162,27 @@ def get_all_data(self): return self.bme680.data def get_heat_stable(self): + """Indicates whether or not the gas resistance value should be read. + """ return self.get_all_data().heat_stable def get_temperature(self): - # Temperature in degree celsius + """Temperature in degree celsius. + """ return self.get_all_data().temperature def get_pressure(self): - # Pressure in hPa + """Pressure in hPa. + """ return self.get_all_data().pressure def get_humidity(self): - # Humidity in % relative humidity + """Humidity in % relative humidity. + """ return self.get_all_data().humidity def get_gas_resistance(self): - # Gas resistance in Ohms + """Gas resistance in Ohms. + """ return self.get_all_data().gas_resistance \ No newline at end of file diff --git a/src/sts1_sensors/edu/BMM150.py b/src/sts1_sensors/edu/BMM150.py index 36b4ab5..6f217d3 100644 --- a/src/sts1_sensors/edu/BMM150.py +++ b/src/sts1_sensors/edu/BMM150.py @@ -8,10 +8,25 @@ class BMM150: """Geomagnetic sensor. - - Datasheet: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmm150-ds001.pdf """ + def __init__(self, address=None, bus=None): + """Geomagnetic sensor. + + Builds on top of the library `bmm150 `_. + + :param hexadecimal address: Physical address of the sensor on the board (see `i2cdetect` command). Allowed values: `[0x10, 0x11, 0x12, 0x13]`. If None, the environment variable `STS1_SENSOR_ADDRESS_BMM150` will be used. If environment variable is not found, 0x10 will be used. + :param SMBus bus: A SMBus object. If None, this class will generate its own, defaults to None. + + Example: + + .. code-block:: python + + mag = BMM150() + x, y, z = mag.get_magnetic_data() + print(f"{x=:.2f} µT, {y=:.2f} µT, {z=:.2f} µT") + print(f"Heading: {mag.get_heading():.2f}°") + """ self.possible_addresses = [0x10, 0x11, 0x12, 0x13] a = address or int(os.environ.get("STS1_SENSOR_ADDRESS_BMM150", "0x10"), 16) @@ -41,11 +56,17 @@ def address(self, address): self._address = address def get_raw_magnetic_data(self): + """Get raw magnetic data in µT. + """ return self.bmm.read_raw_mag_data() def get_magnetic_data(self): + """Get magnetic data in µT. + """ return self.bmm.read_mag_data() def get_heading(self): + """Get heading direction in degrees. Uses only x and y for calculation (z is ignored). + """ x, y, _ = self.get_magnetic_data() return math.degrees(math.atan2(x, y)) diff --git a/src/sts1_sensors/edu/L3GD20H.py b/src/sts1_sensors/edu/L3GD20H.py index 2a11246..f6b84ea 100644 --- a/src/sts1_sensors/edu/L3GD20H.py +++ b/src/sts1_sensors/edu/L3GD20H.py @@ -11,6 +11,21 @@ class L3GD20H(AbstractSensor): _possible_datarates_bin = [(0, 1), (1, 1), (2, 1), (0, 0), (1, 0), (2, 0), (3, 0)] def __init__(self, range=245, datarate=12.5, address=None, bus=None): + """Three-axis gyroscope. + + :param int range: Maximum angular velocity or speed of rotation that the gyro can read, measured in degrees per second (dps). Allowed values: `[245, 500, 2000]`, defaults to 245. + :param float datarate: Number of measurements per second [Hz]. Allowed values: `[12.5, 25, 50, 100, 200, 400, 800]`, defaults to 12.5. + :param hexadecimal address: Physical address of the sensor on the board (see `i2cdetect` command). Allowed values: `[0x6A, 0x6B]`. If None, the environment variable `STS1_SENSOR_ADDRESS_L3GD20H` will be used. If environment variable is not found, 0x6A will be used. + :param SMBus bus: A SMBus object. If None, this class will generate its own, defaults to None. + + Example: + + .. code-block:: python + + gyro = L3GD20H(range=245, datarate=12.5) + x, y, z = gyro.get_dps() + print(f"{x=:.2f} dps, {y=:.2f} dps, {z=:.2f} dps") + """ super().__init__(possible_addresses=[0x6A, 0x6B], bus=bus) self.address = address or int(os.environ.get("STS1_SENSOR_ADDRESS_L3GD20H", "0x6A"), 16) @@ -55,12 +70,14 @@ def _get_raw(self, var): lsb, msb = self.bus.read_i2c_block_data(self.address, self.xyz_addresses[var], 2) return twos_comp((msb << 8) + lsb, 16) - def get_position_raw(self): + def get_dps_raw(self): + "Get raw degrees per second." return self._get_raw("x"), self._get_raw("y"), self._get_raw("z") def _get_dps(self, var): k = self._get_raw(var) return k * self.dps_per_digit[self._possible_ranges.index(self.range)] - def get_position(self): + def get_dps(self): + "Get degrees per second." return self._get_dps("x"), self._get_dps("y"), self._get_dps("z") diff --git a/src/sts1_sensors/edu/TMP112.py b/src/sts1_sensors/edu/TMP112.py index f71205c..caff46f 100644 --- a/src/sts1_sensors/edu/TMP112.py +++ b/src/sts1_sensors/edu/TMP112.py @@ -16,6 +16,13 @@ def __init__(self, conversion_rate=1, extended_temp_range=True, address=None, bu :param bool extended_temp_range: If True, range: -55°C - 150°C, if False range: -55°C - 128°C, defaults to True. :param hexadecimal address: Physical address of the sensor on the board (see `i2cdetect` command). Allowed values: `[0x48, 0x49, 0x4A, 0x4B]`. If None, the environment variable `STS1_SENSOR_ADDRESS_TMP112` will be used. If environment variable is not found, 0x48 will be used. :param SMBus bus: A SMBus object. If None, this class will generate its own, defaults to None. + + Example: + + .. code-block:: python + + temp = TMP112(conversion_rate=1, extended_temp_range=True) + print(f"{temp.get_temp():.2f} °C") """ super().__init__(possible_addresses=[0x48, 0x49, 0x4A, 0x4B], bus=bus) diff --git a/src/sts1_sensors/utils/utils.py b/src/sts1_sensors/utils/utils.py index 92cc629..c911bf5 100644 --- a/src/sts1_sensors/utils/utils.py +++ b/src/sts1_sensors/utils/utils.py @@ -1,5 +1,11 @@ def twos_comp(val, bits): + """Convert a value into its 2-complement. + + :param int val: Value. + :param int bits: Number of available bits. + :return int: The number's 2-complement. + """ if val & (1 << (bits - 1)) != 0: val = val - (1 << bits) return val diff --git a/tests/test_L3GD20H.py b/tests/test_L3GD20H.py index 58d3916..d65dbd5 100644 --- a/tests/test_L3GD20H.py +++ b/tests/test_L3GD20H.py @@ -28,11 +28,11 @@ def test_class_creation6(): def test_get_postition1(): t = L3GD20H() - t.get_position_raw() + t.get_dps_raw() def test_get_postition2(): t = L3GD20H() - t.get_position() + t.get_dps() def test_set_wrong_address1(): with pytest.raises(ValueError):