2014年12月31日水曜日

CouchDBをMapReduceで処理してみる

さてせっかくなので、MapReduce機能を使ってCouchDBのデータ処理をメモしておきます。
調べているうちに非常にわかりやすい所があり、MapReduceの説明にもちょうどよかったので自分なりに解釈して記しておきます。

まずデータを用意しないといけません。以下のような家計簿もどきを用意します。

date    category      item       price
5/10     果物           バナナ       300
5/10       魚               鯛         1000
5/11     果物           みかん       300
5/11     果物           バナナ       300
5/12       魚               鯛           900

各行が1個のドキュメントにあたります。(とりあえず全ドキュメントが持つFieldは同じにしておきます。その方が説明が楽なので。)

FutonでViewをTemplateに切り替えます。するとMapとReduceのプログラムを入力する欄が表示されます。そこでMapとして以下を入力します。

function(doc) {
  emit(null, doc.price);
}

すると全ドキュメントから価格だけ抜き出して一覧表示してくれます。


Reduceのプログラムをしてないので、データの抜き出しだけした結果です。
後、if文で特定のFieldのドキュメントだけ抜き出すこともできます。


次にReduce欄に以下を入力します。Reduce処理として集めたデータの加算を指示しています。

function(keys, values) {
  return sum(values);
}

すると以下の様になります。(emitの第1引数がkeysになり、第2引数がvaluesになるという関係です)


って言いたいところですが、Reduceが動いていない... よく見たらviewの右上にReduceにチェックを入れるボタンが。


どうもここにチェックを入れないとReduce処理をしてくれないようです。無事合計がでてくれました。

次に日付毎の価格を集計してみます。Map欄に以下を入力します。

function(doc) {
  emit(doc.date, doc.price);
}

key欄にdateを指定し、それ毎の塊を作ります。その時、priceの値だけを集めてきます。それをReduceで集計すれば日付ごとの価格の集計になります。


次にcategory毎の件数を集計してみます。とりあえずkeyにcategoryを指定すれば、category毎の塊は作成してくれます。

function(doc) {
  emit(doc.category, 1);
}

この時、valuesに「1」を固定して指定します。つまり集めた塊ごとに「1」の値が与えられることになります。これを集計すれば塊の件数になります。Reduce欄には例によってvaluesの集計をするようにします。


ということで、categoryの件数が出力されました。

本来、MapReduceはGoogleが考えだしたみたいに多数の計算機で処理するのが本当で、1台のPCでやっても旨味があまりありませんが、非常にわかりやすくドキュメント型のデータを処理してくれます。
後はこのMap欄やReduce欄のコードをアプリ側から自由に実行できないと、CouchDBの本当のいいところがでてこないでしょうが、それはまたメモできる程度、試行できたら。(Map欄のコードを実行した例は2回前のCouchDBのメモでもう記してますから、わかりやすいデータが思いつけば書けるでしょう)

CouchDBをpythonで操作する

さて実際のDB操作のための実装に移ります。例題として、ちょっと理科年表のデータを入れてみます。(地球半径とか高度ごとの気圧です)


ちょっと見にくいですが、Raidus, SeaLevelGravity, StaticPressureの3個のドキュメントを作成しました。これをプログラムで参照、変更してみます。
Futon上で最初にデータベースを作成してて困ったのが以下のStaticPressureです。
「高度:気圧」のペアのリストの構造なので、JSON形式でも扱いやすいしpythonでも辞書型で扱い易いと思ったんですが、Futon上からはどうしても思うように入力できません。結局、valueにはカンマ区切りの数字の羅列(高度1、気圧1、高度2、気圧2、。。。)という形式にしました。(そのうち3次元テーブルもでてくるから、このフォーマットの方が汎用性高いでしょう。javaにもpythonにもsplit()関数があって、valueを文字列で取得、個々の数字を簡単に切り出せますし。)
しかし、どうも辞書形式が登録できないのが気に入りません。頑張って上図のdataのように、「文字列:数字」のペアなら辞書として登録できることがわかりました。(どうもこれはFutonというより、CouchDBの制約のようです。後に実装でpythonから数字ペアの辞書を登録しますが、CouchDB上では最初の数字は文字列と認識されてしまいます)

ということで、pythonから直接、数字ペアを登録してみます。ドキュメント「Radius」にdataというFieldを作成しておいて、以下のコードで実行してみます。


# coding: utf-8
import couchdb

server = couchdb.Server('http://localhost:5984')
db = server['environment']

doc = db['Radius'] # ドキュメントの取得(コピーを作成するので注意)

dl = { 1:1, 2:2, 3:3} # サンプルデータの辞書

doc['data'] = dl # ドキュメントの一部を変更

db[doc.id] = doc # ドキュメントの更新
#db.commit() # なくてもいい

見た目は数字ペアの辞書が登録できたように見えます。


ところが、以下のプログラムで確認してみると、
# coding: utf-8
import couchdb

server = couchdb.Server('http://localhost:5984')
db = server['environment']

doc = db['Radius'] # ドキュメントの取得(コピーを作成するので注意)

print doc['data']

実行結果は以下の様になります。
{u'1': 1, u'3': 3, u'2': 2}
全然ダメです、最初の数字が文字列として認識されてしまっています。

余談:
ところでCouchDBは古いリビジョンを残していて、「適当」なところで自動的にガベージコレクションしてくれるそうです。ただ、プログラムを作って、動かしている方としてはHDDの容量も気になるので、意図的に古いのを削除したくなります。python-couchdbでは以下のメソッドで古いリビジョンを削除します。

# coding: utf-8
import couchdb

server = couchdb.Server('http://localhost:5984')
db = server['environment']

#db.cleanup() # これは古い設計
db.compact() # こっちが今の、古いリビジョンのドキュメントは削除する

説明見てたら同じようなメソッドが2個あったので試してみましたが、やはりcleanup()の方はダメで、そもそもエラーが出てきました。(説明にはそこまで書いてなかった)

2014年12月30日火曜日

CouchDBを設定し、pythonで操作してみる

NoSQLのデータベースで、高速性よりもフォーマットを自由に扱いたい場合、CouchDBの評判が高いようです。ちょっと試しに自PC上に(Ubuntu14.04)CouchDBを設定し、ついでにデータ操作をどうやるかを試すために、pythonでのサンプルを作ってみます。(オリジナルでJavaScriptのAPIは持っているそうです)

まずCouchDBのHP(launchpad.net)にいってインストール方法を調べます。Ubuntu14.04の場合は以下のようにするらしい。

$ sudo apt-get install software-properties-common

(aptのリポジトリの状態を確認、更新するらしい。
自分の場合あ既にこのリポジトリが入っていたらしく、最新の状態ですと言われた)

$ sudo add-apt-repository ppa:couchdb/stable

既に(古いバージョンが)インストールされているとまずいので、一度削除します。

$ sudo apt-get remove couchdb couchdb-bin couchdb-common

(自分は3個とも入ってない言われました)

いよいよインストールします。

$ sudo apt-get install -V couchdb
$ sudo stop couchdb
$ sudo start couchdb

ブラウザでhttp://127.0.0.1:5984/にアクセスします。
動いてるようですが、文字列しか表示されません。
couchdbのユーザー設定ないから?
(でも/etc/passwdで確認するとcouchdbのアカウントは登録されていました)
HPのドキュメントを見たら、現状はこれでいいようです。

http://127.0.0.1:5984/_utils

でFutonが動きます。大丈夫なようです。(データベースをWebベースで参照、変更、作成ができます)



PCを再起動しても自動的にデーモンは起動しています、Futonが動きました。

pythonでcoudbを使いたいので、/etc/couchdb/local.iniに以下を追加して再起動しろとのこと。

[query_servers]
python=/usr/bin/couchpy

念の為に/usr/bin以下を知らべてみたら、couchjs(おそらくJavaScript用のモジュール)はあるが、couchpyは存在していません。(注:この設定は必要なかったかも、なくてもcouchpyさえインストールすれば動きました。でも本当は必要な筈...)しばらくぐぐった結果、以下のパッケージをインストールしたらよかった。

$ sudo apt-get install python-couchdb

しかしcouchdbの再起動方法がわからない。(/etc/init.d以下にcoudbというスクリプトがあるという情報があったが、ubutu14.04だとそんなのない!どうやって最初に起動してるんだ?→後述)
PS:ちなみにこのpython-couchdb、昔はgoogle-Codeで開発されていたんですが、githubに移っていました。googleでも特に制約はないと思うけど、流行りですかね。
というか、再起動は必要なかった。(うまくいかないようなら、インストール直後にやったみたいにコマンドで直接、停止、起動をすればいいでしょう。)

試しにpythonでプログラムを書いてみました。試験用に用意したのは以下の様なデータです。
ぱっと見わかりにくいでしょうが、Fieldにわざと"name"と”名前”と英語、日本語の両方を使っています。


# coding: utf-8
import couchdb

db = couchdb.Server('http://localhost:5984')
sampledb = db['sample_db']

for id in sampledb:
 dbitem = sampledb[id]
 name = dbitem[u'名前']
 print name

日本語のフィールド名でも動きました。(まあそれでも、英語にしといた方が無難だろうね)

ところでCouchDBはデフォルトではPCの外部からのアクセスは禁止してあります。(データの操作にhttp使うくせに、こういうとこはしっかりしてます)
これを許可しないと使いずらいので、以下の場所を編集します。(コメントにデフォルトでなっているのをはずして、全部のIPアドレスを許可する、といったところでしょうか)

/etc/couchdb/local.ini
;bind 127.0.0.1
        ↓
bind 0.0.0.0

特に起動用スクリプトが見当たらないんですが、勝手に再起動してくれるようです。(他のディストリビューションだと起動用スクリプトができるものもあるらしいですが、今度はcouchdbのアカウントを自分で作ってあげないといけないとか)
あとFuton上でもConfigurationというToolがありそこからもできそうですが、、、ちょっとよくわかりません。うっかいこの項目を削除という操作をしてしまったらしく、いきなりWeb上から何もできなってしまって(まあ意味から考えて通信ができなくなりますわな)、あわてて手動で設定ファイルを編集しなおしました。

