ラインパトロールロボット - PID制御 - Android設定

ラインパトロールロボット - PID制御 - Android設定

オリジナル

このプロジェクトの目的は、PID 制御を備えたライン追従ロボットを構築することです。また、Android デバイスを使用して主要な制御パラメーターを簡単に設定し、より適切かつ迅速なチューニングを実現します。プロジェクトで使用しているステアリングギヤもMG996に交換可能です MG996などのステアリングギヤの紹介はこちら

このプロジェクトは、複雑な 2 部構成のプロジェクトの最初のプロジェクトであり、私の目的はライン追従ロボットの可能性を探ることです。パート 2: Arduino を使用した人工知能を使用した迷路解決ロボットでは、ロボットは単純な人工知能技術を使用して迷路を探索し解決します。

ステップ 1: 部品表

必要な材料のリストは非常に簡単です。

  • 本体(必要に応じて調整可能):
    • 木製キューブ 2個 (80X80mm)
    • バインダー3個
    • 木製車輪2個(直径50mm)
    • キャスター1個
    • 9本のゴムバンド
    • 3Mストリップ
    • センサー固定用プラスチックコネクター
    • ブレッドボードと配線
  • 電池 2 セット (各 5V)
  • 2 x SM-S4303R 連続回転 360 度サーボ
  • Arduinoナノ
  • HC-06 Bluetoothモジュール
  • 5 ライン追跡センサー (TCRT5000 4 チャンネル赤外線追跡追跡センサー モジュール + 1 つの独立した追跡センサー)
  • 1 LED
  • 1ボタン

ステップ 2: モーターをセットアップする

ここに画像の説明を挿入

ここに画像の説明を挿入
ここに画像の説明を挿入

ここに画像の説明を挿入
連続回転サーボ(SM-S4303R)を2個使用しました。それらは「接着」されて単一の固体ブロックを形成します。これらのサーボは、データ入力が受信するパルスの幅によって定義される特定の速度で動作します。このサーボの場合、パルス幅は 1.0ms (1,000 マイクロ秒) ~ 2.0ms (2,000 マイクロ秒) です。他のサーボは異なるパルス幅を使用する場合があります。

詳細情報を確認します。

  • 1.5ms パルスはサーボを中立位置、つまり「停止」に配置します。
  • 1.0ms のパルスはサーボに一方向のフルスピード (約 70 RPM) で指令します。
  • 逆方向の全速パルスは 2.0ms です。
  • 1.0 ミリ秒と 1.5 ミリ秒の間、または 1.5 ミリ秒と 2.0 ミリ秒の間のパルスは、比例した速度を生成します。

2 つのサーボは物理的に接続されており、上記の回路に従って電力 (外部 5V または 6V) を供給し、Arduino からの信号を供給します。

  • 左サーボ: Arduino ピン 5
  • 右サーボ: Arduino ピン 3

すべて接続したら、最初に行う必要があるのは、1.5ms パルスを送信して、モーターが「停止」(動作していない) ことを確認することです。そうでない場合は、サーボを完全に停止するように調整する必要があります (サーボの下にある黄色のボルトを探してください)。注: サーボにこの物理的な調整がない場合は、完全に停止するまで関数内のパラメータ「1500」マイクロ秒を変更してみてください (上または下)。

次の Arduino コードがその仕事を行います。

#include <Servo.h> // Servo library 
Servo leftServo;
Servo rightServo;

Void setup()
{
  leftServo.attach(5);
  rightServo.attach(3);
  leftServo.writeMicroseconds(1500);
  rightServo.writeMicroseconds(1500);
}

void loop()
{
}

ステップ 3: 動作テストのために本体とモーターを組み立てる

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

  1. 3M ストリップを使用して、2 つのサーボを角材の 1 つに取り付けます。
  2. バインダー クリップを使用して、2 番目の正方形の木材を上部の木材に固定します。必要に応じてプラットフォームの長さを調整してください。
  3. バインダークリップを使用してボールキャスターを固定します。
  4. モーターの電力は 5V バッテリー パックの 1 つから供給されます。このバッテリーのセットは、ブレッドボードと本体フレームの間に取り付けられます。
  5. サーボで使用するバッテリーを接続します。左側はサーボ電源専用です。
  6. Arduino Nanoをブレッドボードに接続する
  7. 電源のGNDをArduinoのGNDに接続します。
  8. サーボを Arduino に接続します: 左 ==> ピン 5; 右 ==> ピン 3
  9. LEDをArduinoのピン13に接続します
  10. ボタンをArduinoのピン9に接続します。

