Scratch1.4をBSDで使ってみるために

2017年02月11日(土) 関西*BSDユーザ会 第1回研究会

ScratchCat-mini.png http://retrobsd.org/styles/subsilver2/imageset/retrobsd_daemon_shad.png../BSD_squeak2013.files/kbug-bug-mini.png

むとうたけし@関西*BSDユーザ会 (@610t)

Why Scratch 1.4?

  • FlashベースのScratch 2.0が全盛で、Node.js(JavaScript)のScratch 3.0も出そうなのになんで1.4?

理由: 大事なものから

  • Scratch Remote Sensor Protocol (遠隔センサープロトコル) が利用できる
    • 比較的簡単に、Scratchと(物理世界を含めた)外部とを接続できる
  • Squeak Smalltalkで自分好みに拡張できる
  • インターネットにつながってなくても利用できる
  • Flashは宗教上の理由で…

などなど

UNIX(Linux)用のScratch 1.4

利用手順

  • C言語で書かれた4つのプラグインをbuildし
  • Scratch.image 本体や(音声や画像などの)メディアファイルなどを適切な場所に置く

4つのSqueak VMプラグイン

  • Scratchプラグイン: ユーティリティ, Serialの取扱など
  • Unicodeプラグイン: Cairoを使ってUnicode対応する
  • Cameraプラグイン: Video4Linuxを使ってUSB Cameraを使う

BSDに未対応

  • WeDoプラグイン: LEGO WeDo 1.0を使うためのプラグイン
    • USB HIDをゴニョゴニョするらしい

Scratch 1.4 @ OpenBSD !!

  • なんと、OpenBSDに graphics/scratch があるじゃないですか!!
    • なぜにgraphicsカテゴリ?
    • 「少しのことにも、先達はあらまほしき事なり。」 from 徒然草(上)第52段

なんかおかしい…

  • locale がEnglishしか無い
  • 画像や音声などのメディアファイルが参照できない

原因を調査 by BSD technology

  • ktrace & kdump : NAMIを探して、見つかってないところを調べる
  9448 squeakvm NAMI  "/usr/share/scratch/locale"
  9448 squeakvm RET   mkdir -1 errno 2 No such file or directory
  • strings Scratch.image で、share/scratch とか参照してないかみる
/usr/share/scratch
ScratchFileChooserDialog class
  • bvi Scratch.image (binary dump) で、 share/scratch とか検索する
004B9B60  40 0B 00 00 0B B8 84 1D 48 65 6C 70 1F B9 38 01↓
           @.......Help..8.
004B9B70  2F 75 73 72 2F 73 68 61 72 65 2F 73 63 72 61 74↓
           /usr/share/scrat
004B9B80  63 68 2F 48 65 6C 70 00 0B BA 72 1C 65 6E 00 00↓
           ch/Help...r.en..

原因を調査 by Squeak Smalltalk technology

  • squeak Scratch.image で、Smalltalk開発環境を出す
    • 画面左上のScratchロゴのRの丸あたりをShift-Click → turn fill screen off
ScratchDebug.png
  • browserで該当箇所を確認したり、変更して挙動を確認
Smalltalk.png

Scratch.imageでの /usr/share/scratch ハードコーディング(4箇所)

  • ScratchFileChooserDialog class >> baseDirectory : 色々
↑ Smalltalk is Unix
  ifTrue: [FileDirectory on: '/usr/share/scratch']
  ifFalse: [FileDirectory default]
  • ScratchFrameMorph >> helpDirectory : Help関連
  Smalltalk is Unix
    ifTrue: [(FileDirectory default directoryExists: '/usr/share/scratch/Help')
      ifTrue: [helpDir ← FileDirectory on: '/usr/share/scratch/Help']].
  • ScratchTranslator class >> translationDir : locale関連
  dir ← FileDirectory default.
  Smalltalk is Unix ifTrue: [dir ← FileDirectory on: '/usr/share/scratch'] 

「適切な場所」問題の解決方法

  • /usr/share/scratch にインストールする
    • BSDでは普通そんなことはしない
  • /usr/share/scratch からパッケージディレクトリにリンク
    • これもやっていいかは微妙
  • Scratch.image を書き換える
    • Scratch catが使えなくなるし、BSDでパッケージがどこにインストールされるかは変わる
    • Scratch.imageからの相対パスを使うようにすれば、あるいは大丈夫かも

で、ましそうな解決策: リンク張る(ようにメッセージを出す)

% sudo ln -s /usr/local/share/scratch /usr/share/scratch

Scratch 1.4 @ FreeBSD

/usr/share/scratch 問題に関して本家に報告

Remove hard-coded /usr/share/scratch directory expectation

  • packageがどこに入るのかは決め打ちできない(/usr/localではないかもしれない)
  • システムディレクトリである'/usr/share'などはパッケージシステムでは使わない
  • Scratchリソースディレクトリのパスは、Scratch.imageからの相対パスで指定すれば良いんじゃないか?

