その他

Raspberry PiでのOpenRTM-aist活用事例

Raspberry_Pi_Logo.svg_.png

はじめに

Raspberry Piとは、ラズベリーパイ財団が英国で開発したARMプロセッサを搭載したシングルボードコンピューターです。

Raspberry Piは組込みボードサイズにも関わらず、ARM用の通常のLinux (Debian、Fedora、Arch Linux)やFreeBSDが動作し、ボード上でセルフコンパイルも行えるため大変使いやすいです。 ディスクも現在は安価で大容量なSDカードを利用でき、本体価格も3000円程度と非常に安価です。 また、基本的なI/Oが提供されており、外部のいろいろなデバイスとも接続できるため、ロボット制御やセンサーによる計測など、いろいろな応用が考えられます。

仕様

Raspberry Piの外観を以下に示します。

raspberrypi.png
Raspberry Pi

Raspberry Piには3つの基本タイプ(Model A、Model B、Model Zero)があり、また基本タイプごとに複数のモデルがあります。詳細については下記Wikipediaのリンクなどを参照してください。

以下に代表的なモデルの仕様を表示します。

仕様
3 Model B 3 Model B+ 4 Model B (4G)
ターゲット価格 $35 $35 $55
SoC Broadcom BCM2837 Broadcom BCM2837B0 Broadcom BCM2711
CPU ARM Cortex-A53 1.2GHz ARM Coretex-A53 1.4GHz ARM Coretex-A72 1.5GHz
GPU Broadcom VideoCore IV Broadcom VideoCore VI
メモリ(SDRAM) 1GB(GPU共有) 4GB(GPU共有)
USB 2.0ポート 4(統合USBハブ) 4 2
USB 3.0ポート - 2
映像出力 コンポジット RCA(PAL&NTSC)、HDMI(rev 1.3 & 1.4)、MIPI DSI コンポジットRCA(PAL/NTSC)、micro-HDMI(up to 4kp60) 2.0 x 2、MIPI DSI
音声出力 3.5 mm ジャック、I2S、HDMI 3.5 mmジャック、I2S、micro HDMI
ストレージ SDメモリーカード/MMC/SDIOカードスロット
ネットワーク 10/100 Mbpsイーサネット(RJ45) Gigabit Ethernet over USB 2.0 (maximum throughput 300Mbps) (RJ45) Gigabit Ethernet (RJ45)
低レベル周辺機器 8 × GPIO、UART、I2C、SPIと2つのチップセレクト、+3.3V、+5V、接地
電源 2.5A(12.5W) 3A(15 W)
電源ソース 5V/microUSBまたはGPIO 5V/USB Type-CまたはGPIO
大きさ 85.0mm × 56.5mm 85.0mm x 56.0mm

より詳しくは上記Wikiなどを参照してください。

このBookの概要

産総研が開発したI/O拡張基盤PiRT-Unitを利用すれば、比較的簡単にI/Oを利用することが可能です。

pirt-unit.png
PiRT-Unit

OpenRTM-aist(C++、Python、Java)もボード上でコンパイル・実行可能ですので、組込みボードでありながら、通常のLinux PC上での開発プロセスとほぼ同様の使い方が可能です。

ここではOpenRTM-aistでRTコンポーネントを開発・実行するための環境構築方法、便利に使うためのノウハウ、移動ロボットの制御やI/Oの利用方法などを解説します。

pirt-unit_app.png
Raspberry PiやPiRT-Unitを利用したアプリケーション

SDカードの準備

はじめに

ここでは、Raspberry Pi用 RTC(以下、RPI RTC)を動作させるための実行環境のインストールについて説明します。

なお、以下のインストール手順は、Windows 環境を前提としています。 Windows 環境以外をご使用の方は以下のサイトなどをご参照ください。

ここでは、Raspberry Pi オフィシャルサイトから OSイメージをダウンロードし、各種セットアップについて説明します。 Raspberry Pi上で OpenRTM を使用できるようにするまでの大まかな手順は以下の通りです。

  • SDカードに OSイメージを書き込む
  • OSの基本的なセットアップ
  • OpenRTM-aist のインストール
  • コンポーネントの実行テスト

なお、OpenRTM-aist のインストールや、Kobuki コンポーネントがすでにインストールされたイメージをこちらに用意していますので、以下の手順はスキップすることができます。

SDカードの容量

使用する SDカードは最低 2GB 必要ですが、実際の使用では 4GB以上が必要 になります。必ず4GB以上の SDカードを用意してください。

イメージのダウンロード

以下のサイトから、Raspberry Pi用 OS Raspbian “wheezy”をダウンロードします。 Raspbian は Debian ベースのRaspberryPi用 Linux ディストリビューションです。

ダウンロードしたファイル YYYY-MM-DD-wheezy-raspbian.zip を展開してください。 YYYY-MM-DD-wheezy-raspbian.img という2GB位のファイルが展開されているはずです。

 $ ls -al 
 total 4752840
 drwxr-xr-x  4 n-ando  staff         136  5 18 13:30 .
 drwxr-xr-x  9 n-ando  staff         306  5 18 13:30 ..
 -rw-r--r--  1 n-ando  staff  1939865600  2  9 12:44 2013-02-09-wheezy-raspbian.img
 -rwxr-xr-x  1 n-ando  staff   493587826  5  7 21:08 2013-02-09-wheezy-raspbian.zip

うまく展開できない場合、ダウンロードに失敗しファイルが壊れている可能性があります。壊れたファイルを削除して、再度ダウンロードしてみてください。

イメージの書き込み

展開された yyyy-mm-dd-hweezy-raspbian.img はイメージファイルといい、Raspbian が起動するディスクの状態をディスクの最初から最後まで1バイトづつ抜き出したものです。 このファイルをSDカードに単純にコピーしても使用することはできません!!

以下に説明する方法で SDカードに書き込んでください。

イメージの書き込み (Windows)

Windows では Win32DiskImager というツールを使用することでイメージの書き込みができます。 以下のサイトからイメージデータ書き込みツール Win32DiskImager のバイナリをダウンロードします。

ダウンロードしたファイル (win32diskimager-vX.X-binary.zip ) を解凍します。

※Win32DiskImager は、2バイト文字に対応していないため、YYYY-MM-DD-wheezy-raspbian.zip は途中のパス名に全角文字や空白が含まれていない場所に解凍してください。

Raspberry Pi で使用する SDカードをPCに挿入し、Win32DiskImager を起動します。

※SDカードはドライブとして認識されている必要があるので、事前に FAT32 形式でフォーマットしておいてください。

「Image File」に解凍したRaspbian のイメージファイル (YYYY-MM-DD-wheezy-raspbian.img)、「Drive」に SDカードのドライブを指定し、「Write」 ボタンをクリックします。

win32diskimager.png
イメージデータの書き込み

以上で SDカードの準備は終了です。 書き込みが終了したら、SDカードを Raspberry Pi に設置し、電源を投入します。

イメージの書き込み (Linux)

Linux では ddコマンドを利用してイメージの読み書きができます。 ddコマンドは UNIX系の OSなら大抵デフォルトでインストールされています。

SDカードを差し込んでから、 dmesg コマンドでカーネルのメッセージを確認します。

 $ dmesg
   : 中略
 [333478.822170] sd 3:0:0:0: [sdb] Assuming drive cache: write through
 [333478.822174]  sdb: sdb1 sdb2
 [333478.839563] sd 3:0:0:0: [sdb] Assuming drive cache: write through
 [333478.839567] sd 3:0:0:0: [sdb] Attached SCSI removable disk
 [333479.094873] EXT4-fs (sdb2): mounted filesystem with ordered data mode
 [333527.658195] usb 1-1: USB disconnect, address 2

このメッセージから SDカードのデバイス名を確認します。この例では sdb が SDカードのデバイス名のようです。/dev/ の下を見てみます。

 ls -al /dev/sd*
 brw-rw---- 1 root disk 8,  0 May  7 17:28 /dev/sda
 brw-rw---- 1 root disk 8,  1 May  7 17:28 /dev/sda1
 brw-rw---- 1 root disk 8,  2 May  7 17:28 /dev/sda2
 brw-rw---- 1 root disk 8,  5 May  7 17:28 /dev/sda5
 brw-rw---- 1 root disk 8, 16 May 18 14:19 /dev/sdb
 brw-rw---- 1 root disk 8, 17 May 18 14:19 /dev/sdb1
 brw-rw---- 1 root disk 8, 32 May 18 14:19 /dev/sdc

