BaseShield Class

class automationshield.shields.BaseShield(port: str | None = None)[source]

Bases: object

Base class for shield devices. Handles communication with Arduino, sensor calibration and unit conversions. The class can also install the proper firmware on an Arduino.

Interface:
  • Actuator input should be provided in percent by default.

  • Potentiometer is provided in percent by default.

  • Sensor values are converted to relevant physical units in the child classes.

Parameters:

port (str | None) – Port on which the Arduino is connected, defaults to None.

TEST: int = 0

Flag to write to Arduino. This flag is used to check if the correct firmware is installed. The response from the Arduino should be the C++ software version and the id of the shield.

RUN: int = 1

Flag to write to Arduino. This flag is used for normal running of the shield device. The actuator value is applied and the Arduino responds with the potentiometer and sensor values.

STOP: int = 2

Flag to write to Arduino. This flag is used to stop the actuator. The Arduino will stop the actuator to ensure the shield is safely stopped.

TIMEOUT: int = 3

Time to wait after opening the serial connection before writing to the Arduino.

script: str = ''

Name of the script directory in which the .ino file for the specific shield is located.

shield_id: str = ''

ID assigned to shield. This is used to check whether the correct firmware is installed on the Arduino.

actuator_bits: int = 0

Number of bits used for actuator.

potentiometer_bits: int = 0

Number of bits used for potentiometer.

sensor_bits: int = 0

Number of bits used for sensor.

class PlotInfo[source]

Bases: object

This class contains information to improve the plots generated by the Plotter and LivePlotter classes in the plotting package.

sensor_unit: str = ''

Sets the unit on the axis label of the output plot.

sensor_type: str = ''

Sets the name of the axis of the output plot.

sensor_min: float = 0

Sets to lower bound of the sensor value. This is used to set up the LivePlotter.

sensor_max: float = 10

Sets the upper bound of the sensor value. This is used to set up the LivePlotter.

find_arduino() str[source]

Get the name of the port that is connected to Arduino. Raises exception if no port was found.

Raises:

AutomationShieldException – Raised if no Arduino was found.

Returns:

COM port of the Arduino.

Return type:

str

check_firmware() int[source]

Check that the correct firmware is installed on the Arduino. When the arduino reads the BaseShield.TEST flag, it should respond with the code version and two bytes which, when converted to ASCII, should match the shield id.

Raises:

AutomationShieldException – If the arduino didn’t respond correctly.

Returns:

version number of Arduino firmware.

Return type:

int

install_firmware(device: str) None[source]

Upload compiled firmware for the current shield to the Arduino.

Parameters:

device (str) – FQBN of Arduino. FQBNs for common devices are provided in automationshield.arduino, e.g. automationshield.arduino.LEONARDO: arduino:avr:leonardo.

Return type:

None

convert_potentiometer_reading(raw: int) float[source]

Convert n-bit potentiometer reading to percentage value. A bit value of \(1023\) is mapped to \(100\) %.

Parameters:

raw (int) – n-bit potentiometer value.

Returns:

Potentiometer value as percentage [0, 100].

Return type:

float

convert_actuator_input(percent: float) int[source]

Convert actuator input from percentage to n-bit value. A value of \(100\) (%) is mapped to \(2^n-1\) where \(n\) equals BaseShield.actuator_bits.

Parameters:

percent (float) – Actuator percentage.

Returns:

n-bit number of actuator value.

Return type:

int

convert_sensor_reading(sensor: int) float[source]

Convert sensor reading to physical units. Should be implemented on subclasses. By default, the sensor value is returned unchanged.

Parameters:

sensor (int) – Raw sensor value

Returns:

Sensor value converted to physical units.

Return type:

float

calibrate_sensor_reading(sensor: int) int[source]

Calibrate the sensor reading with the zero reference. Should be implemented on subclass. The default implementation is

\[y_c = y_r - y_0\]

where \(y_c\) is the calibrated sensor value, \(y_r\) is the raw sensor value and \(y_0\) is the zero reference of the sensor value.

Note

The zero reference is obtained at the start of each experiment. It is therefore important that the system is at rest when an experiment is started.

Parameters:

sensor (int) – Raw sensor value.

Returns:

Calibrated sensor value.

Return type:

int

_read() tuple[int, float][source]

Construct potentiometer and sensor value from bytes received from arduino.

Three bytes are received from the arduino. The second and third byte contain the first eight bits of the potentiometer and sensor values. The first byte contains the remaining bits of the potentiometer and sensor values.

