ジャイロセンサ「ICM20948」で苦しんだ話
初めましての方は初めまして、
そうでない方はお疲れ様です。
この記事は
Micro Mouse Advent Calendar 2020 - Adventar
の13日目の記事です。
昨日はそらさんによる
Raspberry Pi4 SPIでセンサ(L3GD20)から取得した値をROSでPublishする | Sora's Activity Record
でした。
綺麗なコードは正確にやっていることを物語ってくれるので 幸せになりますね...
いつかボクもOS付きのプログラミングに行きたいです(いつになることやら…)
はてさて、今回は今年新しく触っていたジャイロICM-20948君により苦しめられた話です。廃盤となったMPU-9250の代替として売り出されているので触ってみましたが、完全互換とはいかず、苦しみました。とりあえず色々とやって角速度、加速度までは取得できたので報告も兼ねて記事にします。
(データシートやリファレンスをちゃんと読めってのはその通りです…)
これは偶然ですが、先日のブログ記事で「MPU9250で値取得」をしていたのでそちらに書いてあることは省きます。
Advent calendar revenge match in2020 (HAL+MPU9250) - judgeのブログ
ボクは先達の道から学ぶタイプなので縛りプレイで勉強する人には頭が下がります。
本日の目次はこちら
ICM-20948とは
ジャイロセンサといえば多くの人がお世話になったことがあるのはMPU6500やMPU9250に代表されるMPUシリーズではないでしょうか?
これらはInvensane社が製作していましたが、近年、全てのMPUシリーズが新規設計非推奨になってしまいました。
そこで代替となる新シリーズがICMシリーズというわけです。その中でも、9軸IMUであるMPU9250の代替として公式が指名しているのがICM20948なわけです。
ご丁寧に移植の注意点まで出してくれるのだけど、わざわざ注意点だしてくるのに理由があるのでした…。
ジャイロセンサは正式には慣性計測ユニット(IMU)と呼ばれるもので、慣性力から加速度を、コリオリ力から角速度を、地磁気センサで磁気を計測しています。それぞれで3軸取るので9軸になるわけです。
代替品だから殆どそのまま性能だけ上がったんだろうと思っていましたがそんな訳もなく、色々な変更が施されていました。
公式の移植注意に書いてある事、データシートの隅にちょっと書いてある事など
「全部読めば」できるはずですがそんなに真面目でもないので悉く罠にかかりまくりました。
その罠の紹介です。
教訓1. レベル変換回路をつけろ
公式の移植注意にも書いてあるのですが気付きにくい点かと思います。
動作電圧範囲はよく確認するのですが、IO信号の電圧範囲が変更されています。
試しに3V3をぶち込んだらお話することすら叶いませんでした…
互換品えぇ…
対策としてはマイコンの信号とICM20948の信号をレベルシフタで挟んで、電圧レベルを1V8に落としてあげればOKです。
レベルシフタの回路をできるだけ小さくしたいと思ったそこのあなた。
このモジュールを参考にしてFETでレベルシフタを実装すると上手くいきました。小さくできるので嬉しいです。
(そもそも違うIMU使えというのはそれはそう)
教訓2. レジスタマップが完全に別物
これは想定内かもしれませんがレジスタマップは別物扱いでした。WHO_AM_IのアドレスもDefaultの値も違うので注意です。
結局の所、レジスタに関してはほぼ新規になったと考えて睨めっこした方が早そうです。
ただ、後述のUser BankによってWHO_AM_Iは通っているのに設定が適用されない、値が取り出せないなどの問題が発生していました。
教訓3. SPIの最大速度が違う
さていよいよ通信できるぞーと思っているとそういうわけにもいかず、まだできない…。
これはボクの前のプログラムの仕様で、書き込み時には1MBps, 読み込み時には20MBpsぐらいになるようにしていたのが原因でした。MPU9250ではそんな仕様でした。
いや、そんな風に書いた意図は知らないけどそう書いてあったんです…
しかしここで悲報。
データシートをよく見てみるとICM20948は書込みも読み込みも7MBpsが最大らしいのです…。
マジですかい…。最大が大きくなってるわけじゃないのかいな…。
そんか面倒なプログラムでなければ問題無いと思いますがお気を付けを。
教訓4. 「USER BANK」に注意
ここまでやって、ようやく読み込みができると思ったら変な値ばかり返ってくる…。
スケールが合っていない気がする…って類ならコイツの可能性が高いです。
ICM20948はレジスタマップをブロックごとに分割して各ブロックを「USER BANK」と呼称してそれぞれに番号を割り振っています。そして、USER BANK 0に所属するレジスタにアクセスするには
予め、「USER BANK 0を選択する」と書き込む必要がある
ようです。
ちなみにこれに関する1次ソースを自分は見つけていないのでどなたか心当たりがあればご教授いただければと思います。
各ブロックに上のレジスタが共通していることと、データシートの書き方から推測して書いてみたら実際にそうだっただけなので、本当にソースが欲しい…。
デフォルトではUSER BANK 0になっているため、WHO_AM_Iを読み込むには問題無いのですが、角速度のスケール設定レジスタはUSER BANK 1に分類されているため書き込みがうまくいってませんでした。
また、角速度出力や加速度出力はUSER BANK0に分類されているため設定後はそちらに戻す必要があります。
通りでレジスタマップ上で同じアドレスのものが複数あるわけだ…。
(そこで気がつけやってのはそれはそう)
そんなわけで、何とか上手く行きました。
これさえ分かっていればローパスフィルタや移動平均フィルタもこれまで通り引き出せました。
新しい素子を使うのはいつも大変ですね…。
以上、お付きあいありがとうございました。
明日はコヒロさんによる記事です。
皆様、お楽しみに!!!