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とかほしいなぁ。それかトリノホシのモーターグライダー。