前回(「#7-7 Pi ZeroWの非同期シリアル通信」)、Pi ZeroWとArduinoの非同期シリアル通信を試していた時に、ふと思ったのですよ。
「折角デバッグの済んでいるプログラムなのに、"Serial"インスタンスを置換しないとPi ZeroWと通信できないなんて、面倒だな」と。
そう、Pi ZeroWには、USBホストになることが可能なUSB端子(実際にはUSB-OTG)が付いているでは無いですか!このUSBにArduinoを接続して、USB⇔UART変換で通信できないのかしら?そう思って調べてみたところ、「できる」みたいです。
Pi ZeroWのUSBは、USB-OTG(On The Go)と言う規格のインターフェイスで、つながる相手に合わせて、USBファンクションにもUSBホストにもなることができる仕様です。そのお陰で、接続ケーブルには、OTG対応のケーブルが必要でした(以下図、OTG変換アダプタ)。
と、言うことで、Pi ZeroWのUSB端子にArduinoを接続する、と言うことは、Pi ZeroWがUSBホストとなって、Arduinoとつながる、と言うことになります。USB-OTGの規格上は、全く問題なく、接続可能です。問題があるとすれば、Raspbianのデバイスドライバがどうなっているか?
Windowsでもそうですが、新しく買って来たUSBデバイスの場合、デバイスドライバのインストールが必要なケースがありますよね?それと同じで、Pi ZeroWにArduinoをUSB接続した時、適切なドライバがRaspbianにインストールされていれば、良し。そうでなければ、接続はしたものの、認識してもらえず、何も操作できない状態に陥るでしょう。
ネットで調べてみたところ、どうやら、Pi ZeroWのUSB端子にArduinoを接続すると、適切なドライバが機能して、通信できるようになるみたいです。ドライバの心配は要らないということです。
では、早速、Arduino UNOを接続してみます。まずは、OS(カーネル)のリングバッファ状態を表示させておきます。準備ができたら、Arduino UNOのUSBケーブルを、Pi ZeroWのUSB端子に、OTGアダプタを介して接続してください。
実験サンプル:【 】内はshellウインドウでのコマンド入力
【dmesg -w】 …… 実行後、ArduinoをPi ZeroWに接続
usb 1-1: new full-speed USB device number 2 using dwc_otg
usb 1-1: New USB device found,
usb 1-1: Manufacturer: Arduino (www.arduino.cc)
cdc_acm 1-1:1.0: ttyACM0: USB ACM device
usbcore: registered new interface driver cdc_acm
cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
…… 一部省略
【CTRL-C】 …… dmesgを終了する
こんな感じ(↑)です。「新しいUSBデバイスが見つかったよ。Arduinoだってさ。ttyACM0で登録したよ」って、言ってます。
※ttyACM0:Abstract Control Model……「抽象的な制御モデル」みたいですね。
【ls -l /dev/ttyACM0】
crw-rw---- 1 root dialout 166, 0 Sep 29 12:32 /dev/ttyACM0
【stty -F /dev/ttyACM0】
speed 9600 baud; line = 0;
-brkint -imaxbel
認識されたデバイスttyACM0は、前回のシリアルユニット(ttyS0)と同じでした。グループdialoutにリード/ライト権限が付加されていて、ユーザpiがdialoutに属しているので、ユーザpiからUSB⇔UART変換を制御して、Arduinoと通信することが可能です。
前回と同じですけど、今回はArduino UNOにDHT11の制御プログラム(meas_am2302.ino)を書き込んで、Pi ZeroWのUSBポートに接続します。
Pi ZeroW | 接続 | Arduino UNO | 接続 | DHT11 |
USB-OTG | ← | USB | ||
5V | → | VDD | ||
GND | ⇔ | GND | ||
D2 | ⇔ | SDA |
USBから電源がもらえて、レベルシフタ(L/S)も要らないので、とてもシンプルです。前回のネットリストと比べてみてください。
前回使ったawkのスクリプト(meas_am2302.awk)を少し変更する必要があります。以下、変更点周辺の抜粋です。
完成スクリプト:meas_am2302.awk
#! /usr/bin/awk -f
BEGIN {
:
:
# init
FS=",";
Serial="/dev/ttyACM0";
system ("stty -F " Serial " 9600 -echo igncr -hup");
PROCINFO[Serial, "READ_TIMEOUT"]=4000;
# "who" command
print "who" > Serial;
getline < Serial;
if ($0=="RDY")
{
print;
print "who" > Serial;
getline < Serial;
}
if (ERRNO=="")
print;
else
print ERRNO;
:
:
}
青くしたところが、変更・追加箇所です。以下にまとめます。
ちょっと、ArduinoにリセットをかけるDTR信号の動きが明確には、読み切れていないのですが、どうも、"RDY"を受信した時、直前に送っておいた【who】コマンドが無視されているみたいなので、再送信するように記述してあります。
sttyコマンドに追加した-hupを削除すると、デバイス/dev/ttyACM0を開く(open)度に毎回Arduinoにリセットが掛かるようになります。その方が良いケース(毎回リセットしたいケース)もあるかもしれないので、使い分けてください。
※スクリプト(meas_am2302.awk)には、今回必要となったコードを追加してありますが、通信相手(変数Serialの設定値)は、前回のまま「/dev/serial0」としてありますので、ダウンロード後、そこだけ変更してください。
実験サンプル:【 】内はshellウインドウでのコマンド入力
【vi meas_am2302.awk】 …… Serialのデバイス名を変更する。
Serial="/dev/ttyACM0";
【ZZ】 …… セーブして終了
【meas_am2302.awk】
RDY …… Arduinoを接続して、初めの実行時だけ表示される。
DHT11,1.02
OK,30.0,59.0
【meas_am2302.awk 3】
DHT11,1.02
OK,29.0,58.0
OK,29.0,58.0
OK,29.0,58.0
OK,30.0,58.0
USB⇔UART変換経由で、Pi ZeroWとArduino UNOが通信し、Arduinoが読み出したDHT11の気温・湿度データをPi ZeroWに取り込むことができました。
前回(「#7-7 Pi ZeroWの非同期シリアル通信」)の様に、シリアルユニット同士を接続する場合と違って、レベルシフタ(L/S)も要らないし、USBから電源も取れるし、すごく楽チンです。以下、特徴をまとめておきます。
個人的には、欠点を遥かに超越する利点がある、と感じています。皆様はいかがでしょうか?
そもそも、キーボードやマウスなど(HID)の様な、デフォルトのデバイスドライバで事足りる物であれば、Pi ZeroWに接続するだけで使えたわけです。Arduinoも、ある意味、デフォルトデバイスドライバの中から、ttyACM0というデバイスドライバが選択されて、動作することができた、と考えることができます。
※ttyACM0のA.C.M.が、「USB Abstract Control Model (抽象的な制御モデル) driver」の略であろうことは、dmesgのメッセージから明らかです。何らかのデフォルトデバイスドライバだと考えられます。
そこで、「明らかにデフォルトドライバでは動作できないでしょ?」と言う、特殊なものは除き、いくつか、手元に見つかったUSB接続デバイスをPi ZeroWに接続して、対応状況を調べてみようと思います。
調査方法は、shellウインドウで、【dmesg -w】を実行しておいて、次々とUSBデバイスを挿してみるだけです。
実験サンプル:【 】内はshellウインドウでのコマンド入力
【dmesg -w】 …… 実行後、ArduinoをPi ZeroWに接続
:
…… USB機器を接続して、メッセージを確認する。
:
【CTRL-C】 …… すべての機器の確認が終わったら、dmesgを終了
以下、手元のUSB機器で試してみた結果です。
いつも使っている、USB⇔UART変換モジュール(FTDI、下図)をPi ZeroWに接続してみました。
「Product: FT232R USB UART」として認識され、デバイス/dev/ttyUSB0が登録されました。
【ls -l /dev/ttyUSB0】
crw-rw---- 1 root dialout 188, 0 Sep 29 11:22 /dev/ttyUSB0
こちらも、/dev/ttyS0や/dev/ttyACM0と同様、グループdialoutに対してリード/ライト権がありますので、恐らく、普通にデバイスを開いて(openして)、アクセス可能でしょう。ttyS0が使えるのに、敢えてFTDIを使用する機会があるかどうかは疑問ですが……。
※FTDIはジャンパで信号レベルを3.3V/5Vから選べるので、L/S無しで非同期シリアル通信が可能と言う利点はあるかも、です。RTSやCTS、DTRも使用可能です。
Arduino Pro Mini+L/SでttyS0(UART)とつなぐか、Arduino Pro Mini+FTDIでttyUSB0とつなぐか?どっちもどっち?な感じですね……。
同じArduinoですが、UNO(ATmega328+ATmega16U2(USB⇔UART変換チップ))と異なり、ATmega32U4を搭載した、Arduino Micro(下図)は認識されるでしょうか?
Arduino MicroをPi ZeroWのUSBに挿入したところ、「Product: Arduino Leonardo」として認識され、/dev/ttyACM0が登録されました。
【ls -l /dev/ttyACM0】
crw-rw---- 1 root dialout 166, 0 Sep 29 11:25 /dev/ttyACM0
UNOと同様に、USB⇔UART通信することができました。
時に、Windowsの場合だと、新しく検出したUSB⇔UART変換デバイスには、COM1,2,3,…と、番号が振られ、基本的に、初めて検出された時に割り振られた番号を記憶しています。一度、COM2で認識されたUNOは、何度接続しても、COM2で接続され、例えば、UNOが接続されていない時にMicroを挿入したとしても、MicroにCOM2が割り当てられることはありません。
例えばこの時、MicroにはCOM3が割り当てられ、以降、Microを検出すると、毎回COM3になります。
しかし、Raspbianでは、違うことが解りました。今回のMicroも、UNOと同じttyACM0で登録されています。HUBなどを使って、複数台同時接続は試していないので、定かではありませんが、恐らく、毎回検出した順にttyACM0,1,2,…と、番号が振られるのでしょう。
ARM Cortex-M3を搭載した、STM32ボード(下図)では、どうでしょうか?
同様に【dmesg -w】で監視しながらPi ZeroWのUSB端子に挿入したところ、「Product: Maple 003」として認識され、/dev/ttyACM0が登録されました。
【ls -l /dev/ttyACM0】
crw-rw---- 1 root dialout 166, 0 Sep 29 11:25 /dev/ttyACM0
UNO、Microと同様です。USB⇔UART変換での通信も確認できました。
Arduino系の、比較的有名なチップだったから、デバイスドライバが対応していたのか?はたまた、USB接続した時に、デバイスから送られてくる情報を使って、ttyACM0が適切だと判断され、登録に至ったのか?は、定かではありません。
もし、前者だとすると、マイナなUSB⇔UART変換チップを搭載したArduino互換機の中には、認識してもらえずに、制御不能なボードがあるかもしれないので、ご注意ください。手元のArduino系マイコンボードは全て、ttyACM0で認識されることを確認できたので、筆者の環境では、困ることはなさそうです。
最後に、USB接続のハードディスク(HDD)を試してみます。使用したのは、Windowsで使っている、Toshiba製の60Gバイト HDDで、フォーマットはNTFSです。
Pi ZeroWのUSB-OTGコネクタに接続したところ、リムーバブルディスクとして認識され、デスクトップにアイコンが表示されました(下図)。
ただし、dmesgコマンドには、「ntfs: (device sda1): load_system_files(): $LogFile is not clean. Mounting read-only. Mount in Windows.」と、言うメッセージ(リードオンリでマウントしたよ)が出力されており、実際、ファイルへの書き込みはできませんでした。存在するファイルのリスト(lsコマンド)は取得でき、内容の参照は可能でした。ただし、日本語のファイル名は文字化けして読めませんでした。
dmesgコマンドのログを解釈すると、Raspbianでリード/ライトするには、何らかのお作法が必要みたいですね。ちょっと、試しに接続してみただけ、ですので、深追いはしないことにします……。
これで、Arduinoとの通信がとても簡単に確立できるようになりました。使い道のなくなったUARTユニットは何に使おう?個人的には、「シリアルコンソール」って言うのは、あまり魅力を感じないので、何か使い道ができた時の為にリザーブしておこうと思います。