ところでCouchDBを通常のDBとして使おうと思ったんですが、どうもサンプルを探すとCouchDBの特徴であるMap/Reduceにより全文中の特定のFieldを探してくる、という例ばかりひっかかります。(考えてみたら、フォーマット自由のドキュメント型DBなんだから、そういう使い方が本道なんでしょうね)
でも自分はとりあえず普通に(ユニークな)idで検索するのをやりたいんです。

とりあえず、以下のプログラムでまずDBを作成します。
# coding: utf-8
import couchdb

server = couchdb.Server('http://localhost:5984')
db = server.create('python-tests')

db['johndoe'] = dict(type='Person', name='John Doe', sex='male')
db['maryjane'] = {'type':'Person', 'name':'Mary Jane', 'sex':'female'}  # あえてjson形式で指定してみる

db.commit()

# 特にcloseとかsaveは必要ない?
# 不安なら時にcommitするか
# 他のPCからすぐに編集した結果を参照したいアプリでは、あったほうがいい

次に以下のプログラムでidを直接指定します。

# coding: utf-8
import couchdb

server = couchdb.Server('http://localhost:5984')
db = server['python-tests']

print db['maryjane']

これで以下の出力がでてきます。
<Document u'maryjane'@u'1-6d8ea1b66198a41c398662aa3ae07514' {u'type': u'Person', u'name': u'Mary Jane', u'sex': u'female'}>

うまくいきました。(couchdb-pythonにAPIとかのマニュアルが見当たらないので、試行錯誤です)

せっかくなので、Map機能を使い検索してみます。FutonでTemplate Viewにして、

以下の関数をMap関数(左側の欄)として定義します。

function(doc) {
  emit(doc.sex, doc);
}

デフォルトは、emit(null, doc);でどうも全文対象という意味らしいんですが、sexというFieldにマークをします。
これをapplication/sample_viewという名前で保存します。(このスクリプト自体がDB内に保存されるのに注意。Futonで参照できます。)

これを使ったサンプルを以下に示します。
# coding: utf-8
import couchdb

server = couchdb.Server('http://localhost:5984')
db = server['python-tests']

#print db['maryjane']

result = db.view("application/sample_view", key="female")

for r in result:
 print 'id',r['id']
 print 'key',r['key']
 print 'name', r['value']['name']

keyの与え方はともかく、検索された後の他のタグを知る方法がちょっとクセがあります。
以下の様に出力されます。

id maryjane
key female
name Mary Jane

とりあえず最低限、必要なことはわかりました。

2014年12月28日日曜日

cardboardを作る

他にやりたいことは色々あるんですが、何となく目に留まったのがGoogleさんからでている、お手軽VR体験ができるcardboard。型紙をDLして、自分でカット、作成してもいいんですが、レンズとか手に入れるのがめんどくさい。
Amazonさんを覗いてみたら、今は安い値段でキットが色々でてるんですね。最近でたので¥560というのがあったので、ポチッと。ただし到着予定を見たら来年?なにこれ?
まあ安いし、あんまり来なかったらキャンセルするか、と軽い気持ちでいたらしばらくして発送のメールがきました。ところが、これまた到着予定が来年の1月で、荷物の追跡しようにも情報はないといわれる始末。(中国からDHLで送ってますよ!¥560って送料込みの値段なんですが。)これはやばいかな、と思ったら2週間ほどして日本郵便できました。

開けてみたら、普通にGoogleの型紙を加工してあるだけのようです。特に説明とか一切なし。GoogleのCardboardのサイトみても特に作り方は見つからず、たんに型紙に書いてある番号どうしをはめ込めとだけ...ちょっと困りました。作り方の動画なんかを2,3調べて参考にして作ってみましたがなんとかうまくいきました。

最後までわからなかったのが、磁石の仕組み。どうも2個の磁石を段ボール間にはさんでくっつけているだけのようなんですが、なんでこれでスイッチの仕組みになるのかわからない。(表側の磁石はずらせます。それで変化する磁束をNexus5が読み取っているのかな?)ただ、とくに磁石を固定するものもないので、磁石をスイッチとしてずらそうとするとよく内側のが落ちてしまいます。
しかたなく、内側の磁石はセロテープで固定しました。

さてできあがったので、さっそく手持ちのNexus5にアプリをいれてVR体験です!すごいという評判でしたが、確かにこの値段でここまでできれば十分でしょう。Nexus5のCPUパワーが素晴らしいせいもあるのでしょうが、頭を傾けたり、見回すと忠実に反応してくれます。なんか、また試したいことが増えちゃいました。

ところで自分はメガネしてますが、今回のCardboardはサイズ的にメガネしてるときついようです。もう少し大きめに作ってくれないと。Cardboardには色々亜流ができてるようですから、メガネOKなのを選んだ方がよかったかもしれません。(まあ段ボール製なので耐久性はないでしょうから、次に考えましょう)

2014年12月17日水曜日

Deep learningお試し:Pylearn2を動かす

昔から興味があった人工知能、最近Pylearn2がよく話題になってます。要は多重パーセプトロンらしいんですが、理論が難しくてよく分からん。(微分方程式が何故出てくるのか理解できない。重み付けの解法らしいけど……。)

とりあえず動かしてみようと、まずはvagrantでprecise64の環境で挑戦。しかしvagrantではGUIがなく、よく分からないエラーがでて断念。(最初はvagrantのpylearn2がインストール済みの定義ファイルがあったのですが、vagrantのバージョンがかなり古いらしく、動きませんでした。残念( i _ i ))
続いてVMplayerのUbuntu12.04(32bit)上で挑戦。なんだかんだ頑張って、よくあるcifar-10の学習はできました。
色々苦労はしましたが、自分で認識させる所まではまだ全然なんで、せめて自分で認識させることができるようになってから詳しい所はメモしようと思います。

2014年12月6日土曜日

つらつら思うこと:vagrantとDocker

1年くらい前にvagrantのことを知り、仮想マシンの扱いが飛躍的に便利になったと思いました。これで色々実験がしやすくなると思ったら、Linuxメインな自分にとって今度はDockerが現れ、仕組みは違えど狙うところはほとんど同じ。なんか栄枯盛衰が激しいですね。(自分はWeb系は仕事じゃないんで関係ないですが、業界の人は勉強が大変だ)

ただ自分的には、実験色々しようと思うとまっさらなマシンの方がいいから、しばらくはvagrantの方がいいかな、と思うところです。

2014年11月20日木曜日

Nexus5 Android5に更新してみました

2日程前にNexus5に更新のお知らせが来ました。少し悩みましたが(最初の大きいUpdateはバグあるしね)更新してみました。
500MB程DLしてかなり時間がかかりました。その後のインストールがまた時間のかかること。結局、30分くらいかかりました。
使い勝手はまあちょっと慣れるまで大変ですが、困ったのは最初中々LTEと繋がってくれませんでした。初めの1日くらいは、3Gに数秒かかって掴んで、それからLTEになりました。今ではすぐにLTEと接続するようになりましたが、何かキャッシュみたいなもの持ってる様な感じです。WiFiもパスワードは前のを覚えていてくれましたが、中々繋がらず時間がかかったんですが、今ではすぐに接続する様になりました。
ネットで見てると、WiFi等、色々問題が上がっていますが関係ありそうな感じです。(個人毎の環境は色々ですから。自分の所は田舎ですからLTE基地局は数える程しかありませんし、WiFiも混信とは無縁ですし。)

PS@20141123
今日気づきましたが、撮った写真を見ようと思ったら「ギャラリー」がありません!しばし悩んで、もしやと思ったら「Photo」に統合されており、どうしてもGoogleはクラウドに写真をUpさせたいようです。(もちろん最初にUpするか聞いてきますが、大抵の人は意味わからず自動的にUpにしちゃうぞ)あぶない、あぶない...
今時は「無料サービス」だとこんなばっかです。

2014年10月26日日曜日

Rapiro シリアル設定変更でトラブル

前回、そのままにしておいたシリアル設定ですが、やはりまずそうです。デフォルトでシステムコンソール入出力になっているせいか、時々Raspberry Piからのコマンドを受け取らないようです。

仕方ないので、システムコンソールをきる設定を行います。やることは簡単です。(そのはずでした。。。)

まず/boot/cmdline.txtが最初は以下の様になっています。

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait

これを以下の様に変更します。

dwc_otg.lpm_enable=0 rpitestmode=1 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait

次に、/etc/inittabの最後の行、以下をコメントアウトします。

TO:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

念のため、cmdline.txtの方はoriginalを残しておきます。(設定ファイルをいじるときは必須です)さて、rebootしてみますが、リモートログインできなくなりました。(;_;)何か設定ファイルの編集をミスったようです。何度かrebootを繰り返した後、あきらめてRapiroの頭部を分解、Raspberry Piを引き出します。キーボードとディスプレイを接続して電源を入れてみると、案の定起動中に止まってます。

さて、設定ファイルをまず元に戻さないといけないのですが、家にあるPCのうち、直接SDカードのI/Fをもっているのは1台のノートPC(Windows7)だけ。普段はUSBで接続するマルチアダプタで操作していたんですが、これだとUbuntuもMacも認識してくれませんでした。ノートPCで調べてみても、Windowsだと一部のエリアしか見ることができず、万事窮すの状態。これは最後の手段、SDカードを最初のrasbianのイメージで書き換えてはじめから設定し直しかと覚悟しましたが、ノートPCにはVMPlayerでUbuntuが入っていました。「これでSDカードを修正できないか?」かすかな期待を元に試してみると、うまくマウントできました!そこで2つの設定ファイルを元に戻し、無事起動できるのを確認、改めて編集したファイルを調べてみたらcmdline.txtの方でタイプミスと、やはり「0」(数字の0)と「O」(大文字のO)の勘違いがありました。(やな予感したんだよな〜)

