2

Game.m

#import "Game.h"
#import "CoreMotion.h"

@implementation Game

- (id) init 
{
    self = [super init];

    self.stopButtonPressed = NO;

    return self;
}
-(void) play
{
     CMMotionManager *motionManager;
     motionManager = [[CMMotionManager alloc] init];
     motionManager.deviceMotionUpdateInterval = 1.f/10.f;
     [motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue]
                                        withHandler:^(CMDeviceMotion *motion, NSError *error)
                                        {
                                          NSLog(@"--------------> %i %i", motionManager.deviceMotionActive , motionManager.deviceMotionAvailable);

                                          NSLog(@"Degrees : %F",atan(motion.magneticField.field.y/fabs(motion.magneticField.field.x)) * 180.0 / M_PI);
                                        }
     ];
}

MyViewController.m

#import "MyViewController.h"
#import "Game.h"

@interface MyViewController()
{
    Game *game;
}
@end

@implementation MyViewController

-(void) viewDidLoad
{
    game = [[Game alloc] init];
}

- (IBAction)playPressed:(UIButton *)sender 
{
    // using a separate thread
    //[game performSelectorInBackground:@selector(play) withObject:nil];

    // not using a separate thread
    [game play] ;
}

- (IBAction)stopPressed:(UIButton *)sender 
{
    game.stopButtonPressed = YES;
}

@end

3 Answers3

1

the magnetic field value is not available immediately after you call the method startDeviceMotionUpdates. You need to try to retrive the value in a later point (i.e. using a NSTimer and checking for updates.

Although this should work it isn't a good practice. If you only need the magnetic field value you should take a look at the documentation of CMMotionManager and use the method startMagnetometerUpdatesToQueue:withHandler: like the following:

[motionManager startMagnetometerUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMMagnetometerData *magnetometerData, NSError *error) {
  CMMagneticField field = magnetometerData.magneticField;
  NSLog(@"x: %f  y:%f  z:%f", field.x, field.y, field.z);
}];

cheers, anka

anka
  • 3,817
  • 1
  • 30
  • 36
  • I will try that but I don't want to use the magnetometerData's raw values but rather the deviceMotion's processed calibrated data, as in : `NSOperationQueue *myQueue = [[NSOperationQueue alloc] init]; CMMotionManager *motionManager; motionManager = [[CMMotionManager alloc] init]; [motionManager startDeviceMotionUpdatesToQueue:myQueue withHandler:^(CMDeviceMotion *motion, NSError *error){NSLog(@"Value of X : %F",motion.magneticField.field.x)}` will this code work? –  Jul 31 '12 at 01:01
  • I tried that (I've edited my original post as well to reflect the changes I made), the app doesn't crash, but I get nothing. Not even a log output on the console. –  Jul 31 '12 at 11:50
  • Hi, use the following operation queue `[NSOperationQueue currentQueue]` and do not forget to set the update rate with `motionManager.deviceMotionUpdateInterval = 1.f/10.f;`. – anka Jul 31 '12 at 12:10
  • I've re-edited my post to the current code I'm using but I still get nothing. Sorry but I'm fairly new to Obj-C.. :) –  Jul 31 '12 at 12:21
  • The code `while(!self.stopButtonPressed)` is unnecessary because the block will be called repeatedly depending on your update interval. You could just use `if(!self.stopButtonPressed)`. Also try to check the state of your motion manager with `NSLog(@"--------------> %i %i", motionManager.deviceMotionActive , motionManager.deviceMotionAvailable);` and see if magnetometer is available. – anka Jul 31 '12 at 13:10
  • I get" --------------> 0 1 " I goes that means device motion is active (0) but device motion is not available (1) for some weird reason ? –  Jul 31 '12 at 13:15
  • Now I found your problem: You are calling your `play` method in background. Avoid this and let it run on the main thread and the motion updates should work too. – anka Jul 31 '12 at 13:16
  • by the way, I'm not using an NSTimer, I'm only using the code presented on my original post –  Jul 31 '12 at 13:42
  • Have a look at the latest edit of my original post. This is what I get now : --------------> 1 1 Degrees : NAN –  Jul 31 '12 at 15:43
  • You get NAN because you are dividing by 0. – anka Aug 01 '12 at 10:07
  • Obviously. Because I'm not reading any magnetic field values. The question is why? –  Aug 01 '12 at 11:10
1

You need to hold onto the CMMotionManager. So make an instance variable for it. For example:

Game.m

#import "Game.h"
#import "CoreMotion.h"

@interface Game ()
@property (nonatomic, strong) CMMotionManager *motionManager;
@end

@implementation Game

@synthesize motionManager = _motionManager;

- (id) init 
{
    self = [super init];

    self.stopButtonPressed = NO;

    return self;
}
-(void) play
{
     self.motionManager = [[CMMotionManager alloc] init];
     self.motionManager.deviceMotionUpdateInterval = 1.f/10.f;
     [self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue]
                                             withHandler:^(CMDeviceMotion *motion, NSError *error)
                                             {
         NSLog(@"--------------> %i %i", self.motionManager.deviceMotionActive , self.motionManager.deviceMotionAvailable);
         NSLog(@"Degrees : %F",atan(motion.magneticField.field.y/fabs(motion.magneticField.field.x)) * 180.0 / M_PI);
                                             }
     ];
}

The problem is that your CMMotionManager that you're creating is being deallocated at the end of the play method since nothing is holding onto it. So the handler never gets called back because your motion manager has gone away.

mattjgalloway
  • 34,792
  • 12
  • 100
  • 110
  • Have you tried looking at `startMagnetometerUpdatesToQueue:withHandler:`? – mattjgalloway Jul 31 '12 at 22:07
  • No because it is supposed to return raw biased magnetic field values where as the DeviceMotion class (or the CLLocationManager) returns already processed unbiased values, according to documentation.. –  Jul 31 '12 at 22:35
0

BTW One possibility is that the device you are running may not even have a magnetometer. See magnetometer-for-compass-on-ipod-touch-4g Where I point to apple-devices-with-magnetometer

Community
  • 1
  • 1
Peter M
  • 7,309
  • 3
  • 50
  • 91