PiRT-Unitを利用したIOプログラミング

この Book では、Raspberry Pi と PiRT-Unit を組み合わせてOpenRTM-aist から利用する方法を解説します。

PiRT-Unit を利用する

PiRT-Unit は産総研で開発された、Raspberry Pi用 IO拡張ボードです。 ウィン電子工業から発売中です。

PiRT-Unit からは、AD (4ch)、DA (2ch)、PWM (1ch)、I2C (1ch)、RS232C/XBee (1ch) がそれぞれ利用できます。

pirt-unit_connectors.png
PiRT-Unit 入出力コネクタ配置図

特長

  • アナログ入力 (10bit ADC x 4ch) 利用可能
  • アナログ出力 (12bit DAC x 2ch) 利用可能
  • PWM x1ch: RCサーボモーター利用可能
  • I2C シリアル通信利用可能
  • RS232C Dsub コネクタ利用可能
  • Xbee接続用コネクタ利用可能(上記 RS232C との選択式)
  • 5V DC入力: Raspberry Pi に電源供給可能
    • 秋月電子等で安価に購入可能な ACアダプタを利用できます

仕様

Raspberry Pi拡張IOボード
ADコンバータ 10bit, 4ch
チップ: ADC104S021
サンプリング 200kHz
DAコンバータ 12bit, 2ch
チップ MCP4822
PWM出力 1ch, RCサーボモータードライブ用
フォトカプラ絶縁
RS232C D-SUB 9pinコネクタ
XBee とジャンパにて切り替え
XBee XBee接続コネクタ
XBee: Digi International 製 Zigbeeモジュール
XBee とジャンパにて切り替え
電源入力 5V DC入力
Raspberry Piに電源供給可能
Raspberry Piからの電源供給でも動作

pirtunit_blockdiagram.png
PiRT-Unit 回路ブロック図

PiRT-Unitのためのシステム設定

Raspberry Pi のデフォルトの設定 (raspbian armhf) では、SPI デバイスなどは利用できません。 ここで、PiRT-Unit を利用するために必要なデバイスの設定やプログラミング環境の構築を行います。

セットアップスクリプト

以下の内容をスクリプト化したものがこちらにあります。

Raspberry Pi のサイトからダウンロードしたイメージの適当な場所にダウンロードして以下のように実行します。

 $ wget http://svn.openrtm.org/Embedded/trunk/RaspberryPi/tools/rpi.sh
 $ chmod 755 rpi.sh
 $ sudo rpi.sh rtunit0 --type rtunit
 $ sudo rpi.sh rtunit0 --type rtunit_examples

以上で、以下の PiRT-Unit を利用するために行っている設定、パッケージのインストール、サンプルのインストールが自動で行われます。 バージョンアップ、ファイル配置の変更などによってエラーが出た場合にはメーリングリストなどへお知らせください。

rpi.sh ヘルプ

 Usage: rpi.sh hostname --type <TYPE>
 
 TYPE are:  basic kobuki kobuki_only rtunit rtunit_only
   basic:           Installing avahi, cmake, subversion/git and OpenRTM
   kobuki:          Installing basic + Kobuki RTC
   kobuki_only:     Installing Kobuki RTC only
   rtunit:          Installing basic + spi/i2c tools and modules
   rtunit_only:     Installing spi/i2c tools and modules only
   rtunit_examples: Installing basic + PiRT-Unit examples
 
 EXAMPLE:
 1) Just change hostname
 # rpi.sh kobuki0
 
 2) Basic setup: Installing OpenRTM-aist (C++/Python)
 # rpi.sh kobuki --type basic
 "
 3) Kobuki setup: Installing OpenRTM-aist (C++/Python) and Kobuki RTC
 # rpi.sh kobuki --type kobuki

システム設定ファイルの変更

spi と i2c のデバイスモジュールをロードする方法は、カーネルの3.18から変更になりました。Raspberry Pi用 OS Raspbian が2015年のバージョンから該当するようですが、カーネルのバージョンを確認して判断してください。
spi と i2c を利用するためには、raspi-config で Enable に設定します。Raspberry Pi の初期設定 のページをご覧ください。

これより古いバージョンでは、以下のファイルを設定します。

raspi-blacklist.conf の編集

/etc/modprobe.d/raspi-blacklist.conf に

 blacklist spi-bcm2708
 blacklist i2c-bcm2708

という2行が設定されていますが、これをコメントアウトします。

 # blacklist spi and i2c by default (many users don't need them)
 
 #blacklist spi-bcm2708
 #blacklist i2c-bcm2708

これで、spi と i2c のデバイスモジュールがロードされるようになります。

udev rules の設定

spi や i2c デバイスモジュールがロードされても、デフォルトでは一般ユーザーからアクセスできないようなパーミッションに設定されています。 少々不便なので、デバイス作成時に誰でもアクセスできるように設定しておきます。 新たに、/etc/udev/rules.d/50-udev.rules というファイルを作成し、中に以下の1行を追記します。

 KERNEL=="spidev*", SUBSYSTEM=="spidev", GROUP="spi", MODE="0666"

以上で準備は終了です。

Python 拡張モジュールのインストール

PiRT-Unit では AD および DA は SPI経由で接続されており、SPI デバイスを制御する Python モジュールをインストールすることで、Python から手軽に AD および DA を利用することができます。

事前準備

Python から SPI経由で AD、DA を利用するには、以下の拡張モジュールをインストールします。

下準備のため、以下のパッケージをインストールします。

  • python-dev
  • git-core
  • i2c-tools
  • python-smbus
  • python-setuptools

 sudo apt-get update
 sudo apt-get upgrade
 sudo apt-get install python-dev git-core i2c-tools python-smbus

py-spidev のインストール

py-spidev は github https://raw.github.com/doceme/py-spidev にあります。以下のようにしてインストールします。

 $ cd ~ (or 適当なディレクトリー)
 $ git clone git://github.com/doceme/py-spidev 
 $ cd py-spidev
 $ chmod 755 setup.py
 $ sudo ./setup.py install

これで、Python モジュール py-spidev が利用できるようになります。 試しに、spidev モジュールを利用してみます。

 $ sudo python
 sudo: unable to resolve host raspbian-armhf
 Python 2.7.3 (default, Jan 13 2013, 11:20:46)
 [GCC 4.6.3] on linux2
 Type "help", "copyright", "credits" or "license" for more information.
 >>> import spidev
 >>> spi = spidev.SpiDev()
 >>> spi.open(0,0)
 >>> print spi.xfer2([0x00,0,0,0])

