SyntaxHighlighter

2015年3月6日金曜日

マイコン(Arduino等)とMindstorms NXT/EV3をI2Cで繋ぐ

マイコンをセンサーとしてMindstorms NXT/EV3を繋ぐ方法について記す。 英語/日本語の資料をバタバタと行き来して大変だったため。 1.接続方法(物理層) マイコンとMindstorms を接続する方法は、NXTでは3つ、EV3では6つある。 ・Bluetooth ・アナログ ・I2C ・UART (EV3のみ) ・LAN (EV3のみ) ・USB (EV3のみ) このうち、LAN・Bluetoothはセンサーではなく、ホストとしての接続となる。 USBはEV3をツリー接続できることから可能だろうと考えられるが、現状難しいと思われる。 UARTは、シリアルコンソールか、センサーの2種類があるが、 仕様をよく調査できなかったため、扱わない。 アナログ入力については、他の人の情報を参照してほしい。 ここでは、情報の多いI2C接続を用いる。 I2C接続は、公式にはNXTの超音波距離センサーにのみ使われている。 (他サードパーティのセンサーの多くはI2Cを使っている) EV3の超音波距離センサーはUART接続だ。 I2Cは、センサー入力の変形RJ12端子の、端の2ピンに出ている。 5pinにSCL、6pinにSDAが出ている。 この特殊コネクタは通常には手に入らない。 mindsensors社がほぼ唯一取り扱っており、この中では I2C Host Cable with NXT Connector http://www.mindsensors.com/index.php?module=pagemaster&PAGE_user_op=view_page&PAGE_id=136 がケーブル付きで使いやすい。(ピンの解説もここでしている) プラグのみ販売もしれいるが、圧着工具が特殊になる(市販の工具を改造して用いる必要がある)ので注意。 日本ではROBO Product社が扱っている。 http://roboproduct.com/MS02NXTAccessories.html わかりにくいが、2本1セットで525円である。 ちなみに、送料が1180円と高いので注意。買うなら多めに。 2.接続方法(回路・ソフトウェア) 最初は超音波距離センサー(Ultrasonic distance sensor)として接続するのをおすすめする。 超音波センサーであれば、容易にテストが可能だからだ。 I2C機器を直接扱う追加ブロックもあるが、後述する。 接続回路および、プログラムは、松原拓也のNicoSensorがわかりやすい。 I2Cスレーブをソフトウェアで実装しているため、安価な少ピンマイコンを使うことができる。 http://nicotak.com/robot/nxt/ Arduinoを用いる場合、相応のライブラリが公開されているようなので、そちらを用いるといいだろう。 通信プロトコルは、 LEGO MINDSTORMS NXT Ultrasonic Sensor I2C Communication Protocol で検索すればPDFファイルで出てくるが、少なくともNXTでは NicoSensorのように0x42命令にだけ対応していれば問題なく通信できる。

I2Cのクロック速度は10kHz以下と低速で、故にソフトウェアでも処理できる。
ただし、BrickPiなどは100kbpsで通信しようとするため、使用できない可能性がある。注意。

追記
自分の試した限り、NXTでは超音波距離センサーとして接続できたが
EV3では接続できなかった。接続開始時になにやら送信されているのが確認されたため、
これを解析すれば問題なく動くようにできるだろうが、
下記のカスタムブロックでは問題なく通信できているため、詳しくは調べていない。
3.周期など Mindstorm NXTで確認した感じだと、センサー入力で待機、 もしくはループの条件をセンサーにした場合、通信を含め47ms周期で取得が行われた。 通信のタイミングは、センサーの命令が発生した時である。 通信から次の通信までは43msである。 つまり、最高速でも40msの処理時間があり、さらにNXT側のプログラムで ウェイトを入れてあげれば、より処理時間が確保できる。 (実際1secのウェイトを入れると1040msほどになった)

追記
上記の結果は純正超音波距離センサーとしてつないだ場合で、
下記のカスタムブロックを用いると、NXT/EV3共に、10ms以下で取得ループが発生する。

NXTの場合、通信以外の余地は1msしか存在しなかった。

