Skip to content
Snippets Groups Projects
simple_planar_integrator.py 4.32 KiB
Newer Older
  • Learn to ignore specific revisions
  • """
    Use the Newton-Euler equations and simplifications resulting from:
    
    1) Object motion occurs only in 2d plane
    - cross product formulas are simplified
    - torques restricted to the z-axis (following right-handed axes, plane is xy)
    2) Moment of inertia is a multiple of identity matrix
    - angular momentum is zero
    
    Object state defined by:
    
    x_t: 6, | (p_t, v_t, \theta_t, \omega_t)
    p_t: 2, | 2d position of center of mass [m]
    v_t: 2, | velocity of center of mass [m/s]
    \theta_t: yaw [rad]
    \omega_t: yaw rate [rad/s]
    
    Motion of rigid body is determined by thrusters that apply force u_i
    """
    import numpy as np
    from scipy import linalg as la
    from misc import matrix_building as mb
    
    
    class NoDragCts(object):
        """
        Bc = ( 0_{2,k}   =  ( 0_{2,k}
               B_t            rot(\theta_t)f/m
               0_{1,k}        0_{1,k}
               c'      )      c'      )
        where c'u = 1/i_m \sum_{i=1}^n (-r_{i,2} ; r{i,1})'f_i u_i
        The interpretation is that Bc applies forces for linear momentum
    
        in the global frame using current rotation, and torques in the local frame
    
        since no flips result from rotations in the plane.
        """
    
        def __init__(self, mounted_thruster_model):
            self.m = 6
            self.Ac = np.zeros((self.m, self.m))
            self.Ac[:2, 2:4] = np.eye(2)
            self.Ac[4, -1] = 1.
            f = mounted_thruster_model.f
            r = mounted_thruster_model.r
            self.n = f.shape[1]
            self.b_part = 1/mounted_thruster_model.m * f
            self.Bc_t = np.zeros((self.m, self.n))
            self.Bc_t[-1, :] = (-r[1, :] * f[0, :] + r[0, :] * f[1, :]) / \
                mounted_thruster_model.im
    
        def step(self, x_t, u_t):
    
            operators = self.get_process_operators(x_t)
            A, B_t = operators['A'], operators['B']
            x_dot = A.dot(x_t) + B_t.dot(u_t)
    
        def get_process_operators(self, x_t):
    
            Return operators which may be based on current state
    
            :param x_t:
    
            :return: dict{A, B(x_t)}
    
            B_t = self.Bc_t
            B_t[2:4, :] = mb.rot_2d(x_t[4]).dot(self.b_part)
            return dict(A=self.Ac, B=B_t)
    
    
        def get_mn(self):
            return self.m, self.n
    
    
    class AccelApproxDragCts(object):
        """
        Simulate drag by exponential decay to velocity, angular velocity
        """
        def __init__(self, no_drag_cts_model, alpha):
            """
            :param no_drag_cts_model:
            :param alpha: in (0, 1) | 1 == no drag model
            """
            no_drag_cts_model.Ac[:2, 2:4] = np.eye(2) * alpha
            no_drag_cts_model.Ac[4, -1] = 1. * alpha
            self.no_drag_cts_model = no_drag_cts_model
            self.alpha = alpha
    
        def step(self, x_t, u_t):
    
            operators = self.get_process_operators(x_t)
            A, B_t = operators['A'], operators['B']
            x_dot = A.dot(x_t) + B_t.dot(u_t)
    
        def get_process_operators(self, x_t):
            return self.no_drag_cts_model.get_process_operators(x_t)
    
    
        def get_mn(self):
            return self.no_drag_cts_model.get_mn()
    
    
    class ZeroOrderHoldDiscrete(object):
        """
        Use ZOH for discretization.
        - (= assume control u_t held constant until next sample time)
        - This is exact for linear time invariant systems (A, B do not vary with time).
        For the continuous equation
        x_dot(t) = Ax(t) + Bu(t),
        discretize as
        x_{t+1} = A_d x_t + B_d u_t,
        where the system matrices are given by
        A_d = expm{A dt}
        B_d = (itg_{tau=0}^{dt} expm{A tau} dtau) B
        """
    
        def __init__(self, cts_model, dt):
            """
            :param cts_model:
            :param dt: sampling period [s]
            """
            self.cts_model = cts_model
            self.dt = dt
            self.Ad_t = np.zeros(())
            self.Bd_t = np.zeros(())
    
        def step(self, x_t, u_t):
    
            operators = self.get_process_operators(x_t)
            Ad_t, Bd_t = operators['A'], operators['B']
            x_p = Ad_t.dot(x_t) + Bd_t.dot(u_t)
    
            return x_p
    
    
        def get_process_operators(self, x_t):
            operators = self.cts_model.get_process_operators(x_t)
            Ac_t, Bc_t = operators['A'], operators['B']
    
            m = Ac_t.shape[0]
            M = np.block([[Ac_t, np.eye(m)],
                          [np.zeros_like(Ac_t), np.zeros_like(Ac_t)]])
            eM = la.expm(M * self.dt)
            self.Ad_t = eM[0:m, 0:m]
            self.Bd_t = eM[0:m, m:].dot(Bc_t)
    
            return dict(A=self.Ad_t, B=self.Bd_t)
    
    
        def get_mn(self):
            return self.cts_model.get_mn()