Module MAPLEAF.GNC.MomentControllers

Moment controllers determine what overall moments should be applied to the rocket to remain on the course provided by the ControlSystem

Expand source code
'''
Moment controllers determine what overall moments should be applied to the rocket to remain on the course provided by the `MAPLEAF.GNC.ControlSystems.ControlSystem`
'''

import abc

import numpy as np

from MAPLEAF.Motion import AeroParameters, AngularVelocity, Vector
from MAPLEAF.GNC import ConstantGainPIDController, ScheduledGainPIDController

__all__ = ["ConstantGainPIDRocketMomentController", "ScheduledGainPIDRocketMomentController", "MomentController", "IdealMomentController" ]

class MomentController(abc.ABC):
    @abc.abstractmethod
    def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt):
        ''' Should return a list [ desired x-axis, y-axis, and z-axis ] moments '''

class ScheduledGainPIDRocketMomentController(MomentController, ScheduledGainPIDController):
    def __init__(self, gainTableFilePath, keyColumnNames):
        '''
            Assumes the longitudinal (Pitch/Yaw) PID coefficients are in columns nKeyColumns:nKeyColumns+2
            Assumes the roll PID coefficients are in columns nKeyColumns+3:nKeyColumns+5
            Sample gain file: MAPLEAF/Examples/TabulatedData/testPIDCoeffs.txt
        '''
        self.keyFunctionList = [ AeroParameters.stringToAeroFunctionMap[x] for x in keyColumnNames ]
        nKeyColumns = len(keyColumnNames)
        ScheduledGainPIDController.__init__(self, gainTableFilePath, nKeyColumns, PCol=nKeyColumns, DCol=nKeyColumns+5)
        
    def updateCoefficientsFromGainTable(self, keyList):
        ''' Overriding parent class method to enable separate longitudinal and roll coefficients in a single controller '''
        Pxy, Ixy, Dxy, Pz, Iz, Dz = self._getPIDCoeffs(*keyList)

        # Coefficient for each of P, I, and D are: Longitudinal, Longitudinal, Roll
        # Operates the internal PID controller in vector-mode with numpy arrays (using their elementwise operations)
        P = np.array([Pxy, Pxy, Pz])
        I = np.array([Ixy, Ixy, Iz])
        D = np.array([Dxy, Dxy, Dz])
        self.updateCoefficients(P, I, D)

    def _getOrientationError(self, rocketState, targetOrientation):
        return np.array((targetOrientation / rocketState.orientation).toRotationVector())

    def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt):
        '''
            Inputs: 
                gainKeyList:        iterable of length nKeyColumns, containing the data required to interpolate the PIDxy and PIDz coefficients in the gain table
                rocketState:        must have .orientation attribute (Quaternion)
                targetOrientation:  (Quaternion)
                _:                  currently unused (time argument)
                dt:                 (numeric) time since last execution of the control system
        '''
        orientationError = self._getOrientationError(rocketState, targetOrientation)
        gainKeyList = AeroParameters.getAeroPropertiesList(self.keyFunctionList, rocketState, environment)
        self.updateCoefficientsFromGainTable(gainKeyList)
        return self.getNewSetPoint(orientationError, dt)

class ConstantGainPIDRocketMomentController(MomentController, ConstantGainPIDController):
    def __init__(self, Pxy, Ixy, Dxy, Pz, Iz, Dz):
        '''
            Constant PID coefficient controller
        '''
        ConstantGainPIDController.__init__(self)
        
        P = np.array([Pxy, Pxy, Pz])
        I = np.array([Ixy, Ixy, Iz])
        D = np.array([Dxy, Dxy, Dz])
        self.updateCoefficients(P,I,D)

    def _getOrientationError(self, rocketState, targetOrientation):
        return np.array((targetOrientation / rocketState.orientation).toRotationVector())

    def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt):
        '''
            Inputs: 
                gainKeyList:        iterable of length nKeyColumns, containing the data required to interpolate the PIDxy and PIDz coefficients in the gain table
                rocketState:        must have .orientation attribute (Quaternion)
                targetOrientation:  (Quaternion)
                _:                  currently unused (time argument)
                dt:                 (numeric) time since last execution of the control system
        '''
        orientationError = self._getOrientationError(rocketState, targetOrientation)
        return self.getNewSetPoint(orientationError, dt)

