Skip to content

Commit

Permalink
Merge pull request #278 from shreyhas/integration
Browse files Browse the repository at this point in the history
Integration
  • Loading branch information
senthurayyappan authored Oct 3, 2024
2 parents fc7a7a7 + 284c804 commit 835a631
Show file tree
Hide file tree
Showing 6 changed files with 282 additions and 6 deletions.
Binary file added .coverage 2
Binary file not shown.
4 changes: 2 additions & 2 deletions assets/images/coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 19 additions & 4 deletions opensourceleg/sensors/loadcell.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,26 @@ class SRILoadcell(LoadcellBase):

def __init__(
self,
calibration_matrix: npt.NDArray[np.double],
amp_gain: float = 125.0,
exc: float = 5.0,
calibration_matrix=None,
bus: int = 1,
i2c_address: int = 0x66,
) -> None:
'''
TODO: Write docstring for initial values
'''
# Check that parameters are set correctly:
if calibration_matrix.shape != (6, 6):
LOGGER.info(f"[{self.__repr__()}] calibration_matrix must be a 6x6 array of np.double.")
raise TypeError("calibration_matrix must be a 6x6 array of np.double.")
if amp_gain <= 0:
LOGGER.info(f"[{self.__repr__()}] amp_gain must be a floating point value greater than 0.")
raise ValueError("amp_gain must be a floating point value greater than 0.")
if exc <= 0 :
LOGGER.info(f"[{self.__repr__()}] exc must be a floating point value greater than 0.")
raise ValueError("exc must be a floating point value greater than 0.")

self._amp_gain: float = amp_gain
self._exc: float = exc

