2019年5月21日火曜日

RAPIROPをScratchで制御する

5月25日(土)にスクラッチディ 2019 山梨にデモ出展することになりました。

何も準備できていませんが、この秋から予定しているプログラミング塾での教材をデモしようかなと考えています。Scratchでプログラミング可能なLEGO MINDSTORMS NXT(Enchanting)、Edison(EdScratch)、Scratch Jr on Raspberry Piなんですが、それだけでもちょっと寂しいのでRAPIROにMCをやってもらおうかなと考えました。

 Raspbian StretchではScratch 2.0 オフラインエディターが標準でインストールされています。
(注:Scratch3.0のリリースに合わせて2019年1月2日からScratch2.0オンラインエディターの提供が終了しました。)
そしてオフラインエディターには拡張機能があり、独自のブロックを簡単に追加できるようです。
Python で軽量サーバを作って Scratch 2 のHTTP拡張を待ち受けてみる
これで、拡張機能を作ってScratch(RAPIROとは別にRaspberry Pi 3で動かします)でシナリオ通りにRAPIROに喋らせるという魂胆です。確認の為にRaspberry PiでScratch2を立ち上げて、Shiftキーを押しながら「ファイル」を選ぶと「import experimental extension」と表示されるので、行けそうです。

Step1:HTTP拡張機能の作成


参考のページを元に拡張機能を定義しようとしましたが、外部のHTTPサーバへアクセスすることはできないようです。ポート番号は指定できますが、サーバについては指定方法がないようです。

仕方がないので、Bottle+PythonでRAPIROへリクエストを繋ぐ簡易サーバを作成しました。次にJSON 形式の.s2eファイルを作成して、拡張機能を読み込ませようとしましたが、うまく読み込んでくれません。URL を指定するようダイアログが出るので、「file:///.s2eファイルへのパス」で指定しても読み込んでくれません。

ここで、断念かと思いましたが・・・


Step2:Javascript Extensions


拡張機能で検索をしているとこちらのページにたどり着きました。
ここに
The current 2.0 extensions available in the offline editor, like the PicoBoard extension, are Javascript extensions.
とありました。
ということで、Step1で作成したPythonと.s2eファイルをJavaScriptに変換してみました。

Javascriptで拡張機能を作成する詳細仕様はこちらに上がっていますが、Ajaxも使えるようなのでRAPIROへのリクエスト送信も簡単に記述できました。

さて、実際にテストしてみると無事に拡張ブロックが表示されました。
今回は、最低限の機能だけ拡張機能として取り込んだので、今後時間を見てバージョンアップしたいと思います。



Javascriptについてはこちらにアップしてあります。

2019年5月17日金曜日

RAPIRO完全無線化 ー完結編(ソフトウエア)ー

大分時間が空いてしまいました。他の事で時間が取られてしまって書いている時間が取れませんでした。
さて、RAPIROの完全無線化についてハードウエアの方は完了したので、ソフトウエアの設定を行いたいと思います。と言っても、各パーツについてはすでに動作確認が終わっているので、それらを統合して簡単に使えるようにするだけです。

なお、以下の作業はRAPIROに組み込んだRaspberry Pi Zero B+(以下 PiZero)での作業になるので、まずは、sshでログインしてください。

Step1:カメラ画像のストリーミング


カメラ画像のストリーミングについてはこちらに投稿しておきましたが、PiZeroの電源を入れたら自動的にストリーミングを始めるようにサービス化しておきます。

まず、/home/pi/streaming/streaming.shとして以下を作成します。
#! /bin/sh
export LD_LIBRARY_PATH=/usr/local/lib/mjpg-streamer
mjpg_streamer -o "output_http.so -w /usr/local/share/mjpg-streamer/www" -i "input_raspicam.so -fps 5 -x 480 -y 320"
次に、/usr/lib/systemd/system/streaming.serviceとして以下を作成します。
[Unit]
Description=Mjpg-Streamer

[Service]
ExecStart =/home/pi/streaming/streaming.sh
Restart=always
Type=simple

[Install]
WantedBy=multi-user.target
以下のコマンドで作成したサービスをsystemdに登録します。
$ sudo systemctl enable streaming.service

Step2:RAPIROコントローラ(Python)


Bottle + PythonでRAPIROを外部から制御できるようにします。HTTPでコマンドを受け取ると、シリアル通信でRAPIROへコマンドを投げるという簡単な仕組みです。
Python用軽量Webフレームワークとしては他にFlaskもあり、どちらも簡単にREST風アプリが作れますが、私はBottleを利用しています。

