2017年10月15日日曜日

Scratch で日本語入力

Twitter上で「Scratchでキーボード入力から変数の値を変えるには?」的なつぶやきを見た。
「○○と聞いて待つ」を使うんじゃ面白くないから、「○○キーが押されたとき」を使う方法を
考えていたら、ローマ字漢字変換みたいなものになった。
https://scratch.mit.edu/projects/175719052/


リストに、変換する候補の漢字を保持しており、そのリストに対してインクリメンタルサーチ
っぽい動きをで候補を絞り込む。
要は、ひらがな(読み)の文字が増える毎に検索を繰り返しているだけなので、『予測』
などの高級な事は何一つやっていない。

それと、リスト名を変数で指定する方法が分からなかったので、複数のリストに対して
同様の処理をするスクリプトを大量に用意してる。この辺はスマートな方法があるはず。

契機となっTwitterのつぶやきと、「かな入力」の刺激を与えてくれたdream1030さんの
作品「日本語&数字入力機」に感謝。


2017年9月10日日曜日

Raspbian Stretchの迷走(?)



2017-09-07-raspbian-stretchでネットワークインターフェースの命名規則が変わった。
というか、「元に戻った」。
http://downloads.raspberrypi.org/raspbian/release_notes.txt

Raspbian jessieまでのバージョンでは、ネットワークインターフェースには、
eth0、eth1(無線なら、wlan0、wlan1)等の名前が付けられていた。
それが、Stretchからは、インターフェース機器のMACアドレスを基に生成する
enx??????????、wlx??????????("??????????"はMACアドレス)と言う形式になった。
 これまでの、eth0、eth1などの番号は、kernelがネットワークインターフェースを
読み込む順番で振られている為、読み込みの順番によっては、インターフェース名が
変化してしまう可能性があった。
そこで、MACアドレスを使用して(簡単には)変化しないインターフェース名の
採用になったものと考える。(←私の勝手な推測)

これが、
"predictable network interface names"
 予測可能なネットワークインターフェース名の筈だ。

つまり、順番によって変化する名前は「予測不可能」で、MACアドレスは機器に
固有なので「予測可能」と言うことなのだろう。
この変更で、"dhcpcd.conf"にインターフェース名を指定してIPアドレスの固定を
していた場合など、その再設定をしなければならなかった。

でも、それはそれで、まあ理解できる変更だと思う。

それなのに、だ!

その変更から1ヶ月程度で、何故か、元に戻された。
"Disable predictable network interface names for Ethernet devices"
 リリースノートには上記のみで、他の説明が無いので、変更理由は不明。

少なくとも、或るポリシーがあって変更されたシステムが簡単に戻されてしまうのは、
如何なものかと思いながら、eth0、wlan0形式へ再度設定を書き直すのである。

何度かTwitterで呟いたが、
「updateしたら諸々動かなくなりました」ってIoTの民主化なの?
 https://twitter.com/AO_o10yan/status/844033086383841280

※追記1(2017/09/13 21:30)※
ここhttps://www.raspberrypi.org/forums/viewtopic.php?t=191639#p1204352
を参考にして、私の環境で確認して見たところ、やはり
"/etc/systemd/network/99-default.link"("/dev/null"へのシンボリックリンク)が
在ると"wlan0"形式、無いと"wlx????????????"形式になるようです。
実は、色々といじり過ぎているので、これが本当に効いているのかは自信が有りませんが、、、。
※追記2(2017/09/14 22:00)※
"2017-09-07-raspbian-stretch.img"をmicroSDへ焼き直して、素の状態で試して見ましたが、
上記の「追記1」と同じ結果を得ました。
尚、"/etc/systemd/network/99-default.link"無しの状態、詰まり"wlx????????????"形式の
表示状態から、カーネルコマンドラインに"net.ifnames=0"とすれば、"wlan0"になりました。
オプションの選択肢が複数あるということです。

2017年5月14日日曜日

Raspberry Pi Arch Linux ARMにOpenCV入れてみた

Arch Linux ARMにOpenCVとやらを入れてみた。
インストール自体は至極簡単。pacman(yaourt)任せでOK。
sudo pacman -S opencv
Pythonで使いたいので、"numpy"もインストールする。
sudo pacman -S python-numpy
"numpy"は、Pythonで数値計算を効率良く(高速に?)行う為のライブラリらしい。
これだけで、OpenCVが使えるようになる。
このようなBGR値を、操作することで画像処理を行っていく(らしい)。

