Android Steering Wheel Project (Android Application folder)
The application will read orientation by using the accelerator sensor and magnetic field sensor.
Pitch:
- Controls Steering (POV control on xbox controller)
- Float, range = (-90, 90), in degrees
- Three modes are:
- Rest => range(-2, 2)
- Turn Left => range(2, 90)
- Turn Right => range(-90, -2)
Roll:
- Controls Acceleration (LT, RT on xbox controller)
- Float, range = (-90, 90), in degrees
- Three modes are:
- Rest => range(-40, -30)
- Forward => range(-90, -40)
- Backward => range(-30, 90)
Please refer to the values showed on app and adjust your postion
The application will either try to connect a service with unique UUID via Bluetooth, or connect to local network on PC by IP address input.
The connection starts by a validation process, it sends 123456
to service, and expect a returned value of 654321
. After that, a connection will be established for later communication.
Data Pack (each):
10086
as the data pack seperator (4 ints per pack).- motion button indicator (bool)
- motion status indicator (int)
- motion value (float)
Motion Button:
false
=> contains either pitch or roll data, need to read last float numbertrue
=> is a button, can safely ignore last float number
Motion Status:
- If not motion button:
0
=> float number is pitch value1
=> float number is roll value
- If motion button:
0
=> ButtonX
1
=> ButtonY
2
=> ButtonA
3
=> ButtonB
4
=> ButtonLB
5
=> ButtonRB
6
=> ButtonUP
7
=> ButtonDOWN
8
=> ButtonRIGHT
9
=> ButtonLEFT
10
=> ButtonBACK
11
=> ButtonSTART
Here's a world coordinate system I stole from learnopengl:
In this app, the new angles / orientations are computed by a combination of Accelerometer and Magnetic Field, which are in absolute XYZ coordinate as shown in the image.
Now imagine this situation:
motionAngleDemo.mp4
We use the same world coordinate as previous image.
- User starts by holding phone vertically straight, landscape mode.
- User first rotates phone forward (around X) to accelerate car. Then +Z follows the rotation to +Z' (keep vertical to the screen).
- Then user rotate around +Z' to steer car. The angle around +Z' is the expected angle.
- However, the motion sensor only captures the angle in absolute world space.
If use this value from motion sensor directly, there'll be two bugs:
- The more the user accelerate car (rotate forward), the smaller the steering angle becomes, which is against instinct of how steering wheel works.
- Once user steers by rotating the phone, acceleration angle will change drastically.
In my opinion, the steering angle should always be the angle on the plane where the wheel resides, and it should not affect acceleration angle.
To restore true angles, here's the formula I use:
let x = acceleration angle (from sensor)
let y = steering angle (from sensor)
let m = true acceleration angle
let n = true steering angle
m = arcsin(sin(x) * cos(y))
n = arcsin(sin(y) / cos(m))
The formula comes from some intense 3D imagination process in head 🤣 as well as some try-and-guess. It may not be accurate, but it works.
If you know how to compute the real formula or if this is correct, please let me know!