[Update 25 Dec 2020]: Fix HTML, update Japanese, add English descriptions.
[Update 12 Jan 2022]: Separate English article from this, update Japanese.

はじめに Summary

English article:

RoboCupJuniorサッカーリーグの公式球として使われている赤外線パルスボールのセンシング方法について紹介します。 2017年にルールがアップデートされ、オープンリーグではオレンジ色のパッシブボールが使われるようになり、ライトウェイトリーグだけがIRボールを使っています。 オープンリーグで使われているパッシブボールのセンサについては、別記事Self-made 360°Camera for RoboCupJunior 2017で紹介していますので、そちらを御覧ください。

RCJサッカー競技において、IRボールの検出は「パルス幅による距離検出」「センサの指向性による向き検出」を組み合わせて計算することで、平面方向のどの位置にあってもボールの位置が測定できるセンサを構成することができます。 ロボット側にボールの距離と方向を割り出すセンサを搭載して、その相対位置を取得し計算しながら試合をします。 本記事においては、このIRボールセンサを構成するための技術について解説します。 まずIRセンサ単体の原理について説明し、次にそれを組み合わせた全方位のIRボール位置検出をどう実現するかについて、具体的なハードウェア・ソフトウェアの実装例を元に解説します。

本記事において:
IRセンサ:赤外線パルスを検出するためのセンサ素子、モジュール単体のこと
ボールセンサ:ロボットに搭載される、IRボールの方向と距離を検出するためのセンサのこと
として書いていきます。

IRボールセンサの原理

IRボールのセンシングの基本的な原理は、TVのリモコンなどに使われるパルス変調された赤外線をIRボールが常に発しており、市販の赤外線センサによってそれを読み込むことで、ロボットから見たIRボールの位置が検出できるというものです。 ここでいう「パルス変調」というのは、決められた高い周波数で点滅し続けることで、例えば蛍光灯や太陽光に普通に含まれる赤外線とIRボールの赤外線が干渉しないようにする機能の事をいいます。 IRボールがどのような発光パターンをしているかは、ELEKIT 発光波形の詳細より確認できます。

RoboCupJunior soccerの初期は定常発光モードが用いられていた時期があったようですが、現在はMODE Aの発光パターンが公式に使われています。 この発光モードでは、赤外線の明るさを複数段階に分けて発光することで、近くにいると長い時間、遠くに離れていくと短い時間だけパルス信号が受信できるように工夫されています。 この原理を用いることで、センサからボールまでの距離を計測する事ができるようになっています。 また、センサには指向性(特定の方向しか光を検出しない特性)があり、複数のセンサを異なる方向に向けて検出させることでロボットから見たボールの向きを特定する事ができます。

実際に、複数のパルスセンサを全方位に環状に配置して、ボールの距離と方向(位置)を検出するセンサの例として、図1のRosso Version 6(M Robotsの赤い方)のIRボールセンサを実験に使います。 こちらは、Yunitシリーズのボールセンサと構成がほぼ一緒ですので、こちらを使用してソフトウェアの実験をします。 貸してくれたM RobotsのMさんありがとうございました。 以下は搭載されているマイコンとセンサの構成です。

  • 12x IR reciever Vishay TSSP58038
  • 1x Microcontroller Atmel ATmega328P-PU with Arduino bootloader
IMG_0108
Fig.1 Hardware for sensing test consisted of 12 TSSP58038 and atMega168P with Arduino bootloader.

IRセンサの選定

ボールセンサを設計するにあたり、まずはそれを構成するためのIRセンサ(素子)の選定を行います。 実際のところ、センサ素子からこだわって設計しているチームはそこまで多いとは思いませんが、以下で説明されている事を理解することは、ボールセンサのハードウェア・ソフトウェアをより良くしていく上では非常に重要な知識となります。