サーボの取り付け方法 (逆) により、速度範囲は次のようになります。

  • 右サーボの前進速度は 1,500us (停止) から 2,000us (フルスピード)
  • 左サーボの前進速度が 1,500us (停止) から 1,000 (フルスピード) に増加しました。

信号伝達とテストの目的で、外部 LED がピン 13 に追加されます。

ピン 9 に接続されたボタンもあります。このボタンは、テスト目的やロボットの起動に役立ちます。

例えば:

while(digitalRead(buttonPin)) 
{ 
}
motorTurn (LEFT, 500);
motorTurn (RIGHT, 500);

ロボットに左折、2 ミリ秒待機、右折を命令する 500 行は、ボタン (buttonPin = 0) を押した後にのみ実行されることに注意してください。それまで、プログラムは無限ループで停止します。

以下のコードは、完全なモーター テスト (前進、後進、周期、左折、右折) の基礎として使用できます。必要に応じて、モーターに応じて希望の回転角度の遅延を調整する必要があります(また、モーターのバランスの欠如を補うために、左右のパルス値がわずかに異なる必要がある場合もあります)。

付録

Motor_Test.inoのダウンロード

ステップ 4: Bluetooth モジュール (オプション)

ここに画像の説明を挿入
ここに画像の説明を挿入

Bluetooth モジュール HC-06 は図のようにブレッドボードに実装する必要があり、Arduino ライブラリ SoftSerial が使用されます。

HC-06 ピン接続の下:

  • TXから Arduinoピン 10 (Rx)
  • RXピンから Arduinoピン 11 (Tx)
  • VCC/GND~Arduino 5V/GND

ロボットは Bluetooth の有無にかかわらず動作します。このコードは、BT をアクティブ化しない場合、デフォルトのパラメーターがボットによって使用されるように構築されています。したがって、HC-06 MOD をインストールしたくない場合でも、コードは引き続き正常に動作しますので、ご心配なく。このチュートリアルの最後の部分では、ロボット パラメーターをより適切に調整したり手動モードでロボットを動かしたりするために、Android アプリを使用してデータを送信する方法を検討します。たとえば、誰かがライン追跡ボットを使ってさらに多くのレースを探索したい場合、Bluetooth とアプリの使用はオプションとして残しておきます。

ステップ 5: ライン追跡センサーの追加

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

  1. 写真に示すように、5 つのセンサーをプラスチック ストリップに固定します。
  2. テスト用にセンサーにラベルを付けることをお勧めします。センサー名は「0」(左方向)から「4」(右方向)まで
  3. ケーブルをフレームの下に置き、ゴムを使用してケーブルを固定します (ホイールやキャスターと混同しないでください)。
  4. 図のようにケーブルを Arduino ピンに接続します。
    • センサー0 = 12
    • センサー1 = 18
    • センサー 2 = 17
    • センサー 3 = 16
    • センサー 4 = 19
  5. 2 番目の 5V 電池セットを Arduino Vin に接続します。

私の場合は、4 つのセンサー + 1 つの追加センサーを統合したモジュールを使用しています。これらはすべて互換性があります。わかりやすくするために、図には 5 つの別々のセンサーが接続されています。どちらの構成でも最終結果は同じになります。

ステップ 6: IR センサーのロジック

ここに画像の説明を挿入

赤外線センサーは、単一の赤外線 LED と赤外線フォトダイオードで構成されます。LED からの赤外線は表面を照らし、反射して赤外線フォトダイオードに戻ります。フォトダイオードは、表面の反射率のレベルに比例した出力電圧を生成します (「明るい表面」ではより高い値、「黒い/暗い表面」ではより低い値)。
ここに画像の説明を挿入

