FlashAirによる鉄道模型制御-共有メモリ編

寄稿: 綾瀬ヒロ

最終更新: 2015/9

概要

前回、FlashAirのGPIOを用いてArduinoと連携させて鉄道模型を制御してみました。今回は、FlashAirのもつ共有メモリ(Shared Memory)を用いて、Arduinoと連携してみました。
FlashAirでは、command.cgiのAPIを用いて、共有メモリの読み書きを行います。また、Arduinoでは、周期的に共有メモリの状態を参照し、共有メモリ上のフラグの値に応じて、PWM出力を行い、フルブリッジドライバを介して鉄道模型車両のモータを駆動させます。また、同じくフルブリッジドライバを介して、分岐器(ポイント)の転換用電磁石を駆動させます。

FlashAirによる鉄道模型制御

詳細

Arduino IDEにおけるiSDIO対応化

FlashAirのDevelopersサイトに掲載されている手順に従って、Arduino IDEにおいてiSDIO拡張コマンドを扱えるようにしておきます。

参照: iSDIO拡張コマンドの作成

FlashAirとArduinoの接続

FlashAirと、Arduinoの接続は、SPI接続を行います。
今回は、Developersサイトでも推奨されているSeeed Studio SD Card Shield v4を利用します。

参照: Seeed Studio SD Card Shield v4

Controller

Seeed Studio SD Card Shield v4にFlashAirを刺したところ
(写真のArduinoは、Arduino MEGA2560互換ボードです)

Controller

全体の回路図


FlashAirの共有メモリ

FlashAirの共有メモリは、FlashAirのDevelopersサイトに掲載されているメモリマップに記載されている「Reserved for Vendor(01000h〜01FFFh)のうち、command.cgiでユーザーが使用できる部分は、0x1000〜0x11FFの512バイト分です。

参照: Arduinoチュートリアル / カードステータスの読み取り

iSDIOレジスタのメモリ配置 (SD Specifications Part E7 iSDIO Simplifed Specification Version 1.10より抜粋)

Address Name Short Description Type
00000h Command Write Register Port Data Port to write the iSDIO Command Write Data W/O
00001h-001FFh Reserved
00200h Response Data Register Port Data Port to read the iSDIO Command Response Data R/O
00201h-03FFh Reserved
00400h-005FFh Status Register Memory Area for iSDIO Status Register Table2-7
00600h-007FFh Capability Register Memory Area for iSDIO Capability Register R/O
00800h-00FFFh Reserved
01000h-01FFFh Reserved for Vendor
02000h-1FFFFh Reserved

共有メモリのデータ配置

今回は、FlashAirの共有メモリを利用してArduinoとデータのやり取りを行います。そのためには、まずは共有メモリでどのようにデータをやり取りするか検討する必要があります。
前述の通り、FlashAirの共有メモリは512バイトが使用できますので、かなりのデータを扱うことができます。
しかし、今回は大きなデータを扱う必要はありません。ここでは、共有メモリを図及び表に示したような8バイトの文字列配置として、FlashAirとArduinoの間でステータス(状態)データをやり取りすることにします。
ステータスデータのやり取りとする利点については、「FlashAir同人誌2」に詳しく書いているので、そちらを参考にしてください。

Controller

共有メモリのデータ配置

アドレス 値範囲 データ仕様
0x1000〜0x1002 000〜200 3バイト分のアドレスの値を、0x1000は100位、0x1001は10位、0x1002は1位とした3桁の数字として扱う。 このデータで扱う走行速度は000〜200とする。
0x1003 0 / 1 走行方向を示す値とする。
0:右方向、1:左方向とする。(実際は、フルブリッジドライバに接続する2本のデジタルIO線のどちらをHIGHとするかを示している。)
0x1004 0 / 1 分岐器(ポイント)の開通方向を示す値とする。
0:直線方向、1:曲線(分岐)方向(実際は、フルブリッジドライバに接続する2本のデジタルIO線のどちらをHIGHとするかを示している。)
0x1005〜0x1007 未使用 分岐器(ポイント)の予備用

FlashAirの共有メモリの書き込み(command.cgi)