再度設定し直して、リモートログインに問題がないことを確認してRapiroに装着、動作を確認しましたが、raspberry Piからのシリアル出力の受信ミスが発生しなくなるのを確認しました。

やはりシステムの設定ファイルを触るのはこわいですね。

2014年10月19日日曜日

RapiroにRaspberry Piを搭載

まずはRasbianのdisk image最新版をDLしてきます。2014-09-09版でした。zipファイルをDLして解凍しようとしますが、なぜかエラーがでてきます?DLやりなおしてもダメ。しばらくして、解凍しているPCがWindows7(32bit)だからダメなんじゃないかと思いつき、Windows7(64bit)でやってみたらうまくいきました。(おそらくimageからzipつくったのがLinuxの64bitなんだろうな・・・)


最初の起動でraspi-configが表示されます。まずはこのtool自身のUpdateをと思い、メニューを見ると、Updateが見当たりません???代わりに”Overclock”なるメニューになっているような。よく見ると、Advance optionがありましたので、その中にいくとUpdateがありました。


ついでにSSHのenableとhostnameの設定もあったので、そこで済ませました。
またimageを書き込んだだけのSD-cardですと使える領域が最低限しかありません。本来の容量を使えるよう、ちゃんとexpand filesystemしておいてあげましょう。


その後、念のためシステムを最新の状態にしておきます。


$ sudo apt-get update
$ sudo apt-get upgrade


次に無線LANが使えるようにUSB型式のBuffaloの小さいやつを設定します。
(これはあちこちにのっているので、詳細ははぶきます)


無線LANが使えるようになったところで、avahiをインストールします。通常の家庭ではプロバイダーからのDHCPがほとんどだと思います。しかしこれだとIPアドレスが何になるかわかりません。raspberry piは普通ディスプレイとか接続せずに使うので、LAN経由のsshでログインしたいところですが、毎回IPアドレスが変わってしまっては大変です。ホスト名でアクセスしたいところですが、いちいちDNSをたてるのも大変です。
そこでBonjour互換のavahiというサービスをインストールします。BonjourはAppleの提唱するネットワーク上のサービスを自動的に検索し利用できるようにするサービスです。これを使えばDHCPのマシンでもホスト名でアクセスできるようになります。


$ sudo apt-get install avahi-daemon


やることはこれだけです。(hostnameは先にraspi-confで設定してあります)その後、他のPCからpingコマンドで確認できればOKです。


$ ping rapiropi.local


今回はrapiroに搭載するつもりだったので、hostname=rapiropiとしました。urlはその後ろに”.local”をつけたものになります。
なお他のPCでこれを使おうと思うと、Macは当然デフォルトで入っているから問題ありませんが、Windowsの場合、iTunesをインストールすれば使えるようになります。(iTunesなんてインストールするのはいやだ!という方もいるかもしれません。一応単独でBonjourだけインストールするパッケージはiTunesのパッケージ内に入っているそうです)


実際にRAPIROに搭載してみます。ケーブルは元々それ用のものが頭にもってきてありますから簡単です。(頭部には固定用の簡易なツメもあります。なお、基板の穴をとおすノッチがRAPIROにはあります。しかし最初期のRaspberry Piにはこの穴(おそらく基板固定用のネジ通しの穴っぽい)がないものがあるようです)
接続するピンの写真はRAPIROのkickstarterのHPにあります。そこにはあいかわらず何も説明がありませんが、どうもUARTに電源供給とともに接続しているらしいです。デバイス名は、/dev/ttyAMA0になります。ただこれはデフォルトではシステムのコンソール入出力になっており、ボーレートも576000bpsではありません。そちらの設定を切った方がいいんでしょうが、python等プログラムから出力するにはそのままでも問題ないようです。(もしかしたら動作が不安定になるかもしれません。すこし試してからまたレスします。)
このUARTはRaspberry PiのGPIOを使っていますが、これの利用にはroot権限が必要です。プログラムの実行にはsudoが必要になります。

とりあえずリモートで前進させることができたので、いよいよ本格的にプログラムをどうするか検討に入ります。

2014年10月13日月曜日

Rapiroを作る

前から気になっていたんですが、ロボットのRapiroを作ってみました。しかしかなり苦戦しましたので、その記録を残します。

まず組み立て。マニュアルはWebで写真と、数少ない英語の説明のみ。わかりにくい。
しかも途中1カ所、どうみてもネジの指定間違えてるよ。(写真に写ってるネジと説明が食い違っていたので、明らかにわかりますが)


後、サーボのケーブルが長くて、胴体を最後にフタをするとき、かなりきつかったです。


さて動かし方ですが、これがまた不親切で、一言Arduino用のIDE、USB通信用のFTDIドライバをDLしてきてね、だけ。結局、他の方のBlogを参考にして、以下のことがわかりました。


・Arduino IDEは1.0.6を使おう。(βの1.5.8はまずいらしい。RapiroのWikiにも製作者から1.0.6でやってくれとコメントがありました)
・IDEではArduinoのボード型式を指定するところがあります。DefaultではArduino Unoになっていますが、それでいいようです。
・シリアルポートですが、PC(私の場合はMac)とUSBケーブルで接続します。このとき先ほどインストールしたFTDIドライバを使うのですが、Macの場合親切にもボードと接続しないと、そのポートがメニューに表示されません。(認識しているようです)なので、MacとRapiroを接続したのち、/dev/tty.usbserial-xxxxを選びます。(FTDIのHPには/dev/cs.usbserialがどうのと書いてあったので最初こちらかと思いましたが、ttyのようです)
・シリアルモニタでRapiroにコマンドを送れます。このときボーレートがDefaultでは9600になっていますが、57600に変更しないといけません。
・firmware(サンプルスケッチと呼んでいました。Arduino IDEではプログラムことスケッチというんですかね?)として指示されたのがgithubのページ。githubでどうやってソースDLしたらいいのか普通の人は知らないよ?まあ1ファイルでそれほど長くもないので、コピペしていけるとは思いますが。





電源はEneloopを推奨、というかアルカリ電池とかではダメだと明記してありました。本数が5本と中途半端な数で、手元に4本しかなかったため、一つ新品のアルカリ電池でやってみましたが、ダメでした。明らかに低電圧の時の異常動作をします。(アルカリ電池だと流せる電流容量が少ないでしょうからでしょうね)
しかたないので、外部電源(12V)を探したんですが、今はもう1個も持ってません。(大学時代まではよくハンダ付けとかで工作してたので何個か持ってたんですが)見回すと、ノートPC用にと買っておいた21000mAhの外部バッテリがありました。出力電圧や端子も数種類変えれます。これで試すとうまく動きました。


最初のうちは0点調整がうまくいってなかったのか、おかしな動きをしました。しかしこれはどうも最初のアルカリ電池まじりで試していたときに、0点調整の値を色々いじってたのがまずかったらしく、最終的には全部一度0にすることで、いい位置になりました。
(それでも最終的にはいくつか調整しましたが)


また足のPitchの0点調整がどうも難しいらしく、ずっと小刻みに唸っています。一度持ち上げると止まりますが、歩かせたりして止まった後にまた唸ります。これはfirmwareで初期値をいくら調整してみてもダメでした。そんなに大きな音ではないのですが、ちょっと気になります。
(注:YouTubeに某誌のプロモーションとして動かしている映像を見たんですが、その時も静止時に同じように小刻みな唸り音が聞こえたので、これは仕方がないようです。)


とりあえずこのfirmwareではシリアルモニタで以下のコマンドが入れれるようです。


Moveコマンド
#M0 : Stop 停止
#M1 : Forward 前進
#M2 : Back 後退
#M3 : Right 右回り
#M4 : Left 左回り
#M5 : Green 目を緑色にする
#M6 : Yellow 目を黄色にする
#M7 : Blue 目を青色にする
#M8 : Red 目を赤色にする
#M9 : Push 右腕を前に延ばす


Poseコマンド
#Pの後に5つのサブコマンドがあります。
S : Servo
R : Red
G : Green
B : Blue
T : Time


Servo
SxxAxxx
Sxxはサーボ番号00から11まで
Axxxはサーボ角度000から180まで(単位は度です)


Red Green Blue
RxxxGxxxBxxx
xxxは明度000から255まで


Time
Txxx
xxxは時間000から999まで、単位は0.1秒


使い方
#PS00A080T050というように使います。最後のTコマンドなんですが、数値が動きにどう影響してくるのかよくわかりません。ただ必要なようです。


サーボ番号と稼働範囲
00 : Head yaw : 0 – 90 – 180
01 : Waist yaw : 0 – 90 – 180
02 : R Sholder roll : 0 – 0 – 180
03 : R Sholder pitch : 40 – 130 – 130
04 : R Hand grip : 60 – 90- 110
05 : L Sholder roll : 0 – 180 – 180
06 : L Sholder pitch : 50 – 50 – 140
07 : L Hand grip : 60 – 90- 110
08 : R Foot yaw : 70 – 90 – 130
09 : Foot pitch : 70 – 90 – 110
10 : L Foot yaw : 50 – 90 – 110
11 : L Foot pitch : 50 – 90 – 110


数値は、角度の 最小 – 初期値 – 最大

0点調整の位置が初期値であることに注意。角度0が真ん中ではありません。(最初、うっかりHeadに0度と指定しまい、とんでもないことになりました)

さて一通り動作を確認したので、次はRapberry Piを組み込んでみないと。(一緒に発注済み)

2014年10月4日土曜日

Ubuntu14.04.1マシン nvidia不調(T_T)

XPの頃に購入したGaming PCにUbuntuを入れてます。12の時にも苦労したんですが、またやってしまいました。(・_;) Game用のPCなので、当然nVidiaのカードが入っているんですが、nVidiaのドライバって未だに特製のkernelモジュール(昔はkernel再ビルド)必要なんですが、これがよく相性(?)の問題を起こしてくれます。updateするときに注意しないと、すぐXが起動してくれなくなります。

updateの時、普通はupdate-managerに任せるもんですが、理由は不明ですがよく(Firefoxあたりで)リポジトリ内で不整合、と言われて失敗します。それが面倒くさくて、CLIでやってしまいます。