センサー モジュール上の集積回路は、単純なデジタル信号を出力として生成します (高: 暗い、低: 明るい)。モジュールに取り付けられたポテンショメータ (写真を参照) が正しい光レベルを調整し、「暗い」または「明るい」と表示されます。その仕組みは、反射光の色が黒/暗い場合に出力に高レベル (「1」) のデジタル レベルを生成し、別の明るい色の場合には低レベル (「0」) を生成することです。
ここに画像の説明を挿入
ここでは、4 つのセンサーを備えた統合モジュールと、独自のセンサー (形状は異なりますが、ロジックは同じ) を備えた追加モジュールを使用しました。以下で説明するように、このコンボは 5 つのセンサーの配列であり、これが快適でスムーズな制御に役立つことがわかりました。
ここに画像の説明を挿入
ここに画像の説明を挿入
5 つのセンサー アレイは、1 つのセンサーのみが黒い線の中央にある場合、そのセンサーのみが HIGH を生成するように取り付けられています。一方、センサー間のスペースは、両方のセンサーが黒線の幅全体を同時にカバーできるように計算する必要があり、両方のセンサーで高レベルが生成されます (上の画像を参照)。

ラインをたどるときに考えられるセンサー アレイ出力は次のとおりです。

  • 0 0 0 0 1
  • 0 0 0 1 1
  • 0 0 0 1 0
  • 0 0 1 1 0
  • 0 0 1 0 0
  • 0 1 1 0 0
  • 0 1 0 0 0
  • 1 1 0 0 0
  • 10000

5 つのセンサーを使用すると、以下の図に示すように、生産ライン上のロボットの位置の制御に役立つ「誤差変数」を生成できます。

考えてみましょう。ロボットが中心にあり、ラインが「中央センサー」(センサー 2) の真下にあるときが最良の状態です。配列の出力は次のようになります0 0 1 0 0。この場合、「エラー」は「ゼロ」になります。ロボットが左に動き始めた場合 (ラインが「右に動いているように見える」)、正の信号が増加するにつれて誤差も増加するはずです。ロボットが右に動き始めた場合 (「線」が左に動いているように見える)、同様に誤差は増加するはずですが、今度は負の信号が発生します。

センサーの状態に関連付けられたエラー変数は次のとおりです。

  • 0 0 0 0 1 ==> エラー = 4
  • 0 0 0 1 1 ==> エラー = 3
  • 0 0 0 1 0 ==> エラー = 2
  • 0 0 1 1 0 ==> エラー = 1
  • 0 0 1 0 0 ==> エラー = 0
  • 0 1 1 0 0 ==> エラー = -1
  • 0 1 0 0 0 ==> エラー = -2
  • 1 1 0 0 0 ==> エラー = -3
  • 1 0 0 0 0 ==> エラー = -4

Arduino コードを見ると、各センサーは特定の名前で定義されています (センサーに続く左側の行にはラベル「0」が割り当てられています)。

const int lineFollowSensor0 = 12;
const int lineFollowSensor1 = 18;
const int lineFollowSensor2 = 17;
const int lineFollowSensor3 = 16;
const int lineFollowSensor4 = 19;

各センサーの値を保存するために、配列変数が作成されます。

int LFSensor[5]={0, 0, 0, 0, 0};

配列の各位置は、各センサーの出力によって継続的に更新されます。

LFSensor[0] = digitalRead(lineFollowSensor0);
LFSensor[1] = digitalRead(lineFollowSensor1);
LFSensor[2] = digitalRead(lineFollowSensor2);
LFSensor[3] = digitalRead(lineFollowSensor3);
LFSensor[4] = digitalRead(lineFollowSensor4);

各センサーの値を使用して、エラー変数を生成するロジックを実装する必要があります。

if((LFSensor[0]== 0 )&&(LFSensor[1]== 0 )&&(LFSensor[2]== 0 )&&(LFSensor[3]== 0 )&&(LFSensor[4]== 1 )) error = 4;

else if((LFSensor[0]== 0 )&&(LFSensor[1]== 0 )&&(LFSensor[2]== 0 )&&(LFSensor[3]== 1 )&&(LFSensor[4]== 1 )) error = 3; 

