24
Arduino プログラミング 1 工学電気電子工学科 電気電子工学実験3 白井研究室取扱説明書 Arduino (アルデュイーノ)プログラミング 1. Arduino Wikipedia によれば、Arduino とは「AVR マイコン、入出力ポ ートを備えた基板、C 言語風の Arduino 言語とそれの統合開 発環境から構成されるシステム」である。 本実験では Raspberry Pi というボードコンピュータが「主」、 Arduino は「従」という位置づけである。Raspberry Pi Arduino と通信することにより、センサー情報を取得し、モ ーターを制御する、そういうシステムを構成する。 2. Arduino のプログラミング環境 Raspberry Pi PC 上の Arduino IDE (Arduino プログラム開発環境システム)でプログラムを 書き(伝統的に「スケッチ」と呼ばれる)、それを USB を介して Arduino に送り込む。一旦 プログラムが書き込まれれば、新たに他のプログラムが書き込まれない限り(Arduino の電 源を OFF にしても)、そのプログラムが保持される。 本実験では、Raspberry Pi ArduinoIDE の使用を前提としている。 2. Raspberry Pi のデスクトップ(一) Arduino IDE のアイコン 1. Arduino Uno

Arduino - lang.sist.chukyo-u.ac.jplang.sist.chukyo-u.ac.jp/Classes/Experiment3/2019/4_Arduino.pdf · Arduino プログラミング 3 (2) ツール (Tools) タブで、ボード (Boards)

  • Upload
    others

  • View
    5

  • Download
    0

Embed Size (px)

Citation preview

Arduinoプログラミング 1

工学部電気電子工学科 電気電子工学実験3 白井研究室取扱説明書

Arduino (アルデュイーノ)プログラミング

1. Arduino

Wikipediaによれば、Arduinoとは「AVR マイコン、入出力ポ

ートを備えた基板、C言語風の Arduino言語とそれの統合開

発環境から構成されるシステム」である。

本実験では Raspberry Piというボードコンピュータが「主」、

Arduinoは「従」という位置づけである。Raspberry Piが

Arduinoと通信することにより、センサー情報を取得し、モ

ーターを制御する、そういうシステムを構成する。

2. Arduino のプログラミング環境

Raspberry Piや PC上の Arduino IDE (Arduino プログラム開発環境システム)でプログラムを

書き(伝統的に「スケッチ」と呼ばれる)、それを USBを介して Arduinoに送り込む。一旦

プログラムが書き込まれれば、新たに他のプログラムが書き込まれない限り(Arduinoの電

源を OFFにしても)、そのプログラムが保持される。

本実験では、Raspberry Pi の ArduinoIDE の使用を前提としている。

図 2. Raspberry Piのデスクトップ(一部)

Arduino IDEのアイコン

図 1. Arduino Uno

Arduinoプログラミング 2

Arduino IDEは、Raspberry Piのデスクトップ画面から、図 2に示す Arduino IDEのアイコ

ンをダブルクリックにより起動する。図 3に起動後に開かれるウィンドゥを示す。

図 3. Arduino IDEの起動

図 4. デフォルトの IDE ウィンドゥ

図 4 に、起動後に表示される IDE ウィンドゥを示す。ここでプログラムを書いたり、既に

あるプログラムの編集をしたりできる。

Arduino IDEでは C++に準じたプログラミング言語を使用する。ただし、main関数は存

在しない。その代わりに図 4に示されている setup 関数と loop 関数(ともに引数は取らな

い)がなければならない。setup関数は、Arduinoが起動後 (注意:Arduinoはボードコンピュ

ータのことで、Arduino IDEは Raspberry Piなどで動くプログラミング環境であり、全くの

別モノ。Arduino IDEでプログラムを書き、それを Arduinoに送り込むことで、Arduinoが

動作する)、最初に呼ばれる関数でありしかもただ一回だけ実行される。それに対し、loop

関数は、setup関数の終了後に呼ばれる関数で、しかもこれが永久に繰り返される(ループ

実行される)。したがって、Arduinoではある行動を一回だけ行わせたければ、setup関数に

その行動を書き、loop関数には何も書かない、という方法が取られる。

3. Arduino IDE の実行環境のチェック

正常に Arduino IDEが動作するためには次のことをチェックする必要がある。

(1) Raspberry Piと Arduinoボードとを USBケーブルで接続していること(図 5)

setup関数

loop関数

Arduinoプログラミング 3

(2) ツール(Tools)タブで、ボード(Boards)とポート(Port)が正しく選択されていること

このためには、図 6 に示すように、「ツール」タブをクリックし、「ボード」の欄に

Arduino/Genuino Unoが表示されていること、また「シリアルポート」の欄に

