2013年12月10日火曜日

Javaによる画像入出力プログラム

ちょっとWindowsの画面をキャプチャする機能が欲しくなったんで、調べてみたんですが、、、、いろんな関数があって大変(;゜ロ゜)
手動でやれば簡単なんですが、枚数があるもんですからプログラムと思ったんですけどね。しばし考えて、「Javaにも同じような機能あるんじゃない?」調べたらありました。しかも非常に簡単です。

キャプチャ自体は以下の関数になります。

// 指定領域をキャプチャしてスクリーンショットのBufferedImageを返す createScreenCapture(Rectangle screenRect);

それで簡単に画面の一部(左上の512x512)をファイルに保存するものを作ってみました。

import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class test {

 /**
  * @param args
  */
 public static void main(String[] args) {

  // スクリーンキャプチャのテスト
  Robot r =null;
  try {
   r = new Robot();
  } catch (Exception e){
   System.out.println("can't get Robot");
  }

  BufferedImage dd = r.createScreenCapture(new Rectangle(0, 0, 512, 512));

  // jpgで保存
  try {
   File savedImage = new File("sss.jpg");
   ImageIO.write(dd, "jpg", savedImage);
  } catch (Exception e) {
   System.out.println("can't write file");
  }

 }

}

このプログラムはファイルを作成するだけですが、読み込むときは以下の通りになります。

BufferedImage img = ImageIO.read(File);

後は、BufferedImageで適当に調べればpixel単位の操作も簡単にできます。


PS:
あ、念のためいっときますが、これはローカルでjavaを動かして自分のPCの画面をキャプチャしたい目的で調べました。(ですからローカルに画像ファイルを保存しちゃってますし)リモートでこれ実行したらどうなるんでしょうねえ?セキュリティにひっかかるかな。(それにBufferedImageデータをどうやって返信するんだという問題がありますが。取得したイメージデータを返信する方法がなければゲームなんかで使えるテクニックなんですが。)

Nexus7 KitKat更新

少し前にNexus7のOSが4.4(KitKat)に更新されました。最初は、動きがいい、電池の持ちがよくなったと喜んでいたんですが、どうも動作におかしなところが目立つようになってきました。


  1. 画面の回転が遅い。センサへの問い合わせをアプリごとにするんじゃなくOS側でまとめてやるようにして、電力消費を減らしたとはききましたが、アプリによっては中々回転したのを反応してくれないものがでてきました。
  2. WiFiがなかなかつながらない。これは家が1階、2階と別々の親機を設置しているせいもあるかもしれませんが、電源On直後などなかなかWiFiを認識してくれないことがあります。
  3. WiFiの接続キーを忘れる。これが一番困ります。WPSで簡単に接続設定はできますが、何らかの関係でWiFiのAPリストから消えると、接続キーも忘れてしまうようです。数回設定しなおしました。

昨夜、VerUpの連絡が来ていました。(4.4.2へ更新です)セキュリティ強化が主眼のようですが、使いがってはどうでしょう。

2013年12月2日月曜日

3Dモデルの表示がしたい:WebGL編

少し前までAndroidでのOpenGLプログラムやら、Blenderからのモデル出力を調べていました。目的は3Dモデルを表示するのに楽な方法は現状だとなんだろうと試行錯誤していたわけです。
昔はc++なんかでガリガリViewerプログラムをInventorなんかつかったりして作っていたんです。Inventor自体は好きなんですが、肝心のSGIがどうもダメダメ(今ではGraphicsは完全に撤退して、スーパーコンピューティングの会社になってしまってます。唯一Graphicsの部門をNECに売却して日本SGIとして細々とやっているくらいですか。。。)で、Inventorを使い続けるのに不安をずっと感じていたんです。仕事でやるならもう自分でViewerは作りません、できあいの製品かってきます。その方が安心です。

ただそれでもどうしても特注のカスタマイズしたViewerが欲しい場合どうしたらいいか?と考えて、様子を見てたんですが、どうも結局OpenGLでガリガリ書くのが時流のような気がします。それでまあ、特注で必要になるとすると今時のタブレット用アプリくらいかとAndroidを見てたんですが、やはりOpenGLをガリガリするのは疲れます。何より、モデルデータの読み込みを自分で用意しないといけないのがしんどいです。そこでモデルデータ作成にBlenderを調べて、今度はモデルデータのエクスポートから表示方法を考えていました。
実は前から気になっていた技術に「WebGL」があります。JavaにもOpenGLの実装がありますが、それをブラウザのJavaScriptでやってしまおうというものです。可能性を非常に感じていたんですがいかんせん「重い!」に当時はつきました。ブラウザを使うPC性能(正確にはGraphicsボードの性能になります)に依存しますし、それでも素でアプリから動かすより数倍重く感じました。(昔々、SGIが同じような考えでVRMLというのを考えてましたが、結局今じゃ聞かなくなってしまいましたね)その後、セキュリティ上の問題がJavaScriptおよびWebGLの両方に見つかり、一時停滞したようですが、また最近記事がでるようになり、JavaScript用のライブラリもScene.jsとかThree.jsとかさかんにでてくるようになりました。ところで現状WebGLが使えるのは、以下のブラウザだけとのことです。

  • Chrome
  • FireFox
  • Safari
  • Opera(機能限定らしい)
  • IE11(やっとMSも実装したらしいけど、どの程度の実力かは不明)


そんなところで、ChromeとFireFoxを使いながらThree.jsで様子を見てみることにしました。(理由は、BlenderからモデルデータをThree.jsが読み込める形式にする方法があるから)ところがこれが非常に難航しました。まずWebの記事のようにThree.jsが動かない。(表示がおかしい)これの原因究明にかなり時間がかかりましたが、大体わかってきたのでメモしておきます。(利用したブラウザはChromeとFireFoxです)

1.簡単なサンプルしか表示されない
簡単な立方体を表示するJavaScriptのプログラムは問題なく動きました。

ところが、これにjpegのテクスチャを張ろうとすると、、、
何コレ?っていう感じですが、本当は以下の様に表示される(予定)ものです。
(これはその後、試行錯誤の結果表示できるようになったものです)
球体に、地球表面のjpegを用意してそれをテクスチャとして貼り付けているはず、なんですがうまくいきません。

2.ChromeとFireFoxで挙動が違う
上記の地球のサンプルですが、実はFireFoxだとうまく表示できるんです。Chromeはだめ。ブラウザの開発コンソールを見ても特にエラーは返してこないし、なんでだ!?と悩みましたが、確かJavaScriptのセキュリティ問題で、ローカルなファイルはJavaScriptでは読めないようにしたのを思い出しました。(IEは、今更そんな制限つけれるかという感じのようですが)FireFoxも緩いようですが、テクスチャとしての読み込みだけは許可してくれたようです。(注:WebGLはさらにメモリリークの問題も発生していたため、Chromeではテクスチャデータだろうがローカルからの読み込みを禁止しているんでしょうね)

Three.jsのサンプルにテクスチャを貼ったものがありますが、Chromeだと全滅ですね。FireFoxじゃないとローカルな環境ではまともに表示してくれません。

