ipad(6)

女房が姉さんの所へipadを持っていって自慢、もとえ披露すると言うんで、おいらはサポーターと して付き添ってあげた。

姉さん、開口一番に、かわいいですってさ。女房のお勧めは、例のクックパッドやら3分 クッキング。起動すると、動かすには設定からWiFiを設定してくださいと出て来る。

おいらが、あらかじめ機内モードに設定しておいたんだ。だって、姉さんの所、無線環境が 無いからね。 その事を女房に説明すると、やっと分かったみたい。最初にipadが我が家へ来た時に説明したんだけどな。

ネット関係のアプリを諦めると、魅力が10%になっちまうなあ。こりゃ、姉さんの趣味の世界を くすぐってあげるに限るな。って訳で、一生懸命に、無料の文庫本が読み放題だよって 説明してた。ページをめくる時のリアルさに驚いていましたよ。

後は、おいらが引き取って、カメラが付いてて、ぱちぱち取れるよと、実演。おまけで 女房の写真も撮ってあげたら、しげしげと見てましたよ。

そして、あーあ、重力には逆らえない。顔が弛んできたとぬかす。これから毎日、フェイス トレーニングするから、その効果を写真に取って記録しろって言われたよ。 毎日、化粧とかで鏡を見てるはずなんだけど、写真に写った顔は、鏡の中のそれとは別物らしい。

こっそり、ボイスメモをONにしといて、姉妹の馬鹿話を盗録。後で聞かせてあげたら、 あらー、こんな事言ってたっけとのたまう。話と言うより、さえずりだな。

興味が沸いてきたみたい。家でやるにはどうするの? って、聞かれた。にわかコンサルタント業に 変身。 無線が必要ね。このあたりじゃ、LTEが来るのを待っていたら墓場へ行っちゃうから、諦めて 光回線を引きましょう。大丈夫、今有る銅回線の電話が、そっくりそのままガラス回線に なるだけですから。回線を引く時、無線機も無料で貰うといいです。

ipadと無線LAN、回線装置を設定する時に、一時的にパソコンが必要になるけど、そんなの おいらがパソコン持ってきてやりますよ。

だから、姉さんがやる事は、決断だけ。あぷる教へ入信するか否かです。

とか、言ってたら、あぷる教へのお布施代が突然値上げされちゃったね。昔は、42800円 だったものが、今は49800円ですって。これで喜ぶのは、どこものしゃちょーさんだけ。

回光通信機

前回はgambitをやった。こやつSchemeだけど、Lisp族から分派してるんだね。このあたりの Lispの進化が論文となって 公開されてて、非常に興味深いです。

それはさておき、おいらはPaisonista って、開発システムをipad用に購入してるんで、こちらも 有効利用してみたい。どうやって作るより、アイデアを発動する方が重要だ。で、考えたね。

ipad用にSOS信号発生器付きの懐中電灯を入れた事を思い出した。これはこれでいいんだけど、 壊れたレコードプレーヤーみたいに、同じ信号しか発生しなくて、プチ不満があるぞ。

有事の際は空から偵察に来るはずなんで、地上からも意思を伝えたい。まあ、SOSを発してる って事が分かれば、それでOKって見方もあるけどね。

一般に、光の断続で通信を行うのは、軍事通信として発達してきた。SOSだけじゃ、用を 為さないことは、兵士でなくても理解出来るだろう。で、断続での通信は、 回光通信機 というジャンルで、発達してきたようだ。そして、 現代進行形だったりします。

今回は、Paisonistaで、これをやって、溜飲を下げる事にしよう。まあ、大人の工作だわな。 勿論、morseとかでipadのAppを検索すると、同種のものがすでに存在する事は承知してます。車輪の再発明、 大いに結構って事で。。。

基礎実験

いきなりコードを書き始めるのじゃなくて、すこしづつ実験をしながら作って行く事にします。 モールス信号の発生には、正しい時間間隔の認識が必要。これを、どうやって実現するかが、 キーテクノリジー(我ながら、大げさな表現だな)となります。

