工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

PID制御とAndroid連携で作るライントレースロボット — Arduino Nano入門

必要なパーツと材料

パーツ数量備考
Arduino Nano R31
ライントラッカーセンサーモジュール (SparkFun RedBot / TCRT5000 4ch)1+14chモジュール + 単体センサーで計5センサー構成
HC-06 Bluetoothモジュール1Androidアプリとの通信用
Android端末1PIDパラメータ調整用アプリ実行
単3電池ボックス (4本用)2モーター用とロジック用で分離推奨
連続回転サーボ (SM-S4303R等)2左右駆動輪用
ボディ材料: 木板80x80mm×2、バインダークリップ×3、木製車輪50mm径×2、ボールキャスター、ゴムバンド×9、3Mコマンドフック、ブレッドボード、配線、LED、タクトスイッチ1式自作シャーシ用

使用するアプリとオンラインサービス

プロジェクトの概要

PID制御を実装したライントレースロボットを製作し、AndroidアプリでPIDパラメータ (Kp, Ki, Kd) を無線でリアルタイム調整できるようにします。これは2部構成プロジェクトの第1弾で、第2弾では迷路探索ロボット (簡易AI搭載) に発展させます。

PID制御とAndroid連携で作るライントレースロボット — Arduino Nano入門

ステップ1: 材料調達 (約75ドルで完成)

上記パーツリストの通り。ボディは木板とバインダークリップで簡易的に組み立て可能。

ステップ2: モーター (連続回転サーボ) の設定

2個の連続回転サーボ (SM-S4303R) を3Mコマンドストリップ等で背中合わせに固定し、一体化させます。このサーボのパルス幅仕様:

取り付け後、まず1500µsパルスを送って完全停止するか確認。ズレがある場合はサーボ底部の黄色調整ネジで微調整 (調整ネジがない場合はコード側で1500µs前後を微調整)。

#include <Servo.h>
Servo leftServo; Servo rightServo;
void setup() {
  leftServo.attach(5);   // 左サーボ: Pin 5
  rightServo.attach(3);  // 右サーボ: Pin 3
  leftServo.writeMicroseconds(1500);
  rightServo.writeMicroseconds(1500);
}
void loop() {}

ステップ3: シャーシ組み立てと走行テスト

木板にサーボ固定、2枚目をクリップで挟んでプラットフォーム化、ボールキャスター装着。モーター用電池 (5V/6V) をブレッドボード横に配置し、GNDをArduino GNDと共通化。サーボ信号線をPin 5 (左)、Pin 3 (右) に接続。LEDをPin 13、タクトスイッチをPin 9に接続 (テスト/スタート用)。

サーボ取り付け向きが対向しているため、前進時のパルス幅範囲は:

ステップ4: Bluetoothモジュール HC-06 (任意)

SoftwareSerialライブラリ使用。接続: HC-06 Tx→Arduino Pin 10 (Rx)、Rx→Pin 11 (Tx)、VCC/GND→5V/GND。Bluetoothなしでもデフォルトパラメータで動作するようコードは設計済み。AndroidアプリでPIDチューニングや手動操作をしたい場合のみ導入。

ステップ5: ラインセンサー (5ch) の取り付け

センサー5個をプラスチックバーに等間隔で固定し、フレーム下部に配置。配線はゴムバンドでまとめ車輪やキャスターに干渉しないよう注意。Arduinoピン割り当て:

第2電池セット (5V) をArduino Vinに接続。

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

IRセンサーはIR LEDとフォトダイオードで構成。黒/暗色面では反射光が少なく、モジュール上のポテンショメータで閾値調整されたデジタル出力 (HIGH=黒/ライン、LOW=白/背景) を得ます。

5センサー配置では、ライン中央に来たとき中央センサー (Sensor 2) のみHIGH、ライン幅によって隣接2センサーが同時にHIGHになるよう間隔を調整。考えられるセンサー出力パターンと「誤差 (error)」変数の対応:

Arduinoコードでの実装:

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};

void readLFSsensors() {
  LFSensor[0] = digitalRead(lineFollowSensor0);
  LFSensor[1] = digitalRead(lineFollowSensor1);
  LFSensor[2] = digitalRead(lineFollowSensor2);
  LFSensor[3] = digitalRead(lineFollowSensor3);
  LFSensor[4] = digitalRead(lineFollowSensor4);
  
  // 誤差計算 (if-else連鎖またはルックアップテーブルで実装)
  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制御) での方向制御

基本速度 iniMotorPower = 250 とし、右サーボに 1500 + iniMotorPower、左サーボに 1500 - iniMotorPower のパルスを送ると等速前進。誤差 error が正 (右ズレ) なら右減速/左加速、負 (左ズレ) なら右加速/左減速:

int Kp = 50; // 比例ゲイン
rightServo.writeMicroseconds(1500 + iniMotorPower - Kp * error);
leftServo.writeMicroseconds(1500 - iniMotorPower - Kp * error);