/dev/tty/ACM0 (Arduino/Genuino UNO)が表示されていることを確認する。もしも違ってい

図 6. Arduino IDEのツールタブで、ボードとシリアルポートを確認する

図 5. USBケーブルで Raspberry Pi と Arduinoを接続

Arduino側

Raspberry Pi側

Arduinoプログラミング 4

る場合は、その欄をマウスでクリックし、それぞれの項目を選択すること。

4. Arduino プログラムの例

注意: Arduinoのピン番号とモータ制御の関係は 6 項で説明する。ここでは Arduinoプログ

ラムの書き方の例の紹介だけにとどめている。

Arduino IDEを起動し、中央の欄にプログラムを書き、それを Arduinoに書き込む(アップ

ロードする)ことにより、Arduinoに何かをさせることができる。ここでは最初からプロ

グラムを書くのではなく、既にあるプログラムを利用することを考える。そしてそのプロ

グラムを例として Arduinoプログラミングについて紹介する。

参考資料:

• 簡単な資料: http://lang.sist.chukyo-u.ac.jp/Classes/Experiment3/Arduino.pdf

• Arduino日本語リファレンス: http://www.musashinodenpa.com/arduino/ref/

図 7に示すように、Arduino IDEの『ファイル」タブをクリックし、「開く」を選択する。

そして、Arduino ディレクトリの中にある forward_back を選び(図 8)、マウスでクリックす

る(図 9)。

図 7. Arduino IDEのファイルタブで「開く」を選択

Arduinoプログラミング 5

図 8. forwad_backを選択する

図 9. forward_backディレクトリの中にある forward_back.inoを選択する

すると、新たにウィンドゥが開き、forward_backファイルの中身が表示される(図 10)。

ここで表示されたプログラム(forward_back.ino)を示したものが図 11である。

図 9. forward_backディレクトリの中にある forward_back.inoを選択する

Arduinoプログラミング 6

図 10. forward_back.inoを選択して開いたウィンドゥ

//www.elegoo.com // Left motor truth table // ENA IN1 IN2 Description // LOW Not Applicable Not Applicable Motor is off // HIGH LOW LOW Motor is stopped (brakes) // HIGH HIGH LOW Motor is on and turning forwards // HIGH LOW HIGH Motor is on and turning backwards // HIGH HIGH HIGH Motor is stopped (brakes) // Right motor truth table // ENB IN3 IN4 Description // LOW Not Applicable Not Applicable Motor is off // HIGH LOW LOW Motor is stopped (brakes) // HIGH LOW HIGH Motor is on and turning forwards // HIGH HIGH LOW Motor is on and turning backwards // HIGH HIGH HIGH Motor is stopped (brakes) // The direction of the car's movement // Left motor Right motor Description // stop(off) stop(off) Car is stopped // forward forward Car is running forwards // forward backward Car is turning right // backward forward Car is turning left // backward backward Car is running backwards //define the L298n IO pin #define ENB 5 #define IN1 7 #define IN2 8 #define IN3 9 #define IN4 11 #define ENA 6

Arduinoプログラミング 7

図 11. forward_back プログラム

これはモーターを制御し、ロボットカーを前後に動かすプログラムである。この詳細は6

項で述べることとして、このプログラムによって車を実際に動かしてみよう。

そのための準備は次の通り:

(1) モーターに電源を供給するため、電源スイッチ(Raspberry Pi の下にある)を ONにする

(図 12)。

(2) Arduino IDEでアップロード・アイコン(図 13で黄色く表示されている右矢印ボタン)を

クリックする。これによりコンパイルが行われ、エラーがなければ、プログラムは Arduino

にアップロードされる。

void setup() { pinMode(ENB, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT); pinMode(ENA, OUTPUT); digitalWrite(ENA, HIGH); digitalWrite(ENB, HIGH); delay(1000); digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH); //go forward delay(1000); digitalWrite(IN1, LOW); digitalWrite(IN2, LOW); digitalWrite(IN3, LOW); digitalWrite(IN4, LOW); //stop delay(1000); digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); //go back delay(1000); digitalWrite(IN1, LOW); digitalWrite(IN2, LOW); digitalWrite(IN3, HIGH); digitalWrite(IN4, HIGH); //stop delay(1000); } void loop() { delay(1000); }

Arduinoプログラミング 8

アップロードが終了すると、Arduinoはこのプログラムによる実行がすぐに行われるの

で注意すること。つまり予めロボットカーを障害物のない平坦なところに置いておく!

さて、どのような動きをしただろうか。6 項で分析し、作り変えてみることにしよう。

以上により、Arduino IDEを用いて、プログラムにより Arduino(ひいてはロボットカー)

を制御する方法がわかったことになる。なお、モーター電源を ONにする前にプログラム

