-2

I wrote this code to show the sensors data and to read and show them in swiftui, it doesn't work unfortunately. can someone help me ?? there's some bugs in swiftui and I have some errors but the most important is first to get the sensor data. is it the correct code to read data for accelerometer and gyroscope ?

'''

  HStack{
                Button("Start") {
                  // start()
                             
                } .padding()
                Button("Stop") {
                  // start()
                             
                } .padding()
              
            }                      
        }       
    }
   func start(){
       
        self.motionManager.gyroUpdateInterval = 0.5
           motionManager.startGyroUpdates(to: OperationQueue.current!) { (data, error) in
            print(data as Any)
                 
             if let data = self.motionManager.gyroData {
                let xG = data.rotationRate.x
                let yG = data.rotationRate.y
                let zG = data.rotationRate.z
               
                self.appendReadingGyroscope(x: xG, y: yG, z: zG)
                // Use the gyroscope data in your app.
             }
     
    }
          
        
    self.motionManager.accelerometerUpdateInterval = 0.5
        motionManager.startAccelerometerUpdates(to: OperationQueue.current!) { (data, error) in
               print(data as Any)
                  
          
            if let data = self.motionManager.accelerometerData {
                  let xA = data.acceleration.x
                  let yA = data.acceleration.y
                  let zA = data.acceleration.z
                  
                self.appendReadingAccelerometer(x: xA, y: yA, z: zA)
              
                  // Use the accelerometer data in your app.
               }
           }
       }
    func stop() {
         
             self.motionManager.stopGyroUpdates()
             self.motionManager.stopAccelerometerUpdates()
          }

'''
AAA
  • 13
  • 4
  • 1
    Reading data looks fine except the queue to be background i think. But you didn't highlight the exact issue/error. Is it not printing any motion data? or you are not able to show it in UI? – Kamran Sep 29 '20 at 08:19

1 Answers1

1

You've got a couple of problems with your code.

First, try to separate your MotionManager from your ContentView and use Combine to read the properties when they update.

I built a MotionManager class. MotionManagerclass is an ObservableObject (Combine) because we need to implement x, y and z as @Published properties in order to read them in our ContentView when they update.

Here's the class MotionManager :

class MotionManager: ObservableObject {
    // MotionManager use the ObservableObject Combine property.
    private var motionManager: CMMotionManager

    @Published
    var x: Double = 0.0
    @Published
    var y: Double = 0.0
    @Published
    var z: Double = 0.0
    // x, y and z use are Published so ContentView can read the values when they update.

    // init
    init() {
        self.motionManager = CMMotionManager()
        self.motionManager.magnetometerUpdateInterval = 0.5
        self.motionManager.startMagnetometerUpdates(to: .main) { (magnetometerData, error) in
            guard error == nil else {
                print(error!)
                return
            }

            if let magnetData = magnetometerData {
                self.x = magnetData.magneticField.x
                self.y = magnetData.magneticField.y
                self.z = magnetData.magneticField.z
            }

        }

    }
}

And now here's your ContentView. It's way more cleaner. Here you can implement your buttons if you want to.

In your ContentView, you now need to instanciate the MotionManager class in order to access x, y and z @Published properties.

struct ContentView: View {
    
    @ObservedObject var motion: MotionManager
    // You need to instanciate your MotionManager class as an ObservedObject to use x, y and z when the update
    
    var body: some View {
        
        VStack {
                    Text("Magnetometer Data")
                    Text("X: \(motion.x)")
                    Text("Y: \(motion.y)")
                    Text("Z: \(motion.z)")
                }
    }
}

Please note that you'll need to pass your MotionManager() into the preview code and in the WindowGroup in order to compile : ContentView(motion: MotionManager())

I hope my code will help you understand what's going wrong in yours. If not, feel free to ask.

------- EDIT

I implemented start() and stop() functions.

//
//  ContentView.swift
//  todeletenow
//
//  Created by Théo Voglimacci on 29/09/2020.
//

import SwiftUI
import Combine
import CoreMotion

struct ContentView: View {
    
    @ObservedObject var motion: MotionManager
    // You need to instanciate your MotionManager class as an ObservedObject to use x, y and z when the update
    
    var body: some View {
        
        HStack {
            
            Button("Start") {
                motion.start()
                
            } .padding()
            
            Button("Stop") {
                motion.stop()
                
            } .padding()
            
        }
        
        VStack {
            Text("Magnetometer Data")
            Text("X: \(motion.x)")
            Text("Y: \(motion.y)")
            Text("Z: \(motion.z)")
        }
    }
}

class MotionManager: ObservableObject {
    // MotionManager use the ObservableObject Combine property.
    private var motionManager: CMMotionManager
    
    @Published
    var x: Double = 0.0
    @Published
    var y: Double = 0.0
    @Published
    var z: Double = 0.0
    // x, y and z use are Published so ContentView can read the values when they update.
    
    func start() {
        motionManager.startMagnetometerUpdates(to: .main) { (magnetometerData, error) in
            guard error == nil else {
                print(error!)
                return
            }
            
            if let magnetData = magnetometerData {
                self.x = magnetData.magneticField.x
                self.y = magnetData.magneticField.y
                self.z = magnetData.magneticField.z
            }
            
        }
    }
    
    func stop() {
        motionManager.stopMagnetometerUpdates()
    }
    
    // init
    init() {
        self.motionManager = CMMotionManager()
        self.motionManager.magnetometerUpdateInterval = 0.5
        self.motionManager.startMagnetometerUpdates(to: .main) { (magnetometerData, error) in
            guard error == nil else {
                print(error!)
                return
            }
            
            if let magnetData = magnetometerData {
                self.x = magnetData.magneticField.x
                self.y = magnetData.magneticField.y
                self.z = magnetData.magneticField.z
            }
            
        }
        
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(motion: MotionManager())
    }
}
theovogg
  • 51
  • 4
  • I also implement this code, what you say. I think the problem its, that I don't want to show it in contentView() and I want to show it in another page names SensorView().I've add to SensorView(motion: MotionManager()) too. – AAA Sep 29 '20 at 08:47
  • Then, you just have to add `ContentView(motion: MotionManager())` (or whatever view you put your code in) where you want to display the informations. – theovogg Sep 29 '20 at 08:53
  • I did it, but still doesn't work. I put the output in a start function and I have a Start Button, that call this function. do you think the function call is correct and it works like this ? – AAA Sep 29 '20 at 08:57
  • In my code, i didn't implement the functions. I only showed you how to read values from MotionManager. – theovogg Sep 29 '20 at 09:01
  • I implemented your two functions `start()` and `stop()`, please see my code in my original response. – theovogg Sep 29 '20 at 09:07
  • Do you know how can I add this VStack to a button, that after I click the button, the data appears on the screen ? – AAA Sep 29 '20 at 09:08
  • Error : var body: some View { //Function declares an opaque return type, but has no return statements in its body from which to infer an underlying type (underlying type : HStack and VStack). Did to get this error also ? – AAA Sep 29 '20 at 09:26
  • I had to see the stacks in a let and returned it and it did worked. Thank's for your help. it works now :) – AAA Sep 29 '20 at 09:55