われがわログ

最適化アルゴリズムとかプログラミングについて書きたい

QMK Firmwareが焼けるマクロパッド「YMD09」を買った

自分でファームウェア(QMK Firmware)を焼けるマクロパッド「YMD09」を購入したのでメモしておく。

ja.aliexpress.com

Teamsのミュートショートカット(Ctrl+Shift+M)を押せるマクロパッドを探しており、最初はStream DeckかKoolertronのマクロパッドを買おうかと思っていた。だが、Stream Deckは値段が高く、かつ設定がPCに保存されるそうなので却下した。リモートワーク用のPCにも使いたいので、通常のキーボードとして認識してくれることが望ましい。

Koolertronのマクロパッドはその点申し分ないが、設定ソフトウェアがプロプライエタリなため購入に踏み切れなかった。

その後見つけたのがYMD09だ。YMD09は9キーのマクロパッドであり、キーボード向けのオープンソースファームウェア「QMK Firmware」をインストールできる。しかも、QMKの設定を簡単に変更できるVIA(or Remap)にも対応しており、使い勝手もよい。 さらに、完成品にもかかわらず約3000円と値段も安く、購入に踏み切った次第だ。

手元に届いた状態でキーボード用ファームウェアが既に焼かれていたが、今となっては何が入っていたのかよくわからない。 分解した後、Reset用のスルーホールをショートさせてブートローダーを起動し、以下のページからダウンロードできるVIAのファームウェアQMK ToolboxでYMD09にインストールした。

caniusevia.com

あとは、以下のページを読みつつ設定を進めた。

salicylic-acid3.hatenablog.com

salicylic-acid3.hatenablog.com

設定をしていく中で一つ問題が生じた。レイヤーのインジケータとしてRGB LEDを使いたかった(レイヤー1だったら青く光らせるなど)のだが、VIA、Remapでは設定不可だった。ググったところ、QMKの設定を変更すれば対応できるとのことだった。QMKの設定変更というと難しく感じるが、QMKの内部機能に手を入れる必要はない。設定ファイルを編集すればよいだけだ。具体的には、VIAが有効になっているファームウェアのkeymap.cを編集すればよい。詳細は下記ページに譲るが、レイヤー変更のたびに呼ばれる関数 layer_state_set_userの中で、LEDカラー設定関数rgblight_set_layer_stateを呼ぶ。上記設定の場合、LED(正確にはRGBLIGHT_LAYER_SEGMENTSで指定したLED)の色以外はVIAで(すなわちファームウェアの再インストールなしに)設定できるので、VIAによる柔軟性を維持できる。

beta.docs.qmk.fm

ymotongpoo.hatenablog.com

参考のため、編集したファイルを以下のgistにおいておく。 qmk_firmware/keyboards/ymdk/ymd09/keymaps以下に新しくディレクトリを作成し、以下のファイルを置いて書き込めば使用可能だ。デフォルトだとLEDがまぶしすぎたため、RGBLIGHT_LIMIT_VAL を128に設定している。

ymd09

言うまでもないが、マクロパッドはAutoHotkeyと親和性が高い。 マクロパッドを買うような人は既にインストールしていることと思うが、念のため宣伝しておく。

www.autohotkey.com

参考

f:id:estshorter:20210323202539j:plain 画像:https://mechboards.co.uk/shop/kits/ymd09-macropad/

いいかんじのLatexテンプレートをつくった

LaTexは慣れれば非常に良い技術文書作成ツールだが、残念ながら、その段階に至るまでの道のりが険しすぎる。文献リストから参考文献を自動生成するためにbibtexまわりを調べたり、キャプションをいいかんじにするためにcaptionパッケージやsubcaptionパッケージに与える引数を調整したりしていると、「文章を書く」という本来の目的を忘れそうになる。まるで、環境構築に非常に時間のかかるプログラミング言語を触っているようだ。

多くの人はLaTexの細かな設定には興味がなく、「それなりに整って見える文書」が欲しいだけだと思う。そこで「いいかんじのLatexテンプレート:PrettyLatexReport」を作った。

github.com

インストール後、

\usepackage{PrettyLatexReport} 

としてincludeするだけで、論文によくある「図1(a)」のような表示や、bibファイルからの参考文献リスト自動作成ができるようになる。PDFのしおりも挿入される。リポジトリには.latexmkrcも同梱しているので、Perlが動けば*1latexmkコマンドを打つだけでコンパイルできる。インストールの仕方等、詳細は上記ページのREADMEを参照のこと。