をアップロードした場合は、モーター電源を ONにした後、Arduinoのリセットスイッチを

押すことでロボットカーを動かせることを知っておくと良い(図 14)。

図 14. Arduinoのリセットスイッチ

5. ロボットカーの終了のさせ方

図 12. 電源スイッチ 図 13.プログラムのアップロード

Arduinoプログラミング 9

ロボットカーは車体やバッテリーの他に、Arduino、それが制御するモーター、Arduinoと通信する Raspberry Piとで構成されている。したがって実験終了時には、それぞれを「終

了」させなければならない。

(1) モーターと Arduino の終了

図 12 に示す電源スイッチを OFFにする。ただし、Raspberry Piと Arduinoが USBケーブ

ルで接続されている場合、Raspberry Piから電源が供給されるため、これだけでは Arduinoは終了しない。

(2) Raspbery Piの終了

「Raspberry Piを使ってみる」の 9 項にあるように、Raspberry Piの OSのシャットダウン

を行い、それから 5 秒以上後でモバイルバッテリーの電源コードを引き抜く。

(1)と(2)は必ずしもこの順番でなくてもよい。Raspberry Piはとても壊れやすいので扱いに

注意すること。それに対し Arduinoやモーターは電源 OFFはいつでもできる。

6. Arduino プログラム演習

図 11に示した forward_backプログラムを分析し、これを作り変えよう。

図 11 (一部) 再掲 forward_backプログラムの前半

// Left motor truth table // ENA IN1 IN2 Description // LOW Not Applicable Not Applicable Motor is off // HIGH LOW LOW Motor is stopped (brakes) // HIGH HIGH LOW Motor is on and turning forwards // HIGH LOW HIGH Motor is on and turning backwards // HIGH HIGH HIGH Motor is stopped (brakes) // Right motor truth table // ENB IN3 IN4 Description // LOW Not Applicable Not Applicable Motor is off // HIGH LOW LOW Motor is stopped (brakes) // HIGH LOW HIGH Motor is on and turning forwards // HIGH HIGH LOW Motor is on and turning backwards // HIGH HIGH HIGH Motor is stopped (brakes) // The direction of the car's movement // Left motor Right motor Description // stop(off) stop(off) Car is stopped // forward forward Car is running forwards // forward backward Car is turning right // backward forward Car is turning left // backward backward Car is running backwards // define the L298n IO pin #define ENB 5 #define IN1 7 #define IN2 8 #define IN3 9 #define IN4 11 #define ENA 6

ほとんどすべてコメント

Arduinoプログラミング 10

みて分かるように、これは Cプログラミングとほぼ同じ文法と用語を用いている。コメン

トは// で始まり、#define は定数宣言である。つまり、最後の 6行以外はすべてコメントで

ある。ただこのコメントはロボットカーのモーター制御にはとても重要で、これ以降のプ

ログラムはこれに基づいていることに注意しよう。

Arduinoには電源やグラウンド以外に、ボード上に次のようなピンがある:

• 14本のデジタル IO ピン(入力(Input)にも出力(Output)にも使えるデジタル信号用のピ

ン。ピン番号 0〜13。デジタルの場合 0V の信号が LOW、5V の信号が HIGH に相当

する)

• 6本のアナログ IN ピン(入力専用、ピン番号 0〜5)がある。0V から 5V までの信号は

0から 1023までの数値に変換される。

なお、デジタ IO ピンのうち、ピン番号 3, 5, 6, 9, 10, 11はプログラムによって、アナログ

OUT(出力)ピンとして扱える(アナログ出力の場合、取りうる値は 0〜255であり、0が 0V、

255が 5V に対応する)。

次に示す pinMode文はデジタル IO ピン 9を出力として使えるようにするものである(注:

OUTPUTは INPUTとシステムの予約語。アナログ出力するかデジタル出力するかは出力命

令に依存する):

pinMode(9, OUTPUT);

Arduinoのプログラムの多くはアナログ IN ピンやデジタル IN ピンから信号を受取り、何ら

かのアルゴリズムによって OUTピンに出力を行ってモーターを制御するものである。

本実験で用いるモーター制御の仕組みを図 15に示す。L298Nというモーター制御ボード

用いて、ロボットカーのモーター制御を行っている。

図 11(前半)にあるように、

//define the L298n IO pin

#define ENB 5

#define IN1 7

#define IN2 8

#define IN3 9

#define IN4 11

#define ENA 6

Arduinoの 5, 6, 7, 8, 9, 11, 6番ピン(すべてデジタル IO ピン)をモーター制御ボード L298Nに

接続している。そしてこれらのピンに適切な信号を送ることで(L298Nを介して)4つのモー

ターの時計回り回転、逆時計回り回転、停止をコントロールしているのである。

