I2CDeviceクラスの実装について

116 views
Skip to first unread message

Shigeru Kobayashi

unread,
Nov 2, 2008, 7:53:01 AM11/2/08
to funnel-de...@googlegroups.com
みなさま

小林です

先日遠藤さんから提案のあったI2Cを扱うための仕組みに関してですが、r507まででFunnel
Server側およびArduino側の対応(Arduino側はREAD CONTINUOUSが未実装ですが)を行いました。

それに対応するライブラリ側の実装検討として、RubyにI2CDeviceクラス、およびそのサブクラスであるHMC6352クラスを追加してみました。
http://code.google.com/p/funnel/source/detail?r=508

HMC6352はSparkFunで扱っているコンパスモジュールで、日本でもスイッチサイエンスやストロベリーリナックスで購入できます。
http://www.sparkfun.com/commerce/product_info.php?products_id=7915
http://www.switch-science.com/products/detail.php?product_id=55

2つのクラスの実装はこちらです。
http://code.google.com/p/funnel/source/browse/trunk/libraries/ruby/funnel/i2c.rb?spec=svn508&r=508

実際に使う時には、次のようにして使います。

config = Arduino.FIRMATA
@aio = Arduino.new :config => config

compass = HMC6352.new @aio

10.times do
# compassのheadingプロパティを参照して現在の方位角を表示する
puts "heading: #{compass.heading}"
sleep 0.5
end

ここで、HMC6352のコンストラクタにIOModuleクラスのインスタンスを渡しているのですが、これはこのインスタンスを介してSysEx関連のやり取りを行うためです。実際にも、I2CデバイスはI/Oモジュールにぶら下がるものですので、この形式は一つの方法かなと思います。

他の方法としては、

config = Arduino.FIRMATA
@aio = Arduino.new :config => config

compass = HMC6352.new
aio.add compass

のように、add()のようなメソッドをIOModuleに用意して、I2Cデバイスのインスタンスを追加する、というものです。どちらも、実装上の問題や手間などはほとんど変わらないと思いますので、どちらが自然に見えて使いやすいか、で決めてしまっていいのだと思います。また、他にもっと良い案があればそれも含めて、意見やコメントなどをお願いします。;)

Shigeru Kobayashi

unread,
Nov 4, 2008, 9:18:08 AM11/4/08
to funnel-de...@googlegroups.com
みなさま

小林です

AvagoのADJD-S371-QR999とBlinkMでもテストしてみました。Arduino
Nanoでテストしましたが、いずれも想定したような動作をしてくれているようです。Rubyライブラリにはこの2つを追加しました。

http://code.google.com/p/funnel/source/browse/trunk/libraries/ruby/funnel/i2c.rb?spec=svn510&r=510

BlinkMはいいのですが、ADJD-S371-QR999のクラス名は悩みどころです。とりあえずADJD_S371_QR999としてありますが、これはクラス名としては(言語仕様として許してくれますが)不自然ですよね…。かといって、メーカ名のAvagoだけだとセンサ以外にもたくさん製品がありますので…。

以上、取り急ぎのご報告でした。


2008/11/2 Shigeru Kobayashi <koto...@gmail.com>:

takanori endo

unread,
Nov 5, 2008, 12:52:55 AM11/5/08
to funnel-de...@googlegroups.com
遠藤です
とりあえずrubyで動作確認しようとしましたが、うまくいきませんでした。

arduinoにはSimpleI2CFirmataを書き込み
サーバーはr505を使っています。

require 'funnel'
include Funnel

config = Arduino.FIRMATA
@aio = Arduino.new :config => config

compass = HMC6352.new @aio

10.times do
# compassのheadingプロパティを参照して現在の方位角を表示する
puts "heading: #{compass.heading}"
sleep 0.5
end

sleep 1

というコードを実行すると

command port: localhost, 1761
Rebooted successfully
Configured successfully
OK: /polling
heading: 0
heading: 0
heading: 0
heading: 0
heading: 0
heading: 0
heading: 0
heading: 0
heading: 0
heading: 0

となり、出力がとれません。

センサーの接続は別のプログラムで取得できましたので、正しいのではないかと思います。

なにかチェック項目はありますか?

遠藤孝則

2008/11/04 23:18 Shigeru Kobayashi <koto...@gmail.com>:

