def testLQR(self, siso):
        """Call lqr()"""
        (K, S, E) = lqr(siso.ss1.A, siso.ss1.B, np.eye(2), np.eye(1))

        # Should work if [Q N;N' R] is positive semi-definite
        (K, S, E) = lqr(siso.ss2.A, siso.ss2.B, 10 * np.eye(3), np.eye(1),
                        [[1], [1], [2]])
示例#2
0
def newtonKleinman(A, B, Q, K, N):
    assert ((la.eig(A - B * K)[0]) < 0).min(
    ), 'initial gain K is not stabilizing, Newton-Kleinman is not guaranteed to converge!'
    Kopt, Popt, Eopt = mtl.lqr(A, B, Q, 1)
    assert (
        (Eopt < 0).min() or ((la.eig(Popt)[0]) > 0).min()
    ), 'There is no stabilizing solution to Riccati equation for provided (A,B,Q,R), your efforts are futile!'

    # P that corresponds to initial gain K
    P = mtl.lyap((A - np.dot(B, K)).transpose(),
                 (Q + np.dot(K.transpose(), K)))
    assert ((la.eig(P)[0]) > 0).min(), 'P iterate is not positive definite!'
    errorP = []
    errorP.append(la.norm(P - Popt))

    for i in range(N):
        '''Newton-Kleinman is repeated Lyapunov equation that yields iterates P. Each P that constitutes Lyapunov function x'Px '''
        P = mtl.lyap((A - np.dot(B, np.dot(B.transpose(), P))).transpose(),
                     (Q + np.dot(
                         np.dot(B.transpose(), P).transpose(),
                         np.dot(B.transpose(), P))))
        assert ((la.eig(P)[0]) >
                0).min(), 'P iterate is not positive definite!'
        errorP.append(la.norm(P - Popt))

    plt.plot(errorP, 'o')
    plt.grid()
    plt.show()
    pass
示例#3
0
    def calc_input(self, pendulum, reference_z=None):
        """
        Parameters
        -------------
        pendulum : pendulum class

        Returns
        ----------
        f : float in [N]
            input of the system
        """

        # freeze the state
        self._freeze_state(pendulum)
        self._freeze_weight(pendulum)

        K, P, e  = lqr(self.A, self.B, self.Q, self.R)
        
        state = np.array([[pendulum.z], [pendulum.th], [pendulum.v_z], [pendulum.v_th]])

        if reference_z is not None:
            state = np.array([[pendulum.z - reference_z], [pendulum.th], [pendulum.v_z], [pendulum.v_th]])

        f = - np.dot(K, state)

        return f
示例#4
0
def control_input(Alpha, Q, R, X, t):
	# Generate feasible trajectory
	Xd, Ud = feasible_trajectory(Alpha, t)
	x, y, theta = Xd
	omega_L, omega_R = Ud
	x = float(x)
	y = float(y)
	theta = float(theta)
	omega_L = float(omega_L)
	omega_R = float(omega_R)

	# Find controller using LQR at time t
	A = np.array([[0, 0, -r/2*np.sin(theta)*(omega_L+omega_R)],
				  [0, 0, r/2*np.cos(theta)*(omega_L+omega_R)],
				  [0, 0, 0]])
	B = np.array([[r/2*np.cos(theta), r/2*np.cos(theta)],
				  [r/2*np.sin(theta), r/2*np.sin(theta)],
				  [-r/L, r/L]])

	K, _, _ = mt.lqr(A, B, Q, R)

	# Compute control law
	U = Ud - K@(X - Xd)

	# Add input noise
	# U += np.random.uniform(-1.0, 1.0, size=(2, 1))*25

	# Limit the maximum voltage input
	U = np.clip(U, -50, 50)
	return U
