DRV2605でLRAを動かす

触感フィードバックをしようとして詰まったけど何故か突然上手く行った話。
紆余曲折しているので、結論読んでから実践しましょう。

タイトルの呪文を解説しながら、実験環境を説明します。

DRV2605

www.tij.co.jp
I2Cで叩くと良い塩梅で振動モーターを駆動してくれる便利なIC(超意訳)
ブレークアウト基板はAdafruitやSparkfunから出てます。

Overview | Adafruit DRV2605 Haptic Controller Breakout | Adafruit Learning System

Haptic Motor Driver Hook Up Guide - learn.sparkfun.com

AdafruitはENピンはHIGH固定ですが、SparkfunはENピンが出ているので実デバイスに乗っけるならこちらを選んだほうが良さそう。
しかし私はSparkfunから出ていたのを知らずにAdafruitの方を買ったので、この記事ではAdafruitを使います。マルツで買いました。
触感フィードバックモジュール 2305の通販ならマルツオンライン

Sparkfunのほうはスイッチサイエンスで売っています。
DRV2605L搭載 触覚フィードバックモータードライバ - スイッチサイエンス

LRA

リニア・バイブレータ(LRA:Linear Resonant Actuator)。コイルに電流を流すことで電磁力を発生させ、これと磁石との反発力を使ってコイル自体を上下に振動させるものだ。
最新アナログ基礎用語集 - ハプティクス(触感フィードバック) - TI

いわゆるガラケーに入ってたのは偏心モーター(ERM)で、ブルンブルンって感じの振動でしたよね。最近はカチっというクリック感が出せるLRAが主流だと思います。
LRAにはリンク先の絵にあるコイン状のものと、iPhoneでTaptic Engineと呼ばれているような四角いものがあります。*1

LRAは秋月で調達。ちょっとデカイですが、Taptic Engineと同じで横方向に動くタイプです。
リニア振動アクチュエータ LD14−002: パーツ一般 秋月電子通商 電子部品 ネット通販

動かしてみよう

結線は超簡単。ArduinoのI2C用のピンをつなぐだけ。
Wiring & Test | Adafruit DRV2605 Haptic Controller Breakout | Adafruit Learning System

AdafruitからArduino用ライブラリが配布されてるのでこれを使います。
GitHub - adafruit/Adafruit_DRV2605_Library: Arduino library for Adafruit DRV2605L Haptic Controller Breakout

サンプルコードからbasicを書き込み、いざ…

しーん

なんでやねん。Adafruit_DRV2605::begin()を見に行くと

Adafruit_DRV2605.cpp

  // ERM open loop
  
  // turn off N_ERM_LRA
  writeRegister8(DRV2605_REG_FEEDBACK, readRegister8(DRV2605_REG_FEEDBACK) & 0x7F);
  // turn on ERM_OPEN_LOOP
  writeRegister8(DRV2605_REG_CONTROL3, readRegister8(DRV2605_REG_CONTROL3) | 0x20);

デフォルトはERMのオープンループ設定らしい。
useLRAという関数が用意されているので、これを使う。ついでにLibraryもLRA用の6を選択する。

basic.ino

void setup() {
  Serial.begin(9600);
  Serial.println("DRV test");
  drv.begin();
  
  drv.useLRA();
  drv.selectLibrary(6);
  
  // I2C trigger by sending 'go' command 
  // default, internal trigger when sending GO command
  drv.setMode(DRV2605_MODE_INTTRIG); 
}

これでも動かなかった。なんでー?
電流が足らないのかなーと思い、安定化電源つないだりオシロ覗いたりしたけど原因が分からず。
GitHubで他のライブラリを探してみる。AdafruitとSparkfun以外で2つ見つかる。

FlexModule/haptic/LRA/DRV2605L/software/arduino/DRV2605 at master · FyberLabs/FlexModule · GitHub

GitHub - Seeed-Studio/Grove_Haptic_Motor

このうち、後者で動いた。Auto calibrationも機能している模様。*2
f:id:ndanah:20170814111847p:plain

やはりAuto Calibrationが要るのか?と思い、もう一度Adafruitのプログラムを書いてみる。

Buzzzz

動いた(白目)
結局、同じ現象を再現できず。どうもRATED_VOLTAGE(0x16)とOD_CLAMP(0x17)が小さいと鳴らないので、このせいだったのかもしれないが、電源を入れ直すとデフォルト値に戻るので理屈が合わない。
なお、データシートには明示されていないが*3、上記2つのパラメータはどうも絶対値(つまり定格3Vなら0x03)ではなく、入力電圧に対する比率(0xFF=100%)のような気がする。
振動モーターの仕様をみると

・駆動電圧:2V~6V
・駆動電流:120mA(@3V、バイポーラ駆動、150Hz、デューティー比50%)
・コイル構成:1相(バイポーラまたはユニポーラ駆動)
・コイル仕様:直流抵抗25Ω、インダクタンス210μH(@120Hz)
・本体共振周波数(fo):約150Hz(配線材、固定方法等によって変動します)
リニア振動アクチュエータ LD14−002: パーツ一般 秋月電子通商 電子部品 ネット通販

この場合、5Vを与えていて3V定格で動かすならRATED_VOLTAGE=0x99、OD_CLAMP=0xFFでいいのかな?自信ないですが、ひとまず焼けはしなかったです。

結論

よくわかんないけど動いた。

AdafruitのライブラリにAuto calibrationを追加したので、ひっそり公開しておきます。
GitHub - acho702i/Adafruit_DRV2605_Library at AutoCalibration

bool Adafruit_DRV2605::autoCal(uint8_t ratedVoltage, uint8_t overdriveClamp, uint8_t driveTime)

git上のスケッチではデフォルト値を入れてあります。
DRIVE_TIME(0x1B)はデータシートによると周期の半分を入れれば良いらしい。
Optimum drive time (ms) ≈ 0.5 × LRA Period
というわけで、今回の振動モーターでは5Vを繋いだ前提で

autoCal(0x99,0xFF,0x03)

として、モーターを固定してから実行すればOK。

*1:Androidは大概コイン状のものが載っていますが、Taptic Engineと比べると触感のシャープさに欠けますね。チューニング次第かもしれませんが。

*2:initがfailしていますが、これはinitに正常終了を表す0を返すためのリターンパスが書かれていないためのようです。

*3:英語力と読解力が貧弱なだけかもしれない