携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天。
在iOS开发中,经常会用到传感器做一些有意思的程序。 CMMotionManager 可以获取到很多类型的数据:
环境光传感器:感应光照强度
距离传感器:感应靠近设备屏幕的物体
磁力计算器:感应周边磁场(标识设备相对于地球磁场的方位)
内部温度传感器:感应设备内部温度(非公开)
湿度传感器:感应设备是否进水(非微电子传感器)
陀螺仪:感应持握方式(标识设备在三个主轴上的瞬时旋转)
加速计:感应设备运动(标识设备在三维空间中的瞬时加速度)
使用很简单,今天记录一下其中一种场景的使用。
介绍一下属性:
1. attitude
attitude 用于标识空间位置的欧拉角(roll、yaw、pitch)和四元数(quaternion)
其中绕 x 轴运动称作 pitch(俯仰),绕 y 轴运动称作 roll(滚转),绕 z 轴运动称作 yaw(偏航)。
当设备正面向上、顶部指向正北、水平放置时,pitch、yaw 和 roll 值均为 0,其他变化如下
设备顶部上扬,pitch 由 0 递增 pi/2,顶部下沉,由 0 递减 pi/2
设备顶部左偏 180 度范围内,yaw 由 0 递增 pi,右偏递减
设备左部上旋,roll 由 0 递增 pi,左部下旋,roll 由 0 递减
2. rotationRate
rotationRate 标识设备旋转速率,具体变化如下
pitch 增加,x > 0,pictch 减少,x < 0
roll 增加,y > 0,row 减少,y < 0
yaw 增加,z > 0,yaw 减少,z < 0
3. gravity
gravity 用于标识重力在设备各个方向的分量,具体值的变化遵循如下规律:重力方向始终指向地球,而在设备的三个方向上有不同分量,最大可达 1.0,最小是 0.0。
4. userAcceleration
userAcceleration 用于标识设备各个方向上的加速度,注意是加速度值,可以标识当前设备正在当前方向上减速 or 加速。
5. magneticField & heading
magneticField 用于标识设备周围的磁场范围和精度,heading 用于标识北极方向。但是要注意,这两个值的检测需要指定 ReferenceFrame,它是一个 CMAttitudeReferenceFrame 的枚举,有四个值
CMAttitudeReferenceFrameXArbitraryZVertical
CMAttitudeReferenceFrameXArbitraryCorrectedZVertical
CMAttitudeReferenceFrameXMagneticNorthZVertical
CMAttitudeReferenceFrameXTrueNorthZVertical
其中前两个 frame 下磁性返回非法负值,只有选择了 CMAttitudeReferenceFrameXMagneticNorthZVertical 或 CMAttitudeReferenceFrameXTrueNorthZVertical 才有有效值,这两个枚举分别指代磁性北极和地理北极。
1、首先,懒加载创建对象。
- (CMMotionManager *)m_motionManager
{
if (!_m_motionManager)
{
_m_motionManager = [[CMMotionManager alloc] init];
_m_motionManager.accelerometerUpdateInterval = 0.1;
}
return _m_motionManager;
}
//获取数据
if (self.m_motionManager.deviceMotionAvailable) {
//TODO:Pull 方式,自己取
//[motionManager startDeviceMotionUpdates];
//double x = motionManager.deviceMotion.gravity.x;
//double y = motionManager.deviceMotion.gravity.y;
//double z = motionManager.deviceMotion.gravity.z;
//TODO:Push 方式,设置好时间后会自动推过来
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[self.m_motionManager startDeviceMotionUpdatesToQueue:queue withHandler:^(CMDeviceMotion *_Nullable motion, NSError * _Nullable error) {
if (!m_objLiveView.m_enableVR)
return;
CMQuaternion quaternion = motion.attitude.quaternion;
GLKMatrix4 matrix4 = [self calculateMatrixFromQuaternion:&quaternion];
matrix4 = GLKMatrix4RotateX(matrix4, M_PI_2);
float rotationMatrix[16] = {matrix4.m00,matrix4.m01,matrix4.m02,matrix4.m03,matrix4.m10,matrix4.m11,matrix4.m12,matrix4.m13,matrix4.m20,matrix4.m21,matrix4.m22,matrix4.m23,matrix4.m30,matrix4.m31,matrix4.m32,matrix4.m33};
}];
}
//TODO: 重力坐标转换
- (GLKMatrix4)calculateMatrixFromQuaternion:(CMQuaternion*)quaternion{
float xx = quaternion->x * quaternion->x;
float yy = quaternion->y * quaternion->y;
float zz = quaternion->z * quaternion->z;
float xy = quaternion->x * quaternion->y;
float wz = quaternion->w * quaternion->z;
float wy = quaternion->w * quaternion->y;
float xz = quaternion->x * quaternion->z;
float yz = quaternion->y * quaternion->z;
float wx = quaternion->w * quaternion->x;
float r00 = 1 - 2 * (yy + zz);
float r01 = 2 * (xy - wz);
float r02 = 2 * (wy + xz);
float r03 = 0;
float r10 = 2 * (xy + wz);
float r11 = 1 - 2 * (xx + zz);
float r12 = 2 * (yz - wx);
float r13 = 0;
float r20 = 2 * (xz - wy);//xy - wy
float r21 = 2 * (yz + wx);
float r22 = 1 - 2 * (xx + yy);
float r23 = 0;
float r30 = 0;
float r31 = 0;
float r32 = 0;
float r33 = 1;
return GLKMatrix4Make(r00,r01,r02,r03,
r10,r11,r12,r13,
r20,r21,r22,r23,
r30,r31,r32,r33);
}
距离传感器
距离传感器可以检测有物理在靠近或者远离屏幕,使用如下
[UIDevice currentDevice].proximityMonitoringEnabled = YES;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(proximityStateDidChange:) name:UIDeviceProximityStateDidChangeNotification object:nil];
- (void)proximityStateDidChange:(NSNotification *)note
{
if ([UIDevice currentDevice].proximityState) {
NSLog(@"Coming");
} else {
NSLog(@"Leaving");
}
}
环境光传感器
目前没有找到相应的 API,可以采取的思路是通过摄像头获取每一帧,进行光线强度检测
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
CFDictionaryRef metadataDict = CMCopyDictionaryOfAttachments(NULL,imageDataSampleBuffer, kCMAttachmentMode_ShouldPropagate);
NSDictionary *metadata = [[NSDictionary alloc] initWithDictionary:(__bridge NSDictionary*)metadataDict];
CFRelease(metadataDict);
NSDictionary *exifMetadata = [[metadata objectForKey:(NSString *)kCGImagePropertyExifDictionary] mutableCopy];
float brightnessValue = [[exifMetadata objectForKey:(NSString *)kCGImagePropertyExifBrightnessValue] floatValue];
NSLog(@"%f",brightnessValue);
其中主要是要注意这个坐标转换,在进行图形转换或者其他交互时,如果发现手机的动作方向和实际的显示的不对称,调整坐标转换。不同的交互场景坐标转换的方法可能不同。