【ルネサス技術コラム】Arduino Uno R4 WiFiとOLED・加速度センサーで振動データを見える化

設備や機械の異常は、突然起きるように見えて、実際にはその前から振動の変化として兆候が出ていることがあります。
たとえば、

  • モーターの回転が少し荒くなる

  • ベアリングの摩耗で微妙な振動が増える

  • 取り付けの緩みで揺れ方が変わる

  • ファンのアンバランスで周期的なブレが大きくなる

といった変化です。

そこで今回は、「エレクトロニクスを簡単に」をテーマにRenesas RA4M1搭載のArduino Uno R4 WiFi OLEDディスプレイ、加速度センサーを使って、振動データを取得してその場で見える化するPoCを作る前提で、構成・考え方・サンプルコードをまとめます。

Arduino Uno R4 WiFiは、メインMCUにRenesas RA4M1、無線機能にESP32-S3を搭載しており、Arduino Cloudとも互換性があります。

今回は加速度センサーから取得した振動データを可視化し、将来的な故障検知や予知保全へ発展できる仕組みの第一歩として取り組みます。
狙いは単なる表示ではなく、将来的に故障検知や予知保全へ発展しやすい土台を作ることです。

注意
今回は振動可視化を目的とした低電圧PoCです。 実設備への恒久設置や設備制御を行う場合は、安全規格、絶縁、耐環境性、固定方法などを十分検討してください。

目次

この記事で目指すべきこと

今回は、次の流れを実現します。

  1. 加速度センサーでX/Y/Z軸の加速度を読む

  2. 振動の大きさを簡易スコアに変換する

  3. OLEDに現在値や状態を表示する

  4. シリアルへログを出して後で保存・分析できる形にする

  5. 将来的に閾値判定、傾向監視、遠隔通知へ発展させる

つまり、その場の見える化後から分析できるログ化の両方を最初から意識した構成です。

なぜ加速度センサーで振動を見るのか

振動は、機械の状態変化を比較的早い段階で反映しやすい指標です。
温度や電流も重要ですが、振動はとくに次のような変化に敏感です。

  • 回転体のブレ

  • 軸ずれ

  • 緩み

  • 摩耗

  • 衝撃

  • 異常接触

加速度センサーを使うと、これらを3軸の変化として取得できます。

PoCの段階では周波数解析までやらなくても、まずは

  • 振動が大きくなったか

  • いつもより不安定か

  • 短時間にピークが増えたか

といった変化の兆候を見るだけでも十分価値があります。

今回の構成

使用する部品は次のような想定です。

  • Arduino Uno R4 WiFi

  • SSD1306系 OLEDディスプレイ (I2C、128x64推奨)

  • MPU6050 などの加速度センサー (I2C)

  • ブレッドボード

  • ジャンパーワイヤ

加速度センサーはMPU6050のような入手しやすいモジュールを使うと始めやすいです。
OLEDも加速度センサーも I2C接続にすると、配線をシンプルにまとめやすいです。

Arduino Uno R4 WiFi を使う理由

Arduino Uno R4 WiFiは、Renesas RA4M1 (48MHz Arm Cortex-M4) を搭載し、さらにESP32-S3による Wi-Fi/Bluetooth通信に対応しています。

今回のPoCはOLED表示によるローカル可視化ですが、将来的には振動ログのクラウド保存や遠隔監視、異常通知へ発展させることも可能です。

開発環境は PlatformIO + VS Code を利用できます。
board = uno_r4_wifi
platform = renesas-ra

配線

OLED と MPU6050をどちらもI2Cで接続する例です。
I2C は複数デバイスを同じSDA / SCLにぶら下げられるので、今回のような構成と相性が良いです。

注意
MPU6050モジュールの電源電圧は製品ごとに違うことがあります。
使うモジュールの仕様を確認し、必要に応じて3.3V/5Vを正しく選んでください。

接続例

部品

端子

接続先

OLED

VCC