FlashAirに無線LAN接続を行った端末(ブラウザ)から http://flashair/command.cgi?op=131&ADDR=0&LEN=8&DATA=12345678 にアクセスすることで、共有メモリにデータを書き込むことができます。この例では、共有メモリアドレス0x1000から8バイト分のデータ「12345678」を書き込むことができます。


FlashAirの共有メモリのデータ読み込み(command.cgi)

FlashAirに無線LAN接続を行った端末(ブラウザ)から http://flashair/command.cgi?op=130&ADDR=0&LEN=8 にアクセスすることで、共有メモリにデータを読み込むことができます。この例では、共有メモリアドレス0x1000から8バイト分のデータを読み込むことができます。


FlashAirの共有メモリの読み込み(iSDIO)

FlashAirに接続したArduinoにおいて以下のようなコードで、共有メモリのデータを読み込むことができます。

#include <utility/Sd2CardExt.h>
const int chipSelectPin = 4; //Seed Studio SD Card Shield V4は4番ピンを指定する。
Sd2CardExt card;
uint8_t buffer_sharedMem[8];

void setup() {
         if (card.init(SPI_HALF_SPEED, chipSelectPin)) {
             Serial.print(F("OK\n"));
         }
}

boolean iSDIO_sharedMemRead() {
         memset(buffer_sharedMem, 0, 0x08);
         if (!card.readExtMemory(1, 1, 0x1000, 0x08, buffer_sharedMem)) {
    		return false;
         }
}

このコードでは、まずsetup関数内でcardクラスのinit関数をSPI_HALF_SPEEDとSDカードのChip Selectピンを接続したArduinoのGPIOピン番号を引数に指定して実行して、SDカード接続の初期化を行います。初期化がうまくいくと、ArduinoのシリアルポートにOKと表示出力します。
Chip Selectピンの接続されるGPIOピン番号は、今回使用したSeed Studio SD Card Shield V4では4番ピンになっていますので、変数chipSelectPinは4を指定します。
初期化後、loop関数内からiSDIO_sharedMemRead関数を呼び出すと、変数buffer_sharedMemに共有メモリから読み込んだデータを格納します。このコードでは、先頭アドレス0x1000からサイズ0x08のデータを読みだして変数buffer_sharedMemに格納しています。データを利用するときは、変数buffer_sharedMemを使います。
ちなみに、共有メモリにcommand.cgiで半角数字(0〜9)を書き込んだ場合、共有メモリ上にはUS-ASCIIコードで書き込まれているようです。そのため、数字0はバイナリコード0x30(10進数:48)、数字1は0x31(同:49)……数字9は0x39(同:57)となります。半角数字を数値として読み取りたい場合は、char型にキャストして、48を引くと、数字文字と数値を変換できます。(もっとうまいやり方があると思いますが、手っ取り早くできる方法です)


int cmd_buffer;
cmd_buffer = (char)buffer_sharedMem[0] - 48;

操作画面の実装

この事例では、FlashAir内に配置したList.htmにJavaScriptでボタンを押下した際に上記URLを要求するようにしました。Webブラウザで操作画面を表示したイメージを以下に示します。

ボタン 動作・役割
STOP 緊急停止ボタン。鉄道模型の車両が脱線した場合など、すぐに停止させるため
DOWN スピードを落とす。1度押下すると走行速度を−10する
UP スピードを上げる。1度押下すると走行速度を+10する
Left 走行方向を左方向にする
Right 走行方向を右方向にする
SW_L ポイントの向き(開通方向)を左向きにする
SW_R ポイントの向き(開通方向)を右向きにする
Off すべてを初期状態に戻す
Clear 画面をリロードする
テキストエリア 動作・役割
SPEED_STATE 走行速度の表示。現在の走行速度を0〜200で表示する
RESULT HTTPリクエスト時のURLを表示する。(デバッグ用)
Controller

iPhoneで表示させた操作画面List.htm


<script language="javascript" type="text/javascript"> 
<!—
//関数:FlashAirに対してHTTP通信
function flashair_get( param ){
          var request = new XMLHttpRequest();
           request.open("GET", param, false);
           request.send(null);  } 
//グローバル変数定義
var send_mess = "http://flashair/command.cgi?op=131&ADDR=0&LEN=8&DATA="; 