--
endo takanori

Shigeru Kobayashi

unread,
Nov 5, 2008, 1:14:16 AM11/5/08
to funnel-de...@googlegroups.com
遠藤さん

小林です

すみません、サンプルとして示したコードが1行抜けておりまして、正しくは

10.times do
# compassのheadingプロパティを参照して現在の方位角を表示する
compass.update # 手動でアップデートする


puts "heading: #{compass.heading}"
sleep 0.5
end

です。

ファーム側できちんと実装されればupdateの呼び出しは必要なくなるのですが、現状では実装されていないため、明示的な呼び出しが必要になります。


2008/11/5 takanori endo <sweeta...@gmail.com>:

takanori endo

unread,
Nov 5, 2008, 1:55:12 AM11/5/08
to funnel-de...@googlegroups.com
ありがとうございます。

動きました。

遠藤孝則


2008/11/05 15:14 Shigeru Kobayashi <koto...@gmail.com>:

--
endo takanori

takanori endo

unread,
Nov 5, 2008, 4:14:34 AM11/5/08
to funnel-de...@googlegroups.com
遠藤です。


#define I2C 0x76 // I2C read/write message

/* IC2 read/write
* -------------------------------
* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 read/write
0 => write
1 => read once
2 => read continuously
3 => stop reading
* 3 slave address (7bit)
* 4 data 0 (LSB)
* 5 data 0 (MSB)
* 6 data 1 (LSB)
* 7 data 1 (MSB)
* ...
* n END_SYSEX (0xF7) (MIDI End of SysEx - EOX)
*/


example: read a value of a slave device

1. Host => Arduino
* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 1 (read)
* 3 slave address
* 4 register to read (LSB)
* 5 register to read (MSB)
* 6 bytes to read (LSB)
* 7 bytes to read (MSB)
* 8 END_SYSEX (0xF7) (MIDI End of SysEx - EOX)

2. Ardino => Host
* 0 START_SYSEX (0xF0) (MIDI System Exclusive)
* 1 I2C (0x76)
* 2 slave address (LSB)
* 3 slave address (MSB)
* 4 register (LSB)
* 5 register (MSB)
* 6 data 0 LSB
* 7 data 0 MSB
* ...
* n END_SYSEX (0xF7) (MIDI End of SysEx - EOX)


これって今まで通りですよね?
サーバーにsysexで、パケット作っておくっても出力が帰ってこないのですが、
サーバーでなにか変更はありましたか?
writeで送った時も、サーバー側からsysexが戻ってくるようですが
こんな感じでしたか?すいません。忘れてしましました。

2008/11/05 15:55 takanori endo <sweeta...@gmail.com>:

--
endo takanori

Shigeru Kobayashi

unread,
Nov 5, 2008, 10:12:34 AM11/5/08
to funnel-de...@googlegroups.com
遠藤さん

小林です

※すみません、送信ミスで送信できていませんでした。

変更個所について確認してみますね。SysExの送り方に関しては違いがないはずなのですが…。

送っているのは以下のソースをみていただくと一番わかりやすいかと思います。

libraries/ruby/funnel/i2c.rb

考えられるとすると、サーバが担当うすべきLSB/MSBの分割をクライアント側でしてしまっている、とかでしょうか。

takanori endo

unread,
Nov 6, 2008, 2:52:10 AM11/6/08
to funnel-de...@googlegroups.com
通信できました。

一点確認なのですが、レジスタから読み出すときは
readを呼ぶだけでOKなのですね?

1. I2Cで読み出したいアドレスを指定(write)
2. I2Cで読み出しを実行(read)
3. 1で指定したアドレスのデータが読み出される

で、writeとreadをそれぞれ送るという方法でやっていました。

SimpleI2CFirmataでは
readのなかに、このような処理が入っていますよね?


とりあえず、確認できたのでつづきをやります

遠藤孝則


2008/11/06 0:12 Shigeru Kobayashi <koto...@gmail.com>:

--
endo takanori

Shigeru Kobayashi

unread,
Nov 6, 2008, 2:53:19 AM11/6/08
to funnel-de...@googlegroups.com
遠藤さん

小林です

> 一点確認なのですが、レジスタから読み出すときは
> readを呼ぶだけでOKなのですね?

すみません、その通りです。


