传感器信息采集项目到了一定的节点,总结一下iOS中传感器信息采集的相关知识。

代码下载:https://github.com/haojinming/SensorInIOS

Accelerometer
Gyroscope
Magnetometer
Pedometer
Barometer
GPS
Bluetooth
MotionActivity observer
Audio decibel
Wifi status and strength
Ambient Light
Shake status and times
Steps/Pace/Distance
Pressure
NFC
一、 首先是运动传感器,加速度仪、陀螺仪和罗盘。
主要使用Core Motion模块进行采集,有Pull和Push两种模式。
另外有原始数据和经过系统处理两种模式,主要区别在于系统对重力加速度进行了处理,只保留手机用户对手机的输入,在游戏和判断用户运动状态时很有用。
代码示例(原数据):

可以指定数据更新的频率,实时性比较好。

if self.motionManager.isAccelerometerAvailable{
self.motionManager.accelerometerUpdateInterval = timeIntervalUpdate
self.motionManager.startAccelerometerUpdates()
}
if self.motionManager.isGyroAvailable {
self.motionManager.gyroUpdateInterval = timeIntervalUpdate
self.motionManager.startGyroUpdates()
}
if self.motionManager.isMagnetometerAvailable{
self.motionManager.magnetometerUpdateInterval = timeIntervalUpdate
self.motionManager.startMagnetometerUpdates()
}
//get the motion sensor data
if let data = self.motionManager.accelerometerData{
self.realTimeData.sensorData.accelerometerData = data.acceleration
}
if let data = self.motionManager.gyroData{
self.realTimeData.sensorData.gyroscopeData = data.rotationRate
}
if let data = self.motionManager.magnetometerData{
self.realTimeData.sensorData.magnetometerData = data.magneticField
}
代码示例(系统过滤掉重力加速度):

if self.motionManager.isDeviceMotionAvailable{
self.motionManager.deviceMotionUpdateInterval = timeIntervalUpdate
self.motionManager.startDeviceMotionUpdates()
}
if let motionData = motionManager.deviceMotion{
self.realTimeData.sensorData.accelerometerData = motionData.userAcceleration
self.realTimeData.sensorData.gyroscopeData = motionData.rotationRate
}
二、气压,海拔
气压海拔数据更新无法制定更新频率,只能通过Block的方式获取,实际会有几秒钟的延迟。
if CMAltimeter.isRelativeAltitudeAvailable(){
self.altitudeSensor.startRelativeAltitudeUpdates(to: OperationQueue.main, withHandler: {
data, error in
if error != nil{
print(“Error occurs within altitude sensor.”)
}
if let dataTemp = data{
self.realTimeData.sensorData.altitudeData = dataTemp
}
})
}
else{
print(“Altitude sensor is not available.”)
}
三、步行相关的传感器,计步器(Pedometer)采集Steps/Pace/Distance,MotionActivity
计步器:
同样无法制定更新频率,延迟比较大,测试结果能达到10s或10m左右的延迟
private func startPedometerData(){
self.realTimeData.sensorData.pedometerData = CMPedometerData.init()
if !CMPedometer.isStepCountingAvailable(){
print(“Pedometer is not available.”)
}
if !CMPedometer.isPaceAvailable(){
print(“Pace is not available.”)
}
self.pedometer.startUpdates(from: Date.init(), withHandler: { data, error in
if (error != nil){
print(error.debugDescription)
}
if let tempData = data{
self.realTimeData.sensorData.pedometerData = tempData
}
})
}

private func stopPedometerData(){
    if CMPedometer.isStepCountingAvailable(){
        self.pedometer.stopUpdates()
    }
}

MotionActivity :
同样会有延迟,延迟三秒左右。

四、间接传感器,摇一摇,接近传感器
if self.canBecomeFirstResponder{
self.becomeFirstResponder()
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.endEditing(true)
}

override func motionBegan(_ motion: UIEventSubtype, with event: UIEvent?) {
    sensorDataCollector.setShakeStatus(status: "ShakeBegan")
}

override func motionCancelled(_ motion: UIEventSubtype, with event: UIEvent?) {
    sensorDataCollector.setShakeStatus(status: "ShakeCancelled")
}

override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
    sensorDataCollector.setShakeStatus(status: "ShakeEnded")
    sensorDataCollector.setShakeTimes(times: sensorDataCollector.getShakeTimes() + 1)
}