4.任意の通信をする C言語などを使えば任意の通信が可能なのは調べれば容易に出てくるが、 ブロックプログラミング(NXT-G等)を使って、任意のI2C機器と通信するにはどうするか。 以下の追加ブロックを使用すれば可能である。 EV3の場合、Dexter Industries EV3 SensorsのI2C communication blockを使う。 https://github.com/DexterInd/EV3_Dexter_Industries_Sensors ページ下部に書いてあるとおり、Dexter.ev3bをダウンロードし、インポート EV3ソフトウェアからインポートしてあげれば良い。 ※EV3ソフトウェアからNXTをプログラミングするときには使用できない (Program.ev3pが見つからないと表示される) 使い方は以下がいい。 http://www.dexterindustries.com/howto/connecting-ev3-arduino/ NXTの場合、Mindsensor社のIIC_Read.zip、IIC_Write.zipを用いる。 http://www.mindsensors.com/index.php?module=documents&JAS_DocumentManager_op=categories&category=12 解凍し、NXTソフトウェアから解凍したフォルダ内を指定してあげると、インポート項目に現れる。 (導入方法) http://www.mindsensors.com/index.php?module=pagemaster&PAGE_user_op=view_page&PAGE_id=81 5.各ブロックの使い方 I2CReadは次のように使う WriteRegを無効にした状態だと、下のようなプログラムで送信できる。 waitForMe(MYSLA); //(スタートビット&自分のアドレスまで待機) i2c_start(); //送受信切替 i2c_read_byte(); //Writeフラグのたったアドレスを破棄 i2c_write_ack(); // ACK送信 i2c_write_byte(val); // 値送信 i2c_get_ack(); i2c_stop(); WriteRegを有効にした状態だと、レジスタ、つまりアドレス指定ができるようになる。 実質的に1バイトのデータを送った返事として受け取るような形となる。 下のようなプログラムで送受信できる。 waitForMe(MYSLA); //(スタートビット&自分のアドレスまで待機) reg = i2c_read_byte(); //レジスタ受信 i2c_write_ack(); // ACK送信 i2c_start(); //送受信切替 i2c_read_byte(); //Writeフラグのたったアドレスを破棄 i2c_write_ack(); // ACK送信 i2c_write_byte(val); // 値送信 i2c_get_ack(); i2c_stop(); I2CWriteは次のように使う WriteRegを無効にした状態だと、下のようなプログラムで受信できる。 waitForMe(MYSLA); //(スタートビット&自分のアドレスまで待機) val = i2c_read_byte(); //値受信 i2c_write_ack(); // ACK送信 i2c_stop(); WriteRegを有効にした状態だと、レジスタ、つまりアドレス指定ができるようになる。 実質的に2バイトのデータを送ような形となる。 waitForMe(MYSLA); //(スタートビット&自分のアドレスまで待機) reg = i2c_read_byte(); //レジスタ受信 i2c_write_ack(); // ACK送信 val = i2c_read_byte(); //値受信 i2c_write_ack(); // ACK送信 i2c_stop(); ちなみにwaitForMeの中身を以下に示す。 Nicosensorのソースを切り出したそのままなので、そちらを参照していただきたい。 void waitForMe(unsigned char myadr) { unsigned char slaw=0; while(1){ i2c_start(); // 1.マスタからの接続待ち slaw = i2c_read_byte(); // 2.アドレス受信 if (slaw == myadr) { // アドレスが一致の場合、 i2c_write_ack(); // ACK送信 break; } else { // アドレスが不一致の場合、 i2c_write_nack(); // NACK送信 } } }
---

追記
EV3のDexterの場合、挙動が異なる。
アドレスの指定の仕方は7bitで、各ブロックで勝手にRead/Writeビットをセットしてくれる。
1を指定すると、書き込みは0x02、読み込みは0x03になる。

MindsensorのIIC_Read、IIC_Writeの場合、アドレス指定は8bitで行う。
こちらもRead/Writeビットをセットしてくれる。
2を指定すると、書き込みは0x02、読み込みは0x03になる。

が、このセットの仕方がORではなく+1のため、
例えば読み込みなのに1を指定すると、書き込みは0x01、読み込みは0x02とおかしなことになる。

また、読み込みに入るタイミングなどが違うので
各挙動については以下の図を参照してほしい。


追記
EV3のブロックのdigitalWriteは、I2CWriteのWriteRegを有効にした状態、
EV3のブロックのdigitalReadは、I2CReadのWriteRegを有効にした状態と等価に動く。

また、一部のI2C機器はEV3ではアナログセンサーと認識し、初回接続時動作しないことがある。
プログラム実行中に抜き差しするとEV3がI2C機器として認識しなおすため、動作するようになる。

TETRIXのDC Motor装置をEV3のブロックで動かすことができたので記録。


---
Arduinoで動作確認して、PICに移植している。 Arduinoでのソースがほしい方が居たら、お渡しできるので連絡してほしい。 以上、参考になれば嬉しい。 なにか追加の情報を持っている方が居たら、twitterまで知らせてほしい。
---



--- 関係ないが、GoogleDocsで編集したものを画像込みで コピペしたら、画像ごと貼り付けられた。下書きにはGoogleDocsが便利なようだ。 ただ、フォントが違うのがいただけない。

0 件のコメント:

コメントを投稿