ちなみに、テンプレートと言ってもベースはbxjsarticleであり(template.tex参照)、本体であるPrettyLatexReport.styの中では、必要なパッケージをincludeしつつ、figureまわり、「PDFのしおり」まわり、bibtexまわり等の煩雑な設定をしているだけだ。ただ、そのような設定をすべてstyに押し付けたおかげで、メインファイル(texファイル)では文章を書くことに集中できる。

学位論文申請用のテンプレートも作ったのだが、こちらはもう使う予定がないのでアーカイブしてしまった。Reportの方は会社業務で使っているので、大学を離れた今でもメンテしている。

github.com

*1:WindowsではStrawberry Perl等をインストールする必要がある

M5Paper公式ライブラリのOSSライセンス違反について

M5Paperの公式ライブラリであるM5EPDのコードを読んでいたところ、ソフトウェアライセンス的にまずい点を見つけたので記録しておく。なお、issueは以下の通り約1か月前に投稿済みだが、返答なし。

github.com

まずい点は、MITライセンスで公開しているにもかかわらず

  1. GPL-3.0配布のソフトウェア、
  2. CC BY-SA 3.0配布のソフトウェア、
  3. LGPL-2.1配布のソフトウェア

を含んでいることである。いずれもコピーレフト型ライセンスなので、MITライセンスは使えない。

※ライセンス周りはあまり詳しくないので、間違っていたら指摘してください。

GPL-3.0配布のソフトウェア

SHT3x.hSHT3x.cppが該当すると思われる。元リポジトリはおそらくhttps://github.com/Risele/SHT3xGPL-3.0を含むということは、M5EPDだけでなくM5EPDに依存するソフトはすべてGPL-3.0で配布する必要がでてくるため、影響範囲が大きい。

CC BY-SA 3.0配布のソフトウェア

Button.hButton.cppCC-BY3.0SAの資料を改変したり、加工した場合には、同じくCC-BY3.0SAで配布する必要がある。CC-BY4.0SAはGPL-3.0に対して一方向の互換性があるが、CC-BY3.0SAには互換性はないので、上記のGPL-3.0と両立するのか不明。ちなみに、Arduino Button Libraryの最新版はGPL-3.0で配布されている。

GitHub - JChristensen/JC_Button: Arduino library to debounce button switches, detect presses, releases, and long presses

なお、CC-BY3.0SAをincludeしたコード(すなわち、GPLでいうところの「派生物」)はCC-BY3.0SAで配布する必要があるのか、私はよくわかっていない、、(CCはコードへの適用を想定していないのでグレーゾーンか?)

LGPL-2.1配布のソフトウェア

CommUtil.hM5Timer.h。他コードからincludeはされていない。なお、M5Stackライブラリは上記ファイルをincludeしている

M5Stack製品はハードの出来はものすごくよいと思うので、ソフトウェア周りも頑張ってほしいと思う次第である。

なお、私が公開しているM5Paper-Dashboardでは、自身でフォークしたM5EPDを使用している。

github.com

上記ファイルをすべて削除しているため、ライセンス的にはクリーン。ボタンにはezButtonライブラリを使用している。この影響で、ボタンに関するAPIが変わっている。また、画面描画にはLovyanGFXを使用することを想定し、もともとM5EPDに入っていた描画系コードも削除している。

中心力場における単一質点の軌道の可視化

最近、V.I.アーノルド「古典力学の数学的方法」を読んでいるのだが、かっこいい図があったので自分で描いてみた。

古典力学の数学的方法

古典力学の数学的方法

f:id:estshorter:20210202223752p:plain
円環の中、至るところ稠密な軌道

エディタのAtomみたいな画像である。 以下、どう上の画像を描いたかかの説明。

いま、平面上の中心力場(質点にはたらく力の向きが「原点から質点へ向かう単位ベクトルかその逆ベクトル」であり、力の大きさも原点からの距離のみに依存する場。例えば重力場。)における、質量1の質点の運動を考える。支配方程式は、

\displaystyle{
\ddot{\boldsymbol{r}} = - \dfrac{\partial U}{\partial \boldsymbol{r}}, \quad U=U(r)
}

である。この場合、原点からの距離 rは、次のポテンシャルエネルギー(有効ポテンシャルエネルギー)をもつ一次元の問題に従う。

\displaystyle{
V(r) = U(r) + \dfrac{M^2}{2r^2}
}

すなわち、

\displaystyle{
\ddot{r} = - \dfrac{\partial V}{\partial {r}} = - \dfrac{\partial U}{\partial r} +  \dfrac{M^2}{r^3}
}

である。 簡単にいうと、rは、有効ポテンシャルエネルギーVがなす「坂」を滑らかに転がったときの、地面に平行な方向への変位と同様に変化する。

また、今回のケースにおいては、極座標における角度\varphirは次の関係がある。