else if((LFSensor[0]== 0 )&&(LFSensor[1]== 0 )&&(LFSensor[2]== 0 )&&(LFSensor[3]== 1 )&&(LFSensor[4]== 0 )) error = 2;

else if((LFSensor[0]== 0 )&&(LFSensor[1]== 0 )&&(LFSensor[2]== 1 )&&(LFSensor[3]== 1 )&&(LFSensor[4]== 0 )) error = 1;

else if((LFSensor[0]== 0 )&&(LFSensor[1]== 0 )&&(LFSensor[2]== 1 )&&(LFSensor[3]== 0 )&&(LFSensor[4]== 0 )) error = 0;

else if((LFSensor[0]== 0 )&&(LFSensor[1]== 1 )&&(LFSensor[2]== 1 )&&(LFSensor[3]== 0 )&&(LFSensor[4]== 0 )) error =- 1;

else if((LFSensor[0]== 0 )&&(LFSensor[1]== 1 )&&(LFSensor[2]== 0 )&&(LFSensor[3]== 0 )&&(LFSensor[4]== 0 )) error = -2;

else if((LFSensor[0]== 1 )&&(LFSensor[1]== 1 )&&(LFSensor[2]== 0 )&&(LFSensor[3]== 0 )&&(LFSensor[4]== 0 )) error = -3;

else if((LFSensor[0]== 1 )&&(LFSensor[1]== 0 )&&(LFSensor[2]== 0 )&&(LFSensor[3]== 0 )&&(LFSensor[4]== 0 )) error = -4;

ステップ 7: 制御方向 (比例制御 - P)

ここに画像の説明を挿入

この時点で、ロボットは組み立てられ、実行されます。モーターでいくつかの基本的なテストを実行し、センサーの出力を読み取り、ワイヤーでテストする必要があります。欠けているのは、「人工知能」の第一歩である実際の「脳」です。ロボットがラインに従い続けることを保証する制御ロジックを実装します。

シンプルな比例制御:

ロボットがライン上で実行されていると仮定すると、センサー アレイの出力は次のようになります0 01 0 0対応するエラーは「0」です。この場合、両方のモーターが一定速度で前進する必要があります。

例えば:

変数を定義します。左側のサーボが受信するパルスと右側のサーボが受信するパルスiniMotorSpeed = 250;を表します。これらのパラメータを使用すると、ロボットは半分の速度で前進します。右サーボの前進速度のパルス長は(停止)から(フルスピード) までの範囲であり、左サーボのパルス長は(停止)から(フルスピード) までであることに注意してください。 1,250us1,750us1,500us2,000us1,500us1,000us

rightServo.writeMicroseconds(1500 + iniMotorPower);
leftServo.writeMicroseconds(1500 - iniMotorPower);

ここで、ロボットが左に運転していて (「LINE は右に運転しています」のように)、センサー 3 を覆っているとします。配列の出力は次のようになります: 0 0 1 1 0, error = 1この場合、必要なのはロボットを右に回転させることです。これを行うには、右側のサーボの速度を下げる必要があります。これは、パルスの長さを短くすることを意味します。また、左側のサーボの速度を上げる必要があります。これは、左側のサーボのパルスの長さを短くすることを意味します。これを行うには、モーター制御関数を変更する必要があります。

rightServo.writeMicroseconds(1500 + iniMotorPower - error); ==> Positive error: decrease velocity
leftServo.writeMicroseconds(1500 - iniMotorPower - error); ==> Positive error: increase velocity

上記のロジックは正しく、パルス長に「1」マイクロ秒を加算または減算しても、リアルタイムでは望ましい補正が得られないことは容易に理解できます。直感的には、加算または減算する数値は、50、100 など、大きいほうがよいでしょう。これを得るには、「誤差」に定数 (「K」と呼びます) を乗算する必要があります。この定数の効果が誤差に比例すると、これを「比例定数: Kp 」と名付けます。

モーター機能は次のようになります。

int Kp = 50;
rightServo.writeMicroseconds(1500 + iniMotorPower - Kp*error);
leftServo.writeMicroseconds(1500 - iniMotorPower - Kp*error);

