使用python代替matlab仿真线性控制系统(倒立摆)

matlab可以仿真很多控制系统,其实python也有这种中功能。不仅是基础的自动控制原理所涉及的定理如伯德图,奈奎斯特曲线,pid之类的能够仿真,较为复杂的线性系统理论上面的一些原理也可以仿真。

这是对旋转式倒立摆进行一个简单的介绍

在这里插入图片描述
随后对倒立摆进行建模,利用牛顿定律和拉格朗日定律建模
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
以上是对于倒立摆系统进行简单的介绍和matlab仿真,下面程序是将matlab转换成python的
除了使用numpy库和matplotlib库之外,还用到control和slycot,这个库比较难装,需要用anaconda添加清华大学的镜像pip安装,别的方法试了试都不好用,要么装不上要么装上了用不了。

// A code block
var foo = 'bar';
import control
import numpy as np
import matplotlib.pyplot as plt
A = np.array([[0,0,1,0],[0,0,0,1],[65.875,-16.875,-0.00010191,-1.248e-006],[-82.212,82.212,-2.0918e-005,-1e-006]])
b = np.array([[0],[0],[5.2184],[-6.5125]])
c = np.mat([[1,0,0,0],[0,1,0,0]])
d = np.array([[0],[0]])
P = np.array([-5+2j,-5-2j,-8-6j,-8+6j])#desire pole
sys = control.StateSpace(A, b, c, d)#现代控制系统的基本形式
sysd = sys.sample(0.5, method='bilinear')
print(sys)
print(np.linalg.matrix_rank(control.ctrb(A, b)))
print(np.linalg.matrix_rank(control.obsv(A, c)))
h,i = np.linalg.eig(A)
print(format(h)) #特征值
print(control.place(A, b, P))
P1 = np.array([-50+3j,-50-3j,-80-6j,-80+6j])
print(control.place(A, b, P))#get k
L = control.place(A.transpose(),c.transpose(), P1)
print(L.transpose())#观测矩阵极点



非线性仿真
下面展示一些 内联代码片

// A code block
var foo = 'bar';
// An highlighted block
import numpy as np
import math
from scipy.integrate import odeint
from pylab import *
import matplotlib.pyplot as plt
m1=0.200
m2=0.052 
L1=0.10
L2=0.12 
r=0.20 
km=0.0236
ke=0.2865
g=9.8 
J1=0.004 
J2=0.001 
f1=0.01 	
f2=0.001
a=J1+m2*r*r 
b=m2*r*L2
c=J2 
d=f1+km*ke 
e=(m1*L1+m2*r)*g  
f=f2  
h=m2*L2*g
print(a,b,c,d,e,f,h)
def dflun(y,t,a,b,c,d,e,f,g,h):
	sita1,sita2,w1,w2 = y
	K = np.mat([[  0.58498033 ,-69.40930131 , -5.2454833 ,  -8.19545906]])
	xx = np.array([[sita1],[sita2],[w1],[w2]])
	us = np.dot(-K,xx)
	u = us[0,0]
	dydt = [w1,w2,((-d*c)*w1+(f*b*math.cos(sita2-sita1))*w2+b*b*math.sin(sita2-sita1)*math.cos(sita2-sita1)*w1*w1-b*c*math.sin(sita1-sita2)*w2*w2+e*c*math.sin(sita1)-h*b*math.sin(sita2)*math.cos(sita2-sita1)+km*c*u)/(a*c-b*b*math.cos(sita1-sita2)*math.cos(sita2-sita1)),((d*b*math.cos(sita1-sita2))*w1-(a*f)*w2-a*b*math.sin(sita2-sita1)*w1*w1+b*b*math.sin(sita1-sita2)*math.cos(sita1-sita2)*w2*w2-e*b*math.sin(sita1)*math.cos(sita1-sita2)+a*h*math.sin(sita2)-b*math.cos(sita1-sita2)*km*u)/(a*c-b*b*math.cos(sita1-sita2)*math.cos(sita2-sita1))]
	return dydt