sda は大抵システムディスクなので、絶対に触ってはいけません。

ディストリビューションによっては、SDカード内にマウント可能なファイルシステムがある場合自動でマウントするケースもあるようです。 その場合、ディスクをアンマウントしてください。(Ubuntuではデスクトップにマウントしたファイルシステムのフォルダーが現れるので右クリックで取り外してください。それ以外は umount コマンドでアンマウントします。)

ubuntu_adcard_mount.png
Ubuntu上でマウントされた SDカード(右クリックメニューで取り外すことができる)

dd if=イメージファイル of=SDカードのデバイスファイル bs=1M のようにコマンドを入力し実行します。 ただし、デバイスファイルへの書き込みは管理者(root)権限が必要ですので、sudo を使用してください。

 $ unzip  2013-02-09-wheezy-raspbian.zip
 Archive:  2013-02-09-wheezy-raspbian.zip
   inflating: 2013-02-09-wheezy-raspbian.img
 $ sudo dd if=2013-02-09-wheezy-raspbian.img of=/dev/sdb bs=1M
 1850+0 records in
 1850+0 records out
 1939865600 bytes (1.9 GB) copied, 201.543 s, 9.6 MB/s

実行中は別のターミナルなどで、iostat コマンドを実行して書き込みが正しく行われているかどうか見ることができます。 (最近のディストリビューションではデフォルトでインストールされていないことがあります。debian/ubuntu では apt-get install sysstat で iostat コマンドが使えるようになります。)

 $ iostat -mx 1
  avg-cpu:  %user   %nice %system %iowait  %steal   %idle
            0.00    0.00    0.00   50.25    0.00   49.75
 
 Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
 sda               0.00     0.00    0.00    1.00     0.00     0.00     8.00     0.00    0.00   0.00   0.00
 sdb               0.00  1856.00    0.00   78.00     0.00     9.14   240.00   143.40 1855.85  12.82 100.00

sdb の項目を見ると 9.14MB/sの書き込み速度が出ていることがわかります。 class 6 の SDカードなら 6MB/sec, class 10の SDカードなら 10MB/sec 程度の速度が出ていれば、問題なく書き込まれていると考えてよいでしょう。 書き込みが終了すると、ディストリビューションによっては自動でマウントされる場合があります。その場合、アンマウントしてからSDカードを抜いてください。

イメージの書き込み (Mac OS X)

Mac OS Xも Linux と同様 ddコマンドを利用して書き込みます。 ただし、Mac では SDカードを挿入すると自動的にマウントされてしまい、マウント中は ddコマンドで SDカードに書き込むことができないので、アンマウント (OSから取り外す) する必要があります。

SDカードを差し込むと Finder に図のように SDカードのアイコンが現れます。 アンマウントするつもりでイジェクトボタンを押さないよう気を付けてください。

sdcard_mac.png
Mac にマウントされた SDカード

SDカードのボリューム名はここでは Untitled です。ボリューム名を覚えておきます。 コマンドプロンプトから df コマンドを入力すると以下のように表示されます。

 $ df -k
 Filesystem                        1024-blocks      Used Available Capacity   iused    ifree %iused  Mounted on
 /dev/disk0s2                        500000000 437664508  62079492    88% 109480125 15519873   88%   /
 devfs                                     194       194         0   100%       679        0  100%   /dev
 map -hosts                                  0         0         0   100%         0        0  100%   /net
 map auto_home                               0         0         0   100%         0        0  100%   /home
 /dev/disk1s1                            57288     18992     38296    34%       512        0  100%   /Volumes/Untitled

 一番下 ''/Volumes/Untitled'' とあるのが先ほどの SDカードのマウントポイントです。一番左の SDカードのデバイス名 /dev/disk1s1 を覚えておきます。
このSDカードを一旦アンマウント します。diskutil というコマンドを使用し diskutil umount <マウントポイント> のように入力します。

 $ diskutil umount /Volumes/Untitled
 Volume (null) on disk1s1 unmounted
 $ df -k
 Filesystem                        1024-blocks      Used Available Capacity   iused    ifree %iused  Mounted on
 /dev/disk0s2                        500000000 437664716  62079284    88% 109480177 15519821   88%   /
 devfs                                     194       194         0   100%       679        0  100%   /dev
 map -hosts                                  0         0         0   100%         0        0  100%   /net
 map auto_home                               0         0         0   100%         0        0  100%   /home

先ほどの /Volumes/Untitled が消えて、SDカードがアンマウントされていることがわかります。 次にddコマンドを使用してイメージを書き込みます。 dd if=イメージファイル of=/dev/rdisk1 bs=1m のように入力します。 of=/dev/rdisk1 は先ほど覚えたデバイスファイル /dev/disk1s1 のうち後ろの s1 を取り、さらにdiskの前に raw deviceであることを示す r を付けたデバイス名です。

このコマンドはデバイスファイルにアクセスするので管理者 (root) でなければ実行できません。sudoを使用して以下のように実行します。

 $ sudo dd if=2013-02-09-wheezy-raspbian.img of=/dev/rdisk1 bs=1m
 1850+0 records in
 1850+0 records out
 1939865600 bytes transferred in 302.377337 secs (6415380 bytes/sec)
 $

書き込み中は、「アクティビティモニタ」で「ディスクの動作」を見ることで書き込みが正しく行われているかどうかわかります。 class 6 の SDカードなら 6MB/sec, class 10の SDカードなら 10MB/sec 程度の速度が出ていれば、問題なく書き込まれていると考えてよいでしょう。

書き込みが終了すると、自動的に再度マウントされますので、今度は Finder のイジェクトボタンを押して SDカードを抜きます。

Raspberry Pi の初期設定

Raspberry Pi の起動

Raspberry Pi に HDMIモニター、キーボード、ネットワークを接続してください。

SDカードを挿入し Raspberry Pi に始めて電源を投入すると、各種ドライバの読み込み画面が表示された後、以下の設定画面 (raspi-config) が表示されます。

なお、後述の PiRT-Unit のシリアルコンソールから操作する場合、raspi-config は表示されません。 以下のユーザー名、パスワードでログインして raspi-config コマンドを実行することで初期設定を行うことができます。

  • ID' : pi
  • パスワード'' : raspberry

 Debian GNU/Linux 7.0 rtunit0 ttyAMA0
 
 rtunit0 login: pi
 Password:
 Last login: Sat Feb  9 03:40:44 UTC 2013 on ttyAMA0
 Linux rtunit0 3.6.11+ #371 PREEMPT Thu Feb 7 16:31:35 GMT 2013 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. 
 
 NOTICE: the software on this Raspberry Pi has not been fully configured. Please run 'sudo raspi-config'
 $ raspi-config
 
raspi-config2.png
Raspberry Pi 初期設定画面

設定項目

各項目の内容を以下に示します。 必要に応じて各項目の設定を行ってください。

1 Expand Filesystem 使用する SD カードのパーティションを拡張します。初期状態では、SD カードの全体を使用していないので、特に理由がなければ拡張を行ってください。
2 Change User Password 初期設定ユーザー 「pi」 のパスワードを変更します。 利用者のわかりやすいパスワードに変更してください。
3 Enable Boot to Desktop/Scratch 起動時の画面の設定で、デフォルトはコンソール利用となっています。GUI 利用に変更したい場合には設定します。
4 Internationalisation Options 「ロケール」、「タイムゾーン」、「キーボード配列」の設定です。
I1 Change Locale ロケール設定を行います。キーボード配列は必要に応じて [ja_JP.ECU-JP ECU-JP] などに設定してください。 その際は日本語フォントのインストールが必要となるようです。
I2 Change Timezone タイムゾーンの設定を行います。日本国内で使用する場合は [Asia]-[Tokyo] を設定してください。
I3 Change Keyboard Layout Set the keyboard layout to match your keyboard キーボードの設定を行います。必要に応じて日本語キーボード等に設定して下さい。
5 Enable Camera カメラモジュールを接続している場合に設定してください。
6 Add to Rastrack Rastrack への登録
7 Overclock オーバークロック
8 Advanced Options その他のオプション。ここでは PiRT-Unit の環境で必要な項目のみ取り上げます。
A6 SPI SPIを利用する場合は、Enable に設定します。(デフォルトはDisable)
A7 I2C I2Cを利用する場合は、Enable に設定します。(デフォルトはDisable)
9 About raspi-config 本ツールに関する情報を表示します。

