質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

1回答

20173閲覧

arduinoでモーターのPID制御をしたい

akkun-apple

総合スコア13

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

1クリップ

投稿2017/02/15 06:56

編集2017/02/15 10:48

###前提・実現したいこと
PIDライブラリを用いずにarduinoでモーターのPID制御をしたいと考えています。
目標値はanalogReadで150とし、最終的には現在ソースコードにて出来上がっているRCフィルタをかけてグラフ描画を考えております。
使用モーターはFA130RA、arduino uno、モータードライバーTA7291Pで、現在値を200でanalogWriteしたものを発電側のモーターに同期し、発電側のモーターのアナログ値をRCフィルタで処理、描画するところまで仕上げております。
motor同士の接続はチューブで先をつなげることで回転数の動機を図っております。
###発生している問題
無知で大変失礼ですが、analogReadで値を取得した後のプログラム処理が分からず困っています。

操作量=Kp×偏差+Ki×偏差の累積値+Kd×前回偏差との差
記号で表すと、
MVn = MVn-1 + ΔMVn
ΔMVn = Kp(en-en-1) + Ki en + Kd((en-en-1) - (en-1-en-2))
MVn、MVn-1:今回、前回操作量 ΔMVn:今回操作量差分
en,en-1,en-2:今回、前回、前々回の偏差
という流れで組み立てたいと考えております。

###該当のソースコード
//宣言
int analogPin=A0;//analogPin
float eNow;//少数実数型で変数の宣言
float valueOld;//少数実数型で変数の宣言

//セットアップ関数
void setup() {
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
Serial.begin(9600);
}

//ループ関数
void loop() {
float valueOld = 0;//フィルタ計算初期値valueOldに0を代入
analogWrite(9,LOW);
analogWrite(10,200);//モーターを回転させる

//記録をスタート

Serial.println("start");//スタートをプリントする
// 配列数を明示して配列宣言を開始
int value[400]; //変数が400個入るvalueと言う名前の箱を作る
for (int i = 0; i < 400; i++){ // ループ処理 for文以下の処理を400回繰り返す
value[i] = analogRead(A0);//iの要素をA0から流れる電圧の値に設定し、読み取る

delay(5);//5msec間隔で電圧を記録していく
}
analogWrite(9,LOW);
analogWrite(10,LOW);//モーターを制止させる

//記録を終了する

//記録を元にRCフィルタ処理を施す
for(int i = 0; i < 400; i++){ //for文ループ処理 以下の処理を400回繰り返す
eNow = 0.97 * valueOld + 0.03 * value[i];//フィルタ係数を0.97とし、eNowへ書き出す
valueOld=eNow;//書き出し終了後、次回処理へ向けてeNowを更新しておく
Serial.println(eNow);//eNowの結果をプリントする
}

Serial.println("end");//400個のRCフィルタを完了し、ループ関数が1セットしたことをendでプリントして知らせる

}
イメージ説明
イメージ説明
進捗として上記のプログラムでRCフィルタをかけたものが以上のグラフとなっております。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

coco_bauer

2017/02/15 08:23

モータなどがArduinoと(物理的にと、電気的に)どのように接続されているかが判る図を質問に追加してください。
akkun-apple

2017/02/15 09:20

的確なご指摘、ありがとうございます。電気的には以上の図にあるように接続をしております。また、motor同士の先にはチューブでつなげる事で回転の同期を図っております。よろしくお願い致します。
ozwk

2017/02/17 07:32 編集

そのRCフィルタ組めるぐらいなら、「記号で表すと~」以下をそのままコードにできるぐらいのスキルはありそうなものですが、何ができないんですか?
akkun-apple

2017/02/17 16:07

ご返答ありがとうございます。「記号で表すと~」以下のΔMVn部分を含む、配列式によるコーディングが複雑で分からず困っておりました。力不足で大変申し訳ありませんが、このプログラムの立て方を教えていただけると幸いです。
guest

回答1

0

ベストアンサー

MVn = MVn-1 + ΔMVn

ΔMVn = Kp(en-en-1) + Ki en + Kd((en-en-1) - (en-1-en-2))
MVn、MVn-1:今回、前回操作量 ΔMVn:今回操作量差分
en,en-1,en-2:今回、前回、前々回の偏差

から順序立てて考えてみます。

まずこの操作は逐次行うものなので

C

1for (int i = 0; i < 400; i++){ // ループ処理 for文以下の処理を400回繰り返す 2 value[i] = analogRead(A0);//iの要素をA0から流れる電圧の値に設定し、読み取る 3 4 delay(5);//5msec間隔で電圧を記録していく 5}

の中に書いていきます。

やりたいことはモーターの操作量MVnを求めて実際に出力することなので

C

1MVn = ... 2analogWrite(10, MVn);

MVn
MVn = MVn-1 + ΔMVnで求めたいわけですが、
操作量の履歴は今回必要なく、前回値はMVnの更新にしか使わないので、

C

1dMV = ... 2MV += dMV; 3analogWrite(10, MV);

で済みますね。

みたいな感じで何を次のループに持ち越す/持ち越さないを決めていくと
だいたいこんな感じになるはずです。

C

1 2float Kp = 1.0; // とりあえずP制御 3float Ki = 0.0; 4float Kd = 0.0; 5 6int vo = 150; 7float e_0 = 0; // 配列でもいい 8float e_1 = 0; 9float e_2 = 0; 10flaot MV = 0; 11 12for (int i = 0; i < 400; i++){ 13 int v = analogRead(A0); 14 e_0 = (float)(vo - v); 15 16 dMV = Kp * (e_0 - e_1) + Ki * e_0 + Kd * ((e_0 - e_1) - (e_1 - e_2)); 17 MV += dMV; 18 19 analogWrite(10, MV); 20 21 e_2 = e_1; 22 e_1 = e_0; 23 24 value[i] = v; 25 delay(5); 26}

投稿2017/02/18 12:16

ozwk

総合スコア13512

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

akkun-apple

2017/02/18 14:17

適切な修正依頼から迅速なご回答まで、段階を踏んだわかりやすい解説をありがとうございました。 さらなる理解と、適切なkp,ki,kdの値の取得に今後も努めてまいります。今後とも宜しくお願い致します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問