2015年:ESP-WROOM-02 で【モバイル物理スイッチ】を作る!!
※注意)Qiitaからの移転で、2015年12月02日に投稿した記事なので、内容はかなり古いです
2015年12月19日 23時59分追記:申し訳ありません。pullupの仕方に、誤りがありました。
2015年12月20日 14時21分追記:そもそも pullup/pulldown が不要である事が分かりました。
ESP8266 Advent Calendar 2015 の2日目担当 ie4 と申します。
このエントリーでは、「ESP-WROOM-02を使うと、結局どんなものが作れるのか。」という疑問に答えるべく、その1例を挙げてみたいと思います。
携帯できるインターネット物理ボタンを作ろう
Web上のアプリケーションに、ON/OFFの信号を送る物理ボタンを作ります。
で、その物理ボタンにバッテリーを繋いで、持ち歩けるようにするのが目標です。
ぶっちゃけ、物理ボタンである事にこだわらなければ、スマホで実現可能な機能です。
ただ、物理ボタンには、こだわるだけの価値があります
- 操作する人への案内が簡単:「このQRを読んで、このURLにアクセスして、それから…」と長々と説明しなくても、この物理ボタンを手渡せば終了
- 操作が簡単で、誤操作がない: 余計なボタンや機能がないので、ホームボタンやメニューボタンなど、変なボタンを押してしまって、アタフタする事がない
- ボタンをカチカチすることの楽しさ: 説明しづらいけど、ボタンカチカチは楽しい
この辺が、私の考える物理ボタンの良さです。
で、作るのは良いけど、その物理ボタンが結局何の役に立つの、という点ですが、ON/OFFを通知するだけの機能なので、Webアプリ側の作り方次第で何でも出来ます。
オフィスの隅にあるコーヒーメーカーにコーヒーを淹れさせる事も、ドローンにぶら下げたクス玉を割って門出を祝うことも、作り方次第では可能です。(本エントリーより難しい実装が別途必要ですが…)
とりあえず今回は、YesかNoかを回答するボタンを作成する事にします。
ユースケースは、エントリー後半に記載します。
完成品はこちら
かなり雑な作りですが、これでも立派にインターネットに繋がります・・・
白いボタンで1、赤いボタンで10をサーバーに送信します。
同時に押した場合は、11が送信され、何も押してない状態に戻ると0が送信されます。
ケースを開けると、中身は
このようになっており、
基板を裏返すと
このようになっております… (お見せするのが恥ずかしい有様です…)
次に、ただサーバーへ数値を送信するだけでも意味がないので、それをモニタリングします。
サーバー側はNode.jsで実装し、socket.ioを使って、Web画面を切り替えています。
ボタンを何も押していない時は、**?**が表示されます。
赤いボタンを押せばNoが表示され、
白いボタンを押せばYesが表示されます。
以上が、最終的に作るモノになります。
以下、作り方となります。
用意したモノ
ESP-WROOM-02 ピッチ変換済みモジュール (フル版)
- これが無いと始まりません。
- ピッチ変換済みのESP-WROOM-02モジュールは、各社から出ていますが、今回はスイッチサイエンスさんのフル版を利用しました。
- ボタンの入力に使うのは2ピンだけなので、デジタル入力できるピンが2つ空いていれば、どのモジュールでも良いかと思います。ただ、ケースに収まるサイズを選ぶようにしましょう。
- ピンヘッダを付けるために、はんだ付けする作業が必要です。
リチウムイオンポリマー電池 3.7V 400mAh
- 今回の工作の要は、なんと言ってもこの電源(バッテリー)です。サイズ的にもジャストサイズで、電圧も容量もジャストです。電源の確保については、CR2032・CR2450・18650等など、色々と試行錯誤した結果、最終的にココに落ち着きました。
- 先日まで品切れ状態でしたが、大量入荷したようです。
- スイッチサイエンスさんのページにも記載がありますが、取扱いには十分にご注意ください。
リチウムイオン電池充電器 (マイクロUSBタイプ)
- 上記バッテリーと一緒に購入しておきましょう。
- PCでの充電用にマイクロUSBケーブルが別途必要ですが、マイクロUSBタイプの携帯充電器があれば、その携帯充電器から充電可能なので、マイクロUSBケーブルは不要です。
JST製2ピンPHコネクタ用ソケット
- 基板へバッテリーを接続する際に必要になります。
普通のピンヘッダ10本セット
- ESP-WROOM-02を基板に取り付ける際に必要になります。
- また、他の用途にも活躍するので、ぜひ持っておきたい消耗品です。
スライドスイッチ
- 基板に取り付け、電源のON/OFFに使用します。
ポータブル プラスチックケース
- もろもろ、このケースに収めます。手のひらに完全に収まるサイズです。
ユニバーサル基板 (44mm×69mm)
- 上記ケースにスッポリ収まる基板です。
- ケースにカチッとはハマらないので、ケースの中身がカタカタするのが嫌な場合は、ケースにねじ止めするなりする必要があります。
タクトスイッチキャップ 2個 + タクトスイッチキャップ (赤、白 各1個)
- 押しボタンはこちらを使います。
カーボン抵抗 10kΩ
- 追記:今回のケースでは、pullup/pulldown抵抗は不要でした。
プルアップ/プルダウン抵抗に使用します。-
実は、うっかりコレを実装するのを忘れてしまったのですが、それでも動くには動くようです。とはいえ、パーツを破損させない為にも、「なぜか動かない!><」という事態を回避する為にも、実装しておいた方が良いです。追記:今回のケースでは、スイッチング等の開放状態が発生しない為、電流制限抵抗等の目的がない限り、プルアップ/プルダウンは不要でした - プルアップ/プルダウン抵抗に関しては、後述します。
その他
電子工作用はんだ
- 電子工作と言えば、はんだですね。
- ブレッドボードのおかげで、「とりあえず動くもの」を作るのは簡単になりましたが、色んなパーツと組み合わせたり、ケースに入れて云々…とこだわりだすと、やはり避けては通れないのが、はんだ付けです。
- ワイヤラッピング - Wikipediaという、はんだ付けを行わない電子配線もあるみたいです。⇒ ラッピングツール - 共立エレショップ
ダイヤル式温度制御はんだこて
- 温度切り替えできるモノにしようと買い替えました。
- はんだを拭った状態で長時間放置してしまった為、コテが酸化し、はんだ付け効率が非常に悪くなった為、買い替える事にしました。
- はんだこてのクリーニング方法は、こちらの動画「コテ先クリーニングの理想的なタイミングとハンダゴテの保管方法 - Youtube」で分かり易く解説されています。
ラッピングワイヤ 5色セット
- 映画などで、ニッパーでちょきんと切ると、タイマーが止まったり、早まったりする奴ですね。
- 剥き出しの銅線だと、基板の裏で交差したり出来ないので、被膜付きの銅線が必要です。
- 太すぎると取り回しが不便ですが、細すぎると加工が難しいです。
スズメッキ線 φ0.6mm
- ほとんど使ってないので、不要かもしれませんが、持っておくと役に立ちます。
- 抵抗やコンデンサなどの、切り落とした余分な足を再利用するケースも多々あります。
FTDI USB・シリアル変換ケーブル (3.3V)
- ESP-WROOM-02 へのプログラミングは、コレ経由でやることにします。
- 電圧をお間違えなく(5Vではないです)。
- いささか高いので、この辺もある程度自作したい感じではあります。(まぁ、いくつも必要なモノではありませんが)
ホットナイフ
- ケースから押しボタンを出すため、矩形の穴を開けるのに使用しました。
- ただ、プラスティックを溶かして穴を開ける為、バリも大きく、嫌な臭いも出るので、ドリルで小さな穴をたくさん開けて、矩形状にくり抜く方が良さそうです。
配線・回路図
本エントリーでは、ESP-WROOM-02へのスケッチの書き込み方や接続の方法については触れません。
後日、誰かがきっと、そのようなエントリーを投稿してくれるでしょうし、もうあるかもしれません。
というわけで早速、完成した携帯できる物理スイッチが、どのような構成になっているかを見てみます。
配線は、下記のようにしました。
※スケッチ書き込み済みの FLASH Boot Mode での配線です。
追記: pullupの配線に誤りがありました。正しくは、2つ目の図の配線となります。
▼誤りがある方の図
▼正しい方の図
※手書きで申し訳ありません…
- pullup抵抗とpulldown抵抗が入っていますが、「pullup/pulldwonってなんぞ!」という方は、こちらの動画「【実況?】 零からの電子工作 第10回:タクトスイッチ 後編」で非常に分かり易く解説されているので、視聴をオススメします(9分20秒辺りからpullup抵抗を無くした場合の実際の挙動が見れます)。 追記:動画は、不安定になるのを防止する目的でpullup/pulldownを入れていますが、上図では開放状態(不安定になる状態)が発生しない為、実際は、電流制限抵抗としての役割しかありません。電流制限抵抗としての役割が不要であれば、pullup/pulldown抵抗も不要です。
書き込み済みのスケッチは、下記になります。
#include <ESP8266WiFi.h>
const char* ssid = "お使いのWiFiのSSIDを入れてください";
const char* password = "お使いのWiFiのPasswordを入れてください";
const char* host = "IPアドレス or ホスト名"; // Webアプリを設置するサーバー
const int port = 20000; // 接続を受け付けるポート
const int btnYes = 12;
const int btnNo = 13;
int curData ;
int tmpData ;
void setup() {
pinMode(btnYes, INPUT_PULLUP);
pinMode(btnNo, INPUT_PULLUP);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
void loop() {
int yesState = digitalRead(btnYes);
int noState = digitalRead(btnNo);
curData = 0 ;
if(!yesState){
curData = 1 ;
}
if(!noState){
curData |= 1 << 1 ;
}
if ( tmpData != curData ) {
sendMessage(curData);
tmpData = curData;
}
delay(50);
}
void sendMessage(int data) {
WiFiClient client;
if (!client.connect(host, port)) {
return;
}
client.print(data, BIN);
while (client.available()) {
String line = client.readStringUntil('\r');
}
}
WiFiへの接続が成功すれば、これで該当サーバーのポート:20000番へデータを送信します。
サーバー側
サーバー側では、Node.js でデータを受け付けます。
Webアプリですが、通常の80番ポートは使用せず、下記の2つのポートを使用する事にしました。
8888番ポート: モニタリングWebアプリ用ポート
20000番ポート: 物理ボタンからのデータの受け取り
var net = require('net'),
http = require("http"),
socketio = require("socket.io"),
fs = require("fs");
// モニタリング画面の用意
var server = http.createServer(function(req, res) {
res.writeHead(200, {"Content-Type":"text/html"});
var output = fs.readFileSync("./index.html", "utf-8");
res.end(output);
}).listen(8888);
var io = socketio.listen(server);
// 物理ボタンからのデータ受け口
var server = net.createServer(function(conn){
conn.on('data', function(data){
console.log(data.toString('ascii'));
// モニタリング画面へデータ送信
io.sockets.emit("message", {value:data.toString('ascii')});
});
}).listen(20000);
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Yes/No Bottun</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script type="text/javascript">
var socket = io.connect();
socket.on("connect", function(){});
socket.on("disconnect", function(client){});
socket.on("message", function(data){ addMessage(data.value); });
function addMessage(val) {
if(val==1){
color = "#fff";
fontc = "#000";
text = "Yes";
}else if(val==10){
color = "#f00";
fontc = "#fff";
text = "No";
}else{
color = "#333";
fontc = "#fff";
text = "?";
}
$("#answer").css("background-color",color);
$("#answer").css("color",fontc);
$("#answer").text(text);
}
</script>
<style>
body{
background-color: #000;
}
#answer{
height: 300px;
width: 300px;
font-size: 150px;
font-weight: bold;
color: #fff;
display: table-cell;
vertical-align: middle;
text-align: center;
background-color: #333;
}
</style>
</head>
<body>
<div id="answer">?</div>
</body>
</html>
必要に応じて、requireされているモジュールをnpmなりでインストールしておいてください。
動作確認
ユニバーサル基板へ各パーツをはんだ付けし、配線を済ませ、バッテリーを繋いで、node appすれば、準備はすべて完了です。
http://WebアプリのIPアドレス:8888/
へアクセスすると、以下のような?マークの画面が表示され
白と赤の物理ボタンで、YesとNoの表示に切り替わります。
※離すとまた**?**に戻ります
また、ターミナル上にも
$ ls
app.js index.html
$
$ node app
1
0
10
0
のように、物理ボタンから送信された数値が、ほぼリアルタイムで表示されます。
以上で、インターネット接続可能な持ち歩ける物理ボタンの完成です。
おまけ
ユースケース
Webアプリ側は作り変える必要がありますが、例えばこんな使い方。
- 100個作って、その場で人気投票大会
- 10個作って、審査員10名によるオーディション (8イイネ以上が合格)
- 5個作って、審査員5名による、紅白戦 (3イイネ以上が勝利)
- 1個作って、誰かが隠し持ち、みんなの質問にYes/Noで答えて(Yes/Noの回答は画面で確認)、誰がもってるか当てる
ちょうど忘年会シーズンですので、何かのゲームに使ってみてはいかがでしょうか。
書き終えてみて
- Advent Calendar 初投稿でした。作法とかよく分かっていないので、至らぬ点もあったかも。
- スイッチという表記と、ボタンという表記が混在し、統一できていない…スイッチは機能として、ボタンはUIとして、書き分けているとお考えください。
- イメージが湧きやすいようにと、イラスト付きで臨みましたが、逆効果だった可能性も。
- 作っても作っても、作りたいモノが無くならないのが、ESP-WROOM-02の面白さかもしれません。
Discussion
本エントリーについては、過去に色々と誤りを指摘頂いているので、その内容も残しておきます。
▼ご指摘
..snip..
..snip..
▼わたし
▼ご指摘
▼わたし
▼ご指摘
▼わたし
▼ご指摘
すごく優しくご指南頂きました。感謝しかないです。