上記の各項目を設定した後は、[Tab] キーにて [Finish] を選択して実行してください。 Raspberry Pi 本体が再起動し、各種設定が有効となります。

再起動後、コマンド入力待ち状態で、「startx」を実行すると Raspbian のデスクトップ画面が表示されます。

raspberry_xwindow.png
Raspbian デスクトップ画面

終了する場合は、以下のコマンドで停止した後、本体から電源を抜いてください。

 $ sudo halt

無線LAN の設定

Raspberry Pi の USB に無線LANドングルを挿入し設定することで、Raspberry Pi を無線化できます。 移動ロボットなどに搭載する際には便利です。

/etc/network/interfaces の編集

まず、/etc/network/interfaces を以下のように編集します。

 $ sudo vi /etc/network/interfaces

以下の2か所を書き換えます。

 iface wlan0 inet manual
         ↓
 iface wlan0 inet dhcp

 wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
                      ↓
 wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

/etc/wpa_supplicant/wpa_supplicant.conf の編集

次に、無線LANの ESSID とキーを登録します。

 $ sudo bash
 # cd /etc/wpa_supplicant
 # wpa_passphrase ESSID pass >> wpa_supplicant.conf

SSID には無線LANの ESSID、pass には無線LANのキーを入力します。リダイレクトの際、> ではなく >> (追記)を使用するよう注意してください。 結果は以下のようになっていると思います。

 ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
 update_config=1
 network={
         ssid="OpenRTM"
         #psk="4332221111"
         psk=142914b76be167767055ff945898baaaf83c42b3ad3b99afb0ae531e8fb15e5e
 }

無線LAN アクセスポイントの設定によっては、追加の設定が必要になるかもしれません。 以下に、一例を示します。

 ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
 update_config=1
 network={
         ssid="OpenRTM"
         proto=WPA2
         key_mgmt=WPA-PSK
         pairwise=TKIP CCMP
         group=TKIP CCMP
         #psk="4332221111"
         psk=142914b76be167767055ff945898baaaf83c42b3ad3b99afb0ae531e8fb15e5e
 }

最後に、インターフェースを初期化します。

 # ifdown wlan0
 # ifup wlan0
 Internet Systems Consortium DHCP Client 4.2.2
 Copyright 2004-2011 Internet Systems Consortium.
 All rights reserved.
 For info, please visit https://www.isc.org/software/dhcp/
  : 中略
 DHCPREQUEST on wlan0 to 255.255.255.255 port 67
 DHCPOFFER from 192.168.11.1
 DHCPACK from 192.168.11.1
 bound to 192.168.11.26 -- renewal in 34810 seconds.

ここで、無線LAN に接続できない場合、/etc/network/interfaces, /etc/wpa_supplicant/wpa_supplicant.conf の設定を見直してください。

 
 # ifconfig wlan0
 wlan0     Link encap:Ethernet  HWaddr XX:XX:XX:XX:XX:XX
           inet addr:192.168.11.26  Bcast:192.168.11.255  Mask:255.255.255.0
           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
           RX packets:1218 errors:0 dropped:0 overruns:0 frame:0
           TX packets:21 errors:0 dropped:0 overruns:0 carrier:0
           collisions:0 txqueuelen:1000
           RX bytes:250608 (244.7 KiB)  TX bytes:4506 (4.4 KiB)

無事、無線LAN wlan0 に IPアドレスが割り振られました。

ホスト名でリモート接続する

Raspberry Pi に ssh でリモートログインで操作する場合、固定IPアドレスを割り振っていなければ、通常 Raspberry Pi の IPアドレスをコンソールで調べて接続する必要があります。

そこで Bonjour互換の avahi というサービスをインストールします。 Bonjour は Apple が提唱するネットワーク上のサービスを自動的に検索して利用できるようにするためのサービスです。 avahi を使うと、DHCP で IPアドレスを割り振っている Raspberry Pi に対してもホスト名でアクセスすることができるようになります。

ホスト名の設定

他のホスト名と衝突しないホスト名を選び設定します。

 $ sudo vi /etc/hostname

/etc/hostname に1行目にホスト名を記載します。初期値は raspberrypi となっています。 さらに、/etc/hosts の 127.0.1.1 raspberrypi となっている部分を上で決めた自分のホスト名に書き換えます。

 $ sudo vi /etc/hosts

avahi-daemon のインストール

以下のコマンドで avahi デーモンをインストールします。

 $ sudo apt-get update
 $ sudo apt-get install avahi-daemon

自ホストに対してping を打ってみます。ホスト名の後に .local を付けた名前を使います。

 $ ping myhost.local

これで ping が返ってくれば、avahi がほぼ正しく設定されていることになります。

Bonjour のインストール (Windowsのみ)

PC から avahi が設定された RaspberryPi にアクセスするためには、PC側にも avahi か Bonjour がインストールされている必要があります。

Linux では、RaspberryPi と同様に avahi-daemon をインストールすれば使用できます。また Mac はデフォルトで Bonjour がインストールされているので、特に何もする必要がありません。

Windows ではデフォルトでは Bonjour はインストールされていません。 最も簡単に Bonjour を導入する方法は iTunes をインストールすることです。

どうしても iTunes をインストールしたくない場合は、アーカイバアプリケーションなどで、ダウンロードした iTunesSetup.exe を展開すると BonjourSetup.exe を抽出することもできます。

また、以下の Apple Bonjour 印刷サービスにも Bonjour が同梱されています。(iTunesに同梱されているものよりバージョンが若干古いようです。)

現在 Applie では Bonjour for Windows 単体としては配布は行なっていませんが、かつて配布していたものを再配布しているサイトも幾つかあります。(ただし、古いバージョンしか入手できないようです。) 以下は Appleサイト以外の Bonjour ダウンロードサイトです。自己責任でご利用ください。

Bonjour がうまく機能しない場合

ファイヤウォールが動作している場合、Bonjour がうまく機能しないことがあります。 その場合、UDPポート5353を開放するかファイヤウォールを OFF にしてください。

TeraTerm のインストール

Windows から RaspberryPi に ssh 経由でログインするためには、ssh クライアントをインストールする必要があります。 Windows で利用可能なクライアントは多数ありますが、ここでは Tera Term を紹介します。

TeraTerm をインストール後、起動すると接続ダイアログが現れるので、先ほど設定したホスト名+.local を「ホスト」のテキストボックスに入力しOKを押します。 パスワードが変更されていなければ、

  • ID: pi
  • パスワード: raspberry

でログインできます。

なお、Linux や Mac はターミナルウインドウを開いて

 $ ssh pi@myhost.local

のようにして接続します。

xfinderの利用方法

Raspberry Pi はヘッドレス状態 (モニタ、キーボードを接続しない状態) では IPアドレスなどを知る術がないため初期設定を行うのは少々困難です。 最初にモニタとキーボードを接続して、ホスト名を設定し前述のように Avahi経由で IPアドレスをホスト名から知ることも可能ですが、全く設定していない Raspberry Pi についてはこの方法も使えません。

xfinder とは

xfinder は Raspberry Pi や BeagleBone などのCPUボードに搭載されている Ethernet インターフェースの MAC (Media Access Control) アドレスからIPアドレスを割出しログインするためのツールです。

