現象: Core2 において loadOffsetFromNVS() を実行すると、IMU の数値補正が
機能しません。
補正値は、M5Unifiedに含まれる imu.inoを実行して摘要しています。
// --- Check IMU ---
if (M5.Imu.isEnabled()) {
if (M5.Imu.loadOffsetFromNVS())
Serial.println("loadOffsetFromNVS() Ok");
else
Serial.println("loadOffsetFromNVS() Ng");
} else {
// stop
Serial.println("Fatal: This device does not have an IMU.");
while (true) { delay(100); }
}
証拠(ログ): 実際に M5_LOGD で出力された巨大な int32_t の数値。
[457][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ax:-3215561
[458][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ay:-1818034
[460][D][IMU_Class.cpp:362] loadOffsetFromNVS(): az:24262248
[466][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gx:2531496
[473][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gy:-2087627
[480][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gz:5125219
[486][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mx:0
[492][D][IMU_Class.cpp:362] loadOffsetFromNVS(): my:0
[498][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mz:0
[508][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ax:-3215561
[511][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ay:-1818034
[517][D][IMU_Class.cpp:362] loadOffsetFromNVS(): az:24262248
[524][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gx:2531496
[530][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gy:-2087627
[537][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gz:5125219
[543][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mx:0
[549][D][IMU_Class.cpp:362] loadOffsetFromNVS(): my:0
[555][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mz:0
loadOffsetFromNVS() Ok
指摘箇所:
IMU_Class::saveOffsetToNVS と loadOffsetFromNVS において、float 値が適切
な変換がなく、 nvs_set_i32 / nvs_get_i32 で扱われていないようです。
- ログから読み解ける異常事態
値のスケールがおかしい。
例えば az:24262248。
IMU の生データ(Raw)は通常 16bit (-32768 ~ 32767)です。
それに対して 2400 万 という補正値は明らかに桁が違います。
- 原因:
float のバイナリを int として解釈している NVS に保存されているのは、
float (浮動小数点数)のバイナリ と思われますが nvs_get_i32 (32bit
整数として取得)で読み出しているため、ビット列がそのまま整数として
解釈され、このような巨大な数値になっています。
例えば、float の $0.0$ 付近の微小な値は、整数として見ると非常に大き
な数字(IEEE 754 形式)になります。
これでは、M5.Imu.update() 内でこの数値をそのまま(あるいは整数とし
て)生データから引いたり足したりすると、計算結果が飽和(オーバーフ
ロー)するか、デタラメな値になります。
比較: 他の機種(Gray や StickC Plus2)では目立たないが、Core2 の座
標変換ロジックと組み合わさると致命的な誤差になる点。
(写真をご覧ください)
【追記】
上手く機能しているPlus2でのログです。違いはどこにあるのでしょうか。
[ 398][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ax:-645899
[ 399][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ay:-683474
[ 401][D][IMU_Class.cpp:362] loadOffsetFromNVS(): az:6447865
[ 408][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gx:-2441146
[ 414][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gy:249571
[ 421][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gz:511871
[ 427][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mx:0
[ 433][D][IMU_Class.cpp:362] loadOffsetFromNVS(): my:0
[ 439][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mz:0
[ 447][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ax:-645899
[ 451][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ay:-683474
[ 458][D][IMU_Class.cpp:362] loadOffsetFromNVS(): az:6447865
[ 464][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gx:-2441146
[ 471][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gy:249571
[ 478][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gz:511871
[ 484][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mx:0
[ 490][D][IMU_Class.cpp:362] loadOffsetFromNVS(): my:0
[ 496][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mz:0
現象: Core2 において loadOffsetFromNVS() を実行すると、IMU の数値補正が
機能しません。
補正値は、M5Unifiedに含まれる imu.inoを実行して摘要しています。
証拠(ログ): 実際に M5_LOGD で出力された巨大な int32_t の数値。
[457][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ax:-3215561
[458][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ay:-1818034
[460][D][IMU_Class.cpp:362] loadOffsetFromNVS(): az:24262248
[466][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gx:2531496
[473][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gy:-2087627
[480][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gz:5125219
[486][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mx:0
[492][D][IMU_Class.cpp:362] loadOffsetFromNVS(): my:0
[498][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mz:0
[508][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ax:-3215561
[511][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ay:-1818034
[517][D][IMU_Class.cpp:362] loadOffsetFromNVS(): az:24262248
[524][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gx:2531496
[530][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gy:-2087627
[537][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gz:5125219
[543][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mx:0
[549][D][IMU_Class.cpp:362] loadOffsetFromNVS(): my:0
[555][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mz:0
loadOffsetFromNVS() Ok
指摘箇所:
IMU_Class::saveOffsetToNVS と loadOffsetFromNVS において、float 値が適切
な変換がなく、 nvs_set_i32 / nvs_get_i32 で扱われていないようです。
値のスケールがおかしい。
例えば az:24262248。
IMU の生データ(Raw)は通常 16bit (-32768 ~ 32767)です。
それに対して 2400 万 という補正値は明らかに桁が違います。
float のバイナリを int として解釈している NVS に保存されているのは、
float (浮動小数点数)のバイナリ と思われますが nvs_get_i32 (32bit
整数として取得)で読み出しているため、ビット列がそのまま整数として
解釈され、このような巨大な数値になっています。
例えば、float の$0.0$ 付近の微小な値は、整数として見ると非常に大き
な数字(IEEE 754 形式)になります。
これでは、M5.Imu.update() 内でこの数値をそのまま(あるいは整数とし
て)生データから引いたり足したりすると、計算結果が飽和(オーバーフ
ロー)するか、デタラメな値になります。
比較: 他の機種(Gray や StickC Plus2)では目立たないが、Core2 の座
標変換ロジックと組み合わさると致命的な誤差になる点。
(写真をご覧ください)
【追記】
上手く機能しているPlus2でのログです。違いはどこにあるのでしょうか。
[ 398][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ax:-645899
[ 399][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ay:-683474
[ 401][D][IMU_Class.cpp:362] loadOffsetFromNVS(): az:6447865
[ 408][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gx:-2441146
[ 414][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gy:249571
[ 421][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gz:511871
[ 427][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mx:0
[ 433][D][IMU_Class.cpp:362] loadOffsetFromNVS(): my:0
[ 439][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mz:0
[ 447][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ax:-645899
[ 451][D][IMU_Class.cpp:362] loadOffsetFromNVS(): ay:-683474
[ 458][D][IMU_Class.cpp:362] loadOffsetFromNVS(): az:6447865
[ 464][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gx:-2441146
[ 471][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gy:249571
[ 478][D][IMU_Class.cpp:362] loadOffsetFromNVS(): gz:511871
[ 484][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mx:0
[ 490][D][IMU_Class.cpp:362] loadOffsetFromNVS(): my:0
[ 496][D][IMU_Class.cpp:362] loadOffsetFromNVS(): mz:0