なんとなく行きたくなったので、諏訪大社にいってきた。諏訪大社は2社4宮に分かれて点在していて、それぞれが結構離れている。上社と下社は電車で、ほかは徒歩で移動したがかなり疲れた。
上社 前宮
道中
上社 本宮
下社 秋宮
道中
かなり高低差がある。この神社は上から見たのみで行かず
春宮と秋宮で建築技術を競ったらしいので名残りかな?
諏訪大社に続き、仁科神明宮にも行ってきた。諏訪からは同じ長野県内ではあるがかなり離れており、駅からも30分ぐらい歩く。
現存する神明造社殿では最古で、本殿が国宝に指定されている。
神社はどの神社も式年遷宮で造りなおされる傾向があり古いものがそのまま残っているケースが少ない。この神社も300年前までは建て替えをしていたみたいだけど、その後は修繕をやって残っているらしい。
ちなみに神明造りに限らなければ、現存最古の神社は京都の宇治上神社で、こちらも国宝になっている (なおかつ京都の世界遺産を構成する1つ)。宇治上神社は5年前に行った
WebGL があるからね。ブラウザが業を背負ってくれるのだよ。
https://github.com/cho45/go-KX3-panadapter
KX3 (無線機) 用の panadapter (広域スペクトラムスコープ) の実装を WebGL でレンダリングするように変えた。
これまで go-gl を使って頑張っていたが、いつのまにか go-gl の構成が変更され、ビルドができなくなってしまった。
go には依存パッケージのバージョン指定を行う方法がないので (ないよね?) 最新に追従する以外の選択がないのだが、いきなりビルドが通らなくなるみたいな事態がおこるともうやる気がしない。
継続的にメンテするほどの変更は入れてないが「ときどき実用しているアプリケーション」が割とどうでもいい理由で壊れるととにかくやる気が失せる。なので、できるだけ壊れなそうなものに依存するようにしたい。
その点ウェブ技術に依存しておけば、あまりひどい非互換は入らないことが期待できるし、最悪壊れてもググれば非互換情報が見つかりやすく、対処しやすい。そしてそもそも JS で書くのでビルドできないような事態にはならない。
前のバージョンでは go-gl を使い、go で書いたプロセスで直接ウィンドウを作ってレンダリングしていたが、構成の変更により、go で書く部分は portaudio を使って任意のサンプリング周波数で信号のFFTを行い、WebSocket からストリームで投げ続けるというシンプルな動作を行うようになった。(44.1kHz 固定なら WebAudio + WebWorker でできそうだが、すくなくとも 96kHz サンプリングはしたいので WebAudio はつかってない)
ブラウザ側のJavaScriptでgoプロセスへ WebSocket の接続を行い、データを受信し次第 WebGL を使ってレンダリングを行う。
これにより go の部分の cgo 依存は portaudio のみになった。portaudio は非常に薄いラッパーなので将来非互換が入るような余地がほぼないと思われる。安心
別に go に限ったはなしではなく、ビルドができるできないとか依存がどうとか、とにかくダルイ。やらなくてすむことはやらないようにしよう。
rename コマンドで可能だぞ。rename コマンドは Perl の式でファイル名を置換可能だ!
「拡張子のないファイル」にマッチするシェルのglob表現は簡単ではないし、シェルスクリプトの for 文の文法はだいたいいつも忘れている。rename コマンドは Perl の正規表現という大変慣れたものを使え、sed や awk などと比べても安心感がある。
rename -v -n 's/^([^.]+)$/$1.txt/' *
置換が行われなかった場合リネームは行われない。-n はドライランなので実際に実行するときは外す。-v は verbose オプションで、つけておいたほうがいい。
この正規表現では . を含まないファイル名にマッチさせ、.txt をファイル名にあとに追加している。
Ubuntu の wiki によると
UNIXにこのコマンドがないこともあって余り知られていませんが、どのLinuxにも含まれています。
らしいが、本当のところどうなのかよくわからないぞ! すくなくとも Ubuntu では使用可能だ! なお OS X には含まれていない。
OS X では brew install rename で入るが、これは Ubuntu のパッケージのものとはまた別のバージョンである。ただし高機能版であり、-v -n オプションは互換性がある (-n の longname は Ubuntu 版では no-act だが、homebrew で入るものは --dry-run または --just-print となっている)。
ライセンスはどちらも This script is free software; you can redistribute it and/or modify it under the same terms as Perl itself. となっており Perl と同一 (Artistic License) のようだ。原版と同じ名称を使ってはいけないライセンスだった気がするが……
Ubuntu 版
# This script was developed by Robin Barker (Robin.Barker@npl.co.uk),
# from Larry Wall's original script eg/rename from the perl source.
homebrew 版
AUTHORS
Aristotle PagaltzisIdea, inspiration and original code from Larry Wall and Robin Barker.
となっており、Larry Wall (Original?) → Robin Barker (Ubuntu版) → Aristotle Pagaltzis (homebrew版) という感じで進化している雰囲気がある
上のように、スペクトラムのウォーターフォール表示ではよく下に1行追記して全体を上にスクロールさせていくみたいな見せかたをするが、全体の再描画が必須なため、かなり描画負荷が高い処理となる。
いくつか実装を書いてどのぐらい差がでるかを検証してみた。
http://cho45.stfuawsc.com/spectrum-performance/canvas-redraw-whole/
ctx.putImageData( ctx.getImageData(0, 1, canvas.width, canvas.height - 1), 0, 0 );
上のようなコードで canvas 全体を 1px ずらして、最後の一行に新しいデータによる putImageData() をさらに行う。
ピクセルデータを直接シフトさせるやりかただと、一番ナイーブで実装が簡単だが実際のところかなり遅い。
35ms/render ぐらい。
http://cho45.stfuawsc.com/spectrum-performance/canvas-double-dom/
canvas の 描画自体は1px * width だけを常に上書きする形で行い、全体のスクロールは DOM でずらす (ブラウザに再描画をやらせる)
わかりにくいので動画にするとこんな感じで、2枚の canvas 要素を margin で使って動かして、親要素で表示領域を制限 (overflow: hidden) してる。
4ms/render
http://cho45.stfuawsc.com/spectrum-performance/webgl-double-textures/
2枚 canvas とやっていることはほぼ同じだが、canvas の代わりに WebGL のテクスチャを2枚定義し、DOM の代わりにシェーダーを使う。
0.6ms/render
@cho45 デバイスがなくてコードを試せてないのですが、putImageData+getImageDataではなくてdrawImageにcanvas自身を渡してずらして一行描くのだと速くなりそうですがどうでしょう。
— Mayuki Sawatari (@mayuki) October 5, 2015と言われて、drawImage! そういえばそんなのも! という感じだったので試したらこれは十分高速だった。
0.6ms/render で WebGL でやるのと変わらないぐらい。
canvas へ広範囲に putImageData の繰替えしをするより DOM で移動させたほうが圧倒的に早いのがおもしろかった。
WebGL は面倒くさい分たしかに高速で、2D でも可能な限り使ったほうがよさそうだけど、直接文字のレンダリングができないとか (canvas に書いてからテクスチャとして転送する必要がある)、API 的に面倒とか、GLSL というシェーダー言語を覚える必要があるとか、難点もある。
とはいえ、面倒なぶん自力でチューニング可能なポイントが多いのでおもしろい。
もっと早くなる方法がありそうなら是非お知らせください。
だいたい作ってやる気がなくなってきたので動画にいちおうまとめた。
http://cho45.stfuawsc.com/misc/css3-sine-wave.html
CSS 自体では自由な曲線は描くことができないが、CSS animation では、animation-timing-function で cubic-bezier() を使い定義したベジェ曲線に従ってプロパティーの変化量を決めることができる。
なので、複数の animation する要素を組合せることで、全体としてサイン波を描くことができる。
ポイントは animation-timing-function はキーフレーム間 (1回のアニメーション全体ではない) に適用される点で、勘違いしているとひたすらハマる。
上記の例ではアニメーションさせたままだが、animation-delay に負の値を指定して animation-play-state: paused; を指定すれば止めた状態にもできる。
昔 keyString.js という KeyBoardEvent からなんとなく押されたキーの文字列表記になおすやつを書いたことがある。
しかしこれは実装が不完全で一部のキーがちゃんと判定されなかったりした。が、マルチプラットフォーム・マルチブラウザで検証するような気力はないし、そんなことしても無駄になるのは目に見えているのでやる気はおきない。
KeyBoardEvent に key というプロパティが DOM Level 3 Events ではできることになっていて、これは Enter キーの場合 "Enter" という文字列が入り、物理的なキー位置(ということになっている謎の数値)ではなく、論理的なキーを表現するということになっている。が、全てのブラウザで同じように実装されているとはいえない。
ということで KeyBoardEvent.key には polyfill をつかおう。
https://github.com/inexorabletash/polyfill/blob/master/keyboard.js
を読みこむだけでいい。完璧ではないがおそらく現時点で一番まともだと思う。このファイルにはライセンスが書いてないが polyfill 全体で Public Domain となっており適当に扱っても問題ない。
KeyBoardEvent.key は modifierKey (シフトキーとか) の状態は当然含んでいないので、単に
if (e.key === 'Enter') {
} で判定してしまうと、Shift+Enter や Alt+Enter なども同じもの扱いになってしまう。かといって
if (e.shiftKey && e.key === 'Enter') {
} else
if (e.altKey && e.key === 'Enter') {
} else
if (!e.shiftKey && !e.altKey && e.key === 'Enter') {
} とか全部書くのは見通しが悪い。
ということでしかたなしに
var key = (e.altKey?"Alt-":"")+(e.ctrlKey?"Control-":"")+(e.metaKey?"Meta-":"")+(e.shiftKey?"Shift-":"")+e.key;
みたいなのを1行書いて modifier key のプリフィックスをつけておくとやはり楽になる
if (key === 'Shift-Enter') {
} else
if (key === 'Alt-Enter') {
} else
if (key === 'Enter') {
} そろそろ HTTPS でしか使えない新機能なんかを使いたくなるので、すこしずつノウハウを溜めようという気持ちはあります。
ググって出てくるコマンドだと対話的インターフェイスでどうでもいい情報を入力する必要があってダルいので一発で自己証明書つくれるようにします。
#!/bin/sh cd dev CN=localhost openssl genrsa -out server.key 2048 openssl req -new -key server.key -out server.csr -subj "/C=JP/ST=Kyoto/L=Kyoto/O=Example/CN=$CN" openssl x509 -req -days 1024 -in server.csr -signkey server.key -out server.crt rm server.csr
server.key と server.crt を使って HTTPS サーバを立てます。
HTTP2 は一応暗号化はオプションということになってるようだが (H2C/HTTP2 Over TCP)、実際の実装では TLS に乗っているものしかないので必然的に HTTPS でしか使えない。
node の http.Server / https.Server を使っている場合、Server のインスタンス化コードを替えるだけで HTTP2 にできる (インターフェイスが一緒)
コンストラクタに server.key と server.crt を指定するだけ。
localhost だけでの開発ならいいが、LAN 内のスマートフォンなどから HTTPS な開発環境にアクセスしようと思うと、IP アドレス指定してもアクセスできない。Chrome の場合、ERR_CONNECTION_CLOSED (This webpage is not available) になる。
どうやらホスト名でアクセスしないとブラウザ側で強制的に接続を切るようで、どうしようもない。
ということで、一旦 LAN 内に DNS サーバを立てて該当コンピュータを名前でひけるようにする必要がある。(mDNS でいけないかと思ったけどダメだった)
node で DNS サーバを書ける実装もある (node-dns (native-dns)) のでこれを使えばとりあえず簡単に書ける。
/etc/hosts 形式を読んで A レコード返すだけのは雑に書いた。
立てた HTTPS サーバと同じマシン上で良いので、port 53 で起動する。sudo が必要。
端末側でもこの DNS サーバを参照する必要がある。
Android では Settings → Wi-Fi → (接続中のネットワーク名を長押し) → Modify network とすすんで、Show advanced options にチェックを入れ、IP settings を Static に変え、DNS 1 にマシンのIP Addressを指定すれば反映される。
またはルータの設定を書き変えて DHCP 経由で通知する DNS サーバを変えてもいいけど、これはこれで面倒。
link rel="import" によるロードはやはりちょっと時間がかかる。Polymer の場合どうしてもインポート数が増えるのでなんとかしたい。
もちろん vulcanize すれば import 自体は解決するが、created/attached まわりの処理もチリも積もればという感じで、なかなか時間がかかるので、根本的解決にならない。
特に appmanifest によってスタンドアロンアプリ表示させている場合、ロードまでの間完全に真っ白の画面になり、プログレスバーも出ないのでかなり残念なことになる。
ということで、一旦ローディング画面を挟みたい。
HTML Imports はポリフィルされていない場合ブロックする (Chrome にしかネイティブ実装されてないから Chrome だけ)。インポート先がインポートしている場合再帰的にインポートするので、依存全部インポートが終わるまで表示が完全にブロックし、head内でインポートしていると画面描画が全く走らない。
Chrome の場合 first paint が走るまで現在表示中の内容を消さないので、リロードした場合特に「全く操作はできないのに表示はされている」状態になって気持ちが悪い。
なので、まずはインポートなしの状態ないし、最低限必要なものだけをインポートしてから、ロード画面を表示する。
link要素のloadイベントでひとつのインポートの完了はわかるが、再帰的な全てのリクエストのプログレスをとることができない。
どうしようもない?ぽいので、intermidate なローディングプログレス表示するしかない。
CSS でアニメーションさせるのが現状では一番マシっぽい。
<div class='loading'></div>
<my-app></my-app>
<script>
requestAnimationFrame(function () {
var link = document.createElement('link');
link.rel = "import";
link.href = "src/app.html"; // my-app の定義
link.addEventListener('load', function () {
var loading = document.querySelector('.loading');
loading.parentNode.removeChild(loading);
});
document.body.appendChild(link);
});
</script> link rel="import" は作って挿入してもちゃんと動いてくれるのでこれで良い。polyfill もちゃんと動いててうまく動く。
load イベントは再帰的なロードが全部終わってから発火するようになっている。
HTTP2 化してもカスタムエレメントの初期化処理はなくならないので、大量のカスタムエレメントを使う場合なんらかのローディング表示が必要ではないかという気がする。
appmanifest によるスタンドアロンアプリ化ではコンテナ(ブラウザ)側でそのうちちゃんとローディング出せるようになりそう。
ウェブアプリをスタンドアロンアプリのように表示するため (ようはロケーションバーを消したいという) 試してみた。
「ホーム画面に追加」というメニューに manifest が反映される形になる (わかりにくい)
"display": "standalone" の場合、こうなる。
ちょっと考えごとするとき Google Keep にとにかくタイピングしていく、みたいなことが多々あるが、図を入れようとすると途端に困難になるので、ペンと紙という便利な道具を使うことにしてみた。
できればデジタルガジェットで解決したかったがコストの割に性能で満足いくか微妙に感じた結果、良いペンと紙を使うほうが気持ちいいのではないかと考えた。
別段こだわりがないし思考過程を保存しようとも思わないので、紙とかコピー用紙でいいかと思ったが、思いのほかスムーズに書けずイライラしたので、調べた結果ニーモシネが良いだろうという感じだった。装丁がかっこいいのと、方眼の薄さがちょうどよくて気にならない。
ペンは手持ちにあった LAMY の Safari (なんかのときにもらった) の細字(F)と、kakuno の中字(M)、細字(F) で良さそうなのでこれのまま。(Safari も kakuno も学習用の安い万年筆。LAMY のFはkakunoのMと同じかそれより太い線)
この組み合わせはかなり気持ち良く書ける。ペンは安くても紙はちゃんとしたのを使ったほうが良いということを学んだ。
紙 vs コンピュータという点では、結局筆記で書いていくのは自分の場合長くは続かない気がしている。
今のところ8ページぐらい消費したけど、今やっていることに対してはそこそこ良い感じがする。ある程度以上に複雑になると図がないと厳しいけど、コンピュータ上で図を書くのは、書けないことはないけど今のところペンで書くよりも早く書けない。
一方で書いた図を編集させるのが難しいので図の試行錯誤はしにくいのと、字を書く分にはコンピュータ上に書いたほうが早いので、思考過程を最終的にデジタル化したいなら最初っから Inkscape 極めたほうが有益そうではある。
モバイルバッテリーのロードバランサ | tech - 氾濫原 の続き。5V 2A (10W) 出力のモバイルバッテリー複数使って、30W ぐらいの電力を得ようというやつ。
その後、2個ぐらい専用のロードバランサICを使ったりしてみたが、高負荷時にスイッチングノイズで入力電圧が大きく変動するのをカバーできず挙動が不安定だった。
ということで、改めて基本的な回路で実装したら結構うまくいった。
前回は 5V バッテリーの出力を直接合成しようとしていたが、それだとバッテリーの個体差によって電圧の差が大きく、うまくバランスできないうえに、損失が大きくなるという問題があった。
今回はバッテリー出力それぞれを欲しい出力電圧付近まで DC/DC で昇圧してから合成することにした。これにより、DC/DC で電圧で調整が効き、かなり近くに電圧をあわせられる。昇圧後に電流制限回路とダイオードを入れ、ロードシェアさせている。
FET は、最大で、許容する電位差×最大電流値だけの損失を発生させる。±0.5V 700mA だと 700mW。空冷でもよさそう。ただ、全体の許容電流を超えた電流を流そうとすると損失が激しく増えて熱くなるので危険。
電圧を高めにして、ゆっくり電流を増やしていくと最大28Wぐらいとれた。
不定期に電流をとろうとすると、DC/DC 基板についているコンデンサを放電しきってしまうようで、昇圧の入力側すなわちバッテリー出力側に過電流が流れ、バッテリー側の過電流検知にひっかかることがあった。
これは電流制限を昇圧後に入れているせいなので、昇圧前にも入れれば解決するが、それはそれで面倒くさい。
ESR が大きめのコンデンサを出力につけておけばだいたいいい感じになりそうだったがちゃんと試してない。
DC/DC をそれぞれにつけるせいで実装面積が大きい。 DC/DC は小さくしようがないので、ロードシェアの基板を小さくするしかないが、それほど小さくはならなそう。
http://cho45.stfuawsc.com/GrblServer/browser/gcode-viewer.html
GrblServer で使うために実装を書いた。もともとプログレスバーを時間ベース(パスの長さとフィードレートから求めた値)にしたくてG-codeパーサを書いてたけど、結局ビューワー作るのと同じコストがかかることがわかったので、デバッグがてらビューワーも書いた、という感じ……
three.js を初めて使ってみたけど、かなりお手軽の WebGL 使えて良かった。WebGL の API はかなりローレベルなので 3D 初心者には使えない感じだけど、three.js なら誰でも使えるレベルになっている。
ただ、ちょっと凝ったことをしようとすると自力でシェーダープログラムを書く必要はある。今回 Z 軸が 0 以上ならパスを半透明にしたくてシェーダープログラムを書いた。
そして最近のスマートフォンだと three.js で書いたコードがものすごくヌルヌル動くのですごい。ブラウザゲームとかマジでネイティブ疎遠ないレベルで作れるのでは!!??? と思ったけど、別に作りたくはない。
Grbl の現在のバージョン(v0.9)にはジョギング(手動で軸を送れる機能)がない。GUI にあったりするが、基本的には偽物である。
理想的な(というか普通の)ジョギングは、スイッチを押している間だけ設定したフィードレートで動くという機能なのだが、Grbl はGコード単位でしか駆動信号が出せないため、このような挙動ができない。
https://github.com/grbl/grbl/wiki/Interfacing-with-Grbl にもFAQ的に書かれている。ここで書かれているのは、planner buffer queue size (設定すると status として出力できる) を見ながら、一定のキューサイズを保つ、という方法である。
しかしこの方法には以下のような問題がある
次に思いつくのは Hold してから Reset するという方法である。Grbl は Hold など一部のコマンドはリアルタイムで処理されるため、キューサイズに影響されない。
つまり、動いているときに Hold させて即時停止させるということは可能。そしてその状態から Reset を行えばキューをクリアできるため、実質的にジョギング相当になる。
しかしこの方法には以下のような問題がある
ということで使えない。
ということで別の方法を考えた。これは1つのGcodeあたりの実行時間を一定とし、一定時間ごとにキューイングする方式。
理想ジョギングはステップ単位で進むわけではなく、フィードレートのみに依存しているわけで、それに近い挙動をすることができる。
インターバルは Grbl へ送信してキューに入るまでの時間よりも長い時間をとる必要がある。ネットワーク経由だと少し大きめに設定する。
例えば 0.3sec インターバルでフィードレート800mm/minで送る場合、4mm ずつ送ることになる。
この方法のメリットは
デメリットは
ぐらい。
実際はステップジョギングと可変フィードレートを併用できるのほうが嬉しいため、以下のような挙動にした。
かなり自然なジョギングができるようになって満足
シェーダープログラムはGPU内で動く。性質上並列(parallel)に実行される。
頂点ごとの処理内容。線分だったら始点と終点。頂点の最終的な位置を決定する。ついでに頂点ごとの属性 (attribute) から fragment shader に渡すものをどうするか決めたりする。
最終的に gl_Position にスクリーン座標を代入する。
ある断片ごとの処理内容。線分だったら始点から終点までの各要素を分割した1要素 (線分をレンダリングしてピクセル単位にしたときのピクセル単位)
最終的に gl_FragColor に vec4 型で色情報を代入する。
varying として vertex shader から渡された値は、各断片ごとに値が変更されて渡ってくる。
gl_FragCoord という変数があり、これには実際に処理しようとしているピクセル座標が入ってくる (スクリーン座標系)
gl_FragCoord から元の世界座標系を計算するのは面倒なので、fragment shader で世界座標系が欲しい場合 varying で座標を渡すのがてっとりばやい。
varying は vertex shader と fragment shader とを繋ぐものだが、vertex shader でセットした値がそのまま fragment shader に渡るわけではない。fragment shader に渡るときに該当する fragment について計算された値が渡ってくる。
https://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/varying.php