IRボールセンサのセンシングについては、オフィシャルな技術解説が存在します。 Soccer rules (2017) - RoboCupJunior の21ページ“APPENDIX I: Technical Specification for pulsed Soccer Ball”には「汎用的な赤外線信号受信モジュールを使ってON/OFFの時間から距離を割り出したりすることができる」みたいな説明があります。 その汎用的な赤外線信号受信モジュールとして、以下の3つのセンサが例として紹介されています。

  1. Vishay TSOP1140
  2. Vishay TSOP31140
  3. SHARP GP1UX511QS

これらのセンサはいずれも、テレビのリモコン等に用いられている赤外線通信用のセンサで、パルス変調された赤外線のON/OFFを検出するためのセンサです。 オフィシャルが解説しているように、これらのセンサによってIRボールの発光する赤外線を検出し、ボールの方向や距離を割り出すことができそうです。

しかし実際には、パルス幅を使った距離検出を行うためにあたってはいくつか注意すべき点があります。 ルールに書かれているIRセンサのうち、SHARPのGP1UX511QSについてはデータシートが少なくて分かりませんでしたので、今回はデータシートの情報が豊富なVishayのセンサを例に、次セクションでその詳細を見てみます。

センサアプリケーション

IRセンサの センサアプリケーションとは、いわゆる「センサの用途」のことです。 ユーザーはそれを見ることで、そのセンサがどんな目的で使われるかがわかります。 VishayのIRセンサ製品の主なアプリケーションのうち、RCJ IRボールのセンシングに使えそうなアプリケーションとして、今回は以下の2つに着目します。

  1. Remote control:遠隔操作(テレビやラジコン玩具などのリモコン受信)
  2. Presence/Proximity sensors:存在/接近検出(ラインセンサのような反射検出)
アプリケーション比較
Fig.2 Comparison of sensor application

2つのアプリケーションを比較してみると、左のRemote control application(遠隔操作アプリケーション)は (IR) transmitter(送信機:RCJでは赤外線ボールがこれに該当)とIR receiver(センサ)を用いて送受信が行われる事がわかります。 一方、Presence sensingの図はラインセンサと同じような構成をしており、変調された光を壁に照射して反射してきた光を検出するような動作をする事がわかります。 すなわち、どちらのセンサも変調された赤外線信号を受信するセンサである事に変わりはありませんが、検出の特性が異なるという事がわかります。

  1. 遠隔操作:出力されたパルス信号を、光の強弱に影響されずその形のまま受け取りたい
  2. 物体検出:出力されたパルス信号のうち、ある明るさ以上の光で受信した信号のみを受け取りたい

遠隔操作アプリケーションにおいては、センサ側は発行側で照射されたパルス信号の時間幅を、周辺の明るさや距離による光の減衰などに左右されずに、送信されたパルス波形のまま受信できる性能が求められます。 例えば家電のリモートコントロールをイメージすると分かるように、赤外線リモコンはいかなる距離であっても、同じ情報を伝達できる事が求めれます。 このために、遠隔操作アプリケーション用のIRセンサには、AGCと呼ばれる「どの距離であっても同じ明るさで見えるようにする」機能が搭載されています。 AGCについては、以降のセクションで改めて説明します。

さて、この「どの距離であっても同じ明るさで見えるようにする」特性は、ボールの明るさで距離検出を行おうとするRCJボール検出においては非常に嫌な特性になります。 理想的には、センサからボールが離れていくほどパルスの幅が小さくなるなど、光の強さに応じた特性が欲しいのですが、AGCがあるとこれが難しくなります。 ルールで紹介されているTSOP1140やSOP31140は、受信したパルス信号の強さを知りたい場合には、使えないことは無いが最適では無いという事になります。

一方で、物体検出アプリケーション用のIRセンサは、照射された光の絶対的な強度を測定することで、そこに物体があるかどうかを判別する目的で設計されています。 これはすなわち、発光側の強度が変化したり、あるいは距離により赤外線の強度が減衰した場合には、それも検出される事を意味します。 RCJボールの距離検出においては、この特性が非常に有利に働くため、AGCが搭載されていないセンサを選んで使うのが好ましいと考えます。