Arduinoプログラミング 11

左側のモーターは次のような制御を受ける:

// ENA IN1 IN2 説明

// LOW 無関係 無関係 モーター停止

// HIGH LOW LOW モーター停止(ブレーキ)

// HIGH HIGH LOW モーターは前進回転

// HIGH LOW HIGH モーターは後方回転

// HIGH HIGH HIGH モーター停止(ブレーキ)

ENA は左側のモーターの速度を決めるもので、LOW の場合はモーター停止となる。ENA

が HIGH の場合、IN1(7番ピン)と IN2(8番ピン)の値の組み合わせで、モーターの回転方向

(と停止)が決定される。右側のモーターも左側と同様に、ENB、IN3(9番ピン)、IN4(11

番ピン)の組み合わせで動きが決まる:

// ENB IN3 IN4 説明

// LOW 無関係 無関係 モーター停止

// HIGH LOW LOW モーター停止(ブレーキ)

// HIGH LOW HIGH モーターは前進回転

// HIGH HIGH LOW モーターは後方回転

// HIGH HIGH HIGH モーター停止(ブレーキ)

図 15. Arduino(下)とモーター制御ボード L298N(上)

Arduinoプログラミング 12

見て分かるように、右側と左側のモーターは「前進」と「後退」では入力信号の組み合わ

せが異なる。実はどちらのモーターも時計回り、半時計回りのための入力は同じである。

これらが向き合わせで設置されるため、このように組み合わせが異なるのである。

演習 1. 上の事柄を、図をいれて自分の言葉で説明してみよ。

次に図 11 の後半をみてみよう。

見て分かるように、これは setup関数と loop関数の二つだけが定義されている。しかも

loop 関数の本体は delay(1000)だけである。ちなみに delay関数は「動作を止める」ための

関数で、引数の単位は msである。つまり delay(1000)により動作は 1.000s止まる(実はこ

れが延々と繰り返される)。loop 関数は内容がないことがわかったので setup関数を見よう。

setup関数は『こんなプログラムを書いてはいけない」という見本のようなものである。こ

こではこのプログラムを書き換えることを考え、まずこれが何をしているかを分析する。

void setup() { pinMode(ENB, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT); pinMode(ENA, OUTPUT); digitalWrite(ENA, HIGH); digitalWrite(ENB, HIGH); delay(1000); digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH); //go forward delay(1000); digitalWrite(IN1, LOW); digitalWrite(IN2, LOW); digitalWrite(IN3, LOW); digitalWrite(IN4, LOW); //stop delay(1000); digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); //go back delay(1000); digitalWrite(IN1, LOW); digitalWrite(IN2, LOW); digitalWrite(IN3, HIGH); digitalWrite(IN4, HIGH); //stop delay(1000); } void loop() { delay(1000); }

初期設定

前進

停止

後退

停止

Arduinoプログラミング 13

この関数は 5つの部分に分けられる。先頭(初期設定とラベルした部分)から見ていこう。

pinMode(ENB, OUTPUT);

pinMode(IN1, OUTPUT);

pinMode(IN2, OUTPUT);

pinMode(IN3, OUTPUT);

pinMode(IN4, OUTPUT);

pinMode(ENA, OUTPUT);

digitalWrite(ENA, HIGH);

digitalWrite(ENB, HIGH);

delay(1000);

最初の 6 つは pinMode文で、説明したように ENBや IN1 などのピンを出力用に設定するも

のである。次の 2 つは digitalWrite文により ENA と ENBのピンに HIGH 信号を送っている

(ENA と ENBのピンには常時 5V の電圧が出力される)。最後の delay(1000)は 1.000sだけ

『何もしない」時間を設定している(機器のタイミングを合わせるなどに使われる)。

次の「前進」部分をみよう。

digitalWrite(IN1, HIGH);

digitalWrite(IN2, LOW);

digitalWrite(IN3, LOW);

digitalWrite(IN4, HIGH); //go forward

delay(1000);

説明したように、ENA, IN1, IN2が左側のモーターの制御、ENB, IN3, IN4が右側のモータ

ーの制御であり、ともに「前進」回転を指定する。しかしこれだけでは「前進」しない。

そのために delay(1000)がある。この delayが指示している 1.000sだけ信号が保持される、

つまり電流がモーターに供給される。これにより 1.000sだけ前進回転が行われる。

3 番目の「停止」部分は、今までの解説から分かるように自然なものである。

digitalWrite(IN1, LOW);

digitalWrite(IN2, LOW);

digitalWrite(IN3, LOW);

digitalWrite(IN4, LOW); //stop

delay(1000);

IN1, IN2で左側のモーターを停止、IN3 と IN4 で右側のモーターを停止させる信号を出し、

