【UE5】シリアル通信スロコンの作り方

【製造業様向け】UE活用ウェビナー 外部通信編
ウェビナーにご参加いただいた皆様、誠にありがとうございました。

今回は、ウェビナーでお話ししたシリアル通信の内容を、スロットコントローラーの作成を例に、より具体的にポイントを整理していきます。

こちらが、完成イメージ動画です。

準備するもの

必要なソフトウェア
・UnrealEngine
・UnrealEngineでシリアル信号を受信するプラグインとしてSerialCOM
・Arduinoの開発環境としてArduinoIDEを用意します

ハードウェア
・ArduinoUNO
・ArduinoUNOとパソコンを接続するUSBケーブル
・ボタン(BET、ストップx3)
・レバー用にジョイスティック
・ミニブレッドボード
・ジャンパー線

UnrealEngineプロジェクトの準備

UnrealEngineを起動し空のプロジェクトを作成します。

今回は、「ゲーム」「Blank」「ブループリント」で
K:\xGit\SeminarTest\surokon という フォルダに「surokon」というプロジェクト名で作成しました。

プロジェクトを作成したら、一度右上の「閉じる」ボタンでUEを終了させます。

プロジェクトを作成したフォルダに「Plugins」というフォルダを作成します。
※uprojectファイルやContentsフォルダと同一の階層に作成します。

https://github.com/videofeedback/Unreal_Engine_SerialCOM_Plugin

githubでSerialCOMをダウンロードします。

Serial COMのダウンロード及び利用は自己責任でお願いいたします。

スクロールし、Downloads(Releases)から、利用するUnrealEngineのバージョンに対応したSerialCOMをダウンロードします。
今回は、UE5.2.1でプロジェクトを作成したので、V5.5.2.1をダウンロードしました。

ダウンロードしたら、ZIPファイルを展開します。

展開した「SerialCOM」フォルダを、先ほど作成した「Plugins」フォルダ内に配置します。

Arduinoの準備

ArduinoIDE
https://www.arduino.cc/en/software


ArduinoIDEを起動し、スケッチを作成します。

スケッチを作成するために、まずはArduinoUNOとボタン・レバーの接続番号を事前に設計します。

設計通りにジャンパー線でスイッチ・レーバーを接続します。

※スケッチのコードは要点を明確にするため最低限となっています。
 例外処理を入れていなかったり、処理の一部を省略しているなど
 業務で耐えられるコードとなっていないため、ご参考程度にお願いします。
 また、ご利用される場合は自己責任でよろしくお願いいたします。

dipross_surokon.ino

int buttonMaxBetpin = 9;
int buttonLeftpin = 8;
int buttonCenterpin = 7;
int buttonRightpin = 6;
const int Y_pin = 0;

String ret = "";

void setup() {
  Serial.begin(9600);
  pinMode(buttonMaxBetpin, INPUT_PULLUP);  
  pinMode(buttonLeftpin, INPUT_PULLUP);  
  pinMode(buttonCenterpin, INPUT_PULLUP); 
  pinMode(buttonRightpin, INPUT_PULLUP); 
}

void loop() {
  if(analogRead(Y_pin) == 0){
    ret += "1,";
  }else{
    ret += "0,";
  }

  if (digitalRead(buttonMaxBetpin) == LOW)
  {
    ret += "1,";
  }else{
    ret += "0,";
  }

  if (digitalRead(buttonLeftpin) == LOW)
  {
    ret += "1,";
  }else{
    ret += "0,";
  }

  if (digitalRead(buttonCenterpin) == LOW)
  {
    ret += "1,";
  }else{
    ret += "0,";
  }

  if (digitalRead(buttonRightpin) == LOW)
  {
    ret += "1\n";
  }else{
    ret += "0\n";
  }

  Serial.print(ret);
  ret = "";
}

コード説明

int buttonMaxBetpin = 9;
int buttonLeftpin = 8;
int buttonCenterpin = 7;
int buttonRightpin = 6;
const int Y_pin = 0;

String ret = "";

利用するピンの番号と、シリアル値を送信するための変数を定義しています。
・ベットボタンには、ArduinoUNO DIGITAL 9 ピンを利用
・ストップボタンは、ArduinoUNO DIGITAL 8 ~ 6 ピンを利用
・スタートレバーは、ArduinoUNO ANALOG IN 0 ピンを利用

void setup() {
  Serial.begin(9600);
  pinMode(buttonMaxBetpin, INPUT_PULLUP);  
  pinMode(buttonLeftpin, INPUT_PULLUP);  
  pinMode(buttonCenterpin, INPUT_PULLUP); 
  pinMode(buttonRightpin, INPUT_PULLUP); 
}

setupは、最初に一度動きます。
シリアル通信の通信速度を9600bpsで指定します。
pinModeでは、利用するピンの番号と利用方法を設定します。
例.pinMode(buttonMaxBetpin, INPUT_PULLUP);
この場合、9番のピンを、インプット プルアップ(回路が切断された際に、HIGHとなる=通電時LOW)

