2017年5月31日水曜日

妄想:作戦シミュレーションゲームとか


マイコン内蔵LEDスティック


 気分転換に、マイコン内蔵LEDスティックで遊んでみました。
 数百ピクセルとか1万ピクセルとかの電光掲示板で遊んだ後だと、16ピクセルなんて可愛いもんですね。

 例によってロジアナ画面を。

 

 データとしては、800kHzでデューティー比32% or 64%のパルス幅変調でデータを送ります。クロックは1.5MHzから600kHzあたりまで、かなり余裕があるようです。
 真面目にやるならタイマのPWM出力を使うとらくだと思います。STM32なら4本までパラレルで送れるので、60fpsで2000個くらい制御できそうです。複数のタイマを使えばさらに多くの表現も可能でしょうが、そこまでするなら2次元フルカラーモジュールを買うべきだと思います。
 例外としては空飛ぶ球体ディスプレイみたいなああいうのを作るときでしょうか。実際、映像を見る限りではLEDはこのモジュールに似た感じのものを使っているようです。1チップ(1色)に配線1本だと重すぎて飛べないでしょうから、シリアルバスのLEDを使っているはずです。

 今回はマイコンボードの関係で3.3Vの電源を使いましたが、秋月のページによると動作範囲は3.5-5.3Vの間です。LEDの順方向電圧が緑青は最大3.4Vなので、3.3Vだとちょっと足りない感じです。

 LEDチップ自体はRGB888で1677万色を表現できますが、おそらく人間の感度に合わせた補正は行っていないはずです。

2017年5月30日火曜日

STMでUARTのフロー制御




 STM32F4のUARTでHardFlowControlを試してみた。結論から言うと、「ハードウェアフロー制御」は事実上不可能っぽい。

 試したのはUSART3で受信したデータをQueueに送り、10msec毎にキューをチェックして、データが有れば1バイト取り出してUSART1から送信する、という挙動。USART3はPCからおよそ270バイトを連続して送信している。Queueは256バイトあり、Queueは10msec毎に1バイトを取り出すから、途中でバッファが一杯になる。

 最初、Queueが一杯になったらUARTの受信割り込みを停止する、という挙動を実装してみた。受信割り込みを止めれば新たなデータが来てもUSART.DRからデータが抜けないので、USARTがハードウェアでRTSを立ち上げる。
 しかし、テストで使ったUSB-TTL232アダプタはCTSの変化から実際に送信を止めるまでに数バイトを送信してしまい、マイコンがRTSを上げても次のデータが送られてしまった。

 今回は、キューの使用率が75%になったらソフトウェアでRTSを立ち上げ、キューの使用率が50%を下回ったら受信タスク内でRTSを立ち下げる、という挙動を実装してみた。
 一応、取りこぼし無くフロー制御ができているようだ。

 もしかしたら、オーバーランエラー割り込みとかを使えばこのあたりもうまく処理できるのかもしれない。


 ソフトウェアでバッファの使用率を測るにあたり、本来は キュー使用量 >= キューサイズ * 3 / 4 のような判定を行うのが良いはず(ISR内で計算を行う是非は置いておいて)。しかし、FreeRTOSのQueueはISR内でキュー使用量とキューサイズを取得することができないらしい。ということで、今回はISR・受信タスク共に値をべた書きしている。
 ちなみにcmsis_osでのラッパーでもISR内で使用量を得るような関数は用意していないようだ。
 cmsis_osのラッパーは単純にFreeRTOSの関数を再呼び出ししてるだけなので、他のOSに移植できるのか怪しい感じ。単純に再呼び出しするだけならマクロとかで実装してくれればいいのに、ちゃんと関数で実装してるからいちいち関数呼び出しのコストが発生する(はず)。
 マイコンでそんなに抽象化する必用あるのかねぇ。

HUB75

 秋月とかamazonとかスイッチなんちゃらで売ってる16x32とか32x32のLEDパネルのはなし。



 ArduinoとかRasPiだとライブラリがあるみたいなので、簡単に使いたいならそっちを使ってね。

***

 とりあえずロジアナのキャプチャ画像でも。




 上から、1行分、1フレーム分(1bit分)、1フレーム分(4bit分)のキャプチャ。色深度4bitでRGBなので、4096色の表現が可能。ただしコントラストが低いのでそんなに見分けられないと思う。
 1フレームを表示するのにおよそ8msecで、だいたい120fpsくらい出てる。液晶で言えば120fpsはかなり早い方だが、LEDパネルではコレが最小値。コレよりも小さいとパネルの駆動方式の影響でフリッカーが凄い。100fpsでなんかチカチカしてるなーという感じ。
 ちなみに50Hz地域では電球は100Hzで明滅してるので、電球の明滅が気になる人は100Hzが見えてる。僕は見えないが、寿命が近い蛍光灯とかは気になってくるので、デューティー比によっては100Hzは見えるみたい。


 データの転送方法は、クロックに同期したピクセルデータを送り、その後Blankで非表示にしてからラッチやアドレスの変更を行って、Blankを解除して表示する。
 アドレスは「アドレスに一致した行が表示される」という挙動なので、ラッチ時にはアドレスは評価されない。というかパネル1枚にレジスタがあって、アドレスで選択した行のシンクが有効になる、みたいな挙動なのかも。

 同期シリアルなのでSPIを使うのが一番楽だと思うが、RGB2セットで6本の同期シリアルが必用なので、一般的なマイコンではちょっとつらい。
 試作の時はGPIOにDMAとタイマで転送した。転送中はCPUリソースを他に使えるという利点が有ったが、結局転送データの生成に転送と同じくらいの時間が必用、DMAの遅れやTIMの組み合わせが面倒、ということで今はソフトウェアで転送している。

 STM32F405RGでも9kpxくらいの領域は余裕で表示できる。とはいえ動画の再生とかは難しいと思う。主にデータの読み込みの問題で。でも表示領域はせいぜい128x128px程度までなので、頑張ればできるかも?

 FPGAを使える人ならDVI-HUB75の変換を作ったほうが楽かもしれない。データソースの意味で。DVIで入力できるならPCで表示データを作れるし。

***

 前にディスカバリーで見た電光掲示板工場で使ってたのもHUB75を使ったタイプのパネルだった気がする。フラットケーブルに見覚えがある。おそらく球場とかについてるでっかい電光掲示板も同じようなもののはず。でも日本のでっかいやつだと三菱とかが作ってるから、独自バスかな? 三菱電機のWebページを見てみると、解像度は256x256から1024x768あたりまでらし(コントローラ増設で複数を並べることはできる)。
 256x256の静止画でいいならマイコン4個で制御できる。でもリアルタイムで映像を入力して、となるとマイコンじゃつらいかな。そうするとやはりFPGAとかになるんだろうか。

2017年5月28日日曜日

Shift-JISの使用範囲


 MS ゴシックで表示できるShift-JISの文字(上の画像は隙間を埋めるように移動しているので、正しい配置ではないことに注意)。

 誰か欲しがるかもしれないので、というかみらいのじぶんが使いたくなると思うので、Shift-JISで使用されている範囲を整数配列にしてみた。ジャグ配列だが、1つめが行数、2つ目がXの開始値、3つ目がXの終了値で、XY共に0-255の256個、YがMSBでXがLSB、という感じ。

 目視で確認してるので、間違ってたらごめんね。

 ちゃんと仕様とか調べれば出てくるんだろうなぁ。

 ほんとは文字列のテーブルにして検索できるようにしたかったけど力尽きた。そっちはどこかのサイトのシフトJISコード表でやってくださいorz


 最初の方に日本の元号の記号があるんだけど、明治・大正・昭和は並んでて、平成だけ飛んでるのが面白い。JISコードが最初に作られたのは昭和の時代で、その後に年号が変わってから平成が追加された、っぽい感じ。普通に考えると年号は数十年単位で変わっていくのだから、昭和の次に余裕を付けておいたほうが拡張性があるし、実際文字コードはスカスカなのでそうすることもできたはず。でもそうせずに、次の年号は別の場所に飛んでいる。年号が変わることを考えるとか恐れ多い!みたいな話があったんだろうか。
 ちなみに明治から昭和までの3個は規則増加だが、平成は明治の前にある。なので明治・大正・昭和の記号を文字列の最初につけて文字コードでソートした場合、明治の前に平成が来ることになる。せっかくなら昭和の後ろに追加すればよかったのに。
 さらに蛇足だが、平成の隣(前)は数個の空きがある。なので50-200年くらいは余裕がありそう。ただし明治から昭和がインクリメントなのに対し、平成以降はデクリメントで、ちょっと面倒っぽい。
 さらにさらに蛇足だが、Unicodeでは平成から明治までが連続している。ただし平成の隣に空きはないっぽい。

2017/05/29:修正
 0x7Fを例外で対応していたけど、うまく動かないことがあるらしいのでテーブルで対応。

文字コード沼

 マイコンでフォントを扱おうと思っていて、どうやるのが楽かなーって。
 既存のビットマップフォントを流用するのが一番楽なんだろうけど、ほとんどの文字はShift JIS(あるいはJIS)で、ソースコードをUTF-8に移行している身としてはいちいちUnicodeにして、更にShift JISにして、場合によってはそこから更にJISに変換して、という、マイコンで行うにはかなり面倒な処理が必要。
 ということで、Unicodeで一発で行けないかな、と思ってC#でUnicodeの一覧を出して、SJISの全角文字に含まれている文字は背景を赤に塗ってみた。


 傾向としては最初の方に記号やひらがなが有り、途中に漢字、最後の方に全角アルファベット、という感じらしい。日本の漢字の前には中国の漢字があり、日本語の後ろにはハングルがあるらしい(いわゆるCJKの並び)。
 漢字は21000文字くらいが収録されていて、1byte8pxのビットマップだと、656KiBが必要。他に記号やら色々あるので、700kB前後といったところか。
 STBee F4miniはFlashが1MBあるので、日本の漢字と記号だけなら全部収まりそう。とはいえ、プログラムに使う領域が無くなるのでは本末転倒なわけで。


 とりあえずSJISに含まれる文字をUnicodeの2バイトとビットマップの32バイトのテーブルにして、UnicodeでソートしてROMに格納、二分探索でフォントを探す、みたいな流れになるのかなぁ。でもSJISの文字をすべて持つならUnicodeからIndexに変換するテーブルも持ったほうが早いかも。これならUTF-8の文字列からUnicodeにデコードし、それをテーブルのIndexとして使い、BitmapテーブルのIndexを得る、みたいな流れ。これだと一番重い処理はUTF-8のデコードで、あとは簡単なポインタの演算で済みそう。ただしIndexテーブルを全部持つと128KiBで、J以外のCKを除けば64KiBくらいかな。結構でかい。が、1MiBのマイコンならよゆー。
 

 どうも今やってるヤツが8bitコンピュータとか16bitコンピュータのグラフィック周りの再発明らしくて、その頃の資料がほしいけど、30年近く前のマシンなのか。当然インターネットもないような時代なので、リアルタイムで試行錯誤してるブログやらがネットに漂ってるわけがない。インターネットにはインターネットが普及して以降の情報しか残らないのだッ。タイムマシンはタイムマシンが出来て以降の時代にしか戻れない、みたいな話(?)。

 STM32F4の性能だとファミコンからスーファミ、ゲームボーイあたりの計算能力は余裕で超えてるけど、LSIで高速化してるような部分も全部ソフトでやる必要があるし、ROMをソフトウェアエミュレーションするのも大変だろうから、FPGAのようなモドキを作るのは大変そう。
 秋月で売ってる単色のメモリ液晶でテトリスくらいなら余裕の処理能力だろうけど、それならSTBee Miniだって十分足りるだろうし。となるとPSP液晶か、という流れだけど、そこまで来るとF4でもメモリが足りない。4倍でスケーリングしてRGB8色かBW4色あたりならできるんだろうけど、それもなぁ。
 そっちの方もやってみたいけど、手持ちのPSP液晶、なんか逆接して壊したような記憶があるので、ジャンク覚悟であの配線量を作るのはちょっと嫌だなぁ。


