2014年 01月 23日

FT-450D の CAT の挙動

AI の挙動不審

AI (Auto Information) でデータが自動でくるようになるけど、その状態でこちらから読み出しコマンドを出したり、書き込みコマンドを出したりすると、それらのコマンドがうまく読みとってくれなかったり、あるいは出力が混ざったりする。

解決方法でいまいち良いのがない

考えた解決案

  • AI はするが、コマンドは何度か送りつける
  • 一旦 AI を止めて、コマンドを送りつけて AI を再開する
  • AI を一切やめて必要な情報だけをポーリングする
AI はするが、コマンドは何度か送りつける
  • 3回程度送りつけても結局失敗することがある

コマンドが成功していることが確認できるまで送り続ける方法もあるが、コマンドごとに確認方法が違うのでコーディングが大変

一旦 AI を止めて、コマンドを送りつけて AI を再開する
  • まず、AI を止めるためのコマンドが認識されないことがある
  • AI を止めてもすぐに止まるわけではないっぽい
AI を一切やめて必要な情報だけをポーリングする

確実に動くけど

  • 情報が反映されるのが非常に遅くなる

例えば読み出しコマンドを発行すると、250ms ぐらいでようやくレスポンスがあるので (何やってんだ?) 、4個値を読み出すだけで1秒かかってしまう。

AI はそのまま

AI はそのままにするのがやはりよさそう。コマンドを送って確実に操作するよりも情報を早く受けとるほうが重要だと思う。

とはいえ、コマンドを送ったのに反映されないのもイラつくので、かなり執拗に送信確認をする必要がある。

  • 書きこみするコマンドを3回送りつける
  • 読みだしする

として、返答があるのを250msぐらい待って、セットできていなかったらリトライする。

2014年 01月 22日

絶縁型 RS-232 ⇔ TTL レベル変換

RS-232 TTL 変換をフォトカプラでやる。

グラウンドを分離したいと、ノイズ相互の流入を防ぎたいのでRS-232変換を専用ドライバーICではなく、フォトカプラで行うようにした。無線機側とグラウンドを共通にするとインターフェアがでやすいらしい。

面倒な点は、RS-232 側の両電源を別に用意しなくてはならないところだけど、ググってみるとRTSにきてる電圧と RX の電圧をうまいこと利用している例があったので、それに従うことにした。一応RTS CTSをショートさせて電圧を計ってできそうなことを確かめた。

回路

これのコピーです

RS-232 が正負電圧で論理表現をするのでそこが面倒なところ、正電圧はRTSできてるのでいいけど、負電源をとれるピンはないので、TXのアイドル (負電圧がかかってる) を使ってる。47uFの電解コンデンサは電源を安定させるためについてる。

TX のアイドル時にコンデンサに電荷をためといて、RX が正じゃないときはダイオードを通じて RX のレベルを負に保つようになっている。コンデンサの前に 680Ω の抵抗がついているのは正のときにおかしくならないようにかな……

あとは電圧をクリップするダイオードがついていたり、フォトカプラのスペックにあわせるための抵抗がついてたり。

RS-232とTTLは論理が逆だけど、フォトカプラがオープンコレクタなので自動で反転して丁度いい。

手元で試した限りだと、ボーレート 19200 でもうまくうごいた。

挙動を確認する

その後オシロスコープを買ったので再度挙動を確認してみた。

これは Linux → Rig 方向のもの。この方向の負電圧は 47uF に蓄えられているものが使われる (と思う) ので、連続して送信を行うと、だんだん電圧レベルがさがってしまう。最後のほうは 3V 未満になってしまっているので、RS-232 レベル的には動かない。

200uF にすると、だいぶマシになる。適切なのを選択する必要がありそう。

ハマったところ

ハマったのは、USB シリアル変換ケーブルと、無線機のRX TXの配線が逆な点だった。これは普通にドライバーIC使ったときもハマったので比較的すぐ抜けれたけど、毎回ハマる…

あとはTTLレベルのRXをRS232ドライバICに面倒くさがって繋がったままやってたら動かなかったのもハマった (電源が入ったままだったので GND に落ちていたっぽい)。変なことしないほうがよい

あと、もっと簡略化した回路(TXとRXを繋ぐ部分、負電源部分を削除したもの)もググるとでてくるけど、それだと今回はレベルが安定しなくて、エコーする現象が起きてだめだった。

フォトカプラは FOD817B300 というのを使った。応答速度の関係でものによっては動かないとかあるみたいだけど手元にあったのでうまく動いた。

参考文献

2014年 01月 21日

Angular JS で View を伴う Service 的なことをしたいとき、あるいは Directive に Controller をつけたいとき。