Pythonのソース(本体)とindex.html、RAPIROのサーボモータをOFFにする機能をつけたスケッチをGitHubに上げてあるのでそちらを参照してください。詳細はソースを見ていただければすぐにわかると思います。
index.htmlではmjpg_streamerの提供するCSSファイル等をstaticフォルダ経由で利用しているので注意してください。又、python3、bottleについてはインストール済みであるとします。
$ cd ~
$ git clone https://github.com/KeiIchimaru/rapiroctl.git
$ cd rapiroctl
$ ln -s /usr/local/share/mjpg-streamer/www static
スケッチについてはRAPIROへの書き込みを行っておいてください。
あとはサービスとして登録する作業になります。
/usr/lib/systemd/system/rapiroctl.serviceとして以下を作成します。
[Unit]
Description=RAPIRO Controller

[Service]
ExecStart =/home/pi/rapiroctl/rapiroctl.py
Restart=always
Type=simple

[Install]
WantedBy=multi-user.target
以下のコマンドで作成したサービスをsystemdに登録します。
$ sudo systemctl enable rapiroctl.service
以上で、PiZeroのポート80でHTTPリクエストを待ち受けているので、ブラウザでアクセスするとサンプルの画面が表示されます。サンプルではカメラからのストリーミングも表示しているので、RAPIROに搭乗して操縦しているような感覚が得られると思います。(移動すると、画面が左右に大きく揺れるので酔いやすい方はご注意くださいw)

Step3:shutdownスイッチ


PiZeroはRAPIROの頭部に組み込まれているので、shutdownする場合は外部からsshでログインする必要があります。その為にPCを立ち上げるのも面倒なので、ハードウエア編で触れていますが、こちらのサイトを参考にshutdown用タクトスイッチを付けることにしました。利用したGPIOはBCM23(P16:物理ピン番号)とGND(P14)を使い、組み立てる時にタクトスイッチから配線しておきました。

PythonのプログラムはGitHubに上げてあるので、すでにダウンロードしてあるはずですのでサービスとして登録するだけです。
/usr/lib/systemd/system/shutdownbuttond.serviceとして以下を作成します。
[Unit]
Description=Shutdown by Button Daemon

[Service]
ExecStart =/home/pi/rapiroctl/shutdownd.py
Restart=always
Type=simple

[Install]
WantedBy=multi-user.target
以下のコマンドで作成したサービスをsystemdに登録します。
$ sudo systemctl enable shutdownbuttond.service

Step4:動かしてみて


以上で、全て完了したので動作確認です。
PiZeroの電源をONにすると、しばらくしてカメラが赤く光って起動が終了したことがわかりますので、その後RAPIRO本体の電源を入れて準備完了です。

ブラウザからPiZeroにアクセスすると下のような画面が出てきます。どう動くかは、各自試してみてくだサイ。ノートパソコンやスマフォからだと画面からはみ出て使いずらいと思いますので、各自自由にカスタマイズして使いやすい画面にして頂ければ幸いです。


rapiroctl.pyそのものはhttpサーバとして動いているだけなので、スマフォアプリを作成するなど応用は色々あると思います。

画面下部の「Play」はaudioフォルダ内の.wavファイルを再生する機能です。アンプが組み込んであるのでRAPIROを喋らせることができます。「Say」は指定されたテキストを音声合成して喋らせようとしたのですが、処理に時間がかかるので現在は使っていません。この辺りのこともそのうち時間ができたら投稿したいと思います。

電源を切るときは、タクトスイッチを長押しするとshutdownプロセスが開始されるので、しばらくしてカメラのランプが消えたら、PiZeroの電源を切って、最後にRAPIRO本体の電源を切ってください。


2019年4月16日火曜日

RAPIRO完全無線化 ー完結編(ハードウエア)ー

親指の抜糸は終わりましたが、一部の神経は切断されているのでちょっと感触がおかしな状態です。とは言え、作業には支障が無いのでRAPIROの完全無線化を終わらせたいと思います。

出来上がった状態はこんな感じです。



リチウムイオン電池を搭載してRaspberry Pi Zero W用の電源としています。RAPIROに付属している標準の接続ケーブルだとRaspberry Piの電源をRAPIROから取るようになっていますが、今回はそのケーブルからは電源を取らず(UART+RESET用のケーブルを作成しましたが、標準ケーブルからRaspberry Piの+5vに行く2本の線を外してもOKです)にRAPIROの電源と完全に分離しているので、より長い時間、動作させることができます。

Step1: ベース基盤