示例#5
0
    def __init__(self, pendulum):
        # controllers

        alpha_0 = pendulum.p_j * (
            pendulum.p_m +
            pendulum.c_m) + pendulum.c_m * pendulum.p_m * (pendulum.p_l**2)
        inerter_mass = pendulum.p_j + pendulum.p_m * (pendulum.p_l**2)
        mass = pendulum.p_m + pendulum.c_m

        self.A = np.array([[0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0],
                           [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]])

        self.A[2, 1] = -(pendulum.p_m**2) * (pendulum.p_l**
                                             2) * pendulum.g / alpha_0
        self.A[2, 2] = -pendulum.c_mu * inerter_mass / alpha_0
        self.A[2, 3] = pendulum.p_mu * pendulum.p_m * pendulum.p_l / alpha_0

        self.A[3,
               1] = mass * pendulum.p_m * pendulum.p_l * pendulum.g / alpha_0
        self.A[3, 2] = pendulum.c_mu * pendulum.p_m * pendulum.p_l / alpha_0
        self.A[3, 3] = -pendulum.p_mu * mass / alpha_0

        self.B = np.array([[0.0], [0.0], [0.0], [0.0]])

        self.B[2, 0] = inerter_mass / alpha_0
        self.B[3, 0] = -pendulum.p_m * pendulum.p_l / alpha_0

        self.C = np.array([[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0]])

        self.R = 100.0

        self.Q = np.diag([10, 10, 10, 10])

        self.K, self.P, self.e = lqr(self.A, self.B, self.Q, self.R)
示例#6
0
def control_input(Alpha, Q, R, X, t):
    # Generate feasible trajectory
    Xd, Ud = feasible_trajectory(Alpha, t)
    x, y, theta, omega_L, omega_R = Xd
    V_L, V_R = Ud
    x = float(x)
    y = float(y)
    theta = float(theta)
    omega_L = float(omega_L)
    omega_R = float(omega_R)

    # Find controller using LQR at time t
    # Combine a transfer function from Voltage to omega
    # with ss representation from omega to state
    A = np.array([[
        0, 0, -r / 2 * np.sin(theta) * (omega_L + omega_R),
        r / 2 * np.cos(theta), r / 2 * np.cos(theta)
    ],
                  [
                      0, 0, r / 2 * np.cos(theta) * (omega_L + omega_R),
                      r / 2 * np.sin(theta), r / 2 * np.sin(theta)
                  ], [0, 0, 0, -r / L, r / L], [0, 0, 0, -1 / tau, 0],
                  [0, 0, 0, 0, -1 / tau]])
    B = np.array([[0, 0], [0, 0], [0, 0], [K_m / tau, 0], [0, K_m / tau]])

    # Check controllability and find controller using LQR only if controllable
    AB = np.zeros((A.shape[0], B.shape[1] * (A.shape[0] - 1)))
    for i in range(1, A.shape[0]):
        AB[:, i:i + 2] = np.linalg.matrix_power(A, i) @ B
    ctrb = np.hstack((B, AB))
    rank_ctrb = np.sum(np.linalg.svd(ctrb, compute_uv=False) > 1e-10)
    K = np.zeros((2, 5))
    if rank_ctrb == 5:
        K, _, _ = mt.lqr(A, B, Q, R)

    # Compute control law
    U = Ud - K @ (X - Xd)

    # Add input noise
    # U += np.random.uniform(-2.0, 2.0, size=(2, 1))

    # Limit the maximum voltage input
    U = np.clip(U, -12, 12)
    return U
示例#7
0
def control_input(Alpha, Q, R, X, t):
    # Generate feasible trajectory
    Xd, Ud = feasible_trajectory(Alpha, t)
    x, y, theta = Xd
    omega_L, omega_R = Ud
    x = float(x)
    y = float(y)
    theta = float(theta)
    omega_L = float(omega_L)
    omega_R = float(omega_R)

    # Find controller using LQR at time t
    A = np.array([[0, 0, -r / 2 * np.sin(theta) * (omega_L + omega_R)],
                  [0, 0, r / 2 * np.cos(theta) * (omega_L + omega_R)],
                  [0, 0, 0]])
    B = np.array([[r / 2 * np.cos(theta), r / 2 * np.cos(theta)],
                  [r / 2 * np.sin(theta), r / 2 * np.sin(theta)],
                  [-r / L, r / L]])

    K, _, _ = mt.lqr(A, B, Q, R)

    # Compute control law
    U = Ud - K @ (X - Xd)
    return U