/*
 はいふりOVA、何日か前に届いて見ました。良かった。良かった、くらいの感想しか出てこないほんわかした感じの話。コメンタリーも良かったよ。
 実在する風景がかなり出てきているようだけど、現地から一番遠い両極端の片側に住んでる身としては全然関係ないし。。

 はいふりのキャラでバトルシップをコミカライズした薄い本が読みたいなーと思う今日このごろ。映画のキャラの再配置ですべてできるわけではないけど、かなりいいとこいけそうなんだよね。NOAAのデータは情報好きのタブを使うとか、対物ライフルは砲術科に撃たせるとか。
 あとネイビーミッションっぽい感じでイージスシステムを指揮するゲームをやりたい。久しぶりにネイビーミッションをやったけど、航空機が出てくると見張員の報告がうるさくて状況認識が正常にできなくなる。でも戦闘指揮が確立する前はあんな感じななろうなぁ。
 戦略シミュレーションとかは考える範囲が広すぎて大変なので、戦術シミュレーションとか作戦シミュレーションみたいなカテゴリのゲームが出てこないかな。Arma3は作戦指揮ができるけど、でも自分で指揮してても結局AIを後方において自分が前に出てるし、そもそも作戦指揮もできてない可能性が。。
*/

2017年5月27日土曜日

妄想:パーツクリーナー缶サット

 北海道だと缶サットよりSPeC(Space ProvE Contest)と言うべきなんだけど。

 ふとパーツクリーナーを眺めてたら、これで缶サット作ったら面白そうだな、と思った。直径は350ml缶と同じで、長さが2.5倍くらいある。ということで体積(容積)も2.5倍。去年のSPeCレギュレーションでは全長が35cmまでなので、ちょうどパーツクリーナーが入る。レギュでは直径が15cmまでなので、約7cmの缶は2本まで入る。レギュがあと1cmか2cmほど大きければ3本入るのだが。

 パーツクリーナー缶だと、長さがあるので、一端にパラシュートなりストリーマーなりをつければ垂直に安定させやすそう。となると下端にカメラをつければ地上の撮影に有利かも。また細長い形状ではアンテナの設置にも有利。パーツクリーナー缶の大きさのダイポールアンテナだと430MHzあたりなので、アマチュア無線帯が使えるかな。クロスダイポールだと水平偏波の無指向性になる。充分に仰角が取れるなら円偏波にしてもいい。姿勢が安定してるので、円偏波アンテナは効くかも。

 細長い円筒をパラシュートで落とすとなると、見た目的にはソノブイっぽい。でもアレは海面以下が仕事場であって、SPeCとはちょっと違う。

 どちらかと言うと、Nulkaのほうが近いかも。こっちは垂直に飛び上がった筒が固体燃料である程度の時間浮遊しているらしい。となると、パーツクリーナー缶にも固体燃料なりコールドガスなりで減速とかしても面白いかも。モデルロケットとか並べれば浮遊もできるかもしれないけど、そこまでやると自分で飛び上がれよという話になる。
 大きさ的にはEDFが入りそうだし、容量もあるからLiPoとかも充分入るかも。となると展開翼を追加したいな。でもそうなるとまんまトマホークミサイルになってしまう。


 やはりパーツクリーナー缶は衛星軌道に入れるのが良いと思う。重力傾斜で地上を指向できるから、カメラに有利だし、円偏波のUHFアンテナを搭載できる。金属管なので紫外線等の弱いエネルギーはある程度遮蔽できそう。とりあえず大きな問題は電力収支が大変なことか。円筒の表面に貼れる耐放射線のソーラーパネル。HTVなんかも円筒形状に貼ってるけど、アレは直径がデカイので多角形に近似できる。でもパーツクリーナー缶だと四角形に近似する必要がありそう。となるとすでに円筒じゃないぞという。
 解決策としては、パドルで10x10x30cmの角型形状を作って、それを介して3Uキューブサットとして打ち上げ、放出後はパドルを展開して、みたいな感じ。


 ということでちょっと作ってみた。あぁ、こういうところでペンタブを使うべきなのか。。

 左側が展開前、右側が展開後。重力傾斜とかどういうめかにずむなのかわかってないのでてきとー。
 画像下側が地球側で、その方向にカメラが有り、アンテナやパドルもそのあたりに一塊になってる。
 缶の長さを35cmにしてしまったので3Uに収まらないけど、キニシナイ。
「打ち上げてくれるロケットがないって?ならロケットも作ればいいじゃないか!」
 この形状の利点って何があるかなーって考えると、あんまり思いつかないのだけど、長さを利用して焦点距離の長い光学系を積むとかどうだろうか。といっても口径は50mm程度だし、長いと言ってもそれほどでもないので、あんまり分解能は稼げなさそう。逆に空間が光学系に支配されるデメリットが大きいかも。

***

 去年のSPeCは技術交流会が8月初め、打ち上げが10月初めだったので、そのスケジュールで行くとするとあと2ヶ月ほどで技術交流会となる。そろそろレギュレーションとか確定しないとまずいんじゃね? どっかに出てるのかな。でも去年もWeb告知が出たのって技術交流会の直前だった気がするし、そういう時間感覚なのかな。

 そろそろ缶サット、もとい、SPeCもやってみたいけど、一人でネチネチ考えてても良いミッションが思いつかない。

2017年5月26日金曜日

