新型コロナウィルスによる休校とKindle キッズモデル 1,000冊以上の子ども向けの本が読み放題!

世界での感染拡大が懸念される新型コロナウィルス。
今週から私もリモートワークとなり自宅で作業を行っています。たまたま、父親がリモートワークをはじめるのと同じタイミングで学校も臨時休校となり、子どもたちは一足早い春休み気分です。
休校中だとしても、親としては子どもたちにテレビやゲームでダラダラと過ごしてほしくはありません。そこで子どもたちと次の約束をしています。

  • 臨時休校中も、学校と同じスケジュールで勉強しましょう。
  • 父も就業時間をまもって仕事します。 父の仕事中は邪魔をしないこと。

とはいえ、家では授業を受けられるわけでもなく、プリントをやるだけでは子どもたちもすぐに飽きてしまいます。 図書館で本を借りようにも、肝心の図書館も休館なわけで。そこで、新しく登場したkindleのキッズモデルを購入して渡すことにしました。

https://amzn.to/2vCzJSg
ちょうど、1,000冊以上の子ども向けの本を1年間追加料金なしで読み放題なのと、その中に長女の読みたがっているハリー・ポッターシリーズもあったのが決め手になりました。子供二人それぞれに読みたいだろうから、仕方なく2台購入。もちろん1台をアカウントを切り替えながら二人でシェアして使うこともできるのでしょうが、それだと今読みたい!という気持ちを阻害しそうだったのでそれぞれ買いました。小学校3年の下の子のほうは活字よりも図鑑がお気に入りみたい。 設定した子どもの年齢に合った本が表示されるのもマルですね。
内容物はkindle本体とカバー、それに充電用USBケーブル。充電アダプタはついていません。
これはスペースステーションカバー。中は赤色です。
開いてみるとすでに表示されています。そっか、電子ペーパーだから電気がなくても表示されつづけるんでしたね。電源ONを促されます。

設定を終え、早速読み始めてます。これを機会に本を読むようになって欲しいなぁ。まずは興味を持ってくれているのでよしとしましょう。

 

ROS Wrapper 2.0 for Intel RealSense Devices (build 2.1.0)を D435で使用する

まず情報源ですが、ことのおりやればOKです。ただし今回はタイミング悪く、最新バージョンがリリースされてしまってうまくいかないという罠にはまりましたので、手順を残しておきます。
https://github.com/intel-ros/realsense
インストールするものは

  1. LibRealsense
  2. RealsenseのROSラッパー

の順ですが、先に、「RealsenseのROSラッパー」を確認します。
https://github.com/intel-ros/realsense/releases
で、ROSラッパーの条件を確認します。
現在の最新は2.1.0です。
https://github.com/intel-ros/realsense/releases/tag/2.1.0
上記のURLを見ると、2.1.0に必要な libRealSense のバージョンはv2.16.1だと書いてあります。
なので、
https://github.com/IntelRealSense/librealsense/blob/master/doc/distribution_linux.md
を見ながらlibRealSenseをインストールすのですが、この通りやると、現在の最新(執筆時点では2.16.2)がインストールされてしまいます。そこで次のように2.16.1をバージョン指定してインストールします。
※もし、2.16.2をインストールしてROSラッパーの2.1.0をビルドすると、次のエラーが出ちゃいます。これで3時間は無駄な時間を費やしました。

CMake Error at /usr/lib/x86_64-linux-gnu/cmake/realsense2/realsense2Targets.cmake:84 (message):
 The imported target "realsense2::tm" references the file
 "/usr/lib/x86_64-linux-gnu/libtm.a"
 but this file does not exist. Possible reasons include:
 * The file was deleted, renamed, or moved to another location.
 * An install or uninstall procedure did not complete successfully.
 * The installation package was faulty and contained
 "/usr/lib/x86_64-linux-gnu/cmake/realsense2/realsense2Targets.cmake"
 but not all the files it references.
Call Stack (most recent call first):
 /usr/lib/x86_64-linux-gnu/cmake/realsense2/realsense2Config.cmake:33 (include)
 realsense2_camera/CMakeLists.txt:35 (find_package)
