★ TouchArcade needs your help. Click here to support us on Patreon.

3D Tilt calibration

02-20-2009, 04:49 AM
#1
Joined: Jan 2009
Location: Christchurch, New Zealand
Posts: 515
3D Tilt calibration

Hi;

I'm working on my 3rd game for the iPhone, and am having some trouble getting the accelerometer calibration to work correctly.

What I mean by that is that I currently have controls working with the player holding the iPhone with the screen facing straight up, and reading the raw x + y accelerometer values and using them.

I would like to have the player be able to hold the iphone in any position, calibrate using a process in my game, and then the game treats that new position as if it was lying face up.

However, the 3d math are a bit beyond me up until now.

Are there any developers out there who have cracked this who can give me some help?

Shen
02-20-2009, 06:11 AM
#2
Joined: Dec 2008
Posts: 439
The way I do it, I ask the user to place the iphone on a flat table (it doesn't have to be... it's just any position the user wants to treat as the face up position)... then ask him to click a calibrate button... the following code is in my Settings viewcontroller...


Code:
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
	
	self.xcalib=acceleration.x;
	self.ycalib=acceleration.y;
	
}
so in the above method... self.xcalib and self.ycalib are constantly changing as you tilt the iphone... when the user clicks calibrate it runs this method

Code:
-(IBAction)calibrate {

       PongControlAppDelegate *appcontrol= [[UIApplication sharedApplication] delegate];
	
	appcontrol.viewController.xcalibration=self.xcalib;
	
	appcontrol.viewController.ycalibration=self.ycalib;

	self.xcalibrationvalue=self.xcalib;

        self.ycalibrationvalue=self.ycalib;

}
So the calibrate method captures the calibration values....

appcontrol.viewController is where my game actually runs and where I need to read the acceleration values... so I have a

Code:
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
	
	//
	//
}
method there also...

Now that you've captured the calibration values.... all you have to do is wherever you use acceleration.x or acceleration.y... you just replace those with (acceleration.x-self.xcalibration) and (acceleration.y-self.ycalibration)

02-20-2009, 12:35 PM
#3
Joined: Jan 2009
Location: Christchurch, New Zealand
Posts: 515
Thanks for that answer, but I am after something a bit different.

I want to get the user to choose a particular orientation, and then treat that position as if it was flat.

so right now the player must hold the iphone with the screen facing straight up, and move by tilting.

I would like the player to be able to recalibrate it so they could hold the phone with the screen facing the horizon, and that is treated as flat

Or they could recalibrate so they hold the phone at 45 degrees, and that is treated as flat.
02-20-2009, 12:48 PM
#4
Joined: Dec 2008
Posts: 439
Quote:
Originally Posted by shen View Post
Thanks for that answer, but I am after something a bit different.

I want to get the user to choose a particular orientation, and then treat that position as if it was flat.

so right now the player must hold the iphone with the screen facing straight up, and move by tilting.

I would like the player to be able to recalibrate it so they could hold the phone with the screen facing the horizon, and that is treated as flat

Or they could recalibrate so they hold the phone at 45 degrees, and that is treated as flat.
Hmmm... I think that's what the code I provided does... unless I'm misunderstanding what you need... in my game, I can hold the iphone in any position... press the calibrate button... and then the iphone will treat that as the flat position...
02-20-2009, 01:30 PM
#5
Joined: Jan 2009
Location: Christchurch, New Zealand
Posts: 515
And all you need to do is subtract the starting value from the calibration value?

From looking at the accelerometer output it seems like the values are sin wave based, so I thought you would need to do some more complex math to adjust for that.

Plus it you are holding the iphone with the screen facing the horizon, and the y accelerometer is 1 (or -1) tilting forward or backward will both change the y reading the same way won't they?

Shen
02-20-2009, 02:11 PM
#6
Joined: Dec 2008
Posts: 439
Quote:
Originally Posted by shen View Post
And all you need to do is subtract the starting value from the calibration value?

From looking at the accelerometer output it seems like the values are sin wave based, so I thought you would need to do some more complex math to adjust for that.
Yes, you're absolutely right. I was messing up. sorry about that.


Quote:
Plus it you are holding the iphone with the screen facing the horizon, and the y accelerometer is 1 (or -1) tilting forward or backward will both change the y reading the same way won't they?

Shen
Yes... so here I think you'd have to use the z value to figure out which way it is tilting...
02-20-2009, 02:59 PM
#7
Joined: Dec 2008
Posts: 439
Would this do it?

If we take the arcsin of the acceleration values... at the calibration position...

ie: asin(xcalibration), asin(ycalibration), asin(zcalibration)...

So the angles of rotation would be:

xangle = asin(currentxacceleration) - asin(xcalibration)

yangle = asin(currentyaccleration) - asin(ycalibration)

zangle = asin(currentzacceleration) - asin(zcalibration)

whereas without calibration it would have been:

xangle=asin(currentxacceleration)
yangle = asin(currrentyacceleration)
zangle = asin(currentzacceleration)
05-13-2009, 07:03 AM
#8
Joined: Oct 2008
Posts: 178
Quote:
Originally Posted by arkanigon View Post
Would this do it?

If we take the arcsin of the acceleration values... at the calibration position...

ie: asin(xcalibration), asin(ycalibration), asin(zcalibration)...

So the angles of rotation would be:

xangle = asin(currentxacceleration) - asin(xcalibration)

yangle = asin(currentyaccleration) - asin(ycalibration)

zangle = asin(currentzacceleration) - asin(zcalibration)

whereas without calibration it would have been:

xangle=asin(currentxacceleration)
yangle = asin(currrentyacceleration)
zangle = asin(currentzacceleration)
Just wondering if this worked for you?
05-14-2009, 08:46 PM
#9
The first thing you need to recognize is exactly what is going on...

- You might want a tilt vector and magnitude
- You might want two scalers an: x and y

The rest of this is the about two scalers:

In Armor Alley, I support 6 orientations of play.

If you want two scalers:
- You have 3 basic orientations: face up, face down (player on their back), vertical.
- You have 2 variants of each: home button on the left and home button on the right.

Once you realize you have these variants, then you realize that anything that is off of normal is increasingly less accurate.
- In all orientations, tilting the top or bottom away from you is one value (y)
- In horizontal orientations, tilting the left or right away is the other value (x)
- In vertical orientations, tilting the left or right side down is the other value again (x)

As you move between horizontal and vertical orientations you have two conflicting metaphors for measuring orientation.

Armor Alley chooses the closest orientation for the first second of play. After that if the player moves the device with in a few degrees of normal for another orientation, it sounds a warning beep and automatically calibrates to the new orientation.

The system is transparent and just works. Players don't even notice when they have changed orientations due to the excitement of game play.

Manual calibration is possible, but I haven't received any feed back suggesting it is necessary.

-Arthur
05-17-2009, 09:56 PM
#10
Joined: Dec 2008
Posts: 439
Quote:
Originally Posted by spacerage View Post
Just wondering if this worked for you?
Well, I realize now that you can only do it with 2 axes... you can't measure the angle about the vertical axis (the axis along which gravity acts)...

In my game you hold the iphone face up... I measure the tilt using this method I described with x and y (there might be minus signs or something... but basically this method worked for me) ...