EV3RTを使ってみる(8)

Toppers/EV3RTを使ってプログラムを作成したときの記事です。
この記事を書いた時のEV3RTのバージョンはβ4です。
目次はこちら

EV3RTのβ4がリリースされました。console機能が追加されたり、bluetooth機能が整理されたり、C++開発環境が整備されたりしています。ただし、現在 1のEV3RTの最新バージョンはβ4ということですので、リリース版までに動作仕様が変更される可能性がありそうです。ETロボコンのスケジュールを考えるとリリース版を待たずに開発を始めるチームが多いと思いますが、EV3RTの仕様変更に対応できるように設計しておかないとひどい目に会いそうな予感がします。

さて、今回はbluetooth通信のプログラムを作っていきますが、その前にbluetoothの接続名とPINコードの設定を行います。β3版では接続名とPINコードがEV3RTのソースコードにハードコーディングされていました 2。しかし、β4版ではSDカード上に設定ファイル「/ev3rt/etc/rc.conf.ini」を作成し 3、その設定ファイルに接続名とPINコードを記述するようになっています。この設定ファイルの記述例は下記の通りで、「LocalName」が接続名の設定となり、「PinCode」がPINコードの設定となります。

[Bluetooth]
LocalName=Mindstorms EV3
PinCode=0000

次に、EV3本体への接続を確認するのですが、Windows, Linux, OSXからEV3本体へbluetooth経由で接続する方法についてはEV3RTの公式ベージで説明されていますので、こちらを参考にしながらbluetooth経由で接続できることを確認します。

さて、bluetooth経由で接続できることを確認したところで、この通信路を使ってデータの送受信を行うプログラムを作成します。今回のプログラムではタスク「task1」を生成し、このタスク内でbluetooth経由で送られてきたデータを受信し、受信したデータをそのまま返信するようにします。また、受信したデータの内容をLCDに表示するようにします。

まず、設定ファイルapp.cfgにタスク「task1」を実行可能状態で生成するように記述します。

INCLUDE("app_common.cfg");

#include "app.h"

DOMAIN(TDOM_APP) {
  CRE_TSK(TASK1, { TA_ACT, 0, task1, TMIN_APP_TPRI + 1, STACK_SIZE, NULL });
}

ATT_MOD("app.o");

次に、ヘッダファイルapp.hにタスク処理関数「task1」と情報表示関数「display」のプロトタイプ宣言を記述します。

void task1(intptr_t exinf);
void display();

最後にソースファイルapp.cに処理を記述します。タスク「task1」ではbluetooth経由でデータを受信し、受信したデータをそのまま送信しています。また、受信したデータを文字配列変数「message」に保存し、この内容をLCDに表示しています。

#include "ev3api.h"
#include "app.h"

#define MESSAGE_LEN  8

static char message[MESSAGE_LEN + 1] = {0};

/* タスク */
void task1(intptr_t exinf)
{
  FILE *bt;

  // 接続状態を確認
  while(!ev3_bluetooth_is_connected()){
    tslp_tsk(100);
  }

  // シリアルポートを開く
  bt = ev3_serial_open_file(EV3_SERIAL_BT);

  display();

  // 通信処理
  while(1){
    int size = fread(message, 1, MESSAGE_LEN, bt);
    
    if(size > 0){
      fwrite(message, 1, size, bt);
    }

    display();
  }
}

/* 状態を表示する。 */
void display()
{
  ev3_lcd_set_font(EV3_FONT_SMALL);
  ev3_lcd_draw_string("Program is running", 10, 30);
  ev3_lcd_set_font(EV3_FONT_MEDIUM);
  ev3_lcd_draw_string(message, 10, 40);
}

EV3RTでは、bluetoothを介したデータ通信処理をファイルストリームを扱う場合と同じように実装するとができます。ただし、EV3RTのβ4版ではbluetooth機能の仕様がβ3版から少し変更されまして、bluetoothの接続を完了してから通信処理(open, read, write)を実行しないと正常に通信できないようになりました 4

そこで、まずは関数「ev3_bluetooth_is_connected」を呼び出し、bluetoothの接続を完了しているかどうかを確認します。もしbluetooth接続を完了していれば関数「ev3_serial_open_file」を実行し、データを送受信するためのファイルポインタを作成します。あとは、作成したファイルポインタを引数にしてfread, fwrite, fgets, fprintfなどの出入力関数を呼び出すことによりデータの送受信処理を実行できます。

このプログラムをEV3本体で実行し、他のPCからbluetooth経由でEV3本体に接続します。この状態でPC側からデータを送信すると、8byteごとに返信と表示を行います。

上記のようなプログラムを作成することでbluetoothを介した通信が可能になります。ただし、受信データが不足している状態でfreadやfgetsなどの入力関数を実行した場合、その入力関数によって処理がブロックされます。そのため、ロボット制御などのリアルタイム性の高いプログラムを実装する場合は「制御タスク」と「通信タスク」をわけて実装したほうがよさそうです。

Notes:

  1. 2015年4月28日現在
  2. 私の環境ではEV3RT-β3のPINコードの設定部分を書き換えても正常には反映されませんでした。
  3. uImageをEV3本体で実行すると設定ファイルが自動的に作成されます。
  4. β3ではfreadを呼び出してからbluetoothの接続を行っても正常に通信出来ました。