目を付けたのは、Paisonistaのテンプレートに出てた、この部分。

	def draw(self):
		# This will be called for every frame (typically 60 times per second).
		background(0, 0, 0)

これ、2Dグラフィックを扱う、Sceneってクラスの基本部分(の一部)です。毎秒、60回 呼び出されるって事ですね。精度は余り期待出来そうにない、マルチバイブレータですかね。

マルチバイブレータと言うと、古くはトランジスタ2個で組みました。もう少し進歩すると、 SN74123をたすきがけするとか、NE555発振回路 なんてのが定番だったりします。

ああ、話が逸れました。早速ソフトウェア実験をします。

from scene import *
import time

class Sos (Scene):

	def setup(self):
		self.st = time.time()
		self.i = 0
	
	def draw(self):
		if self.i < 600:
			self.i += 1
			self.sp = time.time()
			print (self.sp - self.st)
			self.st = self.sp
			if self.i % 2 == 0:
				background(1, 1, 1)  # LED white
			else: 
				background(0, 0, 0)  # LED black

run(Sos())

幸いな事に、ipadでも、time.time(で、出来るだけ分解能の高いEpoc時間取得)が、サポート されてたので、drawの呼び出し間隔を測ってみました。で、その結果は

0.00389409065247
0.0170869827271
0.0244839191437
0.0243430137634
0.036957025528
0.0138919353485
0.0165331363678
0.0173988342285
  :
0.0169289112091
0.0168769359589
0.0163340568542
0.0166749954224
0.017303943634
0.0159800052643
0.0167229175568
0.0166671276093

呼び出しが始まった直後と、最後の方の部分です。何回測定しても、上記のような結果に なりました。発振開始直後は安定してません。特も4回目で、大きく間隔が開いています。これって、良く 呼び出されるんで、JITコンパイルでもしておくかって、事なんでしょうかね。

それ以降は安定してて、目だったジッタは有りませんでした。よって、drawの呼び出し 間隔を基準に事を進めればよさそうです。

実験基板

キーテクノロジーが確認出来たので、これを元に実験基板を作ります。 まあ、タイミングに基づいてLEDをOn/Offするだけですから、アルディーノの電子工作入門 相当ですな。

from scene import *

class Sos (Scene):

	def setup(self):
		self.i = 0
		self.c = 0
		self.mpy = 30
		self.buf = [ 1, -1, 3, -3, 3, -1, 1, -1, 1, -1, 1, -7]
		self.buf = [x * self.mpy for x in self.buf]
	
	def draw(self):
		if self.i >= len(self.buf):
			self.i =0
		elif self.c == 0: 
			self.c = self.buf[self.i]
			self.i += 1
		if self.c > 0:
			print 'O'
			background(1, 1, 0)    # LED on (yellow = Red + Green)
			self.c -= 1
		else: 
			print '-'
			background(0, 0, 0)    # LED off
			self.c += 1

run(Sos())

self.buf内のそれぞれの要素ですが、タイミングの元を保持してます。プラスの場合は、Led点灯、 マイナスの場合は、Led消灯を意味してます。それぞれ、drawの中で、ゼロに向かって、-1、もしくは +1し、 ゼロになったら、次の信号をFetch。全体は、リピートするようなロジックです。

mpyに信号の増幅度を設定してます。でもって、設定値を実際のカウント値になるように増幅してます。 上記のように30を設定しておくと、 ドットの点滅が、30/60 って事で、0.5秒になります。

bufの中に埋め込んだモールス信号は、'AB' です。無線家には釈迦に説法でしょうけど、 一応念のため。

タイミングのデバックは、目で追うのがしんどかったので、LedのOn/Offに伴って、コンソールに 、'O' と '-' を表示するようにしました。

これで、光送信機の終段は完成です。

モールス信号発生器

