Edited at

PythonでPID制御をやってみる


はじめに

最近、独学で制御工学を勉強し始めました。

理解を深める為にはプログラミングで実装してみるのが一番早い、というのが私の理念です。

なので、今回は最近勉強したPID制御をPythonを使って実現してみます。

なお、この記事ではPID制御や制御工学の原理・理論の説明はしません。

Pythonでの実装にのみフォーカスを当ててます。

matplotlibとnumpyを使います。

OSは、Ubuntu16.04とMacOS High Sierra10.13で動作確認済みです。

Python2.7, Python3.6の両方で動きます。

一応、GitHubにもコードを上げておきます。


変数の説明

M : 与える操作量

M1 : 一つ前に与えた操作量

goal : 目的値

e : 偏差(目的値と現在値の差)

e1 : 前回に与えた偏差

e2 : 前々回に与えた偏差

Kp : 比例制御(P制御)の比例定数

Ki : 積分制御(I制御)の比例定数

Kd : 微分制御(D制御)の比例定数


操作量(M)の求め方

操作量(M)の求め方ですが、本来ならば、微積の計算をして操作量(M)を求めます。

しかし、それには莫大な計算が必要になる上、そもそもコンピュータで扱えるのは基本的に離散的な値です。

そこで、サンプリング方式

M = M1 + Kp * (e-e1) + Ki * e + Kd * {(e-e1) - (e1-e2)}

で操作量(M)を求めます。


プログラムコード

それでは、いよいよプログラムを書いていきます。

まずは、必要なモジュールをimportします。

import numpy as np

from matplotlib import pyplot as plt
from numpy.random import *

次に、メインの部分を書いていきます。

M = 0.00 

M1 = 0.00
goal = 50.00
e = 0.00
e1 = 0.00
e2 = 0.00
Kp = 0.1
Ki = 0.1
Kd = 0.1

t = 100

M, M1, e, e1, e2は最初は0.00に設定しておきます。

goalは目的の値でとりあえず今回は50.00にしておきましょう。

Kp,Ki,Kdはパラメータとなります。最初は様子をみて全て0.10にしておきましょう。

謎の変数tが出てきましたが、これは時間(t)です。for文のループ回数を設定する為に使います。

次に、グラフで表示するための準備をします。

x_list = []

y_list = []

x_list.append(0)
y_list.append(0.00)

x_listには時間(t)が入ります。

y_listには与えた操作量(M)が入ります。

時間(t)が0の時には、操作量も0.00なので、for文で回す前に事前にリストに格納しておきます。

そして、いよいよPID制御に入ります。

と言っても、先ほどのサンプリング方式の式に代入するだけです。

for i in range(1,t):

M1 = M
e2 = e1
e1 = e
e = goal - y_list[i-1] #偏差(e) = 目的値(goal) - 前回の操作量

M = M1 + Kp * (e-e1) + Ki * e + Kd * ((e-e1) - (e1-e2))

x_list.append(i)
y_list.append(M)

偏差(e)の求め方は、制御対象によって変わるので注意してください。

とりあえず今は、(目的値)と(前回与えた操作量)の差を偏差(e)としています。

最後に、グラフで表示してみましょう。

plt.plot(x_list, y_list)

plt.ylim(0, goal*2) #見やすくするため
plt.show()

Figure_1.png

最初の段差が少々気になりますが、綺麗な曲線で目的値まで届いていると思います。


パラメータを変えてみよう

試しに、Kp, Ki, Kdをそれぞれ0.01と0.50に変えてみました。

届かない.png

パラメータが0.01だと、目的値50.00まで届かないです。

ハンチング.png

パラメータが0.50だとハンチングが発生してしまいました。


ノイズが入った場合だとどうなるか

ランダムでノイズを入れてみましょう。

コードはGitHubに上げておきます。

オーバーシュートやハンチングを防ぐにはKi, Kdの細かい調整が必要になりそう。


最後に

簡単ではありますが、PythonでPID制御をやってみました。

PID制御自体があまり勉強できていないので、もしかしたら間違えている部分があるかもしれません(コメントお待ちしております)。

2018/07/03 altさん、編集リクエストありがとうございます。

参考にしたサイトを載せておきます。

モータのPID制御法

【分かりすぎる】PID制御の基礎(YouTube動画)

一応、ソースコードも載せておきます。


pid.py

# coding:utf-8

import numpy as np
from matplotlib import pyplot as plt
from numpy.random import *

def main():
M = 1.00
M1 = 0.00

e = 0.00
e1 = 0.00
e2 = 0.00

Kp = 0.10
Ki = 0.10
Kd = 0.10

t = 100

goal = 50.00

x_list = []
y_list = []

x_list.append(0)
y_list.append(0.00)

for i in range(1,t):
M1 = M
e2 = e1
e1 = e
e = goal - y_list[i-1]

M = M1 + Kp * (e-e1) + Ki * e + Kd * ((e-e1) - (e1-e2))

y_list.append(M)
x_list.append(i)

plt.plot(x_list, y_list)
plt.ylim(0, goal*2)
plt.show()

if __name__ == "__main__":
main()