はじめに
先週参加したラズパイ勉強会でOS壊したのでペアプロしてました.
当日やっていたことのおさらいを含めて「動けばいいんだよ動けば」の精神の下,3時間程度のボリュームを念頭にしたテキストを書いて別の機会で使うかもしれないときの備えをします.
※)実機直してないから試してないけど多分動くよね.という気持ちで酒飲んで書いてるため, コードの修正や美味しい日本酒やウイスキーがあればコメントください
登場人物とゴール設定
相手
- Raspberry Piが前日に届いた.当日はじめて中身を触る
- 大学院の研究でJupyterを触るがプログラミングはよくわからないとのこと
- 電子回路はむかし学校で習った記憶がおぼろげにある
- ロボットを作ってみたい
私
- Raspberry Piは2が出た頃に買って,ニキシー管チカとかオーディオ系とかやっていた
- 趣味でエレキギターやエフェクターを作っている
- Raspberry Piにはここ1年くらい「それじゃなくてもよくない?」ということ(gogsのサーバとか)をやらせていた
- 「Gpiozeroなんていつの間に出てたの?」くらいの認識
ゴール
当日は材料や知識が足りなくてできないが,「何ができるか」を体験しながら目標に向けて何ができそうか考えながらコードを書いていく
持ち込んでいた物
アウトライン
- 電子回路とは
- ブレッドボードを使ってみよう
- まずは模式図(回路図)
- 題材
3. 当日の配線
3. Lチカ(LEDを光らせる)しよう
4. 光る時間を変更できるようにしよう
5. 点灯時間をランダムにしよう
6. 消灯時間もランダムにしよう
7. 色もランダムに変えよう - GPIOで何ができるの?
- Lチカになんの意味があるの?
- 今後の展望
- 自分の感想
電子回路とは
ブレッドボードを使ってみよう
ブレッドボードは穴が沢山空いた板.
下図の線で繋いだ一直線に並ぶ穴の組であればハンダ付けしなくても電気が通じるようになっています.
ここにジャンパワイヤーや電子部品などを挿して試作品を作るのが主な用途です.
うまいことできたら基盤を作ってハンダ付けをすると壊れにくいものができますが,ブレッドボードは組んで試してバラしてを繰り返すにはもってこいでしょう.
まずは模式図(回路図)
『回路』がどういうものか.
たとえば下図のような繋ぎ方をするとスイッチをONにしたときLEDは赤く光ります.2
上図のようなものを実体配線図と呼びます.
次にこれを記号で描いたシンプルな回路図に置き換えます.
こんな感じ.
スイッチをONにすると回線が一周できるので全体に電気が流れます.
スイッチをOFFにしたときは図のように回線の途中で切れるため,電気が流れなくなります.
アノード(電池のプラス側でAと書くこともある)とカソード(電池のマイナス側でKと書くこともある)の間にパーツを配置させながら繋いでいくとそれぞれのパーツが役目を果たしていきます.
今回は面倒なこと考えずに電池のマイナス側をGNDと考えてください.
同じく今回のGPIOは電源出力として使うので,これが電池で言うプラス側です.
たとえばLEDは矢印の方向にアノード(プラス)からカソード(マイナス)を繋ぐと光る部品です.
プラスマイナスの違いが分かりにくいですが見分け方は
- 切る前の足が長い方がアノード側
- 上から見て円形を切ったように見える側がカソード側(切れてないものもある)
- たまに書いてるものもある
- 最悪テスター使って方向を調べる
極性がある部品は足が長い方がアノードと思えば間違いなかったはず.
LEDは3~5V程度の電圧なら壊れないと思うので,ラズパイ触ってるだけなら光らなければプラス側マイナス側を逆にすると光るかもしれません.
光らなかったらLEDのアノード・カソードを元に戻して電源ON.
それでも光らなければ他の線同士がしっかり接続されているか,電池は切れていないかなどをひとつひとつ順番に調べてみましょう.
題材
当日の実体配線図
一応下図のようにGNDへ共通して抵抗を挟んでもLEDは光るし配線もシンプルですが,緑色に比べて赤色がやたら光るので後々やりたいことができなくなるのでパス.
コードを書く
####インポートと定数の定義
from gpiozero import LED
LED_RED = LED(24)
LED_GREEN = LED(25)
赤や緑にLEDを光らせよう
from time import sleep
# 赤を5秒ON→1秒OFF→緑を5秒ON→1秒OFF
LED_RED.on()
sleep(5)
LED_RED.off()
sleep(1)
LED_GREEN.on()
sleep(5)
LED_GREEN.off()
sleep(1)
コピペを続けると延々と光らせられるぞ!
点滅させよう
さすがにコピペを続けるとミスも増えるので(offにするのを忘れて光りっぱなしだったり),点灯を関数にしてまとめてみましょう.
seconds
秒点灯させたあと1秒消灯する関数を定義します.
def flash_red(seconds):
LED_RED.on()
sleep(seconds)
LED_RED.off()
sleep(1)
def flash_green(seconds):
LED_GREEN.on()
sleep(seconds)
LED_GREEN.off()
sleep(1)
# 2色LEDなので,輝度を調節して赤と緑を同時にONにしたら橙色に光った
def flash_orange(seconds):
LED_RED.on()
LED_GREEN.on()
sleep(seconds)
LED_RED.off()
LED_GREEN.off()
sleep(1)
flash_red(3) # 赤色に3秒点灯
flash_green(5) # 緑色に5秒点灯
flash_orange(7) # 橙色に7秒点灯
消灯時間もコントロールできます.
turn_on
秒点灯してturn_off
秒消灯できるように変更してみましょう.
def flash_red(turn_on, turn_off):
LED_RED.on()
sleep(turn_on)
LED_RED.off()
sleep(turn_off)
def flash_green(turn_on, turn_off):
LED_GREEN.on()
sleep(turn_on)
LED_GREEN.off()
sleep(turn_off)
def flash_orange(turn_on, turn_off):
LED_RED.on()
LED_GREEN.on()
sleep(turn_on)
LED_RED.off()
LED_GREEN.off()
sleep(turn_off)
flash_led(3, 1) # 赤色に3秒点灯して1秒消灯する
flash_green(10, 5) # 緑色に10秒点灯して5秒消灯する
flash_orange(1, 60 * 60 * 24 * 365) # 橙色に1秒点灯して1年沈黙する
点灯時間をランダムにしてみよう
ここでrandom.randint
を教えます.
ランダム秒間点灯したあと別のランダム秒だけ消灯して, 毎回違う秒数で点滅をさせてみようという課題を出しました.
最初に書いたコード
# onとoffの時間がどの色も同じになってしまう
from random import randint
on_seconds = randint(1, 10)
off_seconds = randint(1, 10)
for _ in range(3):
flash_red(on_seconds, off_seconds)
flash_green(on_seconds, off_seconds)
flash_orange(on_seconds, off_seconds)
on_seconds
で3
, off_seconds
で2
が代入された場合
『3秒赤色に点灯→2秒消灯→3秒緑色に点灯→2秒消灯→3秒橙色に点灯→2秒消灯』というのを3回繰り返すだけの動作になってしまいます.
これでは課題の動作と違います.
ここで,たとえ乱数を代入したとしても毎回違う乱数を生成してくれる訳ではないと理解します.
修正したコード
from time import sleep
from random import randint
from gpiozero import LED
def flash_red():
turn_on = randint(1, 10)
turn_off = randint(1, 10)
LED_RED.on()
sleep(turn_on)
LED_RED.off()
sleep(turn_off)
def flash_green():
turn_on = randint(1, 10)
turn_off = randint(1, 10)
LED_GREEN.on()
sleep(turn_on)
LED_GREEN.off()
sleep(turn_off)
def flash_orange():
turn_on = randint(1, 10)
turn_off = randint(1, 10)
LED_RED.on()
LED_GREEN.on()
sleep(turn_on)
LED_RED.off()
LED_GREEN.off()
sleep(turn_off)
for _ in range(3):
flash_red()
flash_green()
flash_orange()
これで毎回turn_on
とturn_off
に別の数字が代入されるため,課題を達成しました.
flash_spam
の集まり,共通化できそうだけど3色に光らせるだけだし難しいことさせずこのままで良いのです.
点灯する色もランダムに変えてみよう
クリスマスの電飾みたいになってきた.という感想が出たので次は点灯する色にもランダム性を持たせてもらいました.
そろそろクラスにまとめたくなったけど,当日クラスに直したか覚えていないので関数ベタ書きでいきます.
プログラミング一日目の人がこれ一発で書いたのすごいと思った(こなみ
from time import sleep
from random import randint
from gpiozero import LED
def flash_red():
turn_on = randint(1, 10)
turn_off = randint(1, 10)
LED_RED.on()
sleep(turn_on)
LED_RED.off()
sleep(turn_off)
def flash_green():
turn_on = randint(1, 10)
turn_off = randint(1, 10)
LED_GREEN.on()
sleep(turn_on)
LED_GREEN.off()
sleep(turn_off)
def flash_orange():
turn_on = randint(1, 10)
turn_off = randint(1, 10)
LED_RED.on()
LED_GREEN.on()
sleep(turn_on)
LED_RED.off()
LED_GREEN.off()
sleep(turn_off)
def flash_random():
color_list = [flash_red(), flash_green(), flash_orange()]
select_color = randint(0, 2)
color_list[select_color]
for _ in range(10):
flash_random()
ランダムな色が,ランダム秒間点灯し,ランダム秒間消灯するのを繰り返すプログラムの完成です.
パリピっぽい感じになりましたね.
GPIOピンはまだ余っているので同じ回路を並べてもいいし,遅延回路を用意してLED繋げていったらクリスマス時期によく見かけるアレが作れそうです.
GPIOで何ができるの?
スイッチ.
今回は出力(電源のON/OFF)に使いましたが,一定以上の電圧入力を境にON/OFFと認識して他のコントロールへ渡すこともできます.
ラズパイはピンによって違う役割が振られていることもありますが,GPIOピンとして番号が振られていれば基本的にどれも同じように入出力スイッチとして使えたはず.
2人から疑問を持たれたので,GPIOは何に使うのかよくわからないものなのかもしれない.
Lチカになんの意味があるの?
今後の目標が「ロボットを作る」と明確なので課題設定がしやすかったです.
たとえば今回の例を置き換えれば貧弱な想像力でも下記のようなことはできる訳です.
- LEDのON/OFFを切り替える
- 機構のON/OFFが切り替えができる
- 光る時間を変更する
- 関数を定義したことでモーターなどの動作時間を変更しやすくなる
- ランダム性を持たせる
- 自動制御をする場合,「壁にぶつかったら右へ90°回転する」だけでは都合が悪い場面に対応しやすくなる
今後の展望
gpiozero
には他にもクラスがあって,Motor
やRobot
などクラス名を読んでるだけでも
面白そうなものがたくさんあります.
次はタミヤのリモコンロボット工作シリーズをラズパイで制御しようと話を持ち込んできました.
LED光らせて終わりでなく,次に何やりたいって自分から持ち込んでこれるってすごいですわ.
Lチカがロボットだとどんな応用に繋がるか話したら興味が増したそうなので,
別の人にもラズパイを通じて何か教えるなら「何ができたら楽しいと思ってラズパイ買ったの?」から
話を始めると途中でダレることもなさそう.
自分の感想
私はいま深層学習系の機械学習で仕事をしていて,先日からベイジアンの学習会にも参加しはじめました.
今回の相手は理学療法を学んだ後に心理学へ進んだとのことで「心理学でベイズって何に使うんですか?」
と質問したら面白そうな話を聞かせていただけました.
ついでにロボットの話でもベイジアンの成果が使われていたりするのかなと調べてたら
原田 篤, 鈴木 健嗣(2009). 人間型ロボットによる変分ベイズ学習を用いた稼動範囲の獲得
全国大会講演論文集 第71回(人工知能と認知科学), 199-200
というものを見つけ,アームとかの耐荷重を自己学習できそうやなと思いました.
やってみたいことがドンドン増えていくけど,タミヤのロボット工作シリーズにフォークリフト(許容荷重100g)を
見つけたので自分もこっち側ちょこちょこ触りたい.喋りながらいろいろするの楽しいです.