次は、文字列からモールス信号を発生させる変換器を作ります。どうやって作るか? 同業他社では、どんな風にしてるんだろう? factor社の例の部門を訪れてみました。 語からtagsと辿って、example部門へ行くのが迷わないこつです。何せ、敷地が広いですから。

Ordinary words
Word              Stack effect
 >morse           ( str -- newstr )
 ch>morse         ( ch -- morse )
 morse-code-table ( -- value )
 morse>           ( morse -- plain )
 morse>ch         ( str -- ch )
 no-morse-ch      ( ch -- * )
 play-as-morse    ( str -- )
 play-as-morse*   ( str unit-length -- )

使い方は、簡潔に説明されてました。上記がfactor社の公用語です。

USE: morse
IN: scratchpad Loading resource:extra/morse/morse.factor
Loading resource:extra/openal/openal.factor
Loading resource:extra/openal/alut/alut.factor
Loading resource:extra/openal/alut/backend/backend.factor
Loading resource:extra/openal/alut/other/other.factor
Loading resource:extra/synth/synth.factor
Loading resource:extra/synth/buffers/buffers.factor
Loading resource:basis/sequences/merged/merged.factor
Loading resource:basis/sequences/merged/merged-docs.factor
Loading resource:extra/sequences/modified/modified.factor
Loading resource:extra/sequences/repeating/repeating.factor
Loading resource:extra/morse/morse-docs.factor
IN: scratchpad "ab bc" >morse

--- Data stack:
".- -... / -... -.-."

どんなコードになってるか、見学させてもらいました。

<PRIVATE

CONSTANT: dot-char CHAR: .
CONSTANT: dash-char CHAR: -
CONSTANT: char-gap-char CHAR: \s
CONSTANT: word-gap-char CHAR: /
CONSTANT: unknown-char CHAR: ?

PRIVATE>

CONSTANT: morse-code-table $[
    H{
        { CHAR: a ".-"    }
        { CHAR: b "-..."  }
        { CHAR: c "-.-."  }
        { CHAR: d "-.."   }
             :
        { CHAR: @ ".--.-." }
        { CHAR: \s "/" }
    } >biassoc
]

: ch>morse ( ch -- morse )
    ch>lower morse-code-table at unknown-char 1string or ;

: word>morse ( str -- morse )
    [ ch>morse ] { } map-as " " join ;

: sentence>morse ( str -- morse )
    " " split [ word>morse ] map " / " join ;

: trim-blanks ( str -- newstr )
    [ blank? ] trim ; inline

: >morse ( str -- newstr )
    trim-blanks sentence>morse ;

行頭のスペースを削除して、センテンスをモールスにするんだよとな。で、文字は小文字に 変換してから表を引いてるな。モールスの字の区切りはスペースを挟む、ワードの区切りには スラッシュを挟むとな。よし、おいらも、パイソン語でやってみるか。

def morse(text):
	mor = {'a':'13', 'b':'3111', 'c':'3131', }
	m = [-1]				# Guard
	for c in text:
		if c == ' ':
			m[-1] = -7		# Word gap
		else:
			for d in mor[c]:
				m.append(int(d))
				m.append(-1)
			m[-1] = -3		# Char gap
	m[-1] = -7				# Text end
	return m

与えられた文字列が引数で渡ってくる。内部に文字ー>モールスの変換ROMを内蔵しといて、 ROMを引いてみる。

In [2]: print morse('ab aa')
[-1, 1, -1, 3, -3, 3, -1, 1, -1, 1, -1, 1, -7, 1, -1, 3, -3, 1, -1, 3, -7]

ぐだぐだ言うより、実験しちゃった方が早かったか。

ROMは不完全なので、各自で追加実装してね。 (Morse Code) 表を引けなかったら、BUS ERRORもとえ、Key ERRORで 落ちっからね。何と言っても、一切の防御対策はしてません。裸の実装です。こんな コードを書くにも、 PythonRecipeなんてのを引いちゃったよ。 おいらに取っちゃ、レシピ様々だな。