var run_speed_state = 0;		//走行速度を数値で格納する変数。
var run_speed_val = "000";	//走行速度を文字列で格納する変数。
var run_lr_val = "0";		//走行方向を文字列で格納する変数。
var run_point_val = "0";		//分岐器開通方向を文字列で格納する変数。

//関数:各種変数をコマンド番号に応じて変更し、
//FlashAirの共有メモリに書き込むHTTPリクエストを要求する。
function isdio_send(cmd){
          switch(cmd){
		case 1:	 //緊急停止 run_speed_state を0、run_speed_val を0とする
				run_speed_state = 0;
				run_speed_val = "000";
				document.getElementById('SPEED_STATE').value = run_speed_state;
				url = send_mess + run_speed_val + run_lr_val + run_point_val + “000”;
				flashair_get(url);
				break;
		case 20:	 //ポイント制御 :曲線(分岐)方向  run_point_valを1とする。
			(略)
		case 21:	//ポイント制御 :直線方向 run_point_valを0とする。
			(略)
		case 30:	 //走行方向:右方向 run_lr_valを0とする。
			(略)
		case 31:	//走行方向:左方向 run_lr_valを1とする。
			(略)
		case 4:	 //走行制御:加速 run_speed_state を+10、run_speed_val を+10とする。
				run_speed_state = run_speed_state + 10;
				if(run_speed_state > 200){
					run_speed_state = 200;
					break;
				}
				run_speed_val = ( '00' + run_speed_state ).slice( -3 );
				document.getElementById('SPEED_STATE').value = run_speed_state;
            			url = send_mess + run_speed_val + run_lr_val + run_point_val + “000”;
				flashair_get(url);
				break;
		case 5:	 //走行制御:減速 run_speed_state を−10、run_speed_val を−10とする。
			(略)
		} 
		document.getElementById('RESULT').value = url;
	}
//-->
</script>

操作画面のList.htmに記述したJavaScriptの例

Arduino側の実装

この事例では、さきに示した共有メモリのデータ配置に従って、図のフローチャートのような処理を行います。

Controller

Arduino側のフローチャート

試運転をしてみましょう

それでは、この事例で製作した装置で鉄道模型を運転してみましょう。PWM出力用フルブリッジドライバの出力を線路に接続し、分岐器転換用フルブリッジドライバの出力をポイントに接続します。今回は、関水金属(KATO)の線路を使っていますが、トミーテック(TOMIX)でも同じように接続できます。
写真では、ArduinoにUSBケーブルが接続されていますが、これはArduinoに電力供給しているためです。
また、写真ではiPadをFlashAirと接続し、操作画面List.htmを表示して操作しています。

Controller

動作の様子を動画でも公開しています。



応用事例:鉄道模型コントローラの製作

この事例でご紹介した実装を応用して、鉄道模型コントローラ(いわゆるパワーパック)を製作してみました。このコントローラは、Arduino UNO R3とFlashAirを組み合わせて、PWM出力を2系統、分岐器を4つまで制御可能としました。ArduinoとFlashAirはもちろん共有メモリを介してデータのやり取りを行っています。PWM出力を増やしたので、共有メモリのデータ配置を図のように拡張しています。

Controller

iPhoneで表示させた操作画面List.htm

コントロール画面は、FlashAir内のList.htmにJavaScriptで実装しています。FlashAirの共有メモリに操作に応じてデータを書き込むだけでなく、定期的に共有メモリのデータを読みだして画面更新を行っています。そのため、複数の端末(Webブラウザ)からFlashAirに接続すると、いずれかの端末で操作した状態を、共有メモリを介してすべてのコントロール画面に表示反映されます。
要するに、1つのコントローラを複数人から操作できるようになったわけです。共有メモリにステータス(状態)データを格納し、これを介してArduinoなどで制御をする場合、共有メモリをどのように(例えば、複数の端末から)書き換えようと、Arduino側が意識する必要がありません。これはステータス(状態)データを使った方式のメリットです。

皆さんも、FlashAirを使ってオリジナルの鉄道模型コントローラを製作してみてください。

arduino-sensor

パワーパック外観

arduino-sensor

パワーパック内部

arduino-sensor

FlashAirのList.htmをWebブラウザで表示した様子

arduino-sensor

鉄道模型コントローラを使って鉄道模型運転をしている様子