Byte 1:

7

6

5

4

3

2

1

0

0

0

\(p_9\)

\(p_8\)

\(s_{11}\)

\(s_{10}\)

\(p_9\)

\(p_8\)

Byte 2:

7

6

5

4

3

2

1

0

\(p_7\)

\(p_6\)

\(p_5\)

\(p_4\)

\(p_3\)

\(p_2\)

\(p_1\)

\(p_0\)

Byte 3:

7

6

5

4

3

2

1

0

\(s_7\)

\(s_6\)

\(s_5\)

\(s_4\)

\(s_3\)

\(s_2\)

\(s_1\)

\(s_0\)

The bits are extracted from the bytes and reconstructed, after which they are converted to base 10 (integer numbers).

Returns:

Potentiometer and sensor values, respectively.

Return type:

tuple[int, float]

read(raw: bool = False) tuple[float][source]

Read data from Arduino. If raw == False, the potentiometer value is rescaled to percentages; and the sensor is calibrated with the zero reference and converted to relevant units. This is the default. If raw == True, none of that happens and the potentiometer and sensor are returned as n-bit values. No calibration is performed either.

Parameters:

raw (bool) – If True, returns raw n-bit readings from potentiometer and sensor. Defaults to False, in which case the potentiometer is converted to percent and the sensor to appropriate units.

Raises:

AutomationShieldException – Raised if no data was received. This can happen if there was no BaseShield.write() command invoked preceding a call to BaseShield.read() or if there is something wrong with the serial connection or the cable.

Returns:

(Converted and calibrated) potentiometer and sensor readings, in that order.

Return type:

tuple[float]

static saturate_bits(value: float, bits: int) int[source]

Saturate value between \(0\) and \(2^{bits - 1}\) inclusive.

Parameters:
  • value (float) – Raw value.

  • bits (int) – Number of bits.

Returns:

Saturated value.

Return type:

int

static saturate_percent(value: float) float[source]

Saturate value between \(0\) and \(100\) inclusive.

Parameters:

value (float) – Raw value in percent.

Returns:

Saturated value in percent.

Return type:

float

_write(flag: int, output: int) None[source]

Put flag and output value into bytes and send them to the arduino.

The first byte is the flag value. Technically the flag only needs two bits, so the first byte looks like this:

7

6

5

4

3

2

1

0

0

0

0

0

0

0

\(f_1\)

\(f_0\)

Depending the on the number of output bits (set by BaseShield.actuator_bits), the actuator value is sent in one or two bytes. If BaseShield.actuator_bits \(\leq 8\), only the bottom byte is created and sent, otherwise both are constructed and sent in the order below.

7

6

5

4

3

2

1

0

\(o_{15}\)

\(o_{14}\)

\(o_{13}\)

\(o_{12}\)

\(o_{11}\)

\(o_{10}\)

\(o_9\)

\(o_8\)

7

6

5

4

3

2

1

0

\(o_7\)

\(o_6\)

\(o_5\)

\(o_4\)

\(o_3\)

\(o_2\)

\(o_1\)

\(o_0\)

Parameters:
Return type:

None

write(flag: int, actuator: float, raw: bool = False) int[source]

Write run/stop flag and actuator value to Arduino. Convert and saturate the actuator value before sending.

the flag must be one of BaseShield.TEST, BaseShield.RUN or BaseShield.STOP.

  • BaseShield.TEST returns the version number of the Arduino code and a shield id, which should match BaseShield.shield_id. The actuator input is irrelevant for this command.

  • BaseShield.RUN means normal running mode. Set the actuator value.

  • BaseShield.STOP tells the arduino to stop the actuator. The supplied actuator value is ignored by the Arduino.

Parameters:
Returns:

Saturated n-bit motor value.

Return type:

int

calibrate() None[source]

Read out a zero reference and save it. System should be at rest when calling this method.

Return type:

None

stop() None[source]

Send BaseShield.STOP signal to Arduino.

Return type:

None

open() None[source]

Reset buffers and open connection to Arduino if it is not open already. Wait for BaseShield.TIMEOUT seconds to make sure connection is established.

Return type:

None

close(*args) None[source]

Close connection to Arduino.

Return type:

None

__enter__() BaseShield[source]

Implements the with context manager. This method calls

Returns:

Shield instance.

Return type:

BaseShield

__exit__(*args) None[source]

Closes the context manager. This method calls

Return type:

None