【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内のコンテンツが動いたことを確認します。