> とりあえず、確認できたのでつづきをやります

はい、また何かありましたらお願いいたします。


2008/11/6 takanori endo <sweeta...@gmail.com>:

endo

unread,
Nov 16, 2008, 8:30:57 AM11/16/08
to funnel-dev-talk-ja
遠藤です。

すいません。ちょっと、間が開きましたが、
メールがちゃんとおくれていませんでした。

ーーーーーーーーー

あまり意味がないのですがRTCでテストしています。

よみだすレジスタがいろいろな場所になりますので、
読みだしたデータがどのレジスタから読みだしたものかが
わかるように、返事のパケットに読み出し元のレジスタアドレスを加える
わけにはいかないでしょうか?

Readするときに読み出しのレジスタも指定しますが、返事が同期で
かえってくるわけではないのでちょっとうまく作れないでいます。

センサー用途とかだったら、いつもレジスタを読むような感じでも
良さそうですが。

遠藤孝則


On 11月6日, 午後4:53, "Shigeru Kobayashi" <kotob...@gmail.com> wrote:
> 遠藤さん
>
> 小林です
>
> > 一点確認なのですが、レジスタから読み出すときは
> > readを呼ぶだけでOKなのですね?
>
> すみません、その通りです。
>
> > とりあえず、確認できたのでつづきをやります
>
> はい、また何かありましたらお願いいたします。
>
> 2008/11/6 takanori endo <sweetamana...@gmail.com>:
>
>
>
> > 通信できました。
>
> > 一点確認なのですが、レジスタから読み出すときは
> > readを呼ぶだけでOKなのですね?
>
> > 1. I2Cで読み出したいアドレスを指定(write)
> > 2. I2Cで読み出しを実行(read)
> > 3. 1で指定したアドレスのデータが読み出される
>
> > で、writeとreadをそれぞれ送るという方法でやっていました。
>
> > SimpleI2CFirmataでは
> > readのなかに、このような処理が入っていますよね?
>
> > とりあえず、確認できたのでつづきをやります
>
> > 遠藤孝則
>
> > 2008/11/06 0:12 Shigeru Kobayashi <kotob...@gmail.com>:
>
> >> 遠藤さん
>
> >> 小林です
>
> >> ※すみません、送信ミスで送信できていませんでした。
>
> >> 変更個所について確認してみますね。SysExの送り方に関しては違いがないはずなのですが...。
>
> >> 送っているのは以下のソースをみていただくと一番わかりやすいかと思います。
>
> >> libraries/ruby/funnel/i2c.rb
>
> >> 考えられるとすると、サーバが担当うすべきLSB/MSBの分割をクライアント側でしてしまっている、とかでしょうか。
>
> >> 2008/11/5 takanori endo <sweetamana...@gmail.com>:
> >>> 2008/11/05 15:55 takanori endo <sweetamana...@gmail.com>:
> >>>> ありがとうございます。
>
> >>>> 動きました。
>
> >>>> 遠藤孝則
>
> >>>> 2008/11/05 15:14 Shigeru Kobayashi <kotob...@gmail.com>:
>
> >>>>> 遠藤さん
>
> >>>>> 小林です
>
> >>>>> すみません、サンプルとして示したコードが1行抜けておりまして、正しくは
>
> >>>>> 10.times do
> >>>>> # compassのheadingプロパティを参照して現在の方位角を表示する
> >>>>> compass.update # 手動でアップデートする
> >>>>> puts "heading: #{compass.heading}"
> >>>>> sleep 0.5
> >>>>> end
>
> >>>>> です。
>
> >>>>> ファーム側できちんと実装されればupdateの呼び出しは必要なくなるのですが、現状では実装されていないため、明示的な呼び出しが必要になります。
>
> >>>>> 2008/11/5 takanori endo <sweetamana...@gmail.com>:
> >>>>>> 2008/11/04 23:18 Shigeru Kobayashi <kotob...@gmail.com>:
>
> >>>>>>> みなさま
>
> >>>>>>> 小林です
>
> >>>>>>> AvagoのADJD-S371-QR999とBlinkMでもテストしてみました。Arduino
> >>>>>>> Nanoでテストしましたが、いずれも想定したような動作をしてくれているようです。Rubyライブラリにはこの2つを追加しました。
>
> >>>>>>>http://code.google.com/p/funnel/source/browse/trunk/libraries/ruby/fu...
>
> >>>>>>> BlinkMはいいのですが、ADJD-S371-QR999のクラス名は悩みどころです。とりあえずADJD_S371_QR999としてありますが、これはクラス名としては(言語仕様として許してくれますが)不自然ですよね...。かといって、メーカ名のAvagoだけだとセンサ以外にもたくさん製品がありますので...。
>
> >>>>>>> 以上、取り急ぎのご報告でした。
>
> >>>>>>> 2008/11/2 Shigeru Kobayashi <kotob...@gmail.com>:
> >>>>>>>> みなさま
>
> >>>>>>>> 小林です
>
> >>>>>>>> 先日遠藤さんから提案のあったI2Cを扱うための仕組みに関してですが、r507まででFunnel
> >>>>>>>> Server側およびArduino側の対応(Arduino側はREAD CONTINUOUSが未実装ですが)を行いました。
>
> >>>>>>>> それに対応するライブラリ側の実装検討として、RubyにI2CDeviceクラス、およびそのサブクラスであるHMC6352クラスを追加してみました。
> >>>>>>>>http://code.google.com/p/funnel/source/detail?r=508
>
> >>>>>>>> HMC6352はSparkFunで扱っているコンパスモジュールで、日本でもスイッチサイエンスやストロベリーリナックスで購入できます。
> >>>>>>>>http://www.sparkfun.com/commerce/product_info.php?products_id=7915
> >>>>>>>>http://www.switch-science.com/products/detail.php?product_id=55
>
> >>>>>>>> 2つのクラスの実装はこちらです。
> >>>>>>>>http://code.google.com/p/funnel/source/browse/trunk/libraries/ruby/fu...