接近传感器:
private func startProximityStatus(){
let curDevice = UIDevice.current
let isOpend = curDevice.isProximityMonitoringEnabled
if !isOpend{
curDevice.isProximityMonitoringEnabled = true
}
let defaultCenter = NotificationCenter.default
defaultCenter.addObserver(self, selector: #selector(self.proximityStateDidChange), name: Notification.Name.UIDeviceProximityStateDidChange, object: nil)
}

// stop collect proximity status
private func stopProximityStatus(){
    let curDevice = UIDevice.current
    let isOpend = curDevice.isProximityMonitoringEnabled
    if isOpend{
        curDevice.isProximityMonitoringEnabled = false
    }
}

// listen the state change of proximity sensor.
@objc func proximityStateDidChange(){
    let curDevice = UIDevice.current
    if curDevice.proximityState{
        realTimeData.sensorData.proximityStatus = "Closing."
    }
    else{
        realTimeData.sensorData.proximityStatus = "Leaving."
    }
}

五、音视频数据采集
音频可以采集分贝数:
private func startRecordAudio(){
let audioSetting = [AVSampleRateKey : Float(8000.0),
AVFormatIDKey : Int32(kAudioFormatMPEG4AAC),
AVNumberOfChannelsKey : 1,
AVEncoderAudioQualityKey : Int32(AVAudioQuality.medium.rawValue)] as [String : Any]
self.audioSession.requestRecordPermission { (granted) in
if granted{
var recordURL = self.createAudioURL()
if recordURL nil{
recordURL = URL.init(fileURLWithPath: “dev/null”)
}
do{
try self.audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord, with: AVAudioSessionCategoryOptions.defaultToSpeaker)
try self.audioRecorder = AVAudioRecorder(url: recordURL!, settings: audioSetting)
self.audioRecorder.delegate = self
self.audioRecorder.isMeteringEnabled = true
self.audioRecorder.prepareToRecord()
}catch let error as NSError{
print(error)
return
}
if !self.audioRecorder.isRecording{
do{
try self.audioSession.setActive(true)
self.audioRecorder.record()
self.audioURL = nil
}catch{
print(“Cann’t enable audio record session.”)
}
}
}
else{
print(“Audio is not availible”)
}
}
}

private func stopRecordAudio(){
    if audioRecorder != nil && audioRecorder.isRecording{
        audioRecorder.stop()
        do{
            try self.audioSession.setActive(false)
        }catch{
            print("Cann't disable audio record session.")
        }
    }
}

视频是用来检测环境光的:
//get ambient light brightbess value from camera
private func startGetAmbientLightValue(){
AVCaptureDevice.requestAccess(for: AVMediaType.video) { (granted) in
if granted && AVCaptureDevice.authorizationStatus(for: AVMediaType.video) AVAuthorizationStatus.authorized{
//input of camera
if let cameraDevice = AVCaptureDevice.default(for: AVMediaType.video){
do{
let deviceInput = try AVCaptureDeviceInput.init(device: cameraDevice)
if self.session.canAddInput(deviceInput){
self.session.addInput(deviceInput)
}
}catch{
print(“Error occurs during start recording audio.”)
}
}

            //ouput of camera
            let deviceOutput = AVCaptureVideoDataOutput.init()
            deviceOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)
            if self.session.canAddOutput(deviceOutput){
                self.session.addOutput(deviceOutput)
            }
            self.session.startRunning()
        }
        else{
            print("Camera is not available.")
        }
    }
}
private func stopCaptureSession(){
    session.stopRunning()
}

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
    let metaDataDict = CMCopyDictionaryOfAttachments(kCFAllocatorDefault, sampleBuffer, kCMAttachmentMode_ShouldPropagate)
    let metaData = NSMutableDictionary.init(dictionary: metaDataDict!)
    let exifMetaData = metaData.object(forKey: kCGImagePropertyExifDictionary) as! NSDictionary
    let brightness = exifMetaData.object(forKey: kCGImagePropertyExifBrightnessValue) as! Double
    self.realTimeData.sensorData.ambientLight = brightness
}

六、定位相关的,蓝牙、WiFi,GPS、NFC
蓝牙:
private func startScanPeripheral(){
if self.cbCentralManager nil{
self.cbCentralManager = CBCentralManager.init(delegate: self, queue: DispatchQueue.main, options: [CBCentralManagerOptionRestoreIdentifierKey : “HJMID”])
}
if timerBLEDevice != nil{
timerBLEDevice.fire()
}else{
timerBLEDevice = Timer.init(fire: Date.init(), interval: timeIntervalBLEScan, repeats: true, block: { (timerBLEDevice) in
switch self.cbCentralManager.state {
case .poweredOn:
if self.cbCentralManager.isScanning{
self.cbCentralManager.stopScan()
}
self.cbCentralManager.scanForPeripherals(withServices: [self.cbuuid], options: [CBCentralManagerScanOptionAllowDuplicatesKey: false])
self.realTimeData.sensorData.bleState = “PowerOn”
default:
break
}
})
RunLoop.main.add(timerBLEDevice, forMode: RunLoopMode.defaultRunLoopMode)
}
}