void loop() {
  if(analogRead(Y_pin) == 0){
    ret += "1,";
  }else{
    ret += "0,";
  }

loopは、繰り返し呼ばれます。UEのTickに近い動きをします。
analogRead(Y_pin)では、ジョイスティックの値を受信します。
今回利用したジョイスティックは、中立で512を返し、0~1024の値を返します。
設置する向きによりますが、今回はY軸が0になったとき限界までレバーを倒した状態となるようにするため、取得した値が0となったとき反応するようにしました。

  if (digitalRead(buttonMaxBetpin) == LOW)
  {
    ret += "1,";
  }else{
    ret += "0,";
  }

ベットボタン、ストップボタンは同じ処理なので、ベットボタンで説明します。
先ほど、setupでプルアップの説明を書きましたが、ストップボタンに利用しているスイッチはシンプルな構造で
ボタンを押している間、2極の端子が接続され通電されるスイッチとなります。

ピンの設定で、プルアップ 押されていないときにHIGHとしていますので
digitalRead(buttonMaxBetpin) で取得した値が、LOW(押されている状態)となったとき、反応するようにしました。

  Serial.print(ret);
  ret = "";
}

最後に、ここまで 変数 ret にセットしてきた、0 or 1 の値を、シリアルで送信します。
0,0,0,0,0 の形になっています。

ret += ”1,”; の、+= は、retに代入ではなく、追加しています。
また、buttonRightpin で、\n を代入していますが、こちらは改行コードです。

最後に、次の繰り返しに備えて、ret変数を初期化したら一連の処理が完了します。



メニュー下の(→)アイコンで、プログラムをボードへ書き込みます。
問題なく書き込みが完了すると、下部緑部分に「ボードへの書き込みが完了しました。」と表示されます。

スケッチやポートに問題がある倍は、下の黒い部分にエラーの理由やヒントが表示されます。

虫眼鏡アイコンをクリックし、シリアルモニターを表示します。
右下の転送レートが、スケッチで指定した「9600bps」になっていることを確認します。

このように、「0,0,0,0,0」の形で受信できていることが確認できたら、ArduinoUNOからのシリアル値送信準備は完了です。
シリアルモニターを閉じておきます。

UnrealEngineでのシリアル受信設定

再び、UnrealEngineでプログラムを開きます。

冒頭で、SerialCOMプラグインを追加したので、左下のコンテンツブラウザにPluginsが追加されています。

今回の外部デバイスで操作したことが分かる、アクターを作成します。
「BP_Main」という、Actorを作成しました。

作成した「BP_Main」Actorを開きます。

「イベントグラフ」タブを開き、ブループリントを作成します。
「イベント BeginPlay」起動時に呼ばれるノードに、OpenSerialPortノードを接続します。
Portは、ArduinoUNOが接続されている、USBポート「5」 Baud Rateは、スケッチで指定した「9600」とします。

接続した「OpenSerialPort」の「ReturnValue」を右クリックし「変数へ昇格」をクリックします。

変数名を「SerialCom」に変更しました。

「イベント EndPlay」ノードには、CloseSerialPortを接続します。
この際、ターゲットは、OpenSerialPortの戻り値を変数化した「SerialCom」を接続します。

シリアル受信処理を入れる前に、受信した内容をもとに動かすものを作成します。
キューブ、丸、シリンダーを組合せスロコンを作成しました。

見た目が分かりにくいので、マテリアルも作成し割り当てました。

「Main」というレベルを作成し「BP_Main」を配置します。
座標は、X:0 Y:0 Z:100

「イベントTick」にシリアルの受信処理「SerialReadLine」ノードを接続しシリアル値をフレーム毎に受信します。

値は「0,0,0,0,0」で受信しますので、「ParseIntoArray」ノードで、値をカンマ区切りで分解し配列にセットします。

こちらが作成した、ブループリントの全貌です。コメントをいれまとめました。

データを分割し配列にセットした後、データが5つある場合のみ正常受信として処理をします。

カスタムイベントとして「Action」を作成しています。データチェック後、正常受信している場合、こちらの「Action」を呼び出しています。

レバー処理の詳細を見ていきます。

シリアル取得した値の「0,0,0,0,0」は、
1つ目の0:レバーの動作
2つ目の0:MaxBetボタン操作
3つ目の0:左ストップボタン操作
4つ目の0:中ストップボタン操作
5つ目の0:右ストップボタン操作 となります。

レバーは、一番したまで下げたら、1つ目の”0”を”1”を変えるようにスケッチでプログラムしました。

「GetWorldLocation」は、座標を取得するノード、「SetWorldLocation」は、座標を指定するノードです。

Lever(BP_Mainの黒い丸)の位置(ワールド座標)を取得します。
Leverは、上下の動きのみですのでZ軸のみ値を変更しX,Y軸は取得した値をそのままセットします。
Leverの初期の高さは、”100”でしたので、スロコンで操作されたことが分かるよう、5下に下げる為
1が来たとき、”95”をセットすることで、1を受信している間レバーが下に下がることになります。

要点を分かりやすくするため、汎用性のないプログラムをしていますので、実際に利用の際は適切なノードを利用します。


続いて、ベットボタン(赤いボタン)の処理を見ていきます。

基本的には、Leverと同じで、1の時に動かします。ボタンが押されたように見せる為、Z軸を2下げ押し下げたように見えるようにします。

最後にストップボタンです。

ベットボタンとの違いは、下に下がるのではなく奥に押される動きをします。
Z軸ではなっく、Y軸を動かすことで奥に押し込む動きを表現しています。

Leverを操作し、UE内のコンテンツが動いたことを確認します。

エンジニアリング事業部からの最新情報をお届けします