RAPIROの頭部にRaspberry Pi Zero Wやリチウム電池をのせる為にベースとなる基盤が必要になりますが、RAPIROの頭部はRaspberry Piの基盤サイズを対象としているので、このサイズの基盤を探します。

こちらのサイトで見つけました。

Raspberry Pi用の基盤はいくつかありますが、HAT用の物がほとんでサイズ的にも小さな物ばかりですが、基盤サイズで価格も手頃(¥165+税)でした。








Step2:電源部


部品:

6W 5V UPS mobile power Diy Board Charger & Step-up DC DC Converter
1500mah lithium-ion polymer battery 3.7 V 
基板用マイクロUSBコネクタ(電源専用)
マイクロUSBコネクタDIP化
ピンヘッダ 1×40 (40P)
TJC8ピンターミナル(メス) (10本入)
コネクタ用ハウジング 2P
・配線用コード

TJC8ピンターミナル+コネクタ用ハウジングは工具が必要になるので、工具が無い場合はブレッドボード用ジャンパワイヤーを利用することも可能です。

組立:

USBコネクタをDIP化基盤に取り付ける時には基盤の表裏に気をつけて、こちらの写真を参考に半田付けしてください。なお、ピンヘッダについては下の写真のようにちょっと変則的な取り付け方をします。これは参考にした写真ではブレッドボードでの利用を想定していますが、今回はユニバーサル基盤に取り付けるので、基盤との接触を避ける為にこのような取り付けを行いました。

DCDCコンバータについても、取り付け用の穴が無いので同じようにピンヘッダを取り付けてからベース基盤に半田付けします。配線については、部品のサイトにある画像の通りに配線すれば問題ありません。

電源の出力側についてはマイクロUSBオスコネクターでRaspberry Pi Zero Wへ電源を供給しますが、途中にミニスライドスイッチを入れて電源のON/OFFができるようにしておきます。USBからの給電にしてあるので、電源スイッチによるノイズも問題ないと思います。


Step3:RAPIROへの組込


部品:

・2.6mmネジ+ナット(ホームセンターで精密ねじ、精密ねじ用ナットとして販売されてます)

組立:

RAPIROの後頭部へ、電源スイッチとShutdown用タクトスイッチ(ソフトで解説)を取付ける為に片面ユニバーサル基盤を加工します。

大まかに切断した後、RAPIRO後頭部へ当てながらヤスリで微調整をしていきます。電源スイッチはこのユニバーサル基盤にネジ止めしますが、ネジ穴の位置は具合を見ながら位置決めをします。今回の写真ではちょっと中に寄りすぎでした、もう少し外よりの方が良かったと思います。

RAPIROへの取付位置も実際に調整しながら決めます。なお、電源スイッチを取付たねじの頭があるので、ナットを1つか2つ挟んであげてください。

また、電源スイッチのボックス部分がアンプモジュールを取付けるスペーサーに当たることもあるので、そちらとの兼ね合いも見ながら取付位置を決める必要があります。

当初はネジ1本で支えようとしましたが、実際にスイッチを操作すると安定しないので、上側もネジ止めするようにしました。

次に、Raspberry Pi Zero Wをベース基盤にねじ止めしますが、ここでも基盤同士が接触しないように、ナットを間に挟んで高さ調節をします。今回は3mmのナット1つを挟みました。

最後に、スペーサ(11mm)を使ってアンプモジュールを取付け、配線をして終了です。

Step4:スピーカ用の穴


スピーカは頭部に内蔵しますが、そのままだと音がこもるので耳の部分に穴を開けて音が外に出やすいよう加工してあげます。

まずは、方眼紙に半径2cmの円を描いて穴を開ける位置を決め、マーク部分に穴を開けます。

次にRAPIRO頭部を前後合わせて仮止めし、方眼紙を耳の部分に当てセロテープで仮止めし、上から油性ペンで印をつけてあげます。

方眼紙を外し、頭部を前後分離してからマークに合わせてドリルで穴を開けます。

今回使ったのは2mmの木工用のビットを利用して穴を開けました。あまり力を入れると割れる恐れがあるので、ドリルの自重で穴を開けるような感じで作業します。




2019年3月9日土曜日

Android on Raspberry Piを安全にシャットダウン

左手の親指を怪我して2針縫ったのでしばらく不自由していました。

現在、Raspberry Pi 3 B+でAndroid7.1.1を動かしてScratch Jrを動かしていますが、Raspberry Piには電源ボタンが無いので、Androidをシャットダウンするには他のPCからadbコマンドでシャットダウンしてから電源を切るか、直接電源を切る必要があります。

できればシャットダウンしてから電源を切りたいので、シャットダウンアプリを導入しようとしましたが、rootを取っておく必要があるアプリばかりのようです。

