소스 뷰어
import smbus, time
from math import degrees
import matplotlib.pyplot as plt
import matplotlib.animation as animation

bus = smbus.SMBus(1)  # MPU-6050 초기 설정
address = 0x68        # MPU-6050 I2C 주소

# 레지스터 정의
PWR_MGMT_1 = 0x6B
ACCEL_XOUT_H = 0x3B
ACCEL_YOUT_H = 0x3D
ACCEL_ZOUT_H = 0x3F
GYRO_XOUT_H = 0x43
GYRO_YOUT_H = 0x45
GYRO_ZOUT_H = 0x47

# 센서 활성화
bus.write_byte_data(address, PWR_MGMT_1, 0)

# 데이터 읽기 함수
def read_word(reg):
    high = bus.read_byte_data(address, reg)
    low = bus.read_byte_data(address, reg+1)
    value = (high << 8) + low
    if value >= 0x8000:
        value = -((65535 - value) + 1)
    pass

    return value
pass

def read_accel():
    x = read_word(ACCEL_XOUT_H) / 16384.0
    y = read_word(ACCEL_YOUT_H) / 16384.0
    z = read_word(ACCEL_ZOUT_H) / 16384.0

    return (x, y, z)
pass

def read_gyro():
    x = read_word(GYRO_XOUT_H) / 131.0
    y = read_word(GYRO_YOUT_H) / 131.0
    z = read_word(GYRO_ZOUT_H) / 131.0

    return (x, y, z)
pass

# 각도 계산 함수
def calculate_angles(gyro, dt, last_angles):
    
    roll_x  = last_angles[0] + gyro[0] * dt
    pitch_y = last_angles[1] + gyro[1] * dt
    yaw_z   = last_angles[2] + gyro[2] * dt

    return (pitch_y, roll_x, yaw_z)
pass

# 위치 계산 함수 (이중 적분)
def calculate_position(accel, velocity, position, dt):
    ax, ay, az = accel
    vx, vy, vz = velocity
    px, py, pz = position

    # 속도 계산 (가속도의 1차 적분)
    vx += ax * dt
    vy += ay * dt
    vz += az * dt

    # 위치 계산 (속도의 1차 적분)
    px += vx * dt
    py += vy * dt
    pz += vz * dt

    return (vx, vy, vz), (px, py, pz)
pass

# 그래프 초기화
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 6))
pitch_data, roll_data, yaw_data = [], [], []
x_data, y_data, z_data = [], [], []

time_data = []

last_angles = (0.0, 0.0, 0.0)
angle_data = []

last_velocity = (0.0, 0.0, 0.0)
last_position = (0.0, 0.0, 0.0)
xyz_data = []

last_time = time.time()

# 위치 데이터
plot_x, = ax1.plot(time_data, x_data, "gp-", label="X (9.8 m)" )
plot_y, = ax1.plot(time_data, y_data, "r*--", label="Y (9.8 m)" )
plot_z, = ax1.plot(time_data, z_data, "bs:", label="Z (9.8 m)" )

ax1.set_ylabel("Position (9.8 m)")
ax1.set_xlabel("Time (s)")
ax1.legend(loc="upper left")
ax1.set_title("Estimated Position - X, Y, Z (Without Calibration)")

# Roll, Pitch, Yaw 데이터
plot_pitch, = ax2.plot(time_data, pitch_data, "gp-", label="Pitch: Y (°)" )
plot_roll, = ax2.plot(time_data, roll_data, "r*--", label="Roll : X (°)" )
plot_yaw, = ax2.plot(time_data, yaw_data, "bs:", label="Yaw  : Z (°)" )

ax2.set_ylabel("Angle (°)")
ax2.set_xlabel("Time (s)")
ax2.legend(loc="upper left")
ax2.set_title("IMU Orientation - Pitch, Roll, Yaw (Without Calibration)") 

plots = [ plot_pitch, plot_roll, plot_yaw, plot_x, plot_y, plot_z ]

plt.tight_layout()

start_time = None

# 실시간 업데이트 함수
def update( frame ):
    global last_angles, last_velocity, last_position, last_time, start_time

    current_time = time.time()
    dt = current_time - last_time
    last_time = current_time

    if start_time is None : start_time = current_time

    elapsed = current_time - start_time

    accel = read_accel()
    gyro = read_gyro()
    
    # 자세 계산
    (pitch_y, roll_x, yaw_z) = calculate_angles(gyro, dt, last_angles)
    last_angles = (pitch_y, roll_x, yaw_z)

    # 위치 계산
    last_velocity, last_position = calculate_position(accel, last_velocity, last_position, dt)
    x, y, z = last_position
    velocity = last_velocity

    print()
    print( "-"*40 )
    print( f"[{frame:4d}] elapsed  = {elapsed:.1f} (secs)" )
    print( f"[{frame:4d}] gyro     = {degrees(gyro[0]):.3f}, {degrees(gyro[1]):.3f}, {degrees(gyro[2]):.3f} (°/s)" )
    print( f"[{frame:4d}] angle    = {degrees(roll_x):.3f}, {degrees(pitch_y):.3f}, {degrees(yaw_z):.3f} (°)" )
    
    print( f"[{frame:4d}] accel    = {accel[0]:.3f}, {accel[1]:.3f}, {accel[2]:.3f} (g)" )
    print( f"[{frame:4d}] velocity = {velocity[0]:.3f}, {velocity[1]:.3f}, {velocity[2]:.3f} (9.8 m/s)" )
    print( f"[{frame:4d}] position = {x:.3f}, {y:.3f}, {z:.3f} (9.8 m)" )
    print( "-"*40 )

    if len( time_data ) > 60 :
        time_data.pop( 0 )

        pitch_data.pop( 0 )
        roll_data.pop( 0 )
        yaw_data.pop( 0 )

        x_data.pop( 0 )
        y_data.pop( 0 )
        z_data.pop( 0 )

        del angle_data[:3]
        del xyz_data[:3]
    pass

    # 데이터 추가
    time_data.append( elapsed )

    pitch_data.append( degrees(pitch_y) )
    roll_data.append( degrees(roll_x) )
    yaw_data.append( degrees(yaw_z) )

    x_data.append( x )
    y_data.append( y )
    z_data.append( z )

    plot_pitch.set_data( time_data, pitch_data )
    plot_roll.set_data( time_data, roll_data )
    plot_yaw.set_data( time_data, yaw_data )

    plot_x.set_data( time_data, x_data )
    plot_y.set_data( time_data, y_data )
    plot_z.set_data( time_data, z_data )

    angle_data.append( degrees(pitch_y) )
    angle_data.append( degrees(roll_x) )
    angle_data.append( degrees(yaw_z) )

    xyz_data.append( x )
    xyz_data.append( y )
    xyz_data.append( z ) 

    ax1.set_xlim( min( time_data ), max( 1, max( time_data) ) ) 
    ax2.set_xlim( min( time_data ), max( 1, max( time_data) ) )

    ax1.set_ylim( min( 0, min( xyz_data )*1.1), max( 0, max( xyz_data )*1.1 ) )
    ax2.set_ylim( min( 0, min( angle_data )*1.1), max( 0, max( angle_data )*1.1 ) )
    
    return plots
pass

# 애니메이션 실행
ani = animation.FuncAnimation(fig, update, interval=100, cache_frame_data=0 )

plt.show()