アルドゥイーノ

Arduinoを使ったラインフォロワーロボットの作り方

ラインフォロワーロボット(LFR)は、通常は白地に黒線、または黒地に白線で示された所定の経路を辿る自律誘導ロボットです。これらのロボットは、産業オートメーション、倉庫物流、教育目的で広く使用されています。

この包括的なガイドには、Arduinoベースのラインフォロワーロボットの構築と操作に必要な情報がすべて含まれています。さあ、始めましょう!

概要

ラインフォロワーロボットの動作

前述の通り、ラインフォロワーロボットは黒線を検出し、その線に沿って移動します。では、LFRにこの線検出機構をどのように実装するのでしょうか?黒い表面は最も多くの光を吸収し、白い表面はほぼすべての光を反射することが知られています。この光の特性は、LDR(光依存抵抗器)、IRセンサー、ラインセンサーなど、多くのセンサーによって線検出に利用されています。ここでは、高精度かつ正確な線検出のためにラインセンサーを使用しています。

ラインセンサーは通常、赤外線発光部(LED)と赤外線受光部(フォトダイオード)で構成されています。発光部は赤外線を連続的に発光し、受光部はその反射光を検出します。

発光部から放射された赤外線が白い表面に当たると反射し、受光部で検出されます。光が黒い線に当たると吸収され、受光部に到達しません。下図はラインセンサーの動作を示しています。

IR近接センサーモジュールの動作

ラインフォロワーロボットはどのようにナビゲートするのでしょうか?

ロボットにナビゲーション機能を追加するには、2つのモーターが必要です。1つはシャーシの左側に、もう1つは右側に設置します。モーターの回転方向は、左右に配置されたセンサーから受信した信号によって制御されます。

ロボットが移動できるケースは 4 つあります。

ケース1:ロボットが前進する場合

両方のセンサーが白い面にある場合、つまり線を検知していない(黒い線がセンサーの間にある)場合、ロボットは前進するはずです。この場合、両方のモーターが前進方向に回転し、ロボットは前進します。

ロボットは前進する

ケース2: ロボットが左に曲がる場合

右のセンサーが白い表面上にあり、左のセンサーが黒い線を検知すると、マイクロコントローラに信号が送られます。ロボットは左に曲がるはずです。そのため、左のモーターは逆回転し、右のモーターは前進を続けます。その結果、ロボットは左に曲がることになります。 

ロボットが左に曲がるとき

ケース3: ロボットが右に曲がる場合

左のセンサーが白い面上にあり、右のセンサーが線を検知した場合、マイクロコントローラに信号が送られます。つまり、ロボットは右に曲がるはずです。そのため、左のモーターは前進し、右のモーターは後退するので、ロボットは右に進みます。

ロボットが右に曲がるとき

ケース4: ロボットが停止した場合

両方のセンサーが同時に黒線を検知すると、ロボットは停止します。これにより、両方のモーターの動きが停止し、ロボットは停止します。

ロボットが停止する

ハードウェアとソフトウェアの要件

ハードウェア要件

コンポーネント名購入場所
アルドゥイーノUNO R31Amazon.com / Amazon.in /バングッド
L293D モータードライバーシールド1Amazon.com / Amazon.in
ジャンパー線複数Amazon.com / Amazon.in /バングッド
USB A-Bケーブル1Amazon.com / Amazon.in
ロボットシャーシ、ホイール、ギヤードモーター(キット)Amazon.com / Amazon.in
ラインセンサーモジュール2Amazon.com / Amazon.in /バングッド
ブラックテープ1Amazon.com / Amazon.in

上記のコンポーネントを個別に購入することも、通常は必要なコンポーネントがすべて含まれているDIY ライン フォロワー ロボット キットを購入することもできます。

必要なソフトウェア

  • PCにArduino IDEバージョン2.1.1以上がインストールされている
  • Adafruit の Adafruit Motor Shield Library (V1) バージョン 1.0.1。

L293D モーター ドライバー シールドが必要なのはなぜですか? 

