はじめに
ウェブ技術だけで開発できるプロトタイプに便利なボードがあると聞いて、obniz IoT コンテスト2021に参加してみました。この文章は作業のログです。ドットマトリックスLEDの操作を試してみたところ、あっという間に電子工作に入門できてしまったのでそれを記事にすることにしました。
事前準備
HTML, CSS, JavaScriptは触ったことがないので一通りドキュメントを読みます。ドキュメントとしてはMDNを参照しました。
- JavaScript Primer(これは書籍でも出版されています)
- MDNのウェブ入門
をとりあえず読みました。そうは言っても全てが頭に入るわけではないので適宜MDNのドキュメントを参照します。
次に、obnizの使い方を確認しました。SDKのソースコードとドキュメントを見ました。基本になるObnizクラスは複数回継承されたもので、機能を探すために継承関係を人力で追うのは難しかったのですが、ドキュメントを見るようにすると楽に使い方が分かりました。
その後、チュートリアルでLEDを光らせて遊んでみました。チュートリアルは分かりやすいもので、特につまるところはなかったです。以前RasPiを触ったときはピンごとに機能が異なって頭を抱えたのですが、https://obniz.com/ja/doc/reference/board-1y/pinassign にあるように、obniz Board 1Yのピンはどれも機能は共通で分かりやすいです。アクセストークンを設定しない限りobnizのAPIはobniz idさえ分かれば誰からでもアクセス出来てしまうことに気付いたので一応制限しておくことにしました。https://obniz.com/ja/doc/reference/cloud/device-management/security-setting からトークンを発行すれば自動的にトークンなしでアクセスできなくなりました。
// idだけで通信できる
var obniz = new Obniz("XXXX-XXXX");
// これだともう少し安心
var obniz = new Obniz("XXXX-XXXX", {access_token: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"});
材料
製品 | 備考 |
---|---|
obniz Board 1Y | 無償提供していただきました |
A-3880EG | |
ジャンパワイヤ 18本(オス-メス12、メス-メス6) | |
抵抗 6個 |
動作映像
配線
A-3880EGのデータシート(a3880eg.pdf)によると、内部の配線は以下のようになっています。以下の図の端子の並びは製品と異なるので、番号と行、列の対応だけ確認します。この部品は本来赤と緑の2色の合計128個のLEDが含まれているため、単純に考えると256個も端子が必要になる計算になりますが、陽極や陰極を共通にすることで回路は複雑になるものの、端子は22個に収まっています。
この部品の端子に番号を振ったものが以下の図です。ICなどは反時計回りに番号が振られるのが一般的なようです。
そして、このドットマトリックスを以下の番号のように接続します(obniz Boardの端子は12個なので、今回は8x8のうち、6x6の範囲を使用しました。)配線中に適当な抵抗を入れておきます。2.2Vまで対応のようなので、抵抗を付けないままled.io_anode.drive('3v');
などとしてみましたが、エラーで止まるので、そのまま5Vにしたところ左上の緑色LEDを焼いてしまいました。全く不要な観察ですが、焼けるときは赤色に光ることが分かりました。
obniz Board 1Y | A-3880EG |
---|---|
0 | 19 |
1 | 16 |
2 | 13 |
3 | 3 |
4 | 6 |
5 | 9 |
6 | 21 |
7 | 18 |
8 | 15 |
9 | 1 |
10 | 4 |
11 | 7 |
プログラム
以下ではjsファイルをhtmlファイルに含むように書き換えています。
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
/>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script
src="https://unpkg.com/obniz@3.14.0/obniz.js"
crossorigin="anonymous"
></script>
</head>
<body>
<div id="obniz-debug"></div>
<h3>Connect From Your Browser</h3>
<button class="btn btn-primary" id="on">LED ON</button>
<button class="btn btn-primary" id="off">LED OFF</button>
<div id="print"></div>
<script>
const H = [[1,1,0,0,1,1],[1,1,0,0,1,1],[1,1,1,1,1,1],[1,1,1,1,1,1],[1,1,0,0,1,1],[1,1,0,0,1,1]];
const full = [[1,1,1,1,1,1],[1,1,1,1,1,1],[1,1,1,1,1,1],[1,1,1,1,1,1],[1,1,1,1,1,1],[1,1,1,1,1,1]];
// 指定したミリ秒の間実行を停止する関数
async function sleep(msec) {
await new Promise(resolve => setTimeout(resolve, msec));
}
// // version1
// // 指定した位置のLEDを1回点滅させる
// async function blink(x, y) {
// // 範囲外の入力では何もしない
// if (x < 0 || x > 5 || y < 0 || y > 5) {
// return;
// }
// anode[x].output(true); // obnizの指定した端子を陽極として機能させる
// cathode[y].output(false); // obnizの指定した端子を陰極として機能させる
// await sleep(0.01);
// anode[x].end(); // 陽極機能を停止する
// cathode[y].end(); // 陰極機能を停止する
// }
// ドットマトリックス全体を一回点滅させる
// async function single(matrix) {
// for (let x = 0; x < 6; ++x) {
// for (let y = 0; y < 6; ++y) {
// if (matrix[x][y]) {
// await blink(x, y);
// }
// }
// }
// }
// 連続して点灯させることで表示する(この関数を呼び出す)
async function display(matrix) {
displayOn = true;
while (displayOn) {
await single(matrix);
}
}
// 指定した行のLEDを1回点滅させる
async function blink_row(x, arr) {
if (x < 0 || x > 5) {
return;
}
if (arr.length !== 6){
return;
}
anode[x].output(true);
for (let y = 0; y < 6; ++y) {
if (arr[y])
{
cathode[y].output(false);
}
}
await sleep(1);
anode[x].end();
for (let y = 0; y < 6; ++y) {
if (arr[y])
{
cathode[y].end();
}
}
}
async function single(matrix) {
for (let x = 0; x < 6; ++x) {
await blink_row(x, matrix[x]);
}
}
var obniz = new Obniz("XXXX-XXXX", {access_token: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"});
matrix = new Array(6);
for (let i = 0; i < 6; ++i) {
matrix[i] = new Array(6).fill(false);
}
// このグローバル変数がfalseになるとdisplay中のループは終了する
displayOn = false;
obniz.onconnect = async function() {
anode = [obniz.io0, obniz.io1, obniz.io2, obniz.io3, obniz.io4, obniz.io5];
cathode = [obniz.io6, obniz.io7, obniz.io8, obniz.io9, obniz.io10, obniz.io11];
// 以下はobniz Board 1Yの液晶に表示するためのコード(サンプルそのまま)
// 接続に異常がないか見やすいので残しておく
obniz.display.clear();
obniz.display.print("Hello World");
obniz.display.print("🧡😁");
$("#on").click(function() {
obniz.display.clear();
obniz.display.print("ON");
display(H); // Hello worldの1文字目
});
$("#off").click(function() {
// display関数のループで参照されるグローバル変数をfalseにしてループを終了する
displayOn = false;
obniz.display.clear();
obniz.display.print("OFF");
});
};
</script>
</body>
</html>
ドットマトリックスLEDは端子が少なくて配線はコンパクトに済みますが、その代わりこの製品の場合一度に64個のLEDを自由に操作することは出来ません。そこで、ダイナミック点灯という方法を用いました。ダイナミック点灯方式ではLEDを(人間が知覚できない程度に高速に)順番に点灯、消灯を繰り返すことで、実際には連続に点灯していないLEDを連続に点灯しているように見せる方法です。制御コメントアウトされたバージョン1のコードは、64個のLEDを1個ずつ点灯、消灯を繰り返すものです。コメントアウトされていないコードは横一列は同時に点灯、消灯することでバージョン1より高速に点滅するようにしてみました。(↑の動画はバージョン1のものです)
ダイナミック点灯を始めて試してみたのですが、仕組みの理解にはとても良かったのです。しかし、動画で明らかなように、ブラウザ越しの操作によるレイテンシが原因なのか、点滅しているのははっきり分かってしまうという課題が残りました。今後改善するなら、pwm出力とシフトレジスタなどを使って見れば良いのかなと妄想しています(間違っているかもしれません。)ドットマトリックスの使用が目的なら、MAX7219という制御用ICが付いた製品を最初から購入してしまえば、MatrixLED_MAX7219
というクラスが用意されていて簡単そうです。
終わりに
ウェブ周りも電子工作も技術が一切ないところからスタートしましたが、思ったより簡単に電子工作が出来てしまいました。
arduinoなどを利用した例だとレイテンシは気にしなくて良さそうですが、obniz Board 1Yで良かった点は、12個もある端子全てが同じ機能になっていて、とにかくあるだけ使って配線すれば、ICを組み合わせたりするような知識がなくてもそれなりに動いてしまう、という所だと思います。実は、今回使用したケーブル類やドットマトリックスは、数年前にraspberry piで電子工作しようとして、データシートを読むのが億劫になって途中で投げ出したものを掘り返してきたものでした。
高度な工作をするには機能不足かもしれませんが、挫折経験があっても最初の電子工作が出来てとても良い経験が出来ました。環境構築なしに気楽に始めて試行錯誤出来るので、教育用途だったり、プロトタイピングに便利な製品だと思いました。
-
tak0kada
さんが
2021/05/19
に
編集
をしました。
(メッセージ: 初版)
-
tak0kada
さんが
2021/05/19
に
編集
をしました。
-
tak0kada
さんが
2021/05/19
に
編集
をしました。
-
tak0kada
さんが
2021/05/19
に
編集
をしました。
-
tak0kada
さんが
2021/05/19
に
編集
をしました。
-
tak0kada
さんが
2021/05/20
に
編集
をしました。
Opening
tak0kada
2021/06/07
ログインしてコメントを投稿するhttps://obniz.com/ja/doc/reference/common/io-animation というダイナミック点灯や、ステッピングモーターの制御用のapiがあるのでそれを使うとA-3880EGも正しく点灯できるはず