以下の図に示すように、モーターに何が起こるかを復元できます。

  • センサーアレイ:(0 0 1 0 0 ==> error = 0 ==> 右伺服脉冲长度 = 1,750us ==> 左舵机脉冲长度 = 1,250us両方のモーター速度は同じ)
  • センサーアレイ:(0 0 1 1 0 ==> error = 1 ==> 右舵机脉冲长度 = 1,700us(较慢)==> 左舵机脉冲长度 = 1,200us高速)

状況が逆でロボットが右に駆動された場合、誤差は「負」になり、サーボの速度が変化するはずです。

  • センサーアレイ:(0 0 1 0 0 ==>error = 0 ==> 右伺服脉冲长度 = 1,750us ==> 左舵机脉冲长度 = 1,250us両方のモーター速度は同じ)
  • センサーアレイ:(0 1 1 0 0 ==> error = -1 ==> 右舵机脉冲长度 = 1,800us(更快)==> 左舵机脉冲长度 = 1,300us遅い)

この時点で、ロボットが片側に駆動されていることは明らかであり、誤差が大きいほど、より早く中心に戻らなければなりません。エラーに対するロボットの反応速度はそれに比例します。これは「比例制御」と呼ばれ、より複雑な制御 PDI (比例、微分、積分) の「P」コンポーネントです。

ステップ 8: PID 制御 (オプション)

ここに画像の説明を挿入

ここに画像の説明を挿入

ここに画像の説明を挿入

この部分をスキップしたい場合でも、それは問題ありません。最後のステップで説明した比例制御を引き続き使用することも、頭を使ってより複雑な制御システムをロボットに実装することもできます。次に進みましょう。

PID (比例、微分、積分) は、最も一般的な制御方式の 1 つです。ほとんどの産業用制御ループは、何らかの形式の PID 制御を使用します。この例で使用されている手動手法を含め、PID ループを調整するにはさまざまな方法があります。

PID を単純なスプリングとして考えてください。ばねには元の長さがあり、伸縮によって妨げられると、できるだけ短時間で元の長さに戻ろうとします。同様に、システムの PID アルゴリズムには、「設定点」と呼ばれる、制御される特定の物理量の設定値があり、それが何らかの理由で変化すると、システムは、所望の値を達成するために、システム内の他の必要な機能を制御します。可能な限り短い時間で、元の設定値に戻るまでの時間。PID コントローラーは、物理量を制御して指定の値に等しくする必要がある場合に使用されます。たとえば、車のクルーズ コントローラー、ロボット、サーモスタット、電圧レギュレーターなどです。

PID はどのように機能するのでしょうか?

物理量の現在値をセンサーで測定し、設定値からの「誤差」や「偏差」を計算するシステムです。設定値に戻すには、この「誤差」を最小限に抑え、理想的にはゼロに等しくする必要があります。また、このプロセスはできるだけ早く行う必要があります。理想的には、システムは設定値の変化に対してゼロヒステリシスで応答する必要があります。

詳細については、次のような多くの書籍や Web サイトを参照してください。

PIDを実装する

  1. エラー項目 (e):

これは、設定値と制御量の現在値の差に等しくなります。

error = set_point – current_value(この場合、エラー変数はライン上のロボットの位置から取得されます)

  1. 比例項 (P):

この項目は誤差に比例します。

P = エラー

この値は、設定点に到達するために必要な物理量の変化の大きさに影響します。比例項は、設定点に到達するための制御ループの立ち上がり時間、つまり速度を決定します。

  1. 統合項目 (I):

この項は、以前のすべての誤差値の合計です。

I = I + エラー

この値は、設定値の変更に対するシステムの高速応答に関与します。積分項は、比例項で必要な定常状態誤差を除去するために使用されます。一般に、定常状態誤差は気にせず、「ループ調整」が複雑になるため、小型ロボットには積分項は使用されません。

  1. 微分項または微分項 (D):

この項は、設定値の瞬間誤差と前の瞬間の誤差との差です。

D = エラー - 前のエラー

この値は、設定値に近づくにつれて物理量の変化率を遅くする役割を果たします。微分は、オーバーシュート、つまりシステムの「オーバーチューニング」の程度を減らすために使用されます。

