岐阜でPython教えてきました + 飛騨高山聖地巡礼記

岐阜県は高山市にて「Python Boot Camp in 岐阜」に参加してきました。

pyconjp.connpass.com

今回は柏の葉・茨城に次ぐ3回目のTAということで、2回以上 Python Boot Camp を手伝った証である Python Boot Camp Tシャツをひっさげての現地入りとなりました。

岐阜のPython Boot Campに突然参加した最大の理由…それはなんといっても聖地王国だからです。今回は君の名は。(高山市・飛騨市)と聲の形(大垣市)の聖地を狙って観光半分TA半分で向かいました。結局ミスって君の名は。だけになっちゃいましたけど。

移動など

品川駅からのぞみに乗り、名古屋にて特急ひだへ乗り換えて移動しました。所要時間はトータルでだいたい4〜5時間ぐらい?岡山県の実家に帰るのとだいたい同じ感覚でしたね。

いつものぞみは岡山駅まで乗るのが普通だったので名古屋はあっという間。この移動の時点で既に聖地巡礼は始まっていてずっとハイでした。

特急ひだは台風の影響か人も少ないし、途中の景色がめっちゃ良いので全然飽きませんでした。

ついた

現地に着いて講師の寺田さん、同じTAであるnikkieさん(nikkieさんの参加報告記事はこちら)、現地スタッフの皆さん(スタッフの山ぴ〜さんの報告記事はこちら)と合流しました。そして早速飛騨牛。死ぬほどうまかった。

最高の肉
最高の肉

会場の立地とかとにかく良くて、観光地の中にある良さを強く感じました。マジでこういう場所で仕事したいな〜。

本番

事前の動作環境確認などを済ませ、レクチャーが始まります。

講師の寺田さん。
講師の寺田さん。

進み具合とかは概ねいつもどおりでした。今回はコードを書いたことがないぐらいの初心者が多めだったように感じます。そこはすかさず我々TAがサポートしていきます。

f:id:puhitaku:20190727140103j:plain

途中で実際に手を動かしてもらうことでPythonに慣れてもらいます。その途中で私もPythonの文法や言語機能で遊んだりしてました。今回は with 句に興味を示す人が多かったので、以下のように with でコンテキストを区切る例を作ったりしました。この「精神と時の部屋」は、普段は1秒経つと1秒時間が経過するのですが、 with で精神と時の部屋に入ると経過スピードが1/100になります。減速率は適当です。

gist.github.com

終了後はみんなで片付けて記念写真を撮り、懇親会へ。とある参加者の方から「嫁の友達が君の名は。の方言指導をやってて〜」というびっくりするような話も飛び出して、最高の夜でしたw

f:id:puhitaku:20190727174239j:plain

高山観光

寝て起きて次の日はまず飛騨高山の観光。せっかくの観光地、もちろん食や歴史も楽しんでいきます。飛騨高山まちの博物館は情報量が多く、建物もかつての塩蔵などを改装したもので趣があり良かったです。館内はほぼ撮影禁止でした。まあ仕方ないですね。

博物館によると、高山市はかつて織田信長や豊臣秀吉に仕えた金森長近(かなもりながちか)が飛騨を治めた際に築かれた城下町であり、古城の跡に高山城が築城されたんだそうです。織田信長といえば楽市楽座により商業を発展させたことが(私みたいな歴史オンチでも知ってるぐらい)有名ですね。それを思わせるように長近も商業を重んじ、高山城下では商人の専有面積を通例より大きく取りました。そのことが現在の活発な観光資源へとつながっているのではないかなと思いました。あと博物館で面白かったのは、備前の刀工が作ったという「長船」の字を銘に持つ刀一振りです。長船の名は現在も長船町として岡山県に残ります。高山にある経緯は忘れましたが、長船派は有名であることから当時の刀好きが所有していたのでしょう。

聖地巡礼

そして聖地巡礼。今回は宮水神社のモチーフになったという日枝神社と、瀧くんが飛騨にやって来た時に登場する飛騨古川駅へ行きました。それ以外の場所も車とかでガンガン行きたかったんですが、今回はお酒の試飲もしたかったため断念。さらに図書館も時間切れで閉まってました。また今度行きましょう。