-- Configuring incomplete, errors occurred!
See also "/home/hiroakikaneda/catkin_ws/build/CMakeFiles/CMakeOutput.log".
See also "/home/hiroakikaneda/catkin_ws/build/CMakeFiles/CMakeError.log".

上のようなエラーが出たら、ROSラッパーのバージョンと、それに対応しているlibrealsenseがちゃんとインストールできているかバージョン整合性を確認してみて下さい。
インストールは次の手順で行います。

sudo apt-key adv --keyserver keys.gnupg.net --recv-key C8B3A55A6F3EFCDE || sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-key C8B3A55A6F3EFCDE
sudo add-apt-repository "deb http://realsense-hw-public.s3.amazonaws.com/Debian/apt-repo xenial main" -u
sudo apt-get update
sudo apt-get install -y librealsense2=2.16.1-0~realsense0.88
sudo apt-get install -y librealsense2-dkms
sudo apt-get install -y librealsense2-utils=2.16.1-0~realsense0.88
sudo apt-get install -y librealsense2-dev=2.16.1-0~realsense0.88
sudo apt-get install -y librealsense2-dbg=2.16.1-0~realsense0.88

 
次に、ROSラッパー(ROS Wrapper 2.0 for Intel® RealSense™ Devices (build 2.1.0))をインストールします。
https://github.com/intel-ros/realsense
の手順に従うだけです。ただし、私の場合は既にROSがインストールされておりwork spaceも設定済みだったので、以下のように手順を変更しています。

cd ~/catkin_ws/
wget https://github.com/intel-ros/realsense/archive/2.1.0.tar.gz -O realsense-2.1.0.tar.gz
tar xzvf realsense-2.1.0.tar.gz
catkin_make clean
catkin_make -DCATKIN_ENABLE_TESTING=False -DCMAKE_BUILD_TYPE=Release --source realsense-2.1.0
catkin_make install --source realsense-2.1.0
#ビルドした結果が~/catkin_ws/installに配置されますので、パスを通します。
echo "source ~/catkin_ws/install/setup.bash" >> ~/.bashrc
#installが不完全なので、足りないファイルは手でインストールします。
cp -r realsense-2.1.0/realsense2_camera/cfg install/share/realsense2_camera/
cp -r realsense-2.1.0/realsense2_camera/meshes install/share/realsense2_camera/
cp -r realsense-2.1.0/realsense2_camera/scripts install/share/realsense2_camera/
cp -r realsense-2.1.0/realsense2_camera/urdf install/share/realsense2_camera/
#ビルド後のソースコードは不要なので削除して、ビルドしなおし、realsense-2.1.0フォルダもキレイに消去します
rm -rf realsense-2.1.0
rm -rf build
rm -rf devel
catkin_make clean
catkin_make
#反映
source ~/.bashrc
#installにパス通ったか確認してみる
echo $ROS_PACKAGE_PATH

 
 
これで、realsenseのrosラッパーをビルドして 、~/catkin_ws/installの中にインストールし、パスを通すことができていると思います。
テスト実行してみます。
 

sudo apt-get install ros-kinetic-rgbd-launch
roslaunch realsense2_camera rs_camera.launch

 
 

macOS high sierra Inkscape 起動しない

inkscape fails to start on macos 10.13. うーん困った。
インクスケープが起動しません。インストール直後の1回だけは起動するのですが、その後起動しなくなります・・・トホホ。
In this case,
そのような場合は、アプリケーション、の「その他」にある「ターミナル」を起動し、
 

/Applications/Inkscape.app/Contents/MacOS/Inkscape

と打ってやると起動するそうです。

inkscape fails to start on macos 10.13 (high sierra) from Inkscape


毎回打ち込むのは面倒なんでオートメーションを使います。

シェルスクリプトに先程のコマンドを打ち込み、デスクトップに保存します。

Cmd+Iで情報を表示します。/Application/Incscape.appを選択し同じようにCmd+Iで情報を表示します。

アイコンをコピーします。

 
これで、デスクトップのIncsapeをクリックすると起動するようになりました。

 
 
以上、macOS High SierraでIncscapeが起動しない時の対処法でした。