クソコード を書いたはいいが、釈然としなかった。 "View independent business logic: Services" とドキュメントに書いてある通りなので、やはり他のやりかたのほうがよい。のでよくよく読んだところ、やはり View にかかわる部分は Directive に集約されるようだ…… しかし使いかたが非常に難しい。

iimsApp.directives.directive('dialog', function ($q) {
    return {
        restrict: 'E',
        transclude : true,
        scope : {
            Dialog : '=name'
        },
        controller : function ($scope) {

            $scope.Dialog = {
                open : function (title) {
                    $scope.deferred = $q.defer();
                    $scope.title = title;
                    $scope.show  = true;
                    return $scope.deferred.promise;
                }
            };

            $scope.close = function () {
                $scope.show = false;
            };

            $scope.ok = function () {
                $scope.close();
                $scope.deferred.resolve();
            };

            $scope.cancel = function () {
                $scope.close();
                $scope.deferred.reject();
            };
        },
        templateUrl : '/static/js/app/dialog.html'
    };
});

こんな感じで dialog という directive を定義して、

<div ng-controller="FooCtrl">
    <dialog name="FooBarDialog">
        {{ message }}
    </dialog>
</div>

というふうにすると、FooCtrl のスコープから FooBarDialog というプロパティで見えるようになる。つまり

        $scope.message = "Hello!";
        $scope.FooBarDialog.open('OKK!!!!!').then(function () {
            alert('ok');
        }, function () {
            alert('cancel');
        });

みたいなあ

難しポイント

  • restrict: 'E'
    • この directive は要素として使うよってこと
  • directive の scope の定義がむずかしい
    • プロパティ名には自分のスコープで見える名前、値には謎の書式で親スコープから見える名前が書いてある属性名を書く
  • controller に渡される $scope
    • 親スコープなどからは分離されているスコープが与えられる。directive が何度も出現することもあるからね!
  • transclude: true の意味。これは dialog 要素内に内包される変数が、外側のスコープをさすようにするもの。例では $scope.message を外側のスコープで代入している

こういう謎の構造体を返すのってわっかりにくいので気持ち悪いなあて思いました。全部メソッドになっているべきなのでは????

directive のプロパティの説明がどこにあるかわかりにくいけど、 http://docs.angularjs.org/api/ng.$compile#description_comprehensive-directive-api_directive-definition-object にある

2014年 01月 20日

Angular JS でビューを伴う Service ってどう書けばいいんですか

続きをかきました。

[tech] Angular JS で View を伴う Service 的なことをしたいとき、あるいは Directive に Controller をつけたいとき。 | Tue, Jan 21. 2014 - 氾濫原

よくわからなかったので以下のようにしましたが、まっとうな方法には思えないので正しいやりかたをおしえていただきたく申し上げます……

  • factory で空のオブジェクトをかえしとく
  • view に紐付けた controller で factory で作ったオブジェクトを初期化する
  • 作った Service を依存に加えて使う

一応、controller 間は直接依存しない (Service を mock にさしかえれば動く) のでユニットテストは書けると思うけど、よくわかりません……

myApp.factory('DialogService', function () { return { } });
myApp.controller('DialogControl', function ($scope, $q, DigalogService) {
	DialogService.open = function (title, message) {
		$scope.deferred = $q.defer();
		$scope.show = true;
		return $scope.deferred.promise;
	};

	$scope.close = function () {
		$scope.show = false;
		$scope.deferred = null;
	};

	$scope.ok = function () {
		$scope.deferred.resolve(true);
	};
});


// User
myApp.controller('FooController', function ($scope, DialogService) {
	DialogService.open('foo', 'bar').then(function () {
		...
	});
});

そもそも "View independent business logic: Services" と書いてあるので、定義からして Service はビューを持ってはいけないようです。

じゃあビューを伴う Service 的なものはどうやって書くんですか

Raspberry Pi を中心にやってみようとしているところ

Raspberry Pi せっかくあるので、一応作りたい目標をもっていろいろ試してみてる。現時点での思惑を書いておく。

概要

無線機の周辺を拡張して、PCと連携しやすくしたり便利にしたり、というのが目的。具体的には

  • 無線機の Wi-Fi 化
    • API サーバになってLAN内のコンピュータから無線機の情報を取得・設定する
  • アンテナ切替情報の取得・設定
  • そのたもろもろ

全体

  • Raspberry Pi
    • I2C バス
      • アンテナ切替コントローラー (AVR)
      • センサー計 (温度など)
    • シリアルポート
      • 無線機コントロール (RS-232C 変換)
  • WebSocket サーバー
    • 周辺機器の中央集権サーバー
      • 無線機コントローラー
      • アンテナ情報
      • センサーなど

