53.Arduinoとの連携 (2024.2.6-2024.2.16)

RasPiを使った装置開発の今後の展開を見据えて、まずはArduinoとの連携を考えてみます。RasPiはPCからリモートで操作できたり、GUIが扱えるポテンシャルの高いマイコンですが、OS自体の処理が重いために高速な処理が苦手です。これにはPythonがインタープリター型のプログラミング言語と言う点も影響しています。制御に限って言えば、リアルタイムに処理することは困難なため、センサーの値を直接読み取ったり、モーター制御等を行うには、制御に特化したマイコンを使うのが適切です。そこで目を付けたのがArduinoなのです。入手しやすく使用するための情報も豊富なことから、RasPiをマスターにArduinoをスレーブにして連携させれば、これまで困難だった装置も実現できます。

Arduinoにはハードに密着した部分を専門に処理させ、RasPiはArduinoで得られたデータを読み取って分析したり、Arduinoに対して様々な指示を出して、システムとしての処理を実現することになります。更に次の目標では、同じ目的でPICにArduinoの処理の肩代わりさせたいとも考えています。また、ArduinoとPICによって処理を完結させることも視野に入れていて、いずれはこの三者をうまく使い分けて、より高度な装置の実現に挑みたいと思います。

RasPiとArduinoを連携させるには、両者の間で通信ができなければなりません。幸いお互いにI2Cと呼ばれる通信手段を備えていて、信号線を結べばお互いにデータのやり取りができます。I2Cはこれまでにも幾度となく使用してきました。ハード的にはGND、SDA、SCLの3本が繋がっていれば良く、ソフトもライブラリが用意されていることから、使用するのも比較的簡単です。しかし、この場合はArduinoをスレーブとして使うため、例えばLCDをI2Cに接続したとしても、同じスレーブ同士ではArduinoからLCDを操作できません。従ってI2Cで通信を行うのは次のテーマとし、ここでは同様にシリアル通信を行えるUSB接続でRasPiとArduinoを結び、データの転送実験をしてみましょう。

1.Arduinoへのデータ送信
まずは簡単な通信テストとして、RasPiから指示してArduinoのLEDの点滅を3回(点灯1秒/消灯1秒で1回)行います。それと同時にRasPiではLEDのON/OFF状態を表示します。準備にはArduinoのデジタル出力ピンの13ピンとGNDの間にLEDをつなぎます。そのままでは電流が流れ過ぎるので、LEDに直列に330オーム~1kオーム程度をつなぎます。LEDには極性があるので、つなぐ方向に注意して下さい。次に示すのはRasPi側のプログラムとArduino側のプログラムです。LEDを点灯する時にはRasPiから文字「a」を、消灯する時には文字「b」をArduinoに送ります。その際に、どのポートを使ってシリアル通信するのか指定しなければなりません。私の環境では「ttyUSB0」がそれに当たります。ポートは環境によって異なり、ネットの情報ではttyAMA0等もよく見かけます。あらかじめRasPiのターミナルで「ls -l /dev/tty*」を入力して確認するとポートのリストが出てきます。ttyUSB0はArduinoのIDEで選択したポートと同じで、プログラム書き込み後にすぐに実験できて便利です。

●RasPi側のプログラム

●Arduino側のプログラム

<RasPiでの表示:ArduinoではLEDが3回点滅>

注意点として、データ送信に際してデータのエンコードを行っています。そのまま1バイトの文字データを送ろうとするとエラーになります(コメントアウトの行に注意)。また、RasPiでシリアルポートの初期化を行うと、Arduino側が反応してLEDが点滅してプログラム上の動作なのか判別しにくいため、3秒の時間待ちの後で最初のLED点灯命令「a」を送信しています。

2.Arduinoからのデータ受信-1
逆にArduinoのLEDを点滅(点灯0.5秒、消灯0.5秒)させ、その状態をRasPiに送りRasPi側で表示します。そのままだと延々と表示を続けるため、RasPi側のプログラムはCtrl+Cで終了します。今度は通信速度を速くしてみましょう。設定を9600から115200にします。高速になればなるほどノイズ等の影響を受けて不安定になり易いので、実用レベルでは通信速度を見極める必要があります。

●RasPi側のプログラム

●Arduino側のプログラム

<RasPiでの表示>

RasPi側に送られたデータを表示すると、本来の文字列に加えて前後に文字が追加されています。これは何なのでしょうか。どうやら通信データのコードの違いで、デコードすることで本来の文字列にすることができるようです。RasPi側のプログラムを次のように変更します。


<RasPiでの表示>

これで正常にデータを受信できました。ser.readline()をser.read()とすると、1文字ずつデータを受信することができます。RasPiとArduinoの間でUSBによるシリアル通信を実現したことで、連携操作の下準備ができました。