ブロックダイアグラムとAGC

より詳細にセンサの仕組みを理解するために、Block diagram(ブロックダイアグラム)という、センサICの内部設計を簡易的に示したものを見てみます。 だいたいのIC(集積回路)のデータシートにはこれが書かれていて、ユーザーはこの図を見る事で、細かい説明文を読まなくてもICの機能をざっくり把握することができます。

センサ比較
Fig.3 Block diagram of each Proximity and Remote IR sensor

先ほどの図と同じ構成で、今度はブロックダイアグラムを比較してみます。 細部が微妙に異なることがわかりますが、主に重要なのは“AGC:Automatic Gain Control”というシステムです。 上の図で比較した2つのセンサを見てみると、左のTSOPシリーズにはAGCが搭載されていますが、右のTSSPシリーズには搭載されていない事が分かります。

このAGCが何かを理解するために、Vishayの技術資料Choosing an Infrared Receiver Based on AGC Typeを見てみます。 ざっくり読むと、およそ以下のような事が書かれていると思います。 AGCが何のために付いていて、どんな働きをするかが解説されています。

赤外線レシーバーには、データ信号だけを受け取って、他のノイズは受け取らないような機能が必要です。 赤外線レシーバは、やろうと思えばかなりの距離を読めるし値段も抑えられるが、リモコン受信機を作りたいエンジニアにとってはそれは最適ではないでしょう。
ここで赤外線のノイズとは、白熱灯、ハロゲン、ネオン、蛍光灯、コンパクト蛍光灯の放射、さらには液晶ディスプレイ及びプラズマディスプレイ、日光が挙げられます。 これら外乱(ノイズ)の影響を受けると、信号が破壊されてエラーが発生し、それに伴って信号を繰り返す必要が出てくるので、設計者は苦労する事になります。
そこで、IR受信モジュールは受信信号を受け取る利得(感度みたいなもの)をコントロールするためのフィードバック回路が組まれています。 AGCは、ノイズが検出された時にセンサの感度を下げ、逆にデータが正常に受信されているときには利得を上げる動作をします。

このAGCが搭載されたセンサは、テレビのリモコンなどから発せられる、一瞬のシグナルを正確に検出できるように調整されています。 赤外線ボールから発せられる信号は、テレビのリモコンなどと比較するとはるかに強い・かつ連続したノイズのように見えます。 このため、信号用のAGCが搭載されたセンサで赤外線ボールを見ると、ほとんどの場合でゲインを下げる方向に制御が働きます。 AGCを搭載したIRセンサでボールを検出しようとすると、例えばボールをセンサの視界から隠してもう一度戻すと検出ができたりしますが、これはAGCの働きに由来するものです。

したがって、AGCが搭載されたセンサは受信する赤外線の強さによってゲインの強弱が変化してしまうので、ルールブックに書かれているような「ON/OFFの時間から距離を割り出す」という事が難しくなります。

センサの設計 Designing Ball Sensor

ここからは具体的に、市販のIRセンサ素子を組み合わせてどのようにボールの位置を検出するセンサとして構成するかの話をします。 センサ構成の基本は、図4のようにIRセンサを環状に配置して、それぞれのセンサの受信しているパルス幅を測定してボールの位置を割り出すというものです。

円形のIRボールセンサは、どの方向に対しても同じ計算が適用できるという特徴を持ちます。 以降で説明するベクトル計算や反応センサ数での距離割り出し手法は、この特性を利用したものになります。 私は、Gcraud Nanoの白いロボットで始めて円形のセンサを採用してから、以降はずっと円形センサの設計を使い回しています。