通算200枚ほど撮り、ここでカメラのバッテリーが切れました。「あと2つストックがあるから余裕だぜ…」と思いつつ残りを入れると、どちらも残量ほぼゼロ!やっちまったー!

せっかくここまで来たのに!悲しみのラッシュ!でももう仕方ありません、公式のカメラの充電器はスゲー高いし、どこで手に入るかも不確実です。大垣入りしてアパホテルあたりに泊まる予定を全部諦め、東京に帰ることにしました。写真に収めたかったのに、見るだけでは不十分ですからね。

悲しみに暮れつつも、でもそれはそれで…君の名は。のシーンを思い出していました。

f:id:puhitaku:20190810142959j:plain
三葉捜しも諦めかけ、高山ラーメンを3人で食すシーン。

瀧「今日中に、東京に戻れるかな?」

司「あー…ギリギリかもな。調べるか」

瀧「サンキュ」

アアア〜〜〜〜それはそれで悪くない^〜〜〜〜!

さて。諦めもついたところで、飛騨古川へ行きましょう。また特急で行くにあたり高山駅へ戻りました。その道中も景色の良いこと良いこと。

キモオタ全開ですいません。でも無理!現地は流石に興奮を隠しきれません。あの渡辺酒造店にて聖地の酒をGETしました。…えぇ、もちろん 2つ ですよ。2つ並べたその 右側 を飲むことに意味がありますからね!!!

飛騨古川駅に戻り、帰りの電車を確認して特急券を買い、新幹線も予約しました。1時間半ほど特急まで時間があるので……と危ない危ない。「あの連絡橋」をまだ撮ってなかったですね。

ここまで来たワシは瀧くんなんじゃ……でもみt… 四葉 を見つけることもできずに今日の夜には東京へ……グアアアア!!!戻りたくない!この田舎でゆうゆうとコードを書いてたい!!そこに自分が捜している「誰か」がいる気がしてならない!!

ここらへんは、いい感じの景色もあって極度のエモにやられてしまいました。田舎出身の私には居心地が良すぎましたね。

まとめ

残念ながらいまだ都心に対して情報格差の大きい地方でも、コードを学びたいと思っている人口がいるというのは新鮮でした。私の出身である岡山県でもつい最近PBCがあってすごくいい流れだと思うものの、私が知る限りではそういう人口はほぼ顕在化していないですからね。実際、「こういうのを火種にして地方コミュニティが育っていったら良いな」という話も事後ミーティングでさせていただきました。

久しぶりの Python Boot Camp は、今までで一番旅らしい感じになりました。「ボランティアでいらっしゃったんですか!?」「移動費も自費!?」と現地のいろんな方に驚かれましたが、やはり観光を絡めるとフットワークが軽くなるというものです。ただの旅行よりもある意味濃密な体験や交流ができますから、我々からするとむしろありがたいぐらいです。

ルーターハック Advent Calendar を振り返る

f:id:puhitaku:20181226001750j:plain

今回 ルーターハック Advent Calendar を一人で書いていたのだが、未達となってしまい盛大にやらかしたので、25日の今日、反省記事を投稿して総括とする。「1人 Advent Calendar はマジで大変、ノリでやるものではない」という気持ちが伝われば本望である。

なおこの記事で一旦締めくくりではあるものの、「書けないなら埋めようか?」と話しかけていただいた心優しい方々の投稿がある。感謝を込めてこちらの記事末で紹介させていただこうと思う。

adventar.org

ことの始まり

ルーターハック Advent Calendar をやると公表したのは、もう1ヶ月以上前になる11月24日だった。

この時は酒を飲んでいたので、「埋めたったれオラァ!」と完全に勢いで全部埋めた記憶がある。

次の日シラフに戻り、これは準備せなあかんと奮い立って記事を書くことにした。この時、せめて1日間隔ぐらいに緩和しておけばよかったのだが後の祭りである。

良かった点・努力した点

バッファを確保した

12月1日を迎えるまでに、5〜6記事程度のバッファを設けることに成功した。こんなに前もって何かができることは今までの人生レベルでもそうないのだが、流石に25記事も投稿しなければならないと思うと手を動かすことができた。

