Based on ScratchにShareメニューを追加する

この記事はSmalltalk Advent Calendar 2015のエントリです。

今さらSmalltalkベースのScratch 1.4をイジる必要はなかろうと思うが、ちょっとしたアイデアを試したりするのにまだまだ使える部分が多い。

その1つにRemote Sensor Protocolがある。シンプルなプロトコルなので他の言語でも実装しやすい。ScratchでRemote Sensor Protocolを使うには、ちょっとしたメソッドの変更を行った上で、Shiftを押しながらShareメニューをクリックして、Host MeshまたはJoin Meshを選べばよい。(簡単だけど奥深い!Scratchプログラミングの魅力

しかし、ScratchSource1.4として公開されているオープンなScratch(いわゆるBased on Scratch)環境では、Shareメニューが存在しないので、この機能を利用することができない。

そこで、この記事ではBased on ScratchにShareメニューを追加する方法について説明したい。

目標

この記事では以下の機能の実現を目指す。

  1. Based on ScratchにShareメニューを追加する。
  2. ShareメニューにHost MeshおよびJoin Meshのメニュー項目を置く。
  3. 各メニュー項目がScratchにおけるRemote Sensor Protocolに基づいた機能を提供する。

ScratchのShareメニューには、作品をScratchのウェブサイトにアップロードする機能もあるが、Based on Scratch環境ではアップロードを行うことは許されていない。

you cannot implement the ability to upload projects to any MIT Scratch website (currently, http://scratch.mit.edu)
(License Informationより)

そこで、Host MeshおよびJoin Meshの機能実現のみとする。

準備

まずはScratchSource1.4.zipをダウンロードの上、適当なフォルダで展開する。

展開したフォルダにはイメージのみでVMがないので、普通のScratch1.4もダウンロードしてインストールしておく。

展開したフォルダにあるScratchSourceCode1.4.imageのファイルを、ScratchのVM(アプリケーション)にドラッグ&ドロップして、Based on Scratchを起動する。

ScratchSource1.4.imageの起動

ScratchSource1.4の起動時画面

起動したら、表示されているScratchのウィンドウを閉じる。そのためにはShiftを押しながらCommandキーを押し、表示されたHaloのうち左上の×印のボタンをクリックする。
×印のボタンを押して閉じる

メニュー用メソッドの作成

まずはShareメニューを押した時に反応するメソッドを作成する。

画面左側の緑色のウィンドウ(browser)の上段で、一番左にあるペイン(クラスカテゴリペイン)から、Scratch-UI-Panesを選ぶ。続いて、その右に表示されるクラスペインから、ScratchFrameMorphを選ぶ。そして、その右のプロトコルペインからmenu/button actionsを選ぶ。
browserの上段

するとbrowserの下段のコードペインが以下のようになっている(はず)。
メソッド入力欄

この内容を全て消して、以下の内容をコードペインに入力 or コピペする。

shareMenu: aMenuTitleMorph 
    | menu |
    menu _ CustomMenu new.
    self addServerCommandsTo: menu.
    menu localize.
    menu invokeOn: self at: aMenuTitleMorph bottomLeft + (0 @ 10)

shareMenu:の入力

「_」アンダースコアになっている部分が、入力すると←の記号に変わっているがこれで問題ない。

メソッド入力欄の左上に表示される「ー」をクリックしてコンテキストメニューを出し、acceptを選ぶ。
Screen Shot 2015-12-03 at 8.55.52
Screen Shot 2015-12-03 at 8.56.03

特に問題がなければイニシャルを入れるように促されるので適当なもの(スペースが含んでいてはダメ)を入力してAcceptを押す。
Screen Shot 2015-12-03 at 10.32.48

1行目が太字で表示されればOK。

メニューの登録

メニューにShareを追加して、shareMenu:メッセージを送るようにする。

同じbrowser内で上段の右から2番目のプロトコルペインでinitializationを選び、その右のメソッド一覧ペインでcreateMenuPanelを選ぶ。
Screen Shot 2015-12-03 at 10.37.21

コードペインの20行目付近に、メニュー項目を登録している箇所がある。EditとHelpのエントリの間へ、以下のようにShareメニューのエントリを追加する。
Screen Shot 2015-12-03 at 10.41.16

終わったら先ほどと同様に、コードペインのコンテキストメニューでacceptを選ぶ。

MESH機能の抑制解除

この時点でメニューにはShareと表示されるが、クリックしてもメニュー項目は表示されない。これは、ScratchがデフォルトでMESH機能を抑制しているためなので、この抑制を解除する必要がある。

browserのプロトコルペインでmenu/button actionsを選び、メソッド一覧ペインでaddServerCommandsTo:を選ぶ。
Screen Shot 2015-12-03 at 15.42.25

抑制を解除するには、上のコード中で明るく表示されているtrueを、falseに置き換える。そして、コードペインのコンテキストメニューでacceptを選べよい。

試してみる

3つの追加・変更が完了したら、デスクトップをクリックしてworldメニューを出し、open…からScratchを選ぶ。Shareメニューをクリックして2つのメニュー項目が表示されればOKである。
Screen Shot 2015-12-03 at 15.44.50

ネットワークで接続された2台以上のPCでScratchを起動すればMESH機能の面白さを実感できるが、1台のPC上でもScratchを2個立ち上げて、一方でHost Meshを選び、もう一方でJoin Meshを選べば動作を確かめることができる。後者についてはIPアドレスとして127.0.0.1と入力すればよい。

気をつけなければならないのは、一方で変数値を更新しても、もう一方の変数が変わるわけではないこと。もう一方ではセンサー値として他の変数値を参照できるだけである。

Change File

上記の追加・変更を行うチェンジファイルも公開しておく。
http://itolab.com/software/scratch/enableShareMenu.1.cs

このファイルをダウンロードしたらScratchSourceのフォルダに格納した上で、worldメニューを出して、open…からfile listを選ぶ。enableShareMenu.1.csを選んでコンテキストメニューからfileInを選べば、全ての追加・変更が行われる。

手軽に実施したい人はどうぞ。

Elementary OSにROS indigoをインストールする

Elementary OSの調子がなかなか良いのでROSをインストールして継続的に使ってみることにした。

Elementary OSのウェブサイトからisoイメージをダウンロードする。ダウンロードの際には「Freyaをダウンロード」を押す前に「カスタム」をクリックして0と入力すれば無料で入手できる。もう少し使ってみないとわからないが数ドル払う価値はあるのではと思う。
今回はChromeBook(C720)にインストールして使ったが大きな問題なくインストールできた。

ROS indigoのインストール

OSのインストールが終わったらROSをインストールする。Elementary OS Freyaがubuntu 14.04ベースなので、ROSはindigoをインストールする。
ROS indigoのインストールページを参考に、インストールを進める。

Setup your sources.list

まずsource.listを作成する。画面左上のApplicationからTerminalを選んで起動し、以下を入力する。

$ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'

これを実行すると/etc/apt/sources.list.dにros-latest.listが作られる。インストールページの指示に従ってapt-get updateまで実行すると、以下のようなエラーが発生する。

Err http://packages.ros.org freya/main amd64 Packages
  404  Not Found
Err http://packages.ros.org freya/main i386 Packages
  404  Not Found

/etc/apt/sources.list.d/ros-latest.listを見ると、以下のような内容になっている。

$ cat /etc/apt/sources.list.d/ros-latest.list 
deb http://packages.ros.org/ros/ubuntu freya main

trustyであるべき部分がfreyaになっているのでROSのパッケージを入手できないようだ。

そこで、この部分を書き換えて以下のようにする。

$ cat /etc/apt/sources.list.d/ros-latest.list 
deb http://packages.ros.org/ros/ubuntu trusty main

Set up your keys

以下を実行してkeyを設定する。

$ sudo apt-key adv --keyserver hkp://pool.sks-keyservers.net --recv-key 0xB01FA116

Installation

後は通常どおりROSをインストールすればよい。今回はDesktop-Full Installとした。

$ sudo apt-get update
$ sudo apt-get install ros-indigo-desktop-full

Initialize rosdep

続いてrosdepを実行する。

$ sudo rosdep init
$ rosdep update

ところが2行目の実行後、以下のようなエラーが発生する。

$ rosdep update
reading in sources list data from /etc/ros/rosdep/sources.list.d
Hit https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/osx-homebrew.yaml
Hit https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/base.yaml
Hit https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/python.yaml
Hit https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/ruby.yaml
Hit https://raw.githubusercontent.com/ros/rosdistro/master/releases/fuerte.yaml
Query rosdistro index https://raw.githubusercontent.com/ros/rosdistro/master/index.yaml
Add distro "groovy"

ERROR: Rosdep experienced an error: Could not detect OS, tried ['windows', 'ubuntu', 'rhel', 'qnx', 'osx', 'opensuse', 'opensuse', 'mint', 'linaro', 'gentoo', 'funtoo', 'freebsd', 'fedora', 'elementary', 'debian', 'cygwin', 'centos', 'arch']
Please go to the rosdep page [1] and file a bug report with the stack trace below.
[1] : http://www.ros.org/wiki/rosdep

これもsources.listの時と同様にubuntuのコードネームがfreyaになっているのではないかと考えられるので、以下のようにOSの検出を上書きする。

$ export ROS_OS_OVERRIDE=ubuntu:14.04

再度rosdepを実行する。

$ rosdep update

Environment setup

ROSの設定を行うように.bashrcを変更する。

$ echo "source /opt/ros/indigo/setup.bash" >> ~/.bashrc
$ source ~/.bashrc

これまたエラーが発生する。

bash: /home/itolab/.bashrc: line 168: syntax error near unexpected token `/opt/ros/indigo/setup.bash'
bash: /home/itolab/.bashrc: line 168: `esacsource /opt/ros/indigo/setup.bash'

もともと.bashrcの最終行に改行が入っておらず、echoの出力がつながってしまうことが原因である。適当なエディタで.bashrcを開き、esacとsourceの間に改行を入れる。

さらに先ほどのexportも追加しておく。

$ echo export ROS_OS_OVERRIDE=ubuntu:14.04 >> .bashrc 

Getting rosinstall

rosinstallをインストールする。

$ sudo apt-get install python-rosinstall

以上でElementary OSへのROS indigoインストールは完了する。

ChromeBookへのLinuxインストール(準備編)

【無保証、損壊の危険あり】この記事ではChromeBookのハードウェア・ソフトウェアに変更を加えるため、ChromeBookを元に戻せないような状態にする可能性がある。実施する場合は自己責任で行うこと。

以前にArchLinuxのインストール方法としてまとめたが、ArchLinuxを使っておらずその後の記事を掲載するつもりもないので、元記事を削除し、必要な部分だけ残すことにした。
この記事ではChromeBook(Acer C720)でSeaBIOSを設定する手順について説明し、実際にLinuxをインストールする手順については別途説明する。

前提

自分が購入したChromeBookがAcerのC720(C720-2420)なので、この記事ではそれに関する情報のみ載せる。

Linux導入準備の流れ

  1. デベロッパーモードの有効化
  2. SeaBIOSの有効化
  3. ハードウェア書き込み保護の無効化
  4. GBBフラグの設定
  5. ハードウェア書き込み保護の有効化

デベロッパーモードの有効化

chrubuntuのインストールで説明したのと同じ方法でデベロッパー(開発者)モードにする。具体的には以下の手順となる。

  1. ChromeBookを終了しておく。
  2. キーボード最上段のescと→を押しながら、電源をオンにする。
  3. リカバリ画面になったら、Ctrl-Dを押し、その後、Enterを押す。
  4. 開発者モード用の初期化が始まり、その後自動的に再起動される。

SeaBIOSの有効化

これも以前の記事と同じように無線LANを有効にした後、ログイン画面する。

  1. ChromeBookを起動する。
  2. 無線LANの設定を行い、インターネットへアクセスできるようにする。
  3. EULAの画面をAcceptしてログイン画面に進む。(ただしログインしない)
  4. ctrlとaltを押しながら最上段の→キーを押し、ChromeOSのCUIログイン画面に移る。
  5. ユーザーIDとして、chronos と入力してログインする。(パスワードは入力しない)

次にSeaBIOSを有効化する。
$ sudo bash
# crossystem dev_boot_usb=1 dev_boot_legacy=1

シャットダウンする。

ハードウェア書き込み保護の無効化

デフォルトでSeaBIOSを起動するように変更するにはGBBフラグを設定する必要がある。また、このようにしないとバッテリーが空になった際に、自動的にChromeOSがリカバリされ、インストールしたLinuxが失われてしまう。GBBフラグを設定するには、ソフトウェア書き込み保護の無効化を行う必要があり、それに先立ってハードウェア書き込み保護の無効化を行う。

この手順を行うとAcerの保証が受けられなくなるので注意すること。

ArchLinuxサイト上のC720の情報ページに従い、C720の裏面のネジを全て取り外す。具体的な手順は以下の通りである。

  1. 裏面に見える12個のネジを全て外す。
  2. 保証用のシールを外して、その下のネジを外す。(保証が受けられなくなるので注意)
  3. 裏面のパネルを注意深く外す。
  4. 写真を確認しながら、バッテリー右上にある7番のネジを外す。
  5. 裏面のパネルを元に戻す。

裏面パネルは比較的簡単に外れる。ディスプレイヒンジ側の中央あたりに爪を入れ、やさしく開けていけば良い。

バッテリーが接続されたままなので、基盤上のネジを外す場合はドライバーを電子部品等に接触させないように十分に注意して行うこと。
また、外したネジは後で元に戻すので失くさないように注意する。

GBBフラグの設定

通常通りにChromeBookの電源を入れ、先ほどの「SeaBIOSの有効化」と同じようにCUIログインを行って、以下を実行する。

$ sudo su
# flashrom --wp-disable
# flashrom --wp-status

最後のコマンドで書き込み保護が無効化されていることを確認する。

# /usr/share/vboot/bin/set_gbb_flags.sh

上記を実行した結果が以下のようになっていることを確認する。

GBB_FLAG_DEV_SCREEN_SHORT_DELAY 0x00000001
GBB_FLAG_FORCE_DEV_SWITCH_ON 0x00000008
GBB_FLAG_FORCE_DEV_BOOT_LEGACY 0x00000080
GBB_FLAG_DEFAULT_DEV_BOOT_LEGACY 0x00000400

同じ内容であれば以下を実行して、SeaBIOSがデフォルトで起動するように設定する。

# /usr/share/vboot/bin/set_gbb_flags.sh 0x489

ソフトウェアの書き込み保護を有効にする。

# flashrom --wp-enable

ChromeBookをシャットダウンする。

ハードウェア書き込み保護の有効化

先ほどの「ハードウェア書き込み保護の無効化」と同じように裏面のパネルを取り外し、外したネジを7番の場所に元通り付ける。

SeaBIOS関係の設定は以上である。

グラフ操作フレームワーク:Grafeo公開

Smalltalk

データを元にグラフを生成して、ぐりぐりとグラフを扱うにはRoassalという素晴らしいツールが既にある。一方で、小規模なグラフを作ったり操作したりできるツールの必要性もあって、ここ数年そういったソフトウェアの開発を行っていた。もとはFluoのグラフ操作部分だったのが、汎用的になるようにリファクタリングを重ねていったら、それなりに使えそうなものができたので公開することにした。

Grafeo

方向性としては、状態遷移図を作ったりするようなツールのフレームワークを目指しつつ、ちょっとしたグラフを描きたいといった場合に便利なツールとしても使えるようにしたい。
まだ公開していないが、このGrafeoをベースに既存のFluoを構築したり、umejavaさんのSState向けのUIを作ったりしているので、ぼちぼちと公開して行こうと思っている。

Liva PCにubuntu 14.04.2をインストールする

以前にアマゾンで買ったECSのLiva PCにubuntu 14.04.2のデスクトップ版をインストールした。
要するに、

  1. Ubuntuのサイトから14.04.2 LTSの64bit版をダウンロードする。
  2. Rufusを起動して「MBR UEFIコンピュータのためにパーティション構成」を選んで適当なUSBメモリに書き込む。
  3. Liva PCのBIOSを立ち上げて(電源オン時にDELキーを押す)、BOOTでUSBデバイスを優先にする。
  4. あとは普通にインストール。

だけでよかった。lubuntuも同様。

Raspberry pi model B(Raspbian wheezy版)にROS indigoをインストールする

この記事はRaspbian wheezy用のROS indigoビルドについて書いている。jessie用については別記事を参照のこと。

Raspberry piにROS/indigoをインストールする。現時点でRaspberry pi用のROSのバイナリパッケージは提供されていないようなので、直接ビルドしていくことになる。手順の概要は以下の通り。

  1. Raspbianをインストールする。
  2. ROSビルドの設定を行う。
  3. ROS本体をビルドする。

Raspbianのインストール

まず、Raspberry piのダウンロードページからNOOBSのZIPファイルをダウンロードする。

ダウンロードするしたZIPファイルを適当なフォルダに展開し、FATフォーマットされたSDカードにコピーする。

Raspberry piを適切にセットアップし、インターネット接続できるようにネットワークケーブルを接続したあと、NOOBSをコピーしたSDカードを挿入して起動する。

起動後の画面で日本語を選び、Raspbianのインストールを選んでインストールを始める。

このあたりの手順は、Raspberry piのセットアップページを参照する。

一般的なサイトで紹介している設定を済ませておくと良いだろう。

ROSビルドの設定

この手順はROSのページを参考にしている。要は忠実に一つずつこなしていくことだ。

2016/06/13追記
この記事はRaspberry piのOSであるRaspbianのバージョンがwheezyの頃の内容である。現時点でのRaspbianはjessieになるので、インストールするパッケージは異なる。この場合は別記事を参照してほしい。

なお、自分のRasperry piがどのバージョンのRaspbianで動作しているかどうかは、以下のコマンドで確認できる。

$ lsb_release -a
No LSB modules are available.
Distributor ID:	Raspbian
Description:	Raspbian GNU/Linux 8.0 (jessie)
Release:	8.0
Codename:	jessie
$ 

Codenameの行に動作中のバージョンが表示される。
2016/06/13追記終了

リポジトリの設定と更新

ROSのリポジトリを設定し、認証キーを追加する。

sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu wheezy main" > /etc/apt/sources.list.d/ros-latest.list'
wget https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -O - | sudo apt-key add -

aptのパッケージインデックスを更新する。

sudo apt-get update
sudo apt-get upgrade

ビルド用パッケージのインストール

ビルドに必要なパッケージをインストールする。

sudo apt-get install python-setuptools python-pip python-yaml python-argparse python-distribute python-docutils python-dateutil python-setuptools python-six
sudo pip install rosdep rosinstall_generator wstool rosinstall

rosdepを初期化する。

sudo rosdep init
rosdep update

catkinのワークスペースを作成する。

mkdir ~/ros_catkin_ws
cd ~/ros_catkin_ws

Variantの選択

ここで、ROSのどんなパッケージをビルドするかを選ぶことになる。推奨されているvariantのはros_commだが、他にdesktopやrobotなどがある。目的に応じて好きなものを選べばよい。variantはREP 131のページで紹介されている。

適当なvariantを選んだら、以下のようなコマンドでインストールの設定を行う。なお、下はros_comm用のコマンドなので、選んだvariantに応じてros_commの部分(3カ所ある)をvariantの名前で置き換えて実行する。

rosinstall_generator ros_comm --rosdistro indigo --deps --wet-only --exclude roslisp --tar > indigo-ros_comm-wet.rosinstall
wstool init src indigo-ros_comm-wet.rosinstall

なお、Collada DOMが不要ならば以下のように –excludeの後ろに collada_parser と collada_urdf を追加する。

rosinstall_generator ros_comm --rosdistro indigo --deps --wet-only --exclude roslisp collada_parser collada_urdf --tar > indigo-ros_comm-wet.rosinstall
wstool init src indigo-ros_comm-wet.rosinstall

この時点で選んだvariantを間違えてしまった場合は、srcフォルダを削除して上のコマンドをやりなおせば良い。

必要なパッケージのインストール

ROSのビルドに必要だが、Raspbianではstableになっていないパッケージをそれぞれビルドしておく。まずは、その準備を行う。

sudo apt-get install checkinstall cmake
sudo sh -c 'echo "deb-src http://mirrordirector.raspbian.org/raspbian/ testing main contrib non-free rpi" >> /etc/apt/sources.list'
sudo apt-get update

libconsole-bridge-dev,liblz4-dev,liburdfdom-headers-devをインストールする。

mkdir ~/ros_catkin_ws/external_src
cd ~/ros_catkin_ws/external_src
sudo apt-get build-dep console-bridge
apt-get source -b console-bridge
sudo dpkg -i libconsole-bridge0.2_*.deb libconsole-bridge-dev_*.deb
apt-get source -b lz4
sudo dpkg -i liblz4-*.deb
git clone https://github.com/ros/urdfdom_headers.git
cd urdfdom_headers
cmake .
sudo checkinstall make install

最後のcheckinstallを行うと、以下のような設定が現れる。

0 -  Maintainer: [ root@raspberrypi ]
1 -  Summary: [ Package created with checkinstall 1.6.2 ]
2 -  Name:    [ urdfdom-headers ]
3 -  Version: [ 20150804 ]
4 -  Release: [ 1 ]
5 -  License: [ GPL ]
6 -  Group:   [ checkinstall ]
7 -  Architecture: [ armhf ]
8 -  Source location: [ urdfdom_headers ]
9 -  Alternate source location: [  ]
10 - Requires: [  ]
11 - Provides: [ urdfdom-headers ]
12 - Conflicts: [  ]
13 - Replaces: [  ]
Enter a number to change any of them or press ENTER to continue:

2番のNameをurdfdom_headersからliburdfdom-headers-devに変更する必要があるので、2 を入力してEnterを押し、次に liburdfdom-headers-dev と入力する。再度確認の設定が表示されたらそのまま Enter を押して続ける。

cd ..
sudo apt-get install libboost-test-dev libtinyxml-dev
git clone https://github.com/ros/urdfdom.git
cd urdfdom
cmake .
sudo checkinstall make install

最後のcheckinstallを行うと、以下のような設定が現れる。

0 -  Maintainer: [ root@raspberrypi ]
1 -  Summary: [ Package created with checkinstall 1.6.2 ]
2 -  Name:    [ urdfdom ]
3 -  Version: [ 20150804 ]
4 -  Release: [ 1 ]
5 -  License: [ GPL ]
6 -  Group:   [ checkinstall ]
7 -  Architecture: [ armhf ]
8 -  Source location: [ urdfdom ]
9 -  Alternate source location: [  ]
10 - Requires: [  ]
11 - Provides: [ urdfdom ]
12 - Conflicts: [  ]
13 - Replaces: [  ]
Enter a number to change any of them or press ENTER to continue:

2番のNameをurdfdomからliburdfdom-devに変更する必要があるので、2 を入力してEnterを押し、次に liburdfdom-dev と入力する。再度確認の設定が表示されたらそのまま Enter を押して続ける。

Collada DOMのインストール

variantsの選択時に Collada DOM を除外していなければ、以下を実行する。

cd ~/ros_catkin_ws/external_src
sudo apt-get install libboost-filesystem-dev libxml2-dev
wget http://downloads.sourceforge.net/project/collada-dom/Collada%20DOM/Collada%20DOM%202.4/collada-dom-2.4.0.tgz
tar -xzf collada-dom-2.4.0.tgz
cd collada-dom-2.4.0
cmake .
sudo checkinstall make install

checkinstallを行うと、以下のような設定が現れる。

0 -  Maintainer: [ root@raspberrypi ]
1 -  Summary: [ Package created with checkinstall 1.6.2 ]
2 -  Name:    [ collada-dom ]
3 -  Version: [ 2.4.0 ]
4 -  Release: [ 1 ]
5 -  License: [ GPL ]
6 -  Group:   [ checkinstall ]
7 -  Architecture: [ armhf ]
8 -  Source location: [ collada-dom-2.4.0 ]
9 -  Alternate source location: [  ]
10 - Requires: [  ]
11 - Provides: [ collada-dom ]
12 - Conflicts: [  ]
13 - Replaces: [  ]
Enter a number to change any of them or press ENTER to continue:

2番のNameをcollada-domからcollada-dom-devに変更する必要があるので、2 を入力してEnterを押し、次に collada-dom-dev と入力する。再度確認の設定が表示されたらそのまま Enter を押して続ける。

collada_urdfへのパッチ

Collada DOMをインストールした場合、以下のようにcollada_urdfへパッチを当てる必要がある。

Google Groupのエントリに添付されているパッチファイル(0001-fixed-arm-build.patch)をダウンロードし、ホームディレクトリにコピーしておく。

以下を入力してパッチを当てる。

cd ~/ros_catkin_ws/src/robot_model/collada_urdf/
patch -p1 < ~/0001-fixed-arm-build.patch

依存関係の解決

rosdepを実行して依存関係を解決する。

cd ~/ros_catkin_ws
rosdep install --from-paths src --ignore-src --rosdistro indigo -y -r --os=debian:wheezy

上記を実行すると、python-rosdep, python-catkin-pkg, python-rospkg, python-rosdistro, sbclがない旨のエラーメッセージが表示されるが、これらはpip経由でインストールしているので無視してよい。

ROS本体のビルド

後は以下を入力して本体をビルドする。

cd ~/ros_catkin_ws
sudo ./src/catkin/bin/catkin_make_isolated --install -DCMAKE_BUILD_TYPE=Release --install-space /opt/ros/indigo

終わるまでひたすら待つしかない。SSH経由だとタイムアウトする可能性があるのでタイムアウトしないように設定するかコンソール経由でビルドする。

動作確認

.bashrcで初期化スクリプトを実行するようにする。

echo "source /opt/ros/indigo/setup.bash" >> ~/.bashrc
source ~/.bashrc

roscoreを起動する。

roscore
... logging to /home/pi/.ros/log/9781754e-3a9d-11e5-8b98-b827ebe98f3c/roslaunch-raspberrypi-11718.log
Checking log directory for disk usage. This may take awhile.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.

started roslaunch server http://raspberrypi:42226/
ros_comm version 1.11.13


SUMMARY
========

PARAMETERS
 * /rosdistro: indigo
 * /rosversion: 1.11.13

NODES

auto-starting new master
process[master]: started with pid [11735]
ROS_MASTER_URI=http://raspberrypi:11311/

setting /run_id to 9781754e-3a9d-11e5-8b98-b827ebe98f3c
process[rosout-1]: started with pid [11748]
started core service [/rosout]

Ctrl-Zを押してプロセスを止め、プロンプトでbgを入力してバックグラウンド動作させる。

bg

トピックの一覧を表示させる。

rostopic list
/rosout
/rosout_agg

おそらく正常動作しているだろう。fgを入力した後、Ctrl-Cでroscoreの動作を止める。

fg
roscore
^C[rosout-1] killing on exit
[master] killing on exit
shutting down processing monitor...
... shutting down processing monitor complete
done

ここまでくるのにかなりの日数を要してしまった…

ROS indigoでiRobot Createを動かすまで

以前にもTurtleBotの関係でベースとなるiRobot Createを動かす手順をまとめたが、今回は別の方向に進む準備段階としてできるだけ少ない手間でCreateを動かす手順をまとめたい。

OSのインストール

OSとしてubuntuの軽量ディストリビューションであるlinuxBeanを用いた。linuxBeanの公式サイトから、linuxBean 14.04 (Trifolium) 14.04.2をダウンロードする。ROS/indigoを用いるために14.04を選んでインストールした。
必要な設定などは過去の記事を参考にしながら進めた。

ROS/indigoのインストール

ROSのインストール手順に従って進めて行く。

まず、パッケージのリポジトリ設定を行う。

sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'

次にキーの設定を行う。

sudo apt-key adv --keyserver hkp://pool.sks-keyservers.net --recv-key 0xB01FA116

パッケージインデックスの更新を行う。

sudo apt-get update

GUIツールなしでindigoをインストールする。

sudo apt-get install ros-indigo-ros-base

rosdepの初期化を行う。

sudo rosdep init
rosdep update

環境変数などの設定を行う。

echo "source /opt/ros/indigo/setup.bash" >> ~/.bashrc
source ~/.bashrc

rosinstallをインストールする。

sudo apt-get install python-rosinstall

catkin用のワークスペースを作成する

mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace
cd ..
catkin_make

Createノードの準備

Create用のパッケージを導入する

sudo apt-get install ros-indigo-create-node

CreateとUSBシリアルアダプタを用いて接続する。

上記のノードで使う /dev/ttyUSB0 を見てみると以下のようになっている。

ls -l /dev/ttyUSB0
crw-rw---- 1 root dialout 188,0 7月 23 14:58 /dev/ttyUSB0

/dev/ttyUSB0にアクセスできるように、自分のユーザー名(hoge)をdialoutグループに追加する。

sudo vigr

/etc/groupファイルのうち、dialoutで始まる行の末尾に自分のユーザー名(hoge)を追加する。

dialout:x:20:hoge

Createへの接続テスト

roscoreを起動する。

roscore

(別のターミナルを開いて)create_nodeを起動する。

rosrun create_node turtlebot_node.py

赤字でエラーメッセージが表示されなければ(おそらく)問題ない。

Createを前進させる。

rostopic pub -1 /cmd_vel geometry_msgs/Twist -- '[10,0,0]' '[0,0,0]'

Createが数センチ動けばOK。

はじめてのMorphicチュートリアル(第14回)「文字の表示」

モーフに文字を表示する方法について学ぶ。

モーフに文字を表示するには、おおまかに2通りの方法がある。1つはStringMorphを使う方法、もう1つはdrawOn:で直接描画する方法である。

StringMorphを使う

StringMorphは文字を表示するためのモーフである。

(StringMorph contents: 'aiueo') openInWorld.

上のコードをPlaygroundに入力してDo itすれば、画面の左上に小さく aiueo と表示されるのがわかる。
StringMorph
これは文字を表示するモーフであり、マウスでドラッグして好きな場所に移動することができる。

表示するフォント名やポイント数を指定したい場合には、contents:の代わりにcontents:fonts:メッセージを送る。

(StringMorph contents: 'あいうえお'
                  font: (LogicalFont familyName: 'Osaka' pointSize: 30)) openInWorld.

StringMorphをサブモーフにすることもできる。MyMorph2でメッセージを表示するようにするなら、initializeメソッドを以下のように変更する。

initialize
    super initialize.
    ActiveHand keyboardFocus: self.
    keys := Set new.
    (StringMorph contents: 'Hello!'
                 font: (LogicalFont familyName: 'Apple Chancery' pointSize: 30))
        in: [ :morph | 
            morph topLeft: self topRight.
            morph color: Color red.
            self addMorphBack: morph ]

後半の4行がStringMorphを追加している部分である。簡単に説明しておくと、まず指定した文字列とフォントでStringMorphを生成しておき、得られたモーフに対して位置を設定(StringMorphの左上がMyMorph2の右上の座標になるように)して赤色にし、サブモーフとして追加するという流れになっている。
Screen Shot 2015-06-18 at 7.26.01
残念ながらStringMorphでは背景色を設定できないので、背景色が必要な場合にはStringMorphを、色を付けた素のモーフのサブモーフにして同じ位置に設定する。

drawOn:で表示する

drawOn:はモーフを描画する際に送られるメッセージで、第12回ではそのことを利用して画像を表示した。これと同様にモーフ描画の一部として文字を書く方法がある。

モーフを描画する必要が生じると、各モーフに対してdrawOn:というメッセージが送られる。メッセージには描画先としてのCanvasオブジェクトが引数として添えられているので、このCanvasオブジェクトに描画メッセージを送ってモーフを描く。

文字を描くためにCanvasオブジェクトに送ることのできるメッセージはいくつかあり、Canvasクラスのdrawing-textプロトコルを見ればわかるが、実際にはdrawString:at:メッセージか、drawString:at:font:color:メッセージだけで事足りるだろう。前者は指定された文字列を指定された位置にデフォルトフォントを用いて黒色で描画するというものであり、後者は更にフォントと色を指定できるというものである。

応用例として、押下中の文字を表示する機能をMyMorph2に付けてみよう。

drawOn: aCanvas
    super drawOn: aCanvas.
    aCanvas drawString: keys asString at: self topLeft

2行目は本来のモーフの描画を、親クラスであるMyMorphに行わせるためのものである。3行目では、押下中のキーを保持しているインスタンス変数keysの内容を文字列に変換し、モーフの左上に描画している。

drawOn:を用いる際の注意点として、特定のタイミングで明示的に表示内容を更新したい場合には、自分自身に対してchangedメッセージを送る必要があることである。MyMorph/MyMorph2では、画像を表示させる際に大きさや位置を変更しているため暗黙的な描画が行われるのでchangedメッセージを送る必要はないが、文字列内容だけを変更した場合などは、変更後に描画を行わせるためにself changed.というメッセージ式を実行する必要がある。

(第14回おわり)

はじめてのMorphicチュートリアル(第13回)「サブクラス化とキーイベントの処理」

クラスの機能を拡張するにはメソッドを追加していく必要があることを第5回の記事以降で学んできた。

既存のクラスの機能を維持しつつ、似たような新たな機能を持った異なるクラスを必要とする場合、第4回で学んだクラス定義によって新たなクラスを作成する。

例えば、今まで作成したMyMorphクラスと同様にScratch Catが移動していくのだが、マウスではなくキーボード操作によって移動するようなクラスが欲しい場合、MyMorphを親(基底)クラスとする新たなクラスを作成する。そうすればMyMorphの機能を引き継いだ、新たなクラスを作ることができる。

ここでは、そのような新しいクラスをMyMorph2として定義してみよう。

MyMorph subclass: #MyMorph2
    instanceVariableNames: ''
    classVariableNames: ''
    category: 'Hajimeteno Morphic Tutorial'

この新しいMyMorph2では、モーフをキーボードで操作してみよう。以前の記事ではキーボードイベントの取り扱いが中途半端になっていたので、この回でより具体的にキーボードイベントを扱う。

MyMorph2の基本的な仕様としては、上下左右の矢印キーが押されている間だけ矢印の向きにモーフが動くようにする。

キーボード入力に反応するために定義しなければならないメソッドは以下の通りである。

  • handlesKeyDown:
  • handlesKeyUp:
  • keyDown:
  • keyUp:

前2者はモーフがキーボードイベントを受け取るためにtrueを返す必要がある。後2者で受け取ったキーボードイベントを実際に処理する。まず、前2者のメソッドは以下のようになる。

handlesKeyDown: evt
    ^ true
handlesKeyUp: evt
    ^ true

これらのメソッドにより、キーボードが押された瞬間にkeyDown:メッセージがモーフに送られ、離された瞬間にkeyUp:メッセージが送られる。それぞれキーボードイベントが引数となっている。

キーボードイベントの実体はKeyboardEventオブジェクトであり、keyメッセージを送るとKeyオブジェクトが得られる。Keyオブジェクトにnameメッセージを送ると押されたキーの情報を得ることができる。少し寄り道してkeyDown:メッセージの内容を表示して、どんな内容となっているのか確認してみよう。

keyDown: evt
    self inform: evt key name

今までの3つのメソッドを実装したら以下をDo itする。

ActiveHand keyboardFocus: MyMorph2 new openInWorld.

キーボードイベントの説明のところで述べたように、キーボードフォーカスをモーフに移動しないとキーボードイベントを受け取れない。そこで、生成したモーフに強制的にキーボードフォーカスを設定している。MyMorph2が現れたら適当なキーを押してみると、押した瞬間と押し続けている間、画面の左下にメッセージが現れ、Keyオブジェクトのnameが表示される。

矢印キーのnameは以下のような文字列である。

  • KP_UP — 上矢印
  • KP_DOWN — 下矢印
  • KP_LEFT — 左矢印
  • KP_RIGHT — 右矢印

これらの値を使えば押されたキーの判定を行うことができる。

矢印キーが押されている間だけ矢印の向きにモーフを動かすとすると、押されているキーを覚えておく必要がある。そこで、MyMorph2のクラス定義を修正して、keysという名前のインスタンス変数を追加する。

MyMorph subclass: #MyMorph2
    instanceVariableNames: 'keys'
    classVariableNames: ''
    category: 'Hajimeteno Morphic Tutorial'

押されたキーを全てkeysに覚えておくため、keyDown:メッセージを受け取ったタイミングでKeyオブジェクトの名前をkeysに追加し、keyUp:メッセージで除外する。キーが押し続けられるとkeyDown:メッセージを複数受け取ることになるが、そのあたりをうまく処理するためにSetオブジェクトを用いることにする。Setは集合のようにデータを扱うためのクラスで、同じデータを複数追加しても個数はカウントされない。MyMorph2のinitializeメソッドを用いて初期化しておく。ついでにキーボードフォーカスを自分自身にセットするようにしておこう。

initialize
    super initialize.
    ActiveHand keyboardFocus: self.
    keys := Set new

モーフの移動は今までと同じくstepメッセージを受け取ったタイミングで行うが、移動量であるvecはkeyDown:とkeyUp:のタイミングで更新することにする。keysの内容に基づいてvecの値を計算するメソッドcalcVecを新たに作成する。

calcVec
    vec := 0 @ 0.
    (keys includes: 'KP_UP')
        ifTrue: [ vec := vec + (0 @ -10) ].
    (keys includes: 'KP_DOWN')
        ifTrue: [ vec := vec + (0 @ 10) ].
    (keys includes: 'KP_LEFT')
        ifTrue: [ vec := vec + (-10 @ 0) ].
    (keys includes: 'KP_RIGHT')
        ifTrue: [ vec := vec + (10 @ 0) ]

Setオブジェクトであるkeysに送られているincludes:というメッセージは、引数のデータがSetオブジェクトにあるかどうかを調べるためのものである。calcVecメソッドでは押されているキーに応じて上下左右の移動量をセットしている。

keyDown:メソッドでは、単に受け取ったキーボードイベントのKeyオブジェクトの名前をkeysに追加し、自分自身にcalcVecメッセージを送るだけである。

keyDown: evt
    keys add: evt key name.
    self calcVec

Setなど複数のデータを扱うことのできるものをコレクションと呼ぶ。コレクションにデータを追加する場合、たいていadd:メッセージを用いる。

keyUp:メソッドでは、単に受け取ったキーボードイベントのKeyオブジェクトの名前をkeysから取り除き、自分自身にcalcVecメッセージを送る。

keyUp: evt
    keys remove: evt key name ifAbsent: [  ].
    self calcVec

Setオブジェクトからデータを削除するにはremove:メッセージを使うが、削除したいデータがないとエラーになるので、ここではremove:ifAbsent:というメッセージを用いている。2番目の引数は、データがなかった場合の処理を書くが、ここでは何もしないようにしている。

以上で矢印キーにより上下左右に移動するMyMorph2ができた。

(第13回おわり)

はじめてのMorphicチュートリアル(番外編)「メソッドを整理する」

クラスを拡張してメソッドを増やして行くと、System Browserでのメソッドの一覧性が悪くなってくる。たとえば、今までにMyMorphのクラスで定義したメソッドは14個程度だが、ペインに入りきらない状況になっているだろう。
メソッド一覧

Smalltalkでは、メソッドの分類を行うためにプロトコルと呼ばれるものを用意している。プロトコル自体はプログラムの動作に何の影響もなく、単にプログラマにメソッドの分類方法を提供しているだけのものだ。とはいえ、プロトコルがなければ数十ときに数百に上るメソッドを持ったクラスのメンテナンスがとても面倒なものになってしまう。今回のチュートリアルでは、プロトコルによる分類について学ぶ。

まずプロトコルについて。以前、クラスの分類にクラスカテゴリを用いることを述べたが、プロトコルも同様のものである。座標をあらわすPointクラスを例にあげて説明しよう。
座標をあらわすPointクラスには様々なメソッドが定義されており、座標自身の情報の設定や取得に加えて、座標同士の演算や比較、変換や便利な機能など、およそ100のメソッドがある。
Pointクラス

Point methods size. "99"

プロトコルによって多数のメソッドを分類する。Pointクラスには以下のようなプロトコルがある。

Point protocols joinUsing: String cr.
 "'-- all --
copying
*Fuel
accessing
private
point functions
printing
self evaluating
transforming
interpolating
testing
geometry
truncation and roundoff
polar coordinates
extent functions
converting
truncation and round off
comparing
arithmetic'"

先頭の’– all –‘は、全てのメソッドの一覧を得る際の擬似的なものであり、アスタリスクで始まるプロトコルは他のパッケージに属しているものを表す。その他は、Pointクラスにおけるさまざまな役割や機能を表すプロトコルとなっている。

どのメソッドをどのプロトコルに配置すべきかはクラスの設計者が決定しなければならない。このあたりの判断はなかなか難しい。既存のクラスを参考にしながらどのプロトコルに配置するかを決めていく。例えば、printOn:というメッセージが他のクラスではどのようなプロトコルで定義されているか調べるには以下のようにする。

SystemNavigation default browseAllImplementorsOf: #printOn:

printOn:を定義しているクラスの一覧が表示され、クラス名の右側の丸括弧の内側に定義されているプロトコル名が表示される。
Implementers
これを見ればprintingプロトコルで定義されているのがわかる。

最近のブラウザでは親クラスの配置を参考に、自動的にプロトコルへ振り分けてくれる機能を持っている。SystemBrowserのプロトコルペインで右クリックすると、categorize all uncategorizedというメニュー項目が現れるのでクリックすると、プロトコルに分類していないメソッドを自動的に分類してくれる。
categorize methods
メニューを選んで分類が終わると以下のようになる。
categorized list
おおむねそれらしく配置されているが、handlesMouseOver:がevent handlingではなく、recategorizedに分類されているのは違和感がある。このような場合には手動で分類する。handlesMouseOver:をドラッグしながらevent handlingでドロップすれば良い。

なお、どこにも定義されていないような自分メソッドを作った場合、既存のプロトコルで適切なものがなければ自分で作成することになる。新たにプロトコルを作成するには、プロトコルペインでAdd protocol…を選べば良い。

メソッドはどのプロトコルに分類したからといって実行性能に影響するわけではない。プロトコルはクラスの開発者や利用者がメソッドを探しやすくするための工夫である。Smalltalkerは「こんな機能(メソッド)ないかな?」と思ったときにプロトコルを手がかりにメソッドを探すことが多い。うまくメソッドを分類できれば時間短縮につながるので、ひと手間かけてプロトコルに分類することには価値がある。

(番外編おわり)