Finding the current Accelerometer values - ios

I'm trying to get a label to rotate based on the tit of the device in an app I'm making in swift. Given that I should be fine with rotating the label, does anybody know how to find the current accelerometer values of an iPhone? For example, getting it to print its x, y and z values once every second or so.
Thanks in advance.

Sample code:
Add the framework
Add the following code in the appropriate places
import CoreMotion
var motionManager = CMMotionManager()
var AccelX: CGFloat = 0
// Setup accelemeter detection
if motionManager.accelerometerAvailable == true {
motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue(), withHandler: { (data, error) -> Void in
self.outputAccelertionData(data.acceleration)
})
}
func outputAccelertionData (acceleration: CMAcceleration) {
AccelX = 0
if fabs(CGFloat(acceleration.x)) > fabs(AccelX) {
AccelX = CGFloat(acceleration.x)
}
}

Related

how to find HKMetadataKeyMaximumSpeed

I am wondering how to find a user's top speed using HealthKit.
I have come across this HKMetadataKeyMaximumSpeed but have no idea how to implement/use it. The docs are not very clear to me.
Can anyone provide any help here?
Apple indicates thath :
HKMetadataKeyMaximumSpeed Set this key on a workout, workout segment, or a quantity sample that represents distance. Set its value to an HKQuantity object with a length/time unit (for example, m/s)
So you can use this function with this property :
func workoutSession(_ workoutSession: HKWorkoutSession, didGenerate event: HKWorkoutEvent) {
if event.type == .segment {
let maxSpeed = event.metadata?[HKMetadataKeyMaximumSpeed]
// do it here your logic
}
Regarding to your comment: You can not genererate these events on the simulator.
There is example provided by Apple in docs.
func workoutSession(_ workoutSession: HKWorkoutSession, didGenerate event: HKWorkoutEvent) {
// Check to see if the event is a segment.
if event.type == .segment {
// Get the segment's start and end times.
let startTime = event.dateInterval.start
let endTime = event.dateInterval.end
// Get the segment's metadata.
let averageSpeed = event.metadata?[HKMetadataKeyAverageSpeed]
let maxSpeed = event.metadata?[HKMetadataKeyMaximumSpeed]
let alpineSlope = event.metadata?[HKMetadataKeyAlpineSlopeGrade]
let elevationAscended = event.metadata?[HKMetadataKeyElevationAscended]
let elevationDescended = event.metadata?[HKMetadataKeyElevationDescended]
// Do something with the segment data here...
}
// Also handle any other event types...
}

Accessing state information in swift - DJI Mobile SDK iOS

I can't get my head around how to get out simple status data, like the current gimbal pitch for example.
I have not found a solid connection between the DJI SDK and what actually works in xcode. The SDK gives me hints and together with xcode autocompletion a go forwards, slowly..
Class GimbalState has member getAttitudeInDegrees() with description:
"The current gimbal attitude in degrees. Roll, pitch and yaw are 0 if the gimbal is level with the aircraft and points in the forward direction of North Pole." - Great!
However, it does not autocomplete in xcode nor does it compile.
Other approaches tested:
var gimbalStateInformation = DJIGimbalState()
print(gimbalStateInformatoin.attitudeInDegrees.pitch.description)
--> All pitch roll and yaw values come out as 0.0
var gimbalStateInformation = DJUGimbalAttitude()
print(gimbalStateInformatoin.pitch.description)
--> All pitch roll and yaw values come out as 0.0
I've tried to reach the information via keys, but my app crashes when I run the code.
func getGimbalAttitude(){
// Get the key
guard let gimbalAttitudeKey = DJIGimbalKey(param: DJIGimbalParamAttitudeInDegrees) else {
print("Could not create DJIGimbalParamAttitudeInDegrees key")
return
}
// Get the keyManager
guard let keyManager = DJISDKManager.keyManager() else {
print("Could not get the key manager, manke sure you are registered")
return
}
// Test if key is available
let testing = keyManager.isKeySupported(gimbalAttitudeKey)
self.statusLabel.text = String(testing) // This comes out true
// Use key to retreive info
let gimbalAttitudeValue = keyManager.getValueFor(gimbalAttitudeKey)
let gimbalAttitude = gimbalAttitudeValue?.value as! DJIGimbalState
_ = gimbalAttitude.attitudeInDegrees.pitch
// --> Application crashes on the line above
}
I'm working towards a Mavic Mini.
Please advise in general terms how to connect the DJI Mobile SDK to Swift and specifically how I can read out the current gimbal pitch value.
You can access the current Gimbal pitch through its didUpdate state delegate function
import DJISDK
class GimbalController: NSObject, DJIGimbalDelegate {
let gimbal: DJIGimbal
init(gimbal: DJIGimbal) {
self.gimbal = gimbal
super.init()
gimbal.delegate = self
}
func gimbal(_ gimbal: DJIGimbal, didUpdate state: DJIGimbalState) {
print(state.attitudeInDegrees.pitch)
}
}
// create an instance of the custom gimbal controller in some other class
// and pass it the gimbal instance
if let aircraft = DJISDKManager.product() as? DJIAircraft {
if let gimbal = aircraft.gimbal {
let gimbalController = GimbalController(gimbal: gimbal)
}
}

How to work with accelerometer data from the Apple Watch?

Via the code below I am getting accelerometer data, now I want to work with it to track the user's movement, specifically speed. Looking around at code using Core Motion on the iPhone they are using a motionManager object which can set a value for accelerometerUpdateInterval as well as get the .acceleration.x value for example. How can I work with the raw data I'm given back so that I can determine e.g. how fast a person is moving or how fast their arm is swinging?
//Record the data
if CMSensorRecorder.isAccelerometerRecordingAvailable() {
print("Accelerometer available")
recorder.recordAccelerometer(forDuration: 20 * 60) // Record for 20 minutes
}
//Read the data
if CMSensorRecorder.isAccelerometerRecordingAvailable() {
let accelerometerData = recorder.accelerometerData(from: startDate, to: endDate)
for (index, data) in (accelerometerData?.enumerated())! {
print(index, data)
}
}
Prints:
0 388, 208409.082611, 529770182.607276, (0.038574, -0.762207, -0.652832)
1 388, 208409.102722, 529770182.627387, (0.027588, -0.763184, -0.660889)
2 388, 208409.122863, 529770182.647528, (0.027100, -0.763184, -0.661865)
3 388, 208409.142974, 529770182.667639, (0.030029, -0.756836, -0.661865)
4 388, 208409.163116, 529770182.687781, (0.026611, -0.764648, -0.665039)
Edit: I found this lib which looks like it would be perfect but hasn't been updated in 3 years...anything similar that is still maintained? https://github.com/MHaroonBaig/MotionKit
I found that using a CMMotionManager on the watch works just as good as it does on iPhone. This way you can implement startAccelerometerUpdates in awake and receive real time feed back on watch positions for X Y Z coordinates so that you can get a better grasp of the data;
var motionManager = CMMotionManager()
override func awake(withContext context: Any?) {
super.awake(withContext: context)
manager.accelerometerUpdateInterval = 0.2
manager.startAccelerometerUpdates(to: OperationQueue.current!) { (data, error) in
if let myData = data {
print("x: \(myData.acceleration.x) y: \(myData.acceleration.y) z: \(myData.acceleration.z)")
if myData.acceleration.x > 1.5 && myData.acceleration.y > 1.5 {
}
}
}
}

CMDeviceMotion heading is -1.0

There is a new heading property of CMDeviceMotion in iOS 11.
I'm trying to use it but find that it's always -1.0. It's supposed to hold degrees as a Double from 0.0 to 360.0.
My app targets iOS 11+, and I'm testing on a physical device (iPhone) running iOS 11.
let mmgr = CMMotionManager()
mmgr.showsDeviceMovementDisplay = true // for calibrating magnetometer, maybe not needed?
mmgr.deviceMotionUpdateInterval = 0.1
mmgr.startDeviceMotionUpdates(to: .main, withHandler: { (motionData: CMDeviceMotion?, error: Error?) in
if let motion = motionData {
print("heading:", motion.heading) // always -1.0
}
})
I can get other properties just fine, such as motion.attitude.roll. Is there something I'm missing?
The issue is that I needed to start motion updates with a different method signature which includes the CMAttitudeReferenceFrame option:
let mmgr = CMMotionManager()
mmgr.deviceMotionUpdateInterval = 0.1
mmgr.startDeviceMotionUpdates(using: .xMagneticNorthZVertical, to: .main, withHandler: { (motionData: CMDeviceMotion?, error: Error?) in
if let motion = motionData {
print("heading:", motion.heading) // works
}
})
The What's New in iOS 11 guide states that if you use xArbitraryZVertical (default) or xArbitraryCorrectedZVertical for the CMAttitudeReferenceFrame option, the heading will always be -1.
This helpful tidbit is not stated in the heading property reference.

iOS: Swift: Combine Accelerometer and Attitude data for comparable results

Idea
My idea is to write a little application for my iOS-Device to record a motion after start recording by touching an UIButton and save the data from the accelerometer for this motion. After the recording, I can save this data to use it in the finished Application to detect this motion again.
So, what I'm looking for is a way to compare two NSMutableArrays, each as a set of motion data, and want to check if the current NSMutableArray is the same motion as the recorded one.
Problems
To realize this idea, I found three problems, which I can't solve myself:
How to compare two NSMutableArrays and get e.g. an index-level of the similarity or a percentage e.g. 97.32% equivalent.
What if the user makes the motion in different speeds? E.g. slowly or fast.
The last problem: How to handle different device-orientations? Is there a way to calculate the data from the accelerometer to a neutral level in any orientation? I think I have a solution approach for this last problem, but don't know how to bring this to code: We have the attitude data for pitch, roll and yaw. Maybe we can calculate with these values the neutral data for the accelerometer?
Code
At this moment, I only have the code to get the data from the accelerometer and the attitude data, both from the MotionManager. I played multiple hours with my code and searched a lot on Google, but can't find the right way...
import UIKit
import CoreMotion
var motionManager = CMMotionManager()
var x:Float = 0.0
var y:Float = 0.0
var z:Float = 0.0
var roll:Float = 0.0
var pitch:Float = 0.0
var yaw:Float = 0.0
class FirstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
motionManager.accelerometerUpdateInterval = 1
motionManager.deviceMotionUpdateInterval = 1
}
#IBAction func startRecording() {
accelerometerData = NSMutableArray()
motionManager.startDeviceMotionUpdates(using: CMAttitudeReferenceFrame.xMagneticNorthZVertical, to:
OperationQueue.current!, withHandler: {
(deviceMotion, error) -> Void in
let attitude = deviceMotion?.attitude
let roll = self.degrees(radians: attitude!.roll)
let pitch = self.degrees(radians: attitude!.pitch)
let yaw = self.degrees(radians: attitude!.yaw)
self.roll = Float(roll)
self.pitch = Float(pitch)
self.yaw = Float(yaw)
let accX = deviceMotion?.userAcceleration.x
let accY = deviceMotion?.userAcceleration.y
let accZ = deviceMotion?.userAcceleration.z
self.x = Float(accX!)
self.y = Float(accY!)
self.z = Float(accZ!)
})
}
}
Update
I will update this question, when I know more.
Problem 2: Solution:
With the Attribute CMAttitudeReferenceFrame.xMagneticNorthZVertical for the motionManager.startDeviceMotionUpdates-Method you can neutralize all sensors data to a defined orientation. You can access the accelerometer-data here too. I've updated the code above, too.

Resources