3.Arduinoからのデータ受信-2(センサーのデータ)
次のステップとして、ArduinoでBH1750FVIと言う照度センサーのデータを読み取り、LCD(16桁2行:1602と呼ばれるモジュール)に値を表示すると共に、シリアル通信(USB経由)でRasPiにデータを送信するスケッチを考えます。この照度センサーはI2C通信を使います。Arduinoはマスターとして、LCDとBH1750FVIはスレーブとして動作します。センサーは1秒毎に読み取り、RasPi側では受信データを受けてコンソールに表示を続けます。ArduinoとLCDは下図のような接続になりますが、Arduinoは接続用のピンが少ないため、実際にはブレッドボード等を使って拡張することになります。BH1750FVIを使用するために、あらかじめArduino IDEにモジュールを追加(import)しておく必要があります。


ArduinoとLCDの接続

■BH1750FVIの接続
VCC:3.3V
SCL:ArduinoのSCLピン
SDA:ArduinoのSDAピン
ADD:未接続
GND:GND

注意すべきはロジックレベルです。Arduinoは5VでBH1750FVIは3.3Vなので、そのまま接続するとデバイスを破壊する可能性があります。そこで間に双方向ロジックレベル変換器を入れます。amazon等でも複数個セットで販売されていて、1個当たりでは100円以下で入手可能です。I2Cデバイスを複数つなげられるように、私は写真のような中継基板を作りましたが、もちろんブレッドボードを使っても構いません。基板の中央に位置する小さなモジュールが双方向ロジックレベル変換器です。これだと2系統のI2C通信に使えます。実はもう1点注意があって、ケーブルを接続する際はレベル変換器から見て一番遠くにあるピンから接続するようにします。そうしないと、I2Cデバイスへのアクセス時に正常に通信できない事態が発生しました。一般的に高速伝送では、伝送路の終端から戻ってくる反射波と呼ばれる信号が元の信号に重畳し、ノイズ源になってしまう場合があります。それを抑えるために、終端に抵抗を入れたりデバイスで終端するのですが、実際に後者を行ったら改善することができました。I2Cを使う場合は、こうしたこともあるのだと頭の片隅に入れておくと良いでしょう。

センサーの読み取りに加えて、RasPiとのシリアル通信(USB)とLCDへのデータ表示を行うため、やや複雑なプログラムになっていますが、動作としては単純なものです。RasPi側に表示されるのは、最初に上位8ビットの2進データと下位8ビットの2進データ(アンダーバーで連結)、次に照度(lux)データです。Arduinoからデータを受信し続ける限り、測定データの表示を続けます。終了する場合はキーボードの「Ctrl+C」を押します。

●RasPi側のプログラム
●Arduino側のプログラム

<RasPiでの表示>

4.Arduinoからのデータ受信-3(2種のセンサーのデータ)
更なる応用として、広く使われている温度/湿度センサーのDHT11を加え、前記のBH1750FVIと合わせて2種のセンサーデータを読み取り、LCDに順に表示すると共にRasPiにデータを送ります。上記3.をベースにDHT11を拡張したスケッチになっているのが分かると思います。DHT11を使用するために、モジュールを事前にArduino IDEに追加しておきます。参考までにArduinoでDHT11を使う方法については、「5.Arduino & PIC」のコーナーにおいて「8.LCDモジュールを使う」で扱っています。表示を合わせるために、小数点以下1桁までとして統一しました。

■DHT11の接続
+:5V
out:ArduinoのDIGITAL入出力7ピン
-:GND

●RasPi側のプログラム(3.と同じもの)
●Arduino側のプログラム
*Windowsではエスケープ記号が\になってしまいますが、RasPiではバックスラッシュになるので注意して下さい。

5.RasPiからの指示でArduinoを操作
本項の最後に、RasPiとArduinoを連携する簡単な実験を行います。何をするかと言うと、RasPiからArduinoにコマンドを送信し、その内容によってArduinoではLEDの点灯動作を実行します。そして命令を受理したことをRasPiに知らせるため、Arduinoは特定のレスポンスを返します。この一連の動作は、将来的にRasPiを中核としたシステムにおいて、各種制御を担うArduinoに様々な命令を出して実行させ、結果として得られたデータ等をRasPiに通知する機能を実現するための布石となります。
●RasPi側のプログラム
●Arduino側のプログラム
変数commandは文字通りコマンド(命令)です。RasPi側では文字列を送るためにコマンドの最後にピリオドを付けることで、Arduino側ではピリオドまでを一連の文字列(ピリオドは除外)とみなして受信します。こうして得られたコマンドに従って、ArduinoはLEDの点滅を実行するわけです。一連の文字列であるコマンドには、色々な意味を持たせることができます。例えばsensor01と命令すると、1番目のセンサーの値を読んでRasPiにデータを送信すると言った具合です。コマンドを体系化することで、オリジナルのシステムを構築できます。まだ基礎的な実験に過ぎませんが、夢は大いに広がります。