Javascript - 将设备加速度转换为地球坐标
Javascript - transforming device acceleration to earth coordinates
我在使用纯 javascript 的 Web 应用程序中将设备加速度值转换为地球坐标系时遇到问题(大多数问题的解决方案都是 Android 或 iOS 特定的)。
我正在使用 gl-matrix 库执行计算,到目前为止,我的解决方案主要基于我为 Android 本机应用程序找到的答案。到目前为止,我对方向和运动的事件处理程序有什么:
readonly deg2rad = Math.PI / 180; // Degree-to-Radian conversion
rotMatrix: mat3;
relRotMatrix: mat3;
earthAcc: mat3;
resetOrientationPending: boolean = false;
handleOrientation(event) {
var absolute = event.absolute;
var alpha = event.alpha;
var beta = event.beta;
var gamma = event.gamma;
if (this.rotMatrix) {
let curRotMat = this.getRotationMatrix(alpha * this.deg2rad, beta * this.deg2rad, gamma * this.deg2rad);
this.relRotMatrix = mat3.multiply(mat3.create(), this.rotMatrix, curRotMat);
}
else if (this.resetOrientationPending) {
this.resetOrientationPending = false;
this.rotMatrix = mat3.transpose(mat3.create(), this.getRotationMatrix(alpha * this.deg2rad, beta * this.deg2rad, gamma * this.deg2rad));
}
}
handleMotion(event) {
let x = event.acceleration.x;
let y = event.acceleration.y;
let z = event.acceleration.z;
let accMatrix = mat3.fromTranslation(mat3.create(), [x, y, z]);
this.earthAcc = mat3.multiply(mat3.create(), this.relRotMatrix, accMatrix);
let ex = this.earthAcc[6];
let ey = this.earthAcc[7];
let ez = this.earthAcc[8];
}
getRotationMatrix(alpha: number, beta: number, gamma: number): mat3 {
let _x, _y, _z;
let cX, cY, cZ, sX, sY, sZ;
_z = alpha;
_x = beta;
_y = gamma;
cX = Math.cos(_x);
cY = Math.cos(_y);
cZ = Math.cos(_z);
sX = Math.sin(_x);
sY = Math.sin(_y);
sZ = Math.sin(_z);
let res = mat3.create();
res[0] = cZ * cY + sZ * sX * sY; // row 1, col 1
res[1] = cX * sZ; // row 2, col 1
res[2] = -cZ * sY + sZ * sX * cY; // row 3, col 1
res[3] = -cY * sZ + cZ * sX * sY; // row 1, col 2
res[4] = cZ * cX; // row 2, col 2
res[5] = sZ * sY + cZ * cY * sX; // row 3, col 2
res[6] = cX * sY; // row 1, col 3
res[7] = -sX; // row 2, col 3
res[8] = cX * cY; // row 3, col 3
return res;
}
如果我的 phone 平躺在 table 上(纵向模式),顶部指向远离我的方向,然后执行 "resetOrientation",这适用于 left/right 和 forward/backward 运动。也就是说,如果我将 phone 围绕 z 轴旋转 180 度(意味着仍然平放在 table 上),那么我的顶部指向我,加速度(代码中的 earthAcc 矩阵)为 L/R 和 F/B 移动仍然正确。但是 up/down 不正确,一旦我开始围绕其他轴旋转 phone,我就会得到不一致的结果。
可能只漏了一行或类似的东西,希望矩阵代数大师能发现问题:)
更新:通过将我在 handleMotion 中创建 accMatrix 的方式更改为:
let accMatrix = mat3.create();
accMatrix.set([0, 0, 0, 0, 0, 0, x, y, z]);
...我也有 UP/DOWN 工作,但如果我在 Z 以外的任何其他轴上旋转 phone,它不再给出正确的值。
更新 2:我正在 iOS Safari (Iphone) 上测试这个,所以我不知道这是否是设备类型特定的问题,但我使用的是 Gyronorm 库应该 return 标准化值。
我已经能够解决我的错误。加速度乘法矩阵应如下所示:
accMatrix.set([1, 0, 0, 0, 1, 0, x, y, z]);
也就是说,基数应该是一个单位矩阵,而不仅仅是零。
我在使用纯 javascript 的 Web 应用程序中将设备加速度值转换为地球坐标系时遇到问题(大多数问题的解决方案都是 Android 或 iOS 特定的)。
我正在使用 gl-matrix 库执行计算,到目前为止,我的解决方案主要基于我为 Android 本机应用程序找到的答案。到目前为止,我对方向和运动的事件处理程序有什么:
readonly deg2rad = Math.PI / 180; // Degree-to-Radian conversion
rotMatrix: mat3;
relRotMatrix: mat3;
earthAcc: mat3;
resetOrientationPending: boolean = false;
handleOrientation(event) {
var absolute = event.absolute;
var alpha = event.alpha;
var beta = event.beta;
var gamma = event.gamma;
if (this.rotMatrix) {
let curRotMat = this.getRotationMatrix(alpha * this.deg2rad, beta * this.deg2rad, gamma * this.deg2rad);
this.relRotMatrix = mat3.multiply(mat3.create(), this.rotMatrix, curRotMat);
}
else if (this.resetOrientationPending) {
this.resetOrientationPending = false;
this.rotMatrix = mat3.transpose(mat3.create(), this.getRotationMatrix(alpha * this.deg2rad, beta * this.deg2rad, gamma * this.deg2rad));
}
}
handleMotion(event) {
let x = event.acceleration.x;
let y = event.acceleration.y;
let z = event.acceleration.z;
let accMatrix = mat3.fromTranslation(mat3.create(), [x, y, z]);
this.earthAcc = mat3.multiply(mat3.create(), this.relRotMatrix, accMatrix);
let ex = this.earthAcc[6];
let ey = this.earthAcc[7];
let ez = this.earthAcc[8];
}
getRotationMatrix(alpha: number, beta: number, gamma: number): mat3 {
let _x, _y, _z;
let cX, cY, cZ, sX, sY, sZ;
_z = alpha;
_x = beta;
_y = gamma;
cX = Math.cos(_x);
cY = Math.cos(_y);
cZ = Math.cos(_z);
sX = Math.sin(_x);
sY = Math.sin(_y);
sZ = Math.sin(_z);
let res = mat3.create();
res[0] = cZ * cY + sZ * sX * sY; // row 1, col 1
res[1] = cX * sZ; // row 2, col 1
res[2] = -cZ * sY + sZ * sX * cY; // row 3, col 1
res[3] = -cY * sZ + cZ * sX * sY; // row 1, col 2
res[4] = cZ * cX; // row 2, col 2
res[5] = sZ * sY + cZ * cY * sX; // row 3, col 2
res[6] = cX * sY; // row 1, col 3
res[7] = -sX; // row 2, col 3
res[8] = cX * cY; // row 3, col 3
return res;
}
如果我的 phone 平躺在 table 上(纵向模式),顶部指向远离我的方向,然后执行 "resetOrientation",这适用于 left/right 和 forward/backward 运动。也就是说,如果我将 phone 围绕 z 轴旋转 180 度(意味着仍然平放在 table 上),那么我的顶部指向我,加速度(代码中的 earthAcc 矩阵)为 L/R 和 F/B 移动仍然正确。但是 up/down 不正确,一旦我开始围绕其他轴旋转 phone,我就会得到不一致的结果。
可能只漏了一行或类似的东西,希望矩阵代数大师能发现问题:)
更新:通过将我在 handleMotion 中创建 accMatrix 的方式更改为:
let accMatrix = mat3.create();
accMatrix.set([0, 0, 0, 0, 0, 0, x, y, z]);
...我也有 UP/DOWN 工作,但如果我在 Z 以外的任何其他轴上旋转 phone,它不再给出正确的值。
更新 2:我正在 iOS Safari (Iphone) 上测试这个,所以我不知道这是否是设备类型特定的问题,但我使用的是 Gyronorm 库应该 return 标准化值。
我已经能够解决我的错误。加速度乘法矩阵应如下所示:
accMatrix.set([1, 0, 0, 0, 1, 0, x, y, z]);
也就是说,基数应该是一个单位矩阵,而不仅仅是零。