ここでは、L293Dモータードライバシールドを使用する必要があります。これは、ロボットで使用されるDCモーターは、Arduinoが直接供給できるよりも高い電圧と電流を必要とするためです。モータードライバは高い電力要件を安全に処理し、Arduinoへの損傷を防ぎます。 

また、双方向制御が可能で、モーターを正逆両方向に回転させることができます。

L293D モータードライバーシールド

L293dモータードライバーシールドと、シールドを使用してモーターを制御するために使用されるAdafruitライブラリ関数の詳細については、このチュートリアルをご覧ください:L293Dモータードライバーシールドチュートリアル

ラインフォロワーロボットの回路図

ライン追従ロボットの回路図

この回路は4つの部品で構成されています。赤外線センサー2個、L293Dモータードライバー1個、12V BOモーター4個、そしてArduinoボード1枚です。12V電源はここには示されていませんが、Arduinoに接続します。シールドはArduinoボードの上部に配置する必要があります。

センサーの VCC ピンとグラウンド ピンは、Arduino の VCC ピンとグラウンド ピンに接続されます。

左側の IR センサーまたはライン センサーのアナログ出力ピンは Arduino のアナログ入力ピン A0 に接続され、右側のライン センサーのアナログ出力ピンは Arduino のアナログ入力ピン A1 に接続されます。

左側のモーターはモーター ドライバー シールドのポート M3 に並列に接続され、右側のモーターはモーター ドライバー シールドのポート M4 に並列に接続されます。

❕注記

モータードライバとモーターをArduinoボードに接続した状態でコードを更新する場合は、安全上の注意事項を守ることが重要です。プログラミング用のUSBケーブルを接続する前に、モータードライバシールドの電源ジャンパーを外し、Arduinoから外部12V電源を取り外してください。

プログラミングが完了したら、USBケーブルを取り外し、Arduinoに12V電源を再接続し、シールドの電源ジャンパーを再接続します。これにより、コンポーネントの安全性が確保され、コーディングプロセス中の損傷を防ぐことができます。

Arduinoベースのラインフォロワーロボットの組み立て

すべての接続がわかったので、ロボットの組み立てを始めましょう。ロボットの組み立て手順は、動画の最後に掲載したビデオで段階的に説明しました。

ステップ1 ロボットを組み立てるには、まずシャーシが必要です。ここでは既製のシャーシを使用します。次に、 4つのモーターすべてを少なくとも15cmのワイヤーではんだ付けします。

モーターのはんだ付け

ステップ2:シャーシの保護カバーを外し、4つのモーター、ラインセンサー、ホイールをすべてシャーシに取り付けます。次に、左側モーター(前後)の赤い配線と、右側モーター(前後)の黒い配線を接続します。右側モーターも同様に接続します。

2つのラインセンサーの中心間距離は11 ~11.5cmにする必要があります。この距離は、正確なライン検出と黒テープに沿ったスムーズなナビゲーションに不可欠です。

センサーの LED (地面に最も近いセンサー部分) と平らな面の間の距離は、正確に2 cmに維持する必要があります。 

モーター、センサー、ホイールをシャーシに取り付ける

ステップ3 次に、モータードライバーシールドをArduino Unoボードに取り付け、両面テープまたは取り付けネジを使ってシャーシに取り付けます。しっかりと固定し、他の部品に簡単にアクセスできるように前面に配置してください。 

次に、回路図に従って、ラインセンサーとモーターをシールドに接続します。左側のモーターはモータードライバーシールドのポートM3に接続し、右側のモーターはシールドのポートM4に接続します。

Arduinoとモータードライバーをシャーシに接続する

ステップ4 次に、Arduino UNOをプログラムします。モータードライバーシールドのPWRジャンパーが接続されていないことを確認してください。

Arduino UNOのプログラミング

ステップ5: ロボットの背面にバッテリーパックを取り付け、結束バンドまたは両面テープで締め付けます。次に、PWRジャンパーを接続します。

バッテリーパックの取り付け

ロボットの準備ができました。50mm幅の黒いテープを使って経路を作りましょう。黒いテープの幅は4.8~5cmです。テープは光沢のあるものは使用しないでください。光沢のある表面はセンサーの光を反射し、正確な検出を妨げる可能性があります。