方程式:

PIDvalue = (Kp*P) + (Ki*I) + (Kd*D)

の:

  • Kp は、設定値に到達するために必要な変化の大きさを変えるために使用される定数です。
  • Ki は、設定値に到達するために物理量が変化する速度を変化させるために使用される定数です。
  • Kd は、システムの安定性を変化させるために使用される定数です

ループを調整する 1 つの方法は、エラー暫定メソッドを試すことです。

  1. Kd 変数を 0 に設定し、最初に Kp 項を個別に調整します。この場合、Kp = 25 が適切な開始点です。最終的に、私たちが使用したところKp=50、私のロボットでうまく動作しました。
  2. ロボットの反応が遅すぎる場合は、この値を大きくします。
  3. ロボットがすぐに反応して不安定になる場合は、この値を下げます。
  4. ロボットが適切に応答したら、制御ループの微分部分 ( Kd ) を調整します。まず、Kp 値と Kd 値をそれぞれ Kp 値の $\frac{1}{2}$ に設定します。たとえば、ロボットが Kp = 50 で適切に応答する場合、開始するには Kp = 25 および Kd = 25 を設定します。Kd (微分) ゲインを大きくしてオーバーシュートを減らし、ロボットが不安定になった場合はオーバーシュートを減らします。

考慮すべきもう 1 つの部分は、実際のサンプル/ループ レートです。このパラメータを速くしたり遅くしたりすると、ロボットのパフォーマンスに大きな影響を与える可能性があります。これは、コード内のステートメントによってdelay設定されます。これは、最良の結果を得るためにエラーを試してみるヒューリスティックなアプローチです。

上記の方法に基づいて、PID 関数を実現します。

void calculatePID()
{
  P = error;
  I = I + error;
  D = error-previousError;
  PIDvalue = (Kp*P) + (Ki*I) + (Kd*D);
  previousError = error;
}

最後のステップで使用した単純な Kp 定数は、次のより完全な PID 値に置き換えられます。

void motorPIDcontrol()
{
  int leftMotorSpeed = 1500 - iniMotorPower - PIDvalue;
  int rightMotorSpeed = 1500 + iniMotorPower - PIDvalue;
  
  leftServo.writeMicroseconds(leftMotorSpeed);
  rightServo.writeMicroseconds(rightMotorSpeed);
}

ただし、Kd および Ki =0 の場合、PID 値は単に使用されていることに注意してください。Kp*error

ステップ 9: 最終コード

ここに画像の説明を挿入

ここに画像の説明を挿入

このステップでは、ロボットは一定のループに従い、停止することなく完了できます。

ループプログラムは次のようになります。

void loop ()
{
  readLFSsensors(); // read sensors, storage values at Sensor Array and calculate "error"
  calculatePID(); 
  motorPIDcontrol();
}

ただし、より完全で実用的な操作を行うには、少なくともいくつかの基本的なワイヤ モーション関連コマンドを追加する必要があります。新しい変数「mode」を導入しましょう。この変数に 3 つの状態を定義します。

モデル:

- #define STOPPED  0
- #define FOLLOWING_LINE 1
- #define NO_LINE 2

すべてのセンサーが黒い線を検出した場合、センサー アレイの出力は次のようになります1 1 1 1 1この場合、モードを「停止」として定義でき、ロボットは「完全停止」を実行する必要があります。

if((LFSensor[0]== 1 )&&(LFSensor[1]== 1 )&&(LFSensor[2]== 1 )&&(LFSensor[3]== 1 )&&(LFSensor[4]== 1 )) 
{ 
  mode = STOPPED;
}

ライン追従ロボットのその他の一般的な状況は、次のような「ワイヤレス」またはセンサー アレイ出力を見つけた場合です0 0 0 0 0この場合、ラインを見つけて条件に従って通常のラインに戻るまで、180 度または小さな角度で折り返すようにプログラムできます。

else if((LFSensor[0]== 0 )&&(LFSensor[1]== 0 )&&(LFSensor[2]== 0 )&&(LFSensor[3]== 0 )&&(LFSensor[4]== 0 )) 
{ 
  mode = NO_LINE;
}