UbuntuでApple Magic Trackpadの移動速度を最速にする

こんな感じでトラックパッドの速度を変更できます。
Apple Magic Trackpadが、認識されているトラックパッドの名前です。
最後の1が、マウスの速度。大きくすると遅くなります。
xinput –set-prop “Apple Magic Trackpad” “Device Accel Constant Deceleration” 1
これを自動起動するアプリケーションに登録します。

 

しかし、速度1にすると、速くて快適なのですが、シビアになりすぎて、領域選択とか出来ません(笑)
 

Outdated Kotlin Runtime

Outdated Kotlin Runtimeワーニングが出ました。Intellij ideaの画面ですが、おそらくAndroid Studioも同じでしょう。

 Your version of Kotlin runtime in 'Gradle: org.jetbrains.kotlin:kotlin-stdlib:1.1.3-2' library is 1.1.3-2, while plugin version is 1.1.4-release-IJ2017.2-3.
 Runtime library should be updated to avoid compatibility problems.

ここで、Update Runtimeボタンをクリックしてしてみましたが、次のメッセージが表示されるだけです。

Automatic library version update for Gradle projects is currently unsupported. Please update your build.gradle manually

この場合はbuild.gradleファイルを開き、手動でバージョンを上げます。

 ext.kotlin_version = '1.1.3-2'

となっている所を

ext.kotlin_version = '1.1.4-3'

とします。

最新のバージョンはリポジトリページで見つけることができます。

これでOutdated Kotlin Runtimeワーニングが消えるはずです。

参考:
https://stackoverflow.com/questions/43928118/outdated-kotlin-runtime-warning-kotlin-plugin-1-1-2-release-studio2-3-3

Lenovo Phab 2 Pro で Project Tango 入門3

本日はPointCloudのJavaサンプルを見てみましょう。
Android StudioのでInport projectを選択し、java_point_cloud_exampleを選択してOKボタンをクリックします。

ファイル構成は以下のようになっています。

PointCloudActivity.java Javaによる点群表示サンプル。メインアクティビティです。
PointCloudRajawaliRenderer.java 点群データのレンダラーです。
 TouchViewHandler.java  標準的なパン操作とズームタッチ操作の処理を含む、VR設定のトップダウンビューと3人称ビューを追加するヘルパークラスです。
 rajawali/FrustumAxes.java public class FrustumAxes extends Line3D
FrustumとAxesの組み合わせを表すプリミティブ(基本的なもの)。錐台(すいだい、英: Frustum)は、錐体から、頂点を共有し相似に縮小した錐体を取り除いた立体図形の事。
Axesとは軸の事。
 rajawali/Grid.java public class Grid extends Line3D
現在のシーンの「床」を表すRajawaliオブジェクト。
これはシーンに配置された静的グリッドで、さまざまなビューにパースペクティブを提供します。
 rajawali/PointCloud.java public class PointCloud extends Points
色を使用して深度センサまでの距離を示すポイントクラウドをレンダリングします。
着色は光のスペクトルに基づいています。最も近い点は赤色で、最も遠くは紫色です。
rajawali/Points.java public class Points extends Object3D
Rajawaliの点のプリミティブ(基本型)です。

それでは詳しくみていきましょう。

PointCloudActivity

