北陽電機が発売している測域センサ(URG)をROSのurg_nodeを利用して使う方法について記述する. 動作環境はUbuntu 16.04 LTS.
各種解説
URG
北陽電機が発売している測域センサで無人搬送車(AGV)や安全柵無しの産業用ロボットなどによく使われている. NHK学生ロボコンやつくばチャレンジでもよく見かけるセンサ.
同一平面上の物体の距離を測定できる. Class1レーザを周囲に照射し, 自身に戻ってくるまでの時間(位相差)を測ることによって距離を計測する(TOFセンサ). 基本的には270度の範囲を1081点の点列で取得できる(機種による). 範囲は主に数10mで操作時間は数10ms. 最近平面だけでなく3Dで取得可能なタイプYVT-35LXも発売された. この辺りの話は北陽電機のサイトを見たほうが早いだろう.
似たようなセンサであるVelodyneのLiDARと比べると検出距離が短い(Velodyneは数100mまで検知可能1)一方で価格は数10万円と安い(Velodyneは数100万円)という違いがある.
LRFとも呼称される事もあるが, URGが商品ブランド名で, LRFは学術系で用いられる測域センサの名称, LiDARは産業界で用いられる測域センサの名称として使われているように感じる.
ROS
ROSはRobot Operating Systemの略で, オープンソース(BSDライセンス)で開発されているロボット用のプラットフォーム. マイコンではなくシングルボードコンピュータなどでの利用がメイン.
Operating Systemとは言っているものの, GNU/Linuxの代替になるものではなく既存のOS上に構築する. センサなどのハードウェアの抽象化が行え, 各種ビジュアライザやライブラリなどが豊富なため開発の効率化が図れる.
ROS日本語ページでは以下のように説明されている.
ROS (Robot Operating System)はソフトウェア開発者のロボット・アプリケーション作成を支援するライブラリとツールを提供しています. 具体的には, ハードウェア抽象化, デバイスドライバ,ライブラリ,視覚化ツール, メッセージ通信,パッケージ管理などが提供されています. ROSはオープンソースの一つ, BSDライセンスにより, ライセンス化されています.
URG Library
URG Libraryは北陽電機が公式で配布しているライブラリ. URGからの情報を取得しすることができる. 言語はC/C++でオープンソース(修正BSD/LGPL).
このライブラリはROSとは関係がない. ROSを利用せずに用いる場合はこのライブラリを使うことになるだろう.
urg_node
urg_nodeはURG Library用いた, ROS用のURGからデータを取得するパッケージ. 北陽電機もROSでURGを利用する際にはこのパッケージを推奨している.2
ROSの場合は基本的にurg_nodeで事足りる. 適切にパラメータを設定したり, roslaunchファイルを書いたりすれば良いだろう.
URGセットアップ
通信方式
URGの通信方式は2種類ある. Ethernetを利用するタイプとUSBを利用するタイプだ. TOP-URGや最も安いURG-04LX-UG-01はUSBタイプ. ただしUSBよりEthernetの方がノイズに強いため最近販売している機種は基本的にEthernetらしい.
USBタイプは簡単に利用できるが, Ethernetタイプは一回いじってから利用したほうが便利になる.
Ethernetタイプ
Ethernetタイプは初期状態では 192.168.0.10:100940
でデータを送信している. しかし, 192.168.x.x
はプライベートIPアドレスの中でもwifi接続時によく割り当てられるIPでもある. wifi接続している状態で, URGに 192.168.0.10
が割り当てられると, URGの接続先がルータでもない限りはIPが干渉して上手くネットに接続できなくなることがある. そのため, 他のプライベートIPである 172.16.x.x
をURGに割り当てることでネット接続を両立することができる.
URGのIP変更するためのソフトが北陽電機より配布されている. UTM-30LX-EWの各種ダウンロードからアクセスできる “UTM-30LX-EW IPチェンジャー” がそのソフト. UTM-30LX-EWでなくとも, UST-20LXでもキチンと動作した.
このソフトはWindowsで動かすものなので, 残念ながらWindowsを立ち上げないといけない. 立ち上げた後はEthernetケーブルを指し, ローカルエリア・ネットワークでEthernetポートに適切にIPを割り当ててやる. 3
あとはそのソフトを立ち上げれば設定できる. 今回はこのように設定した.
対象 | 変更後アドレス |
---|---|
IP address | 172.16.0.10 |
Subnet mask | 255.255.255.0 |
Gateway address | 172.16.0.1 |
ちなみに, EthernetタイプのURGを複数台同時運用する際にもこのように異なるIPを割り当てたほうが良い. 同じIPだとURG同士を簡単には区別することができない. そこで異なるIPを割り当て, スイッチングハブなどを介してコンピュータにつなげることで区別したまま同時運用ができるはずである.
動作確認
ひとまずきちんと動作しデータを取得できるか確認する.
ROSは導入してある前提として
sudo apt-get install ros-${ROS_DISTRO}-urg-node
を実行すれば必要なパッケージは揃う.
USBタイプ
まずURGのUSBケーブルをコンピュータにつなげる. すると /dev/ttyACM*
が現れる. *
は実際には数字なので, どの数字になっているかを調べる必要がある.
ls /dev | grep ttyACM*
を実行して表示されるものを順番に試していけば良い. 何も表示されなければ何かがおかしい. 挿しなおすといいだろう. ここでは /dev/ttyACM0
だとする.
次のコマンドを打てばデータを取得できるはずである.
sudo chmod a+rw /dev/ttyACM0
roscore
新しい端末で以下を実行.
rosrun urg_node urg_node _serial_port:="/dev/ttyACM0"
赤色の文字が出ていたら失敗, そうでなければ上手く行っている.
Ethernetタイプ
まずコンピュータのEthernetポートにIPを割り当てる. ifconfig
コマンドを実行すればEthernetポートに割り当てられている名前がわかる. 昔なら eth0
が, 最近なら enp0s25
が用いられる. ここでは enp0s25
という名前が割り当てられていたとする.
次のコマンドを打てばデータを取得できるはずである.
sudo ifconfig enp0s25 172.168.0.20
roscore
新しい端末で以下を実行.
rosrun urg_node urg_node _ip_address:="172.16.0.10"
赤色の文字が出ていたら失敗, そうでなければ上手く行っている.
データの表示
上手くurg_nodeが立ち上がったなら, rvizを用いてデータを可視化して表示することができる. 次のコマンドを打てばrvizが立ち上がる.
rviz
まずはFixed Frameを変更する. デフォルトのmapからlaserに変える.