サッカーロボットではキッカーやドリブラー等の装置が搭載されるため、そのレイアウト上の都合から同一半径の円上にセンサを並べるのが難しい場合があります。 例えば円ではなくアルファベットのD文字状に並べたりといった例がありますが、そのようなレイアウトでもボールの向き検出自体は行えます。 しかし、位置によってセンサの指向性が変わるため、計算がやや面倒になる事が多いです。 これについては、Nitroのゆーきさんが詳細な記事を書かれていたと思います。

IRセンサ
Fig.4 Sensor screen (Yunit3 Hefei 2015 Model)

IRセンサの指向性と遮蔽

基本的にセンサの前方にある赤外線しか受信することができないIRセンサを使ってボールの方向を検出するためには、複数のセンサを異なる方向へ向けて、それぞれの値を比較・監視する必要があります。 この原理が実現されるために、センサはボールが正面にある時に最もよく反応し、逆に正面から外れた位置にある場合には反応が弱まる動きをしている必要があります。 このとき重要になるのが、センサの指向性(Directivity)です。

指向性比較
Fig.5 Comapasion of sensor directivity

IRセンサはメーカーやアプリケーションによって指向性が様々です。 特に気をつけるべきは、左側のTSSP58038のような指向性の低いIRセンサで、このような低指向性のセンサは側面や後ろ側の光も読む場合があり、IRボールの位置の計算を難しくします。

余談ですが、比較対象として図5に示したA2121は、ほぼセンサーカバーなしでもボールの方向検出が可能です。 しかし、AGC搭載センサであるため距離検出に不向きで、時間経過とともに出力するパルスが変化するため距離の把握が非常に難しかったのを記憶しています。

指向性が十分に鋭くないセンサの場合は、メカ的に一方方向しか見ないようなセンサカバーをメカ的に作ってやることで、指向性を挙げてやります。 この指向性をどれ位にすれば良いか、どんな形状のセンサカバーにすればいいのかを厳密に検討するのは難しいですが、私は「ボールの最大検出距離が下がらない範囲で一番絞る」方針で設計しました。 そう手間のかからない部分ですので、何種類か形状を作ってみてテストするのも楽かと思います。

読み込み回路

今回実験に使っているIRセンサ”TSSP58038”に限れば、マイコンのデジタルピンで読み込むだけの回路になるので、ここは端折ります。 冒頭でSTM32(3.3V駆動)でTSSP58038(5V信号)を読み込んでいると書きましたが、これはデジタルピンの5Vトレラント入力機能を使って実現しています。 センサの出力する信号電圧が、マイコンのデジタルピンの許容できる電圧を超えてしまうと、デジタル入力回路が壊れてしまうので、そちらだけ気をつけるべきでしょう。 あるいは、IRセンサによっては外部プルアップが必要だったりもすると思いますので、まずはデータシートを参照しましょう。

ソフトウェア

センシングにあたっては、これら複数のパルスセンサの出力を読み取り、それぞれのパルス幅からボールの位置を計算する事になります。 そこで、まずデジタルパルスの読み込み方法について紹介します。

IRセンサパルスの読み込みアルゴリズム

ボールセンサに搭載されるパルスセンサの数は、少ないもので数個、多いもので数十個に渡ります。 複数のデジタルピンのパルス幅(時間測定)をマイコンで実装する方法はいくつかあります。 例えばArduinoのpulseIn()関数を使って順番に読み込んでいく方法などはすぐに思いつきますが、読み込む対象が増えるとどんどん処理時間が増えていきます。 ここは読み込みの方法をすこし工夫することで、1ピンのパルス幅を読む時間だけで、数十ピンのパルス幅を同時に読み込めるので、その方法を紹介します。

またこれは必須ではありませんが、本記事でテストしたボールセンサの読み込みソフトウェアでは、ArduinoのPort Registersを使って読み込み速度を向上させています。 ArduinoのdigitalRead()関数は非常に便利な関数なのですが、少し処理が冗長な部分もあり、今回は処理速度優先で信号を読み込むために可読性を多少犠牲にしてこちらを使いました。 マイコンにもよりますが、だいたい10倍以上くらい読み込み処理が早くなるので、それだけパルス幅の測定解像度が上がります。