onCreateでは、TangoPointCloudManagerを生成しています。また、PointCloudRajawaliRendererクラス(点群データのレンダラー)のインスタンス生成を行なっています。また、DisplayManagerを取得し、画面の回転方向をmDisplayRotationメンバ変数へ保持しています。
onStartでは、bindTangoServiceメソッド内で、Tangoサービスを通常のAndroidサービスとして初期化します。
onStopでは、OpenGLスレッドまたはUIスレッドで使用されているサービスが切断するまで同期します。Tangoコールバックスレッドでこの同じオブジェクトに対してロックしないでください。すべてのTangoコールバックコールが終了するまで、Tango.disconnectはここでブロックされます。Tangoのコールバックスレッドでこのオブジェクトをロックすると、デッドロックが発生します。
bindTangoServiceではTangoサービスを通常のAndroidサービスとして初期化します。 onPauseでmTango.disconnect()を呼び出すので、これはTango Serviceのバインドを解除するので、onResumeが呼び出されるたびに新しいTangoオブジェクトを作成する必要があります。サービスがOpenGLスレッドまたはUIスレッドで使用されているときに切断に対して同期させます。
setupTangoConfigはbindTangoService内で呼ばれるメソッドで、Tango設定オブジェクトを設定します。 この呼び出しを行う前に、mTangoオブジェクトが初期化されていることを確認してください。これはデフォルトの設定を使用して、さらに深度センサーを追加します。
startupTangoもbindTangoServiceメソッド内で呼ばれるメソッドで、Tangoサービスのコールバックリスナーを設定し、Tango接続後に必要なその他のパラメータを取得します。ポイントクラウドとTangoのイベントとポーズの更新をリッスンします。
setupRendererはonCreate時に呼ばれるメソッドで、Rajawaliサーフェイスビューとそのレンダラーを設定します。 これは、理想的にはonCreateで1回だけ呼び出されます。
setupTangoUxAndLayoutもonCreate時に呼ばれるメソッドでTangoUXの設定とそのリスナーの設定を行います。イベントは、例外条件が観測されたときに「DETECTED」とみなされ、根本原因が解決されたときに「RESOLVED」とみなされます。
画面のFirstボタンを押すとカメラが現在位置に設定されます。いわゆる一人称視点になります。
Thirdボタンを押すとカメラを現在位置に設定し、Z軸に45度回転し、更にカメラをY軸に45度回した位置に固定します。いわゆる第三者視点です。
Topボタンを押すとカメラを現在位置の上部に固定し上からの俯瞰表示にします。これらボタンの処理はTouchViewHandler内で行われます。
画面上には、getAveragedDepthメソッドで計算した平均深度とポイントクラウドの数が表示されています。

PointCloudRajawaliRenderer

ポイントクラウドのデータはXYZC形式で提供されるため、ポイントあたり4つのfloatを示します。
レンダリングされたポイントクラウドを更新します。 このためには、クラウドデータを取得した時点でポイントクラウドデータとデバイスポーズが必要です。
注:これは、OpenGLレンダリングスレッドから呼び出す必要があります。
Rajawaliは左手系を使用するため、共役四元数が必要です。(共役四元数はこちらのサイトの説明がわかりやすい)
現在のデバイスポーズに関する情報を更新します。
注:これは、OpenGLレンダリングスレッドから呼び出す必要があります。
Rajawaliは四元数に対して左手系を使用するため、共役四元数が必要です。

TouchViewHandler

標準的なパン操作とズームタッチ操作の処理を含む、VR設定のトップダウンビューと3人称ビューを追加するヘルパークラスです。
 

実行する

では実行してみましょう。実行すると次の画像のような点群表示が得られます。リアルタイムでかなり高速に点群表示できている事が確認できます。ただ、点群の更新はちょっと遅れるようですね。そんなに応答性が良い感じではありませんが、スマホで使うには申し分ない速度でしょう。

 

 

 

Lenovo Phab 2 Pro で Project Tango 入門 2

前回に続き、サンプルの動作を確認していきましょう。
java_augmented_reality_exampleです。
これは、Tango APIを使用して拡張現実感(AR)アプリケーションを作成する方法を示す簡単な例です。 それは、装置の正面1メートルのところに浮かぶ惑星地球とその周りを回転する月を表示します。
この例では、OpenGLレンダリングにRajawaliを使用しています。これには、バックグラウンドでの カラーカメラ画像と、前方3mの空間に浮かぶ地球の質感を持つ3D球が含まれます。
この部分は、通常のRajawaliアプリケーションのように、{@code AugmentedRealityRenderer} クラスで実装されています。
この例では、Tango APIを使用してOpenGLテクスチャにカラーカメラデータを効率的に取得し、 拡張現実感効果を実現するためにOpenGLカメラがデバイスの動きを追跡するようにする方法に焦点を当てます。
Rajawaliの仮想世界をRGBカメラと同期させる最良の結果を得るには、 KEY_BOOLEAN_LOWLATENCYIMUINTEGRATION設定パラメータを含めることが重要です。
Rajawaliのようなレンダリングライブラリを使用しない、より抜粋した例を探しているなら、 java_hello_video_exampleを見てください。
では、import projectをクリックし、java_augmented_reality_exampleを選択してOKを押します。

