0

I have it codded now so when i flip my phone its add one to some text, but its just keeps adding untill its completes a flip. is there a way i can make it so it just adds one for every flip.

changing the y > code

func startGyro() {
    motionManager.gyroUpdateInterval = 0.2
    motionManager.startGyroUpdates(to: OperationQueue.current!) { (data, Error) in
        if let myData = data {
            if myData.rotationRate.y > 3 {
                tiltOut = tiltOut + 1
                self.labelText = "\(tiltOut)"
            }
        }
    }
}

i would like to have it record one for every flip.

RPatel99
  • 7,448
  • 2
  • 37
  • 45
Splilz
  • 13
  • 4
  • You can probably use `myData.rotationRate` along with elapsed time since gyro updates began to calculate with integration how much the phone has rotated since the gyro updates started. You'd also need to determine what a "flip" is. Is it 180 degrees from starting rotation? Is it 360 degrees from starting rotation? Etc. – RPatel99 Oct 12 '19 at 17:25
  • @RPatel99 I want my flip to = 360 degrees from my starting rotation how should i put that in my code? – Splilz Oct 12 '19 at 17:41
  • Its tough for me to test code with gyroscopes with where I'm at right now, so I'll post an answer, but treat it more like a guideline for what you should do than a copy-paste example. – RPatel99 Oct 12 '19 at 17:50
  • @RPatel99 This is very helpful but I'm receiving a error "Enum case 'milliseconds' cannot be used as an instance member" with the "let dt = prevTime.distance(to: currTime).milliseconds" part and "Use of unresolved identifier 'dTheta'" with the two dTheta parts im very lost and if you could point me in the right – Splilz Oct 12 '19 at 22:09
  • Check the edit on my answer. Also, welcome to Stack Overflow; in the future, comment any discussion about an answer to that answer post's comment section. Also, I meant for my code to be more of a guideline than something to copy-paste. The "Use of unresolved identifier 'dTheta'" error is a very common error in most programming languages that usually means that the variable was not declared/there was a typo in the variable name. @Splilz – RPatel99 Oct 13 '19 at 00:03
  • Also, avoid making new StackOverflow posts about simple follow up questions to an answer. Wait to see if the answerer will update their answer or point you towards a post that already exists. Both of the posts I saw that you created already have posts on SO (I linked one of them in my answer), so make sure you check before you post. – RPatel99 Oct 13 '19 at 00:08

1 Answers1

0

Treat this code as more of a guideline than a copy-paste example, because gyroscope-related code is a little difficult to test, but the core idea here is to keep track of elapsed time and rotation rate to determine how far the device has rotated.

var prevTime = DispatchTime.now()
var totalRotation: CGFloat = 0
var delta: CGFloat = 10

func startGyro() {
    motionManager.gyroUpdateInterval = 0.2
    motionManager.startGyroUpdates(to: OperationQueue.current!) { (data, Error) in
        if let myData = data {
            let currTime = DispatchTime.now()
            let dt = 0
            let interval = prevTime.distance(to: currTime)
            if case .nanoseconds(let value) = interval {
                dt = value
            }
            prevTime = currTime
            // assuming rotationRate is in degrees/millisecond.
            let dTheta: CGFloat = CGFloat(myData.rotationRate.y) * CGFloat(dt)
            // If not milliseconds, convert dt to correct time unit
            // If rotationRate is in radians, convert to degrees or make future comparison check for 2*pi instead of 360 degrees
            totalRotation += dTheta
            if totalRotation > 360 - delta && totalRotation < 360 + delta {
                tiltOut = tiltOut + 1
                self.labelText = "\(tiltOut)"
                totalRotation -= 360
            }
        }
    }
}

The delta is there because the startGyroUpdates will not be called every time the device turns 1 degree, so you have to provide a buffer for determining what is okay for "about 360 degrees". Here I gave the range that if it has turned 350-370 degrees, it should increment the label by one. Of course, this uses discrete chunks of time, but assuming that the time interval between startGyroUpdates calls and the change in rotationRate in that time span is relatively fine, there shouldn't be too much error. The code also makes the assumption that the phone will not rotate more than 360 degrees between startGyroUpdates calls, which I think is a fair assumption.

If you know that the rotation rate will be fairly constant, you can also just use the average of the rotation rate and multiply that to the elapsed time.

Edit: Forgot let before dTheta, and added code to convert DispatchTimeInterval to usable Int. You can add cases for seconds, milliseconds, etc., and convert dt to the time unit for rotationRate. See this SO link for more info on converting the result of prevTime.distance(to: currTime) to an Int that you can do math with. Make sure you don't lose precision when doing unit conversion.

Edit 2: Specified dTheta to be of type CGFloat

Edit 3: Casted myData.rotationRate.y and dt to CGFloat

RPatel99
  • 7,448
  • 2
  • 37
  • 45
  • Thank you for all the help but im still getting a error with "let dTheta = myData.rotationRate.y * dt" and the error says, "Binary operator '*' cannot be applied to operands of type 'Double' and 'Int'". I have a github but i dont know how much that will help. "https://github.com/acllc/bestFlip" – Splilz Oct 13 '19 at 20:55
  • cast `dt` to Double: `Double(dt)` – RPatel99 Oct 14 '19 at 02:40
  • thank you for all the help, this fixed my problem. It opens another problem with "totalRotation += dTheta" it says "Binary operator '+=' cannot be applied to operands of type 'CGFloat' and 'Double'". I do not know how to fix it. You have been so much help and I have been looking for someone like you to actually help and not give up. – Splilz Oct 17 '19 at 04:09
  • @Splilz Any time it says that the types don't match, try casting from one type to the other, or specifying the type you want if a variable is getting initialized. Check the edit I just made. – RPatel99 Oct 17 '19 at 05:50
  • @Splilz If this answer was helpful to you, you can accept it so that others know that this solution was helpful and/or correct. If not, feel free to clarify what isn't working or wait for a new answer if this answer is completely off-base. – RPatel99 Oct 18 '19 at 13:40
  • Yes the same error is there but im getting "1. Overloads for '*' exist with these partially matching parameter lists: (Double, Double), (Double, Measurement), (Int, Int)" for help under the error. I think this will help you and this could be the last time we get this error. The error is under "let dTheta: CGFloat = myData.rotationRate.y * dt" and it says "Binary operator '*' cannot be applied to operands of type 'Double' and 'Int'" – Splilz Oct 19 '19 at 18:03
  • @Splilz like I said before, if it says there is a type mismatch, try casting to one of the types. Check the edit I just made. – RPatel99 Oct 19 '19 at 20:42
  • You have been so much help everything runs perfectly, but when i go to start the app I get. "Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1b6413570)" on this line of code, "let interval = prevTime.distance(to: currTime)". I don't what I need to do and if you need any more detail just message me> – Splilz Oct 20 '19 at 17:42