ある程度拡張性を持たせつつこれらを収めたい。無線機の近くで使うので、ある程度ノイズ対策が必要かもしれない。

ブロックごとの設計

電源部
  • アンテナ切り替えリレー用に 12V (最大 400mA 程度) が必要
  • Raspberry Pi が 5V 700mA が必要
  • ほか周辺機器分はそんなに食うものがないので、かなり余裕を持っても 5V 500mA ぐらいあればよさそう
    • Raspberry Pi の GPIO が 3.3V で接続機器もあわせたいので 3.3V も必要

12V が必要なので、ACアダプタとして 12V を使い、降圧して 5V, 3.3V を作りたい。

  • 12V 500mA (6W)
  • 5V 1A (5W)
  • 3.3V 500mA (1.65W)

ぐらい確保できたら十分そう。PC用の電源だと、100Vから直接これらの電圧を全部調達できるけど、コストはともかくオーバースペックでデカすぎる。

12V 2A ぐらいのACアダプタ (24W) から 5V はスイッチングである程度高容量を高効率でとりだして、3.3V は 5V からリニアレギュレーターで安定化させる感じにする。

http://akizukidenshi.com/catalog/g/gM-02038/

5V 3A のスイッチングDC/DCコンバーターで、変換効率は最低でも73%。

  • アダプタ: 12V 2A
    • 12V 500mA
    • 12V 1.5A (18W) -> 5V 2.6A (18 * 0.73 = 13.14W)
      • 5V 1A
      • 3.3V 500mA を 5V からリニアレギュレーターで作ろうとすると、電圧差はそのまま熱になるので ( (5 - 3.3) * 0.5 = 0.85W が無駄になる)、単に 5V 500mA を消費すると考えることができる。
アンテナ切替コントローラー

ATmega168P をつかって実装。TWI (I2C) がついてるので簡単。内蔵8 M クロックで動作させて、アンテナのリレーのコントールをI2C経由及びボタンで行い、LED でどのアンテナが有効かを表示する。

リレーは2〜6つほどを同時に駆動する必要があり、この時最大で 400mA ほど流れる。かなり余裕があり、3.3V でも十分スイッチできるパワーMOS-FET でスイッチングする。

電源は I2C を Raspberry Pi と直接繋げたいので 3.3V 供給

センサー類

基本的に I2C 対応、3.3V 品なので、そのままバスに繋ぐだけ。ごちゃごちゃやりたいのでブレッドボードを内蔵してそこに差す

RS-232 変換

無線機とのインターフェイスのために RS-232 変換をする。

2014年 01月 17日

Raspberry Pi / BeagleBoard Black / Intel Galileo / Arduino の違いのメモ

いろいろでてきてる。

Raspberry Pi

Type AType B があり、Type A はイーサネットポートと組込みUSBハブがなくメモリが少ない分少しだけ安い。

BeagleBoard Black

本体は Raspberry Pi と同じぐらいの価格だけど、

  • CPU がより高速
  • オンボードなフラッシュメモリがある (SDカードもつけれる)
  • 消費電力がより低い
  • GPIO が多い

という特徴がある。内蔵フラッシュメモリがあるので、(それにおさまるなら) SDカードがいらない分、Raspberry Pi よりコスト面でも有利。一方で欠点は

  • 入手性
    • Raspbery Pi はかなり安定して手に入る感じだけど、BeagleBoard Black はそうでもない感じ
  • 情報源
    • やはりちょっと少ない

Intel Galileo

価格的に上であげたものの1.2〜1.5倍ぐらいする。現時点ではまだ日本未発売。1月中旬らしいのでそろそろかな。2A のAC アダプタとケーブルが一部付属っぽいので、(それらが必要な人なら) そんなに割高とはいえないかもしれない。

Linux が動いてるけど、Arduino 互換を謳ってる。ピン互換があって Arduino 用にでまわっているシールドがつかえるのと、開発環境も Arduino のものが使える。

気になるのは

  • グラフィック出力がない (HDMI とか)
  • 消費電力 (詳しいスペックがわからないけど、2A のアダプタが付属ってことは結構あるのかな)

Arduino

Arduino は AVR というマイコンを使って動いているので、Linux は載っていない。本当にローレベルなことしかできないし、CPU クロックも20MHz程度。2000円〜3000円ぐらいで買えるみたいだけど、できることと、実装方法の苦楽の差を考えると Raspberry Pi や BeagleBoard Black のほうが圧倒的にコストパフォーマンスは高い。

個人の見解のまとめ

最初に手をとるなら Raspberry Pi がよさそう。もっと要求がでてきたら BeagleBoard Black がよさそう。Intel Galileo はなんともいえない。

さらに別の回路を複雑に繋げたり、役割分担をさせたくなったら、Arduino 的なものを導入してもよさそう。