$ sudo apt-get update
$ sudo apt-get upgrade

これでやると不思議と失敗しません。
一つ問題があるのが、これでシステムの更新すると、Ubuntuのバージョン更新(upgrade)も自動的にやってしまうことです。
Ubuntu12の時に少しシステムの末尾の番号が上がってしまうと画面が起動しない、ということを何度も繰り返していました。今度も、気づいたら14.04→14.04.1と末尾が上がってしまい、「やばい!」と思ったら案の定Xが起動しません。Xorg.0.logを見てみるとnvidiaのkernel moduleのロードに失敗しています。

ネットで色々調べたんですがどうにもならず、諦めて再インストールしました。(実験用のマシンだから簡単に再インストールしちゃいますが、実用マシンだったら大騒ぎです。こんな調子ではWindowsに代わるDesktopになるのは未来永劫こないんじゃないか・・・)
システムのupdate-managerを使うと、バージョン更新の時は一応確認してくれます。注意していればいいんですが、たいていの人はうっかりupgradeしてしまうでしょうね。
システムの方でupdate-managerは自動的に動いてくれますが、手動で起動したい場合は以下のコマンドになります。

$ update-manager -d

気をつけて使っていくしかありません。(「安定版」という言葉が非常に重い)

2014年9月15日月曜日

EXCEL:シート内のTextエリア、カーソル進行方向が逆になる

先にEXCELでおかしな動作があったことを書きました。ついでなので、2年ちょっと前にあった別のおかしな動作も書いときます。

これはMicrosoftのHPにはっきりOfficeのバグだと書いてありました。何が起きるかというと、EXCELのシート内にTextエリアを作り、それでWord代わりに書類を作る方が時々います。(こっちからすると、なんでそんな面倒くさいことやるのか、と思うんですが大抵の人は仕事で資料作るときに、覚えるツールは最低限にしたい!という欲求があるようです)
それで2003のExcelで作成したデータを、2007/2010で開いて編集しようとすると、時々Textエリア内にカーソルを持っていき、編集したいところへカーソルを持っていこうと、例えば右に方向のカーソル移動キーを押したとします。だけど実際のカーソルは左に動いてしまう!?という状況です。

必ず発生するわけではありません。条件ははっきりしませんが、そういうことが起きるらしいです。(最初、相談されて実物を見たときはびっくりしました。)おかしいのはカーソル移動だけで、編集は普通にできます。カーソルをなんとか移動させて、そこに日本語を挿入すると普通に右子方向に文字列は挿入できます。

それでは何が起きたかというと、はっきりとはHPに書いてはありませんでしたが、どうも文字列の属性として「アラビア語」のフラグがこっそりOnになってしまうようです。(アラビア語は、右から左へと、通常の世界の言語とは逆に書きますから。)そこで、この属性に関するフラグを設定し直せとあったんですが、それをするためにはEXCELの使用言語に「アラビア語」を追加してやらないと、文字列の書く方向を指定するコマンドを入力できるようにならないそうです。
それで、「オプション」→「言語」で通常は日本語と英語(米国)しかありませんが、何かアラビア語を追加してやります。(なんか10個くらいアラビア語の種類がありますが、違いがわかりません。まあおそらく英語と英語(米国)の違い程度で、スペルチェックなんかが微妙に違うんでしょうが、そもそもアラビア語なんて入力できないんで、何か追加すればいいと思います)

するとEXCELの「配置」のところに以下の様な新しいコマンドが表示されるようになります。
そう、これでカーソルの移動方向がおかしくなったTextエリアを選択したのち、カーソルの進行方向を設定し直してやればいいんです。

Officeが2003から2007に変わったときは、UIが新しい「リボンインターフェース」になり、かなり戸惑いましたが、M$も罪作りなことにかなりバグ(実装上もだけど、要求仕様上の矛盾も含めて)を作りこんでくれたようで困ったもんです。それでもこれで資料作らないと仕事にならないし...

EXCELの動作がおかしい

人からEXCELの動きがおかしい、と尋ねられて以下の様な画面を見せられました。

(本物はもっと違う数字ですが、例なので単純にしています)最後の合計のところが関数になっていません、あきらかに文字列になってます。セルの書式設定を「標準」にしてやるだけだろうと思い、設定を変えようとしてみると、以下の状態になってました。

あれ?ちゃんと「標準」になってるよ?これ実は「オプション」→「詳細設定」の中にある以下の設定によるものです。

デフォルトではこの「データ範囲の形式および数式を拡張する」がOnになっています。これ何のことかといいますと、直上の連続するセル(今回の例では黄色で示してあるセルがそれにあたります)3つ以上が同じ書式を持っている場合、それを自動的に引き継ぐ機能なんです。
種を明かすと、この黄色のセルは実は「文字列」にしてあります。そのため合計を求めようとSUM関数を入れたのですが、自動的に文字列の書式に設定されてしまいます。

でも2枚目のSSで「標準」になっていることを確認しましたよね。これはある操作を行うと、上記な様なおかしな状況になってしまうことを確認しました。(注:毎回必ずなるわけではないようです。もう少しトリッキーな操作が必要かもしれません。)

①デフォルトのままオートSUMを入れる。(EXCELがここで困ったことに文字列の数字でも、変に「気をきかして」数値として計算してくれるのが間違いの始まり)
②SUMが計算され、結果が文字列として表示される。(従ってこの時点ではおかしなことになっているのに気付かない)
③ここで詳細設定の、上記設定をオフにしてやる。
④合計を行うセルの内容をいったん消して、再度オートSUMを入力する。
⑤②のときにこのセルの書式が文字列になってしまっているので、最初のSSの状態になる。
⑥ここで③の操作を取消、「データ範囲の形式および数式を拡張する」をOnにする。
⑦オートSUMが文字列として表示されているままなので、書式を「標準」にしてやる。

おそらく、書式のフラグがユーザーが操作するものと「データ範囲の形式および数式を拡張する」と別個に内部で持っており、そこに矛盾が発生するようです。
また、できる限りユーザのために思ったような動きをしようと、以下の様な状態の時もあります。

オートSUMを入力したんですが、自動的に上のセルの書式が移ってしまい「文字列」なんですが、計算はしてくれて、結果出力の段階で「文字列」として表示しているようです。

明らかに複数の異なる要求仕様の間に矛盾が発生しているようです。

とりあえずこれを直そうと思ったら、一度「データ範囲の形式および数式を拡張する」をOffにして、当該セル、および直上のセル書式を数値にしてやり、再度「データ範囲の形式および数式を拡張する」をOnにしてやるのが早そうです。


PS
早速、直しに行ってきましたが、うまくいきません(;_;) オートSUMのセルの書式を見てみると、「数値」になっていました(@o@) なんだこりゃ?よくよくファイル名を見てみると(自分は拡張子を必ず表示にしてますが、普通の人は表示しないか、登録してあるものは表示しないになってますね)、「*.xls」になっており、どうも2003で最初は作成したもののご様子。うーん、2003のデータを2007/2010で操作すると色々問題が報告されているから、もっと奥が深いかも。結局、「数値だけ」と指定して内容を新しいファイルにコピーして、必要なオートSUMのところだけ手作業で同じ様なファイルを作り直してしまいました。

後から思い返すと、一回2007の形式に変換保存して、上記手順をやってみるという方法もあったな~と思います。おそらくこの機能、2007からだよね。

2014年7月25日金曜日

AndroidStduioを使ってみる

しばらく間があいてしまいました。

Androidプログラムは最近ほとんどしていないんですが、時々ADTの更新(正式にはSDKの更新)はしています。あいかわrずADT本体とのバージョンミスマッチの問題に悩まされます。(ほっといても大抵は動くんですが、warningが気持ち悪い)
少し前に専用の開発IDEとしてAndroidStudioがreleaseされています。見た目、eclipseをやきなおしただけなんじゃない?っていう感じが強いんですが、こっちの方が更新されているようなんで、GoogleとしてはADTよりこっちに力を入れている感じがします。
なので、ちょっと試しに使ってみます。(まだβ0.8ですが、SDKと本体の更新がスムーズにいくようなら、こっちに乗り換えることも考えます)

紹介サイトを見ながら、まずはMacにインストールしてみます。(調子がよければ、Windows/Linuxもこちらに切り替えます)インストール自体は問題なく進みました。そしてサンプルアプリ(よくあるHelloworldです)も問題なく動きます。
ここで実際の実機(今回はgalaxy S2、Android4.0.3で更新は止まっています)での実機デバッグを試してみます。
AVDでシミュレーションするとき、intel版の方が速いという評判でした。実際速いんことは速いんですが、やはり実機にはかないません。(このあたりJavaの限界か)ということで、S2をつないでみると・・・、簡単に動きました。便利なのはメイン画面上でも実機がつながっていることがわかることです。(以下に画面の左下一部を示します)
またADTに比べて、ファイル更新してもすぐ反応して実機に反映してくれる気がします。(eclipse/ADTの時は中々実機アプリに変更が反映されず、よく実機のアプリを手動で削除していました)後、Gitも(Githubももちろん)使えるようですが、ちょっと設定しないといけないようです。
でも、これ昔のADTでGithubに登録したやつはそのままじゃだめだよな〜(ファイル構成が、ADTと似ていてファイル名が異なるといういやらしい作りになっています)
2、3ヶ月ADTとAndroidStudioの様子を見て、Googleがどちらを主力にしたいか様子を見てから考えます。

2014年6月28日土曜日

Kyototycoonを久しぶりにセットアップしてみる

自宅のLinux(Ubuntu)をついに14.04(trusty)にアップしたのを機に、ちょっと久しぶりにKyototycoonをセットアップしてみました。(kyotocabinet-1.2.76 & kyototycoon-0.9.56)
Kyotoって何?という説明は、高速なkey-value型のデータベースだということだけで済ませます。

さてまず上記最新バージョンをDLしてきて、まずはkyotocabinetからです。おきまりの以下のコマンドです。