endo

unread,
Nov 16, 2008, 7:04:10 PM11/16/08
to funnel-dev-talk-ja

あーすいません。
勘違いしてました。
現状でも、取得先のアドレスは戻ってきてますね。


遠藤孝則
> ...
>
> もっと読む >>

Shigeru Kobayashi

unread,
Nov 16, 2008, 7:46:32 PM11/16/08
to funnel-de...@googlegroups.com
遠藤さん

小林です

はい。現状でも取得先のアドレスとレジスタは報告している「はず」です。が、もしかしたらバグがあるかもしれませんので、何かおかしなところがあればお知らせください。

あと、複数のアドレス/レジスタを指定しての連続読み出しは、この後で実装してみます。


2008/11/17 endo <SweetA...@gmail.com>:

Shigeru Kobayashi

unread,
Nov 17, 2008, 12:38:42 AM11/17/08
to funnel-de...@googlegroups.com
遠藤さん

小林です

先ほどコミットしたもので、READ_CONTINUOUSにも対応できるようにしてみました。複数アドレスを読み出すI2Cデバイスが手元にないため、とりあえずコンパスのみで実装してあります。

http://code.google.com/p/funnel/source/detail?r=518

・・・

単にレジスタを読めばそれで値が取得できるHMC6352のようなデバイスはこれで良いのですが、ADJD-S371-QR999のように、サンプリング開始を指示しなければならないものだと、自動取得にはできませんよね。

フィルタなどと同様に、I2CDeviceの派生クラスのインスタンすの場合にも、update()メソッドを呼び出すようにする仕組みを設けた方がいいかなと思うのですが、いかがでしょうか?


2008/11/17 Shigeru Kobayashi <koto...@gmail.com>:

takanori endo

unread,
Nov 17, 2008, 1:18:29 AM11/17/08
to funnel-de...@googlegroups.com
遠藤です。009に対応するI2Cの機能を追加しました。

一応動いているのですが、コンパスを使ったときに
動作がちょっと変で、キャリブレーションもうまくできてないです。


i2cのクラスがたくさん増えるかと思って、パッケージを分けてみました。
不便だったら元に戻すかもしれません。





テストコードを付けます。
-----------------------------------------

import processing.funnel.*;
import processing.funnel.i2c.*;

Arduino arduino;
HMC6325 compass;
float heading;

void setup()
{
size(200, 200);

Configuration config = Arduino.FIRMATA;

arduino = new Arduino(this,config);
compass = new HMC6325(arduino.iomodule());

smooth();
strokeWeight(2.0f);

ellipseMode(RADIUS);
fill(230,230,230);

frameRate(10);
}

