##本作業について
タイトル通り、ドローンを操作できる状態にすることを目指します。
そのためにプログラムの作成・追加を行い、キーボードで操作できるようにします。
「コントローラで動かしたい」といった場合でも、このプログラムを少し書き換えることで実現できるようですので、まずはこのページに従ってキーボードで動かしてみてください。
######はしがき:readmeの情報について
AirSim\Unity上では計2つのREADME.mdが存在します。
その内、UnityDemoフォルダ内にある方を開くと「キー入力で操作できる」旨が書いてあります。
しかし、この情報は古いバージョンのものであり、現在のバージョンではキー入力による操作をデフォルトで行うことはできません。
##具体的な作業
この作業は、前回の「Unityへのインポート作業~実行」までを終えていることを前提としています。これらの作業を終えていない方は、先にそちらをご覧ください。
◆手順
①プログラムの書き足し
②プログラムの新規作成
③キーコンフィグの設定
④実行してみる
⑤ドローンの動作の要素について
##①プログラムの書き足し
「AirSim→Unity→UnityDemo→Assets→AirSimAssets→Scripts→Vehicles」内にVehicle.csというc#スクリプトが存在します。
これをVisual Studioで開き、353行目と354行目の間に以下のプログラムを加筆してください。
// Added for DroneControllerInput Use
public bool ControllerAllowed() {
return isServerStarted && !isApiEnabled;
}
public void SetRCData(AirSimRCData data) {
rcData = data;
}
##②プログラムの新規作成
DroneControllerInput.csというc#スクリプトを作成します。
ファイルを作成する場所は任意です。
対となる車のコントロールプログラムの場所を意識するなら、"AirSim/Unity/UnityDemo/Assets/AirSimAssets/Scripts/Vehicles/Multirotor/"内が妥当ですが、見ての通りかなり深い位置になってしまいます。
深い位置が嫌いな方であれば、自分にとって分かりやすい場所に作る方が良いでしょう。
プログラムの中身は以下の通りです。
using System;
using System.Collections.Generic;
using AirSimUnity.DroneStructs;
using UnityEngine;
namespace AirSimUnity
{
[RequireComponent(typeof(Drone))]
public class DroneControllerInput : MonoBehaviour
{
private Drone drone;
private void Start() {
drone = this.gameObject.GetComponent<Drone>();
}
private void LateUpdate()
{
if (drone.ControllerAllowed())
{
AirSimRCData rcData = drone.GetRCData();
rcData.is_valid = true;
rcData.roll = Input.GetAxis("Horizontal"); //左右
rcData.pitch = Input.GetAxis("Vertical"); //前後
rcData.throttle = Input.GetAxis("Depth"); //上下
rcData.yaw = Input.GetAxis("Yaw"); //回転
rcData.left_z = 0;
rcData.right_z = 0;
drone.SetRCData(rcData);
}
}
}
}
そして、"DroneDemo"シーンを開き、作成したDroneControllerInput.csをドローンのオブジェクト(QuadCopter)にコンポーネントとして追加してください。
追加が終わったら、忘れないうちにシーンを"SimModeSelecter"に戻しておきましょう。
ここまでの作業によって、入力設定でキーコンフィグを行うことが可能になります。
##③キーコンフィグの設定
「(メニューバーの)編集→プロジェクト設定→入力」を選択します。
すると、右側に表示されるインスペクターからキーコンフィグを行うことができます。
デフォルトでは「Horizontal(日本語表記:水平)」「Vertical(日本語表記:垂直方向)」の2つは既に作られています。
この他に、「Depth」「Yaw」の2つを作成してください。不要な「Fire1」「Fire2」あたりの名前を変更するのが一番手っ取り早いです。
あとはキーコンフィグを自由に設定してください。
どこに何を設定すればいいかわからない人は、以下のように設定するのがおすすめです。
Horizontalの負方向ボタン | left (矢印キー左) |
Horizontalの正方向ボタン | right (矢印キー右) |
Verticalの負方向ボタン | down (矢印キー下) |
Verticalの正方向ボタン | up (矢印キー上) |
Depthの負方向ボタン | s |
Depthの正方向ボタン | w |
Yawの負方向ボタン | a |
Yawの正方向ボタン | d |
##④実行してみる
前回と同じく、"SimModeSelecter"シーンから実行してみましょう。
実際に動かせれば成功です。
先ほどおすすめした通りに設定した場合、
・矢印キーで前後左右
・awsdキーで上下回転
となります。
ちなみに、慣性が強く働いているのは仕様のようです。
##⑤ドローンのカスタマイズ
この項目では、より操作をカスタマイズしたい人に向けて記載しておきます。
###・キー入力の限界
単純なキー入力だけでは、残念ながらドローンの速度を微調整することはできません。
なぜなら、キーボードの入力では「押している」か「押されていない」の2つの状態しか扱えないからです。
よって、「キーを半分押したから半分の速度でドローンを動かす」というのは不可能です。
もし、キーボード上で半分の速度で動かしたいのであれば、後述するような手法で「キーを押すと、50%の速度で動くように設定する」必要があります。
ただ、この要領で「複数のスピードを出せるようにする」場合は一つの機能に対して複数のキーを割り当てる必要があります。
そうなると、操作が複雑になり、実用性が低下しています。
そのため、速度を微調整したい場合にはキーボードをコントローラとして使用するのはあまりオススメできません。
別途コントローラーなど用意し、アナログスティックで操作した方が良いです。
###・速度の変更
キーを押した時の速度を変更したい場合、プログラムの数値を弄ることで簡単に変更することができます。
例えば、「左右を1/2のスピードにしたい!」といった場合には、
先ほどの
rcData.roll = Input.GetAxis("Horizontal");
の部分を
rcData.roll = Input.GetAxis("Horizontal")/2;
と変えるだけで半分になります。
また、if文によっても同じことができますが、その場合は以下の2つに注意してください。
1.必ず、「何も押していないときの動作を定義する」こと。(左右なら、if文の最後に必ずelseでrcData.roll=0を入れる。忘れると永久に押しっぱなし判定になる。)
2.小数の値を代入する際には、float型にする。(忘れると小数点以下切り捨てで扱われる)
##おまけ1:参考にしたページ
本作業の内容は、このページの情報を参考に作成しています。
このページが無ければ、私はAirSimを使うことを断念していました。
この場を借りて、元となるプログラムを作成したjasonhbartlettさんにお礼申し上げます。
##おまけ2:私が使用したプログラム
今回紹介したプログラムとは別に、私が編集したDroneControllerInput.csもここに記しておきます。
先述のものとは、3つの変数によって操作している点が異なります。
ちょっと変わった操作方法ですが、プログラムを読める人であれば、大体何をしているのか想定がつくと思います。参考までに。
using System;
using System.Collections.Generic;
using AirSimUnity.DroneStructs;
using UnityEngine;
namespace AirSimUnity
{
[RequireComponent(typeof(Drone))]
public class DroneControllerInput : MonoBehaviour
{
private Drone drone;
private void Start()
{
drone = this.gameObject.GetComponent<Drone>();
}
private void LateUpdate()
{
if (drone.ControllerAllowed())
{
AirSimRCData rcData = drone.GetRCData();
rcData.is_valid = true;
if ((RotateByAccelerometer.Z == 1))
{
//旋回動作
rcData.roll = 0;
rcData.pitch = 0;
if (RotateByAccelerometer.Y > 0.2)
{
rcData.yaw = (float)0.2;
}
else if (RotateByAccelerometer.Y < -0.2)
{
rcData.yaw = (float)-0.2;
}
else
{
rcData.yaw = 0;
}
}
else
{
rcData.yaw = 0;
//左右動作
if (RotateByAccelerometer.Y >= 0.7)
{
rcData.roll = (float)0.5;
}
else if (RotateByAccelerometer.Y >= 0.4 && 0.7>= RotateByAccelerometer.Y)
{
rcData.roll = (float)0.25;
}
else if (RotateByAccelerometer.Y >= 0.2 && 0.4 > RotateByAccelerometer.Y)
{
rcData.roll = (float)0.1;
}
else if (RotateByAccelerometer.Y <= -0.7)
{
rcData.roll = (float)-0.5;
}
else if (RotateByAccelerometer.Y <= -0.4 && -0.7 <= RotateByAccelerometer.Y)
{
rcData.roll = (float)-0.25;
}
else if (RotateByAccelerometer.Y <= -0.2 && -0.4 < RotateByAccelerometer.Y)
{
rcData.roll = (float)-0.1;
}
else
{
rcData.roll = 0;
}
//前後動作
if (RotateByAccelerometer.X >= 0.5)
{
rcData.pitch = (float)0.5;
}
else if (RotateByAccelerometer.X >= 0.3 && 0.5 >= RotateByAccelerometer.X)
{
rcData.pitch = (float)0.25;
}
else if (RotateByAccelerometer.X >= 0.15 && 0.3 > RotateByAccelerometer.X)
{
rcData.pitch = (float)0.1;
}
else if (RotateByAccelerometer.X <= -0.6)
{
rcData.pitch = (float)-0.5;
}
else if (RotateByAccelerometer.X <= -0.3 && -0.6 <= RotateByAccelerometer.X)
{
rcData.pitch = (float)-0.25;
}
else if (RotateByAccelerometer.X <= -0.15 && -0.3 < RotateByAccelerometer.X)
{
rcData.pitch = (float)-0.1;
}
else
{
rcData.pitch = 0;
}
}
rcData.left_z = 0;
rcData.right_z = 0;
drone.SetRCData(rcData);
}
}
}
}