composable-core-motion
                                
                                 composable-core-motion copied to clipboard
                                
                                    composable-core-motion copied to clipboard
                            
                            
                            
                        CMRotationMatrix (Attitude) is broken
When replacing vanilla CMMotionManager I get some flipped axes of the rotation matrix
I've stopped at a breakpoint in Attitude.init(_ attitude: CMAttitude) and let it assign self.quaternion
Comparing the rotation matrices yields the following results:
(lldb) po attitude.rotationMatrix
▿ CMRotationMatrix
  - m11 : -0.1969096064567566
  - m12 : 0.9799075722694397
  - m13 : -0.03173968195915222
  - m21 : -0.7388630509376526
  - m22 : -0.12703722715377808
  - m23 : 0.6617723703384399
  - m31 : 0.6444437503814697
  - m32 : 0.15376073122024536
  - m33 : 0.7490326166152954
(lldb) po self.rotationMatrix
▿ CMRotationMatrix
  - m11 : -0.19690976161972862
  - m12 : -0.7388631294669954
  - m13 : 0.6444438080182784
  - m21 : 0.979907719073764
  - m22 : -0.12703738138275833
  - m23 : 0.1537607421647839
  - m31 : -0.031739689326065
  - m32 : 0.6617724530725418
  - m33 : 0.7490325843885801
(lldb) 
Expected behavior To have the same axes would be nice..
Environment
- Xcode 12.4
- Swift 5.3
- OS iOS 14.4
Temporary workaround is to flip the matrix:
extension CMRotationMatrix {
    var flipped: Self {
        var flipped = CMRotationMatrix()
        flipped.m11 = self.m11
        flipped.m12 = self.m21
        flipped.m13 = self.m31
        flipped.m21 = self.m12
        flipped.m22 = self.m22
        flipped.m23 = self.m32
        flipped.m31 = self.m13
        flipped.m32 = self.m23
        flipped.m33 = self.m33
        return flipped
    }
}
Good find! Some of the math here file must be wrong or CoreMotion has a different basis than what we assume :/
Will look into it soon, but if the fix really is to transpose the matrix we'd be happy to except a PR to update that computed property.
I'll give it a try later today. The hardest part is to write tests since the (core motion) framework types don't have any useful public constructors (I guess that's why you wrote your own implementations in the first place...)
Sorry, I have not worked on this in a while... Anyway, today I have some new findings:
I put a breakpoint inside DeviceMotion.init(_ deviceMotion: CMDeviceMotion):
po deviceMotion
QuaternionX -0.000882 QuaternionY -0.005251 QuaternionZ 0.932196 QuaternionW -0.361915 UserAccelX 0.001116 UserAccelY 0.000844 UserAccelZ -0.003047 RotationRateX -0.000685 RotationRateY 0.003429 RotationRateZ 0.000225 MagneticFieldX -15.539566 MagneticFieldY 8.030884 MagneticFieldZ -36.237579 MagneticFieldAccuracy 2 Heading 47.562225 SensorLocation 0 @ 667686.919423
po self.attitude
▿ Attitude
  ▿ quaternion : CMQuaternion
    - x : -0.000882195988422291
    - y : -0.005250768163730715
    - z : 0.9321958498359307
    - w : -0.36191515007517006
So far, so good.. if we continue:
po deviceMotion.attitude
CMAttitude Pitch: -0.524317, Roll: 0.312014, Yaw: -137.562226
po self.attitude.pitch * 180 / Double.pi
0.3120013533421466
po self.attitude.roll * 180 / Double.pi
-0.52432466754302
po self.attitude.yaw * 180 / Double.pi
-137.56508141514132
My conclusion is that the bases on CoreMotion is different than your assumptions and it's not just the rotation matrix that is broken.
For reference
I'll prepare a PR later tonight.
I've created a new PR with just the rotation matrix fix. The pitch/roll is still an issue. I've searched around the we in my quest to understand the quirks of CMQuaternion and have found this old SO post (unexpected results from glkquaternion conversion from cmquaternion)