This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
tutorials:accelerometer_setup_and_easy_fine-tuning [2011/08/23 05:05] – menehune17 | tutorials:accelerometer_setup_and_easy_fine-tuning [2013/03/05 10:19] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ==== Introduction ==== | ||
+ | Using the accelerometer in applications has become an intuitive and popular way of allowing user input, especially for gaming applications. | ||
+ | |||
+ | * [[accelerometer_setup_and_easy_fine-tuning# | ||
+ | * [[accelerometer_setup_and_easy_fine-tuning# | ||
+ | * [[accelerometer_setup_and_easy_fine-tuning# | ||
+ | * [[accelerometer_setup_and_easy_fine-tuning# | ||
+ | |||
+ | Objective-C proficiency is assumed. | ||
+ | |||
+ | === Setup and Retrieval Code === | ||
+ | |||
+ | == Setup Code == | ||
+ | |||
+ | Place the following code in the initialization method for whichever class will handle accelerometer input (usually Game). | ||
+ | |||
+ | <code objc> | ||
+ | UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer]; | ||
+ | accelerometer.updateInterval = 1.0/60.0; | ||
+ | accelerometer.delegate = self; | ||
+ | </ | ||
+ | |||
+ | This code handles the initialization of the accelerometer and sets the retrieval rate (60 times/sec in second line of code above). | ||
+ | |||
+ | The third line tells the class that it is a delegate for the accelerometer. | ||
+ | |||
+ | <code objc> | ||
+ | @interface MyClass : MySuperClass < | ||
+ | . | ||
+ | . | ||
+ | . | ||
+ | @end | ||
+ | </ | ||
+ | |||
+ | == Retrieval Code == | ||
+ | |||
+ | In order to retrieve data (X, Y, and Z axis measures of force, rated in Gs) from the accelerometer, | ||
+ | <code objc> | ||
+ | - (void) accelerometer: | ||
+ | { | ||
+ | float accelX = acceleration.x; | ||
+ | float accelY = acceleration.y; | ||
+ | float accelZ = acceleration.z; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | === Fine-tuning Accelerometer Data === | ||
+ | |||
+ | The above code works for retrieving raw data from the accelerometer. | ||
+ | |||
+ | == Class-wide Access to Accelerometer Data == | ||
+ | One improvement over the above code would be to allow acceleration data to be accessed by the entire handling class, not just from within the accelerometer: | ||
+ | <code objc> | ||
+ | @property (nonatomic) float accel; | ||
+ | </ | ||
+ | |||
+ | and we will set its value in the accelerometer: | ||
+ | |||
+ | <code objc> | ||
+ | - (void) accelerometer: | ||
+ | { | ||
+ | accel = acceleration.y; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | == Amplify the Acceleration Data == | ||
+ | |||
+ | Since acceleration is rated in Gs (one G is 9.88 m/s^2), the raw data may not get to be much higher than 3.0 or 4.0 (although this varies with use). Consequently, | ||
+ | |||
+ | <code objc> | ||
+ | #define ACCEL_FACTOR 100 // this value can vary depending on the application | ||
+ | </ | ||
+ | |||
+ | and use it in the accelerometer: | ||
+ | <code objc> | ||
+ | - (void) accelerometer: | ||
+ | { | ||
+ | accel = ACCEL_FACTOR * acceleration.y; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | == Filter the Acceleration Data == | ||
+ | |||
+ | The final stage of fine-tuning the accelerometer data is to perform what is called low-pass filtering. | ||
+ | |||
+ | A simple example of a low-pass filter is a moving averager, and is explained further in the [[accelerometer_setup_and_easy_fine-tuning# | ||
+ | <code objc> | ||
+ | #define NUM_FILTER_POINTS 10 // number of recent points to use in average | ||
+ | |||
+ | . | ||
+ | . | ||
+ | . | ||
+ | |||
+ | @property (nonatomic, retain) NSMutableArray rawAccel; | ||
+ | </ | ||
+ | Experimenting with NUM_FILTER_POINTS can cause varying effects, including a lag effect, so have fun toying with this! Setting it to a value of 1 will result in no filtering (because the average over 1 value is the value itself), which can be helpful for comparing results. | ||
+ | |||
+ | To initialize the rawAccel array, the following code must be placed in the handling class' | ||
+ | <code objc> | ||
+ | self.rawAccel = [NSMutableArray arrayWithCapacity: | ||
+ | for (int i = 0; i < NUM_FILTER_POINTS; | ||
+ | { | ||
+ | [rawAccel addObject: | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Then, the accelerometer: | ||
+ | <code objc> | ||
+ | // accelerometer handler | ||
+ | // implement a low-pass filter to extract stable acceleration value | ||
+ | |||
+ | - (void) accelerometer: | ||
+ | { | ||
+ | // insert newest value | ||
+ | // will push current values over by 1 spot, extending length by 1 | ||
+ | | ||
+ | [rawAccel insertObject: | ||
+ | | ||
+ | | ||
+ | // remove oldest value, returning length to NUM_FILTER_POINTS | ||
+ | | ||
+ | [rawAccel removeObjectAtIndex: | ||
+ | | ||
+ | | ||
+ | // perform averaging | ||
+ | | ||
+ | accel = 0.0; | ||
+ | for (NSNumber *raw in rawAccel) | ||
+ | { | ||
+ | accel += [raw floatValue]; | ||
+ | } | ||
+ | accel *= ACCEL_FACTOR / NUM_FILTER_POINTS; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | === Movement Using Accelerometer Data: An Example === | ||
+ | |||
+ | For realistic movement, it is helpful to use the following code in an SPEnterFrameEvent callback: | ||
+ | |||
+ | <code objc> | ||
+ | - (void) onEnterFrameEvent: | ||
+ | { | ||
+ | float dt = event.passedTime; | ||
+ | |||
+ | | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | The above code will cause the object to move left/right with increasing or decreasing speed (a.k.a the physics definition of acceleration). | ||
+ | |||
+ | Note that because dt is much less than 1.0, dt * dt will be even smaller. | ||
+ | |||
+ | Hopefully, this tutorial will get Sparrow users started on using the accelerometer in applications without many prerequisites. | ||
+ | |||
+ | === Appendix: Mathematics Behind Fine-tuning === | ||
+ | |||
+ | The running averager low-pass filter described in this tutorial works by " | ||
+ | < | ||
+ | y[n] = h[0] * x[n] + h[1] * x[n-1] + ... + h[M] * x[n-M] | ||
+ | </ | ||
+ | |||
+ | where the values of the array " | ||
+ | |||
+ | In this tutorial, the filter we used was characterized by the h array: h[n] = ACCEL_FACTOR / NUM_FILTER_POINTS, | ||
+ | < | ||
+ | accel = (ACCEL_FACTOR / NUM_FILTER_POINTS) * rawAccel[0] + (ACCEL_FACTOR / NUM_FILTER_POINTS) * rawAccel[1] + ... + (ACCEL_FACTOR / NUM_FILTER_POINTS) * rawAccel[NUM_FILTER_POINTS-1] | ||
+ | |||
+ | => accel = (ACCEL_FACTOR / NUM_FILTER_POINTS) * sum{rawAccel} | ||
+ | </ | ||
+ | |||
+ | It should now be apparent why our filter is an averager: summing data and dividing by the number of data points results in an average, exactly what is described by the filter above, with the exception of the amplification by ACCEL_FACTOR. |