3.3Vまたは5V

OLED

GND

GND

OLED

SDA

SDA

OLED

SCL

SCL

MPU6050

VCC

モジュール仕様に合わせる

MPU6050

GND

GND

MPU6050

SDA

SDA

MPU6050

SCL

SCL

どんなデータを取るべきか

加速度センサーからは通常、X/Y/Z軸の値が取れます。
PoCではまず次の3段階で考えると分かりやすいです。

  1. 生データ

    • ax

    • ay

    • az

  2. ざっくりした振動の大きさ

    • 軸ごとの差分

    • ベクトルの変化量

    • 簡易スコア

  3. 保全向けの特徴量

    • 平均

    • 最大値

    • 最小値

    • RMS

    • 閾値超え回数

    • 一定時間内のピーク数

最初は「今どれだけ揺れているか」だけでも十分です。
その後、蓄積データを増やしていくと予知保全へ広げやすくなります。

今回のPoCで使う簡易振動スコア

今回は分かりやすさ重視で、
前回値との差分の絶対値を3軸分足し合わせたもの
を振動スコアとして扱います。

イメージとしてはこうです。

vibrationScore = |ax - prevAx| + |ay - prevAy| + |az - prevAz|

この方法のよい点は、

  • 計算が軽い

  • 変化量に敏感

  • 波形解析なしでも揺れの増減が見える

ことです。

もちろん本格的にはRMSやFFTもありますが、PoCの入口としては十分実用的です。

サンプルコード

以下は、MPU6050の加速度データから簡易振動スコアを計算し、OLEDに表示しながらシリアルへCSV形式で出力するサンプルです。

ポイント
・OLEDに現在値を表示
・シリアルにCSVで出力
・後からPC側で保存・分析しやすい
・将来的な異常判定の土台にしやすい

#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define OLED_ADDR 0x3C

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_MPU6050 mpu;

float prevAx = 0.0f;
float prevAy = 0.0f;
float prevAz = 0.0f;
bool firstSample = true;

float vibrationScore = 0.0f;
float smoothedScore = 0.0f;
float peakScore = 0.0f;

unsigned long lastDisplayMs = 0;
unsigned long lastLogMs = 0;
const unsigned long displayIntervalMs = 300;
const unsigned long logIntervalMs = 200;

const char *vibrationLevelText(float score)
{
  if (score < 0.20f)
    return "STABLE";
  if (score < 0.80f)
    return "NORMAL";
  if (score < 1.50f)
    return "NOTICE";
  return "ALERT";
}

int scoreToBarWidth(float score)
{
  float clamped = score;
  if (clamped < 0.0f)
    clamped = 0.0f;
  if (clamped > 2.0f)
    clamped = 2.0f;
  return (int)(clamped / 2.0f * 100.0f);
}

void drawScreen(float ax, float ay, float az, float score, float peak)
{
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);

  display.setCursor(0, 0);
  display.println("Vibration Monitor");

  display.setCursor(0, 10);
  display.print("AX:");
  display.print(ax, 2);
  display.setCursor(64, 10);
  display.print("AY:");
  display.print(ay, 2);

  display.setCursor(0, 20);
  display.print("AZ:");
  display.print(az, 2);
  display.setCursor(64, 20);
  display.print("PK:");
  display.print(peak, 2);

  display.setCursor(0, 32);
  display.print("SC:");
  display.print(score, 2);
  display.setCursor(64, 32);
  display.print(vibrationLevelText(score));

  int bar = scoreToBarWidth(score);
  display.drawRect(0, 48, 104, 10, SSD1306_WHITE);
  display.fillRect(2, 50, bar, 6, SSD1306_WHITE);

  display.display();
}