3日目の翻訳記事も、大変な分量で2日ほどかかったのだが、事前に仕上げることができた。

事前に計画した

Google Keepに25日間何を書くかについて計画を書き、遅れが発生するまではほぼ実行できた。書いてみたら重すぎた文章についてはスキップしたが。

少なくとも、怠けることはなかった

体力や予定で無理そうな時以外は机に向かい作業をしていた。毎日、帰って何をやろうか考え、実行した。

悪かった点・予想外だった点

予想以上に忙しかった

バッファを設けたのはよかったが、12月頭からこの数日前ぐらいまでは仕事が忙しくなったこともあり、あっという間に食いつぶしてしまった。事前に予想できたはずなのだが、読みが甘かった。

体調には波がある

記事を書くのは体力が要る。仕事に必要な分の体力や睡眠時間を確保したとすると、残りの量は日によって変化することになる。これが少ない時は、帰ってくるともうばたんきゅーである。

進捗は手を動かした量に比例しない

手を動かせば順当に進捗が得られるとは限らない。冷静に考えるとえらくまっとうなのだが、これを事前に思い出すことができなかった。1記事相当の進捗に達するのに3日ほどかかるのもザラだった。一記事あたりの分量を薄めれば記事は増やせるが、クオリティを下げるのだけは嫌だった。

これらを踏まえて

来年もルーターハック Advent Calendar はやると思うが、反省を踏まえて以下のように実施したいと思う。

  • もっと早めにカレンダーを作り、告知する
    • できる限り事前に枠を埋めてもらう
  • 自分で埋められる量をちゃんと考える
  • 無理そうになってきたら、素直に枠を空ける

記事投稿を名乗り出てくださった方々

25日も近くなり、「記事を投稿しようか?」とリプライをいただくことがあった。敬意を表し、助け舟を出していただいた方々の記事をこちらに掲載させていただく。

srchackさんの「LinkIt 7688のビルド手順。(Chaos Calmer 15.05.1)」 www.srchack.org

yamori813さんの「ZRouterの事」 qiita.com

『ルーターにつなぐ』I2C温度センサ編

本記事はルーターハックAdvent Calendar 13日目の記事です。12日枠の記事は srchack さんの「LinkIt 7688のビルド手順。(Chaos Calmer 15.05.1)」です。バリバリ遅れてるところに助け舟を出していただいてほんとありがとうございます。

www.srchack.org

今回は、さまざまなペリフェラルを実装しているルーターのために、元々なかったパーツをつないで遊んでしまおうという企画『ルーターにつなぐ』の第2弾だ。

おことわり

技適 に関する筆者の配慮や考えについてはカレンダー1日目「技適とルーターハック」をご覧ください。本記事で紹介する内容は、法を遵守するための慎重な注意をもって書かれています。

www.zopfco.de

I2C とは

アイスクエアドシーとか、アイツーシーとか読まれるシリアルバスの一種。クロックが低速(100kHz〜400kHzが普通)でこれを搭載しないマイコンはないというほどポピュラー。

I2C をしゃべることのできるセンサーを Raspberry Pi につないだことがあるという方も多いだろう。

バスなので1つの信号線に複数のデバイスが接続されるが、スレーブの区別は SPI とは異なっていて、データ線を流れる信号にスレーブアドレスも織り込まれる形式をとっている。これにより、データ (SDA) と クロック (SCL) の2本のみという非常に少ない信号線で通信ができるようになっている。

ルーターで I2C を使うには

今回は、やはり前回に引き続き 多摩電子工業 (Axing) W06 を題材に使うことにする。

ルーターで I2C を使うには、Device Tree の i2c ノードを有効化して Linux kernel に認識させることになる。

ファーム準備

ここから、

  • I2C 関連ツール用意
  • Device Tree の変更
  • I2C の信号が出ている回路を探す

の3つのステップを経て I2C を使えるようにする。

I2C 関連ツール用意

ファームの config に以下追加する。

まず、i2cdetect などが入っているi2c-tools。

  • Utilities -> i2c-tools

カーネルで I2C を扱えるようにするモジュール類。

  • Kernel Modules -> I2C support -> kmod-i2c-core
  • Kernel Modules -> I2C support -> kmod-i2c-mt7628