sscanfのバグ?

 安易に「バグ」というと、「仕様かもしれないだろ!製作者に問い合わせしたのか!?」と突っ込まれたりするらしいので、「謎の挙動」あたりにしておこうかと思いますが。

 char str[] = "hoge 1 2 3"という文字列が有った時に、int i, x, y; uint8_t z;という変数があり、i = sscanf(str + 5, "%d %d %hhu", &x, &y, &z);とした場合、i, x, y, zがそれぞれ3, 0, 2, 3となるとてもふしぎな現象がarm-none-eabi-gccで発生しました。詳細なバージョンは覚えてませんが、4系と5系で発生しています。

 ちなみに、int i, x, y, z;で、フォーマットが"%d %d %d"の場合は問題なく3, 1, 2, 3という結果になります。
 さらに蛇足ですが、一旦"%d %d %d"で変換した場合は、uint8_tを含む"%d %d %hhu"でも問題なく変換できるようです。
 sscanfの実装は見たことがありませんが、なんとなく静的変数の初期値の問題っぽい気がします。一番有り得そうなのは僕が書き換えたリンカスクリプトかなーという気もしますが。

 まぁ、一番手っ取り早い方法は全部intで受け取ることかな、と思います。いちいちビット幅とか気にしないでいいですし、どうせスタックから取ってすぐ開放するんですからメモリ使用量とかも気にしないで(ゲフンゲフン


 どうでもいいですが、「sscanf バグ」でググると、scanfはバッファオーバーランを防げないから使うな、みたいな泥仕合が展開されているようです。
 個人的にはwikipediaに書いてある方法で変数に読み込みつつ、あとでsscanfでパース、というのが楽でいいかなと思います。そんなこと言い始めるとセキュリティ云々とか悪意のあるものが云々とかいろいろ噴出するんでしょうけども。。。

 printfやscanfのフォーマットは、表示するフォーマットと、使用する変数を別の部分で管理できるので、楽だと思っています。C#のConsole.Writeのような方法では変数とフォーマットが複雑に入り混じって面倒です。でもprintfだとどの変数がどこに入って、というのを考える必要があるし、後続の言語でprintfやscanfのようなフォーマットがマイナーになってるからには万人から支持されている方法ではないんだろうなぁとも思います。


 ということで、「よくわからないなぞのきょどう」の話でした(ばぐじゃないよっ!

2017年5月25日木曜日

待ち時間をタイマで生成


 MMCの転送待ちに、タイマでタイミング生成を併用してみました。
 CMD17でシングルブロックリードを開始すると、カードが実際にデータを送ってくるまでにはある程度の待ち時間があるわけですが、これが結構長いので、単純にソフトウェアループを行うとちょっともったいないです。ということでTIMとセマフォを使って数百マイクロ秒のディレイを行い、その間はOSにリソースを返すようにしました。ディレイ中はIdleHookでトグルしているピンが動いているのを確認しているので、予想通りに動いているようです。

 ま、このカードの場合はディレイが1msecを超えてるのでOSに待たせても良いんですけどねorz

 今回は250usのディレイですが、ISRやらセマフォやらタスク切り替えやらで15usほどかかるようです。それでも他にリソースが渡っている時間のほうが長いと思うので、たぶん効果はあると思います。そんなキチキチのプログラムを作ってるのか、という問題はさておき。

 今回はTIM7を使いました。TIM7(と6)はOC/ICが搭載されておらず、トリガの接続も極めて限定的です。実質的に、TIM6/7はタイマ割り込みでソフトウェアのタイミングを作るか、DACの変換トリガに使うか、の2種類しか用途がありません。DACは今のところ使う予定がありませんし、他のTIMにも接続されているのでイザとなればそちらを使えます。ということで7を使いました。ちなみに6は似たような理由で他のソフトウェアタイミング生成に使用済みです。

 STM32のタイマは痒いところに手が届かない感じですが、それでもSTBee F4miniに乗ってる405RGではタイマが14個もありますから、かなり大胆に使えると思います。
 ただし、一部のタイマを除いて、ほとんどはアップカウントしかできない点に注意が必要です。今回の場合はタイマを0xFFFFで初期化しておき、TIMx->CNT = 0xFFFF - 待ち時間 として設定しました(なお、プリスケーラはマイコンの動作周波数[MHz]に設定してあるので、1クロック1usecです)。

2017年5月24日水曜日

妄想:Kindle OH!

 こういうでゔぁいすがほしいなー、という妄想。

 A4サイズの電子ペーパーが100枚(One Hundred page)重なった電子ペーパーデバイス。内蔵電池は無しで、スタンドアロンでの書き換えはできない。USBでPCに接続するとプリンタとして認識され、最初に印刷した100ページ分が表示される。
 オプションでグリップを追加でき、グリップにはLED照明アームがついていて暗いところでも読めるようになる。また、無線LANを内蔵していて、スマートフォンからの印刷が可能。もちろんインターネット接続がある無線LANならamaz○nで買った本を読むことも可能。表示の変更が終わればグリップを外しても表示は持続。
 内蔵ストレージorSDカードでいくつかの文書を持ち歩く、というのもできそう。グリップにはボタンが幾つかついていて、そのボタンで文書を選択するとか。
 設計次第では、複数のKin○le OHをバインダークリップで組み合わせて200ページ、300ページ、といったページ数も可能だと思う。とはいえだいぶ大きい(&重い)モノになるはずなので、複数個組み合わせるよりは個別で読みたいページを含む端末を見るほうが楽そう。

 今の電子リーダーはシーケンシャルリードには便利だけど、ランダムリードがかなりつらい。ということでこういうデバイスが欲しいなぁと思う次第。
 とはいえ、いくら位になるのか。単純計算でKindle PWの倍の面積が100枚とすると300万円くらいか。使用する電子ペーパーが100倍だとしても、売れる量が100分の1なら量産効果は出ない。100分の1も売れるはずがないから、実際の材料単価は上がるはず。使用する電子機器が100分の1になったとしても、あんまり変わらない気がする。
 20万円くらいなら、大量の紙を消費している界隈には売れるかも?10万円くらいなら個人で買える人も多そう。5万円くらいならだいぶ便利だと思う。
 グリップ付きで10万円くらいだと、内蔵ストレージにマンガを2000冊くらい入れればKindleと紙の差分でペイできるかも。「マンガなんてそんな何回も読まねーよ」という人もいるかもしれないが、ちょっとした移動時間に2000冊の中から自由に読んでいいよ、となると読みたくなる人もいるかもよ?今までの紙だと本棚にしまった後はわざわざ取り出して読むのは面倒かもしれないが、常に手元にあるならその面倒はなくなるわけで。

 基本的にページ移動は電子ペーパーをめくることで行うけど、電子ペーパーの隅1箇所にタッチセンサを付けておけば、100冊の表紙を表示して、ざーっと見ていって、読みたい本があればそのページをタッチして選択、10秒位待てばその本が読めるようになる、といったことも可能になる。でもどれくらい便利なのかはやってみないとわからないなぁ。
 タッチセンサが1ページ6分割くらいできるなら、A4のページに6冊分くらいのサムネイルを表示して600冊の表紙を見れる。10分割なら1000冊、20分割なら2000冊で、画面切り替えの待ち時間なしに内蔵された本の表紙をすべて見れる。20分割は小さいと思うけど、Kindle PWのサムネイルも似たような大きさだと思う。


 こういうでゔぁいす、amazonから発売されないかなー。

2017年5月22日月曜日

インデックスカラー

 C#でBitmapをインデックスカラーに変換するのは、Bitmap.Clone(Rectangle, PixelFormat)で、Arg2にFormat8bppIndexedとかを指定すればいい。他にも、4bppや2bpp、1bppも指定できる。ちなみに1bppは白黒の2値画像となる(ネタバレ)。

 Bitmap.CloneでIndexedに変換した場合、以下のカラーパレットが使われる。
たぶん固定値で、変化はしないはず。実際に使われているのは16x14で224色となる。

 Bitmap.Paletteを書き換えればIndexに対するColorを変更することができるが、もちろんIndexとPaletteの関係は変化しないから、単純に色が変わるだけとなる。
 ちらっと試した限りでは自前のPaletteで減色することはできないらしい。そもそも、自分でPaletteを用意できるなら、実際の減色まですべて実装すべき、ということなのだろう。差の評価や拡散によっても再現度はかなり変わるから、自前で作れというのはもっともだと思う。

 それと、帯域が制限されてる回線で画像データを送りたいので、8bppにしてから簡単なランレングスで圧縮してみた。アニメのワンシーンを評価に使うと、画面が一色のときで2%程度、普段が40%前後、状況によって70%くらいの容量となった(ただ簡単にエンコードを書いただけで、デコードも試してないので正しくエンコードされているか不明)。
 減色のアルゴリズムはいくつか有って、グラデーションは閾値を超えるまで同じ色を続けるタイプや、複数の色を並べて見た目上の色をグラデーションさせたりという違いが有る。C#では前者を使っているが、ランレングスでは前者のほうが相性がいい。後者だとグラデーションでは頻繁に値が変化するので、もっと効率のいい圧縮方法を使う必要がある。

 入力画像毎にパレットを生成しなおせば、多少は再現度の高い圧縮が可能なはずだが、1つのパレットを使い続けていれば、最初に1回だけパレットを転送すればいいという利点がある。8bppのパレットを素直に転送すると768バイトになるが、100px四方の8bppは10kB程度で、圧縮して60%くらいまで減らせば6kBになる。そうするとパレットデータが1割くらいを占めるので、かなりデカい。

 そもそもPNGを使えよとか、JPEGを使えよ、という話もあるだろうけど、転送先がワンチップマイコンだったりすると、いちいち展開するのが面倒。今回は相手の処理の都合でインデックスカラーが欲しかったので、JPEGとかで帯域を節約するよりも、減色処理のほうが負荷が高そうということで、8bppBMPを転送することにした。


 そういえば、WinXPとかのペイントで8bppで保存するとかなり劣化したけど、Win7あたりからかなり改善したよなーと思って、Win10のペイントで保存してみたら、かなり劣化した。あれれぇ~~、おかしいなぁ~~。

***

 気がついたらもうこんな時間。ここ2週間くらいはかなり早く寝てたんだけど、急に位相ロックが外れた。夜は涼しくて良いねぇ。静かだし。虫やカエルがうるさいけど。

2017年5月21日日曜日

フォームの一部を透過して、背景をキャプチャする

 タイトルのようなことをやりたかったので、やってみました。



 静止画だとわかりづらいですが、左の赤枠の中が透過になっており、スクリーンのその領域を拡大して右に表示しています。簡易的なスクリーン拡大鏡のような動作です。

 スクリーンの一部を透過にするには、FormのTransparencyKeyに適当なColorを設定し、透過させたいコントロールのBackColorにTransparencyKeyを指定すれば、その部分は透過になります。
 適当な色というのはなんでも良いのですが、Form上のその色の部分はすべて透過になってしまうので、あまり使われない色を指定する必要があります。透過するとどんな色が設定されるかは背景次第ですが、単純計算では1677万分の1の確率で透過が発生します。確率的には大したことないでしょうけども、例えば#FFFFFFや#000000といった、ありふれた色を設定するとよろしくありません。ということで今回は#FFFFFEを指定しました。#FEFEFEとかでも良いのですが、RGBが同じ輝度というのはグレイスケール画像が後ろにある際に256分の1の確率で発生する可能性が高いので、すべて同じ輝度は避けたほうが良いと思います。

 画面をキャプチャするのも、いろいろな方法があるようですが、いくつか試した限りではうまくいくものは1個しかありませんでした。というか何個か試した内でうまく動いたところでそれを採用したので、探せば何個も有るんでしょうが。
 とりあえず、BitBltを使った方法でうまく動いてます。以下のページを参考にしました。
 画面をキャプチャする: .NET Tips: C#, VB.NET
 サンプルコードをちょっと書き換えて、引数でキャプチャする領域を指定するようにしています。

 TransparencyKeyで透過した領域は、マウスも透過して扱われます。なので、スクリーン拡大鏡の中でマウスをクリックすれば、透過先のプログラムにクリックが発生します。ただ、クリックした際にそのWindowがアクティブになるので、拡大鏡が隠れてしまいます。そのような動作をされたくない場合は、常に手前に表示するようにしてやる必要があります。


2017年5月19日金曜日

細々

 怒涛の更新ラッシュから一転、しばらく(といっても数日)、更新をサボっていました。その間、ジンバルとかSTTは休んでいましたが、F4で遊ぶのは続けていました。

 F4はペリフェラルの使い方がF1とほとんど同じなので、初めて使ったマイコンファミリとは思えないほど簡単に使えます。ファミリが違うというか、FPUが追加されて動作クロックが2倍ちょっとになったシリーズ品、みたいな印象。

 今回、久しぶりにSDカードを使いました。といってもSPIで初期化するところから作って、でも時間がないので本当に最低限しか実装していないわけですが。今のところ大容量(といっても10KiB前後)のデータを読み込みたいだけなので、FatFsはリードオンリー構成です。速度もそんなに必要ないので、シングルブロックリードしか作っていません。それでも、CubeでDMAの初期化を生成して、20MHzで流してるので今回の用途では十分ですが。いちいち初期化コードを書かなくても書いてくれるのは結構便利です。

 SDカードは結構待ち時間が多くて、今使ってるSDカードではCMD17からData Tokenまで280usくらいあります。人間からすると極めて短時間ですが、168MHzのマイコンだと50k命令くらい実行できます。この時間をポーリングで浪費するのはもったいない。でもFreeRTOSに処理を投げるとmax1msecかかるので処理が大幅に遅くなる、という問題をどうにかできないかな、と考えています。

 真っ先に思いつくのは、タイマをOne Shotにし、プリスケーラを168-1とかに設定しておき、例えば200マイクロ秒待ちたいなら、タイマを200に設定して開始、タスクはセマフォで止めておく。200マイクロ秒くらい経ったらISRが呼ばれて、セマフォをGiveする。みたいにすれば、だいたい数マイクロ秒の分解能で65msecくらいまでディレイできます。50msec以上待ちたいならOSのdelayで十分でしょうから、充分に使えるはずです。
 と、想像するのは簡単ですが、実際に動くのかどうか。
 いくつか問題が有ると思いますが、一番大きいのは同時に1個のタスクしか止められない、ということでしょうか。ディレイを行うためにmutexを使う。すごく本末転倒な感じ。
 1つのマイコンで作れる規模では、タイミングクリティカルなタスクはそれほど多くないはずで、幸いSTM32F405RGにはタイマが14個載っていますから、タイマをガンガン使っていく、というのでも良いのですが。


 頭の中がごちゃごちゃしてても、ブログに書こうとするとだいぶスッキリしてきます。テディベアデバッグってかなり有効だと思います。ほんとにテディベア買おうかな。でもぶるーとぅーすでくらっきんぐされたら怖いのでやめとこ。サメのぬいぐるみでも買おうか。良い歳した男がぬいぐるみを抱いて悩んでる姿というのもかなりアレなので、やはりラバーダックあたりがちょうど良いのかもしれません。あとこれからの時期ぬいぐるみじゃ暑苦しいでしょうし。あ、ALMDSの抱きまくらとかどうかな?戦車砲の抱きまくらが有るんだからALMDSの抱きまくらが有っても良さそうです。大きさもちょうどいいでしょうし、機雷が敷設されてる海域に迷い込んでも良いひらめきを与えてくれるかもしれませんよっ!あれ、一周して戻ってきちゃった。


 明日は朝が早いので、今日中に準備しておかないと。とりあえずデジカメの充電と、SDカードの準備。あと持っていく荷物の確認。今回はいつにもまして荷物が多いので辛そうです。駅からの2kmくらいはダンボール抱えて歩くことになりそうです。ディスカバリーかナショジオでそういう映像を見たことがあります。たしかナイトストーカーズの入隊試験だったと思いますが。自家用MH-6とかほしいなぁ。それかトリノホシのモーターグライダー。

2017年5月15日月曜日

俺の画像フォルダが火を噴くぜ!


 マイコンで画像を扱ってみたかったので、とりあえず1ピクセルあたり何ビット必用なのかを確かめようと、任意のビット数で画像を表示するアプリを作ってみた。C#だと簡単に作れて便利。この規模ならヘタすると探すより作ったほうが早い。ネット回線がアホみたいに遅い田舎だと特に。
 左側は変換後の画像を表示し、右側には変換後の画像と元の画像を並べて表示している。
 画像の変換には単純な切り捨てを使用している。たぶんマイコンだと下位ビットで四捨五入とかしてる余裕ないだろうなーと思ったので。

 1byte/pxだとRGB242になるけど、さすがに劣化が多い。
 2byte/pxのRGB565だと、比較画面で領域を動かしながらちゃんと見比べないとわからない程度の劣化。劣化と言うか、切り捨てのために輝度が下がってるので、明暗で違いがわかりやすい。うまいアルゴリズムで端折るとかなり優秀かも。
 1.5byte/pxのRGB444だと、さすがに等倍で見れば劣化が目立つ。あと1.5バイトだと3byte/2pxとかで扱うんだろうけどワードアライメント的につらそう。でもuint8_t[3n]の配列ならアライメントとか気にしなくていいかな?

 マイコンの処理内容によっては、IndexedColorのほうが良いかも。1ピクセル1バイトで256色のカラーパレットでも意外とちゃんと見えたりするし。8bitIndexedビットマップなら読み込みは単純にファイルリードで読めそうだし。


 色変換だと画像の内容やグラデーション具合でだいぶ感想が変わるはずなのだけど、どういう画像を使えば良いんだろうか。実際に使う画像があればソレで確認するのが一番だろうけど、そもそもどんな画像を写すかも全く決めてないので。。。

妄想:ハンリー

 学園祭1週間前、横須賀女子海洋学校のとある部室ではHLハンリーの制作が佳境に入っていた…  みたいな薄い本ください。

2017年5月14日日曜日

ペンタブ


 8年くらい前に買ったペンタブ、全然使ってなかったり、一時期知人に貸してたりで、ほとんど使った思い出がない。貸した人はかなり使い込んで色々描くようになったので、僕が買ったものの中ではずば抜けて費用対効果が高かったけど、探しものをしてたらたまたま出てきたので、ドライバとか入れて使ってみた。
 ちゃんとWin10でも動作したが、メインで使ってるPaint.Netとは相性が悪いらしい。以前のバージョンで筆圧機能が削除されたりとか、あんまりペンタブは重視してないのかも。設定の問題かもしれないが、破線を書けないというのがつらいので、P.N以外を使う。
 とりあえず、Windowsのペイントを使ってみた。
 少しくらい絵がかけないとコンセプトとか残したりもできないし、書ければ便利だろうと思って、とりあえず机の上にあるものを眺めながら書いてみた。

 左上から時計回りにホイッスル、水準器、マスキングテープ。水準器はクリアのアクリルブロックなので、屈折するとちょっと不思議な感じ。
 まっすぐ線を引くのがとても難しい。円も言わずもがな。

 ちょっとした事だとA3のホワイトボードに書いてみたりしてるが、ペンタブはまた全然違う感覚。慣れないとどこで接触するのかが全くわからない。ペンタブはオープンループ、物理ペンはクローズドループ。オープンループは学習に期待するしか無い。
 液タブだとクローズドループだけど、ペンタブに慣れると手が邪魔で面倒、みたいな噂を見たことが有る。そういえばサブディスプレイにしてる液晶は10ポイントマルチタッチだけど、腕を伸ばすのが面倒で全然使ってないな。

 ホワイトボードでごちゃごちゃ書いてると、考えてもないところに線を書いてしまってCtrl-Zを押したくなるときが多々あるので、ペンタブももうちょっと使い込んでみようっと。

Cubeのコード生成がアホすぎてつらい

 今日ハマった事。
 Cubeが吐くHAL初期化コードはいくつかの種類があるが、ペリフェラルの初期化を行う際はグローバル変数を使用している。
 一方、クロックの初期化(SystemClock_Config関数)はローカル変数を使用して、パラメータを設定後に初期化関数を呼び出す。この際、構造体のすべてのメンバを使用するわけではないので、Cubeは必用なメンバのみを設定する。が、本来は必用なメンバまでも設定しないで初期化関数に渡すことが有る。
 どうなるかと言えば、ローカル変数は初期値が不定で、不定な設定のまま初期化するわけだから、正常に初期化されない場合がある。場合がある、というのが面倒で、例えば完全に電源を落としてメモリを初期化すると、また新たな不定値が設定されて、運が良ければ正常に初期化できたようにみえる。

 普通、StdPeriphLibとか、HALもそうだけど、USE_FULL_ASSERTを定義した上で適切にassert_failed関数を作っておけば、StdPeriphLib、あるいはHALの関数内で異常値を検出してメッセージを出すことができる。が、今回は新しく作ったプロジェクトのため、まだassert_failedの中身を作っていなかった。なので気がつくまで時間がかかった。

 クロックの初期化でコケると、UARTも正常に動作しない(そもそもUART初期化前にコケる)ので、どこにメッセージを出すかが問題。
 とりあえず、char *p = (char *)0x20000000でメモリの先頭のポインタを作って、そこにsprintfでメッセージを保存することにした。assert_filedが呼ばれたらそこで無限ループに入れるようにしたので、メモリを破壊してもかまわない。メモリの中に入ったままでは読み出すことができないが、とりあえずST-Link(Nucleoについてたやつ)をSWDで接続して、メモリ先頭の数百バイトを表示すれば読むことができる。


 なんか様々な不具合をすべてCube/HALに丸投げしたくなってきた。でもHALのほとんどはグローバル変数だから、未初期化はあんまり問題にならないんだよなぁ。グローバル変数でメモリを大量に消費する vs 未初期化問題が起こりづらいグローバル変数。

***

 小ネタ。
STBee F4miniの大きさだとロジアナのピンヘッダに直接挿せる。
 周辺回路が一切使えないけど、ソースコード中にGPIOをトグルするコードを追加してどこまでコードが進んでるかを確認するのに便利。ちゃんとデバッガを整えてやればこんなことしなくても良いんだろうけどなぁ。
 でもピンヘッダ直差しの恩恵を十分に受けるには32chのモデルが必要になる。16chだとピンヘッダの片側しか読めない。

 ロジアナはいちいちジャンパワイヤを接続するのが非常に面倒なので、基板を発注するレベルで大規模な物を作る時は、ロジアナのコネクタを直結できるデバッグコネクタを付けておけば楽かなぁ、とか思ったり。こんな大きさのコネクタを付けれるってどんなデカい基板になるのか知らんが。

STBee F4miniピンアサイン


 STM32F1ではRemapという機能で、機能グループごと(USARTならTXとRXのセット、SPIならSCK,MISO,MOSIのセット、みたいな)でピン配置を変更することができたが、STM32F4ではさらに柔軟になり、1ピン毎に機能割当が変更できる。
 が、Cubeではそのあたりが面倒で、どのピンに割り当てるかは自分でデータシートからピンアサインを拾ってこなきゃいけない。ということで主要な(僕が主に使いたい機能を)表にしてみた。

 ADCは最初の数字がどのマルチプレクサポートか、次の数字はどのADCで利用できるかを示している。例えば3_123はADC入力3に接続されており、ADC1, ADC2, ADC3のいずれからも利用することができる。8_12はADC入力8に接続されているが、ADC3からは使用できない。
 TIMは1-5と8を個別に表示しており、9-13はひとまとめに表示してある。6,7はGPIO出力がない(NVICでソフトウェアタイミング生成専用?)。
 USARTは1,2,3と、4,5,6を分けている。
 SPIはすべてを個別に、I2CとCANはすべてをまとめて表示している。

***

 STBee F4miniではこのピンアサインで使用できる。ただし、PA0はタクトスイッチへ、PD2はLEDへ、PA11,12はUSBへ接続されており、特にUSBは不用意に操作するとウザいことになるので注意。またPA13-15, PB3-4はJTAGポートへ引き回されており、JTAGデバッグを使う場合は注意が必要。
 PA11,12はUSART1のハードウェアフロー制御が割り当てられているが、これは再配置ができないので、HFCを使いたい場合はUSART1を避けた方がいい。PA13,14はペリフェラルの割当がないので、積極的に使うことはないだろうが、いざという時までは使用しないほうが無難。GPIOで使う場合も可能な限りLEDなどの軽い不可にとどめておけば、いざという時にシリアルワイヤでバッグとかが使える。

 せっかくF4ボードを入手したので、また缶サットでも作ってみたい。でも前に作ったやつから大して変化のないものになってしまいそう。4年前から進歩なしってどうよ。。。
 パラフォイルで誘導とかしても面白そうだけど、模型用のパラフォイルはなかなか無いので自分で作る必要があるが、一人でハードもソフトも全部となると流石に荷が重い。ではソリッドなモノならDMMに発注できるから楽だ、ということになるが、結構な値段になりそうだし、そもそも可変翼型の缶サットを作ってしまうと、そこにブラシレスモータを1個のせれば自分で飛び立てるから、モデルロケットから投下する理由がなくなってしまう、というジレンマ。
 ラジコン飛行機とかやりたいなぁ。PWMじゃなくて、SPIとかUARTで操作量とかが出てくるプロポシステムって無いんだろうか。XBeeで作ったほうが早いかな?

2017年5月13日土曜日

F4Cube

 STBee F4miniのコードをCubeで生成していろいろ遊んでる。とりあえずFreeRTOSでUARTが動くところまでは作れた。

 いろいろとつまずいてるのだけど、とりあえずあとから来る人に「ここに石があるかも!」みたいな感じで書いておきます。

 FreeRTOSをビルドしようとして機械語関係っぽいエラーが出た場合はFPU周りのGCCオプションを要確認。-mfloat-abi=hard -mfpu=fpv4-sp-d16あたりが必用になる。うっかり忘れててかなり悩んだ。FPUを使わなくてもソフトで浮動小数点演算ができるので、簡単にprintfで浮動小数点を表示するくらいじゃ気が付かない。
 ちなみに、FPUを使った際のベンチマークがF4デジタルオーディオプレーヤーのページにあるので、比較してみても良いかも。正常にFPUが動作していれば168MHzで4秒、ソフトだと単精度で30秒ちょっと、倍精度だとさらにかかる(倍精度はすべてソフトで計算するので時間がかかる)。

 HALはかなり抽象化されているが、行き過ぎな気もする。例えばRTOSの機能を使う場合、FreeRTOSの関数を呼び出す必用はなく、Cubeが提供するラッパーを呼べばいい。これなら、FreeRTOS以外のRTOSを使う場合でも、ラッパーを交換するだけで動く。
 しかし、ラッパーを経由しているので、単純な関数(あるいはマクロ展開)を呼ぶ場合でも、複数の関数呼び出しが発生する。パフォーマンスを優先する部分はFreeRTOSの関数を直接呼び出すと楽。
 またSTM32のハードウェアアクセスもHAL経由では冗長な場合がある。そういう場合はstm32f4xx_ll_hoge.hをインクルードして、LL_hoge_hugaのような関数を使うと、レジスタを直接操作できる。やってることはStdPeriphLibと同じだが、命名規則とか関数の取り方は違うので注意。LLは単純な機能の場合、インライン展開されるので、StdPeriphLibより高パフォーマンスを期待できる。

 割り込みハンドラ内でフラグチェックを行う場合、チェックする順番が重要な場合がある。例えばレジスタの読み出しでクリアされるフラグが有ったりする。リファレンスマニュアルを参照のこと。
 他にも、LLでUSARTのフラグチェックを行う場合には、TXEより先にRXNEのチェックが必用だった。TXEをチェックした後にRXNEをチェックするとハングアップした。RMを読んだ限りでは特に注意が必要な感じはしなかったが、いよいよもってバグの原因がわからない時は、プログラムの順番を変えてみるのも試す価値はある。

 HALやCubeに限らないが、FreeRTOSでスタックが足りないと厄介な動作不良を引き起こす。例えばprintfはスタックを多く使うので、特に注意が必要。
 メモリ管理が厳密ではない環境では、スタックオーバーフローが即ハングアップになるとは限らない。いろいろ試して、「このハングアップは何か法則性がありそうだぞ?」と思っても、実は何の法則性もなく、単純にスタック不足だったということはよくある。
 試作段階では可能な限り多くのスタックを割り当てるべき。ある程度機能が出来上がってきたところで、必要以上の割当があれば割当を減らす。


 今のところは、これくらいか。まだまだいろいろ有るんだろうけど。

2017年5月12日金曜日

みに

 遅ればせながら、やっと、ようやく、この間、STBee F4miniを買った。

 で、買ってからもジンバルとかスタートラッカとかいろいろやってたので放置してたのだけど、気分転換にF4で遊んでみた。が、泥沼の予感。

 Cubeで生成したコードを使っているが、HSEを使おうとするとハングアップする。
 これはクロックの初期化で、HSEを使う場合はHSIを使わないため、HSIを停止するわけだが、HSIを止めるのはハードウェアで行われる。一方、HSIの後にHSEを初期化するから、HSIを初期化している時点ではクロックはHSIから供給されている。HSIの初期化は、HSIが一定時間以内に停止しない場合はエラーを出してハングアップするような作りになっているので、どうやったって初期化(停止)に成功するわけがない。
 自動生成コードを書き換えてHSIの初期化をスキップすれば、うまく行けばHSEを初期化できる。
 うまく行けば、電源投入からしばらく時間を置いて、クロックの初期化が終了して、プログラムが動き始める。リセットボタンを押せばすぐにリセットされるが、一端電源が切られると再び初期化に時間を要する。

 クロック周りは、HSEを使おうとすると出てくるので、HSIのみで動作させれば全く問題ない。もちろん、PLLのソースにHSIを指定しても問題ない。
 ということで、タイミング精度が重要でないならHSIを使うべきかなーという感じ。せっかく水晶乗ってるのに使えないってのも腑に落ちないけど。

 HALも出てきてからもう何年も経ってるけど、まだうまく動かないのかなぁ。

 STBeeファミリに限って言えば、F4miniの魅力は中間的な価格でCPUが早く、RAM/ROMが多い、という点。逆に、それが必要ないならmini(F1)で良く、速度や価格よりもポート数が欲しいならSTBeeを選択する必要がある。
 F4miniは比較的小型・安価・高速・大容量で、結構バランスが取れたタイプだと思うので、しっかりとハマれば便利だと思うのだが。。
 F4miniにNETMFWが乗ってれば最強なんだろうなぁ、みたいな妄想。でもStdPeriphLib突っ込んだほうが早そう。


*追記
 泥沼から抜け出そうともがいてて忘れていましたが、F4miniにはホビーユーザーからすると微妙な点がいくつかあります。代表的なのは 1) LDOの上流に給電できない 2) BOOTセレクタスイッチが無い の2点でしょうか。
 1については、STBeeやMiniにはGNDと3.3Vの他に、5Vの端子が存在していました。この5VはLDOのINと接続されており、ここに外部電源を接続すれば、マイコンの3.3Vが生成されました(注)。しかし、F4miniは5V端子が無く、外部から給電する際は自前で3.3Vレギュを用意する必要があります。もちろんSTM32F4の動作電圧範囲であれば非安定化電源を直結しても良いわけですが、外部にセンサなどを付ける場合は結局自分で安定化電源を用意する必要があります。気軽に使える電源としてはUSBと同様の5Vがデファクトスタンダードですから、3.3Vマイコンは自前で降圧する必要があります。
 2についても、STBeeやMiniではユーザースイッチを押しながらリセットをかけることでブートローダを起動することができました。しかし、F4miniではユーザースイッチとブートモード切り替えは切り離されており、STM32F4に搭載されたUSB DFUを起動するには何らかの操作が必要になります(ストリナ推奨の方法はジャンパピンの切り替えですが、開発段階でいちいち切り替えるのも面倒でしょう)。僕は、ユーザースイッチからBOOT0端子へジャンパを飛ばすことで対応しています。