Arduino ラインフォロワーロボットコード

以下のスケッチは、ArduinoとAdafruit Motor Shieldを使ってラインフォロワーロボットを制御するように設計されています。コードをArduinoにアップロードしてください。

/* Library used: Adafruit Motor Shield library V1 version: 1.0.1For this code to run as expected: 1.The centre to centre distance between the Line sensors should be 11 to 11.5 cm2. The width of black tape should be 4.8 to 5 cm3. The distance of the sensor LED from the flat ground surface should be 2 cm.*/#include <AFMotor.h>// MACROS for Debug print, while calibrating set its value to 1 else keep it 0#define DEBUG_PRINT 0// MACROS for Analog Input#define LEFT_IR A0#define RIGHT_IR A1// MACROS to control the Robot#define DETECT_LIMIT 300#define FORWARD_SPEED 60#define TURN_SHARP_SPEED 150#define TURN_SLIGHT_SPEED 120#define DELAY_AFTER_TURN 140#define BEFORE_TURN_DELAY 10// BO Motor control related data here// Here motors are running using M3 and M4 of the shield and Left Motor is connected to M3 and Right Motor is connected to M4 using IC2 of the shieldAF_DCMotor motorL(3);  // Uses PWM0B pin of Arduino Pin 5 for EnableAF_DCMotor motorR(4);  // Uses PWM0A pin of Arduino Pin 6 for Enable// variables to store the analog valuesint left_value;int right_value;// Set the last direction to Stopchar lastDirection = 'S';  void setup() {#if DEBUG_PRINT    Serial.begin(9600);#endif    // Set the current speed of Left Motor to 0  motorL.setSpeed(0);  // turn on motor  motorL.run(RELEASE);  // Set the current speed of Right Motor to 0  motorR.setSpeed(0);  // turn off motor  motorR.run(RELEASE);  // To provide starting push to Robot these values are set  motorR.run(FORWARD);  motorL.run(FORWARD);  motorL.setSpeed(255);  motorR.setSpeed(255);  delay(40);  // delay of 40 ms}void loop() {  left_value = analogRead(LEFT_IR);  right_value = analogRead(RIGHT_IR);#if DEBUG_PRINT  // This is for debugging. To check the analog inputs the DETECT_LIMIT MACRO value 300 is set by analysing the debug prints  Serial.print(left_value);  Serial.print(",");  Serial.print(right_value);  Serial.print(",");  Serial.print(lastDirection);  Serial.write(10);#endif  // Right Sensor detects black line and left does not detect  if (right_value >= DETECT_LIMIT && !(left_value >= DETECT_LIMIT)) {    turnRight();  }  // Left Sensor detects black line and right does not detect  else if ((left_value >= DETECT_LIMIT) && !(right_value >= DETECT_LIMIT)) {    turnLeft();  }  // both sensors doesn't detect black line  else if (!(left_value >= DETECT_LIMIT) && !(right_value >= DETECT_LIMIT)) {    moveForward();  }  // both sensors detect black line  else if ((left_value >= DETECT_LIMIT) && (right_value >= DETECT_LIMIT)) {    stop();  }}void moveForward() {  if (lastDirection != 'F') {    // To provide starting push to Robot when last direction was not forward    motorR.run(FORWARD);    motorL.run(FORWARD);    motorL.setSpeed(255);    motorR.setSpeed(255);    lastDirection = 'F';    delay(20);  } else {    // If the last direction was forward    motorR.run(FORWARD);    motorL.run(FORWARD);    motorL.setSpeed(FORWARD_SPEED);    motorR.setSpeed(FORWARD_SPEED);  }}void stop() {  if (lastDirection != 'S') {    // When stop is detected move further one time to check if its actual stop or not, needed when the robot turns    motorR.run(FORWARD);    motorL.run(FORWARD);    motorL.setSpeed(255);    motorR.setSpeed(255);    lastDirection = 'S';    delay(40);  } else {    // When stop is detected next time then stop the Robot    motorL.setSpeed(0);    motorR.setSpeed(0);    motorL.run(RELEASE);    motorR.run(RELEASE);    lastDirection = 'S';  }}void turnRight(void) {  // If first time Right Turn is taken  if (lastDirection != 'R') {    lastDirection = 'R';    // Stop the motor for some time    motorL.setSpeed(0);    motorR.setSpeed(0);    delay(BEFORE_TURN_DELAY);    // take Slight Right turn    motorL.run(FORWARD);    motorR.run(BACKWARD);    motorL.setSpeed(TURN_SLIGHT_SPEED);    motorR.setSpeed(TURN_SLIGHT_SPEED);  } else {    // take sharp Right turn    motorL.run(FORWARD);    motorR.run(BACKWARD);    motorL.setSpeed(TURN_SHARP_SPEED);    motorR.setSpeed(TURN_SHARP_SPEED);  }  delay(DELAY_AFTER_TURN);}void turnLeft() {  // If first time Left Turn is taken  if (lastDirection != 'L') {    lastDirection = 'L';    // Stop the motor for some time    motorL.setSpeed(0);    motorR.setSpeed(0);    delay(BEFORE_TURN_DELAY);    // take slight Left turn    motorR.run(FORWARD);    motorL.run(BACKWARD);    motorL.setSpeed(TURN_SLIGHT_SPEED);    motorR.setSpeed(TURN_SLIGHT_SPEED);  } else {    // take sharp Left turn    motorR.run(FORWARD);    motorL.run(BACKWARD);    motorL.setSpeed(TURN_SHARP_SPEED);    motorR.setSpeed(TURN_SHARP_SPEED);  }  delay(DELAY_AFTER_TURN);}

