Accelerometer and AccelerometerDelegate

Source code in Accelerometer.zip

  1. main.m
  2. Class AccelerometerAppDelegate
  3. Class View
  4. Property list Accelerometer-Info.plist

Create the project

Allow the app to run only on a device that has the required device capabilities, as we did here. In the Accelerometer-Info.plist file, add the Required device capabilities key with the value accelerometer.

Physics and calculus

Now that we have the iPhone’s acceleration, we can use the mathematical operation of integration to reconstruct the changing speed that gave rise to the given acceleration. Knowing the speed, we can integrate again to reconstruct the iPhone’s changing position that gave rise to the speed. It’s not necessary to perform these integrations using calculus (the integral of 2x is x2). We can perform the first integration by drawing a graph of the acceleration (a series of points connected by straight lines) and then computing the area under this broken line. The area is the speed.

This means that if we put an iPhone in a rocket, we’d be able to caculate the rocket’s speed and then altitude from the accelerometer readings. (No one is suggesting that we build our own V-2.)

The gyroscope measures the iPhone’s angular speed (rate of rotation) around an axis. A CMDeviceMotion object can integrate this for us to compute the iPhone&rsquo's angular position (i.e., its attitude—which way is it facing).

Things to try

  1. The length of the acceleration vector shows the number of G forces. Make it more legible by drawing concentric circles. Insert the following code into drawRect: immediately before we set the stroke color to faint blue.
    	for (int radius = 1; radius <= gForces; ++radius) {
    		CGRect rect = CGRectMake(
    			-radius,	//x of lower left corner
    			-radius,	//y of lower left corner
    			2 * radius,	//width
    			2 * radius	//height
    		);
    
    		CGContextAddEllipseInRect(c, rect);
    	}
    
    Better yet, draw a polar coördinate grid.

  2. Display the CTM (current transformation matrix; see the rooster examples). A CGFloat can be displayed with the %g format.
    	CGAffineTransform ctm = CGContextGetCTM(c);
    	NSLog(@"%8g%8g%8g", ctm.a,  ctm.b,  0.0);
    	NSLog(@"%8g%8g%8g", ctm.c,  ctm.d,  0.0);
    	NSLog(@"%8g%8g%8g\n\n", ctm.tx, ctm.ty, 1.0);	//translate x, translate y
    
    Here is the CTM with the 20-pixel status bar visible at the top of the portrait-orientation screen (40-pixel for iPhone 4). Read the iPhone column first—the numbers are the smallest because the screen is only 320 × 480 pixels. On iPhone, iPhone 4, and iPad the origin is in the upper left corner and the Y axis points down. On the underlying Mac, the origin is in the lower left corner and the Y axis points up.
    iPhone iPhone 4 iPad
    before
    CGContextTranslate
           1       0       0
           0      -1       0
           0     460       1
    
           2       0       0
           0      -2       0
           0     920       1
    
           1       0       0
           0      -1       0
           0    1004       1
    
    after
    CGContextTranslate
           1       0       0
           0      -1       0
         160     230       1
    
           2       0       0
           0      -2       0
         320     460       1
    
           1       0       0
           0      -1       0
         384     502       1
    
    after
    CGContextConcatCTM
     53.3333       0       0
           0 53.3333       0
         160     230       1
    
     106.667       0       0
           0 106.667       0
         320     460       1
    
         128       0       0
           0     128       0
         384     502       1
    

  3. There’s no way to tell the difference between acceleration and gravity—that’s the whole point of Einstein’s General Theory of Relativity.

    Or is there? Filter out random noise with a low-pass filter, so that all that remains will be the tug of gravity. Keep a queue (actually, three queues in parallel) of the 10 most recent x, y, z values received from the accelerometer. One way to implement the queue is as an NSMutableArray, calling its methods addObject: and removeObjectAtIndex:. Each number stored in the NSMutableArray will have to be encased in an NSNumber object, since an NSMutableArray can only hold pointers to objects. It cannot hold numbers.

    An easier way to get the direction of gravity is with the gravity property of class CMDeviceMotion (if you have this class).