しかし AVR 使うなら、普通にチップ買えば1個あたり50円〜300円程度 (チップによる) なので、個人的にはそのほうがいいと思う。ただ、Arduino はオールインワンな感じの開発環境がキモなので、それが欲しいなら Arduino はいいかもしれない。(自分で互換のブートローダーを書きこんでもいいけど)

2014年 01月 16日

関連エントリー (画像)

2014年 01月 15日

Raspberry Pi の SD カードを Mac でバックアップ

特筆するほど難しいことはないけど書いておく。基本的に dd を使う方法が最速だと思うけど、dd コマンドはうっかり使うと死ぬ感じなので、こういうことは GUI で行いたい。なので、ディスクユーティリティを使用してバックアップを作る。

SD カードをさしこむとディスクユーティリティにでてくるので、各パーティションをアンマウントして (boot だけ自動でマウントされるはず)、カード (この例では 32.02GB APPLE SD Card...) を選択して、ツールバーの「新規イメージ」を選択する。

新規イメージでは、デフォルトで「圧縮」が選択されているはずなので、そのまま適当なディレクトリに保存する。

するとコピーがはじまる。基本、SDカードそのものの読み出し速度に律速される。手元のカード (Class 10) の場合、25MB/sec ぐらいで読み出されて、圧縮で 8〜16MB/sec で書き込みがある。32GB だと、32 * 1024 / 25 / 60 で、22分ほどかかる。最終的に 18GB になった。

Mac では Linux で使われる extN には対応していないので、Raspberry Pi の ext4 のパーティションはマウントできない。コピー中、パーティションのタイプ自体は認識されているけど、ext2 として認識されている。

圧縮された .dmg ができるので、復元 (あるいはクローン) もディスクユーティリティを使う必要がある (Mac 上でマウントして復元、または hdiutil convert してから)。dd + gzip だとどこの環境でも簡単に復元可能なので、どっちもどっちかなという感じ。

2014年 01月 14日

関連エントリー (画像)

node.js で Perl における Test::TCP または Ruby における Glint

Perl には Test::TCP というのがあって、テスト中、空いてるポートで何かしらのサーバーを起動して使うということができます。Ruby においては Glint というライブラリがあって、同じことができます。

node.js の場合、node-test-tcp というのがあって、node の net.Server で動くサーバに関しては簡単に同じことができます。が、memcached とか外部プロセスを起動させようとするとちょっと困るのと、done() を呼ばないと終了しないので、何かいい方法はないかなと思ったので書いてみました。

test-tcp だとカブるので glint のほうの名前を仮りています。

つかいかた

glint(
	function (port) {
		// ここは外部プロセスで実行される
		// ただし文字列化して関数が渡されるので外のスコープの変数は使えない。
		// node.js の exec, execFile はいわゆる exec ではないので1つプロセスが余分にできる。我慢するしかない。
		console.log('starting memcached with port: ' + port);
		require('child_process').execFile('memcached', ['-p', port]);
	},

	function (error, server) {
		if (error) throw error;

		// server は起動が確認済み
		// server.port でポート番号がとれる。
		// server.kill() でこのプロセスだけ殺せる

		console.log(server);
		var s = net.connect(server.port, function () {
			s.write("version\r\n");
		});
		s.on('data', function (data) {
			console.log(data.toString('UTF-8'));
			s.end();
		});

		// この関数を抜けても exit されるまで server は (明示的にkillしない限り) kill されない
	}
);

しくみ

他のモジュールとやってることは一緒なのですが、node.js だと面倒な点がいくつかあります

  • fork / exec はいわゆる *nix の fork/exec ではない
  • オブジェクトファイナライザ的な仕組みがない
    • 特定のオブジェクトが破棄されるタイミングで処理を行うことができない

node の fork / exec (execFile) は *nix の fork / exec とは全く違うので、細かいプロセスの制御ができません。特に exec 単体相当はないので、現在のプロセス自体を置き換えるということができません。そんなわけで1つ別プロセスを経由している関係で、無駄に1プロセスを消費しています。

オブジェクトのファイナライザがないので、node-glint では process.on('exit') で起動したサーバを終了しています。ただし、普通に外部プロセスを起動すると、そのプロセスの終了を待つ挙動になり、exit されません。が、spawn() のオプションに detach: true を指定した上で、unref() を呼んであげることで、外部プロセスの終了に関わらず起動元の node プロセスを exit させることができます。

まとめ

一応形にはなりましたが、細かい挙動の検証がめんどうなので npm にあげてません。特に現在の実装はシグナルまわりのハンドリングがいい加減です。node マスターの皆様におかれましては、よりよい方法をご教示頂ければと思う所存です。