レゴEV3

レゴEV3とArduino NANOをI2C通信してみる

EV3の入力ポートは4つしかなく接続するセンサーの数に限界があり、また使用できるセンサーもEV3に対応したセンサーに限定されてしまいます。そこで、EV3のインテリジェントブロックとArduino NANOをI2C通信して、Arduino NANOに接続したフォトリフレクタ(RPR220)でラインを判別し、結果をEV3で受信することを考えています。

今回はとりあえず、EV3インテリジェントブロックとArduino NANOのI2C通信してみました。

以下のページを参考にさせていただきました。
NXT/EV3 Arduino I2C Ultimate Guide

準備したもの
  • EV3インテリジェントブロック
  • Arduino NANO(互換品)
  • EV3ケーブル用ソケット(mindsensors社)
  • モジュラージャックDIP化キット(秋月電子)
  • 抵抗器(82KΩ)
  • フォトリフレクタRPR220
  • 抵抗器(220Ω)
  • 抵抗器(10KΩ)

I2C通信について

I2C(Inter-Integrated Circuit)は、フィリップス社が提唱した周辺デバイスとのシリアル通信の方式です。マスタ側とスレーブ側を明確に分け、マスタ側が全ての制御の主導権を持っており、1つのマスタで複数のスレーブデバイスと通信することが可能です(各スレーブにはアドレスが必要です)。

図のように1台のマスタと1台または複数のスレーブとの間を、SCL(クロック用),SDA(データ入出力用)の2本の線で接続します。

I2C通信の図

EV3とArduino NANOの接続

EV3とArduinoの接続図

Arduinoの動作に必要な電力を提供しますが、過負荷とならないよう注意が必要です。Arduinoへ外部電源で提供する場合は、EV3の「4:緑」の線をArduino NANOの「Vin」に接続する必要はありませんが、「GND」線は常に接続しておく必要があるようです。

EV3はポート1を使用します。ポート1以外(ポート2~4)では動作しないようです。

EV3側プログラム(ROBOTC使用)

ROBOTCのI2C関連の関数

はじめにROBOTCのI2C関連の関数として以下のものが用意されているようです。しかし、ヘルプを参照しても見つかりません。ですので、詳細はよくわかりません。

sendI2CMsg(ポート, 送信データの配列のアドレス, 受信するデータのバイト数);
=> 送信データを送ります。
readI2CReply(ポート, 受信するデータを格納する配列のアドレス, 受信するデータのバイト数);
=> 受信データを取得します。

この2つの関数で何とかなりそうな気がします。他に以下の関数が検索で出てきましたが、詳細はよく分かりません。

nI2CStatus[ポート];
=> I2C通信のステータスを取得。ステータスには、「STAT_COMM_PENDING」、「NO_ERR」は見つけましたが、他にもあるのでしょうか???
nI2CBytesReady;
I2C通信で取得可能なデータのバイト数を取得。
nI2CRetries[ポート];
メッセージの再試行回数を変更できるようですが、ROBOTC のプログラムに打ち込んで紺色の文字になりませんので、使えるのか分かりません(試していません)。
SensorType[ポート];
I2C通信で使用するセンサーを設定し、標準または高速通信をするかどうかを示す。

ROBOTCプログラム

EV3からArduino NANOへのセンサー読み出しのリクエストを行い、Arduinoからのデータを受信し、EV3のディスプレイにセンサーの値を表示します。


#pragma config(Sensor, S1,     ArduinoNANO,     sensorEV3_GenericI2C)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

#define ARDUINO_PORT S1
#define ARDUINO_ADDRESS 0x04

int read_sensor(byte pin_num, byte ad);				// ad: analog/digital

int sensorval = 0;



task main() {
		while (true) {
				sensorval = read_sensor(0, 0);
				eraseDisplay();
				displayBigTextLine(0,"%s : %3d", "Value", sensorval);
		}
}



int read_sensor (byte pin_num, byte ad) {
		char I2Cmessage[4];
		char I2Creply[1];
		int temp_sensorval = 0;

		memset(I2Creply, 0, sizeof(I2Creply));
		I2Cmessage[0] = 5;
		I2Cmessage[1] = ARDUINO_ADDRESS << 1;
		I2Cmessage[2] = pin_num;
		I2Cmessage[3] = ad;
		sendI2CMsg (ARDUINO_PORT, I2Cmessage, 1);
		wait1Msec(20);

		readI2CReply (ARDUINO_PORT, I2Creply, 1);
		temp_sensorval = I2Creply[0];
		wait1Msec(35);
		return temp_sensorval;
}

read_Sensor (byte Pin_Num, byte AD)
2つのパラメーターは、値を取得するセンサーを接続したピンNO、アナログ(0)/デジタル(1)を指定します。RPR220以外のセンサーを使う場合も考えて、デジタルピンも指定できるようにしておきました。

I2Cmessage[1] = ARDUINO_ADDRESS << 1;
アドレスの最後のビットは書き込み(1)か読み出し(0)かを指定していますので、ArduinoのI2Cアドレス0x04 (00000100)を1ビット左シフトし、0x08(00001000)としています。

sendI2CMsg (ARDUINO_PORT, I2Cmessage, 1);
EV3からArduinoへ配列のデータを送信します。受信データのバイト数は、センサーの値を受信したいので、「1」となります。

readI2CReply (ARDUINO_PORT, I2Creply, 1);
Arduinoからのデータを受信します。

= read_Sensor(0, 0)
アナログピン0に接続したセンサーの値を取得する場合となります。

Arduino NANO側プログラム

Arduino NANOでセンサーの値によって「0/1」に判別して、結果「0/1」の値をEV3に返します。


#include

int EV3msg[2] = {0, 0};              // EV3msg[0] : ピンNO、EV3msg[1] :アナログ(0)デジタル(1)
int value = 0;
int sensorval = 0;

void setup() {
    Wire.begin(0x04);                // スレーブアドレスの設定 
    Wire.onRequest(requestEvent);    // EV3へ送信
    Wire.onReceive(receiveI2C);      // EV3から受信
    Serial.begin(9600);
    delay(500);   
}

void loop() {   
}

/* EV3から受信したとき、以下の関数を実行 */
void receiveI2C(int bytesIn) {
    byte read_byte = 0x00;  
    read_byte = bytesIn;
    int byte_count = 0;
    int sensor_W = 900;
    int sensor_B = 300;
    int threshold;
    threshold = (sensor_W + sensor_B) *0.5;

    while(Wire.available() > 1) {
        read_byte = Wire.read(); 
        EV3msg[byte_count] = read_byte;
        byte_count++;
    }
    int x = Wire.read();          // ダミーバイト読み込み(意味はないがないとダメ)

    if (EV3msg[1] == 0) {
        value = analogRead(EV3msg[0]);
        if (value > threshold) sensorval = 0;
        else sensorval = 1;       
    }
    else {
        sensorval = digitalRead(EV3msg[0]);
    }
}


/* センサー値をEV3へ送信  */ 
void requestEvent() {  
    Wire.write(sensorval);
    Serial.print((String)"ピンNo." + EV3msg[0] + " :");    
    Serial.println(sensorval);               
    Serial.println("");
}

複数センサーのデータを同時に受信する方法

今回は、センサー1個の値を受信することができました。ラインセンサーとしてRPR220を3個使用したいため、EV3へ3つのセンサーのライン判別結果を同時に送受信できるように、試行錯誤してみたいと思います。

購入先リンク

EV3ケーブル用ソケット(mindsensors社)

モジュラージャックDIP化キット(秋月電子)

フォトリフレクタRPR220

COMMENT

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です