この記事は、Raspberry Pi Advent Calendar 2017 25日目の記事として、いろいろと手直しを行いました。
メリークリスマス!
クリスマス当日の今日 25日、みなさんいかがお過ごしでしょうか。
今年のクリスマスは、残念ながら25日が平日で、イブの日になんか次の日仕事じゃねえか!と悲しんだ方もきっと多かったはず。
そこで今回は、時間がなくて会えないカップルや、まだクリスマスプレゼントあげてない!という人にぴったりな電子工作に挑戦します。
何ができるかは最後のお楽しみだよ!
購入するもの
今回、使うものは以下の通りです。
- ラズペリーパイZeroセット
- モータードライバー(DRV8835)
- ジャンパワイヤ数本
- ブレッドボード
- 電池ケース(4本入るやつ)と単三電池4本
- 大人のモーター
ラズパイZeroから、電池ケースについては、モーターを動かす際に必要となる一般的なキットだね。
詳しく知りたい!っていう方は、以前、DCモーターを動かした記事があるのでこちらを見てね。
www.tohuandkonsome.site
大人のモーターについては、好きなものを購入しよう!
自分はこんな感じのやつを購入しました。
さあ、何ができるのかな!
ラズペリーパイZeroの設定をしよう
何はともあれ、まずはラズパイを用意しよう。
とはいえ、ラズパイの初期設定については、こちらの記事にも書いたので、ここでは省略しちゃうよ。
www.tohuandkonsome.site
PythonとラズパイのGPIOをコントロールするWiringPiまで使えるようなれば大丈夫!
大人のモーターを電子工作に使えるようにする
ブレッドボードに接続しやすいように、ハサミでケーブルを途中で切っちゃうよ。
カッターでビニール部分を削ると、プラスとマイナスの導線がでてきた。
ちなみに行き当たりばったりでやってるから、ここでどうしよもなかったらこの企画は、ここで中止だったよ!
ラズパイと大人のモーターをつなげる
そしたら、ラズパイと大人のモーター、電池、モータードライバたちをブレッドボード上でつなげます。
なんだかごちゃごちゃしているけれども、こんな感じでつなげてみたよ!
写真には、DRV8835以外のモータードライバと、普通のDCモーターが写っているけれども、これは気にしないで大丈夫!
最初にいろんなモータードライバーと、DCモーターでテストしてたんだ。
モータードライバーの制御は、以下のサイトが一番わかりやすいです!
英語なのでなんとなくしかわからないのですが、それでもなんとなくわかる、わかりやすさです!
www.pololu.com
今回は、シンプルなPHASE/ENABLEモードで設定を行っているよ!
余談ですが、同じDRV8835でもピンの数が少ないやつがあったりして混乱したことがあります。
モーターを動かすシンプルなコード
とりあえずモーターが動くか確認します。
DRV8835を使ったモータ制御
うまくいけば、激しく動くはずです。
操作画面を作成する
コマンドラインからも動かせるのですが、せっかくなので、操作画面を用意しましょう。
そのほうがきっと盛り上がるはずです!
Flaskを準備する
操作画面は、一番シンプルなpythonのWebフレームワーク「Flask」を使用します。
ラズパイにさっそくFlaskをインストールします。
Flaskをインストールするよ
pi@raspberrypi:~ $ sudo pip install Flask
Collecting Flask
インストールが終わったら、小さいWebアプリであるapp.pyを書こう。
最小限のFlaskアプリケーション app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return "Hello World!"
if __name__ == '__main__':
app.run(host='0.0.0.0')
書き終わったら、さっそく起動してみよう。
$ python app.py
python app.py
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
無事、起動したかな?
起動したら、PCで「http://ラズパイのIP:5000」にアクセスしてみよう。
こんな画面が見れるはず。
無事見れたら、Webアプリケーションを止める。
コマンドライン上で、「Crtl + c 」で終了させよう。
さきほどのdc_motor.pyを呼ぶ処理を書こう
それでは、さきほどのdc_motor.pyを、app.pyと同じディレクトリに置こう。
app.pyとdc.motorを同じところに
$ tree
.
├── app.py
├── dc_motor.py
次にapp.pyを修正します。
app.py
from flask import Flask
from flask import render_template
import dc_motor
app = Flask(__name__)
@app.route('/')
def hello_world():
return "Hello World!"
@app.route('/start')
def start_motor():
dcmotor = dc_motor.DC_Motor_DRV8835(a_phase=14, a_enbl=15)
dcmotor.start()
return "start"
@app.route('/stop')
def stop_motor():
dcmotor = dc_motor.DC_Motor_DRV8835(a_phase=14, a_enbl=15)
dcmotor.stop()
return "stop"
if __name__ == '__main__':
app.run(host='0.0.0.0')
ここでは、「/start」「/stop」それぞれにアクセスがあった場合、さきほどのクラス「DC_Motor_DRV8835」のモーターを回転させるstartメソッドと、止めるstopメソッドを呼ぶようにします。
試しにこの段階で、「http://ラズパイのIP:5000/start」にアクセスすると、モーターが動きます。
画面をつくろう
最後に、シンプルな操作画面をhtml、css、javascriptでつくっちゃいましょう。
完成イメージはこんな感じです。
せっかくなのでHerokuにもデプロイしました。
https://sample-basic-css.herokuapp.com/sample/2/toggle3
ただですね、スマホとかの小さい画面でみることを一切考慮していない残念な画面になってます。
まず、リソースを置くディレクトリをそれぞれ作成します。
ディレクトリを新規につくる
$ mkdir templates static
ディレクトリ構成はこんな感じになるよ。
こんな感じになる
$ tree
.
├── app.py
├── dc_motor.py
├── static
└── templates
そうしたら、htmlファイルをtemplates配下に、cssとjavascriptをstatic配下に置きます。
ついでにapp.pyのルートディレクトリにアクセスがあった場合(つまりトップ画面)の処理を以下のように修正します。
app.py
@app.route('/')
def hello_world():
return render_template('index.html', title="大人のモーター")
それぞれのファイルはこんな感じにしました。
index.html
<head>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<script type="text/javascript" src="{{ url_for('static', filename='motor.js') }}"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/earlyaccess/hannari.css">
<title> {{ title }} </title>
</head>
<div class="container">
<input class="toggle" id="left-toggle" type="radio" name="toggle" >
<label for="left-toggle" id="left-label">うごく</label>
<input class="toggle" id="right-toggle" type="radio" name="toggle" checked>
<label for="right-toggle" id="right-label">とまる</label>
</div>
また、以下のcssファイルもstaticディレクトリ配下に置きます。
style.css
*,*:before,*:after{
box-sizing: border-box;
}
html,body{
height: 100%;
font-family: "Hannari";
}
.container{
position:relative;
z-index:0;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
input[type="radio"]{
display: none;
}
label{
border:3px solid #ff99cc;
padding:10px;
width: 50%;
max-width:500px;
max-height:300px;
min-width: 100px;
min-height: 60px;
height: 50%;
font-size:150px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
transition: background 600ms ease, color 600ms ease;
min-width:61px;
cursor:pointer;
}
#left-label:after{
top:0;
left:0;
position:absolute;
content:"";
height: 100%;
width: 100%;
background-color:#ff99cc;
transition: left 200ms cubic-bezier(0.77, 0, 0.175, 1);
z-index: -1;
}
#left-label{
border-right:0;
}
#left-label:after{
left:100%;
}
input[type="radio"]:checked + label{
color: #fff;
transition: color 200ms;
}
input[type="radio"]:checked + label:after{
left:0% !important;
}
motor.js
console.log("motor.js");
function requestMotorControll(message){
const request = new XMLHttpRequest();
request.open("GET", "http://localhost:5000/" + message);
request.addEventListener("load", (event) => {
console.log(event.target.status);
console.log(event.target.responseText);
});
request.send();
}
document.addEventListener("DOMContentLoaded", function(event) {
console.log("DOM fully loaded and parsed");
var leftToggle = document.querySelector("#left-toggle");
leftToggle.addEventListener("click", function( event ){
requestMotorControll("start");
});
var rightToggle = document.querySelector("#right-toggle");
rightToggle.addEventListener("click", function( event ){
requestMotorControll("stop");
});
});
画面に関しては、CodePenで素敵なトグルボタンを探していたのですが、シンプルなトグルという言葉を信じて見てたのですが、ある程度理解するのにものすごく時間がかかりました。
HTMLとCSSになんだかとても苦手意識があります。
See the Pen Simple Toggle by Dominic Magnifico (@magnificode) on CodePen.
最後に
ここまできたら、あとはラッピングしてプレゼントするだけです!
あれ、プレゼント相手の家でラズパイのWifiの設定しないといけないとか、外部からアクセスするときはルーターの設定しなきゃとかあるんですが、二人の愛の間にはきっとささいな問題です!
僕には何に使うかわかりませんが、カメラをつけてボタンの画面からみても面白いかもしれませんね!
それでは、素敵なクリスマスを!