Circuit Playground Express の各種機能を試す(3)
温度センサーを利用する
利用するライブラリは adafruit_thermistor.mpy
でこれを lib に放り込む。
で、コードをしれっと
import time import adafruit_thermistor import board thermo = adafruit_thermistor.Thermistor(board.TEMPERATURE, 10000, 10000, 25, 3950) while True: temp = thermo.temperature print((temp,)) time.sleep(1)
実行するとこんなかんじ
(27.9365,) (27.9139,) (27.959,) (28.004,) (27.8915,) (27.959,) (27.9139,) (27.9139,)
大体 28 度位なのだが、これを手のひらで包むと
(29.4573,) (29.5717,) (29.7322,) (29.7092,) (29.824,) (29.939,) (30.0081,) (30.1693,) (30.2384,) (30.2616,)
単位が 度というのが助かりますね。
海外だと単位が華氏で有ることも多いので…
他のライブラリを利用してみる
circuit playground のアクセスをもっと単純化したライブラリ adafruit_circuitplayground
が存在したので使ってみた。
コードは
import time from adafruit_circuitplayground import cp while True: print("Temperature C:", cp.temperature) time.sleep(1)
うーんシンプル。
Temperature C: 27.3748 Temperature C: 27.3748 Temperature C: 27.3972 Temperature C: 27.4197 Temperature C: 27.4197 Temperature C: 27.4197
このライブラリを利用して温度を視覚化しようか
温度の視覚化
温度で LED 光らせてみようか。
import time from adafruit_circuitplayground import cp # LED の明るさ設定 cp.pixels.auto_write = False cp.pixels.brightness = 0.3 # 25-30 度の間で 10 段階表示 minimum_temp = 25 maximum_temp = 30 # 平たく言えば、最小温度から最大温度までの比率を 10 段階計算 #まぁ、25 度下回ればマイナスにもなるし、30 度超えれば 10 以上になるが、ループとしては特に問題ない def scale_range(value): return int((value - minimum_temp) / (maximum_temp - minimum_temp) * 10) while True: peak = scale_range(cp.temperature) # 10 個ある LED を範囲内で発光させる for i in range(10): if i <= peak: cp.pixels[i] = (255, 255, 255) else: cp.pixels[i] = (0, 0, 0) # 発光! cp.pixels.show() time.sleep(0.5)
ということで、30 度でマックス、25 度からおよそ 0.5 度刻みで光らせるコードを書いた。
その様子がコレである。
ちなみに起動してると、次第に基盤自体に熱を持つので、27 度の室温なら気づくと 30 度とかになる…
Circuit Playground Express の各種機能を試す(2)
環境::
- CircuitPlaygroundExpress : Bootloader 3.10.0
- CircuitPython : 5.0
ライブラリで色彩/明度/彩度 を扱う
どちらかといえば CircuitPython の機能で、 ライブラリ からコピーして使う。
全部のライブラリをコピーはできないので、今回使うものだけ。
この上で
import time import board import neopixel import adafruit_fancyled.adafruit_fancyled as fancy npx = neopixel.NeoPixel(board.NEOPIXEL, 10, auto_write=False) while True: for pp in range(10): h = (pp * (1.0/10)) hsvcolor = fancy.CHSV(h, 1.0, 0.2) npx[pp] = hsvcolor.pack() npx.show() time.sleep(0.2)
すると
綺麗なグラデーションですね…
光学センサーで明るさ計測
import time import analogio import board light = analogio.AnalogIn(board.LIGHT) while True: print((light.value,)) time.sleep(1.0)
としたとき部屋の蛍光灯でこんな感じです
(3168,) # 蛍光灯の光 (3136,) (800,) # 手で隠した (720,) (720,)
タッチセンサー
タッチセンサーによって LED の色を変動させるプログラム
タッチセンサーは周辺の穴の空いた端子ですが、今回 A1, A2, A5, A6 を使います。
以下の写真にそれぞれの配置がプリントされてます。
A シリーズはすべて操作可能なのはわかってましたが、RGB いじりたいだけでしたので今回は避けました。
import time import board import neopixel import touchio from simpleio import map_range # LED セットアップ npx = neopixel.NeoPixel(board.NEOPIXEL, 10, auto_write=True) # タッチセンサーを設定する touch_A1 = touchio.TouchIn(board.A1) touch_A2 = touchio.TouchIn(board.A2) touch_A5 = touchio.TouchIn(board.A5) touch_A6 = touchio.TouchIn(board.A6) # 色のセット r_in = 0 g_in = 0 b_in = 0 while True: # タッチするセンサーによって RGB を決定 if touch_A1.value: r_in += 1 if touch_A2.value: g_in += 1 if touch_A5.value: b_in += 1 if touch_A6.value: r_in -= 1 g_in -= 1 b_in -= 1 # 0 - 255 までに抑える r_in = 0 if r_in < 0 else r_in g_in = 0 if g_in < 0 else g_in b_in = 0 if b_in < 0 else b_in r_in = 255 if r_in > 255 else r_in g_in = 255 if g_in > 255 else g_in b_in = 255 if b_in > 255 else b_in # LED に色を書き込む npx[7] = (r_in, g_in, b_in) time.sleep(0.2)
でちょっとやってみたのがこの 2 枚
タッチ時間によって色が変化します。
Circuit Playground Express の各種機能を試す
環境:
- Circuit Playground Express (Bootloader3.10.0)
- Circuit Python v5
ボタン AB 認識
import board import time from digitalio import DigitalInOut, Direction, Pull # LED definition led = DigitalInOut(board.D13) led.direction = Direction.OUTPUT # A button definition ButtonA = DigitalInOut(board.BUTTON_A) ButtonA.direction = Direction.INPUT ButtonA.pull = Pull.DOWN # Dont push value define. # B BUTTON DEFINITION ButtonB = DigitalInOut(board.BUTTON_B) ButtonB.direction = Direction.INPUT ButtonB.pull = Pull.DOWN # Button change delay delay = 0.1 # Execution loops. while True: delay = 0.05 if ButtonA.value else 0.1 delay = delay * 10 if ButtonB.value else delay led.value = True time.sleep(delay) led.value = False time.sleep(delay)
やってみると分かるけど、ボタンを押している間だけ LED の点滅速度が変化するやつ。
CircuitPython で利用できる基本 API は このへん に落ちてた。
うんドキュメント、ないね☆
カラー LED を光らせる(簡易イルミネーション)
import time import board import neopixel # neopixcel って LED の名前らしい。てか Pixcel というだけあって、RGB カラーで光らせられる npx = neopixel.NeoPixel(board.NEOPIXEL, 10, auto_write=False) loop = 0 # カラーテーブルを定義して colors = [ (128, 0, 128), (255, 0, 0), (128, 128, 0), (0, 255, 0), (0, 128, 128), (0, 0, 255) ] while True: # カラーテーブルの順序に従って色を変える # 光らせる順序は反時計 loop += 1 loop = 0 if loop >= len(colors) else loop col = colors[loop] for pp in range(10): npx[pp] = col # RGB で書き込む npx.show() time.sleep(0.2)
Circuit Playground Express をいじったログ
一通り機能を触ったので、紹介記事と、初期セットアップだけ。
経緯
買って試したのはコレ
当初、IoT として一度ブームになったときは、RasberryPi がやたらと人気で、記事は実質それ一色だったのを覚えてる。
ただ、買って弄ってわかったことは、あれは規模の小さい PC であったという事実だ。
それで何が言いたいかって言うと
ハード設計できない人はお呼びでない ということだった。
もともと Web 屋さんで、ハードなんて大学でマイコンにアセンブラ書き込んでLED と高額センサーで信号通信してみた位しかやったことがない。
まして就職して 当時 8 年目位で、今更回路設計しろって言われても無茶振りに近かった…要するにそんな余裕も金もなくて挫折した(汗
(Web屋さん業界じゃ HTML5 と ecmascript や各種フレームワーク打なんだで群雄割拠ヒャッハーしてたり AI たのすぃーとかいってフラフラしてた)
で、しばらく遠のいてたところを、知人にこんな本紹介されて
え?マジで?と調べて驚いた。
Circuit Playground Express とは
平たくいえば、ネットワーク危機こそないけど、ジャイロ、温度、音声、スピーカー、LED、タッチセンサー、赤外線と、コミコミ全盛り回路セットである。
要するに、多くのソフトやさんなプログラマが挫折するだろう箇所を全盛りで用意してくれてるという一品。
コレは軽くチートじゃないんですかね…(汗
開発準備
Bootloader
USB で繋いで、中央のスイッチを押すと USB 認識するので、ブートローダのアップデートを行う。
Mac でやってたので https://learn.adafruit.com/adafruit-circuit-playground-express/updating-the-bootloader こっからダウンロードして更新した。
update-bootloader-circuitplay_m0-vX.XX.X.uf2
を finder にドロップするだけで、中にある INFO_UF2.TXT
の中に記述されるバージョンなどが上がった。
デバイス的にもこの辺を事前サポートしてるのか…ううむ…。
この記事時点では v3.10.0
が最新だった。
CircuitPython
ここから CircuitPython をダウンロード & インストール。
ここでは 5.3.0
の英語版を選択。
ライブラリも Libraries から入手した。
日本語なんてドマイナー言語対応してないのはある意味仕方ないよな(汗
で、ここで気をつけるべきは、全部のライブラリは容量的にはいらないということ…
なので、 Python コード上使用しているものだけ選択して入れる必要があるという点。
ここで全パターンとライブラリ紹介始めると、時間がいくらあっても足らないので省略。
最も単純な LED 点灯
といっても写経だったりするのだが
ここの code.py
がエントリポイントになってるようなので、コレを弄る。
import board import time from digitalio import DigitalInOut, Direction led = DigitalInOut(board.D13) led.direction = Direction.OUTPUT while True: led.value = True time.sleep(0.1) led.value = False time.sleep(0.1)
色々疑問なので、import してるやつを追いかける。
こういう調査がないと応用効かない…
で、公式ドキュメント漁ると発見 https://learn.adafruit.com/welcome-to-circuitpython/creating-and-editing-code コレか。
で、やっぱそうなのかという話で、 board
, time
, digitalio
が 組み込みライブラリ であるそうな。
board
gives you access to the hardware on your board (ボードはボードに存在するハードウェアへのアクセスを提供します) *digitalio
lets you access that hardware as inputs/outputs (digitalio はハードウェアへ Input/Output を提供します)
ナルホド、で、なんで D13
なん?って思ったらあっさりわかった。
あーうんなるほど…既にそこそこ抽象化してるのね(汗
じゃー何がビルトインされてんのさ?って思ったら
https://learn.adafruit.com/adafruit-circuit-playground-express/circuitpython-built-ins https://learn.adafruit.com/adafruit-circuit-playground-express/circuitpython-digital-in-out
ふむふむ。
で、 Circuit Python のライブラリには何あんのさ?って思って調べたら
しかもハードごとに違うってんだからコレは一瞬「うぉっ」となるよね(汗
デバッグ環境を整える
で、これなにかバグった時にデバッグ出力得られないと泣けるので
この辺を利用する。
何が泣けるって、ここで推奨してる Mu Editor が Mac 10.15.5 で起動しないもの…セキュリティは分かるがちっとヒステリックになってきてないかと思わなくない。
時期バージョンで Arm 移行もあるし、結局「開発者<消費者」ルートで開発者を置いてけぼりにするんかね… Windows もアレだし、Ubuntu に戻ろうかな…。
現在のシリアルコネクションを確認
USB 接続なのは確実なので、/dev/tty.usbmodem144101
が結局デバイスだろうね。
てことで screen /dev/tty.usbmodem144101 115200
と叩く
これで画面が真っ黒になるので、コード中にデバッグ文字列を挿入。
やってみれば分かるが、デバイスに保存した次の瞬間には適用されてる。
CPU は 48MHz なので、Windows95 黎明期?逆に言えばそれくらいのスペックがこんなボードに乗るようになったんだなーと実感(汗
メモリが 2MB しかないというのも割とネックではあるので、ラズパイと組み合わせてやるとネットワーク連携もできて幸せになれそうな気がするよ。
機械学習で使う数学系関数…つーか数式
相変わらず Puthon 3.7.x (anaconda) で検証。
シグモイド関数
基本形はこんな数式らしい。
グラフにしてみるかね
import numpy as np import matplotlib.pyplot as plt import math %matplotlib inline def sigmoid(x): """シグモイド関数""" e = math.e return 1/(1 + e**-x) x = np.arange(-20, 20, 0.5) y = sigmoid(x) fig = plt.figure(figsize=(10.0, 5.0)) plt.plot(x, y, color='blue') plt.grid() plt.show()
よくニューラルネットワークのニューロンにされるやつ。
まぁ要するに 0 - 1
の間、0 でちょうど 0.5
となってるので、パーセンテージを扱う処理に向いてるって話らしい。
これで単純な二値判定するなら、0.5
が当然のようにボーダーになるわけで…
0 がちょうど 50% なので、それがプラスかマイナスかで 1/ 0 と判定すればいいので
という形になる。
これで長方形判定をするものと考えると。
横長である確率を求めると考えて、横軸を 縦軸を として適当なパラメータを与えてみる(あくまでも適当)
式に直すと
図にすると
続きを読む行列使った機械学習で、縦長/横長長方形を判定する
問題
四角が存在して、縦長か横長かを判定する。
正直それだけなら座標見れば一発だが、敢えてベクトル的に考えてみる。
横幅 | 縦幅 | 形 |
---|---|---|
80 | 150 | 縦長 |
60 | 110 | 縦長 |
35 | 130 | 縦長 |
160 | 50 | 横長 |
160 | 20 | 横長 |
125 | 30 | 横長 |
これをプロットすると
import numpy as np import matplotlib.pyplot as plt %matplotlib inline x = np.array([80, 60, 35, 160, 160, 125]) y = np.array([150, 110, 130, 50, 20, 30]) fig = plt.figure(figsize=(5.0, 5.0)) # グラフサイズ plt.scatter(x, y, marker = 'o') plt.grid() plt.show()
これを線引きする直線を求めたい。
これを行列的に求めるなら、重みベクトルを法線ベクトルとした直線
という言葉になる…らしい。
うーん難しい (;^ω^)
重みベクトルを $w$ とすると直線の方程式は
もっというと
ってなるので、 と仮定すると ということは
これを図にすると
fx = lambda x : -x x = np.arange(-10, 10, 0.5) y = fx(x) fig = plt.figure(figsize=(5.0, 5.0)) plt.plot(x, y) # w = (1, 1) も作画 plt.quiver(0, 0, 1, 1, angles='xy', scale_units='xy', scale=1) plt.grid() plt.show()
この論理で、判定できる関数を学習で習得させる。
目的の重みベクトルを として、学習式を以下にしてみる。
縦長をこのベクトルと内積とったときには正、横長をこのベクトルと内積とったときに負と判定するとして、成功するなら何もしない。
判定に失敗したらベクトルの足し算を行うと…
from copy import copy # 学習データ values = [ np.array([80, 150]), np.array([60, 110]), np.array([35, 130]), np.array([160, 50]), np.array([160, 20]), np.array([125, 30]) ] actuals = [ True, True, True, False, False, False ] # 正規化 def normalize(v): # c = np.linalg.norm(v) # ベクトルの長さを求めて return v #(v / c) # 学習データ w = np.array([-1, -1]) # 学習の変遷 log = [ w ] # 学習関数 for n in range(0, 6): v = normalize(values[n]) actual = actuals[n] res = np.dot(w, v) res = float(res) print('--------') print('current:' + str(w)) print('test :' + str(v)) print('res :' + str(res)) # 正常判定したら何もしない if (res > 0) and actual: continue elif (res < 0) and (not actual): continue # 判定に失敗してたら更新 if actual: w = w + v else: w = w - v log.append(copy(w)) print('update to:' + str(w)) print(log)
出力ログこんな感じ。
-------- current:[-1 -1] test :[ 80 150] res :-230.0 update to:[ 79 149] [array([-1, -1]), array([ 79, 149])] -------- current:[ 79 149] test :[ 60 110] res :21130.0 -------- current:[ 79 149] test :[ 35 130] res :22135.0 -------- current:[ 79 149] test :[160 50] res :20090.0 update to:[-81 99] [array([-1, -1]), array([ 79, 149]), array([-81, 99])] -------- current:[-81 99] test :[160 20] res :-10980.0 -------- current:[-81 99] test :[125 30] res :-7155.0
プロットしてみるとこうなる。
ちなみに最終的な法線も入れて作画。
x = np.array([80, 60, 35, 160, 160, 125]) y = np.array([150, 110, 130, 50, 20, 30]) def nvec(v): # 法線ベクトル # 99 / -81 = -1.2222222222222223 # 81 / 99 return v * 0.8181818181818182 nx = np.arange(-180, 180, 1) ny = nvec(nx) # 正規化関数 def normalize(v): c = np.linalg.norm(v) return (v / c) * 80.0 # 計算の過程で出た重みベクトルのリスト plotData = [] for v in log: plotData.append(v) fig = plt.figure(figsize=(8.0, 8.0)) # グラフサイズ plt.xlim(-180, 180) plt.ylim(-180, 180) # 学習データ plt.scatter(x, y, marker = 'o') # 縦長か横長かを判定する法線ベクトル plt.plot(nx, ny, color='blue') # 学習中に出たベクトルの変遷 # 赤を基調に、だんだん青が交じる color = [1.0, 0.0, 0.0] bias = 0.2 for v in plotData: plt.quiver(0, 0, v[0], v[1], angles='xy', scale_units='xy', scale=1, color=color) color[0] = color[0] - bias color[2] = color[2] + bias plt.grid() plt.show()
これで無事青の法線が引けた。
当たり前だけど、学習サンプルが完全ではないので、この法線ベクトルでは縦長か横長かを完全に判定することはできない…が、それが縦長か横長かを学習する学習機はこんな感じでやれる。
多分アヤメ判定とか、ベクトルでの二値判定で使えるはず。
ベクトルは全部グラフにしてみないとわかりにくくてたまらない(汗
テスト駆動開発
書籍
来たよケントベック先生(Smalltalker で XP 開発の始祖様)!
読もうと思ったきっかけ
テスト駆動開発…って聞いた時の自分の知ってる知識は
- ユニットテストを最初に書いて、以下を定義する
- どう動くべきか
- どう書きたいのか
- つまりコードが仕様書なんだ
- テストを通る様に実装する
でしかなかった。
要するに 我流な TDD のイメージ を持ってたわけだ。
なので、改めて勉強してみるのもいいかなと
意識 Before/After
Before
我流TDD 的に考えていれば、テストを書く前の段階からこうしておく必要があると思い込んでた
- どういった機能が必要なのかを事前に設計しなければならない
- インターフェースの定義や、設計の有るべき論を定義してかかるべきである
だから テスト駆動は難しい ので スキルのあるチームでないと出来ない事だ とそう 勝手に思い込んでいた 。
After
ああ、TDD とは 設計まで対象にリファクタを行う 開発様式だったのかと初めて知った。
基本の1サイクルは以下の通り。
- テストを書く
- コンパイルを通す(空実装)
- テストを走らせて失敗を起こす
- テストを通す
- 重複の排除
ただしこれを、1モジュールあたり以下のフェーズで行う。
- 最低限必要とすべき機能を定義する(実装は適当でいい)
- リファクタ(テスト上、内部変数の変化をチェックする様な使い方は微妙とか、インターフェースの見直し)
- オブジェクトとして見た時に、他に必要な物がないかの観点でインターフェース定義
- テストコードのリファクタ
- テストのバリエーション(こんな時はどうあるべきよ?)の作成
- テストから見た同一概念操作の抽出
- 派生型/類似型などの隠蔽化(クラスの同一化か派生クラスの削除など…)
- 不要となったテストの除去
何てこった、 実装だけじゃない、 インターフェース…使い方までサイクルに入ってるやんけ
ざっくり内容と見所
- 第一部: 金額の取り扱いクラスについてTDDの実装を行ってみる(ハンズオン)
- 第二部: xUnit (ユニットテストのほぼデファクトスタンダード)の構成と、考え方(ハンズオン)
- 第三部: テスト駆動パターン(読み物)
- テスト駆動で記述するテストの種類
- テスト手法のパターン
- 仮実装から本実装へのリファクタを行うテスト修正パターン
- xUnit の技法
- デザインパターン(!?まさかの設計パターン)
- リファクタリング手法
- TDD の身につけ方
という構成。
手を動かさないと退屈という自分にはすごく有り難い構成でした。
ってーか
第三部盛り過ぎでしょ(汗
消化不良ならもう何でも関連資料漁る位は当然しますけどさ…(汗
本気で第三部だけで1冊出ても良いと思いました。第三部だけでも技法技術大好きっ子には (^q^)
ですよマジで…