RajawaliはAndroid OpenGL フレームワークです。
実行すると次のように地球と月が表示され、位置がほぼ固定されます。ただ追従はあまりよくない感じです。

 

Lenovo Phab 2 Pro で Project Tango 入門

世界初の Tango 対応スマートフォンLenovo Phab 2 Proを購入しました。

まずは開封の儀

IMG_3839
なんとパッケージから内部が見えます。Phab 2 Proの特徴であるデプスカメラ、モーション・トラッキング・カメラが見えています。
 
IMG_3840IMG_3841
かなりでかい印象です。Xperia Zと比べるとこんなにも違います。
付属品は、ACアダプタ、ヘッドフォン、USBケーブル。
早速電源に繋いで充電をします。充電されるのを待っている間に、Project Tangoについて勉強することにしましょう。
まずは、Googleのサイトから。
https://get.google.com/tango/
まずはProject Tangoの仕組みの概要です。
Tangoのコンセプト
モーショントラッキング
エリア学習
奥行き検知

サンプルプロジェクトのダウンロードと実行

https://github.com/googlesamples/tango-examples-java/archive/master.zip をダウンロードします。
Android Studioを起動して「Inport project」より、java_basic_examplesディレクトリを選択してOKを押します。

プロジェクトが開いたら、ツールバーを見るといくつかのモジュールが存在していると思います。ここからhello_motion_trackingを選択してRunボタンをおして実行してみましょう。

実行するとAndroid Studioの下部に生の姿勢データが表示されます。

では次にhello_depth_preceptionを実行してみましょう。これも同じくLogcatに生の値を吐くだけです。ただポイントクラウドはデータ量が多いからか距離の平均を出力しているようです。

Logcatを見るかぎり、おおよそ0.2秒間隔で3万6千個の点を取得出来ているようです。
次に、heloo_area_descriptinを実行してみましょう。このサンプルは先ほどまでのサンプルより複雑ですね。
Larning mode onにしてStartするとセンサーの値から領域を学習し、学習した領域をADFに保存します。
最後にhello_videoです。
このhello_videoはとてもなめらかに動き、ほぼ遅延なくRGBカメラからの画像が画面上に表示されます。
ヘッダよりこのサンプルは以下の機能を説明しています。

 このサンプルでは、RGBカメラをOpenGLテクスチャに変換します。
 単純なレンダラーで標準のAndroidのサーフェスビュー(GLSurfaceView)を作成し、ビデオレンダリング用の適切な設定でTangoサービスに接続します。
新しいRGBビデオフレームがTango APIを介して利用可能になるたびに、OpenGLテクスチャに更新され、対応するタイムスタンプがlogcatおよびスクリーンに印刷されます。
 
 Tango RGBカメラで生成された特定のテクスチャ形式をレンダリングする方法を理解するために必要な最小OpenGLコードのみが提供されています。
これらの詳細は、HelloVideoRendererで見つけることができます。
 拡張現実エフェクトを使用して実際の3Dオブジェクトをレンダリングする例をお探しの場合は、java_augmented_reality_example
および/またはjava_augmented_reality_opengl_exampleを参照してください。

 

TurtleBot3-プリンターで印刷可能なロボティスク入門機

ロボティクス入門として、ROS入門機として定番のTurtleBotシリーズに新しくTurtleBot3が加わります。

TurtleBot3とは?

ROSの管理団体であるOpen RoboticsとROBOTISが共同開発しているROS対応のモジュラータイプロボットシステム「Turtlebot3」シリーズです。現在ワッフルとバーガーという2種類が販売されるようです。
2017/6/1から購入可能になるようですね。5月は教育機関向けアーリーバードを販売中でした。そちらは既に完売済。

TurtleBot3の特徴

TurtleBot3は教育、研究、製品開発向けの小型ロボットです。

オープンソースソフトウェア及びオープンソースハードウェア