y0=[-0.1,0.05,0,0]
t = np.linspace(0, 10)
sol = odeint(dflun, y0, t, args=(a, b,c,d,e,f,g,h))#将微分方程解,该函数官方库或者百度有详细的解释
plt.plot(t, sol[:, 0], 'b', label='angle1(t)')
plt.plot(t, sol[:, 1], 'g', label='angle2(t)')
plt.plot(t, sol[:, 2], 'r', label='w1(t)')
plt.plot(t, sol[:, 3], 'y', label='w2(t)')
plt.legend(loc='best')
plt.xlabel('t')
plt.grid()
plt.show()

最后画出来的
在这里插入图片描述
还可以画控制反馈阶跃响应的图来对齐进行分析

下面展示一些 内联代码片

// A code block
var foo = 'bar';
// An highlighted block
import control
import numpy as np
import matplotlib.pyplot as plt
import slycot
A = np.array([[0,0,1,0],[0,0,0,1],[65.875,-16.875,-0.00010191,-1.248e-006],[-82.212,82.212,-2.0918e-005,-1e-006]])
b = np.array([[0],[0],[5.2184],[-6.5125]])
c = np.mat([[1,0,0,0],[0,1,0,0]])
d = np.array([[0],[0]])
P = np.array([-5+3j,-5-3j,-8-7j,-8+7j])#desire 
K = np.array([[  3.56808799, -59.64866393,  -4.15501195 , -7.01457373]])
v = A-np.dot(b,K)
#sys = control.ss(v, b, c, d)#feedback sysrtem
sys = control.ss(A, b, c, d)#non-feedback system

#sysd = sys.sample(0.5, method='bilinear')
#print(sys)
#print(np.linalg.matrix_rank(control.ctrb(A, b)))
#print(np.linalg.matrix_rank(control.obsv(A, c)))
h,i = np.linalg.eig(A)
#print(format(h))
#print(control.place(A, b, P))
P1 = np.array([-50+3j,-50-3j,-80-6j,-80+6j])
#print(control.place(A, b, P))#get k
L = control.place(A.transpose(),c.transpose(), P1)
#print(L.transpose())
syss = control.tf(sys)
tfinal = 5
d = np.linspace(0, 1, 500)
t, rec = control.step_response(sys, d,)
plt.plot(t, rec[0,:],'g',label='angle1')
plt.plot(t, rec[1,:],'b',label='angle2')
plt.legend(loc='best')
plt.xlabel('t')
plt.ylabel('angle')

以上我们的仿真任务就完成了,为了更好的说明极点的选取与超调量之间的关系,我们还可以用极点实部为x轴,虚部为y轴,其中一个超调为z坐标画出散点图来
下面展示一些 内联代码片