コードの説明

まず、 ライブラリをインクルードします。これは、Adafruit Motor Shieldを介してモーターを制御するために使用されます。AFMotor.h

#include <AFMotor.h>

次に、アナログ入力とロボット制御用のマクロを定義します。

  • DEBUG_PRINT初期値は0に設定されています。キャリブレーション中に1に変更できます。
  • LEFT_IR 左右のラインセンサーが接続されているアナログピン(A0 と A1)を参照します。RIGHT_IR
  • DETECT_LIMITセンサーが黒線を検知する閾値です。センサーの読み取り値が300以上の場合、黒線が検知されたことを意味します。
  • FORWARD_SPEED、、 は それぞれ前進、急旋回、小旋回の速度を定義します。TURN_SHARP_SPEEDTURN_SLIGHT_SPEED
  • DELAY_AFTER_TURNロボットの旋回前後のモーター動作の遅延を制御するために使用されます。BEFORE_TURN_DELAY
// MACROS to for Debug print, while calibrating set its value to 1 else let it remain 0#define DEBUG_PRINT 0// MACROS for Analog Input#define LEFT_IR A0#define RIGHT_IR A1// MACROS to control the Robot#define DETECT_LIMIT 300#define FORWARD_SPEED 60#define TURN_SHARP_SPEED 150#define TURN_SLIGHT_SPEED 120#define DELAY_AFTER_TURN 140#define BEFORE_TURN_DELAY 10

次に、モーターを初期化します。左側のモーターは出力M3に、右側のモーターは出力M4に接続します。 

// BO Motor control related data here// Here motors are running using M3 and M4 of the shield and Left Motor is connected to M3 and Right Motor is connected to M4 using IC2 of the shieldAF_DCMotor motorL(3);  // Uses PWM0B pin of Arduino Pin 5 for EnableAF_DCMotor motorR(4);  // Uses PWM0A pin of Arduino Pin 6 for Enable

ここでいくつかのグローバル変数を定義します。

  • left_value左右のライン センサーからのセンサー読み取り値を保存するために使用されます。right_value
  • lastDirectionロボットの最後の動きを記録します。初期値は「S」に設定されており、ロボットが停止していることを意味します。
// variables to store the Analog Valuesint left_value;int right_value;// Set the Last Direction to Stopchar lastDirection = 'S';  

セットアップ関数では、デバッグが有効になっている場合( DEBUG_PRINT が1 に設定されている場合)、シリアル通信を初期化します。

