Edited at

bottleでScratchXとDigisparkをつなげる

More than 3 years have passed since last update.

bottle_scratchx_min.jpg


タイトルの簡単な説明


  • bottle → python で作られたシンプルな Webフレームワーク。


  • ScratchX → ウェブブラウザベースな Scratch2.0 にプラグイン拡張をできるようにしたもの?(曖昧)


  • Digispark → 1000円ちょっとで買える、小さくて Arduino クローンなすごいやつ。


やること

DigisparkのRGB Shield(LED Shieldではなく)を使ってプログラミング入門的なことをしたいので、プログラミング入門に最適であろう Scratch (ScratchX) からDigisparkを操作する。

※実際にやる際は、ご自分の責任でお願いいたします。


動作の流れ


環境


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.pymain.jsを同じディレクトリに入れる。


  • app.pyから Digispark に命令を送るには、Digisparkが作ったライブラリ も必要なのでもらってくる。上記リンクの arduino ディレクトリをapp.pymain.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化に期待。できるのかは不明。


  • プログラミングの敷居は本当に低くなった(技術的にも、経済的にも)。フィジカルコンピューティングまがいなこともいろいろとできる。「プログラミングの更なる低年齢化」が話題になってほしい。



参考ページなど