// A code block
var foo = 'bar';
// An highlighted block
import numpy as np
import math
from scipy.integrate import odeint
from pylab import *
import matplotlib.pyplot as plt
import control

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import pandas as pd
fig = plt.figure()
ax = Axes3D(fig)
for real in range(1,7):
    for imaginary in range(2,7):
        m1=0.200
        m2=0.052 
        L1=0.10
        L2=0.12 
        r=0.20 
        km=0.0236
        ke=0.2865
        g=9.8 
        J1=0.004 
        J2=0.001 
        f1=0.01 	
        f2=0.001
        a=J1+m2*r*r 
        b=m2*r*L2
        c=J2 
        d=f1+km*ke 
        e=(m1*L1+m2*r)*g  
        f=f2  
        h=m2*L2*g
        A = np.array([[0,0,1,0],[0,0,0,1],[65.875,-16.875,-0.00010191,-1.248e-006],[-82.212,82.212,-2.0918e-005,-1e-006]])
        bb = np.array([[0],[0],[5.2184],[-6.5125]])
        cc = np.mat([[1,0,0,0],[0,1,0,0]])
        dd = np.array([[0],[0]])
        P = np.array([-real+imaginary*1j,-real-imaginary*1j,-8-6j,-8+6j])
        sys = control.StateSpace(A, bb, cc, dd)
        #sysd = sys.sample(0.5, method='bilinear')
        KS = control.place(A,bb,P)
        K0=KS[0,0]
        K1=KS[0,1]
        K2=KS[0,2]
        K3=KS[0,3]
        def dflun(y,t,a,b,c,d,e,f,h,K0,K1,K2,K3):
            sita1,sita2,w1,w2 = y
            K=np.mat([K0,K1,K2,K3])
            xx = np.array([[sita1],[sita2],[w1],[w2]])
            us = np.dot(-K,xx)
            u = us[0,0]
            dydt = [w1,w2,((-d*c)*w1+(f*b*math.cos(sita2-sita1))*w2+b*b*math.sin(sita2-sita1)*math.cos(sita2-sita1)*w1*w1-b*c*math.sin(sita1-sita2)*w2*w2+e*c*math.sin(sita1)-h*b*math.sin(sita2)*math.cos(sita2-sita1)+km*c*u)/(a*c-b*b*math.cos(sita1-sita2)*math.cos(sita2-sita1)),((d*b*math.cos(sita1-sita2))*w1-(a*f)*w2-a*b*math.sin(sita2-sita1)*w1*w1+b*b*math.sin(sita1-sita2)*math.cos(sita1-sita2)*w2*w2-e*b*math.sin(sita1)*math.cos(sita1-sita2)+a*h*math.sin(sita2)-b*math.cos(sita1-sita2)*km*u)/(a*c-b*b*math.cos(sita1-sita2)*math.cos(sita2-sita1))]
            return dydt
        y0=[-0.1,0.05,0,0]
        t = np.linspace(0, 10)
        sol = odeint(dflun, y0, t,args=(a,b,c,d,e,f,h,K0,K1,K2,K3))
       # plt.plot(t, sol[:, 0], 'b', label='angle1(t)')
      #  print('angle1',max(sol[:, 0])),
        #plt.plot(1,1,1,1, 1, 1, markevery=[1,1,1])  
        #ax.scatter(real, imaginary,max(sol[:, 0]) , c='r', label=format(max(sol[:, 0]), '.4f'))
        ax.scatter(real, imaginary,max(sol[:, 0]) , c='r')
        ax.text(real,imaginary,max(sol[:, 0]),format(max(sol[:, 0]), '.4f'))
        #ax.annotate('abc',(1,1))     
       # plt.text(-2,2,1,r'$this\ is\ a\ function$',fontdict={'size':12,'color':'purple'}
        # plt.text(5,1, 10, t, fontsize=18, style='oblique', ha='center',va='top',wrap=True)
        #plt.plot(t, sol[:, 1], 'g', label='angle2(t)')
    #plt.plot(t, sol[:, 2], 'r', label='w1(t)')
    #plt.plot(t, sol[:, 3], 'y', label='w2(t)')
    #plt.legend(loc='best')
    #plt.xlabel('t')
   # plt.grid()

ax.legend(loc='best')
ax.set_xlabel('real part')
ax.set_ylabel('imaginary part')
ax.set_zlabel('angel 1 max')
plt.show()