class IdealMomentController():
    def __init__(self, rocket):
        self.rocket = rocket

    def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt):
        """ Exactly match the desired target orientation and set the rockets angular velocity to zero """
        self.rocket.rigidBody.state.orientation = targetOrientation
        self.rocket.rigidBody.state.angularVelocity = AngularVelocity(rotationVector=Vector(0,0,0))

Classes

class ConstantGainPIDRocketMomentController (Pxy, Ixy, Dxy, Pz, Iz, Dz)

Helper class that provides a standard way to create an ABC using inheritance.

Constant PID coefficient controller

Expand source code
class ConstantGainPIDRocketMomentController(MomentController, ConstantGainPIDController):
    def __init__(self, Pxy, Ixy, Dxy, Pz, Iz, Dz):
        '''
            Constant PID coefficient controller
        '''
        ConstantGainPIDController.__init__(self)
        
        P = np.array([Pxy, Pxy, Pz])
        I = np.array([Ixy, Ixy, Iz])
        D = np.array([Dxy, Dxy, Dz])
        self.updateCoefficients(P,I,D)

    def _getOrientationError(self, rocketState, targetOrientation):
        return np.array((targetOrientation / rocketState.orientation).toRotationVector())

    def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt):
        '''
            Inputs: 
                gainKeyList:        iterable of length nKeyColumns, containing the data required to interpolate the PIDxy and PIDz coefficients in the gain table
                rocketState:        must have .orientation attribute (Quaternion)
                targetOrientation:  (Quaternion)
                _:                  currently unused (time argument)
                dt:                 (numeric) time since last execution of the control system
        '''
        orientationError = self._getOrientationError(rocketState, targetOrientation)
        return self.getNewSetPoint(orientationError, dt)

Ancestors

Methods

def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt)

Inputs: gainKeyList: iterable of length nKeyColumns, containing the data required to interpolate the PIDxy and PIDz coefficients in the gain table rocketState: must have .orientation attribute (Quaternion) targetOrientation: (Quaternion) _: currently unused (time argument) dt: (numeric) time since last execution of the control system

Expand source code
def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt):
    '''
        Inputs: 
            gainKeyList:        iterable of length nKeyColumns, containing the data required to interpolate the PIDxy and PIDz coefficients in the gain table
            rocketState:        must have .orientation attribute (Quaternion)
            targetOrientation:  (Quaternion)
            _:                  currently unused (time argument)
            dt:                 (numeric) time since last execution of the control system
    '''
    orientationError = self._getOrientationError(rocketState, targetOrientation)
    return self.getNewSetPoint(orientationError, dt)
class IdealMomentController (rocket)
Expand source code
class IdealMomentController():
    def __init__(self, rocket):
        self.rocket = rocket

    def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt):
        """ Exactly match the desired target orientation and set the rockets angular velocity to zero """
        self.rocket.rigidBody.state.orientation = targetOrientation
        self.rocket.rigidBody.state.angularVelocity = AngularVelocity(rotationVector=Vector(0,0,0))

Methods

def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt)

Exactly match the desired target orientation and set the rockets angular velocity to zero

Expand source code
def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt):
    """ Exactly match the desired target orientation and set the rockets angular velocity to zero """
    self.rocket.rigidBody.state.orientation = targetOrientation
    self.rocket.rigidBody.state.angularVelocity = AngularVelocity(rotationVector=Vector(0,0,0))
class MomentController

Helper class that provides a standard way to create an ABC using inheritance.

Expand source code
class MomentController(abc.ABC):
    @abc.abstractmethod
    def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt):
        ''' Should return a list [ desired x-axis, y-axis, and z-axis ] moments '''

Ancestors

  • abc.ABC

Subclasses

Methods

def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt)

Should return a list [ desired x-axis, y-axis, and z-axis ] moments

Expand source code
@abc.abstractmethod
def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt):
    ''' Should return a list [ desired x-axis, y-axis, and z-axis ] moments '''
class ScheduledGainPIDRocketMomentController (gainTableFilePath, keyColumnNames)

Helper class that provides a standard way to create an ABC using inheritance.

Assumes the longitudinal (Pitch/Yaw) PID coefficients are in columns nKeyColumns:nKeyColumns+2 Assumes the roll PID coefficients are in columns nKeyColumns+3:nKeyColumns+5 Sample gain file: MAPLEAF/Examples/TabulatedData/testPIDCoeffs.txt

