エンジニアの夏休み:蓄光テープで「省エネディスプレイ」を作る

第3回 PHP/HTTPを使ってPCから文字を描画しよう

この記事を読むのに必要な時間:およそ 2 分

第1回では,蓄光テープにLEDで像が描けるのを確認しました。第2回では,センサを使い蓄光テープをエンドレスにたどることができるのを確認しました。いよいよ今回は,蓄光テープにPCから文字を描画してみます。

HTTPでの文字送信

さて,ひとつ悩ましいのが通信方法です。ライントレーサですから無線を使いたいというのもありますが,どうせ電源ケーブルがついているのだから有線でもいいという考えもあります。無線ならBluetooth,Zigbee,無線LANなどが考えられます。有線ならUSB,シリアル,LANなどが考えられます。それぞれ一長一短あるのですが,今回はどのプラットフォームでも使え,トータルの開発の手間が少ないという点を評価して,LANを使いました。

今回取り付けたネットワーク(LAN)モジュール

今回取り付けたネットワーク(LAN)モジュール

一昨年,NゲージをPHPから制御するという記事を書きました。このとき使ったLANモジュールを今回も使います。ただし,NゲージのときはPCからHTTPリクエストを受け付けていましたが,今回はPCにHTTPリクエストを送って文字イメージを受け取っています。ひとまず動画を見てみましょう。

PC側ではApacheとPHPが動いています。描画するメッセージをWebから受け付けるのと平行して,ライントレーサからのリクエストに応じて文字イメージを生成しています。今回はASCII文字のみ対応としたので,gdライブラリの内蔵フォントを使いました。動画を見ると,文字と文字のあいだが少し空いていますが,これは文字を描き終わってから次の文字をリクエストしているためです。ライントレーサ側を工夫して,文字を描いているあいだに次の文字イメージをリクエストするように改良すれば,文字間を詰めることができます。あるいは,通信中はモータを止めてしまうという方法も考えられます。

HTTPリクエスト+PHPを使ったわけ

さきほど「トータルの開発の手間が少ない」と書きましたが,もう少し詳しく見てみましょう。

今回のシステムは,ライントレーサが蓄光テープをたどりながら,LEDで文字を出力します。すると,たとえば折り返し地点でテープが途切れたところで描画をいったんやめ,次のテープ上まで進んだら描画を再開する,といったことをやりたくなるかも知れません。このためには,ライントレーサがPCにデータを要求し,これにPCが応答するという仕組みが自然です。なぜなら,ライントレーサが自分の進み具合に応じて要求を出せば,その分だけデータが送られてくるからです。反対に,PC側が決まったスピードでデータを送る方法だと,フロー制御のような仕組みが必要になり,複雑化してしまいます。

今回のシステムの全容,装置本体とコントローラであるSharp NetWalkerをLANケーブルでつないだだけです

今回のシステムの全容,装置本体とコントローラであるSharp NetWalkerをLANケーブルでつないだだけです

もうひとつ,メッセージを受け付けて文字イメージに変換する処理があります。これをどう実装するか決めないといけません。将来的にフォントを変更することを視野にいれると,TrueTypeなどのフォントを扱えるプラットフォームが有利です。今回のシステムではPHPを選択したのですが,前項のLANとも親和性が高く,フォントも扱え,Webベースの入力インターフェースも作れるというおまけまでつきました。

実際の処理ですが,あまり面倒なことはしたくなかったので,メッセージが入力されたらテキストファイルに追記するようにしました。ライントレーサ側は,どこまで進んだかをパラメータで渡します。これによって,追記された分だけを描画することができます。最初だけは,ファイルの最後に移動するようにして,毎回全メッセージを描くのを避けています。

リスト1 PHPによる文字列送信のプログラム

<?php

$fp = fopen("message.txt", "r+") or die("fopen failed.");

if (($offset = @$_GET["offset"]) !== null) {
	if ($offset == "ffffffff") {
		fseek($fp, -1, SEEK_END);
		$offset = ftell($fp);
	} else {
		$offset = ("0x".$offset) + 0;
		fseek($fp, $offset, FSEEK_POS);
	}
	$s = fread($fp, 1);
	if (!feof($fp))
		$offset++;
	
	$g = imagecreate(8, 8);
	$c0 = imagecolorresolve($g, 255, 255, 255);
	$c1 = imagecolorresolve($g, 0, 0, 0);
	imagefilledrectangle($g, 0, 0, 8, 8, $c0);
	imagestring($g, 1, 0, 0, $s, $c1);
# header("Content-Type: image/png");
# imagepng($g);
# die();
	printf("%08x", $offset);
	for ($x=0; $x<5; $x++) {
		$v = 0;
		for ($y=0; $y<8; $y++)
			if (imagecolorat($g, $x, 7 - $y) != $c0)
				$v |= (1 << $y);
		printf("%02x", $v);
	}
	printf("\n");
	die();
}


if (($text = trim(@$_POST["message"]."")) != "") {
	fseek($fp, 0, SEEK_END);
	fputs($fp, $text." ");
	fclose($fp);
}

?>
<HTML><HEAD><TITLE>message.php</TITLE></HEAD>
<BODY>
<H1>message.php</H1>

<FORM method=POST>
<INPUT type=text name=message size=40><INPUT type=submit>
</FORM>

<HR>
</BODY></HTML>

シリアル通信を使うなら

せっかくですので,LAN以外の方法のヒントも紹介しておきましょう。シリアルを使い,Windows用のGUIアプリも必要だった案件です。ボタンを押すとシリアルにコマンドを出力するだけなのですが,このためだけにわざわざ本格的な開発環境を入れたくはありません。そこで,XULRunnerというプラットフォームを使いました。これはFirefoxの枠組みだけを,独立したアプリケーションとしたもので,XULというHTMLライクな(というと語弊がありますが)GUI記述言語とJavaScriptを使うことで,プログラムを動かすことかできます。しかも,Windows,Linux,Macのいずれのプラットフォームにも対応しています。

XULRunnerはシリアルの出力はできません。しかし,dump()を使用することで,コンソールにデバッグメッセージを出力することができます。これをCOM1などにリダイレクトしてあげれば,GUIのボタンを押したときにコマンドをシリアルに送ることができます。Linuxなどの場合は,標準入力を/dev/tty*に出力してあげる簡単なプログラムを作り,setuidしておけばよいでしょう。

残り少ない夏休みですが,みなさんもぜひ面白いものを作ってみてください。

著者プロフィール

木元峰之(きもとみねゆき)

独立系ソフトハウスに8年間勤務,パッケージソフトの開発や記事執筆などを行う。現在はフリーのコンサルタント。SWESTなどのワークショップで分科会のコーディネータを務める。デジタル回路設計歴30年,プログラミング歴27年。

きもと特急電子設計
URL:http://business.pa-i.org/

コメント

コメントの記入