次に、両方のモーターの速度を 0 に設定し、RELEASEを使用してモーターを停止します。これにより、モーターへの電源が切断されます。

その後、モーターを前進方向に最大速度(255)に設定し、最初の「プッシュ」を行います。これにより、ロボットはスタート直後から動き出すことができます。

void setup() {#if DEBUG_PRINT    Serial.begin(9600);#endif    // Set the current speed of left Motor to 0  motorL.setSpeed(0);  // turn on motor  motorL.run(RELEASE);  // Set the current speed of Right Motor to 0  motorR.setSpeed(0);  // turn off motor  motorR.run(RELEASE);  // To provide starting push to Robot these values are set  motorR.run(FORWARD);  motorL.run(FORWARD);  motorL.setSpeed(255);  motorR.setSpeed(255);  delay(40);  // delay of 40 ms}

ループ関数では、 analogReadを使用して左右の Line センサーから値を継続的に読み取ります。

  • デバッグが有効になっている場合は、これらの値を分析のためにシリアル モニターに出力します。

次に、センサーの値を確認し、どのセンサーが黒い線を検出したかに基づいてロボットの動きを決定します。

  • 右のセンサーが黒い線を検出したが、左のセンサーが検出しなかった場合、ロボットは右に曲がります。
  • 左のセンサーが黒線を検知し、右のセンサーが検知しない場合は、左に曲がります。
  • どちらのセンサーもラインを検出しない場合は、ロボットは前進します。
  • 両方のセンサーが黒い線を検出すると、ロボットは停止します。
void loop() {  left_value = analogRead(LEFT_IR);  right_value = analogRead(RIGHT_IR);#if DEBUG_PRINT  // This is for debugging. To check the analog inputs the DETECT_LIMIT MACRO value 300 is set by analysing the debug prints  Serial.print(left_value);  Serial.print(",");  Serial.print(right_value);  Serial.print(",");  Serial.print(lastDirection);  Serial.write(10);#endif  // Right Sensor detects black line and left does not detect  if (right_value >= DETECT_LIMIT && !(left_value >= DETECT_LIMIT)) {    turnRight();  }  // Left Sensor detects black line and right does not detect  else if ((left_value >= DETECT_LIMIT) && !(right_value >= DETECT_LIMIT)) {    turnLeft();  }  // both sensors doesn't detect black line  else if (!(left_value >= DETECT_LIMIT) && !(right_value >= DETECT_LIMIT)) {    moveForward();  }  // both sensors detect black line  else if ((left_value >= DETECT_LIMIT) && (right_value >= DETECT_LIMIT)) {    stop();  }}

前進

最後の移動が前進でなかった場合、ロボットは前進を開始するために一時的に全速力で走行します。それ以外の場合は、定義された速度で走行します。FORWARD_SPEED

void moveForward() {  if (lastDirection != 'F') {    // To provide starting push to Robot when last direction was not forward    motorR.run(FORWARD);    motorL.run(FORWARD);    motorL.setSpeed(255);    motorR.setSpeed(255);    lastDirection = 'F';    delay(20);  } else {    // If the last direction was forward    motorR.run(FORWARD);    motorL.run(FORWARD);    motorL.setSpeed(FORWARD_SPEED);    motorR.setSpeed(FORWARD_SPEED);  }}

停止

両方のセンサーが黒線を検出すると、ロボットは停止を確認するために少し前進します。再び停止条件を検出すると、ロボットは完全に停止します。

void stop() {  if (lastDirection != 'S') {    // When stop is detected move further one time to check if its actual stop or not, needed when the robot turns    motorR.run(FORWARD);    motorL.run(FORWARD);    motorL.setSpeed(255);    motorR.setSpeed(255);    lastDirection = 'S';    delay(40);  } else {    // When stop is detected next time then stop the Robot    motorL.setSpeed(0);    motorR.setSpeed(0);    motorL.run(RELEASE);    motorR.run(RELEASE);    lastDirection = 'S';  }}

右折

ロボットが初めて右に曲がる場合、少しの間停止し、わずかに旋回した後、必要に応じてさらに急な旋回を続けます。

void turnRight(void) {  // If First time Right Turn is Taken  if (lastDirection != 'R') {    lastDirection = 'R';    // Stop the motor for some time    motorL.setSpeed(0);    motorR.setSpeed(0);    delay(BEFORE_TURN_DELAY);    // take Slight Right turn    motorL.run(FORWARD);    motorR.run(BACKWARD);    motorL.setSpeed(TURN_SLIGHT_SPEED);    motorR.setSpeed(TURN_SLIGHT_SPEED);  } else {    // take sharp Right turn    motorL.run(FORWARD);    motorR.run(BACKWARD);    motorL.setSpeed(TURN_SHARP_SPEED);    motorR.setSpeed(TURN_SHARP_SPEED);  }  delay(DELAY_AFTER_TURN);}

左折

この関数はロボットの左旋回を制御します。変数 を比較することで、ロボットが初めて左旋回するかどうかを確認します。turnLeft()lastDirection

最初の左折の場合、ロボットは両方のモーターを短時間停止し、右のモーターを前方に、左のモーターを低速で後方に動かしてわずかに左に曲がります。

ロボットが既に左折している場合は、停止をスキップし、モーターを高速で回転させて急激に左折します。最後に、次の移動前に旋回を完了するための遅延( )が追加されます。DELAY_AFTER_TURN

void turnLeft() {  // If First time Left Turn is Taken  if (lastDirection != 'L') {    lastDirection = 'L';    // Stop the motor for some time    motorL.setSpeed(0);    motorR.setSpeed(0);    delay(BEFORE_TURN_DELAY);    // take slight Left turn    motorR.run(FORWARD);    motorL.run(BACKWARD);    motorL.setSpeed(TURN_SLIGHT_SPEED);    motorR.setSpeed(TURN_SLIGHT_SPEED);  } else {    // take sharp Left turn    motorR.run(FORWARD);    motorL.run(BACKWARD);    motorL.setSpeed(TURN_SHARP_SPEED);    motorR.setSpeed(TURN_SHARP_SPEED);  }  delay(DELAY_AFTER_TURN);}

ラインフォロワーロボットをキャリブレーションするにはどうすればいいですか?

  1. コードで MACRO を 1 に設定し、コードを Arduino にアップロードします。PWR ピン ジャンパーが切断されていることを確認します。
  2. ケーブルが Arduino に接続されている間に、ロボットを黒い線の上に置き、黒い線がセンサーの間に正確に位置していることを確認します。
  3. ターミナルを開き、シリアルモニターウィンドウの出力を確認します。
  4. 最初の値は左側のセンサーのアナログ出力であり、カンマの後の値は右側のセンサーのアナログ出力です。
  5. 次に、左のセンサーを黒い線の上に置くと、最初の値が増加することがわかります。同様に、右のセンサーを黒い線の上に置くと、2 番目の値が増加することがわかります。
  6. センサーが黒線を少し超えた時に得られる最小値は、コード内のMACRO DETECT_LIMITの値です。この値は左右のセンサーで同じです。ロボットのコードでこの値を更新し、Arduinoにコードをアップロードしてください。
  7. Arduinoからケーブルを外します。Arduinoに12V電源を接続し、PWRジャンパーを配置して、自律型ラインフォロワーロボットを起動します。

トラブルシューティング

問題 1: ロボットがコースから外れたり、一貫してラインをたどることができなかったりします。

解決策:センサーモジュールの位置合わせを確認し、必要に応じて位置を調整してください。また、モーターが正しく機能していること、およびホイールがシャーシに正しく取り付けられていることを確認してください。

問題 2: センサーの読み取り値が不安定または信頼できない。

解決策:センサーモジュールとロボットが動作する表面を清掃し、センサーの読み取りに影響を与える可能性のある汚れやゴミを取り除きます。さらに、配線の接続部に緩みや損傷がないか確認してください。

問題 3: モーターが Arduino コマンドに応答しません。

解決策:Arduino、モータードライバモジュール、そしてモーター間の配線接続を再確認してください。モータードライバモジュールに電源が供給されていること、そしてArduinoがモーターを制御するための正しい信号を送信していることを確認してください。