$ ./configure
$ make

と行こうと思ったんですが、忘れてましたzlib.hがありません。4年前に初めてセットアップしたときはzlibをソースからビルドしましたが、今回はUbuntuのapt-getですませます。

$ sudo apt-get zlib1g-dev

今はubuntu packagesのHPで必要なファイルが入っているpackageを教えてくれますので簡単です。続けて確認です。

$ make check

結構時間がかかりました。(10分くらい?)無事終了してインストールします。

$ sudo make install

/usr/local以下にインストールされました。
続けて、kyototycoonのセットアップに移ります。

$ ./configure
$ make

としたんですが、なんかgetpid()がscopeに見当たらないとエラーがでてきました。ググってみると、どうも"ktdbext.h"に、#include <unistd.h>を追加してやればいいそうです。
おそらく開発してる人は色んなツールを入れていて、知らないうちにデフォルトで入っちゃってるんでしょうね。OSSビルドしてるとたまに、この基本のincludeがないエラーがでてきます。(gccの問題だという報告もありました。includeのネストで何か問題がでるバージョンがあるんですかね。)

さてkyototycoonのビルド、checkも終わり、テストです。試しに以下のコマンドをコンソールから実行します。

$ ktserver kyoto.kch

kyoto.kchというファイルを作成してデータベースを起動するんですが、ここでまたエラーが・・・ libkyototycoon.so.2が見つからないといってきました。/usr/local/libにあるんですが、なぜかライブラリパスの設定がうまくいっていないようです。ということで以下を行います。

$ sudo vi /etc/ld.so.conf/kyoto.conf

ここに、/usr/local/libを入力します。/etc/ld.so.confにも/usr/local/libはセットしてあるんですが、なぜkyotoだとこの設定ファイルを追加しないといけないのかよくわかりませんが。

$ sudo ldconfig

これで設定を有効にしてやればサーバーは無事起動します。
さて今度は別のコンソールでデータの入力、確認をしてみます。

$ ktremotemgr set japan tokyo
$ ktremotemgr set korea seoul
$ ktremotemgr set china beijing

$ ktremotemgr inform

count: 3

size: 6297824

$ ktremotemgr get japan
tokyo

うまくうごきますね。

2014年6月15日日曜日

LibreOfficeのビルド(その3)

さてどうしてもうまくいかなかったMac OSX(Mavericks)でのビルドです。前回までautogen.shの実行中、コンパイラのバージョンチェックでひっかかってました。既存のmac用のオプションではXcode4までの対応だったみたいで、最新のMavricksのXcode5ではだめでしたが、以下のオプションでできました。


$  ./autogen.sh --without-doxygen --without-java --enable-macosx-retina --enable-bogus-pkg-config --with-lang=”ja”

retina用のオプションなんて初めて知りました。でもおかげでビルドができて、テストに進みますが、案の定エラーがでます。本当はよくないんでしょうが、とりあえず動かしてみたいのでテストを無視してビルドするようにします。

$ make build-nocheck

これでテストはパスしてくれます。
instrディレクトリ下にできているパッケージを直接実行してみると、一応動きます。

しかしビルドは時間かかりますね。手元の2.4GHz Core i5, memory 8Gのマシンでも2時間くらいかかりました。

2014年6月1日日曜日

MPFRについて:任意精度数値計算ライブラリ

以前、1億桁のπの計算のためGMPを使いました。しかし、これには四則演算しか存在していなくて、通常の科学計算にはとても使えませんでした。
その後、調べていたらGMPを元に三角関数等をできるようにした、MPFR、MPCがありました。これら3つのライブラリは何とgccをビルドするのに必要なパッケージだとかで(何に使ってるんだ?)、最新のgccを使いたければインストールしておかないといけません。依存関係があり、GMP←MPFR←MPCという感じになるので、その順番にインストールしていかないといけません。大雑把に概要をいうと、以下のようになります。

GMP
 任意精度算術演算ライブラリ

MPFR
 こちらも任意精度の浮動小数点数演算ライブラリ(各種関数あり)

MPC
 複素数演算ライブラリ

MPFRの簡単なサンプルを以下に示します。(これらのライブラリはCなのに注意)


/*                                                                                                     
mpfrの使い方を調べてみる                                                                        
 */

#include <stdio .h>
#include <stdlib .h>
#include <gmp .h>
#include <mpfr .h>

int main()
{
  mpfr_t work;

  mpfr_init2(work, 200);  // 有効桁数200bitで初期化                                                  
  mpfr_set_d(work, 1.0, MPFR_RNDD);  // double変数を代入                                              

  printf("work is ");
  mpfr_out_str(stdout, 10, 10, work, MPFR_RNDD);  // 出力 2個目はn進数での出力指定                   
  // 3個目は何桁出力するか(size_t) '0'を指定すると当該変数の有効桁数すべて出力する                     
  putchar('\n');

  mpfr_const_pi(work, MPFR_RNDD);
  printf("pi is ");
  mpfr_out_str(stdout, 10, 0, work, MPFR_RNDD);
  putchar('\n');

  mpfr_clear(work);  // メモリの解放                                                                   

  return 0;
}

2回目の処理でπをセットしています。当然、任意の桁数を指定できますが、おそらく以前やったようなアルゴリズムで毎度必要な桁数を計算しているんでしょう。
ということは、桁数が大きいとそれに応じて処理時間がかかることになる?ちょっと計測してみました。(マシンはMacBookPro Retinaです。現在の我が家ではこいつが最速マシン)

①πの場合
以下の関数の実行前後でclockを取得し、関数の処理時間を調べてみました。

  gettimeofday( &tb, NULL );
  mpfr_const_pi(work, MPFR_RNDD);  // こいつの時間計測を行う
  gettimeofday( &ta, NULL );

変数workの精度を変えて計測してみました。(それぞれ数回計測し、5msec単位で丸めてます)

100,000bit 15msec
500,000bit 140msec
1,000,000bit 340msec
2,000,000bit 800msec

案の定、桁数と処理時間の関係はリニアではありませんね。

②三角関数の場合(atan)
三角関数(時間のかかりそうなatan)で計測してみました。

  gettimeofday( &tb, NULL );
  mpfr_atan(rslt, work, MPFR_RNDD);  // こいつの時間計測を行う
  gettimeofday( &ta, NULL );

100,000bit 15msec
500,000bit 140msec
1,000,000bit 340msec
2,000,000bit 795msec

う〜ん、ほとんどπと変わりませんね。たまたま演算量が同じ程度だったのかもしれません。
ただ何れにしても通常の倍精度浮動小数点の計算なんかとは比べ物にならないくらいの処理時間がかかっています。こういうライブラリがあるから安易に「100桁の精度で計算してよ」(1桁、約4bit弱必要なので400bitくらいですか)と依頼されても事前に注意しとかないと大変なことになります。
あとプログラム中では"mpfr_t"と変数を定義していますが、この実体はポインタで、必要な桁数のエリアをmallocしてそのポインタを保持しているだけです。従って、この変数自体はthread safeではありません。マルチスレッドのプログラムでこれを使おうって時には注意が必要です。

2014年5月16日金曜日

MacでBoostはどんな感じ!?

昔、Boostを使えるようにLinuxやらMacでビルドしたことがあります。(おそろしく時間がかかりました)
そういえば今の新しいMac(Mavericks)になってからgcc→clangに変わったので、どうやってBoost使えるようにしたものかと思って調べてみました。(c++第4版ではBoostが標準ライブラリになるもんだと思ってましたが、正式には発表されてないみたいだし、そもそも第4版って発効されたんだろうか?でもBoost使いやすくていいと思ってます。)

そうしたらどうも、今のMavericksのXcode5だと素直にはBoostはビルドできないらしい。問題なのはXcode5でインストールされるcコンパイラがclangで、libstdc++-4.2.1(実際、gccのバージョンを調べてみるとこういってきます)のため、4.3以降に実装されたstd::moveがなく、boostは当該関数があるのが前提で作られているらしく、ダメだとのこと。(がんばるなら、libc++をリンクするようにしたり、gccの最新版を別途インストールしないといけない。)

なんでこんなことになったのかというと、gnuがGPL v3を出したのが大元の原因らしい。(確かに数年前、OSSの方ではもめてましたね)gccがGPL v3にしたもんですから、これで仕事している人間たちはもっと縛りの緩いBSDライセンスなLLVM、clangを採用し始めたとのこと。(おかげでclangの開発が急に進みましたが)Linux kernelもv3は批判していて、未だにv2だったはずです。
でもLinux kernelはgccコンパイラでないとビルドできないようなgcc固有の機能を使っています。なんでgccコンパイラがGPL v3なのに、それを使っている(正確にはlibstd++に依存している)Linux Kernelがv2のままで居られるのかと思っていたら、gccのライセンスに抜け道が用意されていたらしく、gccでビルドしたものはv2でもいいよ(意訳)と書いてあるそうです。

さてここで本来のMacのBoostの問題に戻りますが、Macとしては新しいlibstdc++を採用したいが、GPL v3は採用したくない。そのためコンパイラをclangにしましたが、そうなるとlibstdc++-4.3からはGPL v3になるため、これを採用できない。という、風が吹けば桶屋、みたいな状況に陥っているようです。

まあclangの方が頑張ってくれれば問題はなくなるんですが、そもそもc++第4版の決定ってどうなったのよ?以前、c++第4版の決定稿の話を聞いた時は、これでしばらくコンパイラの実装が不安定になるなと悩んでいましたが、事態はそれとは別の方向に悩ましいことになってました。
(Boost関係とか実験するときは、しばらくLinuxでやるしかないようです。)

2014年5月7日水曜日

Raspberry Pi:cronの設定(その2)

さてcronで毎日決まった時間に動くようにしたプログラムですが、うまくいかないものがあります。/var/log/syslogに設定した時間になるとプログラムが起動したと記録は残るのですが、1分くらいすると異常終了しています。
/var/log/syslogを見ると、異常終了したと思われる時間に以下の様なログが残っていました。