そこで「android adb shutdown」でネットを検索すると、いくつかのサイトがヒットしますが、概ねrootを取ってあることが前提のようです。

幸い、現在使用しているAndroid7.1.1のadb shellコマンドはroot権限で動作するようなので(adb shellのプロンプトが#になります)、以下のコマンドでシャットダウンが可能でした。
adb shell am start -a com.android.internal.intent.action.REQUEST_SHUTDOWN
adb shell am start -n android/com.android.internal.app.ShutdownActivity
さらに、Android4.4以降は
adb shell setprop sys.powerctl shutdown
でもシャットダウン可能です。

その1:ターミナルアプリのインストール


とは言え、シャットダウンする為だけにPCを立ち上げ、コマンドを叩くのも面倒です。

なんとかRaspberry Piだけでシャットダウンできないかと考え、adb shellを実行しているならターミナルアプリをインストールして、上記コマンドを実行すればいいんでは無いかと考えテストしてみると。

amを利用するものはAndroidの権限で弾かれてしまいましたが、setpropを利用するケースは問題なくシャットダウンしてくれました。

これで、わざわざPCを立ち上げなくてもRaspberry Piだけでシャットダウンしてから電源を切れるようになりました。

その2:ShutdownPiの作成


とは言っても、毎回ターミナルアプリを立ち上げてコマンドを入力するのは面倒です。ワンクリックでシャットダウンしたいものです。

ということで、Kotlinの勉強も含めてシャットダウンアプリを作成することにしました。

以下はメインとなるダイアログ部分のソースです。ダイアログを表示して、シャットダウン/リーブート/キャンセルを選択できるようにしてあります。

package com.example.keiichimaru.shutdownpi.dialog

import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.DialogInterface
import android.os.Bundle
import android.support.v4.app.DialogFragment
import android.support.v4.app.FragmentManager
import android.support.v7.app.AlertDialog
import android.util.Log
import com.example.keiichimaru.shutdownpi.R

class DlgShutdownConfirm(context: Context) {
    private val mContext: Activity? = if (context is Activity) context else null

    companion object {
        const val TYPE_SHUTDOWN = "shutdown"
        const val TYPE_REBOOT = "reboot"
    }

    fun show( manager: FragmentManager, tag: String?) {
        val dialog = DlgShutdownConfirmDialog()
        dialog.onRebootButtonClickListener = DialogInterface.OnClickListener { _, _ ->
            finishActivity()
            doShutdown(TYPE_REBOOT)
        }
        dialog.onShutdownButtonClickListener = DialogInterface.OnClickListener { _, _ ->
            finishActivity()
            doShutdown(TYPE_SHUTDOWN)
        }
        dialog.onCancelButtonClickListener = DialogInterface.OnClickListener { _, _ ->
            finishActivity()
        }
        dialog.show(manager, tag)
    }
    private fun finishActivity() {
        requireNotNull(mContext) {"DlgShutdownConfirm initialize error."}
        mContext.finishAndRemoveTask()
    }
    private fun doShutdown(type: String) {
        require((type == TYPE_SHUTDOWN) or (type == TYPE_REBOOT)) { "type required $TYPE_SHUTDOWN or $TYPE_REBOOT." }
        val command = arrayOf(
            "sh",
            "-c", "setprop sys.powerctl $type"
        )
        val runtime = Runtime.getRuntime()
        try {
            Log.d(DlgShutdownConfirm::class.qualifiedName, command.reduce { s1, s2 -> "$s1 $s2" })
            val process = runtime.exec(command)
            val result = process.inputStream.bufferedReader().use { it.readText() }
            Log.d(DlgShutdownConfirm::class.qualifiedName, result)
            process.waitFor()
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
    }
    class DlgShutdownConfirmDialog : DialogFragment() {
        override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
            val builder = AlertDialog.Builder(activity!!)
            builder
                .setMessage(R.string.dlg_shutdown_msg)
                .setNeutralButton(R.string.dlg_reboot, onRebootButtonClickListener)
                .setNegativeButton(R.string.dlg_shutdown, onShutdownButtonClickListener)
                .setPositiveButton(R.string.dlg_cancel, onCancelButtonClickListener)
            return builder.create()
        }
        internal var onRebootButtonClickListener: DialogInterface.OnClickListener? = null
        internal var onShutdownButtonClickListener: DialogInterface.OnClickListener? = null
        internal var onCancelButtonClickListener: DialogInterface.OnClickListener? = null
    }
}

MainActivityは以下の通りです。
アプリが起動されると、画面は表示せずに確認ダイアログを表示してシャットダウンします。

package com.example.keiichimaru.shutdownpi.dialog

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import com.example.keiichimaru.shutdownpi.dialog.DlgShutdownConfirm

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // setContentView(R.layout.activity_main)
        DlgShutdownConfirm(this).show(supportFragmentManager, MainActivity::class.qualifiedName)
    }

}

