PR

Arduinoでルンバのようなお掃除ロボットを自作してみた【後編】

こんにちは、メカ旦那です!

メカ旦那
メカ旦那

Arduinoを使ってなんか作品を作りたい!できれば生活の役に立つものが良い!

そう思った私は、ルンバのようなお掃除ロボットを作ることにしました。今回は後編です。前編はこちらで解説しているので、まだ読まれていない方はぜひチェックしてくださいね。

電気回路

回路図

回路図はfritzingを用いて作成しています

回路図はこんな感じです。(中央にあるモータードライバーはfritzingにパーツ登録が無かったので、別のもので描きました。なので若干配線が違いますが、大まかにはこんな感じです。)

配線が複雑なので、丁寧に解説していきます!

モータードライバー

まずはArduinoとL293Dモータードライバーシールドを配線します。Arduinoのソケットにドライバーのピンを挿すだけで終わりです。デジタルピン、アナログピン、電源ピンそれぞれ正しいソケットに挿入してくださいね。

メカ坊や
メカ坊や

このモータードライバーってどんな役割があるんですか?ドライバー無しでモーターを直接Arduinoに接続してはダメなんですか?

メカ旦那
メカ旦那

一般的にモーターの消費電流は、Arduinoの出力電流より大きいです(今回使うモーター「RE-260」の消費電流は700 mA、Arduinoの出力電流は40 mAです)。そのため、直接繋ぐとArduinoが無理に電流を流そうとして、壊れてしまいます!そこで、モーターへの給電は代わりにドライバーから行うことで、Arduinoの故障を防ぎます。ちなみにArduinoからはドライバーに制御信号を出力し、給電タイミングを制御します。

合体することでArduinoのソケットは全て埋まったので、他の機器はドライバーに繋ぎます。Arduinoはドライバー経由で他の機器と信号をやり取りします。

モーター

続いて、モーターをドライバーに接続します。今回はM1、M4の端子を使いました。こちらで解説したように、QIコネクタを圧着しておくと、接続が容易になります。

超音波センサ

障害物検知のため、前方に超音波センサ(HC-SR04)を3つ付けました。

今回のセンサ「HC-SR04」はトランスミッタから超音波を送信し、前方の物体に当たって跳ね返ってきたものをレシーバで受信することで、その物体との距離を測定します。基板から20~4000 mm の距離、15度の角度まで超音波が届きます。

15度ということで、センサ1つだけだと検知範囲が狭いので、3つ付けてみました。

配線について、HC-SR04は4ピンあります。VccGndは電源供給のためのピンで、Arduino側ではそれぞれ5VGNDに接続します。Trig(トリガー)は超音波送信の合図信号を出すピンです。超音波は常に出している訳ではなく、Arduinoから一定間隔で合図信号をTrigに送り、トランスミッタから超音波を送信しています。この合図信号は、IT用語ではトリガ信号と呼ばれています。なので、センサのピン名もTrigとなっている訳ですね。このピンはArduinoの14ピンに接続しました。また、Echo(エコー)は超音波を送信した後、返ってくるまでHighになるピンです。このHighの時間を使って障害物との距離を測定します。詳しくはソースコードで解説しますね。EchoはArduinoの16ピンに接続しました。

ちなみに、Arduino側はピンを挿入するだけだと固定が弱いので、はんだづけをしました。

メカ坊や
メカ坊や

今回は3つのセンサを付けるんですよね。1センサ当たり4ピンあるということは、計12本配線をArduinoに接続するという事ですよね・・・なんかゴチャゴチャしそうですね・・・

メカ旦那
メカ旦那

下図のように、Arduinoから中央のブレッドボードに4本繋いで、そこから左右のブレッドボード(センサ)に4本ずつ繋ぐようにしました。これにより、Arduinoへの12本接続が不要になり、スッキリしますね!

電池・スイッチ

電池はモータードライバーの動作電圧が4.5~25Vである事と、何回も使用できるように、9Vの充電池を使いました。またスイッチはON・OFFがしやすいように、ロッカースイッチを用いました。配線は下図のようにドライバーの外部電源端子にそれぞれ繋いでいます。どちらもロボットの上面に設置することで、充電のための取り外しと、操作が簡単になるようにしました。

ソースコード

全体

ソースコードはこちらになります!長いので1つ1つ解説します。

// Adafruit Motor Shield library - Version: Latest 
#include <AFMotor.h>

//モータードライバーシールド
AF_DCMotor motorRight(1);  // モーター(進行方向の右輪)をモーター端子1に接続
AF_DCMotor motorLeft(4);  // モーター(進行方向の左輪)をモーター端子4に接続

//超音波センサ
#define trigPin 14            //TrigPinの定義。今回は14ピンに設定。文末の;は不要。
#define echoPin 16            //EchoPinの定義。今回は16ピンに設定。文末の;は不要。
 
