I've taken a look around, and there aren't that many talks or examples on inertial navigation for iOS5. I know that iOS5 introduced some very cool sensor fusion algorithms:
motionQueue = [[NSOperationQueue alloc] init];
[motionQueue setMaxConcurrentOperationCount:1];
motionManager = [[CMMotionManager alloc] init];
motionManager.deviceMotionUpdateInterval = 1/20.0;
[motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical toQueue:motionQueue withHandler:^(CMDeviceMotion *motion, NSError *error) {
}];
I've taken a look at both videos from WWDC that deal with the block above.
The resulting CMDeviceMotion contains a device attitude vector, along with the acceleration separated from the user induced acceleration.
Are there any open source inertial navigation projects specifically for iOS 5 that take advantage of this new sensor fusion ? I'm talking about further integrating this data with the GPS and magnetometer output to get a more accurate GPS position.
A bonus question: is this kind of fusion even possible from a hardware standpoint? Will I melt my iPhone4 if I start to do 20hz processing of all available sensor data over extended periods of time?
I'm ready to start tinkering with these, but would love to get something more solid to start with than the empty block above :)
Thank you for any pointers!
I am writing an app for scuba divers and hoped to add inertial navigation since GPS and other radio based navigation is unavailable underwater. I did quite a bit of research and found that there is just too much jitter in the sensor data on the iPhone for accurate inertial navigation. I did a quick experiment and found that even when the device is perfectly still, the "drift" due to noise in the signal showed that the device "moved" many meters after only a few minutes. Here is the code I used in my experiment. If you can see something I am doing wrong, let me know. Otherwise, I want my afternoon back!
- (void)startCoreMotion {
CMMotionManager *manager = [[CMMotionManager alloc] init];
if ([manager isAccelerometerAvailable]) {
manager.deviceMotionUpdateInterval = 1.0/updateHz;
[manager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion *motion, NSError *error) {
xVelocity += (( 9.8 * motion.userAcceleration.x ) / updateHz);
yVelocity += (( 9.8 * motion.userAcceleration.y ) / updateHz);
zVelocity += (( 9.8 * motion.userAcceleration.z ) / updateHz);
xPosition += ( xVelocity * ( 1 / updateHz ));
yPosition += ( yVelocity * ( 1 / updateHz ));
zPosition += ( zVelocity * ( 1 / updateHz ));
self.xPositionLabel.text = [NSString stringWithFormat:#"x = %f m", xPosition];
self.yPositionLabel.text = [NSString stringWithFormat:#"y = %f m", yPosition];
self.zPositionLabel.text = [NSString stringWithFormat:#"z = %f m", zPosition];
self.xVelocityLabel.text = [NSString stringWithFormat:#"vx = %f m/s", xVelocity];
self.yVelocityLabel.text = [NSString stringWithFormat:#"vy = %f m/s", yVelocity];
self.zVelocityLabel.text = [NSString stringWithFormat:#"vz = %f m/s", zVelocity];
self.distanceLabel.text = [NSString stringWithFormat:#"dist = %f m", sqrt( pow(xPosition, 2) + pow(yPosition, 2) + pow(zPosition, 2))];
}];
}
}
Related
hello i am calculating the device angle by fallowing code and then converting this angle to rise over run formula i am getting the wrong pitch value but when i start rotating device(left to right and right to left in landscape mode) then after some time i started to get correct pitch value here is my code....
operationQueue = [[NSOperationQueue alloc] init];
motionManager = [[CMMotionManager alloc] init];
motionManager.deviceMotionUpdateInterval = 2.0 / 60.0;
[motionManager startDeviceMotionUpdates];
[motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryZVertical toQueue:operationQueue
withHandler:^(CMDeviceMotion *motion, NSError *error)
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
CGFloat x = motion.gravity.x;
CGFloat y = motion.gravity.y;
CGFloat z = motion.gravity.z;
CGFloat angle = atan2(y, x) + M_PI_2; // in radians
CGFloat angleDegrees = angle * 180.0f / M_PI; // in degrees
CGFloat r = sqrtf(x*x + y*y + z*z);
CMQuaternion quat = motionManager.deviceMotion.attitude.quaternion;
NSNumber *myroll = [NSNumber numberWithInt:radiansToDegrees(atan2(2*(quat.y*quat.w - quat.x*quat.z), 1 - 2*quat.y*quat.y - 2*quat.z*quat.z))];
NSNumber *mypitch = [NSNumber numberWithInt:radiansToDegrees(atan2(2*(quat.x*quat.w + quat.y*quat.z), 1 - 2*quat.x*quat.x - 2*quat.z*quat.z))];
NSNumber *myyaw = [NSNumber numberWithInt:radiansToDegrees(2*(quat.x*quat.y + quat.w*quat.z))];
//double actualYaw = [myyaw doubleValue];
// CGFloat tiltForwardBackward = ceilf(motionManager.deviceMotion.attitude.yaw * 180 / M_PI);
**strong text**float pitchValue = motionManager.deviceMotion.attitude.pitch;
pitchValue = [mypitch doubleValue];
pitchValue = (pitchValue < 0) ? -(pitchValue) : pitchValue;
float pitchAngle = [mypitch doubleValue];
pitchAngle = (pitchAngle < 0) ? -(pitchAngle) : pitchAngle;
//pitchValue = (tan(pitchValue*(M_PI/180))*12);
**strong text**pitchValue = (tan((pitchValue*M_PI)/180))*12; // i am using this formula to calculate roof pitch value.
pitchValue = (pitchValue < 0) ? -(pitchValue) : pitchValue;
if(pitchValue >= 99.9){
pitchValue = 99.9;
}
deviceAngle.text = [NSString stringWithFormat: #"Pitch Value = %0.1f/12, Pitch Angle = %.2f", pitchValue, pitchAngle];
//deviceAngle.text = [NSString stringWithFormat: #" %.1f/12",pitchValue];
}];
}];
please help is there any way to calculate rise over run value by using any of this three value.i am keeping my iPhone in landscape mode and then rotating left to right and right to left.
am using wrong value?.i am interested to calculate roof pitch value.is there any formula?.
please help me thanks in advance.
I am testing Core Motion and using the gyroscope. Right now I am getting values that I am not understanding. My assumption was that with each x, y and z I would get a value between 0-360 which would be a full rotation, but this isn't the case.
[self.motionManager startGyroUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMGyroData *gyroData, NSError *error) {
NSString *x = [NSString stringWithFormat:#"%.02f",gyroData.rotationRate.x];
NSLog(#"X: %#", x);
NSString *y = [NSString stringWithFormat:#"%.02f",gyroData.rotationRate.y];
NSLog(#"Y: %#", y);
NSString *z = [NSString stringWithFormat:#"%.02f",gyroData.rotationRate.z];
NSLog(#"Z: %#", z);
frequency = gyroData.rotationRate.y*500;
float rate = gyroData.rotationRate.z;
if (fabs(rate) > .2) {
float direction = rate > 0 ? 1 : -1;
rotation += (direction * M_PI/90.0)*1000;
NSLog(#"Rotation: %f", rotation);
}
}];
It is possible to get more human readable rotation values? Is my assumption that I should be getting values between 0-360 wrong?
The values are in radians, not degrees, so they should be between 0 and 2Pi. Also, they are a rate, not an angle. They are radians per second.
Is there a way to determine the bit-rate of the stream an MPMovieController is playing?
I am programming in objective-c on iOS
You can get the indicated bit rate from event, which is the bit rate of the stream according to the m3u8. To calculate the actual bit rate I divide event.numberOfBytesTransferred / event.durationWatched and multiply by 8.
NSArray *events = self.player.accessLog.events;
MPMovieAccessLogEvent *event = (MPMovieAccessLogEvent *)[events lastObject];
double calculatedBitRate = 8 * event.numberOfBytesTransferred / event.durationWatched;
value = [nf stringFromNumber:[NSNumber numberWithDouble:calculatedBitRate]];
self.calculatedBitRateLabel.text = [NSString stringWithFormat:#"My calculated bit rate = %#", value];
Found it, the "accessLog" gives you periodic stats which include the observed bitrate:
MPMovieAccessLogEvent *evt=nil;
MPMovieAccessLog *accessL=[moviePlayer accessLog];
NSArray *events = accessL.events;
for (int i=0; i<[events count]; i++) {
evt=[events objectAtIndex:i];
}
return evt.observedBitrate
Does anybody know that what is the maximum sampling rate of the iphone accelerometer.
I want to have have high update rate. i set it to updateInterval to 1.0/ 300.0
But it seems that i am not getting that much update rate.
So can any body tell me that what is the maximum update rate that we can get or how i can get the high update rate.
The max accelerometer and gyroscope sampling rate on the iPhone 6 is 100Hz. You can empirically test this yourself. Here is the code.
/******************************************************************************/
// First create and initialize two NSMutableArrays. One for accel data and one
// for gyro data. Then create and initialize CMMotionManager. Finally,
// call this function
- (void) TestRawSensors
{
speedTest = 0.0001; // Lets try 10,000Hz
motionManager.accelerometerUpdateInterval = speedTest;
motionManager.gyroUpdateInterval = speedTest;
[motionManager startAccelerometerUpdatesToQueue: [NSOperationQueue currentQueue]
withHandler: ^(CMAccelerometerData *accelerometerData, NSError *error)
{
[rawAccelSpeedTest addObject: [NSNumber numberWithDouble: accelerometerData.timestamp]];
[rawAccelSpeedTest addObject: [NSNumber numberWithDouble: accelerometerData.acceleration.x]];
if (error)
{
NSLog(#"%#", error);
}
if (rawAccelSpeedTest.count > 100)
{
[motionManager stopAccelerometerUpdates];
for (uint16_t i = 0; i < rawAccelSpeedTest.count; i+=2)
{
NSLog(#"Time: %f Accel: %f", [rawAccelSpeedTest[i] doubleValue],
[rawAccelSpeedTest[i+1] doubleValue]);
}
}
}];
[motionManager startGyroUpdatesToQueue: [NSOperationQueue currentQueue]
withHandler: ^(CMGyroData *gyroData, NSError *error)
{
[rawGryoSpeedTest addObject: [NSNumber numberWithDouble: gyroData.timestamp]];
[rawGryoSpeedTest addObject: [NSNumber numberWithDouble: gyroData.rotationRate.x]];
if (error)
{
NSLog(#"%#", error);
}
if (rawGryoSpeedTest.count > 100)
{
[motionManager stopGyroUpdates];
for (uint16_t i = 0; i < rawGryoSpeedTest.count; i+=2)
{
NSLog(#"Time: %f Rate: %f", [rawGryoSpeedTest[i] doubleValue],
[rawGryoSpeedTest[i+1] doubleValue]);
}
}
}];
}
Despite the documentation saying The maximum frequency at which you can request updates is hardware-dependent but is usually at least 100 Hz. it looks to me like the maximum sample rate is still 100Hz.
My approach to figure out was taking the existing sample code for CoreMotion called MotionGraphs and adapting the startUpdates function to look like this:
func startUpdates() {
guard let motionManager = motionManager, motionManager.isGyroAvailable else { return }
sampleCount = 0
let methodStart = Date()
motionManager.gyroUpdateInterval = TimeInterval(1.0/100000.0) // Hardcoded to something verfy fast
motionManager.startGyroUpdates(to: .main) { gyroData, error in
self.sampleCount += 1
//...view update code removed
if (self.sampleCount >= 100) {
let methodFinish = Date()
let executionTime = methodFinish.timeIntervalSince(methodStart)
print("Duration of 100 Gyro samples: \(executionTime)")
self.stopUpdates()
}
}
}
I also set motionManager.deviceMotionUpdateInterval = TimeInterval(1.0/100000.0) for good measure (in case it is a global rate).
With that code in place for both Accelerometer and Gyroscope I confirm that an iPhone 8 on iOS 11.4 still maxes out right around 100Hz for both.
Duration of 100 Accelerometer samples: 0.993090987205505
Duration of 100 Accelerometer samples: 0.995925068855286
Duration of 100 Accelerometer samples: 0.993505954742432
Duration of 100 Accelerometer samples: 0.996459007263184
Duration of 100 Accelerometer samples: 0.996203064918518
Duration of 100 Gyro samples: 0.989820957183838
Duration of 100 Gyro samples: 0.985687971115112
Duration of 100 Gyro samples: 0.989449977874756
Duration of 100 Gyro samples: 0.988754034042358
Maybe duplicate. Look at
update frequency set for deviceMotionUpdateInterval it's the actual frequency?
Actual frequency of device motion updates lower than expected, but scales up with setting
The same should be valid if using old UIAccerometerDelegate interface.
I have created a uitableview that calculates the distance of a location in the table. I used this code in cell for row at index path.
NSString *lat1 = [object valueForKey:#"Lat"];
NSLog(#"Current Spot Latitude:%#",lat1);
float lat2 = [lat1 floatValue];
NSLog(#"Current Spot Latitude Float:%g", lat2);
NSString *long1 = [object valueForKey:#"Lon"];
NSLog(#"Current Spot Longitude:%#",long1);
float long2 = [long1 floatValue];
NSLog(#"Current Spot Longitude Float:%g", long2);
//Getting current location from NSDictionary
CoreDataTestAppDelegate *appDelegate = (CoreDataTestAppDelegate *) [[UIApplication sharedApplication] delegate];
NSString *locLat = [NSString stringWithFormat:appDelegate.latitude];
float locLat2 = [locLat floatValue];
NSLog(#"Lat: %g",locLat2);
NSString *locLong = [NSString stringWithFormat:appDelegate.longitude];
float locLong2 = [locLong floatValue];
NSLog(#"Long: %g",locLong2);
//Location of selected spot
CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:lat2 longitude:long2];
//Current Location
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:locLat2 longitude:locLong2];
double distance = [loc1 getDistanceFrom: loc2] / 1600;
NSMutableString* converted = [NSMutableString stringWithFormat:#"%.1f", distance];
[converted appendString: #" m"];
It works fine apart from a problem i have just discovered where the distance text is duplicated over the top of the detailed text label when you scroll beyond the height of the page.
here's a screen shot of what i mean.
Any ideas why its doing this?
I can't see the screenshot, but I don't see a problem with your code used to create the string. At least if you're using garbage collection - if you're using manual memory management you'd want to retain/release. It also may be an issue in your .xib file with the table configuration. Finally, are you using any custom views or just standard Cocoa controls? Custom controls can sometimes cause drawing/refresh issues.