3.Blenderのモデルデータを読み込んでくれない
さあここまでくれば問題はあきらかです。肝心のBlenderのモデルデータファイルを読みこもうとするとChromeやらの開発コンソールに明確に、ローカルファイルは読み込めませんといってきます。(正確にはローカルなファイルを指定するfile://というURLでは不正と判断され、http経由じゃなきゃだめ、みたいな感じ)
これにはまいりました。Webで見つかった記事には一言もそんなこと書いていてくれません。あきらめてLinuxマシンにapache2をインストールしましたよ。(設定はデフォルトのまま。特に外部のPCから見たいわけではないんで。URLはhttp:://localhostで参照できれば十分です。)そうしたら無事表示されました。(基本、ローカルでしか使いません。ローカルなファイル見るのにapache経由というのも変な感じがしますが、そうしないとセキュリティをクリアできない!)
何表示してるの?って感じですが、まずBlenderでモデル作成したとき、XYZ軸の+方向がどう表示されるのか確認しないといけなかったので、Blenderで四角すいを3つ、XYZ軸(RGB)方向に作成した(ついでに各四角すいはそれぞれの軸の色にしてあります)モデルデータを表示してみたものです。(下図のモデルを出力したものです)

WebGLには軸表示としてHelperを使っています。なんかX軸(R)で90度回転してますね・・・
ところで、Three.jsのGitHubにあるエクスポートスクリプト(python)はBlender2.66用です。自分は現状最新の2.69を使っており、これが表示されない原因かとも一時思いました。しかし、結果的にはBlender2.66だろうが、2.69だろうがエクスポートされるファイル(JSON形式です)は同じものでした。Blenderを両方インストールして確認してみました。モデルがもっと複雑になると違ってくるかもしれませんが。

3.5 Blenderモデルのエクスポートオプション
上述の結果は、Blenderにてthree.js用にモデルデータをエクスポートするさい、デフォルト設定で行ったものです。改めてオプションを見てみたら、座標軸を変換するオプションがありました。
下部の「Flip YZ」がデフォルトではオンになっていますが、これをオフにして出力してみると、以下のようになりました。
XYZ(RGB)軸がきちんと同じ方向に表示されるようになりました。しかし、なんでこんなオプションがあるんだか…


色々試行錯誤して、「Blnederで作成したモデルデータをWebGLで表示する」という目的は達成できました。ついでにかなりまだクセが強いのも理解できましたが。(最後のモデルが回転してしまう、というのはよくある話なんで、理解できてればそんなに苦にはなりません。)

結局、Three.jsに多数格納されているexampleですが、テクスチャ関係使っているものはFireFoxでないとローカル環境だけでは見れません。apache動かして、http経由で見ればChromeでも見ることができます。(逆にいうと、これ気づかないと大多数の人が「Three.jsってこんな表現しかできないのか」と勘違いしてしまいそうです。

2013年11月22日金曜日

Windows, Mac, Linux共通のエディタが欲しい:Windowsのsublime text2その後

結局、色々やってるうちに知らないうちに画面表示までくずれていることに気づき、あきらめて再インストールすることにしました。


  1. sublime text2のアンストール
  2. python 3.xのアンインストール
python 3.xを入れていたのは、Blender2.69がpython 3.xを推奨していたからですが、同時にインストールしていたLinuxの方はpython 2.xなんですが特にBlenderの動作に問題は見られないし、Blenderのサイトをよく読むと、推奨はするけどまだpython 3.xでは動かないplug-inがあるよ、と必須ではないようです。(特にpython入ってなくても、手動操作でBlender動かすだけならそんなに問題ないようす)
次に再度インストールです。


  1. python 2.xのインストール(2.7.6にしました)
  2. sublime text2のインストール
さあこれで再度パッケージとか入れなおしていけばいいだろうと思いきや、画面が変です。例によってwindowの最下段に情報表示がされていないし、Tabのファイル名表示もおかしい。おまけになぜかまだパッケージのインストールをしていないのに、日本語のインライン入力までできちゃう???

あきらからにどこかに設定ファイルを残しています。大体予想はつきますが、以下のところに見つけました。

個人設定の「AppData」以下のRoamingというところにありました。sublime text2をインストールしたばかりですが、終了してこのフォルダを削除してしまいます。(中身はpythonがそのまま入っているかとおもったら、わけわからないXMLでした)ここでsublime text2を起動すると、おそらくProgram Dataのところからでしょうがデフォルトのデータをまたここに作ります。
今度はPackage Installすらないまっさらな状態なので、再度環境構築です。結果として日本語入力しても画面表示の乱れない状態で動くようになりました。


最下段の情報ラインが表示されますし、日本語のインライン入力もできます。さらにTabの表示もよくなりました。

python 3.x系がリリースされたのは2008年12月ですからもう5年たっています。このとき後方互換性が犠牲にされたため、いまだにpython 2.xからpython 3.xへの移行は進んでいないようです。言語としての「美しさ」を求めるのはわかるけど、なんらかの移行手段を考えてくれないと困ったことになるといういい見本ですな。(話変わりますが、そういえばc++の第4版、夏ごろ決まった聞きましたがかなり揉めたようですね。新しい機能が欲しい、でもStrupがダメだ!と議論がもめたと聞いています。互換性の問題を保ちつつ、言語はシンプルかつ高機能にすることのせめぎあいですね。)

2013年11月16日土曜日

Windows, Mac, Linux共通のエディタが欲しい

これまでWindowsでテキスト編集するときはSakuraを愛用していました。なんてったって起動が速い!ただこのところLinux, Mac同時並行で操作することが増えて、共通のエディタに何かいいものはないかと考えていました。
Linux, Macでテキスト編集するなら端末開いてemacsでやるのが速いんですが、相互の文字コードの違いの問題もあり面倒くさくなってきました。

最初に見つけたのがKomodo editorです。かなり高機能で、html, python, javaScriptなどのプログラム作成時の支援機能までついています。Windows, Linux, Mac共通のUIで使えるとのことで試しに触ってみました。

なかなかいい感じですが、機能が豊富なためか起動が遅い!ちょっとこれには閉口してしまい、さらに探すと、sublime Textがなんか評判よさそうです。




順にWindows、Linux、Macそれぞれにインストールしてpythonのプログラムを表示してみました。komodoと同じようにプログラム作成時の支援機能もついてますし、右端にファイル全体を表示するミニウィンドウがあるところまで同じです。ただ明らかにKomodoより起動は速いです。(さすがにWindowsのSakuraほどではないですが)なんかPythonでできてるんですかね?様々なPluginがあり、簡単に追加できます。

これはシェアウェアなので、しばらく使ってみてよさげなら登録しましょうかね。

PS:
重大な問題が発生!! Macは問題ないんですが、WindowsとLinuxで日本語入力がまともにできません!!
プログラム書くのには問題ないんですが、コメントに日本語書けないのは致命的です。お金払うなら日本語入力(マルチバイト文字対応)できるようにならないと困ります。(特にwindows64bitだとタイトルも乱れて、どのwindow編集中かもわからないし、windowの文字も乱れる。。。 せっかくマルチOS環境で使えるエディタが手に入ったと思ったんだけど、これでは使えません)

PSその2:
その後、なんとかWindowsとLinuxで日本語入力できる方法を見つけました。Windowsはインライン入力できますが、Linuxは別windowでの入力(;;) ちょっとこれでは常用にはできません;;
ところでKomodo Editorですが、こちらはwindows/Linux/Macどれでも問題なく日本語のインライン入力ができました。見た目のシンプルさはsublime Textが好みなんだが、、、もう少し様子見です。

PSその3:
上記3画面ですが、あらためて見るとWindowsが変わっちゃってます。おそらくなぜか日本語のインライン入力ができるようになったころからでしょうか。。。

・複数Tabは表示できるが、Tabの切れ目がうまく表示されていない。
・最下段に編集中ファイルの言語等を表示するラインがありますが、それが表示されない。
・上記でも少し述べましたが、Tabのタイトル表示が最初乱れる。(Windowを一度小さくして再描画させれば直りますが、、、)

ちょっと気になっているのが、今使ってみているsublime Text2はpython2.x系なんだそうですが、たまたまWindowsだけはpython3.x系を別の事情でインストールした状態でした。そのせいかとも思い、python2.x系を入れなおしたんですが、状態変わりません。もう少し頑張らないとだめなようです。(これだから日本語はつらい)

2013年11月12日火曜日

Ubuntu起動直後のDisk IO

Ubuntuを使っていると、大抵は非常に起動が速いくて助かります。ureadahead(起動時にいつも読み込むファイルを先読みしてファイルキャッシュしてしまう)のおかげなんでしょうが、時々起動後もDisk IOが煩雑に動いていることがあります。ureadaheadのせいではないかもしれませんが、何が動いているのか気になります。(SSは画面上に表示しているシステム負荷の表示です。起動直後のものですが、Disk IOで真っ赤です。)

しばらくするとおさまりますし、何時もこうなるわけではないんですがそのうち調べてみないと。

2013年11月9日土曜日

Raspberry Pi カメラモジュール設定

さてせっかくなんで、簡単な監視装置にしてみます。最初は自動起動にしてしまえばいいと思ったんですが、せっかくなのであまっていたUSB WLANのモジュール(バッファロー:WLI-UC-GNHP 11gが可能です)を使えるようにし、キーボードとかはつけずにリモートログインでコマンド実行するようにしてみました。装置の外観は以下の様な感じです。
カメラからのハーネスは、ケースのLANソケットの隙間から表にだし、USB WLANのアンテナ部分に借り止めでつけてあります。下の黒いのがUSBパワーを供給するバッテリーで、これで好きなところ(ただし、WLANが届くところ)に設置できます。

WLANの設定ですが、以下のようになります。

1.WLANを有効にする
以下の設定ファイルを2か所修正します。

$ sudo vi /etc/network/interfaces

iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
         ↓
iface wlan0 inet dhcp
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

2.無線LANの接続設定
次に親機と接続できるよう、SSIDやキーを設定してやる必要があります。ファイルは、/etc/wpa_supplicant/wpa_supplicant.confです。rootになって以下のコマンドをじっこうします。

# wpa_passphrase SSID pass >> wpa_supplicant.conf

SSID:親機のID
pass:使用しているセキュリティに応じたキー

こうすると以下のような感じになります。

pi@raspberrypi /etc/wpa_supplicant $ sudo cat wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
        ssid="***335786826CE295923343F371E9100"
        #proto=wpa2
        #key_mgmt=WPA-PSK
        #pairwise=TKIP CCMP
        #group=TKIP CCMP
        psk="****ba48855fb70911eb244034920f6a4440d314b341b604891569796a565"
        #psk=****d233afa24051e209237e4ec79b8659d32f7a650e4bb1a0d08720f4d759e
}

SSIDやキーは一部かくしてあります。#のコメント行は基本的に後から自分が追加したものです。もしかしたら必要かもと調べたサイトにあったんですが、自分の場合は必要ありませんでした。それでも最初なかなか接続ができず、なんでだろうと親機のログをみてみるとDHCPのアドレス発行まではいっているようです。どうもキーの設定が悪く、うまく接続できないようです。実は、psk行が2ラインありますが、最初は1行目(赤字部分)がコメントになっていて、2行目が有効になっていました。しかし親機の設定をみるとコメントにしてあるほうが設定してあるキーです。理由がわかりませんが、そちらを有効にしたらつながるようになりました。

これで準備万端です。さっそくベランダに置いてみて、外の風景を撮影してみました。快適に動きます。

2013年11月8日金曜日

Rapberry Pi カメラモジュール購入

今年の5月に発売になっていて、気にはなっていたんですが注文してみました。Rapberry Pi本体を購入したときはRS Componentsのサイトから注文したらイギリスからの輸入(代金はユーロ、レートは発送時のものという条件)になってしまい、クレジットカードの登録がいやだったんでPayPalで注文しましたが、今度は日本のサイトで注文受け付けてくれるようで、代金引換でOKでした。
代金も日本円で表示されたので在庫があるのかなと思ったら、翌日に届きました。そこでさっそく試してみました。

 届いた箱です。チープです。(2,400円ですから。説明サイトだと白箱で、Raspberryの印刷もありませんでした。)
 箱の中に入ってたのはこれだけ。静電防止用の袋にモジュールが入れてあるだけ。袋は封もしてありませんでした。説明書はなし。箱に説明用のURLが書いてありました。(下の白い箱は、Raspberry Piを購入した時、一緒に購入した専用ケースです。)

説明用サイトを見て、接続。コネクタはEtherのソケットのすぐ後ろです。力加減は、慣れが必要かと。なにせスマホが流行ってからこっち、やわいコネクタ増えましたからね。端子ピッチはかなり大きいので、それほどビビるほどではありませんが、初めてこの種のコネクタ触る人は注意が必要だと思います。
 sudo raspi-configでカメラを有効(Enable)にしますが、config画面のカメラ設定の位置が説明用サイトと違いますw(まあこれくらいではめげません。メニューの位置が階層構造になって、隠れてないだけマシ)
静止画の撮影例です。2592x1944と、モジュールのサイズからは信じられないくらいの高精度の絵がとれました。自動焦点のようで、静止画の撮影コマンド実行しても、1,2秒焦点を合わせようとしているような画面が表示されました。










おそらくスマホ用のカメラモジュールなんでしょうが、すごいですね!こんなのが安価にでまわるとは。基盤もろだしなんで、使うときにケースや固定方法を考えないといけません。
何に使おうかというと、Raspebrry PiがUSBパワーで動くので、電源On自動起動で一定時間毎に静止画を監視用に撮影するようにしようかと企んでいます。ノートPCも動かせるUSBパワーの外部バッテリ持ってるんで、それ使えば一日くらい動くんではないかと♪(本当は電源確保して、ネット接続とか考えるんでしょうが、インフラ整備がめんどくさい。元のコストが安いので、簡単な監視カメラ程度になれば十分かと思います。)

2013年11月4日月曜日

番外編:水道 水漏れの修理

外の水道がなんか水漏れしているような、、、下のセメントが常時濡れた状態になっています。気になっていたんですが、ついにパッキンを交換してみました。構造は知っていたんですが、あらためて蛇口を見ると、パッキンを交換するためのナットが蛇口を回すプラスチックによりカバーされています。これどうやるんだ?調べてみたら、先端のカバーは簡単にマイナスドライバーで外れることがわかり、作業してみました。その記録です。


 蛇口を回す取っ手上部のカバーを外したとこです。簡単に外れました。
 中にプラスねじが見えます。これを外します。
 取っ手を外すと、蛇口のパッキンを交換するために外さないといけないナットが見えるようになりました。ここで家の水道の元栓を閉めます。
ナットをはずしてパッキンを確認したところ。直径15mm程度のものでした。見たところ特に痛んでいるようには見えませんね。












家に蛇口のナットを外すような大きなサイズのスパナがなく、ホームセンターで購入してからの作業です。ものの数分で作業は済み、漏れも止まりました。

2013年11月3日日曜日

Androidアプリ開発:Blenderで作成したモデルをopenGL ESで表示したい

Androidのアプリで3Dモデルデータを表示するサンプルプログラムがあります。表示用のサンプルデータも添付していて、それを表示する分には問題ないんですが、自分でモデルを作成したくなりました。
とりあえず簡単に手に入るモデラーとしてBlender(2.69)で簡単な立方体を作成して、表面に色をつけてみました。ところがどうしても表示できません。モデルデータはWavefrontのobj形式です。添付されていたobjファイルはBlenderで作成したものではなく、若干キーワードに相違はありましたが、プログラム内でデータ読み込みをしている部分を調べた限りでは問題なさそうに見えます。
結局、2,3日かかりましたがBlenderでobjファイル形式でExportするときはこのアプリでは以下の注意が必要でした。

1.法線ベクトルを出力する
デフォルトでは法線ベクトルの出力がoffになっています。"Include Normals"にチェックを入れてやりましょう。(→これでobjファイルに、vn成分が出力されるようになります。)

2.面の定義が終了したことを示すための別の行を入れる
これはたまたま参考にしたサンプルプログラムの仕様でしたが、これを見つけるのが一番時間がかかりました。objファイルには面の定義のf行(頂点番号/テクスチャ座標の番号/法線の番号)が一つのオブジェクトで連続して出力されていますが、データの最終行を示すマークがありません。サンプルプログラムでは、何か別の行を読み込んだときにf行が終了したと判断して、自分のobjectデータに登録していました。
Blenderでobj形式で出力してやると、最後の行がf行で終了していました。つまり、サンプルプログラムが最後のobjectの塊を認識できないことになります。(1個しか定義してなければ、0個になります。)ここは仕方なく、手作業で1行害のなさそうな”usemtl default”を最終行に追加しておきました。(複数のobjectが定義してあれば、次のobjectの定義の始まりで通常は認識できるんですが。。。)

3.面は三角形で出力する
上記まででサンプルプログラムに自分がBlenderで作成した立方体が表示されるようになりましたが、各面が三角形で表示されます。Blenderの出力を見ると四角形でf行を出力していました。OpenGLは面の定義が基本三角形のはずで、BlenderのExport時のデフォルトが四角形になっていました。これを三角形にしてやります。("Triangulate Faces"にチェックを入れてやります。)
これで無事立方体が表示されました。

参考までに、2つチェックしたExportの設定画面をのせておきます。


objファイルは色の定義に*.mtlファイルが別途必要になります。ちょっと面倒なので、今度はcollada形式を調べてみようかと思います。

2013年11月2日土曜日

Androidアプリ開発:ファイル入出力 assetsディレクトリ

以前、ファイル入出力に躓いたことがありました。(Androidが複数ユーザー・ログインに対応した直後です)

Androidプログラム開発ーファイル入出力

その後、別のサンプルアプリでeclipseの開発環境内で、assets/ディレクトリがあることを知りました。どうもそこにファイルを配置しておくと簡単にアプリ側の設定等を入出力できるようです。(いつの間にかデフォルトでeclipseのAndroid開発環境に作成されるようになってました。気付かなかった。)

AssetManager assets = context.getAssets();  // 追加
reader = new BufferedReader(new InputStreamReader(assets.open(fileName)));

contextは例の如く、Androidプログラムの本体のインスタンスです。これで個々のアプリのファイルであるassets以下までのパスを供給してくれるようです。これなら簡単にこのアプリの設定ファイル等を作成できます。(一々、アクセス可能なファイルパスを考えなくてもすみます)

あと、最近気づいたんですが以下のデータクラスによるファイルアクセスはもう古い(?)スタイルなのでやめろとeclipseから注意されました。

DataInputStream in=new DataInputStream(context.getAssets().open(path));

どちらも同じ以下の関数で1行を読み込むんですが、何故か注意されます。

String line=in.readLine();

注意されるだけで動きには問題ないんですが、eclipse上で注意のマークが表示されるのが気になります。(古いというより、プリミティブな方法での入出力なので今後の変化に対応出来ない可能性があるからやめとけということですかね。)

PS:
後、assetsフォルダ以外にアプリ内でデータにアクセスする方法として以下の方法があります。(mResourcesは、import android.content.res.Resourcesにより提供されるクラスで、res/ディレクトリ以下の資源を扱うのに使われます)


InputStream is = this.mResources.openRawResource(R.raw.sample);

入力であるInputStreamの定義なんですが、ファイルの指定方法として引数に( R.raw.sample )を指定しています。これはeclipse開発環境内でいうと、res/raw/sample.daeというファイルを指定していることになります。これはこれで便利な方法です。(ただ.以下の拡張子が表示されない、それでも問題ないのがちょっと気になります。この例ではxmlファイルなんですが、R.raw.と入力した時点で、res/raw/以下のファイルがeclipseの補助機能により選択肢に表示されます。)

2013年10月31日木曜日

Androidアプリ開発:OpenGL ESの実装について気になること

AndroidのOpenGLサンプルをちょこちょこ動かしてみてて、ちょっと気になったことがでてきました。Androidアプリの動作確認にはNexus7(初代)を使っています。動きが早くて、デバッグも楽なんですよね。
ところが先週、Nexus7においてOpenGLの動きに独特な箇所があることがわかりました。(GoogleによるAndroid自体の問題なのか、Nexus7に使われているnVidia Tegra3におけるビデオドライバの問題なのかははっきりしませんが)さらに別の、もっと重傷な問題が見つかりました。それは影の描画にNexus7とその他(Galaxy S2)で差がでる場合がでました。

同じアプリをまずNexus7で動かしたものです。

どうみても影の描画が変です。(影が横縞になって、透けてしまってます。)ちなみに同じアプリをGalaxy S2で動かすと以下の様になります。
普通に影が描写されます。

なぜNexus7でこうなるのかまだわかってません。Nexus7のGPUオプションがいくつかあるので色々条件を変えてみましたが、影の描画の異常は変化ありませんでした。当初はGPUアクセラレーション独特な問題に見えたんですが、そうじゃないようです。もう少しプリミティブなOpenGLのプログラム(関数)の動きから比較してみないといけないかもしれません。

2013年10月22日火曜日

Androidアプリ開発:テクスチャの勉強

AndroidではグラフィックスにOpenGL ESが実装されています。OpenGLは以前触っていたんで、個々の関数については「昔、聞いたことあるな~」と思いながら、サンプルを打ち込んでみて思い出しながら作業を進めます。
pngのbitmapをテクスチャとして貼るサンプルを作ってみましたが、これがどうしてもうまくいきません。テクスチャが本来表示されるはずのところが「真っ黒」になります。最初は光源の設定か、あるいはテクスチャを張るポリゴンの法線ベクトルの問題か?と思ったんですが、サンプルはそのあたりはデフォルトにまかせており、特におかしなことはしていません。
最初、bitmapを自分で用意したとき、適当なサイズで作ってしまいましたが、OpenGL ESでは2のべき乗でないといけない制限があるとのこと。そこで512x512で作り直しましたが、状況は変わらず。(大昔のOpenGLではそんな制限がありましたが、だいぶ前に自由になっていました。OpenGL ESは組込み用なので、そのあたりメモリの制限があるんでしょうね。)

さんざん悩んで、google先生にどう質問したらいいか何度か試しているうちに解決法がのっているサイトを見つけました。2012年7月くらいのAndroidの記事で、bitmapなどのresourceを保持するフォルダに、res/drawable-tvdpiというものができたとのこと。これまでアイコンのサイズを3通りくらい保持するためにldpi/mdpi/hdpiとかあったんですが、これら以外に「抽象ドット密度」というものができて、これを画像表示(テクスチャも)に使うとのこと。いやらしいことに、デフォルトでは作成されないフォルダ、res/drawable-tvdpiというフォルダに画像を保存しておくのが前提なんだそうです。そして別のサイトの情報で、さらにやっかいなことに今回最初にデバッグに使ったのがNexus7なのですが、この端末がtvdpiを実装されているtvdpi端末(表現が正しいかわかりませんが・・・)であり、ここに該当する画像ファイルがないと、hdpiにあるファイルを「自動でリサイズ」するとのこと。つまり、2のべき乗で作成しておいても勝手にリサイズされてしまい、それがくずれてしまって表示がされなくなってしまいます。(試しに別のAndroid端末をつないでみたら、表示されました)

解決法としては、res/drawable-tvdpiに2のべき乗の画像ファイルを保存しておくことになります。これでどの端末でも同じように表示されるようになります。
ただこの情報が書いてあったサイトでは、今度Android4.3ではOpenGL ES 3.0がサポートになり、テクスチャ画像の2のべき乗の制限がなくなるという情報がありました。自分のNexus7はAndroid4.3になっていますが、テクスチャ画像は2のべき乗でないとだめでした。まだダメなのかもしれません。

2013年10月18日金曜日

githubでEclipseプロジェクト(Android)の管理

gitの復習を兼ねてgithubの使い方もわかりました。さて次にコマンドラインではなくGUI、特にeclipseでgit(github)を操作する方法を調べてみます。どんなプロジェクトタイプでも同じでしょうが、特にAndroidプロジェクトのgitでのバージョン管理、複数PCでの開発環境構築について調べてみました。(eclipseにはEGitが入れてあります)

今回も結構手間取りました。ネットをググってみると似たような情報は結構あるんですが、いずれも複数のPCでの開発環境を構築するには足りないというか、部分的な解説しか見つからなかったんです。よくあるのが、
  • githubに既に存在しているリポジトリをeclipseで取得(しかもAndroidじゃない)
  • githubにeclipseからAndroidプロジェクトを登録する。但し他のPCでそれをどう使ったらいいかがない。
です。2つ組み合わせればよさそうな気がしますが、問題なのはeclipseのAndroidプロジェクトの場合、プロジェクト内のjava関係のライブラリ等をリポジトリに入れるわけにはいかないので、それを別のPCで開発環境の構築までどうやって持っていったらいいのかがわかりませんでした。
結局、かなり失敗してやり直しましたが(2,3回github上のリポジトリも壊してしまったw)なんとかできたようです。いかに手順を示します。

1.Mac上のeclipseでAndroidプロジェクトを作成し、githubに登録する
2.Windows上のeclipseにgithubからプロジェクトを取得、開発用のAndroidプロジェクトを構築する

大雑把にいって、この2つです。この後、実際に相互にファイルを編集してみて、相手に変更が反映されるのを確認しました。

1.Mac上のeclipseでAndroidプロジェクトを作成し、githubに登録する
まずMac上でAndroidプロジェクトを作成、一応動くことを確認しました。さてこれをgithubに登録するんですが、特にこれは問題なくできました。eclipseのExplorer上のプロジェクトを右クリック→Team→Share Project でダイアログが表示され、そこにリポジトリをどこに置くか聞いてきます。ここで、Mac(或いはwindows)のローカルにリポジトリが作られますが、デフォルトは$HOME/git/以下にどちらも作られました。(この時、プロジェクトは$HOME/workspaceから、$HOME/git/<リポジトリ名>に移動するのに注意。)次に、バージョン管理するファイルを選択、Addしてやります。(Androidのjarとかは当然入れません)そして「最初の」commitをしてやります。(Team→Shareでは、gitリポジトリの入れ物をローカルに作成しただけで、まだ何も入っていない状態です。)そしてPushを選択、githubのリポジトリ(事前にリポジトリの入れ物だけはgithubのHPで作っておきます)を入力して、github上にデータを送ります。ちょっと注意が必要なのが、最初のpushの時何をリポジトリに登録するかです。初めて作ったばかりならmasterのbranchしかないと思っていたら、HEADというのも表示されます。何でこれが表示されるのかわかりませんが、うっかり最初にHEADを選択してリポジトリに登録したら、プロジェクトの登録はできたのですがbranch名がHEADになってしまい、どうやってもmasterにできず結局github上でリポジトリを削除して作り直しました。
別のHPにも情報を後で見つけましたが、

  mastre[branch] (refs/heads/master) → refs/heads/master

が正解のようです。あと、議論が分かれるところですがeclipseのプロジェクトでは、".project", ".classpath"というような設定ファイルがあります。デフォルトではこれもリポジトリに登録する設定になっていますが、これはバージョン管理するな/しろ、の意見が半々でした。どちらがいいかはeclipseの環境にどんなplug-inを入れているかにもよるらしく、一律にコレというのはありませんでした。各自の開発環境で判断するしかありません。
(注:.project内にはプロジェクト名=フォルダ名が格納されています。そのため、gitに.projectがないと2項の方法でAndroidプロジェクトを作成するときプロジェクト名として起動時のクラス名が使われます。デフォルトでは新規プロジェクトを作成する時、プロジェクト名がそのまま起動時のクラス名になるので大抵の場合問題がでないんですが、わざとプロジェクト名と起動時のクラス名を変えている場合に問題がでます。)

追記:
gen/R.javaも管理を外しました。branchを変更したり、古いバージョンに戻す時にエラーがでます。プリコンパイル・ファイルなのでRun/Debug時に生成されますから、元のファイル(res/以下)さえ管理対象に入っていれば大丈夫でしう。

とりあえずこれで、このMacだけで開発を進めていく分にはバージョン管理ができるようになりました。

更に追記:
最初にリポジトリにpushしたPCでは、どうもうまくpullができません。色々やってみたのですが、eclipseのGUIでやるとconfigに以下のものが記録されないようです。(hogeは適当に変換してください)

branch.master.remote=origin
branch.master.merge=refs/heads/master
branch.master.rebase=true

remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
remote.origin.url=https://github.com/hogehoge/hogehoge.git

Repository Explorerでプロジェクトを右クリックして、Propertiesを選ぶとwindowがでてくるので、そこに追加で指定してやります。
どういうわけかeclipseから最初にリポジトリに登録してやるとこの5項目が登録されてなくてpullがうまくいきません。(つまりpushしかできない)
登録したら一度削除して、githubから取り出してやったほうが、このあたりの設定をしてくれて楽かもしれません。

2.Windows上のeclipseにgithubからプロジェクトを取得、開発用のAndroidプロジェクトを構築する
さて次が一番悩んだところです。リポジトリに登録時、Androidプロジェクトだという情報は入っていません。何も考えずにeclipseでgithubからImportしてしまうと、単なるファイルの塊がeclipseのExplorer上にできるだけです。もちろんその状態でファイルの編集/更新を相手に伝えることはできるんですが、Windows上でAndroid実機での動作確認ができない状態です。(Androidプロジェクトになってないから当たり前です)さんざん悩みましたが、以下の手順でいいようです。(一発でやる方法もありますが、あえて一つずつやっていきます。

(1)eclipseのGit Repositoryにgithubからcloneを作る
eclipseで、Window → Show View からGit Repositoryを表示する。そこで右クリック、あるいはボタンで目的のAndroidプロジェクトのcloneを作成する。

OKすると、master branchを取得したとダイアログがでてきます。(今回はmasterしかないし、たいていはmasterを取得するでしょうが、場合によっては別のbranchを取得する場合もあるでしょう)
これで$HOME/git/以下にローカルなリポジトリが作成されます。


次に、eclipseのExplorer上で右クリックでImport(或いは、FileメニューでImport)します。Sourceは、Git/Projects from Gitを選択します。EGitが入っていると、Local、Urlの2つが選べます。Urlは先ほどのGit Repositoryにcloneを作成する手順に入っていきます。Localはすでに存在するgitリポジトリを指定します。今回は先に作成したcloneとなります。そして以下の画面が表示されます。
ここで3つの選択がありますが、真ん中の"Use the New Project wizard"を選択します。次に、"Android Project from Existing Code"を選択します。

これで既存のコードでAndroidプロジェクトを作成することをeclipseに伝えることになります。次のダイアログで、どこにそのコードがあるのか指定する画面になりますが、$HOME/git/以下に1.で登録したプロジェクトのフォルダが存在しているはずなのでそれを選択してやります。これでOKです。

注:
先に、".project"ファイルをバージョン管理に入れるかという問題がありましたが、どうもこれが入っていないとこの時点で指定したフォルダがeclipseのプロジェクトと認識されないようです。実はこのあたりどう解決すべきか正解が自分にもわかりません。個々の開発環境に応じて考えてください。

また、この手順でWindows上にプロジェクトを作成すると、ちょっと通常のプロジェクトとはファイルの位置が異なります。

・通常のeclipseプロジェクトのファイルの位置
       $HOME/workspace/<プロジェクト名>

・今回のgit管理下のプロジェクトのファイルの位置
       $HOME/git/<リポジトリ名>/<プロジェクト名>

eclipseのExplorer画面上は同じように見えるので、ちょっと注意が必要です。(eclipseで操作する上では何も差がありません)

さて結果としてWindows上の画面は以下の様になります。
Package Explorer, Git Repositoriesの両方に同じ名前のフォルダがありますが、実体は同じものです。

2013年10月16日水曜日

githubを使ってみる(具体例)

以前、家庭内の複数のPCでgit repositoryを使う方法について書きました。しかし、いざやってみると、いちいちサーバーを起動しておかないといけないのが面倒くさい。(^^ゞ
色々なメモがき、下書きは既にgoogle drive(google doc)により複数のPCで作業してきましたが、(これもgoogle driveができるまでは家庭内NAS使ったり、USBで持ち歩いたりしてたんだよね〜、便利な世の中になったもんだ)プログラム自体も複数のPCでやり取りしたくなったのと、バージョン管理(特に過去の記録や、複数のブランチを持ちたい。一々プロジェクト名を作り直したくない。)をしたくなったので、githubを使ってみることにしました。(単に複数のPCでプログラムを持ち歩くだけならgoogle driveでもいいんですが、プログラムを作っていく途中で色々な機能を作りこんでいく途中課程を後で見たい場合、これまで一々プロジェクト名を少し変えて新規作成したりしてました。でも本来、バージョン管理でやった方がスマートですよね。)

さてググってみると、色々な使用例の説明がありましたが、どうも具体性に欠けているものが多く、調べ直しが多かったので個々のコマンドの説明を付加しながら、あらためてメモを残しておきます。(注:githubのサービス自体、まだ完成しているわけではなく、UIなんか変わっているせいもあるので、一応SSのっけときますが、何時変わるかわかりません。そのため、何の操作をしているかの説明を付加しておきます。)

1.githubにアカウントを作成する
まずgithubにアカウントを作成します。github.comのTopにいくと昔はアカウント作成のボタンがあったらしいんですが、2013/10/16時点では特にボタンはなく、画面にいきなり欲しいアカウント名、連絡用e-mailアドレス、パスワードを入力し、'sign up'すればアカウントを作成できて、e-mailがきます。
現状では、一般公開プロジェクトを作成するだけならフリーです。
自分のページは、https://github.com/(アカウント名)になります。ブラウザでいきなりURLを見ることができます。(但し、その時はread-onlyになります。データを取得するだけならこれでいいんですが、管理等したい場合はそこでログイン('sign in')してやる必要があります。)

2.リポジトリを作成する
上記、URLでリポジトリを作成します。(注:windows, Macには専用のツールがありますが、最新OSでないといけなかったり、更新が早そうだったのと、Linux用がない?という状態だったので、ブラウザだけでやりました。)
ブラウザのUIがググった先のページと違いましたが、repository操作のタブを選んで、Newすることになります。(ちょっと抽象的ですみませんが、下手にSS貼ってもすぐ変わりそうなので、言葉で説明します)説明用に、「git-hiro」としておきます。

ちなみに、ここで作成したリポジトリのgitコマンドでアクセスするときのURLは以下になります。
(httpsアクセスの場合)https://github.com/(アカウント名)/git-hiro.git
(gitプロトコルの場合)git@github.com:(アカウント名)/git-hiro.git
なお、この状態ではgithubにリポジトリが作成されただけで、当然中身は空っぽです。

3.PC上で最初のデータを作成してgithubに登録する
先ほど専用ツールは使わないと言いましたが、windowsの場合だけはgitコマンドを持っていないので、cygwinを入れるなりしない限り専用ツールが必要になります。(eclipseにplug-inがあるらしいんですが、それはまた別の機会に調べます)元々、gitってGUIがほとんどなかった気がします。なんか、最初に作ったLinusの方針(とにかく早く機能するものが必要だったので、UIなんかなくてコマンド入力でいいから作った?)からか、Linuxで動くGUIツールを見たことがありません。そこで、以下にMacで作業したときのコマンドを載せておきます。(Macでは端末からLinuxと同じようにコマンド入力でやりました。自分も結構、こちらの方が好きです。)

$  mkdir git-hiro  // 作業用のディレクトリを作成します
$  cd git-hiro/   // そこに移動します
$  git init     // gitの初期化をします(.gitディレクトリが作成されます)

最初のディレクトリは特にgithub上に作成したリポジトリ名と同じでなくてもいいと思うんですが、その方がわかりやすいので同じにしています。

$  git config --global user.name "hogehoge"
$  git config --global user.email "hogehoge@gmail.com"

一応、当該リポジトリを操作するユーザーの名前とe-mailアドレスを設定しておきます。(デフォルトだとマシン名が入ったりして格好悪いので)

$  emacs -nw README.txt  // 登録用にREADMEファイルを作成します
$  git add README.txt 
$  git commit -m 'first commit'

$  git remote add origin git@github.com:(アカウント名)/git-hiro.git
$  git push origin master

ところで上記の例で何かおかしいと感じた所はありませんか?自分は他の人のページを見てた時、「これでいいの?」と思ったんですが(githubアカウントの)パスワードを入力するところがありません。
このあたりはマシンの設定にもよるんでしょうが、Macの場合はここでPermissionがないと怒られました。gitプロトコルで行う際、sshの鍵の登録をしておく必要があります。
詳細は別のページにまかせますが、ssh-keygenで鍵を作成し、それをgithubの自分のアカウント設定のページでSSH Keyの登録を行ってやります。(後で、git push/pullをする度にアカウント名/パスワードを入力する例も示しておきます。複数のPCで作業する際、全部のPCに鍵登録するのも大変なので。)

4.githubのページでリポジトリの状態を確認する
2,3回README.txtを変更、登録を繰り返してその履歴などが記録されているのを確認できます。(手順5にSS例を表示します)
わざと2回目の履歴を表示しました。ブラウザ上で内容を確認できるし、前の回との差分も見られるようです。(さらにこのcommitに対するコメントが下段に入力できます)最上段がcommitコメントになっています。

5.別のマシンで既存のリポジトリを取得、変更を登録する
次にUbuntu(わざと別のOSで作業します)で、githubからリポジトリを取得し、変更して登録します。

$  mkdir git-hiro  // 一応、同じディレクトリ名でディレクトリを作成します

ここでgithubからデータを取得します。今度はわざとhttpsでやってみます。

$ git clone https://github.com/hiro1960/git-hiro.git git-hiro

initが必要ないのに注意してください。(やってもいいですが)また、わざとoriginへURLの登録もせず、直にコマンド入力してみました。データの取得なので特にアカウント名/パスワードは必要ありません。

$  emacs -nw README.txt   // 取得したREAMEの内容を変更します
$  git add README.txt
$  git commit -m 'add 3rd line from Ubuntu'  // 3回目のcommitのコメントです
$  git push https://github.com/hiro1960/git-hiro.git master

今度はgithub上のリポジトリの変更になりますので、ここでアカウント名/パスワードを聞かれます。(パスワードのssh設定をしていない場合ですが)

2回ほどMacでcommitし、3回目はUbuntuからcommitした状況です。それぞれの履歴の状態もブラウザ上でクリックして確認できます。

6.別のPCで変更分を取得する
さてUbuntu側でリポジトリを変更/更新したので、Mac側でそれを取得しないといけません。このあたりgitはsubversionと違い、ローカルでもリポジトリを持つのでちょっとコマンドが増えます。

$  cd git-hiro
$  git fetch           // githubからローカルのリポジトリに変更分をとってくる
(以下の様なメッセージがでる)
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 3 (delta 1), reused 3 (delta 1)
Unpacking objects: 100% (3/3), done.
From https://github.com/<プロジェクト名>/git-hiro
   4de59d5..72f762b  master     -> origin/master

$  git merge origin/mater  // 取得した差分をソースに反映(merge)する

fetchだけではローカルのリポジトリに更新データが反映されるだけで、ユーザーが直接さわるファイルには反映されません。わざわざ、origin/master(自分のファイルはmasterブランチだと仮定しています)にmergeすると明確に指示しないといけません。

実はこのあたり色々議論があります。1年前にeclipseでgitの操作するときは何気なしにメニューからpullを選んでいました。これはコマンドでも'git pull'でもいいんですが(実際、こっちではmergeの必要がありません)、ただ現在ではpullは使わない方がいいという人が多いようです。(但し、Toolを使わずに伝統的なコマンドラインでgitを操作する場合の話です。Toolで操作する場合はTool側で以下の問題は考慮してくれるでしょうから。)
最初にgithubからローカルにリポジトリを作成するさい(手順5)にgit cloneを使いましたが、ここはgit pullでも同じようなことはできます。でもcloneでやるとリポジトリのURLも覚えてくれるので、その後のpush/pull/fetch等でURLの指定が必要なくなり、間違いが減ります。そうなるとpullを使うと間違いの可能性が高まるので、いっそpullは使用するな、最初にcloneしてその後はfetch/mergeでやれ、という人が多いようです。
個人的には「慣れ」という気もしますが、仕事で複数の人間、複数のプロジェクト(当然、複数のリポジトリ)に関わる場合はちょっと制限が付きますが、この方が安全だと思います。

ただ一つ問題があるとすると、プロジェクトの作業中gitサーバが問題をおこし、臨時でbackupのサーバーをたてる場合です。当然、一時的にURLが変わるのでその時はpullで作業しないと対応できないでしょう。(当然、backup用のデータは保存してあるという条件です。仕事でやるなら作業の成果は逐次保存しておかないとまずいでしょうし。)でも本当はこんなことしたくないし、プロジェクトのメンバに注意しろと伝えるのも怖い。みんなの技量が同じ程度、あるいは十分なのか見極めれるのは問題が起こらなかった時だけですし。

7.github上のリポジトリの削除の方法
ところでこの使用例を書くためにgithub上に最初のリポジトリを作成するとき、うっかりタイプミスしてしまいました。丁度いいので、その削除方法を示します。(例によって、UIが他のページで調べたSSと若干違いました。そのあたりは何をしたいかを考えて応用してください。)
間違えて「git-hito」と作成してしまいました。これをクリックして、settingをクリックすると当該リポジトリの管理画面になり、削除のボタンがでてきます。(注:少し前までAdminというタブでこの管理画面に飛んだ様です。その辺は応用きかせて、何らかの管理を行う操作を探します。)
一番下に削除ボタンがあります。これを押すと確認用にリポジトリ名を入力するダイアログがでてきます。

面倒くさいですが、キーボードから削除したいリポジトリ名を入力し、"I understand ..."のボタンを押します。すると削除されます。


ちょっと注意が必要なのが、コメントやwiki(githubでは個々のプロジェクトにwikiを提供してくれます)への日本語(マルチバイト文字コード)の扱いに問題があるとの話があります。そのため今回はすべて英文字しか使っていません。

PS
コメントに日本語(UTF-8)と入力してみましたが、普通に使えました。すくなくともコメントは大丈夫のようです。
更に追記、ソースコードにSJISがあってもサイトでの表示、および使用に問題はでませんでした。日本語等のマルチバイト文字への対応ができているようです。


2013年10月14日月曜日

Android開発環境:ADT ver.22への更新

6月くらいにまたADTが、21→22に上がっていたようです。(しばらくさわってなかった(-_-;))
それでやっぱりまたうまくいきません。(いい加減にしてくれ!)

1.googleのURLをhttpsにしてみる。
Android Development ToolsのURLですが、http://dl-ssl.google.com/android/eclipseになっていますが、先頭をhttpsに変えてみる。

ただ、これいくつかのサイトを見てみるとどっちがいいのか時々によって変わるようです。どこかにアナウンスがあるのかもしれませんが、自分は見つけれませんでした。(今回は、結局httpの方で更新しました)

通常だと、SDK managerを単独で起動したりして先にSDKを更新しておき、後でeclipse側でcheck for updateしてやること、とどこでも書いてあるんですが、相変わらず「更新するものはない」といってきます。(でも、eclipse起動時にはADTが古いといって怒ってきます)

2.手動でinstall new software→available softwareにて更新してやる。
試しに手動でADTのURLに対して可能なソフトを調べてみると、ver.22があるといってきます。喜んでこれをインストールしようとすると、、、Macでは固まってしまいました。

しばらくぐぐってみたら、どうもver.22から新しい”Build-tool”というものがADT内に現れたらしく、これがないと色々悲惨なことになるようです。そこでSDK managerでとりあえずインストールしてみました。

(なんか3つくらいのバージョンが並行して表示されます。よくわからないので、とりあえず3つともインストールしてみました。→googleから9/17版の最新ADTをDLして動かしてみたら、最新のBuild-tool 18.1だけでした。試しに古い2つを削除してみましたが、問題なさそうです。ただ設定を変えることになるので、workspaceの再ビルドがかかります。しばらくeclipseをそっとしておく必要があります。

3.手動でavailable softwareでADTのver.22をインストール。
今度は先に進行しました。(固まりません) 最初はMacで試してみましたが、次にWindowsの方もやってみるとADTはver.22になったようです。


ただ、ちょっと気になる状態になってしまいました。

  1. eclipseが、Indigo(3.8)→Juno(4.2)になった。(まあ、大丈夫かな?)
  2. ADTのeclipse起動時のダイアログにADTのバージョンが表示されるが、相変わらずver.21のまま。(でも起動してから、古いとは文句をいってこなくなった。ちょっと気にはなります。)
  3. 「ADTについて」でADT関連のパッケージを調べてみると、なんかver.21が残っている?というかver.22になってから名称が微妙に変わった?(Android Developer Toolsから、Android Development Tools ?)そのせいか、2種類表示されてくる様子。→9/17版では、”Android Development Tools”というのはありませんでした。更にgoogleのAndroid Developerのサイトを見ると、ページにより"Developer Tools", "Development Tools"と両方ありました。google自体、混同してる?


また気になることに、10/15にOracleがJavaの脆弱性に対応するため大規模なJavaの更新をするとの予告がでています。これで問題ないか、簡単なアプリでも作ってみないとわかりません。→既存のHelloAndroidで、一部テキストだけ変更して再ビルド、実行してみましたが、問題なさそうです。

2013年10月7日月曜日

データ・ロギング・システムの検討(Etherによるデータ転送能力の調査)

さて、snappyの実力に関する実験データは取れたので、いよいよ検討してるデータ収集(ロギング)の検討に入ります。まずデータをEtherで転送するときの、実際の転送時間や、HDDへの記録にかかる時間、タイミングなんかを調べます。

まず、いま検討しているシステムは以下の様なものです。

PC1PCxはリアルタイムでデータを収集します。そのため自前でデータを記録していると、リアルタイムでのデータ収集のタイミングが乱される可能性があるので、収集したデータをEhterでどんどんPC0に送ります。(TCP/IPのSocket通信を想定しています)PC0では、送られたデータをどんどんHDDにログしていく。(ここは特にリアルタイムである必要はないが、PC1PCxより送られてくるデータを受信・ログが間に合う必要はある。)

本システムでタイミング的にボトルネックになりそうなのは以下の2点です。

PC1→PC0で収集データを送るときのEtherの通信時間。(データ長が長いと、それだけ通信時間が長くなる)
PC0によるHDDへの書き込み時間。(システムはLinuxで動かすのを想定しているので、PC0では強烈なファイルキャッシュが働くはずですが、それでも結局はHDDへの書き込み時間が問題になる)

結局、2か所でデータ長が問題になり、収集データを圧縮したいという要求がでてきます。それも高速に。(リアルタイム処理が乱されないように)
考えた、システムでの動作シーケンスの概要を以下に示します。
話を簡単にするために、データ収集としてPC1だけにします。

PC1PC0のSocketを接続
PC1で収集したデータをsnappy等で圧縮(今回の実験では、まだこの部分は未実装で計測)
PC1からPC0のEhterでデータを送信
PC0では受信したデータをHDDにログ
PC0からログ処理が終了し、次のデータを送ってもいいことを知らせるためにAckをPC1へ送る

まず基本的なデータを取るために、圧縮なしで100KBのデータをPC1は全速で送り、1回のloop処理時間を計測してみました。(10回loopを、3回実施)

1回目開始からの時間[sec]loopの時間[sec]2回目開始からの時間[sec]loopの時間[sec]3回目開始からの時間[sec]loopの時間[sec]
00.0094580700.0093951200.00931001
10.0188470.0093889310.0186870.0092918810.01864890.00933889
20.0281250.00927820.0280430.00935620.02789090.009242
30.0374820.00935730.03741910.009376130.0371830.0092921
40.0467150.00923340.04685210.00943340.04670190.0095189
50.05598310.009268150.05619910.00934750.05608110.0093792
60.06527520.009292160.0654850.009285960.06545310.009372
70.07459810.009322970.07483820.009353270.0748780.0094249
80.08389210.00929480.08408310.009244980.0841250.009247
90.0931940.009301990.09342410.00934190.09344390.0093189

約9msちょっとかかるようですね。なお、各loop処理時間の計測結果は毎回coutしてしまうと、コンソール出力処理の待ちにかなり時間を喰われてしまい、正確なloopの処理時間が計測できません。(このコンソール処理ってすごい時間がかかるんですよ。HDDへの出力はファイルキャッシュがあるので高速なんですが。)なので、プログラム中に計測した時間をメモリに記憶し、loop処理終了後にcoutするようにしています。

さて9ms/回はわかりましたが、ボトルネックとなる①、②はこのうちどれだけ時間がかかっているんでしょう?PC1にてWireSharkを起動し、パケットが何時送られたか時間を計測してみました。(PC0はHDDにログをしているのでファイルキャッシュがかなりきつい状態になっているはずです。そんな高負荷な状態でWireShark動かしてしまうと時間計測に影響を与えるといけないので、PC1で行います)
大体、以下の様な結果を得ました。(動作説明:PC1では「データ送信」の時に100KB分を1回だけsend( )関数をCallしています。それが35個のパケットに分解され、全部で2msかかったのがWireSharkのログで判明しました。また、PC0では1回のrecv( )関数では100KB分を受信できず、2,3回にわけて受信していました。つまりTCP/IPの実装部で35個のパケットを受信バッファにどんどん取り込んでいますが、アプリに制御が渡るのはまとめて2,3回になっていました。ただし、個々のパケット受信に対してはパケット受領のackがデータ送信の1ms後から始まり、8msの間続いたのがWireSharkのログで判明しました。PC0側で100KB分のデータをHDDにfwrite( )してプログラムに制御が返ってきたところで、PC1にAckの信号を送っています。それらの時間関係を示したのが、下の図です。)


PC0は受信において8msの間に35個のackパケットを250~300usにてほぼ等間隔にPC1に返していました。(例外もあります。時々50usのときもありましたし、1回300msもかかったことがありました。)

ところで上記の実験では10回loopでしたが、これだとログ・サイズは1MBにしかなりません。OSはLinuxでやっているので、余裕でファイルキャッシュに吸収されてしまい、実際のHDDへの書き込み時間(処理)の影響を測定できていません。試しにloopを30,000回にして2GB以上のログファイルを転送するときの時間を計測してみました。(PC0は32bit Linuxでメモリ2GB搭載です。これだけのログファイルをHDDへ書き込もうとすれば、オンメモリ上のファイルキャッシュは一杯になるでしょう。)
結果はやはり9ms/回でした。HDDの書き込み速度がそこそこ速く、処理が間に合ったのでしょう。(しかしファイルキャッシュの効果は偉大だ)

ただそれにしても送信処理より受信処理が4倍かかるのはちょっと予想外に時間がかかりすぎです。これだと高速な圧縮処理使うより、(snappy使うより)多少時間かかってもデータサイズを小さく圧縮(高圧縮率)した方がトータルで性能が出るんでない?
試しにHDDへの書き込みだけコメントアウトして、socketの受信処理だけに絞って計測してみました。

結果は、変わらないでした。ちょっとびっくりしましたが、受信時のackパケットを250us毎に返していたのはTC/IPの受信スタックの処理時間が優勢のようです。TCP/IPの処理は重いとは聞いていましたが、これほどとは・・・ データの圧縮どうこう言う前に、socket通信を少しでも早くするために、socketのパケットサイズを調整しないといけません。

今回実験してみて感じたことをまとめてみます。


  • Linuxのファイルキャッシュはかなり強力だった。(テストプログラムを終了したあとも、しばらくHDDが動きっぱなしでした。実際に2GB強のデータをHDDに書き込まれたのはテストプログラム終了後しばらくしてからでしょう。)
  • TCP/IPの処理はかなり時間がかかる。今回、1回のloopで100KBをまとめてsend( )しましたが、パケットとしては35個に分割されていました。他に何台のPCがPC0に接続されるかによりますが、システムの利用状況に応じてパケットサイズを調整しないといけない。(あるいはこんなくらいの時間がかかると思ってシステムの設計を行うかのどちらか)
  • 結局、snappyの有効性確認ができる状況が作れませんでしたが、ある程度の圧縮率が見込める運用状況ならやった方がいいでしょう。(圧縮率200%が見込めるなら、単純にパケット長が半分になるので、上図の送信・受信処理時間も半分になってくれるはず。)
  • 収集データをHDDにロギングまでする必要があるというのはかなり特殊な用途ですが、1回のシステムの動作で10GBくらいのデータを収集するなら64bit OSマシンでオンメモリに保持した方がいい。今回2GB強のログサイズだったので、ファイルキャッシュがなんとかもったが、10GBくらいだとたぶんHDDの状態にも影響されるでしょう。(テストプログラム終了後のdisk I/Oがすごかったので、ちょっと怖くなった)


まあ、snappy使って送信データを圧縮・伸長しようなんてのは、たいていはクラウド系のシステムでの利用がほとんどでしょうから、今回の検討が特殊な状況だとは思います。

PS:
結論として高速にEtherで通信したいと思ったら、snappy等でデータを圧縮し、パケットのサイズを減らし(なんとか1パケットに抑えれるのがベスト!)、受信側の負荷を下げてやるのが一番いいということになると思います。



2013年10月5日土曜日

emacs内のshellで、変な文字コードが表示される時

Linuxでのプログラム開発のとき、自分はほとんどemacsでプログラミング/ビルド/デバッグおよび実行をします。(マウスを使ってwindowを切り替えるのが面倒)かなり昔からこのスタイルで、はやりの統合開発環境はあまり好きではありません。(さすがにJavaプログラムをするときはeclipse使いますが)
何年か前からですが、emacs内でshellを起動してファイル操作、実行等しているときに"ls"コマンドで変な文字コードが出るようになりました。(行末、行頭に何かの制御コード?)


自分はtcshが好みなんですが、やむをえずbashを起動すると正常になっていました。最近はUbuntu使うことが増えたので、デフォルトのbashを使うことも多くなったのですが、ところが最近のLinuxだとそれでもダメなことが増えてきて、本格的に調べてみました。
原因は"ls"がshell起動時にaliasされて、"ls --color=auto"になっていたことでした。ここ数年前から"ls"コマンドすると、ファイルの種類やディレクトリの表示を種類別にカラー表示してくれるようになるのがデフォルトになっていましたが、emacs内のshellにはカラー表示の機能がないため、その制御コードが表示されていました。
aliasを削除してもいいんですが、普段のコンソールでは便利なのでemacs等のshellだけ無効にするため、.bashrcの最後に以下の様な$TERM環境変数をチェックするif文を追加しました。(TERMにはGUI環境では通常"xterm"等が入っています)


ファイルの種類によるカラー表示はだめになりましたが、昔ながらの"-F"オプションで種類は識別できます。