Ethernet のインターフェースには48ビットの固有のアドレス(MAC (Media Access Control) アドレス)が割り振られており、その上位24ビットはベンダ(ネットワーク機器を開発する企業など)の固有のアドレスとなっています。 Ethernet ではパケットの送受信をするために相互に MACアドレスを知る必要があり、IPアドレスから MACアドレスを調べるための ARP(Address Resolution Protocol) と呼ばれるプロトコルが利用できます。 xfinderでは、ネットワーク上に接続されている特定の MACアドレスのパターンを見つけることにより、Raspberry Pi などのヘッドレスシステムの IPアドレスを調べ、ssh 等でログインし設定・開発を容易に行えるようにサポートします。

raspberrypi_and_arp.png
xfinderでRaspberryPiを見つける

xfinder は一つの実行ファイルでコマンドラインツール (CUI モード) とグラフィカルユーザインターフェースツール (GUI モード) の2通りとして利用することができます。 ここでは、GUIモードの xfinder の使い方について説明します。

xfinder のダウンロード

xfinder は以下の場所からダウンロードできます。

xfinder_folder.png
ダウンロードした xfinder

xfinder (GUIモード) を使う

xfinder の使い方は以下の3ステップです。

  • ネットワークをスキャンしてRaspberry Pi 等を見つける
  • スキャンして見つかった Raspberry Pi を確認する
  • TeraTerm 等ターミナルソフトウエアでログインして作業をする

起動

xfinder.exeを起動すると、以下の様な画面が表示されます。

xfinder_gui_panes.png
xfinder の GUI画面

まず、①左上のペインにてスキャンする条件(インターフェース、ボード、MACアドレスパターン等)を指定しスキャンを開始、②次にスキャンして見つかった Raspberry Pi 等のリストが表示されるので選択、③の左下のペインにてログイン条件を指定してターミナルアプリケーションを起動します。 ターミナルアプリケーションが起動後は、対象となる Raspberry Pi にログインして設定やプログラムの開発などを行うことができます。

なお、右のペインに表示されたボードのリストをダブルクリックすることでターミナルアプリケーションの起動とログインを行うことも可能です。

Scan settings

左上の Scan settings では、ネットワークをスキャンするための条件を設定します。

Interface address

現在の PC のどのネットワークインターフェースから Raspberry Pi を探すかを選択します。複数のネットワークインターフェースがある場合、複数のIPアドレスが表示されるので、どのネットワーク(例えば、一つはグローバル側、もう一つがプライベート側のネットワークにつながっており、プライベート側のネットワークにある Raspberry Pi を探したい場合はここでプライベートアドレスを選択します。)をスキャンするかを選択します。

xfinder_select_ifaddr.png
Interface addressでスキャンするネットワークインターフェースの IPアドレスを指定する

全てのネットワークインターフェースに対してスキャンを行う場合はALLを選択してください。 どの IPアドレスがどのネットワークインターフェースと対応しているかわからない場合は、コントロールパネルネットワークとインターネットネットワークと共有センターアダプターの設定の変更からアダプタのアイコンをクリックしてどのようなIPアドレスが割り当てられているか確認してください。

また、コマンドプロンプトを開いて ipconfig コマンドを実行しインターフェースと割り当てられているIPアドレスを確認することもできます。

Board type

どのボードを探すかコンボボックスから選択します。Raspberry Pi か BeagleBone を選択でき、デフォルトでは Raspberry Pi が選択されています。

xfinder_select_board.png
スキャンするボードタイプを指定する

この一覧に探したいボードがない場合は、該当するボードのネットワークインターフェースの MACアドレスの上6ケタを調べ、次の Match Pattern のテキストボックスに入力しスキャンする必要があります。

Raspberry Pi にUSB 無線LANアダプタを付け、無線LANのみで接続している場合はここで Raspberry Pi を選択しても探すことはできません。 無線LANアダプタの MACアドレスの MACアドレスの上6ケタ (例えば Buffaroの場合10:6f:3f) を Match Pattern に入力して探します。

Match pattern

Raspberry Pi や BeagleBone 以外のボードを探す場合、ここに探したい MACアドレスのパターンを入力します。

xfinder_select_pattern.png
スキャンする MACアドレスのパターンを指定する

また Raspberry Piに無線LANアダプタなどを装着している場合も、メーカー固有の MACアドレス上6ケタを入力することで探し出すことが可能です。 ただし、メジャーなメーカーの無線LANアダプタなどはスキャンすると多数発見されることもあります。

Scan ボタン/ Abort ボタン

Scan ボタンはスキャンを実行する際に押します。スキャン中は押すことができません。 Abortボタンはスキャン実行中に途中でやめたい場合に押します。スキャン実行中のみ押すことができます。 ボタンの下のプログレスバーはスキャンの進捗状況を表示します。

スキャン実行時

Found nodes

右側の Found nodes のペインはスキャンして見つかったボードのIPアドレス、MACアドレスおよびホスト名を表示します。

  • IP address: 見つかったボードの IPアドレスを表示します。ヘッダ部分を押すと IPアドレス順でソートします。
  • MAC address: 見つかったボードの MACアドレスを表示します。ヘッダ部分を押すと MACアドレス順でソートします。
  • Host name: 見つかったボードのホスト名を表示します。ヘッダ部分を押すとホスト名順でソートします。

なお、ここに表示されたリストをダブルクリックすると、左の Terminal launcher の設定に従ってターミナルアプリケーションが起動しログインできます。

xfinder_launchterm_dclick.png
Found nodes から直接ターミナルアプリケーションを起動する

Terminal launcher

左側の Terminal launcher のペインは見つかったホストに対してターミナルアプリケーションを利用してログインする際に使用します。

  • User name: ログイン時に使用するユーザー名を入力します。左上のScan settingBoard type 設定によって自動的に値が入力されます。
  • Password: ログイン時に使用するパスワードを入力します。左上のScan settingBoard type 設定によって自動的に値が入力されます。
  • Port: ログイン時に使用するポート番号を入力します。デフォルトでは ssh のデフォルトポート番号20が設定されています。
  • Terminal App: 使用するターミナルアプリケーションがコンボボックスから選択で来ます。利用可能なターミナルアプリケーションは Windows では TeraTerm, Poderosa, PuTTY のいずれかで、起動時にこれらがインストールされているかチェックし、利用可能なものだけリストに表示されます。
  • Loginボタン: 右側の Found nodes でログインするノード選択すると押下可能になります。このボタンを押すと、上の設定に従ってターミナルアプリケーションが起動され Raspberry Pi にログインできます。
ボードタイプ User name Password
RaspberryPi pi raspberry
BeagleBone root (パスワード無し)

xfinder_launcterm_by_loginbutton.png
Login ボタンを押してターミナルアプリケーションを起動する

launch_teraterm.png
起動したターミナルアプリケーション (TeraTerm Pro)

開発環境のインストール

Raspberry Pi に開発環境をインストールすれば、Raspberry Pi上でのセルフコンパイルによる開発が可能です。(このサイズの組込み Linux ボードでは、通常クロスコンパイルによる開発が普通です。)

従って、PC上の RTCBuilder で生成した RTコンポーネントのコードを、Raspberry Pi上でコンパイル、実行することができます。 残念ながら Eclipse をインストールして実用的な速度で使用することは難しいようです。

この節では RTコンポーネントを開発するために必要なパッケージをインストールしていきます。

OpenRTM-aist のインストール

OpenRTM-aist は、apt-get を使用してインストールすることが可能です。 まず sources.list を修正します。

 $ sudo vi /etc/apt/sources.list

sourcelist に以下の1行を加えてください。

 deb http://openrtm.org/pub/Linux/raspbian/ wheezy main

次に、以下の手順でインストールを行います。

 # apt-get update
 # apt-get -y --force-yes install gcc g++ make uuid-dev
 # apt-get -y --force-yes install libomniorb4-dev omniidl omniorb-nameserver
 # apt-get -y --force-yes install openrtm-aist openrtm-aist-dev openrtm-aist-example
 # apt-get -y --force-yes install openrtm-aist-python openrtm-aist-python-example

サンプルコンポーネントの実行

OpenRTM-aist のインストール後、サンプルコンポーネントを起動してOpenRTM-aist が正しくインストールされたかどうか確認します。