そして左下のAddを押す.

By topicのタブを選択してLaserScanをダブルクリックする.

するとこんな感じでURGの距離情報が取得できる. 色の付いている各点が取得した位置情報で, 色が強度情報(紫が強く赤が弱い)を表している.

設定の永続化
今まで説明した方法は一時的なやり方. 毎回こんなコマンドを打つのはうざったいので自動で済ませるようにする.
USBタイプ
USBのデバイスファイル名は接続した順番で変わってしまう. それではあまりにも使いにくいのでデバイス名を固定する.
まずUSBタイプのURGを接続した状態で lsusb
コマンドを打つ. すると例えば次のような出力を得られる.
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 056e:00e6 Elecom Co., Ltd
Bus 001 Device 002: ID 1038:1607 SteelSeries ApS
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
SteelSeries ApSが目的のデバイスだとすると, そのデバイスのidVendorが1038でidProductが1607だとわかる. 実際にはなんの説明も書かれていないものがURGだったはずである.
あとは /etc/udev/rules.d/99-local.rules
を開いて
sudo emacs /etc/udev/rules.d/99-local.rules
以下を追記すれば良い.
# URG
KERNEL=="ttyACM*", ATTRS{idVendor}=="1038", ATTRS{idProduct}=="1607", SYMLINK+="ttyACM_URG"
これで ttyACM_URG
を接続先とすればいける.
ただし, このままだと権限がないため sudo
でプログラミングを起動しない限りPermission deniedになる. 毎回 chmod
で適切な権限を設定するのが面倒くさい場合は, ユーザーのアカウント情報を変更して素のままでもアクセスできるようにする.
以下のコマンドを打てば良い. ただし $USER
を各自のユーザーネームに書き換えること(カレントユーザーで設定するならそのままでもよいはず).
sudo usermod -a -G dialout $USER
複数のUSBタイプのURGがある場合の対象は面倒くさそう. たしかidProductは各々のURGに固有の値が割り当てられているのではなく0になっている気がしたので(要検証)4, urg_nodeのgetIDなどのライブラリ関数を用いて固有番号を取得するしかないと思われる.
Ethernetタイプ
Ethernetポートをインターネット接続にはほとんど使わず, インターネットはもっぱら無線lanを介して利用している場合の設定方法. EthernetポートをURGを利用するためだけに設定する.
まず自分のEthernetポートのインターフェイス名を確認する. ifconfig
コマンドを打ってeから始まるもの(昔なら eth*
今なら enp*s*
がほとんど)を見つける. ここでは enp0s25
だとする.
/etc/network/interface
を開き
sudo emacs /etc/network/interface
以下を追記する. ただし, enp0s25
関連の設定がある場合はそれを削除する.
auto enp0s25
iface enp0s25 inet static
address 172.16.0.20
netmask 255.255.255.0
このときgatewayは設定しない. そうすることでインターネットはNIC側で通信するので利用できる. 割り当てるアドレスは 172.16.0.20
でなくてもよい.
ネットワーク周りの知識は疎いので, これより望ましい設定方法があるかもしれない.
実際の利用にあたって
roslaunchを用いたurg_nodeの起動
urg_nodeにはいくつかのパラメータがあるが, これはコマンドライン引数を使わなくてもrosparamを用いて変更することができる. どんなパラメータが存在するのかは, 公式リポジトリのlaunchファイルを見るとわかる. 基本的には ip_address
か serial_port
を設定するだけで上手く行くだろう.
sensor_msgs/LaserScan
URGのデータはsensor_msgs/LaserScanというメッセージ型で送信される. C++では距離情報は std::vector<float>
型のrangesというメンバ変数に, 強度情報は同じく std::vector<float>
型のintensitiesというメンバ変数に格納されている.
vector型で格納されているので <algorithm>
や <numeric>
の関数を利用するとより効率的にコードをかけるだろう. algorithm - cpprefjp C++日本語リファレンスやnumeric - cpprefjp C++日本語リファレンスを参考にすると良い.
サンプルコード
需要があるかはわからないがサンプルコードを一応GitHubに公開した. roslaunchで立ち上げれば所定のURGからデータを取得して, その中央の点の距離情報と強度情報を出力する.
サンプルコード
Tips
三角関数テーブル
同じURGを使う限り各ステップの角度は固定である. 三角関数は比較的計算量がかかる処理なので, 毎回毎回計算せずにテーブル5として保有し適宜参照するほうが計算時間の短縮に繋がる.
論文
URGに関する日本語の論文も結構ある. LRFや測域センサで調べるとそれなりにヒットする. ロボット以外の分野でもそれなりに使われるんだなってことがわかる.
Raspberry Piで学ぶ ROSロボット入門
読んでないけどRaspberry Piで学ぶ ROSロボット入門という本に測域センサで地図を作成という章がある. 作者のブログを見るとURGでSLAMもしているようなので参考になるのかもしれない.
参考サイト
- 北陽電機株式会社
- Documentation - ROS Wiki
- URG Network / Wiki / top_jp
- udevでデバイス名を固定する - Qiita
- デバイス名を固定する - Qiita
- Read/Write to a Serial Port Without Root?
- cpprefjp - C++日本語リファレンス