完全なものは次loop()のようになります。

void loop() 
{
  readLFSsensors();
  switch (mode)
  {
    case STOPPED:
       motorStop();
       break;
    case NO_LINE:
       motorStop();
       motorTurn(LEFT, 180);
       break;
    case FOLLOWING_LINE:
       calculatePID();
       motorPIDcontrol();
       break;
  }
}

実際の最終コードには、追加のロジックや初期化が必要な変数などが組み込まれます。上記の説明では、わかりやすくするためにそれらを省略しましたが、最終的なコードを見るとすべてが明らかになるはずです。

ステップ 10: Android アプリを使用した PID 制御の調整

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

前述のコードでは、「robotDefines.h」内の PID コントロールで使用される定数の次の定義を見つけることができます。

float Kp=50;
float Ki=0;
float Kd=0;

前のステップで述べたように、PID コントローラーで使用する正しい定数を定義する最良の方法は、「試行錯誤」方法を使用することです。欠点は、プログラムを変更する必要があるたびに、プログラムを再コンパイルする必要があることです。プロセスを高速化する 1 つの方法は、Android アプリを使用して「**セットアップ フェーズ」中に定数を送信することです。

私はこれ専用の Android アプリケーションを開発しました。要するに:

  • 従来の手動コマンド:
    • FW, BW, Left, Right and Stop、アプリケーションはそれぞれ「f」、「b」、「l」、「r」、「s」の BT モジュールに送信されます。
  • 各 PID 定数に 1 つずつ、合計 3 つのスライダーも含まれています。
    • Kp:「p/XXX」
    • キ:「i/XXX」
    • Kd: 「d/XXX」
      • ここで、「XXX」は 0 ~ 100 の数字です。
  • Arduino Pin9 に接続されているものとまったく同じ追加のボタンを含めます。これらのいずれかを使用できます。

以下に、**MIT AppInventor*** で変更する .aia ファイルと、Android デバイスに直接インストールする .apk ファイルがあります。

付録

MJRoBot_Line_Follower_PID_Control.aia

MJRoBot_Line_Follower_PID_Control.apkをダウンロード

ダウンロード

ステップ 11: PID リモートチューニングのコードを変更する

このプロセスでは、void setup()車をラインに投入する前にロボットに PID パラメーターを送信できるループを導入します。

  while (digitalRead(buttonPin) && !mode)
  {  
    checkBTcmd();  // verify if a comand is received from BT remote control
    manualCmd ();    
    command = "";  
  }
  checkPIDvalues();
  mode = STOPPED;

手動コマンドは次のようになります。

void manualCmd()
{
  switch (command[0])
  {
    case 'g':
      mode = FOLLOWING_LINE;
      break;
    
    case 's': 
      motorStop(); //turn off both motors
      break;

    case 'f':  
      motorForward();  
      break;

    case 'r':     
      motorTurn(RIGHT, 30);
      motorStop();
      
      break;

   case 'l': 
      motorTurn(LEFT, 30);
      motorStop();
      break;
    
    case 'b':  
      motorBackward();
      break;
      
    case 'p':
      Kp = command[2];
      break;
    
    case 'i':
      Ki = command[2];
      break; 
    
    case 'd':
      Kd = command[2];
      break;
  }
}

Android 経由の PID セットアップを含む最終コードは次のとおりです。

付録

一般関数.ino

ダウンロード

モーターファンクション.ino

ダウンロード

robotDefines.h

ダウンロード

センサー機能.ino

ダウンロード

スマート_MJRoBot_Line_Follower_PID.ino

ダウンロード

ステップ 12: 結論

これは、ライン追従ロボットの可能性を探る複雑なプロジェクトの最初のものです。次のパートでは、 「迷路解決ロボット」でこのプロジェクトに基づいて迷路解決ロボットを開発します

このプロジェクトの更新ファイルは、GITHUB で見つけることができます: https://github.com/Mjrovai/MJRoBot-Line-Follower

その他のチュートリアルについては、ブログを参照してください: MJRoBot.org

おすすめ

転載: blog.csdn.net/acktomas/article/details/130009184