//変数
float echoHigh = 0;           //Echo出力のHigh期間を格納
float distance = 0;           //計算した距離を格納する変数
const int speed = 100 ;            //モータースピード値を格納
  
 void setup(){
  //超音波センサ
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}
 
 void loop(){
  digitalWrite(trigPin, LOW);                     //trigPinからLOWを出力
  delayMicroseconds(10);                          //10us待機
    
  //超音波を出力するためのトリガ信号発信
  digitalWrite(trigPin, HIGH);                    //トリガ信号HIGH
  delayMicroseconds(10);                          //トリガ信号パルス幅10 usを生成
  digitalWrite(trigPin, LOW);                     //トリガ信号Low
    
  echoHigh = pulseIn(echoPin, HIGH);              //echoPinのHigh時間を格納。pulseIn(パルスを入力するピン番号、測定するパルスの種類、タイムアウトまでの時間(省略可))
  distance = 340 * echoHigh / 2 / 1000;          //音速340m/sを用いて距離計算。echoHighは往復の距離(μm)であるため、2で割り片道に、1000で割りmmに直す

  if(distance > 30){                              //もし障害物との距離が30 mm 以上なら直進
    motorRight.setSpeed(speed);       // モータースピード(0~255の範囲)
    motorLeft.setSpeed(speed); 
    motorRight.run(FORWARD);        // モーター1とモーター2を正回転させる
    motorLeft.run(FORWARD);
  }
    
  if(distance <= 30){                             //もし障害物との距離が30 mm 以下なら旋回
    motorRight.run(RELEASE);                          // モーターを停止させる(ブレーキ)
    motorLeft.run(RELEASE);
    delay(1000);
    
    distance = 50;                               //距離測定を一時停止
    
    motorRight.setSpeed(speed);                         // 後進
    motorLeft.setSpeed(speed);
    motorRight.run(BACKWARD);  
    motorLeft.run(BACKWARD);
    delay(1000);
    
    motorRight.setSpeed(speed);                          //90°旋回
    motorLeft.setSpeed(speed);
    motorRight.run(FORWARD);  
    motorLeft.run(BACKWARD);
    delay(500);    
      
    distance = 340 * echoHigh / 2 / 1000;         //距離測定再開   
    }
    
}

ライブラリ宣言

まずは冒頭のこちらです!

// Adafruit Motor Shield library - Version: Latest 
#include <AFMotor.h>

こちらは、ライブラリである「Adafruit Motor Shield library」の使用宣言です。1から複雑なコードを作成しなくとも、このライブラリを使うことで、簡単にドライバー、モーターを動かすことが可能です。エディターによってライブラリの使用方法が若干異なるので解説します。

エディターが Web editor の場合

先ほどのコードをそのままエディターにコピペするだけでOKです。ただ、せっかくですので、ライブラリを探す方法についても解説します。

1. サイドバーから「Libraries」を選択
2. 「LIBRARY MANAGER」を選択

3.「motor shield」と検索
4.「ADAFRUIT MOTOR SHIELD LIBRARY」の☆をクリック(その下のV2ではないので注意してください!)

5. 先ほどのライブラリが「FAVORITES」に登録されました。こちらをクリック
6. 「INCLUDE」をクリック
7. 「#include <AFMotor.h>」が入力されました。こちらでライブラリ宣言は完了です!

Arduino IDEでは後述の通りライブラリをPCにインストールする必要がありますが、Web editorは不要です。PC容量も消費せずオススメです!

エディターが Arduino IDE の場合

1.「スケッチ」を選択
2.「ライブラリをインクルード」を選択
3.「ライブラリを管理」を選択

4.「motor shield」で検索
5.「Adafruit Motor Shield library」の「インストール」をクリック(その下のV2ではないので注意してください!)

6.インストール完了すると「INSTALLED」と表示されます

7.「#include <AFmotor.h>」と入力。こちらでライブラリ宣言は完了です!

ちなみに、Web editorでは前述の通りインストール不要で「#include <AFmotor.h>」のコピペで終わるので非常に楽です。是非活用を検討してみて下さい!

定義

次は変数の定義です!

AF_DCMotor motorRight(1);  
AF_DCMotor motorLeft(4);

モータードライバーの端子1には右輪用モーターを、端子4には左輪用モーターを接続しており、それぞれ、「motorRight」「motorLeft」と定義しています。

#define trigPin 14          
#define echoPin 16    

Arduinoの14ピンは超音波センサのtrigに繋がっているので「trigPin」、16ピンはechoに繋がっているので「echoPin」と定義しています。 ちなみに、#defineは文末の;は不要です。

float echoHigh = 0;
float distance = 0; 
const int speed = 100 ;

