【ゆっくり】ArduinoでPID制御を体験しよう!【電子工作】

Поділитися
Вставка
  • Опубліковано 18 лис 2024

КОМЕНТАРІ • 1

  • @Kasanaru-Neko
    @Kasanaru-Neko  2 місяці тому +1

    以下最終的なプログラムとなっています。
    動画内で触れるのを忘れてましたがPythonのプログラムも後ろにつけておきます。Pythonに関してはコピペしただけなので解説は難しいかも…
    const int x7 = A1; // センサー入力
    const int x6 = 9; // PWM出力
    float x1, x2, x3, x3_old, x4, x5, x8, x9;
    float r, t, dt;
    float Kp, Ki, Kd;
    unsigned long previousMicros = 0;
    const unsigned long interval = 3000; // 制御周期3ms
    void setup() {
    Serial.begin(9600);
    pinMode(x7, INPUT);
    pinMode(x6, OUTPUT);
    t = x3_old = x4 = x9 = 0; // 初期化
    r = 2.5; // 目標値
    Kp = 1.0; // 比例ゲイン
    Ki = 0.0; // 積分ゲイン
    Kd = 0.0; // 微分ゲイン
    dt = 0.003; // 制御周期
    // スタート信号を待つ
    while (Serial.available() == 0) {
    // 何もせず待機
    }
    // スタート信号を受信
    if (Serial.read() == 'S') {
    Serial.println("Start received");
    }
    }
    void loop() {
    unsigned long currentMicros = micros();
    // 3ミリ秒ごとに処理を実行
    if (currentMicros - previousMicros >= interval) {
    previousMicros = currentMicros;
    x1 = r;
    x2 = x1 - x9;
    x3 = x2 * 100.0 * (255.0 / 500.0); // x2のままでは小さすぎる
    x4 = Kp * x3 + Ki * integ(x3,x3_old,x4,dt) + Kd * diff(x3,x3_old,dt); // PI制御
    x3_old = x3;
    x5 = limit(x4, 0, 255);
    analogWrite(x6, x5); // 制御入力
    // x6 → RC回路 → x7
    x8 = analogRead(x7); // センサー
    x9 = x8 * (5.0 / 1023.0);
    t += dt;
    Serial.print(t * 1000); // tをミリ秒に変換して出力
    Serial.print(",");
    Serial.print(x8);
    Serial.print(",");
    Serial.print(x4);
    Serial.print(",");
    Serial.println(x5);
    }
    }
    float limit(float x, float min, float max) {
    if (x < min) return min;
    if (x > max) return max;
    return x;
    }
    float integ(float y_in, float y_old, float S_old, float dt) {
    float S_out = S_old + (y_in + y_old) * dt / 2.0;
    return S_out;
    }
    float diff(float y_in, float y_old, float dt){
    float Diff = (y_in - y_old) / dt;
    return Diff;
    }
    ----------------------------------------------------------------------------------------------------------------------------------------------
    #ここから先パイソン
    import serial
    import pandas as pd
    import time
    # シリアルポートとボーレートの設定 (ポートは環境に合わせて変更してください)
    ser = serial.Serial('COM1', 9600)
    # シリアル通信が始まるまで少し待機
    time.sleep(2) # Arduinoのリセット待ち
    # Arduinoにスタート信号を送る
    ser.write(b'S') # 'S'を送信
    # データを格納するリスト
    data_list = []
    while True:
    if ser.in_waiting > 0:
    # シリアルポートから1行読み取り
    line = ser.readline().decode('utf-8').rstrip()

    # 読み取ったデータをコンマ区切りで分割
    data = line.split(",")

    # データが要素を持っているか確認
    if len(data) == 4:
    try:
    t = float(data[0])
    x8 = float(data[1])
    x4 = float(data[2])
    x5 = float(data[3])

    print(f"t: {t}, x8: {x8}, x4: {x4}, x5: {x5}")

    # データをリストに追加
    data_list.append([t, (x8/1023)*5, x4, x5])

    # ループを終了する条件
    if t >= 300:
    break
    except ValueError:
    print("データの変換に失敗しました:", data)
    # データの確認
    print("データリスト:", data_list)
    # データをDataFrameに変換
    df = pd.DataFrame(data_list, columns=['t', 'x8', 'x4', 'x5'])
    # データフレームの確認
    print("データフレーム:")
    print(df.head())
    # Excelファイルに保存 保存したいパスを指定
    try:
    df.to_excel(r'F:\フォルダ1\フォルダ2\エクセル.xlsx', index=False, engine='openpyxl')
    print("データがExcelファイルに保存されました。")
    except Exception as e:
    print(f"エラー: {e}")