\displaystyle{
\dfrac{d\varphi}{dr} = \dfrac{M/r^2}{\sqrt{2(E-V(r))}}
}

ここで、Eは全エネルギー

\displaystyle{
E=\dfrac{\dot{r}^2}{2} + V(r) = \dfrac{\dot{\boldsymbol{r}}^2}{2} + U(r)
}

である。 したがって、ポテンシャルUの形状、Mおよび、Eを決めれば数値的に軌道 \boldsymbol{r}を求めることができる。なお、Uの形状によっては、軌道を解析に求められる。例えば、重力場 U(r)=-Gm/r)では円錐曲線が\frac{d\varphi}{dr}の式より導かれる。

ここまで説明してようやく画像の話に戻れる。 当該画像は、

\displaystyle{
U(r) = \dfrac{r^3}{2}, M=1, E=2
}

と設定したときの軌道である。 以下のPythonスクリプトにより、\frac{d\varphi}{dr}をRunge-Kutta45で積分して描画した。  \dot{r}=0のときに\frac{d\varphi}{dr}の分母が0になってしまいうまく計算できないので多少の誤差はある(U(r)=-1/rと設定し、楕円曲線からズレていくのを見ると明らかだ)が、 解析解は(多分)ないので仕方ないだろう。

from functools import partial

import matplotlib.pyplot as plt
import numpy as np
from scipy.integrate import solve_ivp


def U(r):
    return 0.5 * r ** 3


def V(r):
    return U(r) + 0.5 / r ** 2


def dphi(r, E):
    return 1 / r ** 2 * (1 / np.sqrt(2 * (E - V(r))))


r_min = 0.50842208660526406332007805917088124001667877021803
r_max = 1.5286429152095940020185327716896748970412268021517
E = 2

fun = partial(dphi, E=E)
r_eval = np.arange(r_min, r_max, 0.001)
sol = solve_ivp(lambda r_, phi: fun(r_), [r_min, r_max], [0], t_eval=r_eval)
phi = sol.y.flatten()
r = sol.t

ax = plt.subplot(111, projection="polar")
for i in range(26):
    ax.plot(phi, r, color="k")
    r = r[::-1]
    phi = 2 * phi[-1] - phi[::-1]

circle_phi = np.arange(0, 2 * np.pi, 0.01)
ax.plot(circle_phi, r_min * np.ones(circle_phi.shape), color="k")
ax.plot(circle_phi, r_max * np.ones(circle_phi.shape), color="k")
ax.axis("off")
plt.savefig("orbit.png", bbox_inches="tight", dpi=200)
plt.show()

ちなみに、最初の画像の軌道は「ドーナツ」の部分を稠密に満たす。以下は十分に時間がたった時(range(26*6))の、初期時刻からの軌道である。

f:id:estshorter:20210202233919p:plain
軌道の長期的な発展

M5PaperでNTPサーバの時刻をRTCに正しく設定する

M5Paper開発の際、NTPで取得してRTCに設定した時刻がたまにズレて困っていたが、configTzTime()を呼んだ後にsntp_get_sync_status()で同期状態を確認するようにしたら直った。sntp_get_sync_status()を紹介している日本語記事は見当たらなかったので、短いが記事にしておく。

最初は以下のようなコードを書いていたが、分・秒の値が狂うことがあり気になっていた。

configTzTime(tz, server1, server2, server3);
struct tm datetime;
if (!getLocalTime(&datetime))
    return 1; //error
//以下でRTCに時刻を設定

ググッてみたところ、esp-idfの公式リポジトリに答えがあった。sntp_get_sync_status()の戻り値が、SNTP_SYNC_STATUS_RESETでない(SNTP_SYNC_STATUS_COMPLETEDSNTP_SYNC_STATUS_IN_PROGRESSである)ことを確認すればよさげだ。

github.com

つまり、以下のコードとすればよい。

configTzTime(tz, server1, server2, server3);
struct tm datetime;
int retry = 0;
constexpr int retry_count = 50;
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count)
{
    delay(100);
}
if (retry == retry_count)
{
    return 1; //error
}
if (!getLocalTime(&datetime))
    return 1; //error
//以下でRTCに時刻を設定

ちなみに、上記のesp-idfレポジトリのコードはPublic Domainなのでコピペしても安心である。

dアニメストアの今期アニメ配信情報をGoogleカレンダーに登録する

しょぼいカレンダーにはアニメの放送日をGoogleカレンダーに表示できる機能があり、以前までは便利に使っていた。以前まで、と書いたのは、私は最近、録画派からdアニメ派に鞍替えしており、dアニメ視聴だと上述の機能が使えない*1ためである。 そこで、Golangで同様の機能を簡易に実装してみたというのが本記事の内容である。