delay(1000)でその状態を保持している。

残りの「後退」と「停止」も同様である。

Arduinoプログラミング 14

課題 1. これをもうちょっとスッキリしたプログラムにしてみよう。C プログラミングの

知識を用いて、ENA, ENB, IN1〜IN4 までのピン設定など初期設定を行う initialize関数、

「前進」を val ミリ秒行わせる forward関数、「停止」を valミリ秒行わせる stop関数、「後

退」を val ミリ秒行わせる back関数を書く。そして setup関数は次のように書き換えよう:

(注意:この中にバグがあるかもしれない。その場合は適宜直すこと)

void setup(void) {

int val=1000;

initialize();

forward(val);

stop(val);

back(val);

stop(val);

}

ちなみに forward関数は次のようにかけよう:

void forward(int val) {

digitalWrite(IN1, HIGH);

digitalWrite(IN2, LOW);

digitalWrite(IN3, LOW);

digitalWrite(IN4, HIGH); //go forward

delay(val);

}

書き換えたプログラムを forward_back2 として保存せよ(注:inoという拡張子がつく、また

同じ名前のディレクトリが作られ、プログラムはそのディレクトリの中に置かれる)。また

実際に動かしてみよ。バグがある場合は修正し、動くようにすること。

課題 2. 今度は左回転、右回転をそれぞれ valミリ秒させる関数を追加作成し、ファイル

名を left_rightとして保存せよ。それぞれ left関数、right関数と言う名称とする。次はその

動きをテストするための setup関数である(注意: 先と同様、loop関数の中身は delay(1000)だけとしておこう)。作成したら実際に動かしてみよ。バグがある場合は修正し、動くよう

にすること。

ヒント: 左回転の場合、「左」のモーターは動かさず(注:ブレーキとは異なる)、「右」のモ

ーターを動かす。(参考:左のモーターを後退にしたらどう動き変わるだろうか?)。右回

転の場合はこの逆である。

Arduinoプログラミング 15

void setup(void) {

int val=500; // これくらいが適当

initialize();

left(val);

stop(val);

right(val);

stop(val);

}

7. 速度制御

前項では『全速力」での前進、後退、左回転、右回転をさせてみた。実はこれはモーター

に負担がかかりすぎるのと、精度の良い制御が難しいという問題がある。車(モーター)の

速度を制御する必要がある。そのために PWM (Pulse Width Modulation, パルス幅変調)を用

いる。

今までのプログラムで ENA と ENBの役割に疑問を持っていたことであろう。この二つ

は今まではデジタル出力としてプログラムでは設定していた。HIGH とすることで、モー

ターには常時 5V の電源が供給されていた。それに対し、PWMでは、出力信号をパルスと

して出力することで供給する電力を制御する(したがって、モーターで消費される電力が小

さければ速度減少、大きければ速度増加となる)。いわばデジタル方式でアナログ出力を行

わせる方式である。そのための関数として analogWrite関数が用意されている。

図 16にそのアイデアを示す。ここでデューティサイクルとは常時 0V の出力を 0%、上

智 5V の出力を 100%として、出力電力の割合を表したものである。PWMでは最小値 0V, 最大値 5V の方形波を出力する。最上段は analogWrite(pin, 0) のときに出力される方形波で

ある(ここの pinは出力対象のピン番号が入る)。このときの電力は 0でありデューティサイ

クルは 0%となる。最下段は analogWrite(pin, 255)のときの状態で(注: analog出力の場合、

出力値は 0から 255の値を取る)、常時 5V の出力であり、デューティサイクルは 100%であ

る。上から 2段目は analogWrite(pin, 64)でデューティサイクルは 25%、3段目は

analogWrite(pin, 127)でデューティサイクルは 50%、4段目は analogWrite(pin, 191)でデュー

ティサイクルは 75%となる。

Arduinoプログラミング 16

図 16. PWM: 方形波の周期とデューティ・サイクル

このように基本的にはデジタル出力である(0V か 5V の出力しかない)が、それを切り替

えることにより、「平均して」0%から 100%までのアナログ値を出力するというのが PWMのアイデアである。

これを利用してモーターへの入力を制御することにより、ロボットカーの速度を制御し

てみよう。

それには前項で紹介したロボットカーのプログラムにおいて用いられている ENA と ENBを利用する。先のプログラムでロボットカーが最大速度で動いていたのは

digitalWrite(ENA, HIGH);

digitalWrite(ENB, HIGH);

としていたからである。HIGH とは 5V 出力、つまり最大値である。ここで ENA も ENB も

アナログ出力対応のピンが割り当てられているので、carSpeedを 0から 255までの整数と

して、

analogWrite(ENA, carSpeed);

analogWrite(ENB, carSpeed);