下図のように、PC側でネームサーバと ConsoleIn コンポーネント、Raspberry Pi側でネームサーバと ConsoleOut コンポーネントを実行します。 コンポーネントはデフォルトで localhost のネームサーバに接続しますので、これを利用して rtc.conf に特定のネームサーバを設定することなく簡単にコンポーネントにアクセスします。 PC上の RTSystemEditor で、PC のネームサーバと Raspberry Pi上のネームサーバに接続し、ConsoleIn コンポーネントと ConsoleOut コンポーネントを接続します。

sample_component_test.png
サンプルの実行

Raspberry Pi上で ConsoleOut の実行

Raspberry Pi に TeraTerm などで接続後、コンポーネントを起動します。 ネーミングサービスを起動してから ConsoleOut を起動します。

 $ rtm-naming
 $ /usr/share/OpenRTM-x.y/examples/ConsoleOutComp
 または
 $ python /usr/share/OpenRTM-x.y/examples/python/SimpleIO/ConsoleOutComp.py

上の omniorb-nameserver のインストール時に、システム起動時に自動的に omniORB のネームサービスが起動するようになっています。 しかし、ネームサービスの起動タイミングとネットワークインターフェースの起動タイミングによっては、外部からネームサーバに正しくアクセスできない場合があります。 その場合は、rtm-naming コマンドによりネームサーバを再起動することで、問題に対処できる場合があります。

PC側での ConsoleIn の実行

まず、ネームサーバを起動します。 Windows の場合、スタートメニューから 「OpenRTM-aist x.y」→「C++」→「tools」の下のStart Naming Service から起動します。 ついでに、RTSystemEditor も起動しておきます。

namingservice_on_windows.png
ネーミングサービスの起動

続いて、ConsoleIn を起動します。 「OpenRTM-aist x.y」→「C++」→「examples」の下の ConsoleOut をクリックして ConsoleOut コンポーネントを起動します。

RTSystemEditor により接続

RTSystemEditor の左側の NameService View のコンセントアイコンをクリックし、ネームサーバに接続します。 まず、自ホストのネームサーバに接続します。接続ダイアログに localhost と入力します。

connect_ns_localhost.png
ネームサーバへの接続(localhost)

次に、Raspberry Pi のネームサーバへ接続します。再度 NameService View の接続アイコンをクリックし、Raspberry Pi のホスト名+.localををダイアログに入力します。

connect_ns_myhost.png
ネームサーバへの接続(Raspberry Pi)

ネームサービスビューには2つのネームサーバの状態が表示され、それぞれのネームサーバの下に ConsoleIn0、ConsoleOut0 という2つのコンポーネントが見えているはずです。 RTSystemEditor のメニューバーのonlineエディタアイコン(ONと書かれたアイコン)をクリックし、SystemEditor を開きます。 NameService View から ConsoleIn0 と ConsoleOut0 をそれぞれ SystemEditor 上にドラッグアンドドロップし、InPort と OutPort を接続します。

rtsystemeditor_consoleinout.png
RTSystemEditorによるConsoleInとConsoleOutの接続

メニューバーの緑の再生ボタンをクリックすると、2つのコンポーネントがアクティベートされ上図のような状態になります。

PC側の ConsoleIn コンポーネントのウインドウから適当な数字を入力します。

consolein_window.png
ConsoleIn (PC) 側から数値を入力

すると、下図のように Raspberry Pi側の ConsoleOut の表示に ConsoleIn で入力した数値が現れます。

consoleout_window.png
ConsoleOut (Raspberry Pi) 側の表示

トラブルシューティング

ネットワーク環境や PC の設定により、上記の手順でうまくいかないことがあります。以下のトラブルシューティングを参考に問題を解決してください。

Raspberry Pi側のサービスのしたに ConsoleOut が表示されない

ネームサーバの問題
ネームサーバのエンドポイントアドレスが不正な場合このような現象が起きます。rtm-naming で再度ネームサーバを起動しなおすと解決する場合があります。

このほか、Raspberry Pi の有線LANと無線LAN等2つ以上のネットワークインターフェースがある場合、PCとの接続に使用するどちらかのネットワークのみを使うように設定することで解決するケースもあります。

コンポーネントの問題
コンポーネントが読み込んだ設定ファイル(rtc.conf)に localhost 以外のネームサーバが登録されている場合が考えられます。corba.nameservers: localhost と記述するなど localhost のネームサーバにコンポーネントを登録するよう設定してください。

また、Raspberry Pi の有線LANと無線LAN等2つ以上のネットワークインターフェースがある場合、PCとの接続に使用するどちらかのネットワークのみを使うように設定することで解決するケースもあります。

RTSystemEditor で接続できない、反応がなくなる等

PC側のコンポーネントの問題
PCにネットワークインターフェースが2つ以上ある場合、Raspberry Pi で使用しない側のインターフェースアドレスがコンポーネントの参照として利用されている場合このような現象が起こります。

コマンドプロンプトから ipconfig で PC の IPアドレスを調べる等して、rtc.conf に使用する方の IPアドレスを以下のように設定します。

 corba.endpoints: 192.168.11.20

ただし、Vista 以降の Windows では、C:\Program Files 以下のファイルは簡単には編集ができなくなっています。c:\tmp など適当なディレクトリーに ConsoleIn.exe と rtc.conf をコピー(あるいは新たに作成)するなどして、対処してください。

Raspberry Pi側のコンポーネントの問題
Raspberry Pi の有線LANと無線LAN等2つ以上のネットワークインターフェースがある場合で、それぞれが別のネットワークにつながっている場合、上述のPCと同様の問題が起こります。ifconfig で使用する方のIPアドレスを調べ、rtc.conf に以下のように記載します。

 corba.endpoints: 192.168.11.21

CMake のインストール

cmake は apt-get を利用してインストールする事が可能です。root 権限を持つユーザでインストールを行います。

 $ sudo apt-get update
 $ sudo apt-get install cmake

Doxygen のインストールについて

CMake ベースの RTコンポーネントプロジェクトでは、デフォルトで doxygen を利用してドキュメントを生成するように設定されています。 しかしながら、doxygen をインストールすると、LaTeX等も同時にインストールされてしまい、SDカードの容量を圧迫しますのでこのチュートリアルでは Doxygen をインストールしません。

ドキュメントを生成しない方法

CMake ベースの RTCプロジェクトにおいて doxygen でのドキュメント生成を抑制するには、トップレベルの CMakeLists.txt で、

 option(BUILD_DOCUMENTATION "Build the documentation" ON)
    ↓
 option(BUILD_DOCUMENTATION "Build the documentation" OFF)

のように変更します。

Doxygen のインストール

SDカードの容量が十分ある場合 doxygen を apt-get で以下のようにインストールすることができます。

 $ sudo apt-get install doxygen

※Doxygen のインストールが完了するまでには、十数分程度かかります。

Subversion/Git のインストール

ソースコードを外部から取得する際にたびたび使用するので subversion/git をインストールすることをお勧めします。

 $ sudo apt-get install subversion git

コンパイルのテスト

コンポーネントのコンパイルが行えるかテストしてみます。 以下のリポジトリに移動ロボット Kobuki用コンポーネントがありますので、チェックアウトしてコンパイルしてみます。

ソースコードのチェックアウト

ソースコードをチェックアウトしてみます。

 $ svn co http://svn.openrtm.org/components/trunk/mobile_robots/kobuki
   : 中略
 A    kobuki/libkobuki/doc/CMakeLists.txt
 A    kobuki/libkobuki/License.rtf
 A    kobuki/libkobuki/CMakeLists.txt
 A    kobuki/rtc.conf
 A    kobuki/CMakeLists.txt
 Checked out revision 2.
 $

kobuki ディレクトリーいかにソースコードがチェックアウトされましたので、build ディレクトリーを作成しその中でビルド、インストールします。

  $ cd kobuki
  $ mkdir build
  $ cd build
  $ cmake -DCMAKE_INSTALL_PREFIX=/usr ..
  $ make
  $ cd src
  $ make install

このソースコードはデフォルトで Doxygenに よるドキュメント生成が OFF になっていますので、Doxygen がインストールされていなくてもビルドできるでしょう。

サンプルコンポーネントの実行

