手机至汽车坐标系的加速度转换及校准后有效加速度求解问询
Got it, let's walk through how to solve this acceleration transformation and gravity removal problem—perfect for that taped-down phone scenario. Here's a practical, step-by-step approach tailored to your needs:
First, let's clarify the relationship between the sensor data and what we actually care about:
- When you hit "calibrate" (car is stationary), the phone's accelerometer only measures gravity. So
calibrationAccis exactly the gravity vector in the phone's coordinate system (let's call thisG_phone). - When the car moves, the sensor output
currentAccis the sum of two things:- The car's actual motion acceleration (our target,
A_phonein the phone's coordinates) - The fixed gravity vector
G_phone(since the phone is taped to the car, this vector never shifts relative to the phone)
- The car's actual motion acceleration (our target,
So right off the bat, we can isolate the raw motion acceleration in the phone's system with this simple subtraction:
double[] A_phone = { currentAcc[0] - calibrationAcc[0], currentAcc[1] - calibrationAcc[1], currentAcc[2] - calibrationAcc[2] };
But this is still in the phone's arbitrary orientation. Next, we need to map this to the car's natural coordinate system.
To convert A_phone to the car's system (A_car), we need a rotation matrix R that translates vectors from the phone's axes to the car's axes. Let's build this using only the calibration data (and a small reasonable assumption for rough accuracy).
First, Define the Car's Axes
Let's standardize the car's coordinate system for consistency:
z_car: Vertical axis (points upward, directly opposite gravity)x_car: Forward axis (points the direction the car drives forward)y_car: Lateral axis (points left, perpendicular to forward/vertical)
Step 2.1: Get the Car's Vertical Axis from Calibration
During calibration, gravity in the car's system points straight down (G_car = [0, 0, -9.81]). We know G_phone = calibrationAcc, so the unit vector for z_car (upward) in the phone's system is:
// Calculate the magnitude of the calibration gravity vector double G_magnitude = Math.sqrt( calibrationAcc[0]*calibrationAcc[0] + calibrationAcc[1]*calibrationAcc[1] + calibrationAcc[2]*calibrationAcc[2] ); // z_car points opposite to gravity, so invert the calibration vector and normalize double[] z_car_phone = { -calibrationAcc[0]/G_magnitude, -calibrationAcc[1]/G_magnitude, -calibrationAcc[2]/G_magnitude };
Step 2.2: Estimate the Car's Forward Axis
We don't have direct forward-direction data from calibration alone, but for a rough solution, we can make a quick assumption:
- If you know how you taped the phone (e.g., screen facing forward), just set
x_carto match the phone's forward axis (like the phone's x-axis). - If you don't know, pick an initial guess (like the phone's x-axis) and orthogonalize it to
z_car_phoneto ensure it's horizontal:
// Start with a guess (phone's x-axis here) double[] x_car_initial = {1, 0, 0}; // Make sure it's perpendicular to the vertical axis double dot_product = x_car_initial[0]*z_car_phone[0] + x_car_initial[1]*z_car_phone[1] + x_car_initial[2]*z_car_phone[2]; double[] x_car_phone = { x_car_initial[0] - dot_product*z_car_phone[0], x_car_initial[1] - dot_product*z_car_phone[1], x_car_initial[2] - dot_product*z_car_phone[2] }; // Normalize to a unit vector double x_magnitude = Math.sqrt( x_car_phone[0]*x_car_phone[0] + x_car_phone[1]*x_car_phone[1] + x_car_phone[2]*x_car_phone[2] ); x_car_phone[0] /= x_magnitude; x_car_phone[1] /= x_magnitude; x_car_phone[2] /= x_magnitude;
Pro tip: For better accuracy, you can add a quick "calibration drive" step—accelerate forward once, then set x_car_phone to match the direction of A_phone during that acceleration.
Step 2.3: Calculate the Lateral Axis
The y_car axis is the cross product of z_car_phone and x_car_phone (this keeps our coordinate system right-handed):
double[] y_car_phone = { z_car_phone[1]*x_car_phone[2] - z_car_phone[2]*x_car_phone[1], z_car_phone[2]*x_car_phone[0] - z_car_phone[0]*x_car_phone[2], z_car_phone[0]*x_car_phone[1] - z_car_phone[1]*x_car_phone[0] };
Step 2.4: Assemble the Rotation Matrix
The rotation matrix R (3x3) has each car axis unit vector as a row—this lets us multiply A_phone by R to get A_car:
double[][] R = { {x_car_phone[0], x_car_phone[1], x_car_phone[2]}, {y_car_phone[0], y_car_phone[1], y_car_phone[2]}, {z_car_phone[0], z_car_phone[1], z_car_phone[2]} };
Note: You only need to compute this matrix once after calibration—since the phone is fixed, it won't change.
Multiply the raw phone-space motion acceleration A_phone by R to get the car-space effective acceleration:
double[] A_car = { R[0][0]*A_phone[0] + R[0][1]*A_phone[1] + R[0][2]*A_phone[2], R[1][0]*A_phone[0] + R[1][1]*A_phone[1] + R[1][2]*A_phone[2], R[2][0]*A_phone[0] + R[2][1]*A_phone[1] + R[2][2]*A_phone[2] };
A_car[0]: Rough forward/backward acceleration (what you feel when hitting the gas/brakes)A_car[1]: Rough left/right lateral acceleration (what you feel when turning)A_car[2]: Vertical acceleration (small unless going over bumps)
- If your forward/lateral values seem flipped or reversed, just swap the initial guess for
x_car_initial(e.g., use the phone's y-axis instead) or invert the sign ofx_car_phone/y_car_phone. - Since this is a rough solution, small errors from sensor noise or imperfect calibration are expected—you can add a low-pass filter to
A_carif you want smoother readings.
内容的提问来源于stack exchange,提问作者Michał