TurtleBot3はオープンソースのロボット用ソフトウェアであるROS上で動きます。ハードウェアもすべてオープンになっていて、ロボットを構成するパーツのCAD情報が全てインターネット上で閲覧できます。ですから今すぐあなたの3Dプリンターでパーツを印刷してロボットを組み上げることも可能です。メインコントローラーボードのOpenCRもオープンであり、設計が公開されています。
そのため、その気になれば全て自分で作成して、ソフトウェアをインストールし、動かしてみるということが可能です。メインコントローラーボードの基盤を基板屋さんで作ってもらって自分でハンダ付けすればカスタマイズした基盤だって作れます!

カスタマイズ可能

TurtleBot3は自由にカスタマイズ可能です。ワッフルというベース部品を自由に組み合わせることでいろいろな形のロボットを作成することができます。既に販売が決まっているワッフルとバーガーというタイプの他にも「フレンズ」と言う、車、マニュピレーター、セグウェイ、運搬車、モンスター、タンク、オムニホイール、メカナム、バイク、トレイン、亀ロボット、キャリアといった12種類の形状、設計の違うロボットが用意されています。
それらフレンズ達の部品データもCADデータが公開されているため、プリンターで印刷可能です!

価格

気になる価格はバーガーが5万4千円、ワッフルが17万円です。

IoTプラレールを作ったよ

インターネットから操作可能なIoTプラレールを作成してみました。その手順を残しておきます。

機能

  • インターネット上からプラレールの前方カメラの映像を確認可能
  • インターネット上からプラレレールの前進・後進およびその速度を100段階で変則可能。スムーズな発進・停止が可能
  • ブラウザによるカメラ映像の確認と操縦が行える。


