Source code for do_dpc.control_utils.pid_control_utils

"""
Helper functions for converting double integrator system outputs to error and derivative of error.
"""

from dataclasses import dataclass
from typing import Tuple, Callable, Optional

import numpy as np

from do_dpc.control_utils.pid import MIMOPIDController


[docs] @dataclass class PIDCombo: """ A dataclass to bundle a MIMOPIDController and a converter function. Attributes: MIMO_PID (MIMOPIDController): An instance of MIMO_PIDController. converter_function (Callable[[np.ndarray, np.ndarray], Tuple[np.ndarray, np.ndarray]]): A function to convert outputs to error and derivative of error. """ MIMO_PID: MIMOPIDController converter_function: Callable[[np.ndarray, Optional[np.ndarray]], Tuple[np.ndarray, np.ndarray]]
[docs] def one_D_double_integrator_output_to_err_der_err( output: np.ndarray, output_target: Optional[np.ndarray] = None ) -> Tuple[np.ndarray, np.ndarray]: """ Converts a 1D double integrator output to error and derivative of error. Args: output (np.ndarray): The output array containing the state and its derivative. output_target (np.ndarray, optional): The target output array. Defaults to an array of zeros. Returns: Tuple[np.ndarray, np.ndarray]: A tuple containing the error and the derivative of the error. """ if output.shape[0] != 2: raise ValueError("Output must be a 1D array with exactly 2 elements.") if output_target is None: output_target = np.zeros_like(output) error = np.array([output[0] - output_target[0]]) der_error = np.array([output[1] - output_target[1]]) return error, der_error
[docs] def three_D_double_integrator_output_to_err_der_err( output: np.ndarray, output_target: Optional[np.ndarray] = None ) -> Tuple[np.ndarray, np.ndarray]: """ Converts a 3D double integrator output to error and derivative of error. Args: output (np.ndarray): The output array containing the states and their derivatives. output_target (np.ndarray, optional): The target output array. Defaults to an array of zeros. Returns: Tuple[np.ndarray, np.ndarray]: A tuple containing the errors and the derivatives of the errors. """ if output.shape[0] != 6: raise ValueError("Output must be a 1D array with exactly 6 elements.") if output_target is None: output_target = np.zeros_like(output) error = np.array([output[0] - output_target[0], output[2] - output_target[2], output[4] - output_target[4]]) der_error = np.array([output[1] - output_target[1], output[3] - output_target[3], output[5] - output_target[5]]) return error, der_error
# pylint: disable=too-many-locals
[docs] def rocket_output_to_err_der_err( output: np.ndarray, output_target: Optional[np.ndarray] = None ) -> Tuple[np.ndarray, np.ndarray]: """ Converts a Rocket output to error and derivative of error. Args: output (np.ndarray): The output array containing the states and their derivatives. output_target (np.ndarray, optional): The target output array. Defaults to an array of zeros. Returns: Tuple[np.ndarray, np.ndarray]: A tuple containing the errors and the derivatives of the errors. """ if output.shape[0] != 6 and output.shape[0] != 8: raise ValueError("Output must be a 1D array with exactly 6 or 8 elements.") if output_target is None: output_target = np.zeros_like(output) if output.shape[0] == 6: x, y, vel_x, vel_y, theta, omega = output else: x, y, vel_x, vel_y, theta, omega, _, _ = output dx = x - output_target[0] dy = y - output_target[1] # Fe y_adj = -0.1 # Adjust speed err_1 = y_adj - dy + 0.1 * dx derr_1 = -vel_y + 0.1 * vel_x # Fs err_2 = -theta + 0.2 * dx derr_2 = -omega + 0.2 * vel_x # Psi err_3 = theta derr_3 = omega if abs(dx) > 0.01 and dy < 0.5: err_3 = err_3 - 0.06 * dx # theta is negative when slanted to the right derr_3 = derr_3 - 0.06 * vel_x err = np.array([-err_1, err_2, -err_3]) derr = np.array([-derr_1, derr_2, -derr_3]) return err, derr