echoPin(16ピン)のHigh時間を格納する変数を「echoHigh」、その値を元に物体との距離計算した値を格納する変数を「distance」と定義しました。最初はまだ測定していないので0を格納しています。また、モーターのrpm(毎分の回転速度)を格納する定数を「speed」と定義しました。後述するsetSpeed関数にこのspeedを格納して、回転速度を指定します。0~255の範囲で入力でき、今回は試しに100を入れてみました。

 void setup(){
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
}

trigPinを出力ピン(OUTPUT)、echoPinを入力ピン(INPUT)に定義しています。

超音波センサ

続いて、センサから超音波を送信します。超音波を送信するためには、トリガ信号を出す必要があります。

 void loop(){
  digitalWrite(trigPin, LOW);                     
  delayMicroseconds(10);                          
    
  digitalWrite(trigPin, HIGH);                    
  delayMicroseconds(10);                          
  digitalWrite(trigPin, LOW);                            

まず、trigPinをLOWにして、10 μs 維持します。その後、HIGHにして10 μs 維持します。そしてLOWにします。LOWにした瞬間超音波が送信されます。

  echoHigh = pulseIn(echoPin, HIGH);                      

pulseIn関数を使って、echoPinのHIGH時間をechoHighに格納します。

  • pulseIn(指定ピン番号、パルスの種類、タイムアウトまでの時間(省略可))
    指定ピンに入力されるパルス時間情報を取得します。例えばパルスの種類をHIGHにした場合、指定ピンがHIGHに変わると時間計測を始めます。そしてLOWに戻ったら、それまでの時間(つまりパルス幅の長さ)を [μs] 単位で格納します。
  distance = 340 * echoHigh / 2 / 1000;         

echoHighは単位が時間 [μs] なので、音速340m/sを掛けて距離に変換します。また、往復になっているので、2で割って片道にし、更に1000で割って [mm] に直します

モーター

最後に、超音波センサで算出した障害物との距離に応じて、モーターを制御します。その前に、重要な関数を2つご紹介します!

  • ピン番号.setSpeed(rpm)
    指定したピン番号に繋がるモーターが毎分何回転するか(RPM)を設定します。実際にモータを回転させるのは次のrun関数で、こちらはRPMを設定するだけです。
    例)motorRight.setSpeed(100); : 右輪のRPMを100に設定します
  • ピン番号.run(走行モード)
    モーターの走行モードを指定して、実際に走らせます。モードは3種類です。
    ・FORWARD : 前進(正回転)
    ・BACKWARD : 後進(逆回転)
    ・RELEASE : 停止
    例)motorRight.run(FORWARD); : 右輪を前進させます
    ※モーターの配線によって、回転方向が逆になる事もあるので、実際に動かして確認してくださいね!

離れている場合(障害物との距離が 30 mm 以上)

if(distance > 30){                              
    motorRight.setSpeed(speed);      
    motorLeft.setSpeed(speed); 
    motorRight.run(FORWARD);        
    motorLeft.run(FORWARD);
  }
 

もし障害物と十分離れている場合(距離が30 mm 以上)、両輪とも正回転させて、前進させます。冒頭定義したspeed(rpm : 100)で回転させます。

近い場合(障害物との距離が 30 mm 以下)

if(distance <= 30){                             
    motorRight.run(RELEASE);                          
    motorLeft.run(RELEASE);
    delay(1000);

もし障害物と近い場合(距離が30 mm 以下)、まずモーターを停止させて、1000 μs(1 s)維持します。

    distance = 50;                              

次に、距離測定を一時停止すべく、一旦50をdistanceに格納します。(もし一時停止しない場合、この後の後進で距離が30 mm以上になった際に前進し、また障害物に近づく事になるため、それを防止します)

    motorRight.setSpeed(speed);                         
    motorLeft.setSpeed(speed);
    motorRight.run(BACKWARD);  
    motorLeft.run(BACKWARD);
    delay(1000);
    
    motorRight.setSpeed(speed);                          
    motorLeft.setSpeed(speed);
    motorRight.run(FORWARD);  
    motorLeft.run(BACKWARD);
    delay(500);   

その後、1000 μs(1 s)後進します。そして、500 μs(0.5 s)右輪を正回転、左輪を逆回転させて旋回します。大体90°回転するように、回転時間は調整しました。

    distance = 340 * echoHigh / 2 / 1000;         
    }
    
}

旋回が完了した後、距離測定を再開させ、障害物と離れている事を確認したら前進します。まだ近い場合は再度後進・旋回を行います。

まとめ

作り方の説明は以上です!実際に走らせた様子はこちらです。

よかったら参考にしてみて下さい!

メカ旦那

旧帝大工学部を卒業後、FA業界で会社員をしています。
電子工作の面白さを伝えるべく、ザックリ解説します!

メカ旦那をフォローする
Arduino
ザックリ解説Web

コメント

スポンサーリンク