Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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.hlines([goal], 0, t, "red", linestyles='dashed') #ゴールを赤色の点線で表示
plt.plot(x_list, y_list, color="b") #青色でグラフを表示
plt.ylim(0, goal*2) #グラフの高さを調整
plt.show()

Figure_1.png

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

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

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

Kp = Ki = Kd = 0.01

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

Kp = Ki = Kd = 0.5

Figure_4.png

パラメータが0.50だと値が収束せずにハンチングが発生してしまいました。

ノイズ入りバージョン

ランダムでノイズを入れてみましょう。
コードはGitHubに上げておきます。

最後に

簡単ではありますが、PythonでPID制御をやってみました。
今回はKp,Ki,Kdのパラメータを全て同じ値に設定しましたが、実際は各パラメータを細かく調整する必要があります。

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

参考にしたサイトを載せておきます。
モータのPID制御法
【分かりすぎる】PID制御の基礎(YouTube動画)

ソースコードはGitHub載せておくので参考にしてください。

BIG_LARGE_STONE
ロボティクス/機械学習/画像処理/自然言語処理
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away