29.自動追従距離測定器 (2021.6.15-2021.11.10)

人感センサーは赤外線で人等の接近を検知するものでしたが、今回は超音波を使ったセンサーの応用です。下の写真のような格好をしたもので、円柱状の目立つ部品が2つあります。超音波センサーユニットとして対を成すもので、一方から超音波を出して、もう一方で反射して帰ってきた音波を検出します。空気中では大体秒速340m程(気温15度の時)で音波は伝わりますから、超音波を発して戻って来るまでの時間を計測し、その1/2が検知物体に到達するまでの時間になります。これに音速をかければ距離が得られるわけです。空気中を伝わる音波は温度や気圧等の影響で変化するため、正確な値を得るためには補正する必要があります。実験ではとりあえず無視しますが、最終的には温度センサーによって温度を計測し、距離の値を補正したいと思います。

購入したセンサーはHC-SR04と言うモデルで、amazonで3個セット600円程でした。1個200円なら手軽に使えます。

超音波センサーは色々なものに応用できるので、その基本をマスターしておくことは後々大いに役に立つと思います。そこで、まずは簡単な超音波距離測定実験をします。センサーの動作ですが、基板のトリガーピンをHIGHにすると超音波パルスが送信され、物体に反射して戻ってきた信号を受信してエコーピンに出力します。RasPiのGPIOを使って、トリガー(出力)とエコー(入力)を割り当てることにします。

HC-SR04の主要なスペックは以下の通りです。
測定範囲 :2~400cm
電源電圧 :DC5.0V
動作電流 :15mA
動作周波数 :40kHz
トリガー信号 :10μs

センサーモジュールの電源電圧が5Vなので、直接RasPiのGPIOへの入力(エコー信号)は受けられません。そのため抵抗で分圧してレベルを下げます。1~4.7キロオーム程度の抵抗2本を直列にして接続部から信号を取り出せば、Hレベルで2.5VなのでGPIOの最大入力電圧3.3Vを下回り、しきい値も問題無いはずです。一方、RasPiからのトリガー出力はそのまま直結で駆動できます。GPIOのピンの割り当ては、
トリガー: GPIO23(16ピン)
エコー: GPIO24(18ピン)

としました。

まずはセンサーの前に障害物となるものをかざし、近付けたり遠ざけたりして測定距離の変化を確認します。距離によって値が随時変化するので、スペックの範囲内で測定に成功しているようです。指向性はあまり高く無さそうで、高精度に障害物をよけて動くような用途には向かないと思われます。例えるならぼんやりとうす目を開けながら、何かにぶつからないように進む雰囲気でしょうか。物体が接近してくるのを大まかに把握することは可能なので、その方向で応用を考えてみます。距離は比較的正確に測れるようなので、距離を測定する簡単なサンプルプログラムで実験してみました。(txt→pyは忘れずに)
距離測定プログラム

今回はこのセンサーとサーボモーターを組み合わせて、接近する物体の方向と距離を測定する装置を作ります。サーボモーターを使ってセンサーに一定角度内の首振りを行わせ、接近する物体を検知します。常に相手との距離の最小値とその時の角度を求めれば、物体の位置を捉え続けられるはずです。前述したように指向性はあまり高く無さそうなので、どれだけ正確に把握できるかわかりませんが、実験結果を検討して実用性を探りたいと思います。

距離測定センサーとサーボモーターの組み合わせは、将来的に防犯カメラで侵入者の位置を特定するのに使うのが目標です。相手の位置がつかめれば、より正確にカメラで動きを捉えることもでき、もしもズームまで可能になれば、正体をはっきり映像で確認することができるようになります。前述の実験で距離測定ができることがわかったことから、次はサーボモーターの制御について考えてみます。センサーの首振りに利用するだけなのでさほどトルクは必要無いことから、小型のSG90というモデルを使おうと思います。実はこのサーボモーターもOSOYOOの実験セットに含まれているもので、やはりメジャーに使われているもののようです。それにしても、この実験セットは実に役に立つパーツが色々収められていて、毎度のことながら感心するばかりです。

サーボモーターの結線は次の通りです。ケーブルの赤がVCC(+5V)、茶色がGND、オレンジ色が制御信号(GPIO18/コネクタの12ピン)です。GPIO18は特別な機能が割り当てられていて、ハードウェアPWMを使用することができます。そのためサーボモーターの制御には非常に都合が良いわけです。参考までに、GPIO19/コネクタの35ピンも同じ機能が使えます。ただし、これらはヘッドフォンの音声出力用途と兼用になっていて、アプリケーションで利用している場合はPWMとして使用できません。ハードウェアPWMはRPI.GPIOライブラリでは実現できないため、とりあえずはソフトウェアPWMを使い、サーボモーターを任意の角度(-90~+90度)に動かすサンプルを用意しました。スライダを動かせばサーボモーターも反応します。スライダについては「14.GUIプログラムの基礎」で取り上げたものを利用しました。
サーボサンプルプログラム

このSG90と言うモデルはベストセラー商品らしく、コピー品が大量に出回っているようです。本物はTower Proなるメーカーの商品で、実は手元の実験セットに入っているのはこのメーカーのものではありませんでした。メーカーでは見分け方も掲載していますが(本物はケース上面にTower Proの刻印、モーターギアが金属)、コピーと言ってもそれなりに良くできているようで、実質的には支障は無さそうです。トルクが低いとかギアが壊れやすい等の情報はあるものの、欠陥と呼べるような問題は報告されていない感じです。amazonで売られているものの大半はコピー商品で、堂々と売っているのは少々問題です。著作権侵害になるので、せめて互換品くらいの表記があって然るべきなのでしょう。

SG90のようなアナログサーボの特長として、静止時が一番不安定になりやすいようで、ソフトウェアPWMでは微妙にガタガタと振動したり異音を発します。制御パルスのdutyとポテンショメーターの値で拮抗を保っているため、ほんのわずかな変動によってブレが出るのです。ソフトウェア制御だとこの変動を十分抑えられないので、酷い時にはサーボが外れて思わぬ動きをする場合があります。ハードウェア制御では変動幅は遥かに小さく、ソフトウェア制御よりも安定が期待できます。どれくらいの違いが出るのか確認するために、両方でプログラムを組んで比較してみたいと思います。

さて、本来の目的である距離測定に戻ります。前方の物体までの距離と角度を得るため、常にセンサーは首振り動作をします。センサーを細長く切った基板にスズメッキ線で固定し、その基板をビスでサーボホーンに取り付けました。サーボはプラ容器のフタに両面テープで固定してあるだけです。エコー出力を抵抗分圧するために、途中に中継基板を入れました。実験が目的なので、あくまでも簡易的な装置です。

サーボの安定化を図るため独立した電源も用意しました。手元に9VのACアダプタがあったので、三端子レギュレーター7805で5Vの電圧を生成しています。一般的な用途なら下図の回路で大丈夫でしょう。入力電圧は出力5Vに対して3V以上は必要です。実験では9VのACアダプタを使用しました。電流を多く取るなら7805に放熱器が必要です。

測定の前提として周囲には何も無い状態にしなければならないので、あらかじめ距離センサーでの検出範囲を決定しておきます。実験では1~2m以内を対象としました。室内ではあまり検知角を広く取る必要は無いと考え、今回は前方120度(最終的には180度)の間を範囲とします。また、サーボの回転角をあまり細かく設定しても追従が困難なので、角度は10度ずつ変更します。パルスのDutyを変化させることで、角度を-60~+60度まで順次変化させます。60度になったら直ちに-60度に戻し、再び同じ動作を繰り返します。この1往復が1スキャンとなるわけです。戻す際に1スキャンの距離測定で得た値の最も小さい値と、その時の角度を表示するのが次のプログラムです。どのようなデータが得られるか実験してみましょう。
移動体検知プログラム