void setup()
{
  Serial.begin(115200);
  delay(500);

  Wire.begin();
  Wire.setClock(100000);

  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR))
  {
    while (1)
    {
      delay(1000);
    }
  }

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Starting...");
  display.display();

  if (!mpu.begin(0x68))
  {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("MPU6050 failed");
    display.display();
    while (1)
    {
      delay(1000);
    }
  }

  mpu.setAccelerometerRange(MPU6050_RANGE_4_G);
  mpu.setGyroRange(MPU6050_RANGE_250_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);

  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Sensor Ready");
  display.display();

  Serial.println("ms,ax,ay,az,score,smoothed,peak,level");
}

void loop()
{
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  float ax = a.acceleration.x;
  float ay = a.acceleration.y;
  float az = a.acceleration.z;

  if (firstSample)
  {
    prevAx = ax;
    prevAy = ay;
    prevAz = az;
    firstSample = false;
  }

  float dx = fabs(ax - prevAx);
  float dy = fabs(ay - prevAy);
  float dz = fabs(az - prevAz);

  vibrationScore = dx + dy + dz;
  smoothedScore = smoothedScore * 0.8f + vibrationScore * 0.2f;

  if (smoothedScore > peakScore)
  {
    peakScore = smoothedScore;
  }

  prevAx = ax;
  prevAy = ay;
  prevAz = az;

  unsigned long now = millis();

  if (now - lastLogMs >= logIntervalMs)
  {
    lastLogMs = now;
    Serial.print(now);
    Serial.print(",");
    Serial.print(ax, 3);
    Serial.print(",");
    Serial.print(ay, 3);
    Serial.print(",");
    Serial.print(az, 3);
    Serial.print(",");
    Serial.print(vibrationScore, 3);
    Serial.print(",");
    Serial.print(smoothedScore, 3);
    Serial.print(",");
    Serial.print(peakScore, 3);
    Serial.print(",");
    Serial.println(vibrationLevelText(smoothedScore));
  }

  if (now - lastDisplayMs >= displayIntervalMs)
  {
    lastDisplayMs = now;
    drawScreen(ax, ay, az, smoothedScore, peakScore);
  }
}

PlatformIO設定例

[env:uno_r4_wifi]
platform = renesas-ra
board = uno_r4_wifi
framework = arduino
monitor_speed = 115200
lib_deps =
  adafruit/Adafruit GFX Library
  adafruit/Adafruit SSD1306
  adafruit/Adafruit MPU6050
  adafruit/Adafruit Unified Sensor

プログラムのポイント

  • MPU6050で3軸加速度を取得

  • 前回値との差分から簡易振動スコアを計算

  • OLEDで現在状態を表示

  • CSV形式でログ出力

  • 将来の異常検知や予知保全へ発展できる構成

表示内容の見方

OLEDには次のような情報を出しています。

  • AX / AY / AZ
    現在の3軸加速度

  • PK
    これまでのピーク振動スコア

  • SC
    平滑化した現在の振動スコア

  • STABLE / NORMAL / NOTICE / ALERT
    振動の大きさをざっくり分類した状態

  • バー表示
    現在の揺れの強さを直感的に可視化

たとえばモーターやファンにセンサーを固定して観察すると、

  • 正常時は NORMAL

  • 取り付けを緩めたときに NOTICE

  • 強いブレや衝撃で ALERT

といった変化が見えてきます。

振動のない状態
少し振動のある状態
大きく振動している状態
シリアルモニターへのデータ出力

ログをCSVにしておく意味

このPoCで重要なのは、OLED表示だけで終わらせず、CSVとして出しておくことです。
シリアルログを保存すれば、後から Excel や Python で分析しやすくなります。

出力例はこんな形です。

ms,ax,ay,az,score,smoothed,peak,level
100,0.012,0.045,9.801,0.083,0.017,0.017,STABLE
200,0.021,0.052,9.790,0.027,0.019,0.019,STABLE
300,0.088,0.113,9.720,0.198,0.055,0.055,NORMAL

この形にしておくと、将来的に

  • 時系列グラフ化

  • 平均値や最大値の計算

  • 異常時データとの比較

  • 日単位・時間単位の傾向分析