注:説明書の指示通りに使用している場合は、STBee、STBee Miniの5Vに外部から電源を供給するとPCに逆流する可能性があります。STBeeの場合はポリスイッチを除去する、ポリスイッチをコネクタで着脱できるようにする、Miniの場合はチップポリスイッチを除去するといった事が必要になります。

 他にも、細かいところでは固定用のネジがインチピッチじゃないといった点がありますが、これについてはユニ基板にピンソケットで結合している限りでは問題ないかな、と思います。
 ユーザースイッチやリセットスイッチを回路から分離できないというのもありますが、これはMiniも同様ですし、この仕様が受け入れられないというのはかなり狭い分野だと思うので。
 まぁ、全体的に見ればF4miniはいいボードだと思います。


*追記
 まだUARTも満足に実装してないのに、CubeでFreeRTOSのコードを出してみました。F1で苦労してたのが嘘みたいに、簡単に動いてしまいました。うーぬ、楽だ。。。
 やっぱりクロックは不安定なままですが、HSIでも立ち上がりが遅い時があるので、もしかしたらクロックとは違うところでも何か問題が有るのかもしれません。ちゃんとマニュアル読んでみようかなぁ(おいこら。
 とりあえずRTOSが動くと、協調的マルチタスクみたいな苦労が必要ないので、メモリとかに気をつけてればいろいろと楽ができます。数年前に缶サットを作ったときはセンサから100Hzで読み込んだり、JPEGカメラで写真を撮ったり、ソーラーパネルとLEDでLチカやったり、ぜんぶSDカードにログったり、というのを自前の協調的マルチタスクで作ってましたが、あんな苦労はもういらないんだ…ッ! あれはSTBeeでしたから、F4miniはクロックが2.3倍、Flashが2倍、RAMが3倍、という感じでしょうか。OSのデメリットを補ってなお余る感じがします。でもF4miniはGPIOが少ないので、缶サットにはちょっと厳しいかも。STBeeサイズ(フルサイズ?)で100ピンパッケージを載せたSTBee F4が待たれますねッ! やろうと思えばSTBeeからチップを外して、電源周りを変更して、F4のQFP100を載せて、ということも可能なはずですが、さすがに僕に0.5mmピッチのパターン修正は無理ゲー。。。F1/F4で共用できる、チップ未実装のフルサイズボードとかあれば…? F1のUSB DFUはいろいろ付加回路が必用っぽいので難しいかも。

2017年5月11日木曜日

半自動スタートラッカ4.3


 初期値を与えずにスキャンしてみようと、ループを回したりしています。
 かなりスカスカにして、画像から5個、カタログから50個を使ってマッチングを試すと、0°から画面中心の赤経190°あたりまで1.6秒ほどかかります。今回は赤緯に初期値を与えていますが、これがない場合は赤経1周で3秒、赤緯も動かして20回ほどスキャンするので、全天を走査するのに1分ほどかかります。大抵の場合は途中でマッチングできるでしょうが、ワースト1minは長すぎるんじゃないかな。。。
 「ほとんどの宇宙機は画像をダウンリンクして地上で解析する」とか「まず粗太陽センサでだいたいの姿勢を調べてからSTTで詳細な姿勢を調べる」ってのは、さもありなんという感じです。
 キューブサットのような、6面体ですべての面にソーラーパネルが設置してあれば、発電量の比率からかなりの精度(<30°?)で姿勢の初期値が得られるかもしれません。でもキューブサットくらいの規模ならソーラーパネルで太陽の方向を推定する程度でも充分で、STTは必要ないんだろうなぁ。Core i5なら1min程度で計算できるとしても、キューブサットなら50-200MHz程度のFPU入りマイコンがせいぜいでしょうから、単純なクロック比でも15倍位時間がかかるんじゃないでしょうか。初期捕捉で15分って、全然役に立たなそう。でもWindowsが走るCPUとマイコンってクロック比は2-3桁くらいしか違わないのか。CISCとRISCじゃ同クロックでも演算能力はぜんぜん違うんでしょうけど。


 今回のコードを書くにあたり、最初は画像解析・カタログ読み込み・マッチングの処理を分離しようと思っていました。が、結果的にはより一層複雑になってしまった感じです。ジグソーパズルをテトリスにしようと思ったら知恵の輪になった感じ。なんとかうまい落とし所を探さないと。

半自動スタートラッカ4.2


 マッチングした位置でのカタログと画像のズレをヒストグラムに出力してみました。若干下寄りにズレて、かなり左にズレている、という感じです。実際、結果画像を見てみるとそのようにズレています。
 本来、マッチングした組み合わせ(画像の3個とカタログの3個の恒星)はズレが発生しないか、あるいは三角形の中に中心が有る拡大でズレているはずなのですが、画像を見るとすべて一様にズレているようですので、移動の計算にミスが有るのかもしれません。

 ちなみに、条件はカタログから300セット、画像から200セットの恒星をピックアップして、誤差は半径10ピクセル以内まで、最低マッチング率は0.75の設定で、実際には0.76までマッチングしています。赤経で1°、赤緯で0.5°、視点の回転で2°の誤差を与えています。


 昨日はノイズ除去をやりたかったのですが、結局いいアルゴリズムは思いつきませんでした。
 ペイントソフトでいろいろいじった感じでは、ある程度の広さのガウシアンフィルタで平均化し、それと元画像のピクセルとの差を取れば、何もやらないよりはマシ、というくらいにはなります。ただ、ガウシアンフィルタは計算コストがそれなりに掛かるのと、カメラの特性(主に輝点の大きさとノイズの周波数)に合わせてフィルタを調整する必要があるので、ちょっと面倒です。

 はや2のSTT画像は数px周期の規則的なノイズが載っていますが、複数の領域を比較明合成した際にちょうど明るい部分がズレたために、あの上下方向のノイズが発生したのかな、という気がします。もしそうであるならば、あの明るい模様は写真撮影モードで複数領域を貼り合わせた際にノイズの位相がズレた時のみ発生するものであり、STT姿勢検出モードでは発生しないのかもしれません。
 あまり自分の都合のいいように解釈するのも危険ですが、現状では確かめようがないので、とりあえずそう考えておくことにします。

***

 生活リズムが120°くらい遅れてて、まぁ特に支障はないのですけども、来週末と来月頭に時間固定のイベントが有るので、それまでに位相ズレを直しておく必要があります。ということであんまり頭が動いてません。120°遅れくらいだと、25時から28時あたりまでのインターネットが非常に快適な時間帯に活動できるので、かなりストレスフリーです。といっても2.8Mbpsくらいですが。
 朝6時か7時頃からだんだんレイテンシが悪くなり始めて、18時を過ぎるとほぼインターネットは使えない前提で活動する必要があります。固定回線は64kbps止まりの田舎で、MVNOをメインにしてますが、世間の活動時間が垣間見える感じです。そこを外そうとすると、やはり世間とは違う位相で生活する必要がありますが、たまに世間と同じ時間帯で活動する時に困ります。
 やはりインターネットが快適なところで生活したいなぁ、という思いはありますが、それを言い始めるとエコンが欲しいとか、品揃えの良いホームセンターの近所が良いとか、いろいろ欲が出てきます。住めば都とはよく言ったものです。あ、逆か。

2017年5月9日火曜日

半自動スタートラッカ 番外編

 スタートラッカによる火星の撮影| こちら「はやぶさ2」運用室 | JAXA はやぶさ2プロジェクト

 このブログにはやぶさ2のスタートラッカが撮影した写真がありますが、試しに作ってるソフトに食わせてみました。かなり余裕を持たせて、かつマッチ率閾値を下げてやればちゃんとマッチングできました。

背景画像:(C) 宇宙航空研究開発機構(JAXA)

 図の見方ですが、緑の丸がカタログから予想した星の位置、赤の丸が画像から解析した星の位置、オレンジの線がカタログ予想位置と回転・移動後の予想位置を繋ぐ線、という感じです。緑の線はマッチングに使った恒星の組み合わせです。
 オレンジの線の先端(緑丸の反対側)が画像の星の位置と近ければ、より正確に予想できている、ということになります。
 画像からの抽出がうまくできておらず、例えば右端のηは抽出できていません。このためマッチ率はあまり良くないです。

 今のところ、画像からの抽出は、まずノイズ対策のため閾値未満の輝点を切り捨て、その後残った輝度成分の一覧を作る、という流れになっています。一方、今回使った画像ではノイズ成分が多いので、閾値も高めに設定してあり、暗い星は検出できません。充分に明るいはずの星も見えてないのは謎ですが。
 でも、デジカメみたいな「ニセデータ」じゃない、本物のスタートラッカが宇宙から撮った画像でもちゃんとマッチングできたのは面白いです。
 ブログ内に書いてある情報では、画角は23.44°とのことですが、画角を0.88倍して計算しないとマッチングできませんでした。たぶん、僕のプログラムよりJAXAが出してる数字のほうが確度が高いはずなので、カタログから投影する際に何か誤差が出ているのかもしれません。デジカメの写真ではほぼ綺麗に一致しますが、スタートラッカの光学系はデジカメのそれとは違うのかもしれません。デジカメは周辺に寄ると角分解能が下がりますが、スタートラッカではできるだけ分解能がほしいはずで、なにかうまいこと処理されているのかもしれません。
 やはりさっくりとググって集めた情報だとすぐ限界が見えてきますね。
 中の人に知り合いでもいれば聞けるんだろうけど、聞いたところで教えてもらえるかは別問題だし。あるいは何かイベントが有る時にふらーっと立ち寄ったていを装って「そういえば僕の計算問わないんですけどぉ~どういうレンズなんですかね~」みたいな質問をするとか。

 ま、冗談はさておき、とりあえず今のプログラムでも半自動スタートラッカとして使えるのは間違いなさそうです。大体赤緯赤経で5°程度の誤差までは吸収できてる感じです。

 ちなみに計算時間は、画像解析で90msec、カタログからの投影で30msec、組み合わせの生成で2msec、マッチングで5msecくらいでした。相変わらずカタログの読み込みが1.5secで、結果画像の出力に50msecかかってますが。

 スタートラッカはおおよそ動くのがわかってきたので、次は画像解析の方も真面目にやっておく必要があるかもしれません。人間が見れば明らかにノイズですが、それをどうやってソフトウェアで除去するか。


 スタートラッカ画像が出てくると俺得なので、もっとガンガン出してほしいです。っていっても、例えばひまわり9とかのファーストライトのインパクトに比べれば、STTなんて取るに足らない画像なんだろうなぁ。

 昨年末にはESA(欧州宇宙機構)が打ち上げた衛星がSTT画像を出していました。
 ESA Science & Technology: LISA Pathfinder star tracker image
 この衛星は光学観測機器が搭載されていないらしく、「宇宙だぞ!」みたいな広報画像がSTTの写真しか無いようです。画像の大半が地球なので、STTテスト画像としては使いづらいかなぁ。

追記:2017/05/11
 STT画像をちゃんと図ってみると、解像度がおよそ767pxで、赤枠が1辺222pxくらいでした。ということで、767/222*5.86=20.246036°で、23.44*0.88=20.6272°とおおよそ一致します。実際、20.246036°でマッチングすると、正常に同定できました。
 写真をぱっとみた印象で300x300px(5.86x5.86°)が4x4で16枚だと思ってましたが、ちゃんと確認しておかないとダメですねぇ。0.9倍に違和感を全く感じなかったことに驚き。
 ということで、恒星の投影もJAXAの数値も僕のプログラムも問題なく、僕がポンコツだったという結果です。いやー、道具は使う人間の問題だってことを実感。

天体観望は天任せ

 夕方にVmag-8のイリジウムフレアがありましたが、雲が多くて見えませんでした。2時前も-0.5くらいのフレアがありましたが、こちらも見えませんでした。20時過ぎに外を見た時は結構晴れてましたが、難しいものです。

 せっかく防寒着を着込んでカメラを持ち出してきたんですから、雲の切れ間を写してみました。K-5とGPSの組み合わせでは、シェイクリダクション機構を使って赤道儀のような使い方ができますが、前回はキャリブレーションがうまく行かなかったので、復習も兼ね。


 2minなので、max5minまでは程遠いですが、いちおうこのくらいの時間であればちゃんと撮れるのかな、という感じです。
 キャリブレーションは地磁気センサ3軸の範囲を計測する作業なので、可能な限り1軸のみをゆっくりと回していく、という感じが良いのかもしれません。
 地磁気センサはちゃんと使ったことがないので、どういう風に校正を行うのかいまいち理解できていません。それがわかればキャリブレーションもうまくできるんでしょうけども。
 そう言えば、前に写真家が何かのイベントでペンタデジイチの使い方を説明する時に、「キャリブレーションはGPSの電波を受信して行う。地球の裏のGPSからの電波も拾えるように、上下逆になるまで回す必要がある」みたいなことを言っててびっくりしました。人を集めたイベントで言ってたことですから、それなりに有名な人なんでしょうが。

 イリジウムフレアは結構頻繁に発生しているようですが、来週頭にはまたVmag-8クラスが有るようです。晴れるといいな。

 本来の目的は、ジンバルでイリジウムフレアを撮影したいということだったはずなんですが、いつのまにやらデジカメで撮影したい、にすり替わってます。ジンバルのカメラじゃ画質悪いからなぁ。
 ベランダからジンバルで撮影するには方位180-270くらいである必要があるんですが、このあたりで発生するイリジウムフレアは1週間先までの予測でも無いようです。この位置はかなりレアなのかも。

 ジンバルのモーターはAC100VからACDC経由で供給しているので、屋外で使うことができません。このあたりを改善して、自由に持ち運びできるようなシステムを早く作る必要があるかも。電源電圧は24Vで、多少の変動はドライバが吸収してくれるので、非安定電源でもいいはずです。となると、入手性や安全性で言えば鉛蓄電池12Vを2組が現実的なところかな。22V台のLiPoもありますが、充電器とか一通り揃えると大変ですしね。あんまりエネルギー密度高いものも部屋に置いときたくないですし。
 参考までに、22.2V5AhのLiPoはTNT換算100gくらいのエネルギー量です。手榴弾の半分くらいです。もちろん爆発的に開放されたとしても手榴弾とくらべて10の何乗倍という時間を書けて解放されるでしょうし、圧力構造でもないので、単純に手榴弾の半分の殺傷能力というわけではありませんが。でも周辺に対する引火性はLiPoのほうが高そうですから、手榴弾で部屋が破壊されるのとLiPoで家丸ごと燃やされるのでは、LiPoのほうが被害は大きいかもしれません。

 こういう、益体もないことを延々と書いている時は大抵進捗がないときです。テストに出るので覚えておきましょう(出ません)。

2017年5月8日月曜日

優先順位付きの組み合わせ

 与えられた配列からn個の要素を取り出して組み合わせを作る際、添字が若いほうが優先度が高い、という条件をつけて生成する。
 今回はnが固定なので、forべた書き。可変長の場合は再帰とか使えばできるんだろうけど、今回は必要ないので考えてない。


 単純forネスト(上)は早いうちに4が出てきているが、優先度付き(下)はそうならないようになっている。

 あれとそれとこれの組み合わせが相手にも存在するか、みたいな総当りで、相手にも存在する確率が高い順にソートしてからこの添字で調べていけば、早期にマッチする確率が高い。もっとも、「相手にも存在する組み合わせが何個有るか」みたいな判定の場合は効果がないのだけど。

 左側がぽんぽん動いてるのが気に食わねぇ、って場合は添字に使う順番を変えればいい。ただしその場合は左側>右側になるので、どっちが好きかという話。


 前回のジグザグスキャンのコードとかも、いちいち自分で考えないで、探してきたほうが早かったりするんだろうなぁ。
 四角い車輪の再発明でも、地面のデコボコに一致すれば完璧に走るんです!とか、四角い車輪でも回転数上げれば安定するんです!みたいな言い訳。ま、回転数上げると車軸折れるんだけどな。。。


ジグザグスキャン

 ジグザグスキャンの回し方とか考えてみた。あんまり動作チェックしてないので間違ってたらごめんね。

 戻り値がIEnumerable<Point>なので、Pointを受け取るforeachで回せる。ZigZagScan.ScanのArg1に幅、Arg2に高さを与え、Arg3がtrueなら左上からスキャンを開始し、Arg4がtrueならまず右側に移動する。
 Arg3はJPEGで言うとDC成分をスキャンするかしないかを指定する。Arg4は開始する向きが右か下かを指定し、JPEGならfalseを指定することになるハズ。
 JPEGの場合は8x8の固定サイズなわけだが、コレは長方形にも対応している。ただし、幅高さともに2以上を指定すること。どちらかが1以下の場合は正常に動作しない。

半自動スタートラッカ4.1


 内部的な部分ばっかりをいじってて、目に見える変化が特にありません。

 昨日から今朝にかけてはずーっと天気が悪かったです。夕方にVmag-8くらいのイリジウムフレアがありますが、予報を見ると明日の朝まで天気が悪そうです。

 とりあえず、点から三角形を生成する時のアルゴリズムを変更しました。今までは一番簡単な単純forネストでしたが、ちょっと変えて、マッチング率が高くなるであろう組み合わせを優先して出力するようにしてみました。
 それに合わせて、カタログの三角形リストと画像の三角形リストのマッチングを、こちらも単純forネストから、ジグザグスキャンに変更しました。
 ジグザグスキャンが使えるんじゃね?と思った時に、「あっ!この問題見たこと有る!!」現象が発現しました。でもどこで見たアルゴリズムか全く思い出せなくて、結局ググって調べたわけですが、脳内にそういう情報が入ってる人はさくっと作っちゃうんだろうなぁ。

 今までの単純forネストでマッチングする際、最初の組み合わせでマッチングできない場合は、数万くらいの組み合わせを試みる必要がありました。しかし、マッチング率の高い組み合わせを優先した場合は、数回の試みでマッチングできるようになりました。もっとも、PC用のCPUだとそもそもが早いので、ミリ秒精度のタイマではほとんど違いがありません。数万ループも回して数ミリ秒ってのも凄いもんですが。

 4240x2832の画像を読み込んで解析する際、設定にもよりますが、恒星カタログの読み込みで1.5秒、恒星カタログから視野内の輝点を探すのに0.01秒、画像から輝点を探すのに1.4秒、画像とカタログそれぞれの輝点から三角形を生成するのが合せて0.1秒、三角形のマッチングが0.005秒、結果の画像を生成するのが0.6秒、という感じです。

 今のところは、データ間を比較して、移動と回転を検出するだけなので、ここからカタログ視野の姿勢にフィードバックをかけて再びマッチングさせ、という処理を作っていく必要があります。まぁ他にもやることは色々有るんですが。

***




 ウチの桜は今日一杯かもしれません。杏はだいぶ開いてきた感じです。個人的には杏のほうが好きかな。語感とか。より萌えキャラの名前っぽいし。 杏は白と紅と緑で彩りが良い気がします。桜の花や葉は桜餅っぽいイメージが先行しますし。あぁ、これが花より団子か。

2017年5月7日日曜日

半自動スタートラッカ4


 今までは、そもそもちゃんと動くかわからなかったので、かなりぐちゃぐちゃなコードで実装していました。所謂ラーメンコードです。
 が、ちゃんと動くことがわかったので、一部をコピペしつつ、新しく書き直しています。以前は1回のマッチングで、スターカタログからの投影や、画像からの輝点の読み込み等をすべて行っていましたが、これらを分離することに主眼をおいています。例えば画像の解析は現在の2048x2048ピクセルでおよそ0.5秒かかりますが、同じ画像を解析するのであれば1回の読み込みでよく、1ループあたり0.5秒の短縮が可能です。カタログからの投影は毎回行う必要がありますが、これは0.05秒程度なので、ちょっと動作確認するくらいなら問題にならないくらいです。
 マッチングは、条件によって時間に幅があり、うまくハマれば数ミリ秒で終了する一方、すべてのパターンを試す場合(≒一致するパターンがない場合)は、結果が出るまで40秒位かかります。
 ホンモノのSTTは初期捕捉で数秒、更新レートが数十-百Hz程度ですので、現在の方法ではかなり遅いです。このあたりは、初期捕捉では使用するデータを疎にし、だんだん密にして確度を上げる、といったアルゴリズムになると思います。一方、更新レートの方は主に画像解析が支配的です。
 次のフレームでは確度が何十度もズレてる、といった場合には初期捕捉と同様ですが、人工衛星の場合、10Hzで撮影して、フレーム間で10degズレるということは、3秒で1回転するような速度ですが、このような角速度で運用されることはないはずです。某衛星の事故のような自体も想定すると、「確実にこの速度で回ってるぞ」みたいな情報が出せると良いのかもしれません。もっとも、そんな速度で回ってれば星を撮影しても写らないでしょうが。


 ざっくりとデータ量を考えてみると、宇宙環境耐性とかを気にしなければ、1/3くらいのCMOS1個と、STM32F4を1個の、2チップでスタートラッカが作れそうです。F4のオンチップでも、7等星くらいまでならデータを持てそうな感じです。RAMが多ければその分画像処理が楽になりますが、解像度を落とせばオンチップRAMでもギリギリ足りるかな、という感じです。はやぶさ2のSTTは一度に300x300ピクセルを処理するそうですが、8bit/pxなら90kバイトくらいなので、F4のメモリでも余裕で入ります。あとは浮動小数点の演算速度が鍵になるわけですが、これは作ってみないとわかりません。

 さすがにFlash2M/RAM384kのF4を1個ですべてのミッションを行う、というのは大変ですが、「安価なスタートラッカを自作して軌道上で実証する」(STTから計算した向きと地磁気センサの値だけをダウンリンクして、たまーーに視野の一部も下ろす)くらいのキューブサットなら1個のF4だけでも可能かもしれません。
 タイムスタンプ・地磁気データ・STT出力だけなら1セット32バイト程度ですから、数分に1回程度の頻度でSTTの計算結果をRAMに貯めておいて、指定した時間になったらデータを吐き出す、みたいな運用ができるはずです。タイムスタンプがあれば軌道上の位置がわかりますし、位置がわかれば地磁気線の方向もわかるはずです。地磁気線の向きがわかれば地磁気センサから衛星の姿勢2軸がわかりますから、STT出力と大幅にずれてなければOK、みたいな。ミッション機器に画素がありますから、ある程度以上の面積が明るい写真があれば、それをダウンリンクするみたいな機能があれば広報的にも強いですし。
 サクッとキューブサットを飛ばせるような時代になったら、そういう遊びもやってみたいなぁ。その頃にはSTTを含めたバス機材の値段も暴落してるんでしょうけども。

ISSを撮ってみた


 ISSを撮るのは(カメラで撮るのは)久しぶりです。写真フォルダを見る限りだと、去年7月末に望遠鏡で撮って以来でしょうか。
 ペンタのスタートラッカはハマると綺麗に取れるんですが、なかなかうまくいきません。右上に星団が有るので綺麗にトラッキングしてほしかったんですが。

 右下から上がってきて、左上で消えているのが謎です。おそらく雲に隠れたのだと思いますが。画角から消える直前に雲が出てきて、それ以前は晴れていたので星が明るく撮れているのだと思います。曇るのがあと数分早ければISSも全く見えなかったはずで、ギリギリでした。

 いちおう、ジンバルでもちゃんと追尾できました。ただ手前の障害物でとぎれとぎれなのと、雲で隠れてしまって、追尾できたのは1分半程度です。
 でもまぁ、ジンバルは正常に動いてますし、初期設定が面倒なこと以外は問題ないと思います。衛星追尾の成功率はかなり高いです。

2017年5月6日土曜日

ジンバルでISS追尾

 ここ数日はスタートラッカのネタばっかりですが、久しぶりにジンバルのネタです。
 やっとISSが地上が日没かつ軌道上が日照のタイミングで飛んできてくれたので、それを撮ってみました。といっても日の出直前で、空はかなり明るくなってますが。



 30分ほど前からだんだん雲が出てきて、ISSが登ってくる頃には結構やばそうな感じでした。でもかろうじて撮れてました。
 そういえば、α7sを使い始めた頃に、手持ちでISSを撮って喜んでましたが、今回は自分で作った機材で撮ってるとは言え、すでにISSより遥かに暗いであろうロケットボディを撮っていますから、達成感で言うとそれほどでもありませんでした。まぁ撮れて当然、撮れなくてもそれは空が明るいから…みたいな感じで。

 時々書いてますが、やっぱり35mm換算2000mmくらいの光学系で撮りたいなぁ。これくらいならISSがかなり大きい面積で撮れるはずです。

 それと、ロケットボディを撮っていた時は充分に暗くなってからでしたから、背景の星が写り込んでいて、ちゃんとカメラが追尾してるんだぞ!というのがわかりました。しかし、今回はすでに星は見えず、背景も白一色なので、追尾してる感じが全然ありません。
 あとR/Bの時は充分に暗くて星がちゃんと見えましたから可視前に予め明るい恒星を導入して設置誤差を補正できました。今回はそれがなかったので、ISSを見つけるのに手間取りました。やはり画角5°は狭いです。
 補正は上下左右で2個の値がありますが、マウス1個で同時にそれらを操作するのはかなり大変です。コニカルスキャンで方位仰角のオフセットを動かせるプラグインがほしいかも。ま、自分で作ってるプログラムですから、そのあたりもやる気次第です。とりあえずブログに書いておけばいずれやることになるはずです。

 明日は今日より1時間ほど早いですから、空はまだあまり明るくなっていない頃です。
 それと、8日の2時頃にイリジウムフレアの予測があり、最大-5.9等星だそうです。このパスは向きがピッタリ部屋から撮影可能ですから、楽しみです。晴れれば良いんですが。

2017年5月5日金曜日

半自動スタートラッカ3


 K-5でかみのけ座あたりを撮影してみました。スタートラッカの出力によると、画像中心はRa12h32'29"、Dec+24d50'42"だそうです。便利!!
 あとから写真データを見直しても、どこを撮ったかなんて覚えてないですから、自動で場所を探してくれるスタートラッカは楽でいいです。

 K-5でF4, 15sec, ISO2500, 128mmで撮影しました。オリジナルサイズで書き出してスタートラッカに読ませています。画角は横10.33°、縦6.854°くらいで、STTとしてはちょっと広角かなくらいの感じだと思います。
 画角が似たような感じなら光学系も同じような感じになるはずで、衛星搭載のSTTも大幅にF値が稼げるはずもないでしょうし、感度もISO数千程度だと思います。となると、画角内に確実に星が写るようにするにはかなり暗い星まで撮影する必要があるはずで、シャッタースピードも数分の1秒とかでは足りないはずです。でもあんまり長時間露光すると、衛星が回転していれば星が流れてしまいます。どれくらいのシャッタースピードで撮ってるんでしょうね。

 写っている輝点の数はかなりあり、おそらく9-10等星くらいまでは写っていると思います。ただ、SAOカタログにそこまで大量の星がないらしいので、N100で処理しています。たぶんN200あたりまでは計算できると思いますが、そこまでやる意味もないので。

 カメラの画角が理論値と若干違うので、そこをうまく補正しないと誤差範囲内に収まりません。ただ、そこさえクリアしてしまえば、少なくとも歪み補正を行った写真であれば、画角が変わっても問題なく同定できるようです。


 とりあえず、次の目標はGUIソフトでぐいぐい動かせるような状態にすることでしょうか。GUIが有れば設定をいじったりするのも楽になるはずですし、「ちゃんと動いてるんだぞ!」って感じがします。
 あと、全自動で同定できるようにする必要があります。今は人間が細かく初期値を設定していますが、「どこを撮ったかわからない星空写真」の場所を決定するには、すべての領域を自動でスキャンする必要があります。
 って、当初の目的と変わってきてるな。まぁ、ジンバルのWebカメラで撮影するのは追々。
 やっぱり、デジイチを同軸に2個並べて、片方はスタートラッカと粗捕捉、もう片方の超狭角で衛星を撮影、くらいやりたいなぁ。

2017年5月4日木曜日

うわっ、このレンズ、歪み過ぎ?


 ジンバルのカメラで撮影した画像です。うしかい座のあたりです。
 許容誤差をものすごく大きくしてやっとマッチングできました。
 緑の線は輝点とカタログのリストの恒星を結んだもので、赤の線はカタログのリストを回転の移動で恒星の輝点に近づけたものです。テスト画像ではかなり綺麗に重なりますが、このカメラ、少なくとも今回の画像ではまったく一致しません。

 この画素はダイナミックレンジがかなり狭いので、星はあっという間に白飛びしますし、ノイズも多いです。でもなんとかスタートラッカに使えそうな気がします。白飛びして輝度データはありませんが、面積でソートすればだいたい輝度ソートと同じ感じになると思います。

 この光学系は特に疑問も持たずに使っていましたし、違和感を感じることもありませんでしたが、一度ちゃんとしたチェッカーボードっぽい物を撮ってみる必要があると思います。テスト画像を撮影したカメラは、Lrを通してるとは言え、歪みが全く無かったのはさすが腐ってもデジイチということでしょう。
 さて、35mm換算250mmくらいの光学系の歪み評価、どうやってやりましょうか。最短撮影距離は短いし、ピントを動かしたら意味ないし。


 OpenCv(OpenCvSharp)でWebカメラのコンフィグは色々ありますが、おそらくExposureが露光時間で、Gainがアンプの増幅率、Brightnessがオフセットだと思います。
 Exposureを増やせばかなり輝度が上がりますが、フレームレートが決めて遅くなります。Exp-1で2fpsくらいで-5で30fpsくらいですから、もしかしたら露光時間は2^Exp secくらいなのかもしれません(-1で1/2sec、-5で1/32sec)。露光時間で輝度を調整するのはノイズの面では有利ですが、それでも暗電流が時間分増えることに違いはありません。

 Webカメラは価格の面でも、扱いやすさでも利点が多いですが、やはりその値段と規模で作れる程度のもの、ということだと思います。充分に照度が有る、真っ昼間の日光下で使う分には悪くないですが、星を撮ったりするのは荷が重いようです。
 意外と早く限界が見えてきたなぁ。


 とりあえず、初期値を適切に設定してやれば、マッチ率が極めて低いとは言えなんとかマッチングはできますし、スタートラッカとしてのプログラムはあまり悲観する程ではない気がしてきました。
 とりあえず1/3型に35mmだと、APS-Cの180mmと近い画角ですので、K-5とかでサンプル画像も撮影してみようかと思います。K-5はアストロトレーサーが使えるので、星も極めて明瞭に…って、それじゃダメなのか。
 

半自動スタートラッカ2.1


 角度の計算を、二等辺三角形ではなく、カタログと画像の内角と外角を使うようにしてみました。ループ10回目でも正常にマッチングできます。もっとも、すでに5回目以降で移動・回転が0になっていますが。
 初回のフィードバックが過剰で2回目がオーバーシュートするのはまだ解消していません。気にはしていますが、さっぱり見当がつきません。

 RaDecに許される誤差はかなり小さく、1-4°程度です。画角が36x24°ですから、2度程度というのは極めて狭い範囲だと思います。
 一応、マッチングで一致したと判定する範囲や、何割以上が一致すればいいかというパラメータを変更すれば、もっと広い誤差でも同定することができ、その次のマッチングではさらに高いマッチ率が得られます。
 方向が不明な場合、まずは許容誤差を大きくして、さらにNを少なくして、1回のマッチングの計算量を減らしつつ、数度ずつずらした視界でマッチングを試み、低確率でもマッチングが成功すればそのフィードバックでさらに許容誤差を小さくしてマッチングを試み、というふうに処理していく流れになるのだと思います。

 今のところ、かなり晴れてるので、久しぶりにジンバルを外に出して恒星を撮影してみようかと思います。狭角でもちゃんとマッチングできて、初期値が無くても補足できるようになれば、ジンバルの初期化にも使えるようになります。

 やっと、もうすぐでISSが日没後・日の出前に飛んでくる時期になりました。まだ朝2時とか3時なのでつらいですが、ISSのトラッキングも試したいと思います。1/3型の35mmじゃISSも数ピクセル角の輝点くらいにしか写らないはずですが、ロケットボディとかに比べればものすごい明るさになるはずなので楽しみです。
 理想を言えば30cmで焦点距離2000mmくらいの鏡筒にデジタル一眼を付けたいんですが、さすがにその規模を振り回すジンバルを作るのは大変だし、鏡筒だけでいくら掛かるんだという話で。いや、本当の願望を言えば数mクラスとか、RQ-4みたいなドローンに乗せて高度十数kmからとか、いろいろ出てくるんですけど。


 昼間は融けるような暑さですが、夕方になれば涼しくなるので、まだましかなという感じです。

半自動スタートラッカ2






 前回のエントリからあんまり進んでいません。

 とりあえず方向を推定して誤差をフィードバックして、また推定して、というループを試してみました。ある程度まではうまく回るのですが、誤差が収束してくるとマッチングに失敗します。
 上の画像は、ループ1回目から5回目までの出力です。姿勢の初期値が大雑把なので、1回目はかなり誤差が大きいです。それをフィードバックした2回目は、若干オーバーシュートが出ています。3回目でかなり収束し、4回目は3回目とあまり変わりません。そして5回目はマッチングに失敗しています。
 おそらく、角度誤差の計算を行うための基線長が足りず、計算誤差が大きくなってるのが原因だと思います。離散データめんどくせぇ。

 あと、腑に落ちない処理が有るので色々試してみたいのですが、テキストデータで途中の値をダンプしても読むのが大変ですし、かといって画像データにするとループ数十-数万回分くらいが出てくるので、とても面倒です。まだ試してませんが、とても面倒なことになると思います。

 商業のシステムでも、動作確認用の情報は欲しいけど、実運用時はパフォーマンスを優先して出力させない、とか有るはずなんですが、どーやってスイッチしてるんだろう。データ吐き出してるのに時間がかかっててディレイ代わりになってちゃんと動いてたけど、デバッグ出力止めたら動かなくなった、とかもありそうだし。電子工作だとよくあることですけども。



 作り始めてある程度経つと、一気に進む期間があります。その前は処理方法とかを理解できていないので時間あたりの進捗があまりありません。理解が進むと一気に進捗も進みますが、ある程度のところで鈍化し、時間あたりの進捗がどんどん減ってきます。昨日あたりで鈍化し始めています。

 ウチの桜が今日になってポツポツと開花し始めました。部屋はうだるような暑さです。うだ~~。
 時計についてる温度計は28℃あたりを指しています。調べてみると、那覇の気温は27℃だそうです。避暑に南下しようか。。。

 これから9月とか10月辺りまでは、昼間の作業効率が酷く悪化します。ま、冬も寒いとか言ってグダグダしてるんですけど。
 一時期は夜中に作業して、涼しくなった朝に寝て、昼過ぎに暑くて寝苦しくなり起きて、みたいなサイクルでした。自分の都合で動けるときは問題ないんですが、どっかに行くとか、何かのイベントに参加する時はつらいです。

 部屋が南西向きで直射日光が凄まじいです。アルベド上げりゃ良いんだろ、ということで、去年は不織布にアルミ蒸着したシートを買ってみたりしたんですが、少しでも風が吹くと煽られて余計に自体をややこしくします。

 これからどうなることやら。

2017年5月3日水曜日

半自動スタートラッカ


 若干の誤差を含む赤緯赤経を与え、星を同定する、というところまではできるようになりました。
 領域が重なる初期値を設定する必要があるので、半自動、という感じです。

 オレンジのマーカーがカタログから計算した位置、赤のマーカーが画像から検出した位置、緑のマーカーがマッチングに成功して、カタログ値から動かした位置、緑の線が同じ星と思われるマーカーをつないでいる、という感じです。
 緑のマーカーが赤のマーカーとズレている部分がありますが、これは計算誤差によるものです。

 視野はECIの四元数でZ軸に194.8125°、Y軸に5.563888°、X軸に-4.2°回した向きになります。一方、初期値として与えているのはZ軸に194.0625°、Y軸に4.863888°、X軸に0°です。Z軸が左右の動き、Y軸が上下の動きで、X+が視線方向です。
 ZYの誤差は領域の差に直結するので、ある程度の精度で設定してやる必要があります。一方、X軸は視線軸での回転ですが、この軸はいくら回しても領域が変わることはありませんから、大雑把な値というか、ゼロでも問題ありません。でも、この画像は縦横比が1対1ではないので、視線方向で回すと多少領域も変化します。

 この画像では、星を輝度でソートし、明るい星から50個の同定を試み、およそ60%がマッチしています。
 Nが増えるとマッチ率が下がる傾向がありますが、これは暗くなると近い等級の星が増え、観測誤差で正しい輝度ソートが行われていないため、カタログから選んだN個の星と、画像から選んだN個の星で選んだ対象が異なるためと思われます。Nをどんどん増やしていけば、ある程度のところでマッチ率が改善するはずですが、計算時間とのトレードオフです。


 現在はカタログからリストを作るプログラム、画像から星を抽出するプログラム、それぞれのデータから同定を行うプログラム、というのが別になっています。
 とりあえず、カタログからリスト化するプログラムと同定を行うプログラムを1つにまとめて、1回目のマッチングで推定した角度をフィードバックして再びカタログからリストを作り、と言うような処理を行えば、半自動で高精度なRaDecBankを得られるはずです。
 それができるようになれば、全天を対象にスキャンする処理を追加して、全自動スタートラッカにできるはずです。


 それにしても、とにかくベクトルの計算が多いです。ほとんどすべての計算がベクトルです。あとマッチングを試すのは数段のループで様々な組み合わせを試みますから、並列処理可能な部分も多いはずです。FPGAに固定小数点演算とかで組んだら爆速になるんだろうなぁ、とか想像してみたり。FPGAって触ったこともないのですが。
 画像処理であれば、ベクトルの範囲は0-4000くらいで、解像度が低い画素であれば10^3くらいの範囲を表現できれば事足りるはずです。およそ2^10から2^12程度で足りるはずなので、もしかしたら32bit整数型でも計算できるかもしれません。余裕があったらそっちも試してみようかな。
 でもそれをやるにはマイコンに直結できる画素が入手できることが条件か。ゲームボーイのカメラで星を撮ってるブログが有ったけど、あのカメラってまだ入手できるのかな?
 マイコンに直結できるカメラで簡単なものはUART接続のJPEGカメラとかがあり、マイコンでも輝点を探すくらいの計算はできるはずですが、シリアルカメラのカメラ任せな設定で欲しい星の写真を撮れるかどうか。
 でもそれができれば、STBeeくらいのマイコン1個の人工衛星でもスタートラッカで姿勢検出してRWとか磁気トルカで姿勢制御して、みたいな高精度ポインティングができるかもしれません。やってどうするんだとか、小型STT買ってきたほうが早いという感じですが。

輝点検出


 先程の画像から、輝点の重心を検出したりしてみました。2枚目は1枚目をトリミングした画像です。およそ1000x700pxの範囲ですが、この大きさを計算するのに30msecほどかかっています。VGAの30fpsくらいなら、輝点検出だけならリアルタイムで処理できますが、この後にマッチングとかいろいろやるので、ちょっと問題かも。

 アルゴリズム、というほどでもないですが、計算方法としては、まず画像を読み込んで輝度情報の2次元配列に変換します。
 次に、ある程度の輝度以下は0に置き換えます。これは闇電流によるノイズ対策です。
 その後、左上からスキャンしていって、輝度が0より大きいピクセルがあれば、その周り3方向に対して輝度の判定を行い、というのを再帰的に行います。
 輝度が0より大きければ、そのピクセルの輝度と位置の積を加算し、最終的にすべての輝度を加算した値で割って重心を計算しています。
 その際、輝点として処理したピクセル数と、最大の輝度の情報も返します。
 ということで、サブピクセルの重心位置と、面積、輝度の情報が得られます。輝度情報は後の処理で必用になります。面積は、一定の面積未満であれば無視するといった、フィルタリングに使います。
 国際宇宙ステーションで撮影された映像を見てみるとわかりますが、画面内に常に光っているピクセルが有ると思います。これは放射線により画素が破壊された影響によるものですが、基本的に連続した複数ピクセルに対して発生するものではないので、1ピクセル以下なら無視といった簡単な処理でキャンセルできると予想しています。
 ま、このプログラムが宇宙に行く予定はないんですが。出力画像を作る際に、面積があれば円を書いたりできるので、単純にインクリメントするだけですから、実装してみました。
 あともっともらしい理由としては、スタートラッカのカメラは、サブピクセルの重心を計算するために、わざとピントを外した画像を撮影します。これにより1つの恒星がピンぼけで複数のピクセルに対して照射されますから、それらのピクセルの輝度差からサブピクセルまで計算できるというわけです。このため、原理的に1つの星は一定以上の面積を持ちます。そうなっていない輝点は、充分な光量が無いか何らかのノイズが原因と考えられるので、除外します。

 今のところ、すべてのピクセルに対して輝度判定を行っていますが、例えば間の1ピクセルを飛ばしてチェックするといった処理を行えば、シングルピクセルのノイズを無視しやすくなり、計算に要する時間が数分の1になります。
 といったあたりの最適化は、ちゃんとこのアルゴリズムで問題ないとわかってからでも問題ないので、とりあえず今は全量を計算しています。


 上画像では、中心に木星がありますが、この明るいヤツの周りに、円周状にあるマーカーは木星由来のノイズによるものです。
 おそらくマッチングを行う際に、こういうのでマッチングを試しても、明らかに姿勢がおかしくなるはずで、よほど許容誤差を大きくしない限りは、問題とならないはずです。
 問題になるようであれば、一定以上の面積の輝点があれば、その中心からn倍の範囲のデータは使わない、とかをやるべきかもしれません。

 そういえば、今のアルゴリズムでは左右下への再帰呼び出しに制限がありませんから、目の前に太陽とか月とか地球みたいなデカイ奴がいるとスタックが足りなくなったり、加算レジスタでキャリーするかもしれません。あぁ、スタートラッカのエラー対策の(以下略。


 あとは、画像から計算した恒星候補と、恒星カタログからマッチングを行えば、スタートラッカができちゃうかも?いや、できてくれなきゃ困るんですけどね。

手動スタートラッカ

 スタートラッカを作りたいと思っていて、とりあえずテストデータとして使える星空を撮ってきました。写真にSAOカタログから計算した恒星の位置を重ねてプロットしています。


 フルサイズ機でF1.8 1sec ISO3200 55mmの設定で撮影しています。マーカーは9.5等星まで表示しています。

 星の位置を計算するのは以下のページを参考にしました。
 Star Trackerに結像される星位置の計算 - nyanp::blog
 SAOカタログから読み取った赤緯赤経と、カメラの向きを四元数で渡して計算しています。
 画角は横36.24x0.9975°、縦24.61x0.9975°で、画素サイズ36x24mmで焦点距離55mmの理論値とほぼ一致しています。画角は端から端までの値で、レンズを通過してきた光は上下左右が反転しますから、画像に描き込む場合はそれを反転し直す必要があります。また、この計算では後ろ側の星の判定などは行わないので、何らかの方法で画角外を除外する判定が必用です。

 充分に明るいはずの星があるはずの場所にも何も写っていなかったり、なにもないはずの場所に輝点が写っていたりしますが、かなり綺麗に一致しています。画面中央の一番明るいのは木星です。



 iPadの星アプリとにらめっこしながら、いくつかの星を同定してみました。といっても名前を入れてるのは2個くらいで、あとは飽きてRaDecしか書いてませんが。
 エリアとしては、おとめ座のあたりです。この線でおとめ座ってんだから、昔の人は想像力豊だったんだろうと思います。


 スタートラッカとして使うには、今回は姿勢を人間が設定していますが、これを自動で行うプログラムを作る必要があります。
 とりあえずマッチングにはOPMアルゴリズムが使えるかな、と思います。というか、それくらいしか見つかりませんでした。STTっていろんなところに出てくる割に、内部の詳しい話は全く出てきません。バス機材は衛星チームが宣伝するようなものではありませんし、コンポーネントを作ってるところも、あまり詳しい話は出していないようです。
 でもいちばん大きい難関は、画像から星の位置を検出するアルゴリズムかもしれません。


 STTが使えるようになれば、ジンバルの姿勢とかを自動で補正できて便利かな、と思っています。初期化作業が大幅に簡単になりますから、使うときだけ設置するとか、移動運用とかが楽になると思います。
 この方法は夜間しか校正ができないという欠点がありますが、NICTだったかのPDFにも書いてあったので、ちゃんと使える方法だと思います。
 今ジンバルに乗ってる光学系では、画角は7.8x5.8°くらいで、STTとしては標準的な画角に近いと思いますが、なんせ画素がWebカメラですから、衛星追尾中はSTTとしての使用は難しいと思います。校正時に露光時間を長くして星を撮像して、運用時はSTTとしては使わない、という流れになると思います。もちろん増幅管を通すとか、高感度な画素を使えばそうとは限らないわけですが。

 手っ取り早くやりたいならいくつかの明るい恒星を選んでその角度から計算すればいいだけですから、STTを作りたいのは完全に興味本位です。でも個人の趣味の作業だからそういう理由で良いんです。

***

 木星の存在感があまりにも大きいので、久しぶりにビクセンの望遠鏡にK-5を付けて撮ってみました。


 心の瞳で覗いてみると、縞模様とかガリレオ衛星が見えると思います。
 この鏡筒を使ったのはかなり久しぶりで、以前はISSとか飛行機を撮っていたものです。ということで邪魔なファインダーは外してあり、経緯台からも微動ノブが外してありました。星を見るにはかなりマゾプレイですが、まぁなんとかなるもんです。
 動いてる飛行機を手持ちで撮ったりとか、動いてる衛星を三脚に載せてフリーストップで撮ったりしてると、静止してる星は導入さえできてしまえば逃げないのでかなり楽ですね。

2017年5月2日火曜日

シュトリヒってなーに~?

 書きたいネタはいろいろ有るんですが、なかなか筆が乗らない(?)。


 さて、ひっそりと公開している角度計算ページですが、この度めでたくミルに対応しました。なんで今さらという感じですが、ミルは国や運用者によって定義が違うのでめんどくせーと飛ばした記憶があります。
 とりあえず今回は6400ミルを実装しました。

 そもそもミルというのはなんぞやという話ですが、定義としてはミリラジアン(1周=2PI×1000)です。ざっくり計算して1周6283.185ミルですが、円周率が基準ですので無理数です。であるからして、どこかで丸める必要がありますが、どこで丸めるかという点で国によって違いがあります。
 wikipediaによると、旧ソ連のあたりでは1000の単位で切り捨てて1周6000ミル、スウェーデンは2006年まで100の単位で四捨五入して1周6300ミル、NATOや日本では1周6400ミルです。
 NATOの6400は切り捨てでも四捨五入でも切り上げでもないのですが、6400は2^6*100ですので、2^6、つまり64等分までは100単位で計算できます。例えば4等分した90度は1600ミルですし、8等分した45度は800ミルです。
 と、もっともらしい理由付けをしてみましたが、5等分だと1280ミルで、10等分だと640ミルで、簡単に10単位になってしまいます。


 計算ページの入力フォーマットですが、度、ラジアン、Rev、Milは実数のみ入力可能です。DegMSとHourMSは文字列の入力がかのうで、数字以外の文字(空白やアルファベット、記号等)はひとまとめで区切りとして扱われます。例えばDegMSに12 34 56や12°34'56"と入力すれば、12.582度等と表示されます。緯度(DegMS)や赤経(HourMS)をWebページからコピペしてきたりできるので便利かな、と思います。ただし、先頭に数字以外の文字が1以上あると、不正な値として計算されてしまうので、その点は注意してください。コピペしてくると先頭にコロンやスペース、タブが入ることがありますし、緯度経度だと先頭にNSEW記号がついてたりするので、注意が必要です。

 あと、URLパラメータとしてangle.html?deg=123.456やangle.html?Mil64=3200のように渡せば、ページ読み込み時にデフォルトの数字を設定できます(未指定で全て空白)。SNSとかで角度の変換で口論になったときとかに活用してください。