Expand source code
class ScheduledGainPIDRocketMomentController(MomentController, ScheduledGainPIDController):
    def __init__(self, gainTableFilePath, keyColumnNames):
        '''
            Assumes the longitudinal (Pitch/Yaw) PID coefficients are in columns nKeyColumns:nKeyColumns+2
            Assumes the roll PID coefficients are in columns nKeyColumns+3:nKeyColumns+5
            Sample gain file: MAPLEAF/Examples/TabulatedData/testPIDCoeffs.txt
        '''
        self.keyFunctionList = [ AeroParameters.stringToAeroFunctionMap[x] for x in keyColumnNames ]
        nKeyColumns = len(keyColumnNames)
        ScheduledGainPIDController.__init__(self, gainTableFilePath, nKeyColumns, PCol=nKeyColumns, DCol=nKeyColumns+5)
        
    def updateCoefficientsFromGainTable(self, keyList):
        ''' Overriding parent class method to enable separate longitudinal and roll coefficients in a single controller '''
        Pxy, Ixy, Dxy, Pz, Iz, Dz = self._getPIDCoeffs(*keyList)

        # Coefficient for each of P, I, and D are: Longitudinal, Longitudinal, Roll
        # Operates the internal PID controller in vector-mode with numpy arrays (using their elementwise operations)
        P = np.array([Pxy, Pxy, Pz])
        I = np.array([Ixy, Ixy, Iz])
        D = np.array([Dxy, Dxy, Dz])
        self.updateCoefficients(P, I, D)

    def _getOrientationError(self, rocketState, targetOrientation):
        return np.array((targetOrientation / rocketState.orientation).toRotationVector())

    def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt):
        '''
            Inputs: 
                gainKeyList:        iterable of length nKeyColumns, containing the data required to interpolate the PIDxy and PIDz coefficients in the gain table
                rocketState:        must have .orientation attribute (Quaternion)
                targetOrientation:  (Quaternion)
                _:                  currently unused (time argument)
                dt:                 (numeric) time since last execution of the control system
        '''
        orientationError = self._getOrientationError(rocketState, targetOrientation)
        gainKeyList = AeroParameters.getAeroPropertiesList(self.keyFunctionList, rocketState, environment)
        self.updateCoefficientsFromGainTable(gainKeyList)
        return self.getNewSetPoint(orientationError, dt)

Ancestors

Methods

def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt)

Inputs: gainKeyList: iterable of length nKeyColumns, containing the data required to interpolate the PIDxy and PIDz coefficients in the gain table rocketState: must have .orientation attribute (Quaternion) targetOrientation: (Quaternion) _: currently unused (time argument) dt: (numeric) time since last execution of the control system

Expand source code
def getDesiredMoments(self, rocketState, environment, targetOrientation, time, dt):
    '''
        Inputs: 
            gainKeyList:        iterable of length nKeyColumns, containing the data required to interpolate the PIDxy and PIDz coefficients in the gain table
            rocketState:        must have .orientation attribute (Quaternion)
            targetOrientation:  (Quaternion)
            _:                  currently unused (time argument)
            dt:                 (numeric) time since last execution of the control system
    '''
    orientationError = self._getOrientationError(rocketState, targetOrientation)
    gainKeyList = AeroParameters.getAeroPropertiesList(self.keyFunctionList, rocketState, environment)
    self.updateCoefficientsFromGainTable(gainKeyList)
    return self.getNewSetPoint(orientationError, dt)
def updateCoefficientsFromGainTable(self, keyList)

Overriding parent class method to enable separate longitudinal and roll coefficients in a single controller

Expand source code
def updateCoefficientsFromGainTable(self, keyList):
    ''' Overriding parent class method to enable separate longitudinal and roll coefficients in a single controller '''
    Pxy, Ixy, Dxy, Pz, Iz, Dz = self._getPIDCoeffs(*keyList)

    # Coefficient for each of P, I, and D are: Longitudinal, Longitudinal, Roll
    # Operates the internal PID controller in vector-mode with numpy arrays (using their elementwise operations)
    P = np.array([Pxy, Pxy, Pz])
    I = np.array([Ixy, Ixy, Iz])
    D = np.array([Dxy, Dxy, Dz])
    self.updateCoefficients(P, I, D)