Help us understand the problem. What is going on with this article?

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化に期待。できるのかは不明。

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

参考ページなど

uitspitss
http://uitspitss.hatenablog.com/
https://uitspitss.net
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away