esp32とMPU6050を繋いで立方体を動かす

 esp32とMPU6050を繋いでPCに仮想シリアルでデータを渡すCのプログラムとPC側では3軸の加速度データに応じて立方体を動かすPythonのプログラムを作ってください

PythonはPyOpenGLとpygameのライブラリを使ってください


はい、承知いたしました。ESP32とMPU6050で加速度データを取得し、PC上のPythonプログラムで立方体を動かすサンプルプログラムを作成します。

ESP32とMPU6050は、I2C通信で以下のように接続してください。

  • ESP32 SCL (GPIO 22) <-> MPU6050 SCL

  • ESP32 SDA (GPIO 21) <-> MPU6050 SDA

  • ESP32 3V3 <-> MPU6050 VCC

  • ESP32 GND <-> MPU6050 GND


1. ESP32側のプログラム (C/C++)


まず、Arduino IDEにAdafruitのMPU6050ライブラリをインストールする必要があります。

ツール > ライブラリを管理 から Adafruit MPU6050 を検索してインストールしてください。依存ライブラリである Adafruit Unified Sensor と Adafruit BusIO も一緒にインストールされます。

以下のコードをESP32に書き込んでください。MPU6050から取得したX, Y, Z軸の加速度データを x,y,z\n の形式でシリアルポートに出力します。


C++



#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>

// MPU6050オブジェクトを作成
Adafruit_MPU6050 mpu;

void setup() {
  // シリアル通信を開始 (ボーレートはPython側と合わせる)
  Serial.begin(115200);
  while (!Serial) {
    delay(10); // シリアルポートの接続を待つ
  }

  // MPU6050の初期化
  if (!mpu.begin()) {
    Serial.println("Failed to find MPU6050 chip");
    while (1) {
      delay(10);
    }
  }
  Serial.println("MPU6050 Found!");

  // センサーのレンジ設定
  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
  mpu.setGyroRange(MPU6050_RANGE_500_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);

  delay(100);
}

void loop() {
  // センサーイベント(加速度、ジャイロ、温度)を取得するための変数
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  // 3軸の加速度データをカンマ区切りでシリアルポートに出力
  // フォーマット: "x,y,z\n"
  Serial.printf("%.2f,%.2f,%.2f\n", a.acceleration.x, a.acceleration.y, a.acceleration.z);

  // 50ms待機 (送信レート: 約20Hz)
  delay(50);
}


2. PC側のプログラム (Python)


PC側では、まず必要なライブラリをインストールします。


Bash



pip install pyserial pygame PyOpenGL PyOpenGL_accelerate

以下のPythonコードを実行すると、ウィンドウが開き、ESP32から送られてくる加速度データに応じて立方体が回転します。

**注意:**コード内の SERIAL_PORT は、お使いの環境に合わせて変更してください。Windowsなら 'COM3' や 'COM4'、macOSやLinuxなら '/dev/tty.usbserial-XXXX' のような名前になります。Arduino IDEのシリアルモニタで確認できるポート名と同じものを指定してください。


Python



import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
import serial
import time

# --- 設定 ---
# ESP32が接続されているシリアルポート名を指定
SERIAL_PORT = 'COM3'  # ★★★★★自分の環境に合わせて変更★★★★★
BAUD_RATE = 115200    # ESP32のプログラムと合わせる
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600
# --- 設定ここまで ---


def draw_cube():
    """立方体を描画する関数"""
    vertices = (
        (1, -1, -1), (1, 1, -1), (-1, 1, -1), (-1, -1, -1),
        (1, -1, 1), (1, 1, 1), (-1, -1, 1), (-1, 1, 1)
    )
    edges = (
        (0, 1), (0, 3), (0, 4), (2, 1), (2, 3), (2, 7),
        (6, 3), (6, 4), (6, 7), (5, 1), (5, 4), (5, 7)
    )
    surfaces = (
        (0, 1, 2, 3), (3, 2, 7, 6), (6, 7, 5, 4),
        (4, 5, 1, 0), (1, 5, 7, 2), (4, 0, 3, 6)
    )
    colors = (
        (1, 0, 0), (0, 1, 0), (0, 0, 1),
        (1, 1, 0), (0, 1, 1), (1, 0, 1)
    )

    glBegin(GL_QUADS)
    for i, surface in enumerate(surfaces):
        glColor3fv(colors[i])
        for vertex_index in surface:
            glVertex3fv(vertices[vertex_index])
    glEnd()

    # 立方体のエッジを黒で描画
    glColor3fv((0, 0, 0))
    glBegin(GL_LINES)
    for edge in edges:
        for vertex_index in edge:
            glVertex3fv(vertices[vertex_index])
    glEnd()

def main():
    # PygameとOpenGLの初期化
    pygame.init()
    display = (WINDOW_WIDTH, WINDOW_HEIGHT)
    pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
    pygame.display.set_caption("ESP32 MPU6050 Cube Demo")

    # OpenGLの射影設定
    gluPerspective(45, (display[0] / display[1]), 0.1, 50.0)
    glTranslatef(0.0, 0.0, -10) # カメラを少し後ろに下げる
    glEnable(GL_DEPTH_TEST) # Zバッファを有効にする

    # シリアルポートの初期化
    try:
        ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
        time.sleep(2) # 接続が安定するまで待機
        print(f"Connected to {SERIAL_PORT}")
    except serial.SerialException as e:
        print(f"Error: Could not open port {SERIAL_PORT}. {e}")
        return

    # メインループ
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                ser.close()
                pygame.quit()
                quit()

        # シリアルデータの読み込みと解析
        accel_x, accel_y = 0, 0
        try:
            if ser.in_waiting > 0:
                line = ser.readline().decode('utf-8').strip()
                data = line.split(',')
                if len(data) == 3:
                    # Y軸の加速度でX軸周りの回転、X軸の加速度でY軸周りの回転を行う
                    accel_x = float(data[0])
                    accel_y = float(data[1])
                    # z_val = float(data[2]) # Z軸データは今回は使用しない
        except (ValueError, UnicodeDecodeError):
            # 不正なデータは無視
            continue

        # OpenGLの描画処理
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
       
        glPushMatrix() # 現在の行列を保存

        # 加速度データに基づいて回転
        # 傾きをより大きく反映させるために係数(例: 5)をかける
        # MPU6050のX加速度でY軸周りに回転
        glRotatef(accel_x * 5, 0, 1, 0)
        # MPU6050のY加速度でX軸周りに回転
        glRotatef(accel_y * 5, 1, 0, 0)

        draw_cube() # 立方体を描画
       
        glPopMatrix() # 行列を元に戻す

        pygame.display.flip() # 画面を更新
        pygame.time.wait(10) # 少し待機

if __name__ == '__main__':
    main()


実行方法


  1. 上記のC++コードをESP32に書き込みます。

  2. ESP32をPCに接続したままにします。

  3. 上記のPythonコードのSERIAL_PORTを正しいポート名に修正します。

  4. Pythonスクリプトを実行します (python your_script_name.py)。

  5. ウィンドウが表示され、ESP32/MPU6050を傾けると、その動きに応じて立方体が回転します。

コメント