最后画出来的图如下,这样分析起来就简便多了
在这里插入图片描述
以上只是简单的介绍,如果想查看仿真控制系统的详细信息请看:https://python-control.readthedocs.io/en/latest/control.html
关于对旋转式倒立摆介绍这一部分转载至
转至线性系统理论 第一版 科学出版社 陆军,王晓凌编著

  • 0
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 以下是使用Python编写使用PID控制一阶直线倒立摆的代码: ``` import time # Define initial parameters theta = 0 # Angle of the pendulum (in degrees) omega = 0 # Angular velocity of the pendulum (in degrees per second) Kp = 5 # Proportional gain Ki = 0.05 # Integral gain Kd = 2 # Derivative gain last_error = 0 # Last error (for calculating the derivative term) error_sum = 0 # Error sum (for calculating the integral term) # Define function to calculate the control signal (u) def calc_control_signal(theta, omega, Kp, Ki, Kd, last_error, error_sum): # Calculate the error (setpoint - current state) error = 0 - theta # Calculate the proportional term P = Kp * error # Calculate the integral term (use anti-windup to limit the effect of saturation) error_sum += error if error_sum > 100: error_sum = 100 elif error_sum < -100: error_sum = -100 I = Ki * error_sum # Calculate the derivative term D = Kd * (error - last_error) # Calculate the control signal (u) u = P + I + D # Store the last error last_error = error return u, last_error, error_sum # Simulate the system for 10 seconds start_time = time.time() while time.time() - start_time < 10: # Calculate the control signal u, last_error, error_sum = calc_control_signal(theta, omega, Kp, Ki, Kd, last_error, error_sum) # Update the angular velocity and angle of the pendulum omega += u theta += omega # Print the current state of the system print("theta: ", theta, "omega: ", omega) time.sleep(0.1) ``` 注意:该代码仅为示例,实际的系统可能包含更多参数和复杂性。 ### 回答2: PID控制器(Proportional-Integral-Derivative)是一种常见的控制算法,其中包括三个部分:比例项、积分项和微分项。使用PID控制器可以对一阶直线倒立摆进行控制。 下面是使用Python编写的PID控制一阶直线倒立摆的代码: ```python import time class PIDController: def __init__(self, Kp, Ki, Kd): self.Kp = Kp self.Ki = Ki self.Kd = Kd self.last_error = 0 self.integral = 0 def update(self, setpoint, measured_value): error = setpoint - measured_value self.integral += error derivative = error - self.last_error output = self.Kp * error + self.Ki * self.integral + self.Kd * derivative self.last_error = error return output def main(): # 设置PID参数 Kp = 1.0 Ki = 0.1 Kd = 0.2 # 实例化PID控制器 pid_controller = PIDController(Kp, Ki, Kd) # 设置初始状态 setpoint = 0 # 目标位置 measured_value = 5 # 测量值 # 模拟运行 for _ in range(10): output = pid_controller.update(setpoint, measured_value) print("PID输出: ", output) # 模拟执行控制动作,更新测量值 measured_value += output time.sleep(1) if __name__ == "__main__": main() ``` 在上述代码中,首先定义了一个`PIDController`类,包含了比例项、积分项和微分项,以及相应的参数。`update`方法用于更新PID控制器的输出值。在`main`函数中,设置了初始状态,并利用PID控制器进行模拟运行。每次迭代,都会输出PID的输出值,并模拟执行控制动作,然后隔1秒钟更新测量值。 请根据实际需求调整PID参数和模拟运行的次数,以达到对直线倒立摆的控制。 ### 回答3: 直线倒立摆是一种控制系统,用于维持一个竖直直线的平衡。在这种系统中,存在一个质点悬挂在一个可以垂直移动的杆上,通过调整杆的纵向位置来保持质点保持竖直。这种系统可以通过使用PID控制器进行控制。 在Python中,可以使用Matplotlib库来模拟和可视化直线倒立摆的运动。首先,导入必要的库和模块: ```python import numpy as np import matplotlib.pyplot as plt ``` 然后,定义PID控制器的参数: ```python Kp = 1.0 Ki = 0.5 Kd = 0.1 ``` 接下来,定义直线倒立摆的动力学模型和控制函数: ```python def dynamics(y, dy, u, dt): m = 1.0 # 质点质量 L = 1.0 # 杆的长度 g = 9.8 # 重力加速度 d2y = (m * g * np.sin(y) - u - m * L * (dy ** 2) * np.sin(y) * np.cos(y)) / ( m * L * (np.cos(y) ** 2) - m * L) dy += d2y * dt y += dy * dt return y, dy def control(y, dy, y_ref, dy_ref): error = y_ref - y error_d = dy_ref - dy u = Kp * error + Ki * (error + error_d) * dt + Kd * (error - error_d) / dt return u ``` 然后,设置仿真参数和初始条件: ```python dt = 0.01 # 仿真时间间隔 t_final = 10.0 # 仿真时间 n_steps = int(t_final / dt) # 仿真步数 y = np.pi / 6 # 初始位置角度 dy = 0.0 # 初始角速度 y_ref = 0.0 # 参考位置角度 dy_ref = 0.0 # 参考角速度 t = np.linspace(0.0, t_final, n_steps) y_hist = np.zeros(n_steps) u_hist = np.zeros(n_steps) ``` 最后,进行仿真和控制: ```python for i in range(n_steps): y_hist[i] = y u = control(y, dy, y_ref, dy_ref) u_hist[i] = u y, dy = dynamics(y, dy, u, dt) ``` 最后,我们可以使用Matplotlib将结果可视化: ```python # 画图 plt.figure(1) plt.subplot(211) plt.plot(t, y_hist) plt.ylabel('角度 (rad)') plt.subplot(212) plt.plot(t, u_hist) plt.xlabel('时间 (s)') plt.ylabel('控制输入') plt.show() ``` 这个代码会模拟一个直线倒立摆的运动,并通过PID控制器来控制倒立摆的位置。我们可以根据需要调整PID控制器的参数来获得较好的控制效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值