これで、CN2のAD変換器の値を読みだしてプリントしています。AD変換器 (ADC104S021) は10bitのシングルエンド型で、サンプリングレートは最大200kHzです。(Linux上で200kHzのサンプリングレートを保証するものではありません。) 実際には、"spi.xfer2([0x00],0,0,0])" で出力される値を 1024 (bit) で割って、5.0 (V) を掛けた値が計測された電圧になります。

 >>> r = spi.xfer2([0x00,0,0,0])
 >>> print r[0] * 5.0 / 1024.0, " [V]"

ここまで、エラーなく実行できれば、spidev モジュールが正しくインストールされています。

WiringPi-Python のインストール

WiringPi-Python は GPIO を制御するツール: WiringPi を Python から利用するためのモジュールです。 まずは WiringPi をインストールします。

 $ git clone git://git.drogon.net/wiringPi
 $ cd cd wiringPi
 $ git pull origin
 $ ./build

次に、WiringPi-Python 本体を以下のようにインストールします。

 $ sudo apt-get install python-dev  
 $ git clone https://github.com/WiringPi/WiringPi-Python.git  
 $ cd WiringPi-Python  
 $ git submodule update --init  
 $ sudo python setup.py install

以上で、必要なモジュールのインストールは終了です。

IOのテスト

ここでは、PiRT-Unitの入出力をそれぞれ簡単にテストしてみます。

ADコンバータのテスト

PiRT-Unit の CN2-CN5 がADコンバータのピンです。 ピンアサインは以下の図のようになっており、GND-5V間を分圧したものを入力ピンに加えることでセンサ値などを読み取ることができるようになっています。

adc_circuit.png
ADコンバータと接続回路

ADコンバータをテストするもっとも簡単な方法は、Phidgetsのセンサを接続することです。 Phidgets は Phidgets Inc. から発売されている、IO拡張ボードとセンサ群製品です。 日本では、ぷらっとほーむなどで購入することができます。

PCにUSB接続の拡張IOボードを接続し、様々なセンサ、アクチュエータユニットを追加して、プログラム等から計測・制御することができるキットです。

PCと接続する場合は、Interface Kitが必要ですが、PiRT-Unitでのみ使用する場合は、Sensor Kitのみでよいでしょう。

PIRT-UnitのADピンは、Phidgetのセンサが接続可能なピンアサインとなっており、Phidgetデバイスを接続することで、容易に拡張することができるようになっています。

サンプルプログラム

adc_test.py

 #!/usr/bin/env python
 # -*- coding: euc-jp -*- 
 import sys
 import time
 import spidev
 
 class ADC:
   def __init__(self):
     self.spi = spidev.SpiDev()
     self.spi.open(0, 0)
 
   def get_value(self, channel):
     sned_ch = [0x00,0x08,0x10,0x18]
     if ((channel > 3) or (channel < 0)):
       return -1
     r = self.spi.xfer2([sned_ch[channel],0,0,0])
     ret = ((r[2] << 6 ) & 0x300) |  ((r[2] << 6) & 0xc0) | ((r[3] >> 2) & 0x3f)
     return ret     
 
   def get_voltage(self, channel):
     ret = self.get_value(channel) * 5.0 / 1024
     return ret     
 
 def main():
   adc = ADC()
   while 1:
     adc1 = adc.get_value(0)
     msg1 = "%1.5fV(%04x)" % ((float(adc1)*5/1024),adc1)
     print msg1,
 
     adc1 = adc.get_value(1)
     msg1 = "%1.5fV(%04x)" % ((float(adc1)*5/1024),adc1)
     print msg1,
 
     adc2 = adc.get_value(2)
     msg2 = "%1.5fV(%04x)" % ((float(adc2)*5/1024),adc2)
     print msg2,
 
     adc3 = adc.get_value(3)
     msg3 = "%1.5fV(%04x)" % ((float(adc3)*5/1024),adc3)
     print msg3,
 
     sys.stdout.write("\n")
     time.sleep(0.5)
 
 if __name__ == '__main__':
   main()

テスト

ADコンバータにピンに適当な可変抵抗やPhidgetセンサなどを接続して、adc_test.py を実行すると、下図のようにセンサ値を読み取ることができます。

ministick_teraterm.png
adc_test.py によるADコンバータの読み取り

DAコンバータのテスト

dac_test.py

 #!/usr/bin/env python
 # -*- coding: euc-jp -*- 
 import spidev
 from time import sleep
 
 spi = spidev.SpiDev()
 spi.open(0,1)
 
 def changeLevel(ch,  onOff, percent):
   bit7 = ch    << 7
   bit6 = 0     << 6
   bit5 = 1     << 5
   bit4 = onOff << 4
   size=12
   number=(2**size-1)*percent/100
   number= number<<(12-size)
   number= number<<(12-size)
   bottomPart= number % 256
   topPart=(number-bottomPart)>>8
   firstByte=bit7+bit6+bit5+bit4+topPart
   secondByte=bottomPart
   return spi.xfer2([firstByte,secondByte])
 
 
 def which_channel():
   channel = raw_input("Which channel do you want to test? Type 0 or 1.\n")
   while not channel.isdigit():
       channel = raw_input("Try again - just numbers 0 or 1 please!\n")
   return channel
 
 
 def main():
   channel = 3
   while not (channel == 1 or channel == 0):
       channel = int(which_channel())
   
   print "These are the connections for the digital to analogue test:"
   print "jumper connecting GP11 to SCLK"
   print "jumper connecting GP10 to MOSI"
   print "jumper connecting GP9 to MISO"
   print "jumper connecting GP7 to CSnB"
   print "Multimeter connections (set your meter to read V DC):"
   print "  connect black probe to GND"
   print "  connect red probe to DA%d on J29" % channel
   
   raw_input("When ready hit enter.\n")
   percent=[0,25,75,100]
   
   for p in percent:
       r = changeLevel(channel,1,p)
       print "Your meter should read about {0:.2f}V".format(p*2.048/100.0)
       raw_input("When ready hit enter.\n")
 
   r = changeLevel(0,0,0)
   r = changeLevel(1,0,0)
 
 if __name__ == '__main__':
   main()
 

I2Cのテスト