May  7 18:46:52 raspberrypi /USR/SBIN/CRON[3380]: (CRON) info (No MTA installed, discarding output)


何かよくわかりませんが、”MTA”って確かメーラーのことだよね?なんかcronが異常をメールで送ろうとした?
調べてみると、Raspberry Piはデフォルトではメーラーが入っておらず、postfixを入れるといいよ、という記事が多くありました。

$ sudo apt-get install postfix

ただ記事を見てると、インターネットで使うための設定(アカウント名、パスワード等)が書いてありますが、こっちはそんな気はありません。上記コマンドで初めてpostfixをインストールすると初期設定が動き出してくれて、そこでlocalを選択できました。(インターネットなんかする気ないよ、ということ)
これで無事、異常終了してたプログラムも何が問題があったかをlocalでメールしてくれて、その続きの処理をしてくれるようになりました。(要は、最初に問題が見つかりメール送ろうとしたけど、それが送れなくて、プロセス自体が止まってしまっていた。問題は単なるワーニング・レベルで、無視してくれればよかった。)

2014年5月6日火曜日

Raspberry Pi:cronの設定

Raspberry Piは電源もたいしてくわなくて、ファンがなくても動作OKです。更にHDDがなくてもLinuxが動作するということで、1日中電源Onにしておくサーバーにするのにもってこいです。ただ外部記憶がmicroSDだけで(自分は32GBを使っています)、ファイルサーバーには使えませんし、CPUも大した性能がなく、Ethernetの口も基本一つしかつていませんから、Firewallにするわけにもいきません。
まあ何に使うかはともかく、電源入れっぱなしのマシンにして何がしかのサービスをさせようと思うと、定期的にプログラムを起動するための設定、crontabをちょっと調べてみました。

自分がcrontabのこと調べてた時は、/etc/crontabに定期的に動かしたコマンドを登録して、crondデーモンを再起動したもんですが、今はだいぶ変わりましたね。(便利になった)

  1. crontabの登録
  2. これは簡単で、以下のコマンドでOKです。
    $ crontab -e
    /etc/crontabはroot権限がないと編集できませんが、今はユーザー毎にcrontabが存在しており、それを自由に登録・削除できます。/etc/crontabはシステムに一つしかないファイルですので、ここにコマンドを登録するときは、当該コマンドを実行するユーザーも設定しないといけませんが、今は個々のユーザーがcrontabを持てるので、、上記コマンドで設定するときはユーザーの設定はいちいち必要ありません。(当然、設定しているユーザー権限で動作しますから)
    尚、editorはデフォルトで"nano"が動きますが、はっきり言ってこれは使いにくい!せめてviかemacsでやりたいところです。crontabの説明を調べると、起動時にどれを使うか問い合わせてくれるとか、後で変更できるとありますが、Raspberry Piではできないようです。従って汎用的な方法として.bashrcに以下の設定を追加します。
    EDITOR=emacs
    export EDITOR

  3. crontabの確認
  4. 以下のコマンドで自分用のcrontabの登録状況を確認できます。
    $ crontab -l

  5. crontabの場所
  6. さて肝心の個々のユーザーのcrontabがどこにあるかですが、以下の場所です。
    /var/spool/cron/crontabs/(ユーザー名)
    というファイル名で保存されています。crond自身は1分程度毎にこのファイルの変更状況を確認しているようで、特にcrondを再起動しなくても変更は反映されます。(そもそもcrontabは分単位でしかプログラム動作を設定できないので、これで十分です)
注意として、実行したいコマンド(特に自分で作成したプログラム)、ファイル等を指定するとき、なるべくフルパスで行った方が安全です。cronで当該コマンドが実行される時の環境(動いている時のカレントパスがどこなのか等)がよくわからないので、できるだけ依存性がないようにしておくべきです。

追記:
なぜcrontabの設定なんか調べていたかというと、Raspberry Piをネットラジオの録音サーバー(特定の番組を予約録音して、結果をmp3ファイルにする)にしたてようと目論んでいるんです。crontabで留守録音の登録をしてみて、うまくいきました。某サイトに録音スクリプトが公開されていたので(注:著作権的にグレーな気がしますので、詳しい場所は伏せておきます。探せばすぐに見つかります。)、それを使いましたが、以下のパッケージが必要で、apt-get installですべてインストールしました。
swftools
rtmpdump
libxml
wget
ffmpeg
lame
ちょっと困ったのが、1時間ほどの録音をした後、mp3変換にffmpegが動いているのですが、これが40分くらいかかってしまいました。サイズも56MBと結構なサイズになりました。とりあえず原理的には動くことがわかったので、ブラウザで録音設定ができるようなフロントエンドや、録音データを簡単にタブレットに転送できるような方法を考えないと。

2014年5月2日金曜日

Coin 3D:現状とビルド

Coin 3Dってご存知でしょうか?3DのGraphics Libraryですが、20年位前その分野で有名だったのがSGIというコンピュータ会社でした。そこが今では業界標準になっているOpenGL(大胆にも、GLはGraphics Libraryの略です)を作り、更により上位のライブラリとしてOpenInventorを作りました。(Inventorは1995年くらいだったかな?)
当時のSGIは非常にバカ高いWS(Work Station)を販売しており、そこでしかOpenInventorは使えませんでした。そのとき、有志で互換のライブラリを作ろうと出てきたのがCoinでした。(皆、興味がなくなったのかぐぐっても、情報がないですね。)

1.概要
2009年頃書いていたブログ(今とは別の所で書いてました)にその当時のCoinの状況を書いてました。
SGIの経営が2000年を越えてしばらくしてから怪しくなり、Inventorの権利を別会社に販売したり、OpenInventorと命名して(Openを頭文字に入れた)、ソースを公開していました。(2005年くらいだったかな。OpenInventor2.1.5が最後に公開されたソースコードで、当時RedHat9でビルドができました。)
結局SGIは3Dグラフィクス分野からは手を引き(日本SGIに確かその分野を譲渡し、NECが資本を注入してました。)、完全にOpenInventorのソースコードが中に浮いてしまった状態になりました。(その前にInventorのライセンスを買った会社は今でもOpenInventorのメンテナンス、といっても新しいプラットフォームへの対応、バグとり程度しかしてませんが、これがまた高い!こちらのソースコードは非公開なので、全く独立にメンテされています)
2009年の2、3年前にCoinがフリーになったOpenInventorのソースコードを使うことの許可をSGIに得て(それまではAPI定義だけを元に、独自の実装をしていた)、メンテナンスを行うという発表を見た記憶がありました。その後、2009年に調べてみたら、なんかCoin 3Dがどこかの会社(資源探査会社?)に買い取られ、Qtのようなダブルライセンスになっていました。当時、CentOS5でビルドしてみましたが、あっさりビルドできて動いた記憶があります。(ただ見た目がまだかなり、本物のOpenInventorとは違っているところがありました。はっきりいって「いけてない」感じのデザインでした。)

さて2014年現在ですが、なんとCoin3Dはその会社が放棄していました!!(2012年)商売にならないと判断されたのでしょう、現在では一部の有志だけで公開されているようです。(JIRAで有名なAtlassianが行っているSourceForgeのようなサービスでプロジェクトを公開していました。リポジトリはgitではなく、Mercurialを使っていました。そこではwikiサービスも行っており、JIRAのようなタスク管理も動いていましたが、活動があまり活発ではありませんでした。)
従って、ソースコードも2012年から更新されていないようです。

2.Coin 3Dのビルド
さて現状のバージョンはCoin-3.1.3となっています。これをDLしてきて、以下の環境でビルドしてみます。

・Ubuntu 13.10
・g++-4.8.1

(1)configureでのエラー
何も考えずに、no-optionでconfigureすると以下のエラーがでて、configureができなかった。cc_debugerror_post()の関数定義で、先行定義してあるデバッグ用関数において、gcc-4.7以降ではtemplateの解釈が変わったらしく、namespaceの範囲解釈が変わり問題がでるようになった。
 元々、trickyな定義がしてあったらしい。解決方法が見つからないので、debugをスルーするようにした。

$ configure --disable-debug

これで当該エラーはでなくなり、ビルドができるようになった。

(2)g++のバグ
ビルドをしてみると、以下のエラーがでた。

In file included from ../../../Coin-3.1.3/src/base/dict.h:31:0,
from ../../../Coin-3.1.3/src/fonts/freetype.cpp:142:
/usr/include/c++/4.8/cstdlib: In function ‘long long int std::abs(long long int)’:
/usr/include/c++/4.8/cstdlib:174:20: error: declaration of C function ‘long long int std::abs(long long int)’ conflicts with
abs(long long __x) { return __builtin_llabs (__x); }
^
/usr/include/c++/4.8/cstdlib:166:3: error: previous declaration ‘long int std::abs(long int)’ here
abs(long __i) { return __builtin_labs(__i); }


どうもabs()関数の多重定義に関するエラーらしい。ただ問題が、abs()関数を使うところではなく、abs()関数をinline定義しているcstdlibをincludeしているところで発生しているため、どう対処したらいいのかがわからない。

英語でぐぐってみたら、gcc-4.8のバグで、cstdlib(c++用)がstdlib.h(c用)を含めてマクロ定義を多重に読み込むのを防ぐときのバグらしい。(cで書かれたプログラムをc++で流用するときが多分にあり、そのとき両方がincludeされることが多々発生するが、同じマクロ定義が行われていることが多い。その問題を解決するのにg++側でバグがでているっぽい)
別のプロジェクトのブログに解決法として、両方includeしているようならcstdlibをやめろ(stdlib.hだけにしろ)というのがあったので、ソースを一部修正してみると、ビルドが先に進んだ。
(src/base/dict.h:31  cstdlibのincludeをコメントアウトした)

(3)namespace指定の問題
更にビルドが進むと、以下のエラーがでた。

