NSEG勉強会 feat. 高専カンファレンスの感想

2012年6月23日に長野で行われた「NSEG勉強会 feat. 高専カンファレンス」についての記事です。

勉強会の開催情報は↓のページに載っています。
NSEG勉強会 feat. 高専カンファレンス - 高専カンファレンス Wiki

前回の日記に書きましたが、今回の勉強会には発表者として参加してきました。
これまでにも長野へ行くチャンスはあったのですが、体調不良で過去のチャンスを逃したため、今回が初めての長野となりました。
長野って近いようで遠いなーと思いました。

長野に着くなりお約束のお蕎麦を食べたのですが、写真撮りそこねてしまいました。
ちゃんと写真撮っとけばよかったなー。
信州そば美味しかったです。

今回の発表は実はiPadを使ってやろうかなーと思い、iPadからVGA出力をするアダプタも購入したのですが、
なぜかきちんと出力されず、結局諦めてノートPCを使ってプレゼンしました。
ちょっと悲しかったです(´;ω;`)

DSC_7174

信州大学の教官の方の発表は、畑違いではあったものの話が面白くすごくわかり易く感じました。
実際の教育機関で教鞭をとられている人はさすがだなーと思いました。

今回の勉強会はばりばりのソフトウェア畑の勉強会ということで、
開発よりのお話が多かったかなーと思います。
その割にガチガチの技術ネタばかりではなかったので、
わりととっつきやすい感じの勉強会だったかなという印象を持ちました。

あと、長野周辺の方が半数を占めるのもあってか、
NSEGというのはかなりアットホームな感じの勉強会なのだなーと感じました。
長野にいるソフトウェア技術者の方は顔を出してみれば、きっと優しく迎え入れてくれると思いますよ。

今回発表の場を提供して頂いたNSEG感じのおびなたさん、
勉強会運営スタッフのみなさん、
私の話を聞いて頂いた参加者の皆さん、
どうもありがとうございました。

「NSEG勉強会 feat. 高専カンファレンス」に参加してます。

まだ終わってないので感想は後ほど。

長野で行われている「NSEG勉強会 feat. 高専カンファレンス」に参加しています。

私も15分の枠を頂いて発表をしてきました。

タイトルは「Hello, Ruby!」で、mrubyの紹介と私の作っているjamrubyの紹介の話をしてきました。
発表資料はこちらです。


DropBoxのリンク : https://www.dropbox.com/s/ajb5pp9qtt13aeb/HelloRuby.pdf


発表の様子は録画されているそうなので、Ustreamで見られなかった方も後ほど公開される予定の録画をご覧頂くことができるそうです。

AndroidのPreferenceを簡単に使いたい

AndroidでPreference関係の処理書くのすごーく面倒なんですよねー。
もう面倒すぎて鼻血でそうな感じですよね。
なので、うまいこと使える部品使って使い回したいなーっと。

そういうことで最近はこんな感じのコード書いてます。

public class Preferences {
	private static SharedPreferences prefs;
	private static Resources res;
	
	public static void create(Context context) {
		if (null == prefs || null == res) {
			prefs = PreferenceManager.getDefaultSharedPreferences(context);
			res = context.getResources();
		}
	}
	
	public static String getHoge() {
		return get(R.string.pref_key_hoge, getString(R.string.pref_defval_hoge));
	}
	
	private static String getString(int id) {
		return res.getString(id);
	}
	
	@SuppressWarnings("unchecked")
	private static <T> T get(int id, T defVal) {
		final Map<String, ?> map = prefs.getAll();
		final String key = getString(id);
		if (!map.containsKey(key)) {
			return defVal;
		}
		return (T)map.get(key);
	}
}

Preferences#createをActivityのonCreateとかonStartとかonResumeとかで適宜呼び出します。
AndroidのSingletonはアプリケーションのlife cycleにあわせて自動的にunloadされる可能性があるので気をつけてくださいね☆)

内部で設定項目を取得するのは" T get(int id, T defVal)"を呼び出します。
デフォルト値やキーは基本的にリソースに追い出して使う前提なので、
"String getString(int id)"でリソースから文字列を取得できるようにしています。

こんな感じのラッパーを書いておけば設定項目へのアクセスが楽になるかなーと思います。

jamrubyのリポジトリを分離しました。

jamruby関連のリポジトリを、私個人のリポジトリから移動しました。
jamruby専用のアカウントをgithubに作ったので、
以後はそちらからソースを引っ張って頂けると良いかなと思います。

https://github.com/jamruby

しばらくは私個人のリポジトリにもpushしますが、
どこかのタイミングから完全に移行したいなと思っています。

jamrubyの状況ですが、ちまちまとmrubyのAPIのラッパーを書いています。
まだたくさん追加すべき部分があるので、まずはここをある程度やってしまおうと思います。

Androidのセンサーで気をつけるべきこと

「気をつけるべきこと」とか書きましたが、
ありていに言えば「自分がはまったのでくやしい!ぐぬぬ!」ってことですね。

ということでAndroidのセンサーから値を取得する上で、気をつけなきゃいけないこと書いておきます。


  1. SensorManager取得時に指定したセンサーのタイプを信用するな。
  2. SensorのResolutionはよくわからない。


具体的にどういうことかコードを見ていきましょう。

Androidでセンサーの値を取るときはこんな感じのコードを書きます。

@Override
void onCreate(Bundle savedInstanceState) {
    ...
    final SensorManager mgr = (SensorManager)getSystemService(SENSOR_SERVICE);
    final Sensor acc = mgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    mgr.registerListener(listener, acc, SensorManager.SENSOR_DELAY_NORMAL);
}

private final SensorEventListener listener = new SensorEventListener() {
    @Override
    public void onSensorChanged(SensorEvent event) {
        ...
    }
		
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }
};

このとき、SensorManagerに対して指定したセンサータイプのセンサのイベントが取れるようになります。
きっと取れると思います。取れるはずなんです。本当なら。
でも実はうまくいかないことがよくあります。
で、よくよく調べてみると、Android端末のいくつかでは指定したセンサータイプと、
getDefaultSensorで実際に取得できるセンサーの物理的な種類が一致していないことがわかりました。
そりゃうまく動かないわけですよ。
だって加速度センサの値が欲しいのに実際には磁気センサを取得してたりするんですから。


これをどうやって回避するかというと、実際に取得したいセンサに関連する他の論理センサも動作させるということを行います。
具体的なコードで説明をすると、

final Sensor acc = mgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mgr.registerListener(listener, acc, SensorManager.SENSOR_DELAY_NORMAL);

final Sensor ori = mgr.getDefaultSensor(Sensor.TYPE_ORIENTATION);
mgr.registerListener(listener, ori, SensorManager.SENSOR_DELAY_NORMAL);

final Sensor mag = mgr.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mgr.registerListener(listener, mag, SensorManager.SENSOR_DELAY_NORMAL);

こんなふうにして関連するセンサを全部使用します。
後はイベントを受ける側で、どのイベントが来たかを振り分けてあげればうまくいきます。
(どうして加速度センサと磁気センサと傾きセンサが関連するかの説明は省略します)

private final SensorEventListener listener = new SensorEventListener() {
    @Override
    public void onSensorChanged(SensorEvent event) {
        switch(event.sensor.getType()) {
        case Sensor.TYPE_ACCELEROMETER:
            ...
            break;
        }
    }
		
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }
};

次にSensorのResolutionですが、名前からして測定値を物理量に変換するのに使用するものだと思うじゃないですか普通は(たぶん普通の感覚だよね?)。
でもこれ、実は実装によってはただの固定値であまり意味のある値が入っていません。
Resolutionを使わなくても、普通に値を使えば物理量に単位変換された値が入っています。
Resolutionの単位も実装依存のため、何のために存在するかいまいちわかりません。
なので間違っても↓みたいなコードは書いちゃだめですよ!ダメ、ゼッタイ!

private final SensorEventListener listener = new SensorEventListener() {
    @Override
    public void onSensorChanged(SensorEvent event) {
        final float res = event.sensor.getResolution();
        switch(event.sensor.getType()) {
        case Sensor.TYPE_ACCELEROMETER:
            final float accX = event.value[0] * res;
            // do something
            ...
            break;
        }
    }
		
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }
};

↑こういうことしちゃダメですよ!

jamrubyのこれから

jamrubyをちゃんとやろうかなぁーと思いまして、
今回jamruby用にドメインとったりする作業をしています。
まだもうちょっと時間がかかりますが、
準備が出来次第jamrubyのgithubアカウントを別に用意したり、
エントランス用のページを用意したりしようかなと思います。

開発ももちろん続けます。
とりあえず現状でできる範囲を拡大して、

  • Ruby側への動的なメソッドなどの追加
  • Java側のメソッド呼び出し機能の提供
  • Android依存部分の切り出し(Android以外のPlatformのサポート)

などをしたいなぁと考えています。


とりあえず準備が出来次第、また改めてこのブログにでも続報を掲載しようと思います。

mrubyの話というかただのC言語の話

つい先日mrubyのissue trackingを使ってとある議論をしていました。
該当のページはこれですね。

Inappropriate assumption about the pointer address.

ここで何人かのお話にあったのは、ざっくりと以下の3つのことかなと思っています。
ちなみに内容はmrubyというよりはmruby中のコードがC言語の規格にてらして問題があるかどうかって話です。

  1. NULLが0でないケースがあって、その場合にpointerとvalueの変換および比較が問題になるケースがあるよってこと。
  2. intptr_tをvoid*に変換してさらにそれを元に戻せることが保証されてるか?
  3. intptr_tが完全にportableでないから使いたくないよ。


で、このうち1.については、いくつかの前提を置くことでクリアしていることがわかりました。
次の2.については、C言語の規格上、intptr_tをvoid*に変換することは許可されているので問題無いわけです。
(詳しくはC言語規格書のドラフト版(リンク先PDF注意)の「7.20.1.4 Integer types capable of holding object pointers」とか読むと良いですね。)
最後の3.については、intptr_tが関数ポインタを保持できないというお話かなと思います。
これは言語規格上許されていない(pointer to functionとpointer to objectまたはpointer to voidの相互変換ができると書いていない)ので、そもそもやっちゃダメよということですね。


話の中でunion使おうぜってことになってるんですが、なぜunionの話になってるのか私にはいまいち理解できないんだけど、とりあえずフォローアップの記事ということで。