watch コマンドがあった方が便利だ。

  • Basy system -> busybox -> Process Utilities -> watch

Device Tree の変更

W06 の Device Tree は、 openwrt/target/linux/ramips/dts/W06.dts に入っている。この中で mt7628an.dtsi という SoC 共通の dtsi (include用の dts は拡張子として dtsi がつく) を include している。

mt7628an.dtsi は汎用なものなので、ルーターで使わない I2C のノードも記載されているものの標準で disabled になっている。include する側、つまり W06 の dts でこれを有効化する。

W06.dts を開き、I2C のノードを okay にするように以下追記する。

diff --git a/target/linux/ramips/dts/W06.dts b/target/linux/ramips/dts/W06.dts
index 8c3bbe4058..cd70ebbb2f 100644
--- a/target/linux/ramips/dts/W06.dts
+++ b/target/linux/ramips/dts/W06.dts
@@ -66,6 +66,10 @@
        };
 };

+&i2c {
+    status = "okay";
+};
+
 &spi0 {
        status = "okay";

I2C の信号が出ている回路を探す

探りを入れる前に、ひとまず i2cdetect してみよう。このコマンドを使うと、I2Cの各スレーブアドレスに対して応答を要請することができる(しくみは後述)。応答のあったアドレスはそのアドレス自体が表示され、応答がないと -- になる。

root@OpenWrt:~# i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: 30 31 32 33 34 35 36 37 -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

What? 何も繋がってないはずなのに亡霊がいる。オシロで探りを入れるしかないな。 watch -n 0.5 i2cdetect -y 0 でずっと信号が出るようにしよう。

Every 1s: i2cdetect -y 0                                                                                                                                                   2018-12-09 13:45:51

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: 30 31 32 33 34 35 36 37 -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

データシート曰く、I2C は21ピンが SDA、20ピンが SCL らしい。近くに先日いじった SPI のピンも見える。

f:id:puhitaku:20181218005741p:plain

実際の写真はこれ。該当するピンと、その配線の先にあるチップ抵抗のランドをピンクで示した。

f:id:puhitaku:20181218005608p:plain

よく見ると…どちらのピンも、共通のランドにチップ抵抗で接続されている。もしや… I2Cのために最初からPull-upしてくれてるのか!!?*1

21ピンの SDA からのびた先のチップ抵抗に試しにプローブを当ててみる。

f:id:puhitaku:20181218004447j:plain

f:id:puhitaku:20181218004823p:plain
SDAぽい。

うんうん、それっぽい!

なんと、ご丁寧にも I2C の配線は最初からPull-upされていた。なんて親切なルーターなんだ(感激)

あっさり I2C の配線が特定できたが、本来出ない亡霊が i2cdetect で出てきているのが気になる。配線をこのランドから伸ばし、ロジアナに接続してみる。

信号をより詳細に計測する

ロジアナで詳しく調べる前に、I2C の probe のしくみを解説しよう。

I2C では、スレーブアドレス および レジスタアドレス を使ってアドレッシングする。

  • スレーブアドレス = バスに繋がれたデバイスを特定する値
  • レジスタアドレス = デバイス内のレジスタを特定する値

マスターが何らかの値を送るときには、まずスレーブアドレスを流し、そして書き込みたいレジスタアドレスを流し、最後に入れたいデータを流すことになる。これをビット単位で表したのが以下の図である。

f:id:puhitaku:20181222155653p:plain
出典: TI - Understanding the I2C Bus http://www.ti.com/lit/an/slva704/slva704.pdf

示されている各ビットは、以下のようなタイミングで表現され、伝送される。クロックとデータのエッジが重なる SPI などとは異なり、クロック (SCL) が High である時間をいわば前後に「包み込む」ようにしてデータ (SDA) のエッジが描かれるのが I2C の特徴である。

f:id:puhitaku:20181222160041p:plain
出典: 同上

ここで、上記2つの図で ACK と表現されているビットが、スレーブ側と正しくコミュニケーションできているかどうかを示す。このビットの区間だけは、マスターは SDA をコントロールしていない。つまり、スレーブ側が意図的に Low に落とせば「スレーブは指示を理解した」とマスター側に伝えられることになる。

よって、ACK に相当する区間が Low であれば ACK (OK)、High であれば NACK (NG) となる。

f:id:puhitaku:20181222161333p:plain
出典: 同上 ACKビットが High のため、スレーブに指示が伝わっていない = NACK となる。

それでは、本来居ないはずのアドレス 0x30 を実際に i2cdetect した時のスクリーンショットを見てみよう。Digilent - Analog Discovery 2 に接続し、Scope(オシロ) と Logic (ロジアナ)の両方で観察したのが以下のスクリーンショット。上が Scope、下が Logic。

f:id:puhitaku:20181222154844p:plain

まず、SDA が Low に落ちて START condition になる。次に、アドレス 0x30 を Read したいと伝える。さらにその次が件の ACK になるのだが、High のままになっているため NACK (NCK) を示している。

電気回路レベルでは特に問題がないのだが、やはり i2cdetect は 0x30 を検知したように表示している。

Every 1s: i2cdetect -y 0 0x30 0x30                                                                                                                                         2018-12-14 03:56:11

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                                                 
10:                                                 
20:                                                 
30: 30                                              
40:                                                 
50:                                                 
60:                                                 
70:

回路構成はどうだろうか?リファレンスとなる LinkIt Smart 7688 の Schematic から I2C 部分を抜粋したのが以下の画像だ。

f:id:puhitaku:20181222163025p:plain
出典: LinkIt Smart 7688 Resources - Documentation https://docs.labs.mediatek.com/resource/linkit-smart-7688/en/documentation

Pull-up抵抗は 4.7 kΩ となっている。W06 の表面実装抵抗にテスターを当てたところ、やはり 4.7 kΩ を示したため、これも問題ないようだ。う〜んわかんなくなってきたぞw

ドライバにパッチを当てる

電気的に問題が無さそうなのに i2cdetect が false-positive を示すということは、SPI の時と同じく物理層以上ソフトウェア以下で問題がありそうである。早速 OpenWrt の Issue/PR を検索すると…

あった!

github.com

クロックの扱いや ACK のハンドリングがダメだったらしい。この PR で出ているパッチは Upstream (Mainline) に出すとだけ書かれて閉じられているが、Fork 先を git add remote からの fetch して cherry-pick すればよい。

パッチを当てると静かになった。行けそう。

root@OpenWrt:~# i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

温度センサを繋げてみる

I2C の亡霊問題は大丈夫っぽいので実際に何か繋ごう。今回は秋月で雑に買った 高精度温度センサ STTS751 を接続する。

akizukidenshi.com

ただ、あまりにも無計画に買ったのでDIP化基板を買い忘れてしまった。カプトンで固定して配線。そしてブレッドボードへ。

f:id:puhitaku:20181225221318j:plain
ルーペで撮った。

f:id:puhitaku:20181225223245p:plain
データシートより

左の点がある足から、反時計回りに1〜6ピンがのびる。4ピンはデータシート曰く may not float らしいがなくてもそれっぽく動くので今回はよしとした。

1ピンを Pull-up する抵抗の値によってアドレスが決まる。テストのため 10k + 10k = 20kΩ を接続したところ、データシートどおり 0x38 で認識された。

root@OpenWrt:~# i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- 38 -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

計測してみる

温度レジスタの構成は以下のようになっている。0x00 の値を読むだけでも1℃単位の温度が得られるので、今回は簡易的に 0x00 の値だけ読むことにする。

f:id:puhitaku:20181225223408p:plain
データシートより

i2cdetect の兄弟に i2cget があるのでそれで読んでみる。

root@OpenWrt:~# i2cget -y 0 0x38 0
0x13

19℃。部屋にある別の温度計曰く19.6℃なので正しそうだ。指で温めると温度が上がり、離すと下がることも確認できた。

やったぜ!!!!!!!

次回

次回というか、Advent Calendarではない更新でこれからもこういったネタを投稿していけたらと思う。今回は以上!

*1:I2Cは上りも下りも単一の信号線で通信するため、ホストとスレーブどちらでも信号線を操作できるようにPull-upされている。このような、信号線上の誰かがLowを出力すると全体がLowになるような回路構成をワイヤードORという。