とすればそれぞれのモーターの電流制御ができ、したがって速度が制御できる。

Arduinoプログラミング 17

演習 2. 課題 1と課題 2で作成した forward, back, left, right関数を PWMを用いて速度制御で

きる関数に書き直せ。つまりそれぞれの関数は制動時間(val)とデューティサイクル

(carSpeed)という二つの引数を取るものとする。例として forward関数を示す。

void forward(int val, int carSpeed) { // 制動時間 val, デューティサイクル carSpeed

analogWrite(ENA, carSpeed);

analogWrite(ENB, carSpeed);

digitalWrite(IN1, HIGH);

digitalWrite(IN2, LOW);

digitalWrite(IN3, LOW);

digitalWrite(IN4, HIGH); //go forward

delay(val);

}

演習 3. PWM方式を用いると stop 関数は今までのものとは別の実現方法がある。それを示

せ。

課題 3. デューティサイクルの値と制動時間によって 前進、後退、左、右の制動距離がど

のようになるか、計測せよ。デューティサイクル(100%と 80%程度)と制動時間(300ms,

500ms, 1000ms)それぞれに対し、少なくとも 3 回試行せよ。ここで前進や後退の場合であ

っても左右にブレる可能性があるので、まずほぼ直進(や後退)するように左右のモータ

ーのデューティサイクルを調整してから、平均と標準偏差を求めよ。

注意: 重心の位置の移動をここでは考えているが、ロボットとしては『車体の向き(角度)』

も重要である。その計測方法についても考慮すること。

発展課題: leftや rightにおいて、デューティサイクルを 0 としたときと、従来どおりそれぞ

れの IN 値を HIGH(もしくは LOW)にしたときでは、動きに違いがあるだろうか。

Arduinoプログラミング 18

8. 超音波センサと回転台の使用

ロボットカーの前部には図 17に示す超音波センサーとそれを回転させる台が設置してある

(さらにウェブカメラも付いているが、この扱いは別稿で述べる)。

注意: Arduinoの電源をいれるたびに半時計回りに 15°くらい回転するが、これは正常であ

る。プログラムでコントロールしていない場合は、電源を入れる前に手で通常の状態に戻

すことが可能である。別な言葉で言えば、電源が入っている場合は回転台に用いられてい

る SG90マイクロサーボが制御しているので、手で無理に回したりしないこと。

(1) 回転台の制御

以下に回転台の制御のためのプログラムの例(turnTable.ino)を示す。

#include <Servo.h> // servo library

Servo myservo; // create servo instance to control servo

#define servoPin 3

void setup() {

myservo.attach(servoPin); // attach servo on the pin 3 to control the servo motor

int deg ;

for (deg =0; deg <= 180; deg += 30) { // from 0 to 180 with the step 30

myservo.write(deg); // turn the table

delay(1000); // wait 1.0 s

}

}

void loop () {

}

図 17. 超音波センサー(上の機器)と回転台(青い機器)。右が 0°(左図)、正面が 90°(中

央図)、左が 180°(右図)である。

Arduinoプログラミング 19

このプログラムが示すように、Arduinoの Servo ライブラリを使用し、回転台の制御の

SG90マイクロサーボは 3番ピンに接続してから、インスタンスメソッド write(角度) を実

行することにより、回転台の制御が行える。

注意: myservo.writeに負の値や 180より大きな値を与えないこと。また回転には時間がか

かるため、適当に delay させること。

課題 4. 30°ごとの回転を行い、それぞれの平均角度と標準偏差を求めよ。少なくともそれ

ぞれ 3 回以上行うこと。また、正確に正面を向けるための角度を求めてみよ(注: これは別

稿でカメラと連動させて補正を行う予定である)。 なお、実験の最後に 90°(正面)を向いて

停止させるようにすること。

課題 5. 回転台の制御にはサーボモータを用いている。これは車輪駆動に用いている直流

モーターとは原理や制御方式が異なり、プログラムにおいてもそれが反映されている。両

者はどのように違うのか、調べよ。

(2) 超音波センサーの利用

超音波距離計測センサは音(超音波)を用いて音源と対象物との距離を計測する。短距離なら

精度もよく、人間の可聴領域外の音を使っているため、環境にもやさしい。超音波発振器、受信機、

制御回路からなり、計測距離は 2cmから 400cmである。発振器から発せられた超音波が対象物に

当たり、その反射音を受信器で受信する、その間の距離を計測する。「音の速さ=距離/時間」で

あり、気温を T℃とすると標準大気中において室温付近では「音の速さ=331.5+0.6T m/s」という近

似式が成り立つ。この 2 つの式から距離が求められる(便宜的に音の速さを 340 とすることが多い)。