示例#8
0
w1_offset_eql = 0
th2_offset_eql = -30
w2_offset_eql = 0

A_lin = np.matrix(A_Lin.A_lin(M1, M2, L1, L2, G, state_eql[0], state_eql[1],
                              state_eql[2], state_eql[3]),
                  dtype=np.float)
B_lin = np.matrix([0, 1, 0, 0]).T
C_lin = np.matrix(np.identity(len(A_lin)))
D_lin = np.matrix(np.zeros_like(B_lin))

#sys = ctr.ss(A_lin, B_lin, C_lin, D_lin)
sys = ctr.StateSpace(A_lin, B_lin, C_lin, D_lin)
Q = np.matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1000, 0], [0, 0, 0, 1000]])
R = 1
K, S, E = ctr.lqr(sys, Q, R)


def derivs(state, t):
    if Control == True:
        T_1 = -K.dot(state - state_eql)
        T_1 = T_1[0]
    elif Control == False:
        T_1 = 0

    dydx = np.zeros_like(state)
    dydx[0] = state[1]

    delta = state[2] - state[0]
    den1 = (M1 + M2) * L1 - M2 * L1 * cos(delta) * cos(delta)
    dydx[1] = ((M2 * L1 * state[1] * state[1] * sin(delta) * cos(delta) +
示例#9
0
    '''3D case '''
    if case == '3D':
        A = np.array([[-1, 2, -1], [2.2, 1.7, -1], [0.5, 0.7, -1]])
        A1 = np.array([[-1, 2, -1], [2.2, 1.7, -1], [0.5, 0.7, -1]])
        eigs = la.eig(A)
        eval = eigs[0]
        evec = eigs[1]
        print('eigen values of A:\n', eval)
        B = np.array([[2], [1.6], [3]])
        B1 = np.array([[2], [1.6], [0.9]])
        Q = np.array([[5, 0, 0], [0, 8, 0], [0, 0, 1]])
        q = np.random.rand(3, 3)
        Qrand = np.dot(q.transpose(), q)

    #K0,X,E = mtl.lqr(A,B, Qrand,1)
    K0, X, E = mtl.lqr(A, B, Q, 1)

    #eigs = la.eig(A-np.dot(B,K0));    eval = eigs[0];    evec = eigs[1];    print('eigen values of Acl:\n', eval)

    #newtonKleinman(A, B, Q, K0, 10)
    #inverseReinfLearning1(A, B, Q, 10)
    algorithmProperties = {
        'updateP': 'Ricc',
        'alpha': 1.0,
        'isQDiagonal': False
    }
    inverseReinfLearning(A, B, Q, 30, p=algorithmProperties, debugMode=True)
    #inverseReinfLearning_Lyap1(A,B,Q,50)

    print('Main finished')
示例#10
0
    Cx = np.cos(x[2])
    D = m * L * L * (M + m * (1 - Cx**2))
    dx = np.zeros(4)
    dx[0] = x[1]
    dx[1] = (1 / D) * (-(m**2) * (L**2) * g * Cx * Sx + m * (L**2) *
                       (m * L *
                        (x[3]**2) * Sx - d * x[1])) + m * L * L * (1 / D) * u
    dx[2] = x[3]
    dx[3] = (1 / D) * ((m + M) * m * g * L * Sx - m * L * Cx *
                       (m * L *
                        (x[3]**2) * Sx - d * x[1])) - m * L * Cx * (1 / D) * u
    return dx


#%% Traditional LQR
K = lqr(A, B, Q, R)[0]

#%%
x0 = np.array([[-1], [0], [np.pi], [0]])

perturbation = np.array([
    [0],
    [0],
    [np.random.normal(0, 0.1)],  # np.random.normal(0, 0.05)
    [0]
])
x = x0 + perturbation

w_r = np.array([[1], [0], [np.pi], [0]])

action_range = np.arange(-500, 500)
示例#11
0
    def velocity(self):
        pub = rospy.Publisher('/cmd_vel', Twist, queue_size=100)
        rospy.init_node('controller_kay')
        rate = rospy.Rate(100)  # 10hz

        #controller gains
        alpha_v = 0.4
        alpha_w = 0.4
        lambda_v = 0.2
        lambda_w = 0.2

        kv1 = 0.1
        kv0 = 0.05
        kw1 = 0.01
        kw0 = 1
        pi = np.pi
        dt = 0.012

        while not rospy.is_shutdown():
            #xr       = controller.path[0]
            #yr       = controller.path[1]
            #theta_r  = controller.path[2]
            #refVel   = controller.path[3]
            #refOmega = controller.path[4]

            curPose = [
                controller.xs, controller.ys,
                np.mod(controller.yaw, 6.28), controller.vs, controller.ws
            ]
            refPose = controller.path[:3]
            refVel = np.matrix(controller.path[-2:])

            t = (np.matrix([refPose]) - np.matrix([curPose[:3]]))
            t = np.transpose(t)
            x = t[2, 0]

            if (-3.14 > x >= -6.28):
                x = x + 6.28
                t[2, 0] = x
            elif 3.14 < x <= 6.28:
                x = x - 6.28
                t[2, 0] = x

            p_e = np.matrix([[math.cos(curPose[2]),
                              math.sin(curPose[2]), 0],
                             [-math.sin(curPose[2]),
                              math.cos(curPose[2]), 0], [0, 0, 1]]) * t

            # kayacan tracking controller
            A = np.matrix([[0, curPose[4], 0], [-curPose[4], 0, refVel[0, 0]],
                           [0, 0, 0]])

            B = np.matrix([[1, 0], [0, 0], [0, 1]])

            Q = np.diag([1000, 1000, 5])
            #[1000,1000,0.0005]
            R = np.diag([100, 1])
            #100,0.1

            K = lqr(A, B, Q, R)

            u_b = K[0] * p_e

            #Forward learning rate controller

            e1_dot = curPose[4] * p_e[1] - curPose[3] + refVel[0, 0]
            e2_dot = -curPose[4] * p_e[0] + refVel[0, 0] * p_e[2]
            e2_dot2 = -p_e[1] * refVel[0, 1]**2 + refVel[
                0, 1] * curPose[3] - refVel[0, 0] * curPose[4]

            kv1_dot = alpha_v * refVel[0, 0] * (e1_dot + lambda_v * p_e[0])
            kv0_dot = alpha_v * (e1_dot + lambda_v * p_e[0])
            kw1_dot = alpha_w * refVel[0, 0] * refVel[0, 1] * (
                e2_dot2 + 2 * lambda_w * e2_dot + lambda_w**2 * p_e[1])
            kw0_dot = alpha_w * refVel[0, 0] * (
                e2_dot2 + 2 * lambda_w * e2_dot + lambda_w**2 * p_e[1])

            kv1 = kv1 + kv1_dot * dt
            kv0 = kv0 + kv0_dot * dt
            kw1 = kw1 + kw1_dot * dt
            kw0 = kw0 + kw0_dot * dt

            vf = refVel[0, 0] * kv1 + kv0
            wf = refVel[0, 1] * kw1 + kw0

            v = u_b[0, 0] + vf
            w = u_b[1, 0] + wf

            v = min(0.3, abs(v))
            w = min(max(-3.5, w), 3.5)

            vel_msg = Twist()
            vel_msg.linear.x = v
            vel_msg.angular.z = w

            print(t[2, 0], p_e[2, 0])

            #rospy.loginfo(vel_msg)
            pub.publish(vel_msg)

            rate.sleep()
示例#12
0
def LTI_CLQE(system,saveComputation):

    A = system.A
    B = system.B
    C = system.C
    G = system.G
    g = system.g

    tol = system.tol

    size_x = A.shape[1]
    size_u = B.shape[1]
    size_y = C.shape[0]
    size_l = G.shape[0]

    G = svd_suit(G, tol)
    N = G.null 
    R = G.row_space #E = [N, R]
    

    ##################################################################
    # Derivative-State Constraints and Effective States 
    #D1*dx/dt + D2*x = 0
    dof = int(size_x/2)
    D1 = np.hstack([np.eye(dof), np.zeros((dof,dof))])
    D2 = np.hstack([np.zeros((dof,dof)), np.eye(dof)])

    GG = vertcat(horzcat(G.M, np.zeros((size_l, size_x))),horzcat(D1, D2))
    GG = svd_suit(GG, tol)
  
    NA = svd_suit(N.T@A,tol)
    temp = svd_suit(np.hstack([NA.null,N,GG.row_space[size_x:,:]]),tol)

    R_used = temp.left_null

    size_z    = N.shape[1]
    size_zeta = R_used.shape[1]
    size_chi   = size_z+size_zeta

    E = np.hstack([N, R_used])
    
    N1 = np.hstack([N, np.zeros((size_x, size_zeta))])

    
    ##################################################################
    class OutStruct:
        def __init__(self):
            self.matrix_chi = None
            self.matrix_u= None
            self.matrix_y= None
            self.vector = None
            self.map= None

    
    class Output:
        def __init__(self):
            self.sizes = None 
            self.initialConditions = None
            self.desired = None
            self.closed_loop = None
            self.matrices = None
            self.observer = OutStruct()
            self.controller = OutStruct()

    output = Output()

    output.sizes = {'size_x': size_x, 'size_u': size_u, 'size_y': size_y, 'size_l': size_l,
        'size_z': size_z, 'size_zeta': size_zeta, 'size_xi': size_chi}

    ##################################################################
    if system.controllerSettings is not None:
        if system.controllerSettings.Q.shape[1] == 1:
            costQ = np.diag(system.controllerSettings.Q[:size_z,:].squeeze())
        else:
            costQ = np.diag(system.controllerSettings.Q)
        
        if system.controllerSettings.R.shape[1] == 1:
            costR = np.diag(system.controllerSettings.R[:size_z].squeeze())
        else:
            costR = np.diag(system.controllerSettings.R)
        
        Kz = lqr(N.T@A@N, N.T@B, costQ, costR)[0]
    else:
        p = system.controllerSettings.poles[:N.shape[1]]
        Kz = place(N.T@A@N, N.T@B, p)
    
    if system.observerSettings is not None:
        if system.observerSettings.Q.shape[1] == 1:
            costQ = np.diag(system.observerSettings.Q[:size_z].squeeze())
        else:
            costQ = np.diag(system.observerSettings.Q)
        
        if system.observerSettings.R.shape[1] == 1:
            costR = np.diag(system.observerSettings.R[:size_z].squeeze())
        else:
            costR = np.diag(system.observerSettings.R)
        
        L = lqr((N1.T@A@E).T, [email protected], costQ, costR)[0]
    else:
        p = system.observerSettings.poles[:E.shape[1]]
        L = place((N1.T@A@E).T, [email protected], p)

    L = L.T
    


    Kzeta = np.linalg.pinv(N.T@B) @ N.T@A@R_used
    K = np.hstack((Kz, Kzeta))
    ##################################################################
    #observer structure

    output.controller.matrix_chi = K
    output.observer.matrix_chi = N1.T@A@E - L@C@E
    output.observer.matrix_u = N1.T@B
    output.observer.matrix_y = L
    output.observer.vector = N1.T@g

    output.observer.map = E

    output.matrices = {'G': G, 'N': N, 'R': R, 'R_used': R_used, 'E': E, 
        'Kz': Kz, 'Kzeta': Kzeta, 'K': K, 'L': L, 
        'N1': N1}
        
    if saveComputation==2:
        return output

    ##################################################################
    ### desired

    class Desired:
        class Derivation:
            def __init__(self):
                self.NB = None
                self.NB_projector= None
                self.M = None
                self.zdz_corrected = None

        def __init__(self):
            self.x = None
            self.dx = None 
            self.z   = None
            self.dz = None
            self.z_corrected= None
            self.dz_corrected = None
            self.u_corrected = None
            self.derivation = Desired.Derivation()



    desired = Desired()
    desired.x  = system.x_desired
    desired.dx = system.dx_desired
    desired.z = [email protected]
    desired.dz = [email protected] 

    desired.derivation.NB = svd_suit(N.T@B,tol)
    desired.derivation.NB_projector = desired.derivation.NB.left_null @ desired.derivation.NB.left_null.T

    desired.derivation.M = svd_suit(np.hstack([[email protected]@A@N, desired.derivation.NB_projector]), tol)
    desired.derivation.zdz_corrected = [email protected][email protected]@g + [email protected] @ np.vstack([desired.z, desired.dz])

    desired.z_corrected  = desired.derivation.zdz_corrected[:size_z]
    desired.dz_corrected = desired.derivation.zdz_corrected[size_z:]

    if np.linalg.norm( [email protected]_null.T@
            (desired.dz_corrected - N.T@A@[email protected]_corrected - N.T@g) ) < tol:

        desired.u_corrected = desired.derivation.NB.pinv @ (desired.dz_corrected - N.T@A@[email protected]_corrected - N.T@g)
        output.controller.vector = desired.u_corrected

    else:
        raise Warning('cannot create a node')
    
    if saveComputation == 1:
        output.desired = desired
        return output

    ##################################################################
    ### IC

    class InitialConditions:
        def __init__(self):
            self.x 
            self.z
            self.zeta 
            self.chiEstimateRandom

    x_initial = system.x_initial

    initialConditions = InitialConditions()

    initialConditions.x    = x_initial
    initialConditions.z    = N.T@x_initial
    initialConditions.zeta = R_used.T@x_initial

    InitialConditions.chi_estimate_random = 0.01*np.random.randn(size_chi, 1) 

    output.initialConditions = initialConditions

    zeta = initialConditions.zeta

    u_des = desired.u_corrected
    z_des = desired.z_corrected 
    x_des = N@z_des + R_used@zeta

    desired.zeta_corrected = zeta
    desired.x_corrected    = x_des

    output.desired = desired

    ##################################################################
    ### Projected LTI in z-chi coordinates
    class ClosedLoop:
        class Coords:
            def __init__(self):
                self.matrix = None
                self.vector = None
                self.ode_func = None
                self.Y0 = None
                self.M = None
        
        
        def __init__(self):
            self.z_chi = ClosedLoop.Coords()
            self.x_chi = ClosedLoop.Coords()

    closed_loop = ClosedLoop()

    closed_loop.z_chi.matrix = np.vstack(np.hstack([N.T@A@N,   -N.T@B@K]),
                                np.hstack([L@C@N,     (N1.T@A@E - N1.T@B@K - L@C@E)]))
        
    closed_loop.z_chi.vector = np.vstack([N.T@A@R_used@zeta + N.T @B@Kz@z_des + N.T @B@u_des + N.T @g,
                                L@C@R_used@zeta  + N1.T@B@Kz@z_des + N1.T@B@u_des + N1.T@g])
                    

    closed_loop.z_chi.ode_fnc = lambda y:  closed_loop.z_chi.matrix @ y + closed_loop.z_xi.vector                       
    closed_loop.z_chi.Y0 = np.hstack([initialConditions.z,initialConditions.chi_estimate_random])

    ##################################################################
    ### LTI in x-chi coordinates


    closed_loop.x_chi.M = np.vstack([
                        np.hstack([np.eye(size_x), np.zeros((size_x, size_chi)),   -R]),
                        np.hstack([np.zeros((size_chi, size_x)), np.eye((size_chi,size_chi)),np.zeros((size_chi, size_l))]),
                        np.hstack([G.M,np.zeros((size_l, size_chi)),np.zeros((size_l, size_l))])
                        ])

    iM = np.linalg.pinv(closed_loop.x_chi.M)
    iM11 = iM[:(size_x+size_chi), :(size_x+size_chi)]

    closed_loop.x_chi.matrix = [email protected]([np.hstack([A,     -B@K]),
                                    np.hstack([L@C,    (N1.T@A@E - N1.T@B@K - L@C@E)])])
        

    closed_loop.x_chi.vector = [email protected]([B@Kz@z_des + B@u_des+ g,N1.T@B@Kz@z_des + N1.T@B@u_des + N1.T@g])       


    closed_loop.x_chi.ode_fnc = lambda y:  closed_loop.x_chi.matrix @ y + closed_loop.x_xi.vector
    closed_loop.x_chi.Y0 = np.vstack([initialConditions.x, initialConditions.chi_estimate_random]) 

    output.closed_loop = closed_loop

    return output