Full GT Acceleration Computation (lines 153-207)
Implemented the complete formula: a_base = R_br * f_sensor + g_base - α×r - ω×(ω×r)
Components:
Uses exact offset from go2.xml: r = [-0.02557, 0, 0.04232] m
You should now see:
IMU and GT curves that closely match (small error)
Z-axis showing ~9.81 m/s² (not 0) when robot is stationary
그림처럼 z가 9.78정도를 가진다. 로봇의 바디가 기울어져있으므로 R*accelermeter 의 영향으로x와 y도 값을 가진다.

imu_acc = np.array(lowstate.imu_state.accelerometer) # Specific force!
gt_acc = kinematic_acc - gravity_acc # = 0 - (-9.81) = +9.81
Z = 9.788 m/s²는 정지 상태에서 정상적인 specific force 값
이것은 바닥의 수직항력을 나타냄
IMU accelerometer는 항상 specific force (a - g)를 측정
자유낙하 중일 때만 specific force = 0 (무중력 상태)
Specific force는 "중력을 느끼지 않는 가속도"가 아니라 "중력을 제외한 힘에 의한 가속도"입니다! 정지해 있을 때 오히려 +g만큼 큰
값이 나오는 것이 정상입니다. 🎯
데이터 변환 관계
┌─────────────────┐
│ Velocity (v) │ ← ROS2 topic: /go2/imu/base_velocity
└────────┬────────┘
│ differentiate
↓
┌─────────────────┐
│ Acceleration(a) │ = f + g
└────────┬────────┘
│ subtract gravity
↓
┌─────────────────┐
│ Specific Force │ = a - g (IMU measures this!)
│ (f) │
└─────────────────┘
a_base = R_br * f_sensor + g_base - α×r - ω×(ω×r)
이것을 specific force로 변환하면:
f_base = a_base - g_base
= R_br * f_sensor - α×r - ω×(ω×r)
문제 1: R_br 행렬이 없음
결론적으로 순수한 Linear Acceleration을 얻을 수 있다.
그 방법은 를 통해 할 수 있다.
Linear Acceleration은 specific_force + gravity로 계산되는 값
# imu_plotter_ros2.py:108
linear_specific_force = np.array([msg.vector.x, msg.vector.y, msg.vector.z])
- /go2/imu/accelerometer 토픽에서 받음
- Specific Force (f): IMU가 측정하는 비력 = a - g
# gravity_callback:122
self.latest_gravity = np.array([msg.vector.x, msg.vector.y, msg.vector.z])
- /go2/imu/projected_gravity 토픽에서 받음
- Normalized direction: 크기가 1인 단위 벡터 (body frame)
Projected Gravity 계산 과정
개념
"Projected"의 의미: World frame의 gravity를 Body frame으로 투영(회전 변환)한 것
World frame: gravity = [0, 0, -9.81] (항상 아래로)
Body frame: gravity = ? (로봇 자세에 따라 변함)
Step 1: Quaternion 받기
quat = np.array(lowstate.imu_state.quaternion) # [w, x, y, z]
IMU에서 제공하는 현재 자세 (orientation)
Step 2: Quaternion → Rotation Matrix
w, x, y, z = quat
# World-to-Body rotation matrix (transpose of body-to-world)
R_T = np.array([
[1-2*(y*y+z*z), 2*(x*y+w*z), 2*(x*z-w*y)],
[2*(x*y-w*z), 1-2*(x*x+z*z), 2*(y*z+w*x)],
[2*(x*z+w*y), 2*(y*z-w*x), 1-2*(x*x+y*y)]
])
Step 4: Body frame으로 변환
# Transform to body frame
gravity_body = R_T @ gravity_world_normalized
# Ensure normalized
gravity_body = gravity_body / np.linalg.norm(gravity_body)
# imu_callback:112-115
if self.latest_gravity is not None:
gravity_vector = self.latest_gravity * 9.81 # m/s²로 변환
self.latest_linear_acceleration = linear_specific_force + gravity_vector
공식:
a = f + g