2019年2月25日月曜日

Raspberry Pi 3b+でLineageOS 15.1を動かす

前回、Raspberry Pi 3b+でLineageOS 14.1 (Android 7.1.2)をインストールしてみましたが、Scratch Jrのマウスクリックができずに挫折してしまいました。今回、LineageOS 15.1(Android 8.1.0)を見つけたので、再度チャレンジしてみました。

ステップ1:LineageOS 15.1インストール


インストールそのものは簡単です。システムイメージをダウンロードして、マイクロSDカードに書き込んで、Raspberry Piで起動するだけです。

LineageOSの嬉しいところは、F5の長押しで、電源OFFかリブートのメニューが出て安全に電源を切ることが出来ることです。
スマフォでしたら電源ボタン長押しで電源を切ることができますが、Raspberry Piには電源ボタンがないので、電源そのものをOFFにするしかないことです。この場合、SDカードへの書き込み中だとシステムが壊れる可能性もあるので、安全を考えるならshutdownをしてから電源を切りたい所です。
rootが取れれば電源OFF用アプリをインストールできますが、現在Raspberry Piで動いているAndroid 7.1.1ではrootを取るのことは出来ませんが、adb shellがroot権限で動くようなので、別端末から「adb shell setprop sys.powerctl shutdown」で電源を切るようにしています。

ステップ2:Google Play Storeのインストール


こちらもホームページに導入手順が書いてありますので、そのまま実行すればGoogle Play Storeが使えるようになります。
事前準備としては
  • Settings -> Developer options -> Root accessでadbとappにRoot権限を与える
  • Settings -> Developer options -> Local terminalでターミナルを使えるようにする
  • ブラウザを立ち上げて必要なファイルをRaspberry Piにダウンロード
ここで、ともかくやたらと設定が落ちます。この時点で、使い物にならないと諦めてしまいそうになります。コツとしてはスクロールはマウスで行わずに、上下矢印(↑↓)を使って、ゆっくりと行うことがポイントです。どうやらListViewで画面スクロールをする時に処理が追いつかずに落ちている感じです。↓しては待って、また↓して待ってと、ひたすら我慢で使いこなしてください。

準備ができたらTWRPへブートし直します。これもFAQに方法が書かれていますが、ターミナを立ち上げて
su
rpi3-recovery.sh
を叩いて、再起動します。




TWRPのメニュー画面です。
まずは、ダウンロードしておいたGappsをインストールします。
「Install」ボタンを押して






Downloadをクリックすると









ファイルがあるのを確認してクリック後「Install Image」ボタンを押します。









「Swipe to confirm Flash」を右にスワイプしてインストール開始です。









インストールが終わったら、
「Wipe cache/dalvik」を押すと










右にスワイプしてキャッシュのクリアを行います。









キャッシュのクリアが終わったら、続けてFactory resetを行うので「Back」でTOPメニューに戻ります。







TOPメニューで「Wipe」ボタンをクリックすると、この画面が表示されるのでスワイプしてFactory resetを行います。







Factory resetが完了したら、Androidが起動するように起動時設定を変更するために「Back」ボタンでTOPメニューへ戻ります。






TOPメニューで「Mount」ボタンを押して、Systemのマウントを行います。








OKでマウントします。










TOPメニューから「Advanced」を選択して、「Terminal」を開きます。









「rpi3-recovery.sh boot」で起動設定を変更して、TOPメニューへ戻ります。








最後にTOPメニューから「Reboot」を選択して、「System」を再起動します。










ステップ3:Scratch Jrのインストール


再起動後は、Play Storeがインストールされているので、ログインすることでScratch Jrのインストールが可能です。

ただ起動してみると、やはりマウスクリックが効きません。Android 7.1.1では問題なく動いているのでアプリ側の問題ではなさそうです。

そこで
add connect [Raspberry PiのIPアドレス] ・・・adbで接続
adb shell wm size                    ・・・画面サイズの表示
adb shell input mouse tap [x] [y]    ・・・マウスクリックのシミュレーション
で、概ねの座標からボタンをクリックさせると、問題なく動きました。でも、物理的なマウスでクリックしても動かないんですね。

