こちらのブログでBNO055の問題点を知った。
yaw軸の問題については同様に体験していたので、クォータニオンについていろいろ調べてみたが、よく理解できなかったため、とりあえず先のブログのコードを参考にクォータニオンで値を取得し、オイラー角に変換してみた。改善したように思うが、それでもずれるときはずれるみたい。
旧版C-Style Ver.190706で動作確認してみた。 「C:\Daisen\C-Style for TJ3B V190706\Build\Build_V190617\D_I2C.c」の「UINT get_bno(BYTE dno)」を次のように書き換えると試せる。 (注意)以下のコードは無保証です。
UINT get_bno(BYTE dno) { BYTE adrs = BNO_ADRS; BYTE n; U_UINT d; float wf, xf, yf, zf, ysqr, t0, t1, t2, t3, t4; int xd, yd, zd; // DSR1603:9D-Compass(BNO055)の初期設定 if (gIsSetDSR1603 == false) set_bno(); /* * BNO055 datasheet * https://cdn-shop.adafruit.com/datasheets/BST_BNO055_DS000_12.pdf * 3.4 Axis remap * 3.6.5.5 Orientation (Quaternion) */ n = 0; gI2C_Buf[n++] = 0x20; // Register 0x20:AZIMUTH(LSB-MSB), 0x22:ROLL(LSB-MSB), 0x24:PITCH(LSB-MSB), 0x26:PITCH(LSB-MSB) if (i2c_send(adrs, n) == false) return(gDeg[dno]); if (i2c_recv(adrs, 8) == false) return(gDeg[dno]); // n = 0; d.L = gI2C_Buf[n++]; d.H = gI2C_Buf[n++]; wf = (int) d.W; d.L = gI2C_Buf[n++]; d.H = gI2C_Buf[n++]; xf = (int) d.W; d.L = gI2C_Buf[n++]; d.H = gI2C_Buf[n++]; yf = (int) d.W; d.L = gI2C_Buf[n++]; d.H = gI2C_Buf[n++]; zf = (int) d.W; wf /= 16384; // 2^14 xf /= 16384; yf /= 16384; zf /= 16384; /** * クォータニオン→オイラー角変換は以下を参考にした * http://l52secondary.blog.fc2.com/blog-entry-50.html * センサモニタ * 0(dir(yaw)), 1(pitch), 2(roll) * yaw :左向359←0→1右向 * pitch :前下がり90←180→前上げ270 * roll :右下がり0←90→右上がり180 */ ysqr = yf * yf; // X-axis rotation t0 = 2.0 * (wf * xf + yf * zf); t1 = 1.0 - 2.0 * (xf * xf + ysqr); xd = (int)(atan2(t0, t1) * 57.2957795131) + 180; // オリジナルとオフセットを揃える xd = (xd + 360) % 360; gDeg[1] = (UINT) xd; // pitch // Y-axis rotation t2 = 2.0 * (wf * yf - zf * xf); if (t2 > 1.0) { t2 = 1.0; } else if (t2 < -1.0) { t2 = -1.0; } yd = (int)(- asin(t2) * 57.2957795131) + 90; // オリジナルと向き・オフセットを揃える yd = (yd + 360) % 360; gDeg[2] = (UINT) yd; // roll // Z-axis rotation t3 = 2.0 * (wf * zf + xf * yf); t4 = 1.0 - 2.0 * (ysqr + zf * zf); zd = (int)(- atan2(t3, t4) * 57.2957795131); // オリジナルと向きを揃える zd = (zd + 360) % 360; gDeg[0] = (UINT) zd; // yaw return(gDeg[dno]); }