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

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

ただいまの
回答率

90.51%

  • C

    3710questions

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

  • C++

    3468questions

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

  • Arduino

    539questions

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

  • 配列

    525questions

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

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

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 5,780

akkun-apple

score 5

前提・実現したいこと

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フィルタをかけたものが以上のグラフとなっております。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • coco_bauer

    2017/02/15 17:23

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

    キャンセル

  • akkun-apple

    2017/02/15 18:20

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

    キャンセル

  • ozwk

    2017/02/17 16:32 編集

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

    キャンセル

  • akkun-apple

    2017/02/18 01:07

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

    キャンセル

回答 1

checkベストアンサー

+1

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:今回、前回、前々回の偏差 

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

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

for (int i = 0; i < 400; i++){ // ループ処理 for文以下の処理を400回繰り返す
    value[i] = analogRead(A0);//iの要素をA0から流れる電圧の値に設定し、読み取る

    delay(5);//5msec間隔で電圧を記録していく
}

の中に書いていきます。

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

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

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

dMV = ...
MV += dMV;
analogWrite(10, MV);

で済みますね。

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

float Kp = 1.0; // とりあえずP制御
float Ki = 0.0;
float Kd = 0.0;

int vo = 150;
float e_0 = 0; // 配列でもいい
float e_1 = 0;
float e_2 = 0;
flaot MV = 0;

for (int i = 0; i < 400; i++){
    int v = analogRead(A0); 
    e_0 = (float)(vo - v);

    dMV = Kp * (e_0 - e_1) + Ki * e_0 + Kd * ((e_0 - e_1) - (e_1 - e_2));
    MV += dMV;

    analogWrite(10, MV);

    e_2 = e_1;
    e_1 = e_0;

    value[i] = v;
    delay(5);
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/18 23:17

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

    キャンセル

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

  • ただいまの回答率 90.51%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C

    3710questions

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

  • C++

    3468questions

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

  • Arduino

    539questions

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

  • 配列

    525questions

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