ついでなので、画像での顔検出をやってみる。
下のページを参考にさせてもらいました。有り難うございます。
http://peaceandhilightandpython.hatenablog.com/entry/2016/02/18/194303
(自分の環境で動くように、パスの指定等は変更しています。)
検出用には、OpenCVをインストールすると標準で入っている、
"/usr/share/opencv/haarcascades/haarcascade_frontface_default.xml"
を使用する。
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import cv2
import numpy as np

faceCascade = cv2.CascadeClassifier('/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml')

img = cv2.imread('./face.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
face = faceCascade.detectMultiScale(gray, 1.1, 3)

if len(face) > 0:
    for rect in face:
    cv2.rectangle(img, tuple(rect[0:2]), tuple(rect[0:2]+rect[2:4]), (255, 255,255), thickness=2)
else:
    print("no face")

cv2.imwrite('detected.jpg', img)

元の画像(お馴染みの)

検出結果

試しに、180度回転して上下逆にした画像で実行してみた。
これは、"no face"となり、検出できなかった。

2017年5月5日金曜日

「簡易ポーズエディタ」 遂に、ボタンを使う


Raspberry Pi 2 Model B + ServoBlaster + シェルスクリプト(GtkDialog)で4足歩行ロボットを操作。
「簡易ポーズエディタ」の、今まで飾りになっていた上部のボタンに、機能を持たせた。
「左回転」「前進」「後退」「右回転」のボタンでそれぞれの動作を起動する。
(GtkDialogから、別のシェルスクリプトに書かれたfunction呼んでいるだけ)
ただし、「停止」ボタンを押さない限り、繰り返し回数上限まで動作を続行する。

ヘボいのは、上限に達して終了しても、操作ボタンがグレイアウトから復帰しない点。
「停止」ボタンを押さないと、復帰しない。

2017年3月26日日曜日

Raspberry Pi kernel 4.9でServoBlaster(その2 非推奨)

前回の暫定的な処置を少し変更。
"/proc/cpuinfo"の"Hardware"情報を元にする方法はkernel 4.9では通用しないので、
"/proc/device-tree/soc/ranges"を読み込んで、"board_model"を判定するように変更してみた。

参考:下のリンク、pelwellさんのコメントを参考にしました。
https://github.com/raspberrypi/linux/issues/1902#issuecomment-287365600

 ※以下は非推奨です!! Raspberry Pi 2 Model Bでしか確認していません!※

"servod.c"をエディタで開き、958行目からの
if (strstr(modelstr, "BCM2708"))
            board_model = 1;
else if (strstr(modelstr, "BCM2709"))
            board_model = 2;
else
            fatal("servod: Cannot parse the hardware name string\n");
ここを下のように書き換える。
char buffer[5];
  FILE *file;
        
  file = fopen("/proc/device-tree/soc/ranges", "rb");
  fread(buffer, 1, sizeof(buffer), file);
  fclose(file);

  if (buffer[4] == 0x20)
        board_model = 1;
  else if (buffer[4] == 0x3f)
        board_model = 2;
  else
        fatal("servod: Cannot parse the board model\n");
※追記1(2017/04/22 20:20)※
本当は"hardware name"を読んでいる訳ではないので、最後のメーッセージは
"servod: Cannot parse the board model\n"
 とでもすれば良いですかね

※追記2(2017/04/27 20:25)※
"char buffer[8]"から"char buffer[5] "へ変更

以前の"servod"を削除して、改めて"make"し、"servod"を起動する。



※追記3(2017/05/03 21:40)※
下記にて、"/proc/device-tree/soc/ranges"を開けなかった場合の処理を追加。
fseekでファイル読込開始位置を指定し、配列への読み込みを限定してみた。
(特に意味は無い)

char buffer[1];
  FILE *file;
 
  file = fopen("/proc/device-tree/soc/ranges", "rb");
 
  if (!file)
        fatal("Unable to open /proc/device-tree/soc/ranges: %m\n");
 
  fseek(file, 4, SEEK_SET);
  fread(buffer, 1, sizeof(buffer), file);
  fclose(file);

  if (buffer[0] == 0x20)
        board_model = 1;
  else if (buffer[0] == 0x3f)
        board_model = 2;
  else
        fatal("servod: Cannot parse the board model\n");

2017年3月13日月曜日

ラズパイ kernel 4.9でServoBlaster(非推奨)

Raspberry Pi 2 Model Bで使っているArch Linux ARMのkernelが、4.9系に上がりましたが、、、。
ServoBlasterは4.9系に対応しておらず、
"servod: Cannot parse the hardware name string"
エラーを吐いて起動しません。


ServoBlasterは、"/proc/cpuinfo"から情報を取ってRaspberry Piの機種ボードモデルを判別しているらしいのですが、
kernel 4.9になってから、"/proc/cpuinfo"での情報が変わったようです。
これに対応させるように、応急処置をしてみました。

※追記1(2017/03/26 16:55)※
Raspberry Piのボードモデル判別の方法を修正したものが、次にあります。
 http://aoo10yan.blogspot.jp/2017/03/raspberry-pi-kernel-49servoblaster.html


※以下は非推奨です!! Raspberry Pi 2 Model Bでしか確認していません!※

"servod.c"をエディタで開き、
else if (strstr(modelstr, "BCM2709"))
この行を下のように書き換える。
else if (strstr(modelstr, "BCM2709") || strstr(modelstr, "BCM2835"))
以前の"servod"を削除して、改めて"make"し、"servod"を起動する。


自分の環境では、これで動きました。

2017年3月10日金曜日

Scratch 1.4へテキストファイルを読み込む

前回、Scratchのブロックを追加して、Linuxコマンドを送るようにしたので、
コマンドの出力結果をScratchへ読み込むブロックも作ってみる。

※言うまでもないですが、Scratchの改造は自己責任で!※
通常は、直接外部ファイルを読み込むためのブロックは用意されていないので、
ScratchをSmalltalkのレベルで改造する必要があり、以下を参考にして、
ブロックの追加を行った。情報を公開してくださった方々に感謝。
参考
http://itpro.nikkeibp.co.jp/article/COLUMN/20111019/371085/
http://oohito.com/nqthm/archives/2243
http://d.hatena.ne.jp/minekoa/20080314/1205484707


ブロックの追加。

('addFile %s to %L' #- #addfile:toList: 'filename')

外部ファイルを読み込んで、Scratch側のリストに追加するメソッドを設定する。
読み込むファイルまでのパスを抽出し 、空ならデフォルトのパスにする。
空でなければ、抽出したパスを使う。その上でファイルの有無を確認して処理を進める。
一行ごとに指定したリストに追加して行く。
この、リストに追加して行く処理は、まるごとScratchの「(なにか)を(リスト)に追加する」
利用する。

リストに追加して行く処理を考えている最中に、内容をTwitterにつぶやいたところ、
Smalltalkに詳しいsumimさんからスマートな方法をご教示頂きました。 有難うございました。

addfile: t1 toList: t2 
    | path file |
    path _ FileDirectory dirPathFor: t1.
    path = '' ifTrue: [path _ FileDirectory default pathName].
    ((FileDirectory on: path)
        fileExists: t1)
        ifTrue: 
            [file _ FileStream readOnlyFileNamed: t1.
            file contentsOfEntireFile lines do: [:line | self append: line toList: t2]]


先に格納用のリストを作っておく。
前回追加したブロックで、コマンドの出力をファイルにリダイレクトする文字列を実行。
リダイレクトで指定したファイルを、格納用のリストに追加するように実行。

"ls > /home/o10yan/lstest.txt"で"ls"コマンドの結果をファイルにして、
それをScratchのリストに読み込む一連の流れをやってみた。

勿論、出力結果にこだわらなくても、平文テキストファイルの読み込み用としても使える。

2017年3月5日日曜日

Scratch 1.4からLinuxコマンドを使う

前回では、ServoBlasterと言う限られた条件化で動かしたが、
少しだけ書き換えて、Linuxコマンド全般を使えるようにしてみる。

※言うまでもないですが、Scratchの改造・シェルスクリプトの実行は自己責任で!※
通常は、直接Linuxコマンドを動かすためのブロックは用意されていないので、
ScratchをSmalltalkのレベルで改造する必要があり、以下を参考にして、
ブロックの追加を行った。情報を公開してくださった方々に感謝。
参考
http://itpro.nikkeibp.co.jp/article/COLUMN/20111019/371085/
http://oohito.com/nqthm/archives/2243
http://d.hatena.ne.jp/minekoa/20080314/1205484707


ブロックの追加。

('shell %s' #- #shell: '')

メソッドで、保存するファイル名を変更。
(ホームディレクトリは私の環境の場合なので、そこは御自分の環境に読み替えて下さい)

shell: t1 
    | file |
    file _ FileStream fileNamed: '/home/o10yan/Scratch/shell'.
    file nextPutAll: t1.
    file close.
    (Delay forMilliseconds: 100) wait


シェルスクリプトの指定ファイルも変更。
読み込んだ文字列(コマンド)をそのまま"eval"で評価して実行。

#!/bin/bash

if [ ! -e /home/o10yan/Scratch/shell ]; then
    touch /home/o10yan/Scratch/shell
fi

while inotifywait -e modify /home/o10yan/Scratch/shell; do
    text_line=$(cat /home/o10yan/Scratch/shell)

    if [ -n '$text_line' ]; then
         echo '' > /home//o10yan/Scratch/shell
         eval $text_line
    fi
done

Scratchから"gpio readall"を送って見たところ
SLを走らせてみた

まとめ
やってることは非常に単純。
Scratchから文字列をファイルに保存する。
シェルスクリプトで、文字列をコマンドとして実行する。

現実的には、「遠隔センサー接続」を利用したり、scratchClient と言うソフトで
できるようなので、そちらを使った方が楽だと思います。
が、実験としては、面白かったです。

2017年3月3日金曜日

Scratch 1.4からServoBlasterを使う

Arch Linux ARMに入っているScratch 1.4のブロックを使ってServoBlasterを動かそうという試み。

※言うまでもないですが、Scratchの改造・シェルスクリプトの実行は自己責任で!※

通常は、直接ServoBlasterを動かすためのブロックは用意されていないので、
ScratchをSmalltalkのレベルで改造する必要があり、以下を参考にして、
ブロックの追加を行った。情報を公開してくださった方々に感謝。
参考
http://itpro.nikkeibp.co.jp/article/COLUMN/20111019/371085/
http://oohito.com/nqthm/archives/2243
http://d.hatena.ne.jp/minekoa/20080314/1205484707

概要
ServoBlasterは、"echo 0=50% > /dev/servoblaster"と言った形式のコマンドで、
"/dev/servoblaster"に値を送る事でサーボモータを動かす。
 なので、Scratch側から上記のコマンド相当(ファイルへの書き込み)を実行できれば、
ServoBlasterが動くはず。

だったが、、、。

やってみたところ、Scratchで直接ファイル(/dev/servoblaster)への書き込みを
実行しても、ServoBlasterで拾わなかった。
そこで、Scratch外部のシェルスクリプトから"echo 0=50% > /dev/servoblaster"を送ってみた。
動作確認ができたので、この方法を使うことにした。

手順
①・ScratchからSmalltalkへ降りて、ブロックの追加をする。
②・追加したブロックに任意のファイルへの書き込みのメソッド(?)を設定する。
③・任意のファイルの更新を監視し、変更があった場合にファイル内容(文字列)を読み込んで、
"echo"コマンドで"/dev/servoblaster"へ送る為のシェルスクリプトを作成する。


手順①は上述の参考サイトを見て、適当なブロックのカテゴリに追加。


('servo %s' #- #servo: '0=50%')

ブロックができたことを確認。


手順②では、今回は任意のファイルを"/home/o10yan/Scratch/servo"と決めうちする。
(ホームディレクトリは私の環境の場合なので、そこは御自分の環境に読み替えて下さい)
書き込む文字列は引数"t1"で渡されていると推測。

servo: t1 
    | file |
    file _ FileStream fileNamed: '/home/o10yan/Scratch/servo'.
    file nextPutAll: t1.
    file close.
    (Delay forMilliseconds: 10) wait

(注:上記"file _"は、Scratchでは"file ←"と表示される)


Scratch側の準備は以上で終了。
試しに動かしてみて、ファイルができているかを確認。



手順③で以下のように、ファイル監視のシェルスクリプトを作成。
ファイルの更新監視用に"inotifywait"を使うので、予め"inotify-tools"をインストールしておく。
先ずは、監視用のファイルが存在するかを確認して、無ければ作っておく。
"inotifywait"で指定のファイルに更新があるかを監視し、更新があった場合、
ファイルの内容を変数(text_line)に読み込んで、それを"/dev/servoblaster"へ送る。
ファイルに文字列が残ってしまうと気持ち悪いので、空白を書き込んでおく。

#!/bin/bash

if [ ! -e /home/o10yan/Scratch/servo ]; then
    touch /home/o10yan/Scratch/servo
fi

while inotifywait -e modify /home/o10yan/Scratch/servo; do
    text_line=$(cat /home/o10yan/Scratch/servo)

    if [ -n '$text_line' ]; then
         echo '' > /home//o10yan/Scratch/servo
         echo $text_line > /dev/servoblaster
    fi
done

出来上がったシェルスクリプトを実行し、監視状態になることを確認し、
Scratchのブロックを動かす。


今回は、ServoBlasterを動かすための改造を行ったが、次回はLinuxコマンドを
送るような改造を行う。

※お願い※
私は、Smalltalkについて全然分かっていないので、コピペ主体で改造してます。
Smalltalkに詳しい方で、「ここは間違っている」「こうした方が良い」と言う
指摘がありましたら、コメントを頂けると有難いです。
よろしくお願いします。