成果物は以下のリポジトリにおいた。

github.com

これは、dアニメストア今期アニメ一覧ページの情報をスクレイピングし、指定したアニメの配信情報を表すiCalデータを作るプログラムである。iCalデータは手動でGoogleカレンダーに読み込ませることを想定している。アニメ一覧ページのURLおよび、アニメタイトルの指定はconfigs.jsonで行う。configs.jsonの場所は下記のようにコマンドライン引数で与える。指定しない場合には、カレントディレクトリのものが読み込まれる。

danime-ical.exe PATH_TO_CONFIGS_JSON

生成されるiCalファイルの例は以下の通り。クールの初めの月(冬アニメだったら1月)の最初の配信曜日から、毎週の配信予定が記述されている。アニメの話数は13話を想定。

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Arran Ubels//Golang ICS library 
METHOD:REQUEST
BEGIN:VEVENT
UID:のんのんびより のんすとっぷ
DTSTART;TZID=Asia/Tokyo:20210101T010000
DTEND;TZID=Asia/Tokyo:20210101T013000
SUMMARY:のんのんびより のんすとっぷ
RRULE:FREQ=WEEKLY;COUNT=13
END:VEVENT
END:VCALENDAR

クールの始まり終わりあたりは不正確な可能性もあるが、ひとまずはこれで十分だろう

*1:しょぼいカレンダーにはdアニメでの配信日時が登録されていないため

PlatformIO + ESP32をC++14 (or C++17)に対応させる

※21/04/17現在の情報です。

M5Paperを開発していたところ、ちゃんと設定しないとC++14以上の機能が使えなかったのでメモ。

PlatformIO + ESP32環境をC++14に対応させるには、platformio.iniに以下を設定すればよい。

build_flags = 
  -std=gnu++14
build_unflags =
  -std=gnu++11

M5Paper向けにiniを全て書いた例はこんな↓感じ。

github.com

なお、2021/1/7現在、PlatformIOでESP32を指定した際にインストールされるGCCのバージョンは5.2であり、%HOMEPATH%\.platformio\packages\toolchain-xtensa32\bin\xtensa-esp32-elf-g++.exeにインストールされている。また、-std=gnu++14でなく-std=gnu++17と指定してもよいが、 以下のコンパイラ実装状況ページによれば、GCC5.2ではC++17の機能はほぼ使えないようだ。

cpprefjp.github.io

C++17を使いたい場合には、toolchain等を最新版に更新する必要がある。具体的には、Windowsで開発する場合、以下のようにplatformio.ini を設定する。

platform_packages =
    toolchain-xtensa32 @ ~2.80400.0
    framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git
build_flags =
    -std=gnu++17
build_unflags =
    -std=gnu++11

toolchain-xtensa32に関しては、以下のページから最新版(と思われる)を指定した。GCC 8.4がインストールされる。

platform-espressif32/platform.json at feature/arduino-idf-v4.2 · platformio/platform-espressif32 · GitHub

また、framework-arduinoespressif32に関しては、ESP-IDFに最も追従していると思われるidf-release/v4.2ブランチを指定している。

上記のm5paper-dashboardリポジトリC++17設定を試してみたところ、LovyanGFXライブラリでいくつかのコンパイルエラーが出た。足りないヘッダファイルをincludeするだけでコンパイルは通るようになったが、FastLEDライブラリで多数の警告が出たりと、安定はしていないようだ。

ちなみに、framework-arduinoespressif32をバージョン指定なしでいれると、ESP-IDF v3.2がインストールされる1。最新版はESP-IDF v4.2であるから、かなり古いバージョンだ。 サポートも2020/10に切れている。

追記

LovyanGFX、FastLEDでのコンパイルエラー、警告に関してはプルリクを出し、無事マージされた。

追記2

21/3/1現在、platform.iniでflashパーティションを明示的に設定しないとflashの容量が正しく反映されない。

board_build.partitions = default_16MB.csv

210218追記

toolchain-xtensa32の設定を修正。bintray閉鎖の影響?

210330追記

toolchain-xtensa32, framework-arduinoespressif32のバージョンを指定するのでなく

platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-idf-v4.2

としてプロットフォームのブランチを指定するだけでいけそう。ただし、platform-espressif32のdevelopブランチよりコミットが遅れてるかも。

210417追記

framework-arduinoespressif32のgitのアドレスを変更し、idf-release/v4.2ブランチ指定を消した。 同ブランチが削除されたため。

参考

community.platformio.org


  1. %HOMEPATH%\.platformio\packages\framework-arduinoespressif32\tools\sdk\include\config\sdkconfig.h の最後あたりの記述から分かる