ああ、Guardってのは、発振が安定するまでの逃げ時間を確保するのと、冒頭にスペースが 来た時に落ちるのの防止です。スペースのトリムをするのが本筋だろうけど、まあ、この ままでいいか。

組み込みで困った

後は、最終配線するだけ。画面にお触りしたら、テキストボックスが出てきて、そこに テキストを入力ってイメージしたんだ。

けど、目を皿のようにして探しても、相当の関数は見つからない。思い余って、 Paisonista Forlamを覗いちゃったぞ。

そしたら、あぷるの横暴によって、UI用のグラフィック部品(テキストボックスとか押しボタン、 チェックボックス類)の提供は、まかりならん事になってるから、皆さんには出せないのよって、App作者の 悲痛な叫びが載ってました。続けて作者さんは、UIやりたかったら、さふぁりのJSで我慢 してねってアドバイス。

でも、こっそりと闇部品を組み立てているみたいだ。そのうちに仕入れてきて試して みるかな。今日の所は、泣く泣く断念しましょ。という事で、最終配線をします。

msg = raw_input('Enter msg: ')
Sos.buf = morse(msg)
run(Sos())

見ての通り、先にコンソールモードで、テキストを受け取っておき、クラスの属性に 変換した信号を渡してから、終段を駆動するって方式に落ち着きました。(あぷるの 横暴で、こうせざるを得なかったって事です)これを試す時は、setupの中でbufに 実験データをセットしてる所を、パターンカット(みんな、得意だよね)もとえ、 コメントにしとく事。

そう言えば、どんなちっちゃな送信機を作っても、電寒に届けてからじゃないと電波を 出せないってのは、あぷると同類項だと思っちゃうぞ。

とまあ、領主様に泣かされる事が多くなったら、もうしょうがない、首をくくって 領主様の懐に飛び込むしかないな。その時の心得は、 こちら

昔は面倒な手続きを経て輸入した、Inside MAC 相当品が、無料でしかも日本語版で公開されてる。 iOSヒューマンインターフェイスガイドライン。 世の中、進歩してんのね。

TODO

とまあ、LEDのOn/Off装置は作ってみたものの、いまいちビジュアルっぽくないな。 何か良い題材は無いか?

しばし考えて、通信とビジュアルの融合ってのはどうだろう。太古の昔から行われていた、 のろしのシュミレータなんてのはどうだ。 リアル世界じゃ、のろしはおろか焚き火も禁止されてて、煙を出すとすぐに消防署の方からサイレン 鳴らして飛んでくるからな。

この狼煙、最近話題になってたね。こんくらべ とか言うやつ。白い煙/黒い煙で、キリスト教団の 大親分が決まった/決まらない を表すってんだから、昔のデジタル通信だな。あれ? 煙が上がらない状態も有るから、 正確には、はすけるで言うMaybeの世界。Lisp族だと、t/niの他に有る、undefinedって事だな。はるか昔 からのを現代風に表現した訳だ。

狼煙が1本だと1ビットの通信だけど、狼煙を2本同時に上げると、2ビットって事で、4つの 状態を表現出来る。デジタルの世界は、2の倍数が基本になるんで、2ビットの次は 4ビットだ。これだと、16の状態を表せる。

とか言ってたら、通信の世界では3ビットまとめてって方式もあるのね。 詳しくは、デジタル変調の あたりを参照。

で、狼煙を4本まとめて上げるアプリでも作ってみるかな。煙のふわふわ感をどう表現 するかが、キーテクノロジーになりそうだな。 こういうのが、参考になりそう。 それと、風が吹くような悪い条件の時は 当然、煙が混ざり合って混沌とした世界になるんで、こういう時は、狼煙の本数を2本、 1本にするとかも考えておかないとな。いわゆる、フォールバックってやつか。