概要
メタバースを使った、自動運転シュミレーターを提供します。
方針を転換する。
今まで、neosvrの世界でセンサーを作り、その情報を外に出して、エージェントが環境として読み込み自己判断させようとしていたが、
これからは、エージェントも環境も外で作り、表示のみneosvrで表示する。
上記に従い以下を実験する。
エージェント(ローバー)が環境で、自動運転するシュミレータを作り、結果をwebsocketに出力、neosvrで受け取り、BOXを移動させる。
websocketサーバーは、elixirで準備します。
設定は、ローバーが、8の字運転を続けるシュミレーターです。
各ポイントは、以下です。
var point1 = {
'x': 260,
'y': 148
};
var point2 = {
'x': 278,
'y': 169
};
var point4 = {
'x': 161,
'y': 278
};
var point3 = {
'x': 141,
'y': 257
};
ローバーは、ステートマシンを持っていて、ポイントをクリアすれば、次のポイントに向かいます。
ローバーは、getDistanceとgetDegreeでポイントまでの距離と方角を得て、自分で判断します。
環境は、60fpsで更新し、ローバーを移動し、位置を更新します。
ローバーは、位置を受け取り、方向を出力します。
さらに、ローバーの位置情報をwebsocketで、垂れ流しします。
neosvrは、ローバーの位置情報をwebsocketで受け取り、BOXを移動させます。
手順
websocketサーバーの準備
いつものやつです、省略。
エージェントと環境の準備
サンプルコード
function getDistance(x, y, x2, y2) {
var distance = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));
return distance;
}
function getDegree(x, y, x2, y2) {
var radian = Math.atan2(y - y2, x - x2);
var degree = radian * 180 / Math.PI + 180;
return degree;
}
function draw() {
ctx.save();
ctx.translate(point1.x, point1.y);
ctx.fillStyle = "red";
ctx.fillRect(-5, -5, 5, 5);
ctx.restore();
ctx.save();
ctx.translate(point2.x, point2.y);
ctx.fillStyle = "red";
ctx.fillRect(-5, -5, 5, 5);
ctx.restore();
ctx.save();
ctx.translate(point3.x, point3.y);
ctx.fillStyle = "red";
ctx.fillRect(-5, -5, 5, 5);
ctx.restore();
ctx.save();
ctx.translate(point4.x, point4.y);
ctx.fillStyle = "red";
ctx.fillRect(-5, -5, 5, 5);
ctx.restore();
ctx.save();
ctx.translate(car.x, car.y);
ctx.fillStyle = "maroon";
ctx.fillRect(-3, -3, 3, 3);
ctx.restore();
}
var koko;
var canvas;
var ctx;
var state = 2;
var r = 0;
var car = {
'px': 0,
'py': 0,
'x': 210,
'y': 210,
'r': 0
};
var point1 = {
'x': 260,
'y': 148
};
var point2 = {
'x': 278,
'y': 169
};
var point4 = {
'x': 161,
'y': 278
};
var point3 = {
'x': 141,
'y': 257
};
function hand(p) {
var d = getDistance(car.x, car.y, p.x, p.y);
if (d < 5)
{
return;
}
var f = getDegree(car.x, car.y, p.x, p.y);
var e = getDegree(car.px, car.py, car.x, car.y);
var s = Math.abs(f - e);
if (s < 5)
{
return;
}
if (s < 180)
{
if (e < f)
{
r = 10;
}
if (e > f)
{
r = -10;
}
}
else
{
if (e < f)
{
r = -10;
}
if (e > f)
{
r = 10;
}
}
}
function send() {
var mes = "[";
mes += car.x / 30;
mes += "; 0.5; ";
mes += car.y / 30;
mes += "]";
koko.value = mes;
socket.send(mes);
}
function loop2() {
var dis;
car.px = car.x;
car.py = car.y;
car.r += r * Math.PI / 180;
car.x += Math.cos(car.r) * 0.3;
car.y += Math.sin(car.r) * 0.3;
switch (state)
{
case 0:
dis = getDistance(point4.x, point4.y, car.x, car.y);
if (dis < 5)
{
state = 1;
break;
}
hand(point4);
break;
case 1:
dis = getDistance(point3.x, point3.y, car.x, car.y);
if (dis < 5)
{
state = 2;
break;
}
hand(point3);
break;
case 2:
dis = getDistance(point2.x, point2.y, car.x, car.y);
if (dis < 5)
{
state = 3;
break;
}
hand(point2);
break;
case 3:
dis = getDistance(point1.x, point1.y, car.x, car.y);
if (dis < 5)
{
state = 0;
break;
}
hand(point1);
break;
}
}
canvas = document.getElementById('canvas');
koko = document.getElementById('koko');
canvas.width = canvas.height = 300;
ctx = canvas.getContext('2d');
function loop() {
draw();
loop2();
send();
requestAnimationFrame(loop);
}
let url = "ws://localhost:50002/";
let socket = new WebSocket(url);
socket.onmessage = function(event) {
//alert(event.data);
};
socket.onclose = event => alert(`Closed`);
socket.onopen = function(event) {
alert('open');
loop();
};
socket.onerror = event => alert(`err`);
成果物
メタバースの準備
手順
DevToolTipを装着
新規作成>3Dモデル>Boxをクリック
Transform->Interaction->TouchButtonを追加
追加コンポーネント->network->WebsocketClient
logixtooltipを装着
TouchButtonのインターフェースを取り出す 右ドラッグしてRキー
WebsocketClientのインターフェースを取り出す
boxのスロットルを取り出す インスペクタ左上の「●Box」の文字部分を右ドラッグしてRキー
ノードブラウザを表示
Interaction>ButtonEventsをスポーン
network->websocket->WebsocketConnectをスポーン
network->websocket->WebsocketTextMessageReceiverをスポーン
Users>HostUserをスポーン
actions->writeをスポーン
variables->stringをスポーン
Operation>Parse>ParserFloat3をスポーン
下の様に、俺コードでつなぐ。
{w0, _, _, _, _, _, _, _, _, _} = ButtonEvents [Obj.Box.TouchButton]
{} = WebsocketConnect [w0, FrooxEngine.WebSocketClient, "ws://localhost:50002/", HostUser]
{w2, w3} = WebsocketTextMessageReceiver [w0, FrooxEngine.WebSocketClient]
{w4} = Write [w2, w3]
{w5} = String [w4]
{w6} = ParserFloat3 [w5]
{} = Obj.Box.Slot.Position [w6]
起動
websocketサーバーを起動
クライアントを起動
neosvrを起動
動作確認
メタバース上のBOXが動けば、成功です。
以上。