以下の例では、GPIO を用いて、スイッチの ON/OFF の検出と、LED の点灯を行うコンポーネント (DigitalIn-RTC、DigitalOut-RTC) を作成して Raspberry Pi の特徴である GPIO の利用について理解を深めます。 サンプルコンポーネントのソースコードは以下からダウンロードできます。

Raspberry Pi の GIOP

Raspberry Pi には GPIO端子があり、これを利用することで様々な外部デバイスを利用することができます。

Raspberry Pi 本体に付属している GPIO のピンアサインを以下に示します。

raspberrypi_gpio_pinassign.png
Raspberry Pi GPIO のピンアサイン

GPIO を使用する場合には、各ピンの位置に注意してください。特に5V 端子を使用する場合、配線を誤ると Raspberry Pi 本体および SD カードを破壊してしまう危険がありますので、十分に注意してください。

ブレッドボード配線例

LED を点灯させる回路と、スイッチの ON/OFF を検出する回路を作成します。 ブレッドボード等があれば簡単に回路を組めますが、ない場合でも部品点数が少ないのでリード線をはんだ付けするなどすれば比較的容易に回路を組むことができるでしょう。 以下に、必要な部品のリストを示します。

部品表
LED回路
LED 1個
抵抗 100Ω (茶黒茶金) ~330Ω (橙橙茶金)
リード線 若干
スイッチLED回路
LED 1個
抵抗 330Ω (橙橙茶金) ~1kΩ (茶黒赤金)
リード線 若干

Raspberry Pi が1台の場合は、以下の LEDとスイッチ回路を同じ Raspberry Pi に接続します。 もし、Raspberry Pi が2台あるなら、それぞれの Raspberry Pi に LED とスイッチを取り付けると面白いかもしれません。

DigitalIn-RTC 用配線例

DigitalIn-RTC は、データポートに入力された bool 値 (true/false) を指定された GPIO ポートに出力するコンポーネントです。GPIO ポートの出力値を観測するために、GroundピンとGPIO 18ピンに LED と抵抗を接続し下図のような回路を作成します。

gpio_led_circuit.png
LED 接続回路図

ブレッドボードでこの回路を作成する場合はこのようになります。

3_rp2.png
ブレッドボードによる LED 回路配線例

DigitalOut-RTC 用配線例

DigitalOut-RTC は、GPIO ポートに入力された bool 値 (true/false) をデータポートから出力するコンポーネントです。 GPIO に値を入力するために、Ground, 3.3V Power, GPIO 17に抵抗とスイッチを接続して下図のような回路を作成します。

gpio_stiwch_circuit.png
タクトスイッチ接続回路図

ブレッドボードでこの回路を作成する場合はこのようになります。

3_rp3.png
ブレッドボードによりスイッチ回路配線例

コンポーネントのコンパイル

ソースコードを以下から Raspberry Pi にダウンロードして、DigitalIn-RTC/DigitalOut-RTC コンポーネントをコンパイルします。

DigitalIn-RTC のコンパイル

 $ unzip RaspberryPi_sample.zip
 $ cd RaspberryPi_sample/DigitalInRPI/
 $ vi CMakeLists.txt

ここで、CMakeLists.txt を書き換えて、ドキュメントの生成を抑制するよう設定します。

 option(BUILD_DOCUMENTATION "Build the documentation" OFF)
  ↓
 option(BUILD_DOCUMENTATION "Build the documentation" ON)
 
 $ mkdir build
 $ cd build
 $ cmake ..
 -- The C compiler identification is GNU 4.6.3
 -- The CXX compiler identification is GNU 4.6.3
   : 中略
 -- Configuring done
 -- Generating done
 -- Build files have been written to: /home/pi/RaspberryPi_sample/DigitalInRPI/build

OpenRTM-aist が正しくインストールされていれば、問題なく configure が終了します。 もし、OpenRTM や coil が無いなどでエラーが出た場合、OpenRTM-aist (C++版) が正しくインストールされていることを確認 (dpkg -l |grep openrtm 等) してください。

 $ make
  : 中略
 Scanning dependencies of target DigitalInComp
 [ 66%] Building CXX object src/CMakeFiles/DigitalInComp.dir/DigitalInComp.cpp.o
 [100%] Building CXX object src/CMakeFiles/DigitalInComp.dir/DigitalIn.cpp.o
 Linking CXX executable DigitalInComp
 [100%] Built target DigitalInComp
 $

コンパイルされたコンポーネント DigitalInComp は src の下にあります。

 $ ls src/
 CMakeFiles  cmake_install.cmake  DigitalInComp  DigitalIn.so  Makefile

DigitalOut-RTC のコンパイル

DigitalIn-RTC と同様にコンパイルします。

 $ cd RaspberryPi_sample/DigitalOutRPI/
 $ mkdir build
 $ vi CMakeLists.txt

ここで、CMakeLists.txt を書き換えて、ドキュメントの生成を抑制するよう設定します。

 option(BUILD_DOCUMENTATION "Build the documentation" OFF)
  ↓
 option(BUILD_DOCUMENTATION "Build the documentation" ON)
 
 $ mkdir build
 $ cd build
 $ cmake ..
 -- The C compiler identification is GNU 4.6.3
 -- The CXX compiler identification is GNU 4.6.3
   : 中略
 -- Configuring done
 -- Generating done
 -- Build files have been written to: /home/pi/RaspberryPi_sample/DigitalOutRPI/build
続いて make します。

 $ make
 -- OpenRTMConfig.cmake found.
 -- Configrued by configuration mode.
  : 中略
 Scanning dependencies of target DigitalOutComp
 [ 66%] Building CXX object src/CMakeFiles/DigitalOutComp.dir/DigitalOutComp.cpp.o
 [100%] Building CXX object src/CMakeFiles/DigitalOutComp.dir/DigitalOut.cpp.o
 Linking CXX executable DigitalOutComp
 [100%] Built target DigitalOutComp
 $

コンパイルされたコンポーネント DigitalOutComp は src の下にあります。

 $ ls src/
 CMakeFiles  cmake_install.cmake  DigitalOutComp  DigitalOut.so  Makefile

コンポーネントの実行

各RTC が正常にコンパイルできたら、NameServer を起動後、各RTC を起動します。

 $ rtm-naming
 $ sudo  /home/pi/RaspberryPi_sample/DigitalOutRPI/build/src/DigitalOutComp &
 $ sudo  /home/pi/RaspberryPi_sample/DigitalInRPI/build/src/DigitalInComp &

&color(red){※サンプルコンポーネントは GPIO を利用するので root 権限で実行する必要があります。}

PC上で RTSystemEditor を起動し、Raspberry Pi上の NameServewr に接続します。 各RTC を配置し、ポート間の接続を行った後、活性化(Activate)します。

3_rp4.png
サンプル RTC の実行

各RTC が正常に起動すると、タクトスイッチの状態に応じて、LED が点灯/消灯するようになります。

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バスへのアクセスを単一コンポーネントにまかせ、個別デバイスからポート間通信でデータを取得する
  • ロックなどの排他制御を共有オブジェクトなどを使って実装する などが考えられますが、それぞれ一長一短があるので状況に応じて選択するのがよいでしょう。

移動ロボットKobukiの制御

Kobuki は Yujin Robotics から発売されている研究用移動ロボットです。 掃除機ロボット Roomba とほぼ同様の大きさで、USBシリアル接続でPC等から制御ができるようになっています。 また、IO、シリアル入出力、電源コネクタ、ボタン、LED等が装備されており、実験用ロボットとしての利用に適しています。

以下の Kobuki のサンプルを動作させるために必要なソフトウエアのインストールなどを行うスクリプトがこちらからダウンロードできます。

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

で、以下の解説で行っている環境構築と Kobuki のサンプルのコンパイルが自動で行われます。

Raspberry Pi と Kobuki の接続

下図は Kobuki のメインパネルです。

kobuki_panel.png
Kobuki DC 出力コネクタ

Raspberry Pi への電源供給に 5V1A DC出力コネクタ、Raspberry Pi との接続には USBコネクタを利用します。

電源

Kobuki には 5V 1A 出力可能な DC出力コネクタがあり、Raspberry Pi の電源をここから供給することができます。