へつなげやすくなります。

将来的な故障検知・予知保全への発展

ここから先は、PoCを少しずつ保全用途へ近づける段階です。

  1. 基準値を作る
    まずは正常状態で長めにデータを取り、平均的な振動レベルを記録します。

  2. 閾値を持つ
    平常時より明らかに大きいレベルを超えたら NOTICE や ALERT にします。

  3. 単発ではなく傾向を見る
    一瞬の振動より、じわじわ増えているかの方が保全では重要です。

  4. ピーク回数を数える
    一定時間で「大きな揺れが何回あったか」を見ると、異常兆候の把握に使えます。

  5. 無線送信する
    UNO R4 WiFiのESP32-S3を使えば、Wi-Fi経由でサーバーやダッシュボードに送る構成へ発展できます。

  6. 時刻を付ける
    RTCを使ってデータに時刻を付けると、保全記録として扱いやすくなります。

実運用に近づけるときの改善案

将来的には、次のような改善が考えられます。

  • smoothedScore だけでなくRMS を使う

  • 1秒ごとの集計値を作る

  • SDカードやWi-Fiでログ保存する

  • 閾値超えでLED Matrixやブザー通知を出す

  • 複数センサーで設備の複数箇所を比較する

  • FFTなどで周波数成分を見る

  • 正常データとの差分を学習ベースで見る

PoCの段階では全部やる必要はなく、
まずは安定してデータが取れること
その場で揺れの変化が見えること

が大事です。

注意点

1.センサーの取り付け方法で結果が大きく変わる 
 両面テープか、ネジ固定か、筐体のどこに付けるかで振動の見え方はかなり変わります。 
 比較したいなら、毎回なるべく同じ条件で固定するのが重要です。

2.振動の向きで見え方が変わる
 X/Y/Zのどの軸に振動が乗るかは設備によって違います。
 最初は3軸すべてを取っておく方が安全です。

3.環境ノイズがある
 机の振動、人の接触、周辺設備の影響でも数値は変わります。
 そのため、単発の値より時間変化を見た方が実用的です。

4.いきなり診断には使わない
 このPoCは、あくまで兆候を取る入口です。
 本格的な故障診断は、蓄積データや設備知識と組み合わせて進めるのが現実的です。

ルネサス製品への展開

今回のPoCではArduino Uno R4 WiFiを利用しましたが、
実際の設備監視用途へ発展させる場合は、
ルネサスのRAファミリを活用した組込みシステムへ展開できます。

例えば、

  • RA4M1: 小規模な設備監視ノード

  • RA6シリーズ: Wi-Fi/Bluetoothを活用した遠隔監視やクラウド接続機器への展開

  • センサー+RAマイコン: 振動監視や状態監視のエッジ処理

  • クラウド連携: MQTTやダッシュボードによる見える化

といった構成が考えられます。

PoCで得られた振動データを蓄積し、
異常検知や予知保全アルゴリズムへ発展させることで、
より実運用に近い設備保全ソリューションへ展開できます。

まとめ

今回は、Arduino Uno R4 WiFiとOLED、加速度センサーを使って、振動データを取得・表示するPoCの考え方と実装例をまとめました。

ポイントは次の通りです。

  • 加速度センサーで3軸の振動変化を取る

  • OLEDでその場の状態を見える化する

  • シリアルにCSVで出して後から分析できるようにする

  • 振動スコアの傾向を見ることで異常兆候の入口にする

  • 将来的にWi-Fi送信、RTC時刻付け、閾値監視へ広げやすい

この構成は、最初は小さなPoCですが、
そこから

  • 異常検知

  • 故障兆候の早期発見

  • 予知保全の基礎データ収集

へ発展しやすいのが魅力です。

まずは単純な振動スコアの見える化から始めて、
次にログ蓄積、
その次に基準値比較、
という順で育てていくと、かなり実用に近づけやすいテーマです。

参考リンク