Scratch 1.4 @ その他のBSD

  • ソースを取ってきて展開
  • プラグインをbuildし、プラグインとして探せる場所に配置
    • Video4Linux関連だけ注意が必要
  • メディア関連ファイルを配置
  • scratch-1.4.0.7.src/src/scratch シェルスクリプトを修正して、/usr/local/bin/などに配置
% squeak-vm -plugins /usr/local/share/scratch/Plugins/:\
                        /usr/local/lib/squeak/4.10.2-2614/

Scratch Remote Sensor Protocol

<size: 4 bytes><msg: size bytes>

  • 4バイトのパケットサイズヘッダ
  • 実装されているメッセージ
    • broadcast "msg"
    • sensor-update "var1" value1 "var2" value2 ......

デモ: Scratch Remote Sensor (Android)

PhysicalSensor4Scratch.png

デモ: Scratch Remote Sensor (ESP8266)

ESP8266-Scratch.png

デモ: Scratch 1.4@FreeBSD と chibi:bit (micro:bit)

microbit-Scratch.png

FreeBSDから見たmicro:bit

  • dmesg
ugen4.2: <ARM> at usbus4
umass0: <USBMSC> on usbus4
umass0:  SCSI over Bulk-Only; quirks = 0x8100
umass0:2:0:-1: Attached to scbus2
da0 at umass-sim0 bus 0 scbus2 target 0 lun 0
da0: <MBED VFS 0.1> Removable Direct Access SCSI-2 device
da0: Serial Number 1021000017e0f38800000000000000000000000097969902
da0: 1.000MB/s transfers
da0: 64MB (131200 512 byte sectors)
da0: quirks=0x2<NO_6_BYTE>
uhid0: <CMSIS-DAP> on usbus4
umodem0: <mbed Serial Port> on usbus4
umodem0: data interface 2, has CM over data, has break

micro:bitってBLEあるので…

ugen4.2: <Bluegiga> at usbus4
umodem0: <CDC control> on usbus4
umodem0: data interface 1, has CM over data, has no break

micro:bitのソース

from microbit import *

def get_sensor_data():
    x, y, z = accelerometer.get_x(), accelerometer.get_y(), accelerometer.get_z()
    a, b = button_a.is_pressed(), button_b.is_pressed()
    print(x, y, z, a, b)

uart.init(115200)

while True:
    sleep(100)
    get_sensor_data()
    if uart.any():
        str=uart.readline()
        display.scroll(str,wait=False,loop=True)
  • micro:bit sensorのデータをシリアル経由でコンピュータへ出力(print)
  • コンピュータ側から送られてきた文字列をシリアル経由で入力(uart.readline)して、LEDマトリックスに表示

microbit-scratch.py: メッセージ受信時のコールバック関数

import serial
from time import sleep
import scratch

class ScratchReceiver(object):
  @staticmethod
  def broadcast_handler(message):
    print('[receive] broadcast:', message)
    s.write(message.encode('utf-8'))
  @staticmethod
  def sensor_update_handler(**sensor_data):
    for name, value in sensor_data.items():
      print('[receive] sensor-update:', name, value)
  • sensor-updateやbroadcastが送られてくると、これらのコールバックが呼ばれる
  • broadcastで受け取った文字列メッセージを、シリアルに出力

microbit-scratch.py: シリアルの初期設定

PORT = "/dev/cuaU0"
BAUD = 115200

s = serial.Serial(PORT)
s.baudrate = BAUD
s.parity   = serial.PARITY_NONE
s.databits = serial.EIGHTBITS
s.stopbits = serial.STOPBITS_ONE
  • micro:bitは/dev/cuaU0として認識される
  • 一般的なパラメータでシリアルを初期化

microbit-scratch.py: Scratch Remote Sensorとしての動作

rsc = scratch.RemoteSensorConnection(ScratchReceiver.broadcast_handler, ScratchReceiver.sensor_update_handler)  
rsc.connect()  
while True:
    data = s.readline().decode('UTF-8')
    data_list = data.rstrip().split(' ')
    try:
        x, y, z, a, b = data_list
        print(x,y,z,a,b)
        rsc.send_sensor_update(x=int(x))
        rsc.send_sensor_update(y=int(y))
        rsc.send_sensor_update(z=int(z))
        rsc.send_sensor_update(a=str(a))
        rsc.send_sensor_update(b=str(b))
    except:
        pass
rsc.disconnect()  
  • センサーデータをsensor-updateで送る

まとめ

  • BSDでScratchを使う方法をまとめてみました
  • /usr/share/squeak の埋め込み問題に関して考察しました
  • Scratch Remote Sensorは楽しいです

Future works

Last modified: 2017-02-10
Post-it: New Post-it (help)

Text color: [_][_][_][_]

Background: [_][_][_][_][_][_]

Draw Line:

x: y: