加速度センサや角速度センサで動きを検出する場合、通常センサ出力をACカップリングして使います。つまり、DC(直流)成分をカットします。これは、センサの0点オフセット問題を回避するためです。
例えば、ANALOG DEVICES社の加速度センサADXL203の場合、0点オフセット値(加速度センサを水平に置いた場合に示す値)は2.4V~2.6Vです。感度が1V/gですから、±0.1g相当です。そのまま使うには0点(水平)の電圧を予め計測しておくことが必要です。
動きだけを使うのであれば、ACカップリングで使えばこと足ります。ACカップリングにすれば、動いていない(動いていないとしたい動きの)時の値を、任意に設定(ACカップリング後の印加電圧)できますから、0点オフセット問題を回避できます。もちろんACカップリングの時定数を使いたい範囲に設定する必要があります。
それでは、予め0点(水平)電圧を計測しなければ、DCでは使えないのでしょうか?
ここでは、自動オフセット調整を考えてみましょう。
さて、ではどうやってオフセットを設定するかですが、動き(センサの値)がある一定範囲であれば、
そのときの平均値をオフセットに設定する方法を考えます。
Cのソースをリスト1に示します。
まず、センサの値を複数個(例えば32個)格納するメモリを用意します。このメモリには、常に最新のセンサの値を格納します。つまり、新しいデータが入ってきたら、一番古いデータを捨てます。リスト1では、循環メモリのような使い方をしています。
(構造体cyclic_array、関数ca_input参照。C++ならこんな手間はいらないのですが)
次に動きを判定する閾値(threshold)を決めます。
動きの判定は、1個1個の値を閾値で判定するのも手ですがノイズに惑わされる可能性が高いので、平均値を使います。(関数auto_offset2参照)
平均値を算出するのに使う個数(max_count)を2つに分け、前半の平均値と後半の平均値の差の絶対値が閾値より小さいなら後半の平均値をオフセット値にします。閾値以上なら、今までのオフセット値(old_ave)を使います。
ここでは、前半と後半の二つに分けましたが、3つや4つに分けるのも手です。3つに分けた例が関数auto_offset3です。
如何でしょうか?コメントは付けておりませんが、短いプログラムですので比較的簡単に読めると思います。また、分割をいくつにするかとか、平均値を取る個数をいくつにするかとか、等々は、使用環境により変わりますので、色々とお試し下さい。
リスト1はCで書いていますが、お気付きのようにC++で書いたほうがスマートにかけます。
C++を使われている方は、簡単に書きなおせると思いますし、C++初心者の方には、クラス定義の良い練習になると思いますので、C++の例は掲載しません。
私の場合、マイコンに組み込むことが多いのでCでアルゴリズムを書いています。実際に実装する際は、あちこち省いてアセンブラで書くほうが多いです。(例えばcyclic_arrayのindexやdata_countを、共通にするとか)
掲載したCソースは、ご自由にお使い下さい。ただし、ご使用により、いかなる弊害や不具合が生じたとしても当方ではいかなる責任も持ちません。予め、ご了承下さい。