実行すると1スキャンに2秒程時間がかかるため、速い速度で横切ったりすると捕捉できないケースが出てきそうです。実用的には0.5秒程度に抑えたいところですが、このサーボの性能では無理だと思います。ソフトウェアPWMでは時々不安定な動作をしたり、微妙にガタついたりしてどうしても限界があることから、次はハードウェアPWMを試してみることにしました。ハードウェアPWMを使うにはRPI.GPIOライブラリではだめでpigpioライブラリが必要です。導入するには次のようにします。私の場合は最新状態だったため、新たに導入する必要はありませんでした。
sudo apt-get install pigpio python-pigpio python3-pigpio
pigpioは実行する前にdaemonを起動しておく必要があるとのこと(必須!)で、ターミナルから
sudo pigpiod
を実行しておきます。

ハードウェアPWMで動作するように、上記の移動体検知プログラムを修正します。
ハードウェアPWM-移動体検知プログラム

このプログラムを走らせて驚きました。あれだけ不安定だったガタ付き等が収まり、かなり安定した動作をします。主観ながら、カタカタと一息つきながら回転してまた戻る姿は、ずっと見ていても飽きません。動作が安定したところで物体検知実験をしたところ、角度と距離は物体の移動と概ね相関があることが確認できました。角度変更して超音波を発するまでのWAITはある程度必要(時間が短いと目標角度に達する前に検出動作をしてしまう)なので、この辺りが限界では無いかと思います。

しかし、課題も浮かび上がります。当然と言えば当然ですが、超音波が物体に当たって反射しても、受信器の方に戻ってこなければ検出はできません。例えば平面状の物体で受けて、それが常にセンサーに対して垂直面を見せていれば良いのですが、斜めになると超音波が関係無い方向へ反射してしまいます。物体の表面で乱反射したり吸収されても、同様に正しく検知できないでしょう。そもそも実験に使用しているセンサー自体、さほど指向性が高いとも言えず、検出の精度を上げるにはアルゴリズムを含めて、色々と対策が必要と思われます。

数値だけを見ていても今ひとつ感覚がつかめないので、第二段階として検出した値を使い、カメラマウンタにセットした別のサーボモーター(パン/水平方向回転用)を動かしてみます。このサーボモーターの制御信号には、同じハードウェアPWMを使えるGPIO19/コネクタの35ピンを使います。

カメラマウンタを連動させる方法ですが、先の実験によって検知した物体の方向が分かるので、その角度にカメラマウンタを回転させれば良いわけです。うまくすれば物体の移動に合わせて向きを追従させることができるはずです。その機能を追加したのが次のサンプルです。
カメラマウンタ自動追従プログラム

カメラマウンタにセットしてあったサーボモーターは、ソフトウェアPWMではかなり動作が怪しいものでしたが、ハードウェアPWMによって安定して動くようになりました。なるべくセンサーが正しく反応するように注意して、センサーの前で物体を移動させると、その方向に追従することが確認できました。基本的な考え方は正しいことが実証できたので、実験は成功と見て良さそうです。ただし、サーボモーターは作動音が大きいため、監視カメラのような用途で使うには隠密性に課題もあります。極力静かなサーボを使うか別の方法で回転をさせるのか、実用化に向けては今一度検討する必要があるでしょう。

<追記(2021.11.10)
距離センサーのスキャン時間短縮方法として、新たに2個のセンサーを使ったツインソナー化を検討してみました。回転角度も処理時間等を考慮して-60~+60度としていたものを、最初に想定した-90~+90度にします。ハードウェアPWMは上記カメラマウンタのサーボモーターの代わりに、第二センサーの回転用サーボモーターに割り当てます。それぞれにマイナス側、プラス側の角度スキャンを担当させることで、1スキャンを1/2の時間に短縮する計画です。他にも色々と実験したい課題があるため、新たに「39.自動追従測定器-2 ツインソナー」で話を進めます。