iOS传感器数据采集
传感器信息采集项目到了一定的节点,总结一下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传感器数据采集