これによりロボットはラインから外れようとすると自動的に修正方向に舵を切ります。これが「比例制御 (P制御)」、PIDの「P」成分です。

ステップ8: PID制御の実装 (任意だが推奨)

P制御だけでも動作しますが、オーバーシュート (行き過ぎ) や定常偏差を改善するため、D項 (微分) とI項 (積分) を追加します。

PIDの数式:

実装関数:

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

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

チューニング手順 (試行錯誤法):

  1. Kd = 0, Ki = 0 でKpのみ調整。Kp=25〜50から開始。
  2. ある程度追従したら、KpとKdを半分ずつにし (例: Kp=25, Kd=25)、Kdを増やしてオーバーシュートを抑制。不安定なら減らす。
  3. 必要ならKiを微小値から導入 (小型ロボットでは不要なことが多い)。
  4. ループ周期 (delay 値) も性能に影響。試行錯誤で最適化。

ステップ9: 完成版メインループと状態管理

単純なループだとライン見失い時や停止ライン検出時に対応できないため、mode 変数で状態管理:

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

int mode = STOPPED;

void loop() {
  readLFSsensors();
  
  // モード判定
  if (LFSensor[0]==1 && LFSensor[1]==1 && LFSensor[2]==1 && LFSensor[3]==1 && LFSensor[4]==1) mode = STOPPED;
  else if (LFSensor[0]==0 && LFSensor[1]==0 && LFSensor[2]==0 && LFSensor[3]==0 && LFSensor[4]==0) mode = NO_LINE;
  else mode = FOLLOWING_LINE;
  
  switch (mode) {
    case STOPPED:  motorStop(); break;
    case NO_LINE:  motorStop(); motorTurn(LEFT, 180); break; // 180度ターン例
    case FOLLOWING_LINE: calculatePID(); motorPIDcontrol(); break;
  }
}

ステップ10: AndroidアプリでPIDリモートチューニング

毎回コンパイル・書き込みせずにパラメータ調整できるよう、MIT App Inventor 2で専用アプリを作成。機能:

PID制御とAndroid連携で作るライントレースロボット — Arduino Nano入門

アプリファイル: .aia (App Inventor編集用)、.apk (直接インストール用)

ステップ11: リモートチューニング対応コードへの修正

setup() 内でボタン押下待ちループ中にBTコマンドを受信処理:

while (digitalRead(buttonPin) && !mode) {
  checkBTcmd();  // BTコマンド受信チェック
  manualCmd();   // 手動操作/PID設定反映
  command = "";
}
checkPIDvalues();
mode = STOPPED;
void manualCmd() {
  switch (command[0]) {
    case 'g': mode = FOLLOWING_LINE; break;
    case 's': motorStop(); 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.substring(2).toFloat(); break; // "p/XXX" パース
    case 'i': Ki = command.substring(2).toFloat(); break;
    case 'd': Kd = command.substring(2).toFloat(); break;
  }
}

ステップ12: 結論と次のステップ

PID制御とAndroid連携で作るライントレースロボット — Arduino Nano入門

このライントレースロボットは、PID制御の基礎を学び、Androidアプリで直感的にチューニングできる優れた教材です。次回はこのベースで迷路探索ロボット (簡易AIで最短経路探索) を製作予定。ファイル一式は GitHub に公開中。詳細はブログ MJRoBot.org もご覧ください。

南半球からこんにちは! — Marcelo

コードリポジトリ

https://github.com/Mjrovai/MJRoBot-Line-Follower

回路図 (Fritzingファイル)

oIDhLcHQ30lDgVBXZvb8.fzz

製造プロセス

  1. Raspberry Piでライントラッキングセンサー – シンプルなKY-033ドア/ライン検出器
  2. Raspberry Piでセンサーとアクチュエータを制御:加速度計、サーボ、データストリーミング
  3. Raspberry Pi & Android スマホで Wi-Fi 制御ロボットを構築
  4. Arduinoと1Sheeldで作る万能Androidリモコン──IR制御で家電を一括操作
  5. 産業用ラインフォロワーロボット - 物資輸送用自律走行ロボット
  6. V4スピードラインフォロワーロボット – Arduino Nanoベースの高度な自律走行
  7. MATLAB/Simulinkで3DロボットグリッパーのPID制御をマスター
  8. Wittmann Battenfeld、高クランプ力成形向け新ロボットラインWX153を発表
  9. ファナック、SCARAロボットライン拡充:6モデル、3-20kgペイロード、400-1100mmリーチ
  10. 高度な自動制御システムで包装品質保証を効率化
  11. 21世紀のロボティクス:分散システム、テレプレゼンス、宇宙探査
センサー出力 (S0-S4)error意味
0 0 1 0 00中央 (理想)
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 1 1 0 0-1わずかに左
0 1 0 0 0-2やや左
1 1 0 0 0-3左にズレ
1 0 0 0 0-4大きく左にズレ