g++ -DHAVE_CONFIG_H -I../../include -I../../../Coin-3.1.3/include -I../../src -I../../../Coin-3.1.3/src -D_REENTRANT -DNDEBUG -DCOIN_DEBUG=0 -DCOIN_INTERNAL -g -O2 -W -Wall -Wno-unused -Wno-multichar -Woverloaded-virtual -MT glyph.lo -MD -MP -MF .deps/glyph.Tpo -c ../../../Coin-3.1.3/src/fonts/glyph.cpp -fPIC -DPIC -o .libs/glyph.o
../../../Coin-3.1.3/src/fonts/glyph.cpp:41:12: error: ‘std::free’ has not been declared
using std::free;


std::freeというnamespaceがg++-4.8にはないらしい。とりあえずコメントアウトしてみる。

 free()はstdlib.h内に定義してあるが、includeしてないせずにnamespaceの定義だけでエラーを逃げようとしたらしい。他にもmallocでも別の近い箇所でエラーでる。
どうも(2)で述べた、stdlib.hとcstdlibの多重includeで問題がおきて、一部ソースではstdlib.hをincludeするのをやめ、using std::freeとかのnamespace定義で逃げようとしたらしいが、それが問題になったらしい。(先に、cstdlibのincludeをコメントアウトしたせいか?)

 かわりに#include <stdlib.h>してやれば先に進んだ。
結果として、これでビルドはパスし、make installができた。(/usr/local以下にヘッダ、ライブラリはインストールされた)


3.サンプルプログラムの作成
さて実際にビルドが成功したかを確認するために、サンプルプログラムとして、Inventor mentorの最初にある、Red Coneをコンパイルしてみます。
しかし、これだけではビルドができません。よく見たら、Coin-3.1.3のtarボールにあるのはOpenInventor本体だけであり、それをwindow上に表示するためのSoXt(WindowsならSoWin等)がありません。Coin3DのHPに別途、SoXt-1.3.0があり、それをインストールする必要があります。

(1)configureでのエラー
何も考えずにconfigureすると、Coinと同じようにcc_debugerror_post()の関数定義でエラーがでました。同じように、--dsiable-debugオプションで逃げます。

(2)実行時にエラーがでる
これでSoXtのビルドは成功、インストールできました。しかしサンプルプログラムを実行すると以下のエラーがでます。

Coin error in SoXtGLWidget::buildWidget(): SoXt does not support detecting best visual/colormap without the Xmu library (yet)

よくわかりませんが、ビルド環境を調べてみるとXmuのランタイムは入っていますが、開発環境(libxmu-dev)までは入ってませんでした。試しにインストールしてSoXtを再ビルドしてみましたが、状況はかわりません。

このエラーを出している箇所を調べてみると、場所は、SoXtGLWidget.cpp:1064らしい。

#ifndef HAVE_LIBXMU
SoDebugError::post("SoXtGLWidget::buildWidget",
"SoXt does not support detecting best visual/colormap without the Xmu library (yet)");
exit(1);
#else // HAVE_LIBXMU


内容的には、Xmuライブラリを持っていなかったらとのフラグでここに入っているが、当該環境にはXmuライブラリはインストール済みである。configureに問題があるらしい。
config.logを見ると、環境調査の中で以下の箇所で問題がでていた。

configure:22291: g++ -o conftest -g -O2 -W -Wall -Wno-unused -Wno-multichar -Woverloaded-virtual\
  -DNDEBUG -DSOXT_DEBUG=0 -DSOXT_INTERNAL      conftest.cpp -lXmu -lXext  -lSM -lICE -lX11  -ldl\
  >&5
conftest.cpp:31:41: fatal error: X11/Xmu/Xmu.h: No such file or directory
                 #include <X11/Xmu/Xmu.h>
                                         ^
compilation terminated.

おそらくこのエラーのせいで、Xmuライブラリが環境に存在しないと判断されたらしい。しかしなぜこんなエラーが出てくるのか不明。(当環境には、当該位置にXmuは入っている)
再度、通常のターミナルでSoXtをmakeし直しました。(前回はおそらくemacs内のshellで行っている。通常、ログをあとで確認するためよくemacs内のshellでビルドをしているくせがついている。)
するとXmu関係のエラーがconfig.log内にでなくなり、SoXtを再インストールしたら動きました!


4.サンプルプログラムの実行
2個ほど、実行結果を示します。

(1) HelloCone
まずはmentorの最初にでてくる一番シンプルなものです。

画面の真ん中に、赤い3角錐が表示されるだけです。

(2)ExaminarViewerの実装
最初のCoinにはまだ実装がなかったんですが、OpenInventorではとても便利なViewerだったExaminar Viewerです。

ぱっと見、大して変わらないように見えますが、このViewerではマウスで表示中のモデルを自由に視点を回したり、拡大/縮小ができます。右端の一文字のボタンが何か昔のSGIの実装とは違いますが(確かアイコンで機能が表示されていたはずなんですが、一文字になってますね)、とりあえず動作には問題がありません。

と、まあ一応は動くようです。(g++周りの実装が変わったことによるエラーには少し悩みました。昨年末、やっとc++第4版の仕様が確定したらしいという話を聞いたせいか、多少実装に変更があったようです。)

Ubuntuも14.04LTSが発表されたところで、今の環境だと「アップデートするか?」と毎回聞かれますが、こんな時にg++のバージョンが変わってしまったら訳がわからなくなりますから、そのままにしてあります。

2014年4月20日日曜日

データ・ロギング・システムの検討(socket::send関数の戻り値について)

半年ほど前にちょっと検討したことがあります。
その時わかったこととして、socketの処理時間(特に受信時間?)が随分かかるのと、ファイルキャッシュが強力で、受信する方はかなりの容量受信してしまうが、本格的にプログラムを作って動かしたときの挙動が心配なことがわかったところで、そのまま放置していました。(特にまだ切羽詰まった必要性がなかったもんで)

なんとなくsocketまわりのコードを見ていたら、ちょっとsend関数の挙動について気になることがでてきました。
send関数のman見ると、以下の説明がでてきます。

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

これまでリターンでは"-1"しか気にしてませんでしたが、よくみると「送信できたバイト数を返す」とあります。
これって”必ずしも要求した送信データをすべて1回のAPIコールでは送信しきれないこともあるよ”っていうことです。これまで経験したことないんですが、ここで考えているようなsocket通信に負荷が高いことをやろうとする場合は考えとかないといけないんじゃない?と気づきました。そこんところ注意するなら、以下のようにコーディングすべきです。

while (送信したいバイト数 > 0) {
  送信済バイト数 = send(  );
  送信したいバイト数 -= 送信済バイト数
}

みたいな感じでwhile-loopを組むべきです。
しかし更に問題として、ここでそもそも「一度に送信できない状況って何?」ということがあります。
このsocketが実装された当時は単純にCPUの処理速度やらまわりのHWの性能が遅くて、途中でも制御を返すようにしていたと考えられますが、現在の様にHWの性能が格段に進歩していて、それでも要求されたバイト数を送りきれない、としたら以下の状況が考えられます。

  1. 送信側のバッファが一杯になった
  2. 上記が起きる原因として、受信側の処理が間に合わなくなりAckを十分返しきれてない

従って、単純にwhile-loopで待ってても大丈夫なのか?ということになります。それにあまりsend()で負荷をかけるとkernelが不機嫌になる(暴走する)ことも起きそうで、そうなるとsend自体がerrorで返されることも考えられます。

そもそもデータ・ロギング・システムを作ろうと考えたとき、ロギングデータの抜けを許すか?ということを頭から考えてませんでした。抜けを許さない状況なら、エラーに対処するコード(sendがerrorを返したときの復旧コード)を考えるだけ無駄です。実際、現状自分が考えている用途は試験データの収集を想定しており、途中でログ・データの抜けがあったら試験失敗になり、再試験となります。従ってエラーがでない限りのロギング可能なデータ量が事前にわかっている必要があります。

とりあえず、sendの戻り値は監視するようにしとかないといけませんね。(現状は、エラーの"-1"しかチェックしないことがほとんどです)
もし送りきれない状況が起きたら、システムとしてロギング可能量をオーバーしたのか見極めないと。

あと、現状Webサーバー等でこの種の大量のデータをSocketで送受信しているシステムだと、CPU負荷の問題でもこのような送信不可の状況が一時的に発生することが考えられます。そういうシステムの場合は、抜けが発生したらそれはいさぎよく諦めて再送信してね、という対応になるでしょうから、上記while-loop内に更にtime-outに関する実装も必要になってくるでしょう。

2014年4月17日木曜日

Mac Book Pro(Retina) sleepから起きるときに暴走する(ことがある)

表題の通りなんですが、今年の1月に購入したMacBook Pro Retina 13'によく外部ディスプレイをthunderboltアダプター経由つないで使っていると、しばらく操作していなくて画面がsleep(AC powerで動かしています)したときに起こそうとすると、暴走することが時々あります。(レインボーのアイコンが回りっぱなし、CPUファンも全力になります。当然、マウスの動きも遅く、何か操作しようにもなかなか反応しなくなります。)
なんとか「アクティビティモニタ」を起動し、動いているプロセスを確認すると、kernelが暴走しているようです。シャットダウンもできません。(がんばって時間をかければメニューから選択できるのかもしれませんが・・・・)

どうにも具合が悪く、色々調べていましたが、自分の状況に近い書き込みを見つけました。症状は、外部ディスプレイを接続時にkernelが暴走することがあるとのことで、原因はInsomniaTというアプリのバグだということです。ただ自分のMacには入れた覚えがなく、何のアプリか見てみると、MacBookProで画面がSleepしても、CPUをSleepさせない(バックグラウンドで動かしているアプリを動かし続ける)ツールとのことです。しかも、kernel-pluginで実装してあるとか・・・ちょっとヤバげなツールです。

