bottleでScratchXとDigisparkをつなげる
タイトルの簡単な説明
- bottle → python で作られたシンプルな Webフレームワーク。
- ScratchX → ウェブブラウザベースな Scratch2.0 にプラグイン拡張をできるようにしたもの?(曖昧)
- Digispark → 1000円ちょっとで買える、小さくて Arduino クローンなすごいやつ。
やること
DigisparkのRGB Shield(LED Shieldではなく)を使ってプログラミング入門的なことをしたいので、
プログラミング入門に最適であろう Scratch (ScratchX) からDigisparkを操作する。
※実際にやる際は、ご自分の責任でお願いいたします。
動作の流れ
- bottleで http://localhost:9000 のローカルサーバーを立てる。
- ScratchXから http://localhost:9000/blink にRGBデータを送信する。
- bottleで http://localhost:9000/blink に送られてきたデータを解析する。
- pyusbでDigisparkにLEDを点灯させる命令を送信する。
- 動作の様子
環境
Digispark
- DigisparkのWikiを参考にArduino IDEをインストールする。
- 上記ページを参考にArduino IDEにDigisparkのボードマネージャーを入れる。
- ArduinoIDEで、ファイル > スケッチの例 > DigisparkUSB > DigiBlink を開いて、Digisparkに書き込む。
※"→"のアイコンのボタンが書き込むボタン。"Plug in device now..."の表示が出てきたら、Digisparkを抜き差しする。上手く書き込めなかった場合は、諦めず、また書き込む。2,3回の書き込み失敗はよくある。諦めない、大事。
libusb
USBライブラリ
Windows(Win7)
- Windowsではドライバのせいか、うまくいかなかったので、ドライバを書き換えた。
- zadig(usbドライバ書き換えソフト)をダウンロードする。
- zadigでDigiUSBのドライバを
libusb-win32
に変更する。※他のデバイスのドライバを書き変えるとマズいので、慎重に…
追記 2016/09/26
他のサイトなどを見ると、WinUSB
のほうが多数なので、私の方でもWinUSB
に変更するようにしています。
追記終わり
OSX(El Capitan 10.11)
- homebrewでlibusbをインストールする。
brew install libusb
Linux(Ubuntu14.04)
- apt-getでlibusbをインストールする。(なんとなくdevバージョンを入れた)
sudo apt-get install libusb-dev
Python
※いずれの環境下でも、バージョンは 3.5.0
だった
pythonをインストール
pip(pythonパッケージマネージャー)をインストール
easy_install pip
bottleとpyusbをインストール
pip install bottle pyusb
LinuxでユーザーローカルのPythonだと、pyusbを使ってUSBにアクセスするとき、パーミッションエラーが出たので、Stack Overflowのこの投稿 や USB Devices - Google Chrome を参考に解決した。
(Chromeのページを見ると、pyusbに限ったことではない感じ。)私の場合は、
/etc/udev/rules.d/
に50ーdigispark.rules
というファイルを作り、
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05df", MODE="0664", GROUP="plugdev"
と書き込み、再起動した。
ウェブブラウザ
ScratchX が Flash Player で動作してるので、 Flash Player が動くブラウザなら何でも良いはず。
プログラム
app.py
- bottle のローカルサーバーを建てて、ScratchX で動いている javascript からRGBデータを受ける。
- pyusbでDigisparkに命令を送る。
#!python #-*-coding:utf-8-*- from __future__ import print_function from __future__ import unicode_literals from __future__ import division # for bottle from bottle import route, run, template, request, response, static_file # for scratchx import usb import sys sys.path.append("..") from arduino.usbdevice import ArduinoUsbDevice theDevice = None @route("/") def top(): return ''' <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <a href="http://scratchx.org/?url=http://localhost:9000/main.js">ScratchX</a> </body> </html> ''' @route("/<filepath:path>") def server_static(filepath): return static_file(filepath, root="./") @route("/blink") def blink(): theDevice = ArduinoUsbDevice(idVendor=0x16c0, idProduct=0x05df) red = request.query.get('red') green = request.query.get('green') blue = request.query.get('blue') print("red:{}, green:{}, blue:{}".format(red, green, blue)) red = int(mapping(red)) green = int(mapping(green)) blue = int(mapping(blue)) theDevice.write(ord("s")) theDevice.write(red) theDevice.write(green) theDevice.write(blue) print("mred:{}, mgreen:{}, mblue:{}".format(red, green, blue)) def mapping(arg): arg = float(arg) if arg < 0: return 0 elif arg > 100: return 255 else: return arg * 0.01 * 255 if __name__ == '__main__': run(host="localhost", port=9000, debug=True, reloader=True)
main.js
- ローカルサーバーにRGBデータを送るためのブロックを ScratchX に作る。
(function(ext){ var device = null; ext._deviceConnected = function(dev){ if(device) return; device = dev; console.log(device); device.open(); }; ext._deviceRemoved = function(dev){ if(device != dev) return; device = null; }; ext._shutdown = function(){ if(device) device.close(); device = null; }; ext._getStatus = function(){ if(!device) return {status: 1, msg: 'digiUSB disconnected'}; return {status: 2, msg: 'digiUSB connectd'}; }; ext.blink = function(r, g, b){ $.ajax({ type: "GET", url: "http://localhost:9000/blink", dataType: "script", data: { red: r, green: g, blue: b } }); }; var descriptor = { blocks: [ ["", "red: %n, green: %n, blue: %n で光らせる", "blink", "100", "100", "100"] ], menus: {}, url: 'http://localhost:9000' }; var hid_info = {type: 'hid', vendor: 0x16c0, product: 0x05df}; console.log(ScratchExtensions.register('DigiUSB', descriptor, ext, hid_info)); })({});
動作手順
app.py
とmain.js
を同じディレクトリに入れる。app.py
から Digispark に命令を送るには、Digisparkが作ったライブラリ も必要なのでもらってくる。上記リンクのarduino
ディレクトリをapp.py
とmain.js
があるディレクトリに入ればOK。- ここまでで、ディレクトリの中身は、
Directory |- arduino/ |- app.py |- main.js
- bottleを起動する。
python app.py
- ウェブブラウザで
http://localhost:9000
にアクセス。"ScratchX"というリンクがあるので、リンク先に飛ぶと同階層にあるmain.js
が読み込まれたScratchXのページが開く。 - スクリプトタブの"その他"にある、"~で光らせる"ブロックを使ってプログラムを作成すると、その通り動く。
(RGBがそれぞれ2byteのデータ(数値では0~255)を受けるが、入門状態ではその説明からすることになり面倒なので、
app.py
の中で0~100を0~255にスケールしている。要は、ScratchX上では0~100の範囲で数値を吐き出そう、ということ)
最後に
- ScratchXのWiki を見ると、USB-HID に javascript からデータを直接送れるようになっているはずだが、上手くいかなかったので、今回のようなまわりくどい形になってしまった…
上記ページのコードを見ると、このあたりを使っている感じではある。 - chrome.hid
main.js
にはその名残りを残してて、Scratch Extensions Browser Pluginのプラグインを入れると、ScratchX上の "その他のシグナルが未接続状態の赤ではなく、接続状態の緑色になる。(OSX, Chromeでのみ確認)今回はRGB Shieldを使ったが、今は在庫切れのようなので、たぶん同じことができるLED Shiledを取り寄せ中。Wikiを見る限り、AdafruitのNeoPixelクローンのような感じ。(曖昧)
前述の通り、ScratchXは Flash Player 上で動作をする。しかし、LLKのgithubを見ると、Playerであるものの ScratchのHTML5バージョンのリポジトリもあって、今後の完全HTML5化に期待。できるのかは不明。
プログラミングの敷居は本当に低くなった(技術的にも、経済的にも)。フィジカルコンピューティングまがいなこともいろいろとできる。「プログラミングの更なる低年齢化」が話題になってほしい。
参考ページなど
- LLK/scratchx/wiki → ScratchXのWiki
- Digispark Wiki → DigisparkのWiki
- ScratchXの開発を爆速で開始できるテンプレートを作りました → ScratchXの拡張についての貴重な日本語記事、node.jsを使う方法など
- ScratchXのExtensionsをES2015で開発できるテンプレートを作りました → この記事も貴重。これからはES2015(ES6)だよねということで…
- 895円の超小型Ardunoクローン DigiSparkを買った/橋本商会 → Digisparkの日本語記事。Rubyとの連携についても書かれている。
- bottle_scratchx.git → 今回の
app.py
とmain.js
はここに置いた。