ということで、システム全体の動作ももっさりしていますし、マウスクリック問題があるので、やはり使い物にはなりませんでした。Raspberry Pi 4が出て、処理能力がさらにアップすれば使えるようになるかな?







2019年2月22日金曜日

EclipceからAndroidStudioへのお引っ越し ーその2ー

Eclipce側での修正はひと段落したので、いよいよAndroidStudioへの移行を行いたいます。
AndroidStudio側でEclipceのワークスペースをインポートする機能があるので、簡単にできるかと思いましたが、3箇所ほどつまづきましたのでメモを残しておきます。

その1:ビルドができない。


インポートそのものは本家の解説を見て問題なくできたのですが、ビルドをするとエラーが出てしまいます。
ERROR: Could not find com.android.tools.build:gradle:3.3.1.
Searched in the following locations:
  - https://jcenter.bintray.com/com/android/tools/build/gradle/3.3.1/gradle-3.3.1.pom
  - https://jcenter.bintray.com/com/android/tools/build/gradle/3.3.1/gradle-3.3.1.jar
Required by:
    project :
Add Google Maven repository and sync project
Open File
Enable embedded Maven repository and sync project
色々と検索をして見ましたが、これはというサイトが見つかりませんでした。いずれにしろGradle関連の設定では無いかと検討をつけてこちらのサイトを参考に、プロジェクト全体のbuild.gradleにgoogle()を追加すれば良いことがわかりました。
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        jcenter()
        google() ・・・・・この行を追加
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.3.1'
    }
}

allprojects {
    repositories {
        jcenter()
        google() ・・・・・この行を追加
    }
}

新規にプロジェクトを作成する場合は、初めから追加されているようですがEclipceからインポートした場合には記述されなかったようです。

これに関連して、自動生成された各モジュールのbuild.gradleのdependenciesですが、compileで生成されますがcompileが非推奨となったとのことで、implementationとapiに変更しておいた方が良いようです。
私のアプリでは「アプリケーションモジュール→ライブラリモジュール→Android supportライブラリ」という依存関係があるので
アプリケーションモジュール
 dependencies {
     implementation project(':myLib')
 }

myLibモジュール
 dependencies {
     api project(':lvl')
     api 'com.android.support:appcompat-v7:28.0.0'
     api 'com.android.support:preference-v7:28.0.0'
     api 'com.android.support:recyclerview-v7:28.0.0'
 }

lvlモジュール
 dependenciesは無し
lvlモジュールのメソッドで一部アプリケーションモジュールで利用するものがありますが、myLibでapi宣言しているのでアプリケーションモジュールではlvlを指定する必要はありません。

その2:実行ができない!


無事にビルドも完了したので、さて実行をと思ったところで問題発生。
実行の構成を行おうとメニューから実行>実行の構成>TemplatesからAndroid Appを選択しましたが、モジュールが空っぽで選択することができません。

ソースも特にいじっていなかったので、一旦モジュールを削除して再度インポートし直したところ、実行の構成でモジュールの選択ができるようになりました。

1つのプロジェクトにアプリケーションと共通ライブラリがあったので、まずはライブラリからインポートしたので原因でしょうか?

後でわかった事として、各モジュールのbuild.gradleの先頭で各モジュールの属性を宣言しているようです。Android developerではビルドの設定>ビルド設定ファイル(build.gradle ファイル)>モジュール レベルのビルドファイルにもそれらしい説明はなく詳細はAndroid Plugin DSL Reference(英語)を見ろと突き放しています。結局、こちらに先頭行のプラグインでアプリケーションとライブラリを切り替えている事が説明されていました。ただ、ここは日本語に翻訳されていますが、バージョンが古いのでしょう依存関係の説明でcompileが使用されています。

その3:":" is not a valid resource name


やっと実行に漕ぎ着けましたが、実行してみると上記のようエラーが出てしまいます。

同じようなエラーはネット上でもいくつか見受けましたが、何れにしてもリソース関係のようです。string.xml又はlayout.xmlあたりでnameに":"を使っていないかということをヒントに、検索してみるとlayout.xml内でname="@id/android:empty"と指定しているところがありました。これはListActivityでデータが1件も無かった場合、自動的にこのidを持っているTextViewを表示してくれるという機能を使うためなんですが、どうやらこの指定方法が古かったようです。最近では@android:id/emptyと指定するようです。

ここでも浦島太郎になっていました(笑)

その他


Javaには長いことお世話になってきましたが、Oracleは(サポート≒セキュリティパッチ)有償化に踏み切ったようで、その話題で盛り上がっている界隈もあるようです。