figure1
Fig.6 One-by-one Reading Method

パルス読み込みを1つのピンごとに個別に行う方法をOne-by-one Readingと呼ぶことにします。 Arduinoであれば、pulseIn()という関数を使ってパルス入力をし、それをセンサの数だけ繰り返すような実装がこれに当たります。 図6の例では、プログラムは1パルスの間に13回読み込みを行い、そのうち何回Hが入力されたかカウントしてパルス幅を計算します。 実際にはプログラムの周期はもっと早いので、およそ数百回から数千回くらい読み込みが行われます。 ここで、実際のパルスセンサとは論理が逆(実際のセンサは赤外線を受光すると出力がLOW)であることに注意して下さい。

この方法では、パルス幅の測定は細かいサンプリングで行えますが、(センサの数×パルス幅)の分だけ時間がかかります。 ロボットにおいては、センサの個数が増えるほどセンサのサンプリングレートが下がるため、レスポンスの低下が懸念されます。 pulseIn関数を使う場合、833[us]周期のパルスにトリガをかける(図で言うとSensor output signalが0→1になる瞬間を検出する)まで1周期の間待機する必要があるものとすると、この時点で、最小0〜最大833[us]の待機時間が発生します。

目安として、平均の待機時間を0.5[ms]とし、トリガがかかってからの読み取りには最大で833 - 346[us] ≒ 0.5[ms]とすると、 1つのセンサの読み込みにかかる時間は、平均の待機時間0.5[ms] + 読み取り時間0.5[ms] = 1[ms]となります。 12個のセンサで読み込むのにかかる時間は、1[ms/1センサ] × 12[センサ] = 12[ms]となります。

実際にArduinoで実験した読み込み速度を元に、読み込み以外の処理に5[ms]である事を考慮すると、1回の読み込みにかかる時間はおよそ(0.017[s])^-1 ≒ 59[Hz]となります。 この周期はそれなりに早い周期に見えますが、RoboCupJuniorのロボットにとっては、59Hzはロボットにとってはかなり遅いサンプリング周期です。 センサを増やすなどして、読み込み以外の処理が増えたりした場合には、結構目に見える形でレスポンスが落ちていくのが分かるでしょう。

figure2
Fig.7 Simultaneous Reading Method

もう一つの読み込み方法として、読み込みの速度を向上させるために、全てのセンサにサンプリングを振り分けて同時に読み込む方法があります。 この方法では、全てのセンサを833[us](およそ1000分の1秒)以内に読み込むことができます。 読み込み以外の処理を先ほどと同じ5msで計算すると、全体で約6ms、読み取り周期は約166[Hz]まで向上します。

一方で、センサの読み取りの解像度はセンサの数に反比例するため、センサ数が増えれば増えるほど距離の解像度がどんどん悪くなっていきます。 しかし実際のところ、赤外線ボールから発せられるパルスの強さが4段階しか無く、パルス幅の測定精度が問題になることはほぼありません。 読み取り周期を上げてレスポンスを向上させたほうが競技においては有利になると思いますので、個人的にはこちらを実装するのを推奨します。

パルス幅データからボールの位置を計算する

GitHubリポジトリ(y6tada/RCJr_IRball)にプログラムを公開しました。

ハードウェアに依存するパラメータを以下に示します。

Constant
  • #define IR_NUM 12
    Number of pulse sensors
Functions
  • bool getSensorPin(uint8_t pin)
    Return digital read result from index(0~11)
Variable
  • const uint8_t SensorPins[IR_NUM]
    正面を0として時計回り11までのセンサ番号
  • const float     unitVectorX[IR_NUM]
  • const float     unitVectorY[IR_NUM] 12個のセンサの向いている方向のcos, sinの単位ベクトルが格納された配列
  • const float     deltaPulseWidth パルス幅を加算していく際の1回読み込みあたりの加算量 必要に応じて変更