5V1A 出力コネクタは以下の型番のものを使用します。

Kobuki 5V1A用コネクタ
ハウジング Molex PN : 43645-0200
ターミナル Molex PN : 43030-0001

kobuki5v_connector.png
Kobuki DC5V1A用コネクタ

RTロボットショップなどでも購入できます。

下図のような DCコネクタと USBの変換ケーブルを作成することで、Raspberry Pi へ電源を供給します。

kobuki_raspberry_dccable.png
Raspberry Pi用 DCケーブル

近年ではスマートフォン用の USB出力端子がついたバッテリーが多数発売されていますので、こういった電源も利用できます。

battery.png
スマートフォン用バッテリー

USB

Kobuki に付属している USB ケーブルで Kobuki と Raspberry Pi を接続します。 Raspberry Pi側からは /dev/ttyUSB0 として見えます。

 $ ls /dev/ttyUSB*
 /dev/ttyUSB0

接続

Raspberry Pi を Kobuki に搭載して、電源と USBを接続します。Raspberry Pi を無線LAN接続にすれば、無線遠隔操作可能な Kobuki になります。

kobuki_and_raspi.png
Raspberry Pi を搭載したKobuki

Kobuki 動作時に脱落する可能性がありますので、Raspberry Pi はマジックテープなどで固定するとよいでしょう。

KobukiAIST RTコンポーネントのコンパイル

前節でも RTコンポーネントのコンパイルのテストを行いましたが、ここで再度おさらいします。まずは、KobukiAIST RTコンポーネントを以下のリポジトリからチェックアウトしビルドします。

  $ svn co http://svn.openrtm.org/components/trunk/mobile_robots/kobuki
  $ cd kobuki
  $ mkdir build
  $ cd build
  $ cmake -DCMAKE_INSTALL_PREFIX=/usr ..
  $ make
  $ cd src
  $ sudo make install

以上で、KobukiAIST RTCがビルドされ、実行ファイルが
  • /usr/lib/openrtm-1.1/rtc/KobukiAISTComp にインストールされるはずです。

試しに起動してみます。デバイスファイル /dev/ttyUSB0 へのアクセスには root 権限が必要ですので、sudo を使って起動しています。

 $ rtm-naming
 $ sudo /usr/lib/openrtm-1.1/rtc/KobukiAISTComp

RTSystemEditor を起動し、Raspberry Pi のホスト名またはIPアドレスに接続すると、KobukiAIST0 というコンポーネントが見えるはずです。 クリックして Configuration ダイアログを表示させてみてください。

LED1 や LED2 などの操作が行えるようになっていますので、radio ボタンで RED や GREEN などをクリックしてください。LED が点灯します。

KobukiAIST コンポーネントの自動起動

KobukiAIST コンポーネントをRaspberry Pi 起動時に自動的に起動するようにします。 これにより、Kobuki に電源を投入すると、Raspberry Pi および KobukiAIST コンポーネントが自動的に起動するようになり、Raspberry Pi にいちいちログインしなくとも Kobuki を RTC 経由で操作できるようになります。

以下のようなスクリプトを /etc/kobuki.sh として作成します。

 $ sudo vi /etc/kobuki.sh