用意したもの。

  • プラレールの車体(ドクターイエロー)
  • Raspberry pi zero w
  • コンビニで買ったスマホ用バッテリー(ラズパイ及びモーター用電源)
  • 余ってたモータードライバ(TA7291A)
  • 電圧変換器(http://amzn.to/2rCJZlJ)
  • Raspberry pi camera v2

先に言っておきますが、作るぐらいなら買ったほうが・・・という気もしますが。まあ、自分で作ることに意義があるのです。ちなみに本物では車窓からの画像も表示できるようですね。
お約束:当ウェブサイトの情報により生じた、いかなる損害等に関しましても、一切責任を負うものではありません。本サイト掲載情報の利用によって利用者等に何らかの損害が発生したとしても、かかる損害については一切の責任を負うものではありません。
では作っていきます。
車体の作成
まずはカメラがマウントできないと意味がありません。先頭車両にカメラを配置します。使用するのは手元にあったラズパイカメラ。これをいい感じに先頭車両にマウントしてやります。今回は3Dプリンタでカメラマウントを自作、カメラ部分を持ち上げ配置します。これが一番大変な作業でした。

ラズパイzero用のマウンタも作成しラズパイも先頭車両に収めてしまいます。

コンビニで買ってきたモバイルバッテリーは殻割りして中央車両に埋め込みます。できるだけ車体に穴は開けたくないので、充電用のUSBソケットが車両のドアから覗いているような感じで仕上げました。

後部車両には電圧変換器を収めます。モーターの定格電力は1.5vで、モバイルバッテリーが5Vのため、電圧を落としてからモーターに接続します。

 
 
ラズパイのセットアップ
Raspberry pi zero wの基本的な設定をしていきます。といっても他のラズパイシリーズとやることは同じです。無線LANで自宅のルーターに接続できるように設定しておきます。
カメラ画像の配信はMJPG-Streamerを使います。これをインストール&セットアップするだけでラズパイカメラの映像をインターネット上から確認することができます。
スピート調整はモータードライバを使います。TA7291Aの詳しい使い方はこちらを参考にしてください。
モーターはTA7291Aに接続しています。GPIOを操作することで、前進、後進が可能で速度を調整することが可能です。

また、ソフトウェアPWMを行いたいので、WiringPiをインストールしておきます。

 WiringPiのインストール

sudo apt-get install libi2c-dev
sudo apt-get install git
sudo apt-get install git-core
sudo apt-get install build-essential
cd /opt
sudo git clone git://git.drogon.net/wiringPi
cd wiringPi
sudo ./build
cd /opt
sudo git clone https://github.com/WiringPi/WiringPi-Python.git
cd WiringPi-Python
sudo git submodule update --init

このインストールは必須ではありません。コマンドラインからGPIOをテストできたり、GPIOの状態を表示したりとデバッグで使います。
GPIOの操作にはWebIOPiを使用します。WebからI/Oを制御できます。PWMの制御も出来ます。正直これ一つあればWebと連動したシステムは簡単に構築できるという優れものです。
Raspberry Pi2 以降でも使えるように、WebIOPiの0.7.1にパッチを当てて使用します。

$ wget http://sourceforge.net/projects/webiopi/files/WebIOPi-0.7.1.tar.gz
$ tar xvzf WebIOPi-0.7.1.tar.gz
$ cd WebIOPi-0.7.1
$ wget https://raw.githubusercontent.com/doublebind/raspi/master/webiopi-pi2bplus.patch
$ patch -p1 -i webiopi-pi2bplus.patch
$ sudo ./setup.sh

setup.shを実行するとPythonのインストールも行われます。
途中、

Do you want to access WebIOPi over Internet ? [y/n]

と聞かれた場合は「n」を入力してEnterを押します。

次に、WebIOPiを起動するための設定です。

$ cd /etc/systemd/system/
$ sudo wget https://raw.githubusercontent.com/doublebind/raspi/master/webiopi.service
# 起動
$ sudo systemctl start webiopi
# 自動起動on
$ sudo systemctl enable webiopi

動作確認です。Raspberry Pi のポート8000にアクセスします。認証ダイアログではデフォルトのパスワード
ユーザー名:webiopi
パスワード:raspberry
を入力します。今回はおもちゃとして作成するのでパスワードは邪魔です。このパスワード設定を削除するには/etc/webiopi/passwdを削除してWebIOPiを再起動します。

$ sudo mv /etc/webiopi/passwd /etc/webiopi/passwd.backup
$ sudo systemctl restart webiopi

GPIOを制御するプログラムを作成していきましょう。

/home/pi/work/webiopi/script.py を作成します

import webiopi
GPIO = webiopi.GPIO
VREF = 14
IN1 = 15
IN2 = 18
def setup():
 # Set GPIO to PWM
 GPIO.setFunction(VREF, GPIO.PWM)
 # Set GPIO to OUT
 GPIO.setFunction(IN1 , GPIO.OUT )
 GPIO.setFunction(IN2 , GPIO.OUT )
 # Run
 GPIO.pwmWrite(VREF , 1)
def destroy():
 # stop
 GPIO.pwmWrite(VREF , 0)
@webiopi.macro
def forwardTrain():
 GPIO.digitalWrite(IN1, True )
 GPIO.digitalWrite(IN2, False )
@webiopi.macro
def backwardTrain():
 GPIO.digitalWrite(IN1, False )
 GPIO.digitalWrite(IN2, True )
@webiopi.macro
def stopTrain():
 GPIO.digitalWrite(IN1, False )
 GPIO.digitalWrite(IN2, False )

/home/pi/work/webiopi/index.html を作成します

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <meta name="viewport" content="width=device-width">
 <title>運転席</title>
 <script type="text/javascript" src="/webiopi.js"></script>
 <script type="text/javascript">
 var imageNr = 0; // Serial number of current image
 var finished = new Array(); // References to img objects which have finished downloading
 var paused = false;
 function createImageLayer() {
 var img = new Image();
 img.style.position = "absolute";
 img.style.zIndex = -1;
 img.style.marginLeft="-160px";
 img.onload = imageOnload;
 img.onclick = imageOnclick;
 img.src = "http://192.168.0.10:9000/?action=snapshot&n=" + (++imageNr);
 var webcam = document.getElementById("webcam");
 webcam.insertBefore(img, webcam.firstChild);
 }
 // Two layers are always present (except at the very beginning), to avoid flicker
 function imageOnload() {
 this.style.zIndex = imageNr; // Image finished, bring to front!
 while (1 < finished.length) {
 var del = finished.shift(); // Delete old image(s) from document
 del.parentNode.removeChild(del);
 }
 finished.push(this);
 if (!paused) createImageLayer();
 }
 function imageOnclick() { // Clicking on the image will pause the stream
 paused = !paused;
 if (!paused) createImageLayer();
 }
 var IN1 = 15;
 var IN2 = 18;
 webiopi().ready(function() {
 var parts;
 parts = webiopi().createRatioSlider(14);
 $("#vref").append(parts);
 //初期値を指定
 $("#ratio14").val(1);
 parts =webiopi().createButton("forwardButton","GO",function() {
 webiopi().callMacro("forwardTrain");
 })
 $("#forward").append(parts);
 parts =webiopi().createButton("stopButton","STOP",function() {
 webiopi().callMacro("stopTrain");
 })
 $("#stop").append(parts);
 parts =webiopi().createButton("backwardButton","BACK",function() {
 webiopi().callMacro("backwardTrain");
 })
 $("#backward").append(parts);
 $("#forwardButton").css('background-color','green');
 $("#stopButton").css('background-color','red');
 $("#backwardButton").css('background-color','blue');
 });
 </script>
 <style type="text/css">
 input[type="range"] {
 display: block;
 width: 150px;
 height: 30px;
 -webkit-transform:rotate(-90deg);
 -moz-transform:rotate(-90deg);
 -o-transform:rotate(-90deg);
 transform:rotate(-90deg);
 transform-origin:right bottom;
 }
 input[type="range"]::-webkit-slider-thumb{
 -webkit-appearance: none;
 -moz-appearance: none;
 appearance: none;
 background-color: #666;
 text-align:center;
 width: 40px;
 height: 40px;
 border:1px solid transparent;
 border-radius:20px;
 cursor:pointer;
 -moz-box-sizing:border-box;
 -webkit-box-sizing:border-box;
 box-sizing:border-box;
 }
 button {
 display: block;
 margin: 5px 5px 5px 5px;
 width: 100px;
 height: 45px;
 font-size: 24pt;
 font-weight: bold;
 color: black;
 }
 </style>
</head>
<body onload="createImageLayer();" bgcolor="yellow">
 <div align="center">
 <div id="webcam" style="width: 320px;height: 240px;" >
 <noscript>
 <img src="http://192.168.0.10:9000/?action=snapshot" />
 </noscript>
 </div>
 </div>
 <div id="content" align="right">
 <div id="vref"><label>vref</label></div>
 </div>
 <div id="forward" style="float:left;"><label>すすむ</label></div>
 <div id="stop" style="float:left;"><label>とまる</label></div>
 <div id="backward" style="float:left;"><label>さがる</label></div>
</div>
</body>
</html>

/etc/webiopi/configを編集して、作成したプログラムを実行するように設定します。

$ sudo vim /etc/webiopi/config
[SCRIPTS]
# Load custom scripts syntax :
# name = sourcefile
# each sourcefile may have setup, loop and destroy functions and macros
#myscript = /home/pi/webiopi/examples/scripts/macros/script.py
myscript = /home/pi/work/webiopi/script.py
# Use doc-root to change default HTML and resource files location
#doc-root = /home/pi/webiopi/examples/scripts/macros
doc-root = /home/pi/work/webiopi/
# Use welcome-file to change the default "Welcome" file
welcome-file = index.html

再起動します。

sudo systemctl restart webiopi

これでネットワーク内の他のPCやスマホからラズパイにアクセスします。ではhttp://192.168.0.10:8000/にアクセスしましょう。(192.168.0.10はraspbery piに設定したIPアドレスです)

次のような画面が表示されれば成功です。

上部にはプラレールの前方映像がリアルタイムで配信されています。すすむ「GO」、とまる「STOP」、さがる「BACK」をタップしてドクターイエローを操作します。左のスライダーを上にすればパワー100%で最高速度になりスライダーを下にすれば速度が落ちます。

これで完成です。きっかけは息子の一言から。本人曰く、「プラレールの車窓から外をみてみたい」とのご要望でしたがあいにくカメラは1つしか搭載できなかったので、前方カメラだけと相成りました。