void draw()
{

if(!mousePressed){
compass.update();
}
pushMatrix();
background(200,200,200);
translate(width/2,height/2);

stroke(10,10,40);
ellipse(0,0,85,85);
stroke(230,30,40);

//

line(0,0,80*cos(radians(0)),80*sin(radians(0)));
line(0,0,80*cos(radians(compass.heading)),80*sin(radians(compass.heading)));

popMatrix();
}


void keyPressed()
{
if(key=='c'){
compass.enterCalibrationMode();

float start = millis();

float t=0;
int i=0;
while(t < 20000){

delay(1000);
println(i++);
t = millis() - start;
}
compass.exitCalibrationMode();
println("finish");

}
}


2008/11/17 14:38 Shigeru Kobayashi <koto...@gmail.com>:
--
endo takanori

takanori endo

unread,
Nov 17, 2008, 1:43:55 AM11/17/08
to funnel-de...@googlegroups.com
遠藤です。
単純にシフトの仕方が間違っていました。
これで、ただしく動いているようにおもえます。

遠藤孝則


2008/11/17 15:18 takanori endo <sweeta...@gmail.com>:
--
endo takanori

Shigeru Kobayashi

unread,
Nov 17, 2008, 1:44:21 AM11/17/08
to funnel-de...@googlegroups.com
小林です

サンプルコードをこちらでも試してみました。確かに、急に値がジャンプしたりしておかしいですね…。

こちらでももう少し追いかけてみたいと思います。


追伸
テスト中に気がついたのですが、Ruby版のサンプルではcontinuous
modeを使うようにしています。これを使った後(=一定間隔ごとに自動的にデータが飛んでくるようになった後)でProcessingから利用しようとすると、以下のようなエラーが出て停止してしまうようです。

終了時、Funnel ServerからI2Cの停止を指示するようにしてみますが、もしクライアント側でも対応できるようでしたらお願いします。

2008-11-17 15:40:51.816 java[10496] CFLog (0): CFMessagePort:
bootstrap_register(): failed 1103 (0x44f), port = 0x11b03, name =
'java.ServiceProvider'
See /usr/include/servers/bootstrap_defs.h for the error codes.
2008-11-17 15:40:51.816 java[10496] CFLog (99):
CFMessagePortCreateLocal(): failed to name Mach port
(java.ServiceProvider)

opened host address 127.0.0.1
ececCode /reset

Exception in thread "Animation Thread" java.lang.NullPointerException
at processing.funnel.Arduino.waitMessage(Arduino.java:117)
at processing.funnel.IOSystem$CommandTokenizer.acceptMessage(IOSystem.java:494)
at com.illposed.osc.utility.OSCPacketDispatcher.dispatchMessage(Unknown Source)
at com.illposed.osc.utility.OSCPacketDispatcher.dispatchMessage(Unknown Source)
at com.illposed.osc.utility.OSCPacketDispatcher.dispatchPacket(Unknown Source)
at processing.funnel.CommandPort.receive(CommandPort.java:153)
at processing.funnel.OSCClient.waitFunnel(OSCClient.java:73)
at processing.funnel.IOSystem.execCode(IOSystem.java:227)
at processing.funnel.IOSystem.reboot(IOSystem.java:292)
at processing.funnel.IOSystem.initialize(IOSystem.java:263)
at processing.funnel.Arduino.<init>(Arduino.java:49)
at processing.funnel.Arduino.<init>(Arduino.java:62)
at sketch_081117a.setup(sketch_081117a.java:33)
at processing.core.PApplet.handleDraw(PApplet.java:1371)
at processing.core.PApplet.run(PApplet.java:1299)
at java.lang.Thread.run(Thread.java:613)


2008/11/17 takanori endo <sweeta...@gmail.com>:

Shigeru Kobayashi

unread,
Nov 17, 2008, 2:02:45 AM11/17/08
to funnel-de...@googlegroups.com
遠藤さん

小林です

r521で動作確認しました。手元のArduino Nanoとコンパスもジュールの組み合わせで、いい感じで動いているようです。:)


2008/11/17 Shigeru Kobayashi <koto...@gmail.com>:
Reply all
Reply to author
Forward
0 new messages