Bota Control Toolkit Python
Definitions
BotaControlBlock
BotaControlBlock is defined as a parent class from which all control blocks inherit.
- class BotaControlBlock(config)
Abstract base class providing the interface for all control processing blocks.
Constructor
- __init__(config)
Unified constructor that dispatches based on the type of
config.
Runtime Update Methods
Note
All update methods operate on NumPy arrays (
numpy.ndarray, dtypefloat64). Output arrays are written in-place — allocate them once before your control loop and reuse them every iteration to avoid unnecessary allocations.- update(input_signal, output_signal)
Reads input data and performs processing, writing the result into
output_signalin-place.- Parameters:
input_signal (numpy.ndarray) – Input signal data. Shape
(N,), dtypefloat64.output_signal (numpy.ndarray) – Pre-allocated output array. Overwritten in-place with the processed result. Shape
(M,), dtypefloat64.
- Returns:
A return code indicating the status of the update operation.
- Return type:
- update_inplace(signal)
Reads data and performs processing in place, overwriting
signalwith the result.- Parameters:
signal (numpy.ndarray) – Signal data to be processed in place. Shape
(N,), dtypefloat64.- Returns:
A return code indicating the status of the update operation.
- Return type:
- update_observer(measurement, state_estimate)
Observer update: reads measurement data and writes the state estimate in-place.
- Parameters:
measurement (numpy.ndarray) – Measurement data. Shape
(N,), dtypefloat64.state_estimate (numpy.ndarray) – Pre-allocated output array. Overwritten in-place with the state estimate. Shape
(M,), dtypefloat64.
- Returns:
A return code indicating the status of the update operation.
- Return type:
- update_controller(reference, state_estimate, control_action)
Controller update: reads reference and state estimate, writes the control action in-place.
- Parameters:
reference (numpy.ndarray) – Reference / setpoint data. Shape
(N,), dtypefloat64.state_estimate (numpy.ndarray) – Current state estimate from the observer. Shape
(M,), dtypefloat64.control_action (numpy.ndarray) – Pre-allocated output array. Overwritten in-place with the control action. Shape
(P,), dtypefloat64.
- Returns:
A return code indicating the status of the update operation.
- Return type:
In-line Configuration Methods
Specific implementations of control blocks may include additional in-line configuration methods that allow users to modify block parameters at configuration or runtime without needing to re-instantiate the block. These methods are specific to each block and are not part of the base class interface.
BotaControlReturnCode
Pipeline Wiring
Here’s how to connect multiple blocks to create a processing pipeline:
###############################################
# EXAMPLE OF A BUNDLED CONTROL PIPELINE USING THE BOTA CONTROL BLOCKS #
###############################################
import time
import numpy as np
# Define signals as pre-allocated numpy arrays (reused every iteration)
signal_1 = np.zeros(N, dtype=np.float64)
signal_2 = np.zeros(M, dtype=np.float64)
signal_3 = np.zeros(P, dtype=np.float64)
# Path to the JSON configuration file for each block
config_1 = "path/to/config_1.json"
config_2 = "path/to/config_2.json"
config_3 = "path/to/config_3.json"
# Instantiation & configuration at initialisation time
block_1 = Block1(config_1)
block_2 = Block2(config_2)
block_3 = Block3(config_3)
# Block in-line static configuration
block_1.set_parameter(value_1)
block_2.set_parameter(value_2)
block_3.set_parameter(value_3)
# Set the desired processing rate
rate_hz = 500.0 # 500 Hz
dt = 1.0 / rate_hz
running = True
# Loop reactor function to handle return codes and control flow
def loop_reactor(code: BotaControlReturnCode) -> None:
global running
match code:
case BotaControlReturnCode.OK:
pass # Normal operation, continue processing
# ... other cases ...
case BotaControlReturnCode.FatalError:
# Handle fatal errors (e.g. log the error, shut down safely, etc.)
running = False # Stop the loop on fatal error
while running:
start_time = time.perf_counter()
# Update signal_1 with new data (e.g. from sensors, reference generators, etc.)
# Write directly into the pre-allocated array to avoid re-allocation
signal_1[:] = get_new_data_for_signal_1()
# Process data through the pipeline
loop_reactor(block_1.update(signal_1, signal_2))
# => signal_2 freshly updated by block_1 algorithm can be used HERE
loop_reactor(block_2.update_inplace(signal_2))
# => signal_2 freshly updated by block_2 algorithm can be used HERE
loop_reactor(block_3.update(signal_2, signal_3))
# => signal_3 freshly updated by block_3 algorithm can be used HERE
#############
# Control logic here #
#############
# Rate control — sleep to maintain the desired frequency
elapsed = time.perf_counter() - start_time
sleep_time = dt - elapsed
if sleep_time > 0:
time.sleep(sleep_time)
Distribution
The Bota Control Toolkit definitions are distributed as a Python package.
It can be installed using pip:
pip install bota-control
Important
The bota-control package is a dependency of all the other Bota Control Toolkit blocks.