kobuki.sh の内容な以下の通りです。

 #!/bin/sh
 #
 # KobukiAIST RTC launch script
 #
 #       Copyright Noriaki Ando <n-ando@openrtm.org>
 #       2011.03.27
 #
 # This script should be executed from rc script like a rc.local
 # as the following command line.
 #
 #
 ns=/usr/bin/rtm-naming
 kobukiRTC=/usr/lib/openrtm-1.1/rtc/KobukiAISTComp
 workdir=/tmp/kobuki
 
 \$ns
 sleep 5
 
 if test -d $workdir ; then
         echo ""
 else
         mkdir \$workdir
 fi
 
 cd $workdir
 
 while :
 do
     rm -f \$workdir/*.log
     \$kobukiRTC
     sleep 5
 done

実行権限をつけます。

 $ sudo chmod 755 /etc/kobuki.sh

さらに、自動的に起動するように /etc/rc.local の最後の exit 0 の手前に以下のような一行を挿入します。

 /etc/kobuki.sh 2>&1 | perl -p -e 's/\n/\r\n/g' 1>&2 &
 exit 0

これで、Raspberry Pi が起動すると、KobukiAIST コンポーネントも自動的に起動します。 また、万一 KobukiAIST コンポーネントを exit で終了させても、5秒後再度起動します。 Kobuki に電源が入っている限り、KobukiAIST コンポーネントは常駐し続けるようになっています。

Kobuki コンポーネントの操作

TkJoystick による操作

TkJoystick は OpenRTM-aist-Python にサンプルとして含まれているコンポーネントです。ただし、出力はジョイスティックのX-Y値と、対向2輪型移動ロボットの車輪速度用の出力のみで、2次元速度ベクトル (TimedVelocity2D) 出力は有りません。

TkJoyStick コンポーネントを改良して、2次元速度ベクトル (TimedVelocity2D) の出力をするようにし、Kobukiと接続して操作してみてください。

Windows では以下のディレクトリーもインストールされています。(x.yはバージョン)

  • C:\Program Files (x86)\OpenRTM-aist\x.y\examples\Python\TkJoyStick
  • C:\Program Files\OpenRTM-aist\x.y\examples\Python\TkJoyStick

ヒント

TkJoystick.py の中では、左右の車輪速度を計算しています。ここから、移動ロボットの運動学を考慮すれば、速度 v および角速度 ω を計算することができます。 (参考のため、東北学院大学の熊谷先生のページへのリンクを張っておきます。)

なお、TimedVelocity2D は以下のようなデータ構造となっています。

 struct Velocity2D
 {
   double va; // 角速度 [rad/s]
   double vx; // 並進速度(前方) [m/s]
   double vy; // 並進速度(横方向) [m/s] 対向2輪型では0
 };
 struct TimedVelocity2D
 {
   Time tm;
   Velocity2D data;
 };

自律的に移動させる

Kobuki をセンサーを利用して自律的に移動させてみます。 Kobuki は、バンパセンサー、近接センサー(遠・近)、Cliffセンサーを装備されています。 ここでは、Roomba っぽく、前進し続けて壁を検知したら、少し下がり、回転し、再び前進をする、というアルゴリズムで動かしてみます。 (Roomba はもう少し賢く動きますが。。。)

KobukiAIST RTC のセンサ出力は以下のようになっています。 IRセンサはドックからの赤外線による信号を受けるためのもので、障害物検知には使用できません。したがって、バンパおよび崖センサーのみが障害物・崖検知に利用できます。

No. enum 意味
0 RIGHT_BUMPER 右バンパ
1 CENTER_BUMPER 中央バンパ
2 LEFT_BUMPER 左バンパ
3 RIGHT_WHEEL_DROP 右車輪脱輪
4 LEFT_WHEEL_DROP 左車輪脱輪
5 RIGHT_CLIFF 右崖センサ
6 CENTER_CLIFF 中央崖センサ
7 LEFT_CLIFF 左崖センサ
8 RIGHT_IRFAR_RIGHT 右IR/ドック右遠
9 RIGHT_IRFAR_CENTER 右IR/ドック中央遠
10 RIGHT_IRFAR_LEFT 右IR/ドック左遠
11 RIGHT_IRNEAR_RIGHT 右IR/ドック右近
12 RIGHT_IRNEAR_CENTER 右IR/ドック中央近
13 RIGHT_IRNEAR_LEFT 右IR/ドック左近
14 CENTER_IRFAR_RIGHT 中央IR/ドック右遠
15 CENTER_IRFAR_CENTER 中央IR/ドック中央遠
16 CENTER_IRFAR_LEFT 中央IR/ドック左遠
17 CENTER_IRNEAR_RIGHT 中央IR/ドック右近
18 CENTER_IRNEAR_CENTER 中央IR/ドック中央近
19 CENTER_IRNEAR_LEFT 中央IR/ドック左近
20 LEFT_IRFAR_RIGHT 左IR/ドック右遠
21 LEFT_IRFAR_CENTER 左IR/ドック中央遠
22 LEFT_IRFAR_LEFT 左IR/ドック左遠
23 LEFT_IRNEAR_RIGHT 左IR/ドック右近
24 LEFT_IRNEAR_CENTER 左IR/ドック中央近
25 LEFT_IRNEAR_LEFT 左IR/ドック左近
26 KOBUKI_DOCKED ドック完了

これらの出力を受けるため RTC::TimedBooleanSeq 型の InPort が一つ必要になります。 また、Kobuki に移動速度指令を出力するための TimedVelocity2D型の OutPort が一つ必要になります。

基本プロファイル
コンポーネント名称 KobukiAutoMove
モジュール概要 Kobuki auto move component
バージョン 1.0.0
ベンダ名 AIST
アクティビティ
onInitialize、onFinalize、onActivated、onDeactivated、onExecute
データポート
[in] bumper
概要 センサ情報 true:障害物検出(バンパ接触、車輪落下、崖検知) false:障害物無し
データ型 TimedBooleanSeq
詳細 data[0]: 右バンパ、data[1]: 中央バンパ、... data[7]: 左崖センサ(上の表参照)
[out] targetVelocity
概要 移動ロボットの速度ベクトル
データ型 TimedVelocity2D
詳細 vx: 並進速度、vy: 0.0、va: 角速度
単位 vx [m/s]、va [rad/s]

以上の情報を手掛かりに、Kobuki を自律移動させる簡単なコンポーネントを作成してみてください。 コンポーネントの接続でうまく行かない場合は、トラブルシューティング をご覧ください。

ヒント

Kobuki の速度指令は TimedVelocity2D という型で、上でも示しましたが、以下のようなデータ構造です。

 struct Velocity2D
 {
   double va; // 角速度 [rad/s]
   double vx; // 並進速度(前方) [m/s]
   double vy; // 並進速度(横方向) [m/s] 対向2輪型では0
 };
 struct TimedVelocity2D
 {
   Time tm;
   Velocity2D data;
 };

対向2輪型移動ロボットでは、vyは常に0.0であると考え、たとえば直進なら

 va = 0.0; vx = 0.2; vy = 0.0;

となります。後進するなら、

 va = 0.0; vx = -0.2; vy = 0.0;

であり、その場で旋回するなら

 va = 0.0; vx = 0.0; vy = 1.0;

となります。

timed_velocity_2d.png
移動ロボットの座標系と TimedVelocity2D

InPort にデータが来ていたら、データを読み込みバンパ情報を取り出します。バンパ情報は、TimedBoolSeq というデータ型の .data という配列のメンバに格納されており、上の表で0,1,2番目の要素であることがわかります。 これらのどれかが true になっていたらバンパで衝突を検知したということですから、いったん下がり、旋回します。そして、再び前進します。 これらの動きを TimedVelocity2D のメンバーにそれぞれ設定して OutPort に writeすれば、速度指令データは Kobuki に伝達されます。 アルゴリズムのフローチャートを下に示します。

kobuki_auto.png
フローチャート

どのくらい下がるか・下がったか、あるいは旋回するか・したかを計測しながら制御するのが理想ですが、簡単のために sleep関数を使用することもできます。 Linuxではcoil::sleep が使えます

 coil::sleep(coil::TimeValue(0.01); // 10ms待つ

Windows では coil::sleep の精度が悪いので、Sleep関数を利用したほうがよいでしょう。 これらのヒントを基に、Kobuki を自律移動させるような制御コンポーネントを作成してみてください

解答

解答として、上記の TkJoyStick コンポーネントと自律移動コンポーネントを以下に示します。

Kobukiにロボットアームを搭載する手順

アカデミックスカラロボット

アカデミックスカラロボットはヴイストンが販売しているロボット制御学習用の水平多関節型ロボットアームです。

アカデミックスカラロボット制御の RTC については以下のページを参考にしてください。

この章ではアカデミックスカラロボットを Kobuki のプレートに固定する手順を説明します。


s_DSC00494.JPG

この作業には必要なものは以下の通りです。

名前 数量
Kobuki 1台
プレート 1枚
支柱(5cm) 8本
アカデミックスカラロボット 1台
木ネジ(2cm以上) 4本

ロボットの仕様

アカデミックスカラロボットの仕様
自由度 4自由度 + ハンド
サーボモーター RS304MD
通信方法 HID USB - UART ブリッジ

プレートに直接スカラボットを固定する場合

プレートに直接スカラロボットを取り付ける手順を説明します。

まずはプレートにキリ等で下穴をあけます。 以下の赤い点の位置に穴をあけてください。


plate.jpg

後はスカラロボットの根元部分を木ねじで固定すれば固定できます。


s_DSC00511.JPG

土台ごと固定する場合

スカラロボットを土台に取り付けて、土台をプレートに固定する方法について説明します。

土台の加工

Kobuki のプレートに固定するために、スカラロボットの土台に穴をあけます。 以下の図の赤い部分に穴をあけてください。穴の大きさは使用する木ねじの大きさで決めてください。


s_DSC00493.JPG

土台の取り付け

まずスカラロボットを土台に取り付けます。 図のように逆向きの取り付けた後、ユリアねじで固定してください。


s_DSC00492.JPG

ロボットの取り付け

予めプレートにはキリ等で下穴をあけておいてください。 土台の穴をあけた部分に木ネジを差し込んでネジでプレートと接合すれば完成です。


s_DSC00508.JPG

プレートの取り付け

まずは Kobuki に支柱を4本立てます。 レーザーレンジセンサー、Raspberry Pi は両面テープなどで Kobuki に接着しておいてください。


s_DSC00499.JPG

支柱は5cmの支柱を2つ接続したものを使用してください。


s_DSC00496.JPG

そしてプレートを載せてねじで留めれば完成です。


s_DSC00503.JPG

サインスマート製4自由度ロボットアーム

この章ではサインスマートが販売している4自由度ロボットアームを Kobuki に取り付ける手順を説明します。

4自由度ロボットアーム制御の RTC については以下のページを参考にしてください。

この作業には必要なものは以下の通りです。

名前 数量
Kobuki 1台
プレート 1枚
支柱(5cm) 8本
4自由度ロボットアーム 1台
Arduino Uno※ 1台
ジャンパーコード 15本以上
ブレッドボード 1枚
電池ボックス 単3×4本用 1個
単三電池 4本
木ネジ(2cm以上) 4本

※Intel Edison、Raspberry Pi から制御する場合は PCA9685 搭載のサーボドライバでも可

ロボットの仕様

4自由度ロボットアームの仕様
自由度 4自由度
サーボモーター MG995、SG90 9G

ロボットの取り付け

4自由度ロボットアームには最初から取り付け用の穴があいているためこちらへの加工は不要です。


arm_4axis.jpg

土台部分の穴に木ネジを差し込んでプレートと接合してください。

プレートの取り付け

アカデミックスカラロボットの手順と同じです。

付録

Raspberry Pi へのファイルコピー

Raspberry Pi の設定画面(Raspi-config)にて SSH を有効に設定することで、sFTP が利用できるようになります。 Windows から sFTP で Raspberry Pi に接続する場合には sFTP に対応したソフト(WinSCP など)を使用します。

こちらから WinSCP のダウンロードページに移動することができます。

4_app1.png
4_app2.png
図4-1 sFTP 接続

VNC(Virtual Network Computing)の利用

Raspbian のGUI 環境を開発用PC上で操作するために、VNCサーバーをインストールします。

こちら から VNC をダウンロードすることができます。

&#10;$ su&#10;# apt-get install tightvncserver&#10;

インストール途中で、VNCサーバーに接続する際のパスワード入力を求められますので、適当なパスワードを設定します。 VNCサーバーをインストール後、開発用PC からターミナルを使用して Raspberry Pi に SSH 接続し、VNCサーバーを起動します。

&#10;$ vncserver :1 -geometry 1024x600 -depth 16 -pixelformat rgb565&#10;

4_app3.png
図4-2 VNCサーバーの起動

Windows から VNCサーバーに接続する場合には、VNCクライアントソフト(RealVNC など)を使用します。

4_app4.png
図4-3 VNC 接続