HC-SR04を用いた距離計測では次のステップによる:(HC-SR04のマニュアルから)

1) TRIG入力にトリガー信号を与える。ここで 10μs以上の間 HIGH 信号を送ることがトリガー信号

の条件である。

2) これにより 40kHzの短時間の音波(超音波)8 個が発信される。

3) 前方に障害物があれば、その音波はその障害物に反射する

4) 音波を送信した後、反射波を受信するまで ECHO出力が HIGH になる。このパルス幅(off-on-off)は対象物との距離により 150μsから 25msの間である。反射波を受信しなければ(障害物がなけ

れば)38msである。

5) 距離は次の式から計算される:

Time を μs単位の Echoパルス幅とすれば、 Time/58 により距離がセンチメータ単位で求められる。ただし、よりよい

精度のためには対象物は少なくとも 0.5m2の面積が必要と

されている。また有効角度は 15°、測定角度は 30°とマニュ

アルには記載されている。

次は超音波センサーを用いた距離計測の関数 Distance である。その結果を表示するのには「シリアルモニタ」を用いる

ため、次項で具体的に述べる。

図 18. 角度と測定距離

Arduinoプログラミング 20

int Echo = A4; // ECHOの入力のピン番号(アナログ IO ピン、4)

int Trig = A5; // TRIGへの出力指令のためのピン番号(アナログ IO ピン、5)

//Ultrasonic distance measurement Sub function

int Distance(void) {

digitalWrite(Trig, LOW); // トリガーをリセット

delayMicroseconds(2);

digitalWrite(Trig, HIGH); // トリガー信号

delayMicroseconds(20); // 20μ s待つ(トリガー信号出力)

digitalWrite(Trig, LOW); // トリガーをリセット

float Fdistance = pulseIn(Echo, HIGH); // ECHO出力が HIGH までの時間計測

Fdistance= Fdistance / 58; // 測定距離をセンチメータ単位に変換

return (int)Fdistance; // 浮動小数点数を整数にして返す

}

void setup(void) {

pinMode(Echo, INPUT); // 超音波センサーを使える状態にする

pinMode(Trig, OUTPUT);

}

課題 6(予告): 次のシリアル通信を学んだ後に、超音波センサーの課題を行う。

Arduinoプログラミング 21

9. シリアル通信

今までのプログラムを見てきて、Cプログラミングなどで学んだプログラムとの違いがい

くつかあることに気づいただろうか。文法は Cプログラムとほぼ同じであるが、人間に対

する入出力(入力のための scanf関数や出力のための printf関数が出てきていない)が今まで

現れていなかったことに気づいただろうか。

Arduinoのプログラミング言語では、scanfも printf も存在しない。そもそもモニタ画面や

キーボード入力を想定していない Arduino 用のプログラミング言語だからである。その代

わりにピンに対する信号を入力したり、ピンに信号を出力する関数が用意されていた。

ここでシリアル通信を介して人間に対しメッセージを送ったり、指令を受け取ったりする

ことを学ぼう。

Arduinoと Raspberry Piは USBケーブルによって接続されている。そのケーブルを通して

通信が行われる。一ビット一ビットが逐次的に(serialに)送受信されているのでシリアル

通信と呼ぶ。Arduinoボードには今まで取り上げてきたデジタル IO ピンの 0番(RX)と 1番

(TX)がシリアル通信用のポートとして設定されている(注: Arduinoのバージョンによっては

複数のシリアル通信用のポートがあるものがある)。ちなみに RX は受信(Receiver)、TX は

送信(transmitter)を表す。また Arduino IDE の『ツール」のシリアルモニタによって Arduinoからのデータを受信し、Arduinoに送信することができる。

以下にシリアルモニタと「通信」するプログラムの例(serialComm.ino)を示す。ここで

Serial は組み込みのシリアル通信用のインスタンスであり、まず Serial.beginによって通信

速度の設定をすることを忘れないようにしよう。通信速度は 300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200のいずれかである。単位は bps (ボー, baud)といい、

bit/s を表す。ちなみに 10 ビットが受信送信の単位であり、これは ASCII 文字1文字に相当

する。したがって、通信速度 9600 bpsの場合、1秒間に最大 960字の情報のやり取りが可

能となる。

char x; // 1文字読み込み用の変数

void setup(void) {

Serial.begin(9600); // 通信速度を 9600 bpsとする

}

void loop( void ) {

x = Serial.read(); // シリアル通信を利用して 1文字読み込む

if (x != -1) { // 読み込んだデータが意味のあるデータならば

Serial.print(x): // シリアル通信を利用してその情報を

// 「そのまま」で送信する

}

}

Arduinoプログラミング 22

図 19. シリアル通信の実行例