ここで公開しているプログラムはあくまで参考で、先程のパルス読み込みの処理フローと、ボールの方向を計算するソフトウェアをそれっぽく実装したものになります。 当然、実装やコーディングはより良くできると思うのですが、自分はソフトウェアのほうは専門ではないためどうか大目に見て頂けたらと思います。

距離角度計算手法の比較テスト


Movie.1 Ball Tracking Test with Each Reading Method

実験プログラムを動作させて、実際にボールの軌道をトラッキングしてみました。
ボールの追跡方法は、以下の3つの組み合わせとしました。

  1. 一番強い反応を示したセンサの方向をボールの方向とし、 そのセンサのパルス幅をボールとの距離とする
  2. 一番強い反応を示したセンサの方向をボールの方向とし、 円形に並べたセンサのうち反応した個数を距離とする
  3. ベクトル計算

結果は次のようになりました。

graph3 Fig.8 Result of ball position detection calculation with method 1

変数:maxSensorNumber は、最大のパルス幅を示したセンサの番号(12方位)で、これをボールの方向として計算しています。 つまり、ボールセンサの数が12個であるため、12段階でしか角度を検出できないことになります。 ただ、実際12段階あれば競技には十分だったりもします。

変数:maxPulseWidth は、最大のパルス幅がいくつであったかを示しています。 この方法では、最大のパルス幅が大きければボールが近いというような計算を行っています。
しかし、グラフと動画の実際のボールの動きを照らし合わせてみてみると、角度は正しいものの距離がほとんど判別できていないことがわかります。 パルス幅に含まれているノイズ成分が大きいため、このままでは実用には値しません。

この方法をうまく使う事は難しいでしょう。 これの代わりとして、円形センサの特性を利用した距離判別方法があります。

graph2
Fig.9 Result of ball position detection calculation with method 2

変数:activeSneosrs は、パルス幅が0以上を示すパルスセンサの数を示しています。 ボールが近づいていくに連れて数が増えていく原理がイメージできるかと思います。 ロボットのすぐ近くでは、センサカバーで遮蔽していても反射などで真後ろのセンサに光が入るため、12個全部のセンサが反応する事があります。

この方法は、私がHefei世界大会マシンまで実際に使っていた方法です。 円形センサの大きな特徴として、この「反応個数で距離が割り出せる」事が挙げられます。 先程のセンシング方法と比較すると、動画の挙動と同じような、遠くから近くへと回ってくる軌跡を、きちんと追跡できていることがわかります。 円形配置でかつ遮蔽がきちんとできているセンサであれば、この反応個数をカウントする方法で距離を割り出すことができます。

では最後に、より高度なセンシング方法としてベクトル計算を紹介します。 本当は数学的な解説もしたいのですが、余裕が無いのでごめんなさい。

graph1
Figure11 Result of ball position detection calculation with method 3

12個のセンサの反応をベクトル合成した軌跡を示したものです。 詳細はプログラムを参照して下さい。

方法1と2と比較すると、角度の検出精度が大幅に上がっていることがわかります。 距離についてはかなり誤差が大きくあまり当てにならない部分がありますが、角度に関しては今まで見えていなかった細かい挙動まで正確に追跡できています。 また距離についても、ベクトルの長さがボールとの距離に対応しているのが分かります。

ロボットを関数制御したいのであれば、この方法を用いて高解像度の角度情報を取得すると、うまくいくと思います。 また、オープンリーグはカメラを使う事でこれと似たような高い精度のボールの位置情報を得られるため、今後はボールの位置情報から回り込みを決定するまでの部分の技術が進歩していく可能性はありますね。

さいごに

質問や改善提案があればコメントまでお願いいたします。 また、サンプルコードに対する改善提案等が(ないと思いますが)あれば、GitHubの方でIssueかPull req投げていただけると対応できると思います。 よろしくおねがいします。