Expand All @@ -64,7 +78,8 @@ def __init__(
self._is_streaming: bool = False

def start(self) -> None:
if self._bus or self._i2c_address is None:
# TODO: What is the purpose of this check?
if (self._bus) or (self._i2c_address is None):
return

self._smbus = SMBus(self._bus)
Expand All @@ -89,7 +104,7 @@ def update(
if calibration_offset is None:
calibration_offset = self._calibration_offset

signed_data = (data - self.OFFSET) / self.ADC_RANGE * self._exc
signed_data = ((data - self.OFFSET) / self.ADC_RANGE) * self._exc
coupled_data = signed_data * 1000 / (self._exc * self._amp_gain)

self._data = (
Expand All @@ -105,7 +120,7 @@ def calibrate(
) -> None:
"""
Obtains the initial loadcell reading (aka) loadcell_zero.
This is automatically subtraced off for subsequent calls of the update method.
This is automatically subtracted off for subsequent calls of the update method.
"""

if not self.is_calibrated:
Expand Down
4 changes: 4 additions & 0 deletions tests/test_actuators/test_actuators_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -562,3 +562,7 @@ def test_motor_constants_properties(mock_actuator: MockActuator):
== 2 * 3.14159 / 1000
)
assert mock_actuator.MOTOR_CONSTANTS.NM_PER_MILLIAMP == 0.0001


def test_hello_world():
assert len("Hello World") == 11
105 changes: 105 additions & 0 deletions tests/test_sensors/test_loadcell.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Global Units Dictionary
import enum
from dataclasses import dataclass

import numpy as np
from numpy import typing as npt
import pytest
import time

from opensourceleg.sensors import loadcell
from smbus2 import SMBus

VALUES = np.append(np.array([0, 1, -1, 1000, -1000]), np.random.random(5))
DEFAULT_CAL_MATRIX = np.ones(shape=(6,6), dtype = np.double)

# TODO: Test loadcell not responding exception

def test_SRILoadcell_init():

invalid_cal_matrix = np.ones(shape=(5,6), dtype = np.double)
with pytest.raises(TypeError):
SRI = loadcell.SRILoadcell(calibration_matrix=invalid_cal_matrix)
with pytest.raises(ValueError):
SRI = loadcell.SRILoadcell(calibration_matrix=DEFAULT_CAL_MATRIX, amp_gain=0)
with pytest.raises(ValueError):
SRI = loadcell.SRILoadcell(calibration_matrix=DEFAULT_CAL_MATRIX, exc = 0)

SRI = loadcell.SRILoadcell(calibration_matrix=DEFAULT_CAL_MATRIX)

assert SRI._amp_gain == 125.0
assert SRI._exc == 5.0
assert np.array_equal(SRI._calibration_matrix, DEFAULT_CAL_MATRIX)
assert SRI._bus == 1
assert SRI._i2c_address == 0x66

def test_SRILoadcell_start():

#Initialize SRILoadcell object
SRI = loadcell.SRILoadcell(calibration_matrix=DEFAULT_CAL_MATRIX)

start = time.time()
SRI.start()
end = time.time()

#assert SRI._bus == SMBus(SRI._bus) #?
assert (end - start) >= 1 # TODO: Link to var
assert SRI._is_streaming == True

# Test start with bus or i2c_address set to None
SRI = loadcell.SRILoadcell(DEFAULT_CAL_MATRIX, 125.0, 5, 1, None)
result = SRI.start() # TODO: Am I doing this correctly?
assert result == None

def test_SRILoadcell_reset():

SRI = loadcell.SRILoadcell(calibration_matrix=DEFAULT_CAL_MATRIX)
SRI._calibration_offset == np.ones(shape=(1, 6), dtype=np.double)
SRI.reset()
assert np.array_equal(SRI._calibration_offset, np.zeros(shape=(1, 6), dtype=np.double))

def test_SRILoadcell_update():

# Test basic call execution
SRI = loadcell.SRILoadcell(calibration_matrix = DEFAULT_CAL_MATRIX)
SRI.update(data_callback=_read_data)

# Ensuring self._calibration_offset was used
data = _update_calculations(SRI, SRI._calibration_offset)
assert np.array_equal(SRI._data, data)

# Testing if passed calibration offset was used
passed_calibration_offset = 0.1
SRI.update(data_callback=_read_data, calibration_offset=passed_calibration_offset)

# Ensuring passed calibration_offset was used
data = _update_calculations(SRI, passed_calibration_offset)
assert np.array_equal(SRI._data, data)


def test_SRILoadcell_calibrate():
#Test reset, else statement

return

# Function to bypass _read_compressed_strain() with an array of ones
def _read_data() -> npt.NDArray[np.uint8]:
return np.ones(shape=(1,6))

# Function to bypass _read_compressed_strain() with random data
def _read_random_data() -> npt.NDArray[np.uint8]:
return np.random.randint(low=0, high=255, size=(1, 6), dtype=np.uint8)

# Function to run update calculations from inside the update method
def _update_calculations(SRI: loadcell.SRILoadcell, calibration_offset: float):
test_data = _read_data()
signed_data = ((test_data - SRI.OFFSET) / SRI.ADC_RANGE) * SRI._exc
coupled_data = signed_data * 1000 / (SRI._exc * SRI._amp_gain)
data = (
np.transpose(a=SRI._calibration_matrix.dot(b=np.transpose(a=coupled_data)))
- calibration_offset
)
return data

if __name__ == '__main__':
test_SRILoadcell_update()
152 changes: 152 additions & 0 deletions tests/test_units/test_units.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# Global Units Dictionary
import enum
from dataclasses import dataclass

import numpy as np
import pytest

from opensourceleg.units import *

# Values to iterate over for testing
VALUES = np.append(np.array([0, 1, -1, 1000, -1000]), np.random.random(5))


def test_convert_to_from_default():
# Testing behaviour when invalid input type is passed to convert_to_default & convert_from_default
with pytest.raises(TypeError):
convert_to_default("TEST", force.kgf)
with pytest.raises(TypeError):
convert_to_default("T", force.kgf)
with pytest.raises(TypeError):
convert_from_default("TEST", force.N)
with pytest.raises(TypeError):
convert_from_default("T", force.N)

# Testing behaviour on all possible unit conversions to default & from default
categories = [
force,
torque,
stiffness,
damping,
length,
position,
mass,
velocity,
acceleration,
time,
current,
voltage,
]
units = []
# Add all units to array
for c in categories:
for unit in dir(c):
if not unit.startswith("__"):
value = getattr(c, unit)
print(value)
units.append(value)

# Iterate over all possible units and test converting to/from default
for unit in units:
for value in VALUES:
assert convert_to_default(value, unit) == value * unit
assert convert_from_default(value, unit) == value / unit


def test_force():

assert force.N == 1.0
assert force.lbf == 4.4482216152605
assert force.kgf == 9.80665
# assert repr(force) == "force"


def test_torque():

assert torque.N_m == 1.0
assert torque.lbf_inch == 0.1129848290276167
assert torque.kgf_cm == 0.0980665
# assert repr(torque) == "torque"


def test_stiffness():

assert stiffness.N_m_per_rad == 1.0
assert stiffness.N_m_per_deg == 0.017453292519943295

# assert repr(stiffness) == "stiffness"


def test_damping():

assert damping.N_m_per_rad_per_s == 1.0
assert damping.N_m_per_deg_per_s == 0.017453292519943295

# assert repr(damping) == "damping"


def test_length():

assert length.m == 1.0
assert length.cm == 0.01
assert length.inch == 0.0254

# assert repr(length) == "length"


def test_position():

assert position.rad == 1.0
assert position.deg == 0.017453292519943295

# assert repr(position) == "position"


def test_mass():

assert mass.kg == 1.0
assert mass.g == 0.001
assert mass.lb == 0.45359237

# assert repr(mass) == "mass"


def test_velocity():

assert velocity.rad_per_s == 1.0
assert velocity.deg_per_s == 0.017453292519943295
assert velocity.rpm == 0.10471975511965977

# assert repr(velocity) == "velocity"


def test_acceleration():

assert acceleration.rad_per_s2 == 1.0
assert acceleration.deg_per_s2 == 0.017453292519943295

# assert repr(acceleration) == "acceleration"


def test_time():

assert time.s == 1.0
assert time.ms == 0.001

# assert repr(time) == "time"


def test_current():

assert current.mA == 1
assert current.A == 1000

# assert repr(current) == "current"


def test_voltage():

assert voltage.mV == 1
assert voltage.V == 1000

# assert repr(voltage) == "voltage"

0 comments on commit 835a631

Please sign in to comment.