図 19にプログラムの実行例を示す。下に示されたウィンドゥは「ツール」から「シリアル

モニタ」を選んで開いたものであり、上部に入力した文字が Arduinoに送られ、Arduinoから送信された文字が下部に表示される。

参考: 半角英数字や改行などの制御文字を表す ASCII1文字は本来 8ビットであるが、その

前後に区切りを表すビット(startビット、stopビットという)がつき 10 ビットとなる。

Arduinoはシリアル通信用のバッファ(メモリの一種)をもっており、入力されたデータは

128バイトまで溜めておけ、『読み込み」はそのバッファからの読み出しとなる。なおバッ

ファにデータが貯まっていることの検査や、バッファをクリアする関数が用意されている。

シリアル通信における入力用の関数:

• Serial.available() : シリアルバッファにあるデータのバイト数を返す

• Serial.flush():シリアルバッファをクリアする

• Serial.read():読み込み可能な受信データのうち最初の 1バイトを返す。データがな

い場合は -1 を返す

• Serial.readStringUntil(char) : char(文字)まで読み込み、文字列を返す

シリアル通信における出力用の関数

• Serial.print(data):データを ASCII テキストとしてシリアルポートに出力する(送信).

dataが整数の場合、1 桁ずつ数字に変換する。浮動小数点数の場合は、小数点以下

第 2 位まで出力する。文字列の場合(二重引用符"でくくられた文字の並び)、そのま

ま送信される。

• Serial.println(data):Serial.printが送信する文字列に加えて、復帰コード(ASCII コード

13、'\r')と改行コード(ASCII コード 10、'\n')をつけて送信する。

• Serial.write(val):valデータをバイナリとして送信する。文字として送信するには Serial.printを使うこと

Arduinoプログラミング 23

演習 4. 1 秒毎に超音波センサーによって計測された障害物との距離(センチメータ単位)を

シリアルモニタに出力するプログラムを書いてみよう。概略、以下のようになろう。

// 超音波センサーを使うための準備(Echo, Trigの宣言)を書く。

// 関数 Distanceを定義しておく。それ以外に必要な変数も宣言

void setup(void) {

Serial.begin(9600); // 通信速度を 9600 bpsとする

// 超音波センサーを使用できるよう設定を行う

}

void loop(void) {

// 計測結果をシリアル送信

}

課題 6. 5cmから 200cm の間の距離に障害物の材質(スポンジ、衣服、紙、木、金属など)や大きさ

やロボットカーに対する角度(正面から 45°までの範囲)をいろいろに変え、距離計測の精度を求め

よ。距離の測定には関数 Distance(もしくはそれ相当の自作の関数)を用いよ。(次の課題の後にや

ってもよい)

課題 7. リモコンロボット

シリアル通信を用いて(シリアルモニタに対しコマンドを打ち込むことで)、ロボットを操作する「リモコ

ンロボット」を実現させよう。コマンドとしては以下のものを想定する(これに限定されない)。一定時間

作動させるか、または別コマンド入力まで動作を保持させる。なお速度制御を行うこと(ENA と ENB

の値を HIGH もしくは 255だと速すぎる)。

• F (もしくは f)コマンドで前進。

• B(もしくは b)コマンドで後退。

• L(もしくは l)コマンドで左回転。

• R (もしくは r)コマンドで右回転。

• S (もしくは s)で停止。前進、後退などで「適当な時間だけ動く」ように設定した場合は不要

• D (もしくは d)コマンドで、超音波センサーによって測定された距離を返す

参考: 別稿で Raspberry Piを用い、カメラからの映像をみながらリモコンロボットを操作するプログ

ラムを作成する

注意: Serial.read関数は「1文字」の読み取りを行う。そして改行コードも「1 文字」である。

Arduinoプログラミング 24

課題 7 の追加: 別稿で Raspberry Piと Arduinoとを連動させるために、以下のコマンドも実行でき

るようにしておこう。

T 数(もしくは t 数)で、数だけ超音波センサーの回転台を回転させる。8節で述べたように、90

が正面に対応し、0から 180までの値それぞれに対して適切に回転することが望ましい。

その手法の実現方法: まず先頭の 1文字が T であれば、その場合に引き続く 100 という文字

列を読み取り、100という「整数」を変数 degの値にセットし、myservo.write(deg);を実行す

る。文字列の読み取りには Serial.readStringや Serial.readStringUntil 関数が使える(注:

readString関数は Serial.readStringUntilに比べて時間がかかりすぎるという指摘がある)。

また数字列を整数にするには次の関数が使えるであろう:

int atoi (String str) {

int n=0, ans=0;

while (isAlphaNumeric(str[n])) { // str[n]が英数字ならば

ans = ans*10 + (str[n] - '0');

n += 1;

}

return ans;

}