しかし自分のにはインストールしてませんし、念のため手動でアンインストールする手順があったので調べても、やはり使ってません。しかし症状は同じ感じなんですよね。
そんなときはApple Hardware Testを使って、ハードウェアに問題がないか確認しろという意見がありました。故障というのも困るので念のためやっておきます。手順は以下の通りです。(Appleのサポートページ内にあります)
→2013年6月以降発売のMacの場合はAHTではなくApple Diagnosticと名称が変わっていました。画面もSSと同じでした。

  1. 電源ボタンを押してコンピュータを起動する。
  2. グレイの起動画面が表示される前に「D」キーを押したままにする。
  3. AHTが起動しハードウェア構成を検査するまでに約1分かかる。検査の実行中はアイコンが画面に表示される。
  4. プロセスが完了したら言語を選択して「return」キーを押す。
  5. AHTコンソールが表示され実施するテストを選択する。
  6. AHTを終了するにはウインドウの下部にある「再起動」もしくは「システム終了」をクリックする。

ただ、自分のMavericksが最初から入ったMacでは3.のところでアイコンがでませんでした。しかもいきなり4.の言語選択画面になり、(スクリーンキャプチャは動かないだろうからデジカメで撮りました。ピンボケですみません。)

(ピントがあってませんが、左上2個目が日本語です)
言語を選択するとテストの実行に入りました。(「検査中」と表示されたんですが、多分テストだよね?)


(約2分という表示で、バーがだんだん伸びていきます)
ちょっと動きが違いますが、とにかく異常はでてきませんでした。

(診断結果で、異常なしとでてきました)

Macのシステム環境設定→省電力のところを確認すると、デフォルトではAC powerで動かしていても画面がSleepするとCPUもSleepしてしまうようです。試しにこれを外し、AC powerのときは画面がSleepしてもCPUはSleepしないようにしてしばらく使ってみます。

2014年4月12日土曜日

Raspberry Pi 監視カメラの実験

昨秋、カメラモジュールを買ってから少し試しただけでそのままにしてましたが、ちょっと監視カメラの実験をしてみました。

やることは単純で、

  1. 静止画撮影コマンドをプログラムで定期的に起動
  2. ffmpegで動画にする

これだけです。

1.プログラム作成
色々試しながらやるのでpythonにて作成してみました。30秒毎に1枚、1時間記録してみます。(最初はキャプチャした時間をファイル名にするようにしてましたが、それだと動画にするのが大変だったので単純にカウンタにしました。)

capture.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import threading
import time
import datetime
import subprocess

# 画像保存エリア
cabstr = 'Cab/'

class test(threading.Thread):
    def __init__(self, idx):
        threading.Thread.__init__(self)
        self.setDaemon(True)
        self.i = idx

    # captureに10秒くらいかかるので連続呼び出しには注意!
    def run(self):
        # print "Start."
        # 日時を表す文字列の生成
        # filename = datetime.datetime.now().strftime(u'%Y%m%d%H%M%S') + '.jpg'
        # print filename
        # 0埋め、後ろから4文字とる
        filename = ("00000000" + str(self.i))[-4:]
        # カメラでのキャプチャコマンド(640x400)
        cmd = 'raspistill -w 640 -h 400 -o ' + cabstr + filename + '.jpg'
        # cmd = 'ls -F'
        subprocess.call(cmd, shell=True)

if __name__ == "__main__":
#    t = test()

    for loop in range(120):
        t = test( loop )
        t.start()
        time.sleep(30)


24H動かすなら、本当はキャプチャしたファイルを転送することも考えないといけないんですが、そこまで本格的なことはとりあえず考えてないので、Raspberry Pi本体のSDに記録です。(32GBをのせてます)メモリを喰いたくないのと、それほど詳細な画像も必要ないので、640x400でキャプチャしてみました。
ちょっと注意が必要なのが、プログラムでは静止画キャプチャ(スレッド)を30秒毎(正確にはスレッド起動時間分だけだんだん遅れていくんですが)に起動しています。キャプチャにはRaspberry Piが提供しているコマンドをそのまま使っていますが、これが結構時間がかかります。(数秒くらい。下手すると10秒近いこともある。)最初、「5秒間隔で試すか」とやってみたら、なんかmmalエラーとかでてきて意味が分かりませんでした。(ぐぐっても関連するのはヒットしませんでした)
これ、raspistillコマンド実行中に別スレッドが起動して更にraspistillコマンドを実行するとリソースの衝突が起きていることを示しているエラーのようです。スレッドの起動間隔を10秒以上にしたらエラーがでなくなり、うまく動くようになりました。

2.動画にする
ここはffmpegのコマンドで静止画を動画にするだけです。(さすがにこれは別PCのUbuntuでやりました)

$ ffmpeg -r 2 -i %04d.jpg -vcodec mjpeg  out.mp4

(Ubuntuでは最近"avconv"に変わったとも聞きましたが、両方入ってました。2枚/秒のレートで動画にしてみました。(1時間分を1分の動画に短縮することになります)「-vcodec」オプションが怪しい気がしますが、とりあえずこれで変換できたようです。)


3.おまけ
今回はリモートログインしたままで実行しましたが、実際に長時間監視するときはそうもいきません。バックグラウンドで動かして、ログアウトしたくなります。そんなときは以下のようになります。

$ nohup ./capture.py &




2014年3月30日日曜日

vagrant覚書

あちこちで仮想環境構築ツールのvagrantについて書かれてますが、操作コマンドと実際のデータファイルの関係を調べたので記録しておく。(応用きかせようとするとき、実際の仮想マシンのディスク等がどうなっているか理解しておいた方がいいので)

仮想マシンは昔からつきあっていますが(この世界では有名なVMwareが1.5の時から使っていました。当時英語のHPを一生懸命読んで、DL販売で購入しました。)、色々な実験をするときいちいちPCを準備しなくてもいいので重宝してました。しかし仮想マシンの構築はそれなりの手間がかかり、慣れてない環境を構築しようとして失敗したときなどは、再度仮想マシンの構築からやった方が早い時が多く、大変でした。(仮想マシンのディスクイメージのsnapshotや、コピーを保存しておいたりして、再構築しなくてもいいようにしましたがGB単位のデータ量になるのでコピーだけでも結構時間がかかります。)その点vagrantだとテンプレートがあればコマンド一発で仮想マシンのセットアップをしてくれるので、心置きなく環境構築を試すことができます。(といっても基本GUIなしの環境ですが)一通り手順と、よく使うコマンドの簡単な説明一覧を示しておきます。

1.Virtual Boxをインストールする
(個人的にはVirtual Boxにはあまり良いイメージは持ってません。発表当時はVMwareに比べて実行速度がかなり遅く、すぐに使わなくなってしまいました。今回改めて使ってみましたが、随分早くなったな〜という感じです。vagrantが基本的にVirtual Boxのテンプレートが多いので、こちらでいきます。)

2.vagrantをインストールする

3.テンプレートの準備
vagrant box add (テンプレート名) (URL) ;仮想マシンのテンプレートを取得する(今後、引数のテンプレート名で操作する)
list ;システムにインストールしてあるテンプレートの一覧
remove (テンプレート名) ;テンプレートの削除

4.仮想マシンの構築(仮想マシンの設定ファイル:Vagrantfileの場所で下記のコマンドを実行)
vagrant init (テンプレート名) ;vagrantの初期化(Vagrantfileの作成)
up ;仮想マシンの起動
ssh ;仮想マシンと接続
status ;仮想マシンの状態
suspend ;実行中の仮想マシンの一旦停止
resume ;一旦停止した仮想マシンの実行
status ;仮想マシンの状態
reload ;仮想マシンの再起動
halt ;仮想マシンの停止
destroy ;仮想マシンの削除(Virtual Box上の仮想マシンが削除される)

5.テンプレート・データの保存場所
~/.vagrand.d/boxes/(テンプレート名)
基本的にはvirtual boxの仮想ディスクイメージが入っている

6.vagrant設定ファイル
~/(任意)/Vagrantfile
仮想マシンの起動等を行う場所、任意のパス名を自分で設定する。
initコマンドにより作成される。

7.Virtual Boxの仮想マシン
~/VirtualBox VMs/(仮想マシン名)
初回のupコマンドで作成される。
vagrant設定ファイルのパス名を頭文字として、仮想マシン名は作成される。
vagrant設定ファイル毎に仮想マシンの実体は作成されるので、一つのテンプレートから複数の仮想マシンを作成・実行できる。

今回、UbuntuとMacの両方でvagrantを試してみましたが、全く同じような動作をしてくれました。(Rubyベースで作成されているとのことですが、それでも異なるOSで同じように動いてくれるというのはなかなか無いことです。)
仮想マシンの作成/起動は、5.、6.、7.の順番に行われますが、それぞれのコマンドで作成されるデータ、およびその関係を下図に示します。

説明を聞いて、最初の1個の仮想マシンを起動するまではなんとなくわかった気になるんですが、いざ複数の仮想マシンを起動したい、同じテンプレートで複数の仮想マシンを動かしたい、と考えたときどうなるんだろうと思い、データがどこに保存されているかまとめてみました。
従って、調子にのって多数の仮想マシン、テンプレートを作ると、~/.vagrant.d/以下、~/VirtualBox VMs/以下のHDD容量が大変なことになりますので注意しないといけません。

後、使っていて気づいたんですが、CentOSのテンプレートから作成した仮想マシンにおいて外部へのポートが閉じた設定(今のクライアント指向のデストロはこれが基本です)のままテンプレートが作成されていたものがありました。そのため$ vagrant sshで仮想マシンに接続はできますが、ping等まったく通らず、サーバーの実験をしようと思う時、ちょっと面倒くさいです。(逆に、vagrant sshはどうやって接続しているんだろう?と思ってしまいます。)

PS.
上記、仮想マシンの外部との接続ですが、その後CentOSでも設定でpublic_networkを一度有効にして新しいethのルート(仮想マシンに対するネットワークデバイス?)を設定してくるか聞いてきた時、有効にしたら仮想マシン上で新しいeth1が認識されるようになり、CentOSでも外部からのpingに応答するようになりました。(これは複数のEther HWがMacにあったためのようです。Ubuntuでは聞かれませんでした。)
その後はpublic_networkを無効にしても外部(host PC)からのpingは通るようになったままになりました。Virtual Boxのネットワークデバイス周りの設定を変更してしまったようです。