その昔、SunがOracleに買収された時にJavaが有償化されるのではという危惧をしましたが、ついに来たかという感想です。そうなると次は「MySqlよお前もか!」にならなければいいんですが。(MySqlは現在も有償版とGPL版がありますが、今後はサポートを有償化という流れで、Oracleがあまたある利用サイトからお金を徴収しようと考えるかですね)

まあ、使う側としては、お金のある企業さんはサポート契約を結ぶんでしょうし、中小企業ではセキュリティリスクを我慢して(というか、サポート要員もいないので納品されたシステムをそのまま運用しているので、セキュリティもへったくれも無い)今のまま何もしないという流れではないか、と予想しています。(Oracle側もプライバシーマクを取得しているような企業や、セキュリティに責任を持つ企業さんは有償化わかってるよね、的な発言しているようですしね。)

Androidの開発でもJavaを使っていますが、Androidは2016年にはJavaのライブラリをOpenJDKへ切り替えていますので、直接の影響は出ないでしょう。まあ、GoogleとOracleの間ではJavaに関して訴訟が2010年ごろからあったので、Googleとしてはこの事態はすでに予想して対応していたんでしょう。

この話題と関連してかKotlinという言語が話題に上がってきているようです。すでにAndroid関連の話題でもKotlinを使ったページもだいぶ出てきているようです。

ということで、今年は今あるアプリをSwiftとKotlinで書き直してみたいと思います。

2019年2月11日月曜日

Raspberry Pi 3B+でScratch Jrを動かす

2020年から小学校でプログラミング教育を行うということで教育関係ではそれなりに混乱されているようです。そんな中でバズワードとしてScratchが浮上し、Scratchの入門編としてScratch Jrもあちこちで聞くようになってきました。
ScratchについてはRaspberry Piで動くことは実証済みですが、Scratch Jrは動作環境がiOSまたはAndroidということでRaspberry Piでは動かすことはできません。

とは言えRaspberry PiでAndroid OSを動かしてみた方もたくさんいますし、ビジネスとして展開している会社もあるようです。そこで、我が家のRaspberry Pi 3B+にAndroidを導入してその上でScratch Jrを動かしてみたいと思います。

ステップ1:Raspberry Pi で動くAndroid


まずはRaspberry PiでAndroid OSを動かしている例を検索してみると。
といったところが出てきます。

結論から言うと、現在は一番上のページを参考にしてRaspberry Pi 3B+にAndroid7.1.1を導入してScratch Jrを動かしています。

☆ emteria.OS
企業がビジネスとして公開しているので無償版といえ安定して動いてくれました。ただ、マーケットアプリがF-DroidということでScratch Jrは登録されていませんでした。また、個人使用なら無償ですが、ビジネスで使用するとなるとライセンスが必要なのも注意点でしょうか。Play Storeのインストールは試してみませんでしたが、sshサーバが無償版では使えなかったりと自由にカスタマイズするのは難しそうです。

☆LineageOS 14.1
WikipediaによるとCyanogen Inc.が開発していたCyanogenModというAndroidをカスタマイズしたOSが元になっているそうです。
OSをインストールした状態ではPlay Storeはインストールされいませんが、こちらの方法でインストールは可能なのでScratch Jrのインストールも問題なくできました。
ただ、残念なのはScratch Jrを起動したところ初回の利用場所設定画面でマウスクリックができずに先に進めず、Scratch Jr利用することはできませんでした。

☆Android 7.0 Nougat on Raspberry Pi 3
インストールは問題ありませんでしたが、起動後に設定画面を開こうとしたところ設定が終了してしました。

ステップ2:Raspberry Pi3にScratch Jrをインストール


先ほどの参考ページにもありますが、元ページはこちらになります。ほぼ元ページの作業手順で問題なくPlay Storeのインストールまで出来ました。

参考ページでは有線接続の時のIPアドレスの確認方法がわからないとありますが、Android起動後、設定>端末情報>端末の状態で確認できますし、あらかじめRaspberry Pi 3をrasbianで立ち上げてIPアドレスを確認しておいても良いと思います。

今回、時間がかかったのが画面表示のところでした。今回は古いSharp LL-173Cというディスプレイを使っていましたが初めは真っ黒で何も表示してくれませんでした。
この場合、AndroidをインストールしたSDカード内の/boot/config.txtを編集するのですが、Androidを起動した状態では編集できない(そもそも画面が真っ黒です!)ので、Windows等で編集する必要があります。

