タイトルの簡単な説明
- 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
に変更する。 ※他のデバイスのドライバを書き変えるとマズいので、慎重に…
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 からデータを直接送れるようになっているはずだが、上手くいかなかったので、今回のようなまわりくどい形になってしまった…
上記ページのコードを見ると、このあたりを使っている感じではある。 -
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
はここに置いた。