i2c_test.py

 #!/usr/bin/env python
 # -*- coding: euc-jp -*- 
 import smbus
 import time
 
 def main():
   # LCD initialize
   i2c = smbus.SMBus(1)
   addr = 0x3e
   contrast = 42   # 0-63
   i2c.write_byte_data(addr, 0, 0x38)  # function set(IS=0)
   i2c.write_byte_data(addr, 0, 0x39)  # function set(IS=1)
   i2c.write_byte_data(addr, 0, 0x14)  # internal osc
   i2c.write_byte_data(addr, 0,(0x70 | (contrast & 0x0f))) # contrast
   i2c.write_byte_data(addr, 0,(0x54 | ((contrast >> 4) & 0x03)))  # contrast/icon/power
   i2c.write_byte_data(addr, 0, 0x6c)  # follower control
   time.sleep(0.2)
   i2c.write_byte_data(addr, 0, 0x38)  # function set(IS=0)
   i2c.write_byte_data(addr, 0, 0x0C)  # Display On
   i2c.write_byte_data(addr, 0, 0x01)  # Clear Display
   i2c.write_byte_data(addr, 0, 0x06)  # Entry Mode Set
   time.sleep(0.2)
 
   # LCD Clear
   i2c.write_byte_data(addr, 0, 0x38)  # function set(IS=0)
   i2c.write_byte_data(addr, 0, 0x0C)  # Display On
   i2c.write_byte_data(addr, 0, 0x01)  # Clear Display
   i2c.write_byte_data(addr, 0, 0x06)  # Entry Mode Set
   time.sleep(0.2)
 
   # Send to LCD
   line1 = '__test__'
   for c in line1:
     i2c.write_byte_data(addr, 0x40, ord(c))
   i2c.write_byte_data(addr, 0, 0xc0)  # 2nd line
   line2 = '__!(^^)!__'
   for c in line2:
     i2c.write_byte_data(addr, 0x40, ord(c))
       
 
 if __name__ == '__main__':
   main()

PWMのテスト

XBeeのテスト

Ministickコンポーネントの作成

Ministickコンポーネントの作成

Phidgets は Phidgets Inc. から発売されている、IO拡張ボードとセンサ群製品です。 日本では、ぷらっとほーむなどで購入することができます。

PCにUSB接続の拡張IOボードを接続し、様々なセンサ、アクチュエータユニットを追加して、プログラム等から計測・制御することができるキットです。

PCと接続する場合は、Interface Kitが必要ですが、PiRT-Unitでのみ使用する場合は、Sensor Kitのみでよいでしょう。

PIRT-UnitのADピンは、Phidgetのセンサが接続可能なピンアサインとなっており、Phidgetデバイスを接続することで、容易に拡張することができるようになっています。

ここでは、Phidget の Ministick sensorを利用して、移動ロボットを制御してみます。 Ministick sensor は Phidget Sensor Kit #2 に含まれています。

Ministick sensorとPiRT-Unitの接続

Ministick sensorの出力ピンとPiRT-Unitを以下のように接続します。

  • X軸方向: CN2
  • Y軸方向: CN3
    ministick_connection.png
    Ministick sensorとPiRT-Unitの接続

X軸方向 (横向き) がADのCH0に、Y軸方向 (縦向き) がADのCH1に対応します。

このデータを読むプログラムをPythonで書いてみます。

サンプルプログラム

 #!/usr/bin/env python
 # -*- coding: euc-jp -*- 
 import sys
 import time
 import spidev
 
 class ADC:
   def __init__(self):
     self.spi = spidev.SpiDev()
     self.spi.open(0, 0)
 
   def get_value(self, channel):
     sned_ch = [0x00,0x08,0x10,0x18]
     if ((channel > 3) or (channel < 0)):
       return -1
     r = self.spi.xfer2([sned_ch[channel],0,0,0])
     ret = ((r[2] << 6 ) & 0x300) |  ((r[2] << 6) & 0xc0) | ((r[3] >> 2) & 0x3f)
     return ret     
 
   def get_voltage(self, channel):
     ret = self.get_value(channel) * 5.0 / 1024
     return ret     
 
 def main():
   adc = ADC()
   while 1:
     adc1 = adc.get_value(0)
     msg1 = "%1.5fV(%04x)" % ((float(adc1)*5/1024),adc1)
     print msg1,
 
     adc1 = adc.get_value(1)
     msg1 = "%1.5fV(%04x)" % ((float(adc1)*5/1024),adc1)
     print msg1,
 
     adc2 = adc.get_value(2)
     msg2 = "%1.5fV(%04x)" % ((float(adc2)*5/1024),adc2)
     print msg2,
 
     adc3 = adc.get_value(3)
     msg3 = "%1.5fV(%04x)" % ((float(adc3)*5/1024),adc3)
     print msg3,
 
     sys.stdout.write("\n")
     time.sleep(0.5)
 
 if __name__ == '__main__':
   main()