Sharp LL-173C、DELL E2014H、Panasonic TH-32LX70(液晶テレビ)で画面表示できるようにしましたが、その時の設定を以下に示しておきますので、画面が真っ黒になった時には参考にしてください。直感的には最近のモニタであればデフォルト設定で問題なく表示されるのではないかと思います。
# DELL E2014H
#hdmi_group=2
#hdmi_mode=87
#hdmi_cvt=1600 900 60 6 0 0 0
#disable_overscan=1

# Panasonic TH-32LX70 4(720p),16(1080p)
#hdmi_group=1
#hdmi_mode=16
#disable_overscan=1

# Sharp LL-173C(OK=36,17,8)
hdmi_group=2
hdmi_mode=8
disable_overscan=1

Androidが起動直後は、言語設定が英語になっているので、設定>言語と入力>言語>言語の追加で日本語を追加して、日本語をドラッグして一番上に持って行きます。これで設定の表示なども日本語に切り替わります。また、設定>日付と時刻>タムゾーンで「日本標準時」を選択して日本時間にしておきます。

次にユーザ登録をしてからPlay Storeのインストールをしましょう。

ユーザ登録は設定>アカウント>アカウントを追加>Googleで、ユーザの追加をします。
私はAndroidが起動後すぐにPlay Storeのインストールをしたので、Play Storeインストールでユーザ登録が要求されましたが、うまく既存ユーザでの登録ができませんでした。

あとはScratch JrをPlay StoreからインストールすればRaspberry Pi 3でScratch Jrが利用できるようになります。

ステップ3:マウスポインターの解消


Raspberry PiにAndroidを導入したサイトをみてもマウスポインターが化けているとの報告(導入動画でもマウスがモヤモヤしています)がされています。Androidでは標準でマウスカーソルの表示(そもそもマウス全般)に対応して無いのが原因かと思いますが、以下の方法で解消できましたので、モヤモヤカーソルを解消した方は設定して見て下さい。
  • 設定>ユーザ補助>大きなマウスポインタをONに設定
ちょっと大袈裟なくらい大きくなってしまいますが、画面サイズからすればまあ許容範囲かなということで(笑)

ステップ4:Scratch Jrでの日本語入力


Scratch Jrは問題なく利用できたのですが、日本語の入力でちょっと問題がありました。

標準のJapanese IMEでは日本語キーボードのレイアウトがサポートされてませんし、入力ができたり、できなかったり、長い文章を入力するとおかしくなったりと不安定でした。そこで日本語入力をGoogle日本語入力に変更して、設定を一部見直したところ安定したようです。
  • Play Storeで「Google日本語入力」を検索して、インストールします。
  • 設定>言語と入力>仮想キーボード>キーボードを管理で、Google日本語入力をON、Japanese IMEをOFFに設定
  • 設定>言語と入力>仮想キーボード>Google日本語入力>入力>ハードウエアキーボードのキーマッピングで「日本語109A」を選択
  • 設定>言語と入力>仮想キーボード>Google日本語入力>入力で変換オプションを全てOFFに設定(CPU負荷を軽減するためです)
  • 設定>言語と入力>物理キーボードで「仮想キーボードの表示」をOFFに設定

最後に:使い物になるか?


今のところScratch Jrの操作感として、速度的には我慢どころかなという印象です。日本語入力も余り早いキータッチには追随できませんが、CPUの能力を考えれば致し方ないかなと思います。

音の出力は外部スピーカーを付けるか、テレビをモニタ代わりにすれば問題はありませんが、その場合はconfig.txtの設定が必要になるかもしれません。カメラとマイクの利用もUSB接続という方法もありますが、プログラムの勉強用なら特に無くても問題はないかと考えています。

今回はScratch Jrを動かすことが目的でしたが、他の学習用アプリもいくつかインストールして使ってみました。結果は、全てのアプリが使い物になりませんでした。起動しないアプリ、起動してもマウスクリックを受け付けなくて(全く受け付けない、画面の一部で受け付けないの2パターンがありました)操作ができないものなど、普通に使う範囲で問題が発生しました。

ちなみに、私が公開しているアプリもインストールしてみましたが、アプリそのものは動いているようですが、画面が真っ黒になりやはり使えませんでした。動作はしているようなのでテーマ絡みで画面が真っ黒になっているのではないかと想像しています。現在、Android 8.0対応を進めているので、落ち着いたら調べてみたいと思います。

そういった意味でScratch Jrは特に問題なく動いているのはすごいなという感想でした。

RAPIROPをScratchで制御する

5月25日(土)にスクラッチディ 2019 山梨にデモ出展することになりました。 何も準備できていませんが、この秋から予定しているプログラミング塾での教材をデモしようかなと考えています。Scratchでプログラミング可能なLEGO MINDSTORMS NXT(Enchant...