private func stopScanPeripheral(){
    if timerBLEDevice != nil{
        timerBLEDevice.invalidate()
        timerBLEDevice = nil
    }
    if cbCentralManager != nil{
        cbCentralManager.stopScan()
        for peripheral in peripheralDevices{
            cbCentralManager.cancelPeripheralConnection(peripheral)
        }
    }
}

func centralManagerDidUpdateState(_ central: CBCentralManager) {
    switch central.state {
    case .poweredOn:
        self.realTimeData.sensorData.bleState = "PowerOn"
        if self.cbCentralManager.isScanning{
            cbCentralManager.stopScan()
        }
        cbCentralManager.scanForPeripherals(withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey: true])
    case .poweredOff:
        self.realTimeData.sensorData.bleState = "PoweredOff"
    case .resetting:
        self.realTimeData.sensorData.bleState = "Resetting"
    case .unauthorized:
        self.realTimeData.sensorData.bleState = "Unauthorized"
    case .unsupported:
        self.realTimeData.sensorData.bleState = "Unsupported"
    default:
        self.realTimeData.sensorData.bleState = "Unknown"
        break
    }
}

let cbuuid = CBUUID.init(string: "0xFEA7")

func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
    
    var bleState = "Not supported"
    switch peripheral.state {
    case .connected:
        bleState = "Connected"
    case .connecting:
        bleState = "Connecting"
    case .disconnecting:
        bleState = "Disconnecting"
    case .disconnected:
        bleState = "Disconnected"
        //cbCentralManager.connect(peripheral, options: nil)
    }
    var bleName = "No Name"
    if peripheral.name != nil {
        bleName = peripheral.name!
    }
    let bleUUID = peripheral.identifier.uuidString
    //print(bleUUID)
    let bleRSSI = RSSI.intValue
    let bleDevice = BLEDeviceData.init(name: bleName, uuid: bleUUID, state: bleState, rssi: bleRSSI)
    
    updateBLEDeviceDate(inputBleDevice: bleDevice)
    if !peripheralDevices.contains(peripheral) {
        self.peripheralDevices.append(peripheral)//Strong reference
    }
}

private func updateBLEDeviceDate(inputBleDevice : BLEDeviceData){
    //If exist same device, update its information.
    var currentIndex = -1
    for ii in 0..= 0{
        realTimeData.sensorData.bleDevicesData.remove(at: currentIndex)
    }
    realTimeData.sensorData.bleDevicesData.append(inputBleDevice)
}

func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
    if error == nil{
        //print("Discover services in device.")
        for service in peripheral.services!{
            peripheral.discoverCharacteristics(nil, for: service)
        }
    }
}

func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) {
    print("APP will restore")
    
    let restoreID = dict[CBCentralManagerOptionRestoreIdentifierKey]
    if restoreID != nil {
        cbCentralManager = CBCentralManager.init(delegate: self, queue: DispatchQueue.main, options: [CBCentralManagerOptionRestoreIdentifierKey : restoreID as! String])
    }else{
        cbCentralManager = CBCentralManager.init(delegate: self, queue: DispatchQueue.main, options: [CBCentralManagerOptionRestoreIdentifierKey : "HJMID"])
    }
}

GPS:
private func startUpdateLocation(){
if locationManager nil {
locationManager = CLLocationManager.init()
locationManager.delegate = self
}
locationManager.requestWhenInUseAuthorization()
}

private func stopUpdateLocation(){
    locationManager.stopUpdatingLocation()
}

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    if status == .authorizedWhenInUse || status == .authorizedAlways{
        manager.startUpdatingLocation()
    }
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    if !locations.isEmpty{
        self.realTimeData.sensorData.location = locations[0].coordinate
    }
}

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    print(error)
}

NFC(iOS11及iPhone7 Plus之后才支持)

public func startReadNFCTag(){
if NFCNDEFReaderSession.readingAvailable {
session = NFCNDEFReaderSession.init(delegate: self, queue: DispatchQueue.main, invalidateAfterFirstRead: false)
session.begin()
}
}

func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) {
    valid = false
    print(error)
}

func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) {
    valid = true
    self.messages.removeAll()
    for message in messages {
        for item in message.records{
            var prefix = 0
            let identifier = String.init(data: item.identifier, encoding: .utf8)!
            let type = String(data: item.type, encoding: .utf8)!
            if type == "U" {
                prefix = 1
            }else if type == "T" {
                prefix = 3
            }
            let payload = String(data: item.payload.advanced(by: prefix), encoding: .utf8)!
            let typeNameFormat = String(item.typeNameFormat.rawValue)
            
            let ndefData = NDEFData.init(identifier: identifier, payload: payload, type: type, typeNameFormat: typeNameFormat)
            self.messages.append(ndefData)
        }
    }
}

原文地址

文章来源于互联网,如有雷同请联系站长删除:iOS传感器数据采集

发表评论