このようなプログラムを作成します。TeraTermなどでRaspberry Piにログインして、サンプルプログラムを作成、テストします。

 Linux raspbian-armhf 3.2.27+ #307 PREEMPT Mon Nov 26 23:22:29 GMT 2012 armv6l
 
 The programs included with the Debian GNU/Linux system are free software;
 the exact distribution terms for each program are described in the
 individual files in /usr/share/doc/*/copyright.
 
 Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
 permitted by applicable law.
 Last login: Tue May 14 07:07:04 2013 from dhcpe2078.a02.aist.go.jp
 pi@raspbian-armhf ~ $ vi adc_test.py
 pi@raspbian-armhf ~ $ chmod 755 adc_test.py
 pi@raspbian-armhf ~ $ ./adc_test.py

サンプルプログラムを実行すると以下のような画面になります。ジョイスティックを倒してみると、Ch0,Ch1のデータが変化します。

ministick_teraterm.png
ministick sensorの座標軸

それぞれ、X軸は左に倒すと、Y軸は上に倒すと電圧値が上がり、逆に倒すと電圧値が下がることがわかります。 ministick sensorの座標の関係を図に表わすと以下のようになります。

ministick_axis_ja.png
ministick sensorの座標軸

これは、一般的な座標系とはX軸が逆向きになっていますので、センサ値を処理する際には注意が必要です。

また、中心位置では、それぞれ5.0Vの半分、2.5V程度を指していることもわかると思います。 ただし、この値はぴったり2.5Vではなく、状況によっても変化するので、使用する前にキャリブレーションが必要なこともわかります。

ジョイスティックコンポーネントの仕様

ministick sensorを利用したジョイスティックコンポーネントを作成します。 仕様としては、以下のようにします。

基本プロファイル
コンポーネント名 Ministick
モジュール概要 Phidget ministick sensor component
バージョン 1.0.0
ベンダ名 AIST
モジュールカテゴリ Input Device
アクティビティ
onInitialize, onFinalize, onActivated, onDeactivated, onExecute
データポート
[out] pos
概要 ジョイスティックのX-Y位置データ
データ型 TimedFloatSeq
詳細 data[0]: x位置, data[1]: y位置
単位 無し
[out] vel
概要 移動ロボットの速度ベクトル
データ型 TimedVelocity2D
詳細 vx: 並進速度, vy: 0.0, va: 角速度
単位 vx [m/s], va [rad/s]
[out] wheel_vel
概要 車輪速度
データ型 TimedFloatSeq
詳細 data[0]: 左車輪角速度, data[1]: 右車輪角速度
単位 [rad/s]
コンフィギュレーション
scaling
概要 スケーリングファクタ
データ型 double
GUIコントロール slider.0.1
制約条件 0.0<=x<=10.0
tread
概要 移動ロボットのトレッド幅
データ型 double
GUIコントロール slider.0.01
制約条件 0.0<=x<=1.0
print_xy
概要 XYデータプリントのデバッグフラグ
データ型 string
GUIコントロール radio
制約条件 (YES,NO)
print_vel
概要 velデータのデバッグプリントフラグ
データ型 string
GUIコントロール radio
制約条件 (YES,NO)
print_wvel
概要 wheel_velデータのデバッグプリントフラグ
データ型 string
GUIコントロール radio
制約条件 (YES,NO)

この仕様に従い、RTCBuilderでPythonのテンプレートコードを生成します。

ministick_builder_basic.pngministick_builder_activity.pngministick_builder_dataport.png
ministick_builder_configuration.pngministick_builder_documentation.pngministick_builder_lang.png
RTCBuilderの設定画面(クリックすると拡大します)

実装

コンポーネントにADCの読み込みなどの機能を追加していきます。

SPIモジュールの初期化

まず、コンポーネントのコンストラクタでSPIオブジェクトを生成し初期化します。

他の import 文の近くに、spidevをimportする一文を追加します。計算などで使用するのでmathモジュールもインポートします。

 # Import RTM module
 import RTC
 import OpenRTM_aist
 
 import math
 import spidev

さらに、コンストラクタで、必要な変数を初期化子、SPIオブジェクトを生成します。

 class Ministick(OpenRTM_aist.DataFlowComponentBase):
   def __init__(self, manager):
     OpenRTM_aist.DataFlowComponentBase.__init__(self, manager)
 
     self._scaling = [1.0]
     self._tread = [0.2]
     self._print_xy = ["NO"]
     self._print_vel = ["NO"]
     self._print_wvel = ["NO"]
     self.x = 0.0
     self.y = 0.0
     self.spi = spidev.SpiDev()
     self.spi.open(0, 0)

get_adc 関数の追加

AD変換器からデータを読む関数を Ministickクラスに追加します。 init() 関数の次あたりに、以下の関数を追記します。

  def get_adc(self, channel):
    sned_ch = [0x00,0x08,0x10,0x18]
    if ((channel > 3) or (channel < 0)):
      return -1
    r = self.spi.xfer2([sned_ch[channel],0,0,0])
    ret = ((r[2] << 6 ) & 0x300) |  ((r[2] << 6) & 0xc0) | ((r[3] >> 2) & 0x3f)
    return ret

X-Yの位置→車輪速度変換関数

X-Yの位置から車輪の速度へ変換する関数をMinistickクラスに追加します。

 dev xy_to_wvel(self, x, y):
   th = math.atan2(y, x)
   v = math.hypot(x, y)
   vl = v * math.cos(th - (math.pi/4.0))
   vr = v * math.sin(th - (math.pi/4.0))
   return (vl, vr)

車輪速度→速度ベクトル変換関数

車輪速度から速度ベクトルへ変換する関数をMinistickクラスに追加します。

 def wvel_to_vel2d(self, vl, vr):
   v = (vr + vl) / 2.0
   if v < 0.0:
     w = - (vr - vl) / self._tread[0]
   else:
     w = (vr - vl) / self._tread[0]
   return RTC.Velocity2D(v, 0.0, w)

キャリブレーション

コンポーネント初期化時に、ジョイスティックのニュートラル位置をキャリブレーションします。 AD変換器からデータを100回程度読み込み平均し、オフセットデータとして保存します。

 def onInitialize(self):
     : 中略
    self.x_offset_v = 0.0
    self.y_offset_v = 0.0
    for i in range(1, 100):
      self.x_offset_v += self.get_adc(0)
      self.y_offset_v += self.get_adc(1)
    self.x_offset_v = self.x_offset_v / 100.0
    self.y_offset_v = self.y_offset_v / 100.0
 
    return RTC.RTC_OK

onExecuteの実装

最後に、onExecute関数を実装します。

 def onExecute(self, ec_id):
    self.x = - (self.get_adc(0) - self.x_offset_v) * self._scaling[0] / 1000.0
    self.y = (self.get_adc(1) - self.y_offset_v) * self._scaling[0] / 1000.0
    if self._print_xy[0] != "NO":
      print "(x, y) = ", self.x, self.y
    self._d_pos.data = [self.x, self.y]
    
    self._d_wvel.data = self.xy_to_wvel(self.x, self.y)
    if self._print_wvel[0] != "NO":
      print "(vl, vr) = ", self._d_wvel.data[0], self._d_wvel.data[1]
    self._d_vel.data = self.wvel_to_vel2d(self._d_wvel.data[0],
                                          self._d_wvel.data[1])
    if self._print_vel[0] != "NO":
      print "(vx, va) = ", self._d_vel.data.vx, self._d_vel.data.va
 
    self._posOut.write()
    self._velOut.write()
    self._wvelOut.write()
 
    return RTC.RTC_OK

テスト

Ministickコンポーネントと、いろいろなものを接続してテストしてみます。

OpenRTM-aist-Pythonに付属のサンプルと接続

TkMobileRobotCanvasと接続してみます。

Windows上のインストールされているOpenRTM-aist-Pythonのサンプルから TkMobileRobotCanvasを起動します。 同時に、ネームサービスとRTSystemEditorも起動してください。

tkmobilerobotcanvas.png
Tk Mobile Robot Simulator 画面

Createボタンを押し、移動ロボットを一つ生成します。 ネームサーバにコンポーネントが一つ現れるので、SystemEditor上にドラッグアンドドロップします。

次に、Raspberry Pi上でネームサーバとMinistickコンポーネントを起動します。

 $ rtm-naming
 $ ./Ministick.py
 

RTSystemEditorから、RaspberryPiのネームサーバに接続すると、Ministickコンポーネントが見えますので、SystemEditor上にドラッグアンドドロップします。

Ministick の wvel データポートから先ほど生成した移動ロボットコンポーネントへポートを接続します。

ministick_and_mobilerobot.png
Ministickと移動ロボットコンポーネントの接続

アクティベートすると、両方のコンポーネントが緑色になり操作可能になります。

Kobukiと接続

前述のKobukiの制御、の節に従ってKobukiコンポーネントをRaspberryPi上で起動します。

Ministickコンポーネントを別のRaspberry Pi上で起動します。

それぞれのコンポーネントはローカルのネームサーバ(デフォルト)に参照を登録させて、別のPCからこれら2つのネームサーバにRTSystemEditorで接続します。 Name Service Viewに2つのコンポーネントが見えるはずですので、これら (Ministick の vel と KobukiAIST の targetVelocity) を接続します。(下図参照)

ministick_and_kobuki.png
Ministick RTCとKobukiAIST RTCの接続

RTSystemEditorのメニューバーの緑色の再生ボタン(全活性化)を押すと、システムが動き出しMinistickでKobukiを操作できます。

トラブルシューティング

Ministickがニュートラル状態でもロボットが動く

Ministickがニュートラル状態でも、TkMobileRobotのロボットやKobukiが少しずつ動く場合があります。これは、ニュートラル状態のキャリブレーションが十分ではないためです。 Ministickコンポーネントを工夫して、使いやすいコンポーネントにしてみましょう。

例えば、キャリブレーションをonActivatedで行うようにすれば、一旦Deactivateして再度Activateすれば零点をリセットできます。 また、onDeactivatedの時には速度0を出力するようにすれば、JyoistickのDeactivateによりロボットが安全に停止します。 あるいは、零点付近に不感帯を設けることで、多少キャリブレーションがずれても、ニュートラル状態で必ず0が出力されるようにできます。

Permission deniedエラー

以下のようなパーミッション関係のエラーが出ることがあります。 上述のudevの設定が正しく行われていない可能性がありますので、見直してください。

 pi@raspbian-armhf ~ $ ./adc_text.py
 Traceback (most recent call last):
   File "./adc_text.py", line 47, in <module>
     main()
   File "./adc_text.py", line 25, in main
     adc = ADC()
   File "./adc_text.py", line 10, in __init__
     self.spi.open(0, 0)
 IOError: [Errno 13] Permission denied

また、sudo を利用しても実行可能です。

PiRT-UnitによるXBeeモジュールの利用

PiRT-UnitによるXBeeモジュールの利用

PiRT-UnitにはZigBeeモジュールXBeeを接続するためのコネクタがあります。 RaspberryPiからシリアルデバイス経由で利用して、他のZigBeeモジュールとの通信に利用したり、シリアルコンソールを無線化するのにも利用できます。 Raspbian Wheesyではデフォルトでシリアルコンソールに設定されています。 この解説では、シリアルコンソールをXBeeで無線化する方法を説明します。

XBeeとPCの接続

XBeeモジュールとPCを接続するにはXBee-USBエクスプローラを利用する必要があります。 XBeeモジュール接続コネクタとUSBコネクタがついており、PCに接続してPCからXBeeの各種設定を行ったり、XBeeをシリアルポートとして利用することができます。

XBee-USBエクスプローラは、様々なメーカーから発売されています。

商品名 メーカー 価格 URL
AE-XBEE-USB 秋月電子通商 1,280円 http://akizukidenshi.com/catalog/g/gK-06188/
SFE-WRL-08687 Sparkfun
Switch Science
2,619 円 http://www.switch-science.com/catalog/30/
http://strawberry-linux.com/catalog/items?code=18128 でも入手可能
SFE-WRL-09819 Sparkfun
Switch Science
2,619 円 http://www.switch-science.com/catalog/344/

xbee-usb.png
XBee-USBエクスプローラ (Sparkfun(左), 秋月電子通商(右))

デバイスマネージャを開く (Windows)

デバイスマネージャを開いてください。 Windows7では、「コントロールパネル」→「システムとセキュリティ」→「システム」→「デバイスマネージャー」から開くことができます。 デスクトップに「コンピュータ」がある場合、右クリック→「プロパティー(R)」→「デバイスマネージャー」から開くのが最も早いでしょう。

XBee-USBエクスプローラの接続

XBee-USBエクスプローラをPCのUSBポートに接続します。 初めて接続する場合は、デバイスの認識とデバイスドライバのインストールでしばらく時間がかかります。 デバイスドライバのインストールが終了すると、以下のようにデバイスマネージャにCOMポートとして現れます。 この時、どのCOMポートに割り当てられたかを覚えておいてください。(下の例ではCOM8に割り当てられた。)

debice_manager_xbbcomport.png
デバイスマネージャに現れたXBee-USBエクスプローラデバイス

デバイスが認識されない場合

運悪くドライバが自動でインストールされない場合、FTDI社のチップ(FT232B等)を使ったXBee-USBエクスプローラの場合はFTDI者から直接ドライバをダウンロードしてインストールしてください。

なお、秋月およびSparkfunのXBee-USBエクスプローラでは、Windows7はドライバのインストールは不要でした。

XBeeモジュールの設定

XBeeモジュールは大きく分けて親機と子機に分かれており、そのXBeeモジュールを親機にするか子機にするかはXBee-USBエクスプローラ経由でPCから設定します。

一つのXBeeネットワーク内には必ず1台の親機"Coordinator"が必要で、親機に対して複数の子機がぶら下がる形になります。 一方、購入直後のXBeeモジュールは子機"Router"に設定されており、初めてXBeeネットワークを構成する際には、どれか一つを親機"Coordinator"にしてあげる必要があります。

XBeeモジュールを設定するには、DigiのWebページからX-CTUという設定ソフトウエアをダウンロードしPCにインストールする必要があります。

X-CTUのダウンロード・インストール

DigiのX-CTUのダウンロードサイトへ行きます(更新等によるリンク切れがあった場合はMLなどでお知らせいただければ幸いです)。

ページの Diagnostics, Utilities and MIBs の項目をクリックすると、X-CTUのインストーラへのリンクが現れるので、クリックしてダウンロードします。(63MB程度あります。)

digi_xctu_webpage_xctu_link.png
X-CTUインストーラのダウンロード

ダウンロードした実行ファイル 40003002_C.exe (このファイル名はバージョンアップなどにより変更されるかもしれません) をクリックして実行すると、インストーラが開始されます。指示に従ってインストールを完了してください。

xctu_setup0.png
X-CTUインストーラの実行

最後に、frimwareのバージョンアップをするか聞いてくることがありますが、特に必要がなければスキップしてください。(結構時間がかかります。)

X-CTUの起動

インストール完了後、X-CTUを起動します。起動後は以下のような画面が表示されます。

xctu0.png
X-CTU起動後の画面

X-CTUの「PC-Settings」を選択します。 タブ内のSelect Com PortでXBee-USBエクスプローラデバイスが接続されているCOMポートを選択します。(この例ではCOM8です。) XBee-USBエクスプローラデバイスが接続されているCOMポートが不明な場合は、一旦デバイスをPCから取り外し、デバイスマネージャでなくなるCOMポートを観察するか、X-CTUを再度起動してなくなったCOMポートを見つけるなどして対応するCOMポートを特定してください。

Select Com Portで対象となるCOMポートを選択したら、右下のTest/Queryボタンを押してください。XBeeと通信を行い、以下のようにシリアルナンバーなどを表示します。

xctu1.png
接続テスト

ファームウエア設定情報の読み込み

次に接続されているXBeeが現在どのような設定になっているか、ファームウエアの情報を読み込みます。 X-CTUの「Modem Configuration」タブをクリックし、下のModem Parameter and Firmwareのエリアの「Read」ボタンをクリックします。 すると、XBeeとの通信が開始され、少し経つと以下のようにXBeeの設定情報が下のエリアにツリー表示されます。

xctu2.png
ファームウエア設定情報の読み込み

また、「Modem」の部分にXBeeモジュールの種類、「Function Set」の部分にファームウェアの種類、「Version」にファームウェアのバージョンが表示されます。

「Function Set」の部分はおそらく ZIGBEE ROUTER AT となっているはずですが、これはこのXBeeモジュールが"Router"すなわち子機として設定されていることを意味します。

RouterからCoordinatorへの変更

ここで子機"Router"を親機"Coordinator"に変更してみます。 親機すなわり「Coordinator」に変更するために、プルダウンメニューからZIGBEE COORDINATOR ATを選択します。

xctu3.png
ファームウエア ZIGBEE COORDINATOR AT への変更

「Write」ボタンを押すとXBeeへの書き込みが開始されます。1から2分程度で書き込みが終了します。

xctu6.png
ファームウエアの書き込み

ATとAPIの違い

先ほどのファームウエアの選択時に、ZIGBEE COORDINATOR AT のほかに ZIGBEE COORDINATOR API というファームウエアがあったことに気付かれたかもしれません。 AT とつくものは、ATコマンドでXBeeの設定を行うタイプのファームウエアで、一方APIとつくものは、API経由でXBeeの設定を行うタイプのファームウエアを意味します。

もしXBeeが全く応答しなくなったら

もしXBeeが全く応答しなくなったら、強制的にファームウエアを上書きし出荷状態に戻します。 以下の手順に従って、工場出荷状態に戻してください。

  1. XBee-USBエクスプローラデバイスからXBeeを外す
  2. その状態でXBee-USBエクスプローラデバイスをPCに接続する
  3. X-CTUを起動
  4. "Modem Configuration"タブをクリック
  5. "Always update firmware" チェックボックスをクリック
  6. 適切な"Modem"タイプを選択
  7. 適切な"Function Set"を選択
  8. "Write"をクリック。しばらくすると、エラーダイアログが出るので、XBeeをXBee-USBエクスプローラデバイスに挿入
  9. ファームウエアの書き込みが始まる

PiRT-UnitによるI2Cデバイスの利用

はじめに

Raspberry Pi上に存在する GPIO ピンのうちのI2C用ピン(2本)を用いると、複数の I2C デバイスを操作することができます。 ここでは、I2C を利用するためのセットアップ、C言語によるプログラム記述の実例、RTコンポーネント化するためのヒントを示します。

必要なもの

  • OpenRTM-aist の C++版がインストールされた Raspberry Pi
  • I2C デバイスを配線するための資材(ブレッドボード、ケーブル、抵抗、他)
  • I2C デバイス(秋月、ストロベリーリナックス、スイッチサイエンス等で入手)
  • ネットワーク(インターネット、apt-get するため)
このドキュメントでは、I2C デバイスとして、

を取り上げます。

I2C(アイ・スクエア・シー)とは

I2C は2線を用いるシリアルバス通信の一種です。クロック線のエッジを用いてデータ線上で値の授受行い、バス上にある複数デバイスを制御することができます。 バス上にはマスターとスレーブがあり、規格では複数のマスター/スレーブの存在を許しているようですが、実際には単一マスター/複数スレーブによる使用が簡単です。 マイコンなどから利用する場合は、マスターによるクロック信号の送信と、データの通信プロトコル実装などを考慮して実装しなければなりませんが、Raspberry Pi を用いると既存のライブラリを使用して非常に簡単に I2C デバイスを利用することができます。

Raspberry Pi の GPIOポート(26pin)のうち、もともと I2C 通信専用に設定されている GPIO が2本存在します。(下図参照) GPIO 0 が I2C のデータ用ポート、GPIO 1 が I2C のクロック用ポートとしてあらかじめ設定されており、これらを利用することで簡単に I2C 通信を行うことができます。

raspberry_gpio.png
Raspberry PiのGPIOポート、GPIO0 (I2C SDA), GPIO1 (I2C SCL)

この2本のポートを用いて I2C デバイスを直接接続するだけで、クロック線のドライブ・通信プロトコルの解釈などはすべて Raspberry Pi上の Linux で行われます。 ユーザーはデバイスファイル (/dev/i2c-*) の読み書きを行うことでデバイスからのデータ取得/デバイスへのデータ出力を実現できます。

複数のデバイスの接続はバス接続(下図)で実現することができます。 デバイス間の調停も Raspberry Pi側である程度は行うことになっています。 なお、上記GPIO 0、GPIO 1ポートは Raspberry Pi 基板上でプルアップ抵抗によりプルアップされていますので、別途プルアップする必要はありません。

i2c_devices.png
I2Cバス接続

準備

システム設定

Raspberry Pi で I2C 通信を使うためにはいくつのかの設定ファイルを変更する必要があります。 ファイルは root 権限で編集してください。

/etc/modules の編集

/etc/modules に以下の一行を追加します。

 i2c-dev

これにより、/dev/i2c-* が有効になります。

/etc/modprobe.d/raspi-blacklist.conf の編集

/etc/modprobe.d/raspi-blacklist.conf の以下の一行をコメントアウトします。

 # blacklist i2c-bcm2708

以上の変更が終了したら、変更を反映するために再起動してください。

i2c-tools のインストール

i2c-tools はコマンドラインから I2C デバイスへアクセスするためのツールです。 実際に開発する際には、コマンドラインから I2C デバイスの動作を確認したいことがたびたびありますので、事前に i2c-tools をインストールしておいてください。

 sudo apt-get install i2c-tools

として、インストールします。

配線

上記のブロック図では、I2C デバイスは SDA、SCL の2線のみが配線されていましたが、実際には当然各デバイスに電源を供給してあげる必要があります。 それほど消費電力の大きくない I2C デバイスであれば、Raspberry Pi の GPIO ピンヘッダ 26pin のうち、2,3pin(5V)、1,17pin(3.3V)からでている電源を利用することができます。 I2C デバイスの説明書・データシートを参照した上で、5V ないし 3.3V のうち適切な電源を供給するようにしてください。 また、PiRT-Unit には I2C用の4ピンのコネクタが付属しており、SDA、SCL、3.3V、GND が配線可能です。

今回用いる I2C デバイスはすべて 3.3V で動作するため、Raspberry Pi の 1,17pin(3.3V)から各デバイスに電源を供給します。 以下にブレッドボード上に上記の4つのデバイスを配置した際の配線図を示します。

i2c_devices_circuit.png
I2CデバイスとRaspberryPiの接続

配線の際にはデバイスの説明書/データシートをよく読んで間違いのないよう配線してください。配線を間違うとデバイスが認識されないだけでなく、場合によってはデバイスが破壊される可能性もあります。

デバイスの種類によっては、使用方法によって適宜ジャンパが必要なものや、I2Cの2本の信号線以外に割り込み、リセット信号などをが必要なものもあります。その場合は、Raspberry Pi の GPIO ピンを適宜利用し、プログラム側から制御する必要があります。

動作確認

デバイスアドレスの確認

上記の配線が完了したら、Raspberry Pi上から i2c-tools を利用してデバイスを操作することができます。 まずは、i2cdetect コマンドで、I2C バスに接続されているすべてのデバイスのアドレスを確認してみましょう。以下のようにタイプすると、下図のような表示が現れます。

 $ sudo i2cdetect 1
i2c_i2ctools_i2cdetect.png
I2CデバイスとRaspberryPiの接続

図では4個のデバイスが存在していることが確認できます。-(マイナス)以外に16進数の数字が表示されていますが、それぞれが各デバイスのアドレスを表しています。内訳は、

  • 0x19:LSM303DLHCの加速度センサー
  • 0x1e:LSM303DLHCの地磁気センサー
  • 0x51:RTC-8564NB(リアルタイムクロック)
  • 0x6a:L3GD20(ジャイロセンサー)

となっています。このコマンドと各デバイスの説明書/データシートを突き合わせることで、Raspberry Pi が I2C デバイスを認識できているかを確認することができます。 なお、Raspberry Pi のリビジョンによって、コマンドの後ろに入れるバス番号が0の場合と1の場合がありますので注意してください。

デバイスの制御テスト

デバイスに実際にデータを書き込むには i2cset コマンドを、デバイスからデータを読み込むにはi2cgetコマンドを使用します。(下図参照)

i2c_i2ctest.png
i2ctestコマンドによるI2Cデバイスの制御の様子

 // LSM303DLHCの地磁気センサーへアクセス
 $ sudo i2cset -y 1 0x1e 0x00 0x14
 $ sudo i2cset -y 1 0x1e 0x01 0x20
 $ sudo i2cset -y 1 0x1e 0x02 0x00
 $ sudo i2cget -y 1 0x1e 0x32
 $ sudo i2cget -y 1 0x1e 0x31
 $ sudo i2cget -y 1 0x1e 0x03
 $ sudo i2cget -y 1 0x1e 0x04
 $ sudo i2cget -y 1 0x1e 0x05
 $ sudo i2cget -y 1 0x1e 0x06
 $ sudo i2cget -y 1 0x1e 0x07
 $ sudo i2cget -y 1 0x1e 0x08
 $ sudo i2cget -y 1 0x1e 0x09
 // LSM303DLHCの加速度センサーへアクセス
 $ sudo i2cset -y 1 0x19 0x20 0x27
 $ sudo i2cget -y 1 0x19 0x28
 $ sudo i2cget -y 1 0x19 0x29
 $ sudo i2cget -y 1 0x19 0x2a
 $ sudo i2cget -y 1 0x1e 0x2b
 $ sudo i2cget -y 1 0x1e 0x2c
 $ sudo i2cget -y 1 0x1e 0x2d

この例では、LSM303DLHCの説明書に従って、まず地磁気センサを動作させるために0x1eのアドレスのデバイスに対して内部レジスタ0x00~0x02に所定の数値を書き込み、内部レジスタ0x31~32、0x03~0x09を読み出しています。 その後、LSM303DLHCの加速度センサを動作させるため、0x19のアドレスのデバイスに対して内部レジスタ0x20に所定の数値を書き込み、0x28~0x2dまでの数値を読み込んでいます。

i2c-toolsのコマンド群はルート権限でのみ実行可能であるのでsudoを使用するか、sudo bashとしてrootになって実行する必要がありますので注意してください。

C言語によるデバイス操作

プログラムからこれらのデバイスにアクセスするには、デバイスファイル (/dev/i2c-0 または /dev/i2c-1) をオープンし、読み書きすることでデバイスのレジスタ操作および値の読み出しを行います。

ただし、I2Cデバイスの種類によっては特有の初期化シーケンスを持っていたり、デバイスのデータの読み書きに一定の手順を要求するものがあります。各デバイスの説明書やデータシートを確認しながらプログラムを作成する必要があります。 (インターネット上には、RaspberryPi/AVRマイコン/ArduinoなどからのI2Cデバイスの制御方法に関する情報が色々あるようですので、そちらも参考にしてください。)

以下に、L3GD20デジタル3軸ジャイロセンサモジュールを用いたサンプルプログラムを掲載します。

このモジュールはI2CおよびSPIでの通信が可能なセンサモジュールで、I2Cデバイスとして利用する場合、アドレスを0x6a、0x6bの2種類から選択可能です。ここではアドレスを0x6aとして使用しています。

内部レジスタは、

0x0f 常に0xd4を出力
0x20 0x0fを書き込むことで動作開始
0x28~2d 3軸ジャイロデータが格納される

このほか、検出レンジ、サンプリングレート等の設定も可能ですが、ここでは触れません。

プログラム

以下にプログラムを示します。 なお、こちらからダウンロードすることもできます。また、I2CセンサをRTコンポーネント化した、データ取得コンポーネントおよびディスプレイコンポーネントもサンプルとして示します。

 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
 #include <unistd.h>
 
 #include <linux/i2c-dev.h> // I2C用インクルード
 #include <fcntl.h>
 #include <sys/ioctl.h>
 
 #include <wiringPi.h> // delay関数用にインクルード
 
 // プロトタイプ宣言
 void L3GD20_readData(int *gyrodata, int fd);
 void L3GD20_write(unsigned char address, unsigned char data, int fd);
 unsigned char L3GD20_read(unsigned char address, int fd);
 void L3GD20_init(int fd);
 
 int main(int argc, char **argv)
 {
     int i2c_fd;       // デバイスファイル用ファイルディスクリプタ
    // char *i2cFileName = "/dev/i2c-0"; // I2Cデバイスファイル名
     char *i2cFileName = "/dev/i2c-1"; // RaspberryPiのリビジョンに合わせて変更
     int i2cAddress = 0x6a;   // L3GD20のI2Cアドレス
     int gyroData[3]; // ジャイロ3軸(x,y,z)データ格納用
     
     printf("i2c Gyro(L3GD20) test program\n");
     delay(500);
    // I2Cデバイスファイルをオープン
     if ((i2c_fd = open(i2cFileName, O_RDWR)) < 0) 
     {
         printf("Faild to open i2c port\n");
         exit(1);
     }
     // L3GD20用にセット
     if (ioctl(i2c_fd, I2C_SLAVE, i2cAddress) < 0) 
     {
         printf("Unable to get bus access to talk to slave\n");
         exit(1);
     }
     //デバイス初期化
     L3GD20_init(i2c_fd);
     
     // 1秒ごとに20回ジャイロデータを取得、表示
     int i;
     for(i=0; i<20; i++){
         // デバイスからデータ取得
         L3GD20_readData(gyroData, rtc); 
         // 取得したデータを校正して表示、1秒待ち
         printf("x, y, z : %5.2f, %5.2f, %5.2f\n",
               (float)gyroData[0]*0.00875,(float)gyroData[1]*0.00875,
               (float)gyroData[2]*0.00875);
         delay(1000); 
     }
     return;
 }
 
 // L3GD20用 1バイト書き込みルーチン:addressで示すレジスタにdataを書き込む
 void L3GD20_write(unsigned char address, unsigned char data, int fd)
 {
     unsigned char buf[2];
     buf[0] = address;
     buf[1] = data;
    if((write(fd,buf,2))!=2){
         printf("Error writing to i2c slave\n");
         exit(1);
    }
     return;
 }
   
 // L3GD20用 1バイト読み出しルーチン: addressで示すレジスタの値を読み出す
 // 戻り値がレジスタ値
 unsigned char L3GD20_read(unsigned char address, int fd)
 {
     unsigned char buf[1];
     buf[0] = address;
     if((write(fd,buf,1))!= 1){ // addressを一度書き込む所に注意
         printf("Error writing to i2c slave\n");
         exit(1);}
     if(read(fd,buf,1)!=1){
         printf("Error reading from i2c slave\n");
         exit(1);}
     return buf[0];
 }
 
 // L3GD20用 ジャイロデータ読み出しルーチン:
 // 整数値配列へのポインタを使ってデータを受け渡す
 void L3GD20_readData(int *gyrodata, int fd)
 {
     unsigned char data[6];
     // センサから3軸に対して2バイトずつデータを読み出す
     int i;
     for(i=0; i<6; i++){
         data[i]=L3GD20_read(0x28+i,fd);
     }
     // 各数値を32bit幅の整数に整形する
     // センサの数値精度が16bit・2の補数表現での出力のため、シフトで加工
     gyrodata[0]=((int)data[1]<<24|(int)data[0]<<16)>>16;
     gyrodata[1]=((int)data[3]<<24|(int)data[2]<<16)>>16;
     gyrodata[2]=((int)data[5]<<24|(int)data[4]<<16)>>16;
     return;
 }
 
 // L3GD20用 ジャイロデータイニシャライズルーチン
 void L3GD20_init(int fd)
 {
     unsigned char Data;
     printf("L3GD20 init seq. start\n");
     // L3GD20 動作確認
     // L3GD20の0x0fレジスタは常に0xd4にセットされているため動作確認ができる
     Data = L3GD20_read(0x0f,fd);
     if(Data != 0xd4){
         printf("L3GD20 is not working\n");
         exit(1);}
     delay(10);
     // レジスタへの書き込みチェックとイニシャライズを同時に行う
     printf("read OK, Now writing check...\n");
     // 0x20レジスタに0x0fを書き込むことで動作させる
     L3GD20_write(0x20, 0x0f, fd);
     // 0x20レジスタに実際に0x0fが書かれたか確認
     Data = L3GD20_read(0x20,fd); if(Data != 0x0f){
         printf("Writing miss\n");
         exit(1);
     } 
     printf("Writing OK\n");
     delay(10);     
     return;
 }

RTコンポーネント化のためのヒント

RaspberryPi上でI2Cデバイスにアクセスするプログラムは以上のように記述することができます。上記のコードをRTコンポーネント化する場合には、例えば初期化部分をRTコンポーネントのonInitializeまたはonActivatedに実装、デバイスからデータを取得して表示するルーチンを onExecute に実装し、OutPortから出力するようにすれば、センサデータを出力するコンポーネントが出来上がります。

実行コンテキストの周期は、I2Cデバイスおよびバスの速度と、バスに接続されているI2Cデバイスの数、それぞれのI2Cデバイスのサンプリングレートなどから決める必要があります。

複数のデバイスをI2C接続した状態でこれらをコンポーネント化する場合、各デバイス間でデータの読み書きのスケジューリングを考慮する必要があります。 実現手法として考えられるのは、
  • すべてのI2Cデバイスを一つのコンポーネントとして取り扱う
  • I2Cバスへのアクセスを単一コンポーネントにまかせ、個別デバイスからポート間通信でデータを取得する
  • ロックなどの排他制御を共有オブジェクトなどを使って実装する などが考えられますが、それぞれ一長一短があるので状況に応じて選択するのがよいでしょう。