ワタタツの日記
2022 年 12 月 30 日 (金)
☆ Linuxカーネルの関数の書き方が変わっていたので対応した
LinuxカーネルのPCI関係のモジュールに使っていた関数の書き方が変わっていたので対応しました。
具体的には次のAPIが無くなっていました。
- pci_alloc_consistent
- pci_free_consistent
- pci_set_dma_mask
遅くとも Linux 6.1.0 にはもうありませんでした。実際にはもう少し前から無くなっていたようです。以前までは pci-dma-compat.h に入っていたようです。
Christophe JAILLETさんの Remove usage of the deprecated "pci-dma-compat.h" API という投稿によるととっくにdeprecatedだったようです。を見ます。ここにいくつかのドライバのパッチもあたっているので、どう書き換えればいいのかわかりました。
書き換え方
関数の名前は、
- pci_alloc_consistent は dma_alloc_coherent に
- pci_free_consistent は dma_free_coherent に
- pci_set_dma_mask は dma_set_mask_and_coherent に
それぞれ変更します。
次に、どの関数も、第1引数を p
とすると &p->dev
に変更します。
dma_alloc_coherent だけは、第4引数として GFP_KERNEL
を追加します。
成功
以上でコンパイルも通りました。カーネルにロードして少し使ってみたところ正常に動いているようでした。
2022 年 12 月 9 日 (金)
☆ consult.el の非同期コマンドの仕組み
このエントリはEmacsのAdvent Calendar 2022の9日目用です。
以前の記事「はてなブックマーク用のconsultコマンドを作っている」で書いた consult-hatena-bookmark を改良するにあたり、今年夏から秋にかけて、(自分としては)かなり consult.el のコードを読みました。
そのコードリーディングの中で、consult.el が非同期な候補の読み込みをどうやっているのか、だいぶわかったのでご紹介します。
公式で非同期で読んでいる consult コマンドのまねをしたい
公式で用意されている consult コマンドの中で、候補を非同期で読んでいるタイプのものは次などがあります。
- consult-grep
- consult-ripgrep
- consult-man
- consult-find
コマンドを実行してからプロンプトを表示しながら、入力するたびに、検索的なことが非同期に実行されて、その結果を受けとりながら、インクリメンタルに候補を表示します。
はてなブックマークの検索でも、同様の非同期検索体験が実現できるととても快適になると思うので、どうしても非同期に読み込む方法を理解して実装したかったです。 (2021年の初期バージョンでは、同期的に検索して結果を表示していました)
これらの非同期な consult コマンドは全部 consult--async-command
を使っていました。これが鍵です。
consult--async-command
consult.el は基本的に consult--read
関数に候補のリストを渡して使います。
静的な候補を絞り込みたい場合は、候補のリストをそのまま consult--read
の第1引数に渡します。
一方、非同期に候補のリストがどんどん更新されるようにしたいときのために consult--async-command マクロが用意されています。
consult--async-command を使えば作れそう……と思ったのですが、これは、さらに consult--command-builder
なる、(UNIX的な意味での)コマンドのビルダを渡して、またさらに consult--async-process
で非同期に(そのコマンドの)プロセスを起動するという使い方をされています。
今使いたいはてなブックマークの検索はweb APIであって、ローカルのコマンドではないので、これではだめです。(前回の初期バージョンでは w3m コマンドを使ってブックマーク検索結果を取得していたので、この外部コマンドを使う方法でいけたかも知れませんが、もう w3m ではログインできなくなったのでweb APIにしました。) (UNIX的な意味での外部コマンドの結果を consult.el で絞り込みたい非同期 consult コマンドを作る場合は、そのまま consult--async-command を使えばできると思います。)
consult--async-command みたいなのの web API を叩く版を作る!
というわけで consult--async-command の中身のコードちゃんと読んで、外部コマンドを叩こうとしているところを、必要な処理に置き換えることにしました。
というわけでコードリーディングはまだまだ続きます。
つまり consult--async-command の中身です。ここが今回わしが 一番面白さを感じたところ です。
thread-first
から始まって、(consult--async-sink)
、(consult--async-refresh-timer)
、終わりの方では (consult--async-throttle)
、(consult--async-split)
などと、consult--async-系の単独の関数がどんどん並んでいます。
thread-first
マクロは、「前の結果(出力)を次の関数の第1引数に入れる」ことを繰り返して1本のスレッドのようにつなげていく書き方ができるマクロです。ちなみに thread は英語の単語で、糸という意味です。
「次の関数」は第1引数を省略した形で書いておきます。そこだけ見ると不完全なように思えますが、thread-first
の中ではその書き方でいいわけです。オードリーの春日が「春日のここ、空いてますよ。」と言うような感じです。(「春日のここ」が第1引数ではなく、最終引数になったバージョンの thread-last
マクロもあります。)
ヘルプに載っている例がわかりやすいです。
(thread-first
5
(+ 20)
(/ 25)
-
(+ 40))
は (+ (- (/ (+ 5 20) 25)) 40)
と同じことだと書かれています。
最初の 5
が (+ 20)
の第1引数に入力されます。第1引数は省略された形として評価されるので 20
は第1引数ではなく第2引数です。つまり春日のここは (+ 春日のここ 20)
です。
(thread-first
(foo)
(bar a b)
(baz c d e)
(qux f)))
を図解してみます。
これがこの非同期のためにぴったりなんです!
まず (consult--async-sink)
で非同期用のジェネレータ、いわゆる非同期 sink 関数を作って返します。
consult--async-sink
のドキュメント文字列に書かれているように、これが返す sink 関数は、次のように引数 action
を受け取って動くようになっています。
'setup
が引数の場合、セットアップして nil を返す。'destroy
が引数の場合、状態を壊して(やり直す感じ)、nil を返す。'flush
が引数の場合は、ためていた候補をまっさらにして (flush) nil を返す。'refresh
が引数場合、(consultの)UIをリフレッシュして nil を返す。- nil が引数の場合、Return the list of candidates.
- リストが引数に来たら、今ある候補のリストに追加してそのリストを返す。
- 文字列が引数に来たら、現在のユーザが入力している文字列を更新して nil を返す。
この仕様に沿っている関数を、thread-first
でどんどん次の関数に渡しながら、「ご所望」の関数になるようにちょっとずついじっていき ます。面白いです。
例えば consult--async-refresh-immediate
は、候補が追加されたらすぐにUIをリフレッシュするように、いじります。
consult--async-throttle
は、スロットルします。web APIを使うときなんかは特にそうですが、同じ入力文字列(プロンプトで入力中の文字列です)が入っているときに、何度も同じ検索を流したくないです。そういうときに使えます。
consult--async-split
は後述しますが、‘#’ 記号を挟んで検索絞り込みを外とローカルで分けてくれる超便利関数変更関数です。
このように consult.el では、自分のちょっとの仕事だけをうまくやる小さい関数を組み合わせて全体の機能を作り上げていく書き方がされていることがわかりました。UNIX哲学〜ですね。
今回は、 consult-hatena-bookmark--search-generator
という関数を作ってみました。 https://github.com/Nyoho/consult-hatena-bookmark/blob/b85484b11705ebd896878d3ac7fdb12bc8c9637a/consult-hatena-bookmark.el#L205-L211
コードがかなり consult--async-command
と似ていますが、外部コマンドを呼ぶ処理ではなく (consult-hatena-bookmark---async-search)
が真ん中あたりに挟まっています。
ここで、必要な引数が来たときだけ、特に、文字列が来たときには、実際のはてなブックマーク検索をする consult-hatena-bookmark--search-all 関数が走るようにしました。
さらに工夫したところ、工夫できなかったところ
さらに今回はその中で async/await, promise が使える async-await を使っています。web API の1回分の問い合わせの結果を await して受け取ることに使いました。(追記: async-awaitパッケージという名前ですが、今回のconsult.el自体の非同期の仕組みのことではありません。)
さらに、念願のページネーション的な取得も実装しました。つまり最初は20件だけ取得しておいて、検索結果が20件より多い場合は、オフセットをずらしながら何度もAPIを発行して全件を取得するというものです。
このままでは、途中で検索ワードを変更した場合や、consult-hatena-bookmark コマンドを終了/キャンセルしたときに、全件取得のルーチンが動きっぱなしなってしまうので、 consult-hatena-bookmark--stopping
という変数を作って、これが nil のときには検索を止めるようにしました。グローバル変数っぽくてかっこわるい実装なのかも知れませんが、どうしてもいい方法が思いつかなかったので、この変数を用いることにしました。いい方法がありましたらお教え下さい。または pull request をいただければ嬉しいです。
consult での絞り込みの好きなところ
ここで consult での絞り込みの好きなところをご紹介します。
consult--async-split
による機能です。
それは ‘#’ 記号です。
M-x consult-hatena-bookmark
してプロンプトが出てくると、キーワードを打ちます。emacs とか。ここでマイはてなブックマークの検索の外部通信が走ります。
それに続けて ‘#’ 記号を1発入れて、さらに文字列を打ち込みます。29 とか。合わせて「emacs#29」が打ち込まれたところです。
そうすると、
- ‘#’ の前は、web APIで取得する外部のデータへの問い合わせ
- ‘#’ の後は、前者で得られたデータを絞り込むための文字列に!
これです! これがすごくいいです。
APIで検索する文字列(この段階で自分のブックマークから絞り込まれています)、さらにそれをローカルで絞り込むという、2段階の絞り込みが1行でできてしまいます!
ここ好き
コードリーディングの感想
Lisp万年初心者としてはかなり頑張ってコードリーディングし(て自分のコードを書き)ました。感想としましては、非同期処理のために、何か特別な別プロセスなどがあるわけではなくて、とにかく関数を関数に食わせてどんどん関数をいじって関数だけでなんとかしようとしているところが、とても関数型プログラミングっぽいなあと思ったりしてグッときました。以前の自分よりはちょっとだけLispが読めるようになった気もしました。この調子でもっとLispの面白さを学んでいきたいです。コナミ環。
2021 年 12 月 25 日 (土)
☆ はてなブックマーク用のconsultコマンドを作っている
これはemacs Advent Calendar 2021の25日目の記事です。
minad氏による、Emacsの最近のパッケージの一つ、consultをすごく気に入ったので、自分のはてなブックマークを検索するパッケージを書いています。
https://github.com/Nyoho/consult-hatena-bookmark
です。
はてなブックマーク
はてなブックマークはソーシャルブックマーキングサービスです。
ソーシャルなので、ブックマークするときだけでも他の人のコメントを見て勉強になります。
そんな一期一会な使い方も面白いですが、ストックしていくものとしても便利です。そこで欲しくなるのが「自分のブックマークを全部検索する」機能です。実は、サイト上でもできます。これがEmacs上でもすばやくできたら楽だし楽しいなと思います。
counsel用のものは途中まで書いた
昨年 (consult ではなく) counsel 用のコマンド counsel-hatena-bookmark は書いていました。しかし、非同期的に読むところがまだうまく書けてなくてそのままになっていました。 そして放置しています。
それは置いといてconsult用で書いてみようと思って書き始めたところ、非同期的なところが割と簡単に書けました(気がします)。と言っても「結果が多いときに繰り返し読む」機能はまだ書けていません。
歴史と問題と全文検索API
実装に関係するので先行研究(事例)をご紹介します。
おそらく歴史的にはまず、anything用の anything-hatena-bookmark がありました。その後にhelm用の helm-hatena-bookmark がありました。わしもどちらも使っていました。
このどちらの実装も、はてなブックマークの自分のブックマークをダンプしたものを定期的に(または手動で) 全部 取得しておいて、それをローカルで串刺し検索するというものでした。
しばらくは楽しく、便利に使っていたのですが、
- このダンプするURLがすごく重い
- ブックマークが数万を超えてくると以前のものが取得されない
という問題がありました。
そんな中(わしが)見付けたのが、マイブックマーク全文検索APIです。
これはその都度クエリを投げて返答をもらうAPIで、定期的にローカルにダンプしておく必要がありません。そのため、今ブックマークしたばかりのブックマークもひっかかります。(anything/helm用の上の実装では、その前に重たい手動ダンプが必要です。)
また、このAPIは、そのページのタイトル、ブックマークコメントだけでなく、ページの本文にもヒットする仕様になっています。これが便利なときがあります。(便利ではないときもあります。)
そんなわけで、 dump v.s. API で、後者の全文検索APIを使う方法をとることにしました。(counsel用のものも同様の方針にしています。) これならブックマークが数万を超えていても安心ですし、いつでも最新のブックマークが検索できます。
実装
consultのいろいろなコマンドの実装のソースとにらめっこしながら少しずつ作っていきました。
基本的には consult--read
関数がメインです。これに絞り込みたい候補を突っ込みます。そうするとプロンプトの上で絞り込みが行えます。オプションが色々付いていて、ヒストリを作ったりできます。
ログインはw3mにまかせる
工夫したところの一つはw3mを使ったことです。
はてなブックマーク全文検索APIを使うのにログインが必要です。 ログインの認証コードやクッキー保持などを書くのは(わしには)大変そうなので、外部コマンドのCUIブラウザであるw3mにおまかせしました。
そうすると、consult--async-command
で外部コマンドとして w3m でAPIにアクセスするものを呼び出して、結果をJSONテキストでゲットし、あとはEmacsで処理するだけにできます。
JSON解析は27.1の新機能を使ってみた
ゲットしたテキストのJSONデータを実際のJSONオブジェクトにするには、Emacs 27.1で導入された新関数 json-parse-string
を使ってみました。ビルトインの関数なので高速に解析してくれると評判(?)です。
これでパースしてEmacsのリストにします。
リスト項目にpropertize
ブックマークは、タイトル、URL、ブックマークコメント、日付という様々な要素があります。これが結果のリストの項目です。
これをconsultでうまく受け取るために、文字列本体は
format
した文字列にしました。これで割と整頓して表示できました。(これでいいのかな)
これだと絞り込んだ後のURLが表示用のこの文字列になってしまうので、 propertize
で 'consult--candidate
というキーに URLを値として付与しました。
こうしておいて、 consult--read
の :lookup
に :lookup #'consult--lookup-candidate
としておくと、 このキーの値を返してくれるようになりました。表示用と実際の値をこのように分けることができたのでした。(これでいいのかな)
未来。今後の課題
以上で一旦公開までこぎ着けましたが、まだまだ課題があります。
MELPAかどこかに登録したい
せっかくなのですぐに使ってもらえるように、MELPAかどこかに登録したいです。
「結果が多いときに繰り返し読む」機能
APIでは、ディフォルトでヒットした最初の20件が返ってきます。本当はもっと多いときは、オフセットを指定して何度も問い合わせることで全件を取得できます。まだその機能は付けていません。どう書けばいいかまだわかっていないからです。わかる方は、どうかお教え下さい。🙏
Embarkへの受け渡し
今は絞り込み中に Embark を起動して、URLなので例えば eww に渡すとかしても、表示用の文字列が渡ってしまいます。ちゃんとURLはURLとしてEmbarkに渡したいです。こうするにはどうすればいいかまだわからないので、後回しにしています。 これもわかる方、是非ともお教え下さい。🙏
marginalia対応した方がいいのか
というかそもそもformatで自分で整形するより、そういうのはmarginalia対応してうまいこと日付とか表にしてもらった方がいいのではないだろうか、などと思うけど、maginaliaのことがよくわかっていないのでまだわからない。理解したい。
結論: 楽しい
ともかくこれで楽しく自分のブックマークを全文検索できるようになりました。Happy social bookmarking!
追記
はてなへのログインがJavaScript必須になってしまって w3m でアクセスする方法ではできなくなりました。
他の方法を模索中です。→WSSE認証にしました (後で書く)
2021 年 9 月 12 日 (日)
☆ PyCharityでの広島コミュニティの発表をきっかけにして電子工作に入門できた #PyCharity
昨日 2021年9月11日(土) Python Charity Talks in Japan 2021.09 というイベントにすごい広島 with Pythonチームのメンバとして出ました。
出て得られたことのまとめ
- 電子工作初心者だったわしが、電子工作に入門できた。
- 広島のすごい広島 with Pythonコミュニティによって、電子工作・Pythonに精通した人たちから一歩一歩学ぶことができた。
- 「ソフトウェアは趣味でずっとやってきたので少しは書けるが、ハードウェアは全くできない」という複素数、あ違った、コンプレックスが解消できた。
- 「0が1に」なった実感。急に自分が手を下せる世界が広がった。
- 普段生活しているときに、「あれ、これってこうやったら作れそうじゃないか」という視点で生活できるようになったと感じる。
- 0の状態をレベル1にすることは本当に革命的だ。
当日の録画と提示資料
当日のYouTubeの録画はこちらです。
(広島チームの出演部分から再生が始まるようにしているつもり(30分))
わしの電子工作入門の発表部分 (およそ5分) へのジャンプもどうぞ。
スライドはこちらです。途中本番では動画が流れています。
今回の Python Charity Talks の構造
Python Charity Talks 自体は、日本のPythonコミュニティが PSF (Python Software Foundation) に寄付をするために開催されているイベントです。(わしも Python は、主に Python や Julia を使っているときに使っているので、日頃の感謝を込めて喜んで参加費を支払いました。) これまで何度も開催されています。
今回は日本のPythonコミュニティから4地域が発表するという構造でした。飛騨高山、駿河・静岡、山梨、広島です。コミュニティ活動と技術という2面から話が聞けるというものになっていました。
その地域のコミュニティの一つとして、広島からはすごい広島 with Pythonが出演しました。すごい広島 with Python チーム全体で「これから始める電子工作とMicroPython」というテーマにしました。
すごい広島 with Pythonチームでは4人が出演、わしはそのうちの一人として出ました。
すごい広島チームでのわしの立ち位置とわしの出演経緯
すごい広島 with Pythonのわし以外の3人は、電子工作が中級・上級者です。まとめ役のにしもつ(@24motz)さんなんかは子供の頃から電子工作をされていたそうで、コンピュータ・電子工作の歴史も40年見てこられていて、技術的にもベテランです。
初めににしもつさんがこのPython Charity Talksの話を受けられていたときに、コミュニティ内 (PyCon広島のSlack) で「誰か一緒にしゃべりませんかー」と呼びかけられました。
わしは、電子工作は、いつかやりたいことの一つでしたので、「よしよし電子工作初心者としての視点を持って、聞き手として参加し、あわよくばこの機会に入門してみよう」という魂胆を抱きました。魂胆です。
早速にしもつさんに、初心者のマインドを持った聞き手として参加したいと名乗り出ました。その後むじん(@mu2in)さんとさんのみや(@sn3y2)さんが、実践者として名乗りを上げました。
電子工作の聞き手として
電子工作の「初心者視点での」聞き手として、本当に何もわからない状態から、初心者としてやってみた状態になることを目指しました。そうすることで本当に初心者が何がわからないかや、何に困っているのかがわかると思ったからです。
そのために「電子工作何もわからん」状態から一歩踏み出そうとしました。「電子工作何もわからん」の内訳はこちらです。
- 何を、どのパーツを買ったらいいのかわからない
- 買ったとしてもどう繋げばいいのかわからない
- プログラムをどう書けばいいのか
(↓当該スライドをページ指定して表示)
幸いわしは日曜プログラマなのでソフトウェア部分はある程度ならわかります。そこで、最初の二つについて、にしもつさんに課題を出してもらうことにしました。
- わし「僕が素人の視点で感想を言うので、そろそろ初心者入門向けとしてこの辺を買ってやっといてくれという課題をぶっ込んでください。」
- にしもつさん「じゃあ Raspberry Pi Pico で Lチカ を最初の目標にしましょうか。安いし流行ってるし技適の心配がないし」
なるほど!
ということで Raspberry Pi Pico と、LEDチカチカするための他のパーツを何を買えばいいのか、引き続きPyCon広島のSlackで聞きながら調べました。
このスライドではコピペしにくかったりしますので買ったもののリストを紹介しましょう。
買ったものとリンク
秋月電子通商で次を購入しました。
- Raspberry Pi Pico ベーシックセット
- ブレッドボード EIC-801
- ミニブレッドボード BB-601(白)
- マイクロサーボ9g SG-90
- 小型圧電振動ジャイロモジュール
- KXTC9-2050使用3軸加速度センサモジュール
- ブレッドボード・ジャンパーワイヤ(オス-オス)セット 各種 合計60本以上
- はんだごて FX600-02
- 細ピンヘッダ 1×20
- 有機ELディスプレイ 0.95インチ 96×64ドット RGB
- 0.96インチ 128×64ドット有機ELディスプレイ(OLED) 白色
- はんだこて台 ST-11
- はんだ吸取器 GS-108
- CdSセル(1MΩ)GL5528(4個入)
- 電池ボックス 単3×2本 リード線・スイッチ付
- 抵抗いろいろ (今思えばもう少し大きい抵抗値の抵抗も買えばよかったです)
- LEDいろいろ (安いのでいろいろな色を適当に混ぜました)
作例サイトを教えてもらう
作例サイトをいろいろ教えてもらいました。「単一のパーツを付けた動かすだけ」のようなものを教えてもらったところがポイントです。これで一歩一歩試すことができました。
- Raspberry Pi Picoで最初の一歩、Lチカしてみよう! – ツクレル Raspberry Pi を使ったテクノロジー学習 LEDチカチカ、通称Lチカ
- 【Raspberry Pi Pico】サーボモーターをPWMで動かす【MicroPython】 | メタエレ実験室 サーボモータ
- ラズパイでAD変換!Picoでアナログ入力してみた
- 【Raspberry Pi Pico】電池駆動での動作実験 | メタエレ実験室 OLEDディスプレイ
- 【Raspberry Pi Pico】OLEDディスプレイ(I2C)に文字を描画する方法【MicroPython】 | メタエレ実験室
- MicroPython的午睡(24) ラズパイPico、CDSセンサをADCに接続 | デバイスビジネス開拓団 CdSセンサで明るさを取れました。暗くなると反応するものが作れました。これで踏切が作れます。
これだけでも十分入門できました。
初めてのはんだ付け
はんだ付けも初めてです。Raspberry Pi Pico やセンサにピンヘッダという部品をつなげるために、はんだ付けをしました。これでブレッドボードというボードに「線を好きに刺して実験」することができます。そうでないと、直接パーツを線でつないだりしないといけないんだと思います。それは大変です。ブレッドボードがこういう実験には必須だと思います。
はんだ付けをミスったりやり直したいときには、はんだ吸い取り器を使います。動画ハンダ吸取器の使い方LED工作 (YouTube) が参考になりました。
プログラムをどう入れるか
Raspberry Pi Pico にまず MicroPython を入れます。
- Raspberry Pi Pico のUSBからパソコン(わしはMac)のUSBと繋ぐ。
- https://www.raspberrypi.org/documentation/rp2040/getting-started/#getting-started-with-micropython から UF2 ファイルをダウンロードして書き込み (マスストレージになっているところにファイルを放り込めばいい)
(失敗した場合は Raspberry Pi Pico の BOOTSEL ボタンを押しながらUSBに差し込むとまたマスストレージモードでマウントされます。)
MacにはThonnyという開発環境を入れました。
- Homebrew なら
brew install thonny
でOK。 - Thonny.app で右下メニューから "MicroPython (Raspberry Pi Pico)" を選択する
ちなみに、完全におかしくなったら flash_nuke.uf2 をダウンロードしてきて書き込む。そうするとまっさらなRaspberry Pi Pico になります。初めて次の中国語のブログが役に立ちました! 分享科技與遊戲 by HKGoldenMr.A: 解除死鎖狀態的 Raspberry Pi Pico (Google翻訳で読んだ)
自分でいじってみる
作例をいじったり、自分で組み合わせたりしてみます。
サーボモータで楽器
安いサーボモータである SG90 (400円) 側の
- 黄を1(GP0)へ
- 赤を40(VBUS)へ
- 茶を38(GND)へ
接続して次のプログラム
from machine import PWM, Pin
import utime
import random
servo = PWM(Pin(0))
servo.freq(50)
max_duty = 65025
deg_m90 = 0.025 # -90 deg
deg_0 = 0.0725 # 0 deg
deg_p90 = 0.12 # +90 deg
def rot(deg):
servo.duty_u16(int(max_duty*((deg/90.0)*(deg_p90-deg_0)+deg_0)))
basetime = 0.2 # [sec]
def p0():
utime.sleep(basetime*4)
def p1():
utime.sleep(basetime*2)
def p2():
utime.sleep(basetime)
while True:
rot(0.0)
p1()
rot(-45.0)
p2()
rot(-90.0)
p2()
rot(-45.0)
p1()
rot(0.0)
p0()
rot(45.0)
p1()
rot(90.0)
p0()
を動かすと、楽器ができました!
なんか楽器でキタ━━━━(゚∀゚)━━━━ !!!#RaspberryPiPico pic.twitter.com/qtPalCOeid
— 線型空間の基底大好きbot (@NeXTSTEP2OSX) August 20, 2021
さらにマラカスを付けてみました。
やった! 楽器をさらに改良して、自動 #東出 応援装置ができた!#はじめての電子工作 #RaspberryPiPico #サーボモータ #マラカス pic.twitter.com/IG4MRuqnqi
— 線型空間の基底大好きbot (@NeXTSTEP2OSX) August 23, 2021
面白い!
今まで何十年も趣味でソフトウェアは書けましたが、物を思いのままに動かせたのはこれが初めてです!!!!! 感動!!!!! この動き自分で作ったんよと言える!!!!!
マラカスはこのようにプログラムを書いてみました。
from machine import PWM, Pin
import utime
import random
import math
led = machine.Pin(15, machine.Pin.OUT)
servo = PWM(Pin(0))
servo.freq(50)
max_duty = 65025
deg_m90 = 0.025 # -90 deg
deg_0 = 0.0725 # 0 deg
deg_p90 = 0.12 # +90 deg
def rot(deg):
servo.duty_u16(int(max_duty*((deg/90.0)*(deg_p90-deg_0)+deg_0)))
# hit
preparation_duration = 0.17
def h(duration):
led.value(0)
for i in range(10):
rot(90 - i/10*45)
utime.sleep(preparation_duration/10)
rot(90)
led.value(1)
utime.sleep(duration - preparation_duration)
b = 60/144
led.value(0)
while True:
h(2*b)
h(2*b)
h(b)
h(b)
h(2*b)
3軸加速度センサとOLEDディスプレイ
OLED (有機発光ダイオード) ディスプレイも、モノクロとカラーの2種類買うてみました。加速度センサが使えるとこのように、手を回してディスプレイに立方体を回転させることができます。3次元の数学を使えばどのように線分を描けばいいか計算できます。この辺はiPhoneで加速度センサを使ってプログラミングしているのと同じことですね。
しかし、今は、ディスプレイも、加速度センサも自分で買ってきたパーツを取り付けて配線しているのです! これが大きな違いです。
発表には入れてないですが、加速度センサとOLEDディスプレイを組み合わせればこんなのも作れます。当たり前ではありますが、自分で組んで、自分でプログラムを書いているので、楽しいというメリットがあります。 pic.twitter.com/pgMTeMN8KF
— 線型空間の基底大好きbot (@NeXTSTEP2OSX) September 12, 2021
3軸加速度センサとサーボモータで機械学習の強化学習のQ学習
発表で紹介したのは、3軸加速度センサとサーボモータを組み合わせて、機械学習の強化学習のQ学習をしてブランコの揺れを強化学習してみようというものです。
今まで機械学習はソフトウェアの上でしかやったことがありませんでした。単なる思いつきですが、「何らかのセンサ」と「動かすもの」があれば、機械学習を実物でできると思いつきました。やってみた様子は当日の録画をご覧ください。
ソフトウェア的にやっていることは大して違いがありませんが、機械学習に便利な numpy や PyTorch が使えないので、float の list だけで書いていくのがこれはこれで楽しかったです。
終わり
というわけで、ソフトウェアしか作れなかったのがちょっと広がりました。きっかけとなった Python Charity Talks と、入門として一歩一歩やらせてもらえた広島のコミュニティの皆さんに感謝です。
2021 年 9 月 3 日 (金)
☆ Fact checks
Vaccinated People Found to be 600% More Likely to Die from Covid 'Variants' than Unvaccinated People などに対するファクトチェック記事は次などにあります。
2021 年 9 月 1 日 (水)
☆ いわゆるusr mergeに遭遇し、乗り越えた
Linuxのファイル群が /bin
や /sbin
になっているものを /usr/bin
や /usr/sbin
に書き換えていこうという変更を usr merge または UsrMerge と呼ぶようです。
https://en.opensuse.org/openSUSE:Usr_merge
最近この動きを知らずに一部のパッケージをアップデートしたときに整合性がとれなくなって当たって往生しました。メモしておきます。
openSUSEでzypper upしたらログインできなくなって気付いた
openSUSEでzypper upして一部のパッケージをアップグレードしたところ、ログインできなくなってびっくりしました。 login incorrect "Module is unknown"
です。最初は何が起きているのかわからなかったのですが、
PAM unable to dlopen(/lib64/security/pam_keyinit.so): /lib64/security/pam_keyinit.so: cannot open shared object file: No such file or directory
というエラーが出ていることに気付きました。 /lib64
も usr.merge されて /usr/lib64
になろうとして、一部が整合性が取れない状態になっていたようです。
Mailing List
ググるとopenSUSEのメーリングリストでこのことが話し合われていました。
アップグレードの途中で /bin
や /lib64
にあるはずのファイルが見えなくなってこけるので、 zypper dup
(distribution upgrade) する前に 一旦 zypper dup -l --download-only
するとかいろいろな技が書いてありました。(ちなみに最終的にどうやったのか忘れました(笑))
転ばぬ先のスナップショット (バックアップ)
この復旧作業をするときに何度か元に戻す作業をしました。
ここ数年はbtrfsで毎日スナップショットを取るようにしているので、リストアするのが非常に楽でした。スナップショットは1つのディレクトリのディレクトリがコピーされているように見えるので、一旦rescueメディアで立ち上げてマウントして、単なるディレクトリに見えるスナップショットからがばっとコピーするだけで何とかなります。
スナップショットはとても軽量で、ほぼ一瞬で行われます。実際にファイルの内容をコピーしまくるのではないので、とても気楽です。
2021 年 6 月 15 日 (火)
☆ consultをmigemoizeしたい (未完→だいたいできた)
consultがとてもいい感じなので @rocktakey さんのivy-migemoでcounsel系をやるようにmigemo化したいです。 まずは調査調査。
ちなみに、consult, vertico, orderless, embark などの便利な組み合わせの紹介についてはとんさんのEmacsの次世代ミニバッファ補完UI | 日々、とんは語る。がおすすめです。
ivy
まずivy-migemoがなぜ適用できるかで、counsel系に使われている ivy-read
関数を見てみます。
https://github.com/abo-abo/swiper/blob/040d458bce4a88f37359192061bcea5ebe87007c/ivy.el#L2019
re-builder
というのが設定できるようになっていて、入力したクエリをさらに関数でいじることができます。
ivy-migemo では ivy-re-builders-alist
に (counsel-hogehoge . ivy-migemo--regex-plus)
などと ivy-migemo--regex-plus
を突っ込むことで各種 counsel-*
の :re-builder
に渡ってきます。
consult
一方 consult系はどうなっているでしょうか。 ivy-read
にあたるものはたぶん consult--read
とそのマルチ版 consult--multi
です。
- consult--read: https://github.com/minad/consult/blob/9e34c679a2bc39cd167a7226568dfac5b2193292/consult.el#L1794
- consult--multi: https://github.com/minad/consult/blob/9e34c679a2bc39cd167a7226568dfac5b2193292/consult.el#L1958
それで、こ consult--read
と consult--multi
には re-builder
にあたるものが、 なさそう ということまで調査しました。
現状
根元の関数 | re-builder(っぽいもの) |
---|---|
ivy-read | ある |
consult--read | ない |
という感じです。 ( ˃ ⌑ ˂ഃ )
追記: 2021-06-16
だいたいできました。 emacs-jp の Slackで orderless のソースでも読んでみようかと書いていたら、なんと orderless そのものから忍び込めることを教えていただきました。
orderless は、標準の completion-category-overrides
を定義すればカテゴリごとに補完スタイルを設定できるように作られています。標準のものを使うようにうまく出来ていますねえ。
カテゴリというのは metadata として提供されていて Emacs 28 からはたくさんついており、27以前は marginaliaが頑張ってくれるみたいです。
そこでまず command カテゴリに設定する例を教えてもらい、ちゃんと動くことがわかりました。
あとはどのコマンドがどのカテゴリで実行されるのかを調べればだいたい良いということがわかりました。
ソースコードリーディングをしたところ、次のことがわかりました。
コマンド | カテゴリ |
---|---|
execute-extended-command (M-x) | command |
find-file | file |
consult--multiを呼ぶコマンド (consult-bufferなど) | consult-multi |
consult-lineなど | consult-location |
あとは最近使っている org-roam の org-roam-find-file
はどのカテゴリになっているのかがわかりませんでした。
なんとなく marginalia を見ていたところ marginalia-prompt-categories
という変数にいろいろカテゴリが書いてあることがわかりました。
なんとプロンプトに書いてある文字列にヒットしてカテゴリを設定してしまおうというもののようです(たぶん。たぶんね。)。なので、
(add-to-list 'marginalia-prompt-categories
'("\\<File\\>" . file))
と設定しました! すると動きました! org-roam-find-file
のプロンプトには "File" と出ているからです!
勝ちました!
勝った様子
(leaf consult
:ensure t
:bind* (("M-m" . consult-buffer))
:bind (
("M-s" . consult-line)
("M-g ." . consult-ripgrep))
:config
(autoload 'projectile-project-root "projectile")
(setq consult-project-root-function #'projectile-project-root))
(leaf orderless
:ensure t
:init
(icomplete-mode)
(defun orderless-migemo (component)
(let ((pattern (migemo-get-pattern component)))
(condition-case nil
(progn (string-match-p pattern "") pattern)
(invalid-regexp nil))))
(orderless-define-completion-style orderless-default-style
(orderless-matching-styles '(orderless-literal
orderless-regexp)))
(orderless-define-completion-style orderless-migemo-style
(orderless-matching-styles '(orderless-literal
orderless-regexp
orderless-migemo)))
(setq completion-category-overrides
'((command (styles orderless-default-style))
(file (styles orderless-migemo-style))
(buffer (styles orderless-migemo-style))
(symbol (styles orderless-default-style))
(consult-location (styles orderless-migemo-style)) ; category `consult-location' は `consult-line' などに使われる
(consult-multi (styles orderless-migemo-style)) ; category `consult-multi' は `consult-buffer' などに使われる
(org-roam-node (styles orderless-migemo-style)) ; category `org-roam-node' は `org-roam-node-find' で使われる
(unicode-name (styles orderless-migemo-style))
(variable (styles orderless-default-style))))
;; (setq orderless-matching-styles '(orderless-literal orderless-regexp orderless-migemo))
:custom
(completion-styles . '(orderless)))
(leaf marginalia
:ensure t
:init
(marginalia-mode)
:config
(add-to-list 'marginalia-prompt-categories
'("\\<File\\>" . file)))
2021-10-10追記: Naoki Sakamotoさんに org-roam-node-find
のカテゴリが org-roam-node
であることを教えていただきました。感謝いたします🙏