程序员

大疆文档(8)-Android教程-模拟器App

2019-04-15  本文已影响1人  世外大帝

本节全篇为大疆 Mobile SDK 安卓教程 部分,ios教程参见 IOS教程 .

模拟器应用程序

在本教程中,你可以学习如何使用DJI Mobile SDK在你的Android Studio项目中使用DJISimulator。通过虚拟摇杆控制,你可以输入虚拟杆飞行控制数据,并且可以实时检查模拟器状态变更。

你可以在这里下载本教程最终示例项目 Github Page.

我们用 Mavic Pro 作为示例进行演示,开始吧

介绍

DJISimulator 用于根据虚拟杆输入在模拟环境中控制飞机。模拟的飞机状态信息也将显示在屏幕上。

您可以用 FlightController 中的 Simulator 类去控制模拟。它允许模拟手动和自动飞行,而无需让飞机实际飞行。

此外,可以通过SDK直接控制模拟器初始化,监视和终止,从而允许在持续集成环境中进行应用程序开发。

在中国进行应用激活和飞机绑定

对于在中国使用的DJI SDK移动应用程序,需要激活应用程序并将飞机绑定到用户的DJI帐户。

如果未激活应用程序,未使用飞机(如果需要)或使用旧版SDK(<4.1),则将禁用所有 相机实时流 ,并且飞行将限制为直径100米和高度为30米的区域,以确保飞机保持在视线范围内。

要了解如何实现此功能,请查看本教程 Application Activation and Aircraft Binding.

实现应用程序UI

导入 Maven 依赖

在我们之前的教程中l Importing and Activating DJI SDK in Android Studio Project,您已经学习了如何导入 Android SDK Maven 依赖项并激活您的应用程序。如果你之前没看过,那就回去看一下相关实现。然后再继续。

构建 Activity 布局

1. 实现操纵杆控制

为了输入一些模拟数据, 像 pitch, roll, yaw and verticalThrottle, 你可能需要一个操纵杆控制。让我们来实现它吧。

我们根据 Github 开源项目 OnScreenJoystick 实现操纵杆控制。你可以从下载的Github项目中获取 OnScreenJoystick.java and OnScreenJoystickListener.java 文件,或者从本教程的Github示例项目中获取。现在,复制粘贴这两个java文件到 "com.dji.simulatorDemo" 下面:

onScreenJoystick

当你触摸 OnScreenJoystick 视图时,OnScreenJoystickListener 的 onTouch 方法将被调用,你可以从这个方法中获取 "OnScreenJoystick" 操纵杆对象,还有节点参数的 x,y 坐标。如下所示:

/** Called when the joystick is touched.
 * @param joystick The joystick which has been touched.
 * @param pX The x coordinate of the knob. Values are between -1 (left) and 1 (right).
 * @param pY The y coordinate of the knob. Values are between -1 (down) and 1 (up).
 */
public void onTouch(final OnScreenJoystick joystick, final float pX, final float pY);

Note: 节点的 x 坐标值在 -1 (left) 和 1 (right) 之间,y坐标值在 -1 (down) 和 1 (up) 之间。

接下来,从本教程的Github示例项目中复制粘贴 joystick.pngjoystick_bg.png 文件到 mipmap 文件夹(as3.3.2 是 mipmap-xxxhdpi):

joystickImages

2. 实现 MainActivity 类的UI元素

现在,让我们打开 MainActivity.java 文件,并用以下代码替换:

public class MainActivity extends Activity implements View.OnClickListener {

    private static final String TAG = MainActivity.class.getName();
    protected TextView mConnectStatusTextView;
    private Button mBtnEnableVirtualStick;
    private Button mBtnDisableVirtualStick;
    private ToggleButton mBtnSimulator;
    private Button mBtnTakeOff;
    private Button mBtnLand;
    private TextView mTextView;

    private OnScreenJoystick mScreenJoystickRight;
    private OnScreenJoystick mScreenJoystickLeft;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        initUI();
    }

    @Override
    public void onResume() {
        Log.e(TAG, "onResume");
        super.onResume();
    }

    @Override
    public void onPause() {
        Log.e(TAG, "onPause");
        super.onPause();
    }

    @Override
    public void onStop() {
        Log.e(TAG, "onStop");
        super.onStop();
    }

    public void onReturn(View view){
        Log.e(TAG, "onReturn");
        this.finish();
    }

    @Override
    protected void onDestroy() {
        Log.e(TAG, "onDestroy");
        super.onDestroy();
    }

    private void initUI() {

        mBtnEnableVirtualStick = (Button) findViewById(R.id.btn_enable_virtual_stick);
        mBtnDisableVirtualStick = (Button) findViewById(R.id.btn_disable_virtual_stick);
        mBtnTakeOff = (Button) findViewById(R.id.btn_take_off);
        mBtnLand = (Button) findViewById(R.id.btn_land);
        mBtnSimulator = (ToggleButton) findViewById(R.id.btn_start_simulator);
        mTextView = (TextView) findViewById(R.id.textview_simulator);
        mConnectStatusTextView = (TextView) findViewById(R.id.ConnectStatusTextView);
        mScreenJoystickRight = (OnScreenJoystick)findViewById(R.id.directionJoystickRight);
        mScreenJoystickLeft = (OnScreenJoystick)findViewById(R.id.directionJoystickLeft);

        mBtnEnableVirtualStick.setOnClickListener(this);
        mBtnDisableVirtualStick.setOnClickListener(this);
        mBtnTakeOff.setOnClickListener(this);
        mBtnLand.setOnClickListener(this);

        mBtnSimulator.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            }
        });

        mScreenJoystickLeft.setJoystickListener(new OnScreenJoystickListener(){

            @Override
            public void onTouch(OnScreenJoystick joystick, float pX, float pY) {
          }
        });

        mScreenJoystickRight.setJoystickListener(new OnScreenJoystickListener() {

            @Override
            public void onTouch(OnScreenJoystick joystick, float pX, float pY) {
            }
        });
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btn_enable_virtual_stick:
                break;
            case R.id.btn_disable_virtual_stick:
                break;
            case R.id.btn_take_off:
                break;
            case R.id.btn_land:
                break;
            default:
                break;
        }
    }
}

以上代码中,我们实现了以下功能:

1. 创建布局UI元素变量,包括两个TextView,4个Button,1个ToggleButton和2个 OnScreenJoystick 控制。

2.onCreate() 方法中, 我们要请求几个运行时权限确保编译时或SDK版本大于22的时候SDK可以正常工作。 然后调用 initUI() 方法去初始化UI变量和监听事件。.

3.initUI() 方法中, 我们首先初始化UI元素变量, 然后将四个按钮的监听事件设置为this 。此外,实现切换按钮监听事件 mBtnSimulator.setOnCheckedChangeListeneronCheckedChanged() 方法。 最后,实现两个 OnScreenJoystick.setJoystickListener 对象的监听事件的 onTouch() 方法。

实现切换按钮“mBtnSimulator”的“setOnCheckedChangeListener”的“onCheckedChanged()”方法。
4. 重写 onClick() 以实现4个按钮的点击操作。

3. 实现 MainActivity 布局

打开 activity_main.xml 布局文件,并且用以下代码替换:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/main_title_rl"
        android:layout_width="fill_parent"
        android:layout_height="40dp"
        android:background="@color/black_overlay" >

        <ImageButton
            android:id="@+id/ReturnBtn"
            android:layout_width="wrap_content"
            android:layout_height="35dp"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="5dp"
            android:adjustViewBounds="true"
            android:background="@android:color/transparent"
            android:onClick="onReturn"
            android:scaleType="centerInside"
            android:src="@drawable/selector_back_button" />

        <TextView
            android:id="@+id/ConnectStatusTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="SimulatorDemo"
            android:textColor="@android:color/white"
            android:textSize="19sp" />
    </RelativeLayout>

    <TextView
        android:layout_marginTop="70dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="Simulator is off."
        android:id="@+id/textview_simulator"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Enable Virtual Stick"
        style="@style/common_button"
        android:id="@+id/btn_enable_virtual_stick"
        android:layout_marginLeft="5dp"
        android:layout_alignTop="@+id/btn_start_simulator"
        android:layout_alignStart="@+id/directionJoystickRight"
        android:layout_marginTop="0dp" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Disable Virtual Stick"
        style="@style/common_button"
        android:id="@+id/btn_disable_virtual_stick"
        android:layout_below="@+id/btn_enable_virtual_stick"
        android:layout_alignStart="@+id/btn_enable_virtual_stick"
        android:layout_marginLeft="0dp"
        android:layout_alignEnd="@+id/btn_enable_virtual_stick" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Take Off"
        style="@style/common_button"
        android:id="@+id/btn_take_off"
        android:layout_alignTop="@+id/btn_disable_virtual_stick"
        android:layout_alignStart="@+id/btn_start_simulator"
        android:layout_marginTop="0dp"
        android:layout_alignEnd="@+id/btn_start_simulator" />

    <ToggleButton
        android:id="@+id/btn_start_simulator"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start Simulator"
        android:textOff="Start Simulator"
        android:textOn="Stop Simulator"
        style="@style/common_button"
        android:layout_below="@+id/textview_simulator"
        android:layout_toEndOf="@+id/btn_enable_virtual_stick"
        android:layout_marginTop="107dp"
        android:layout_marginLeft="10dp" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Land"
        style="@style/common_button"
        android:id="@+id/btn_land"
        android:layout_alignTop="@+id/btn_take_off"
        android:layout_marginTop="0dp"
        android:layout_alignEnd="@+id/directionJoystickLeft"
        android:layout_toEndOf="@+id/btn_take_off"
        android:layout_marginLeft="10dp" />

    <com.dji.simulatorDemo.OnScreenJoystick
        android:id="@+id/directionJoystickRight"
        android:layout_width="130dp"
        android:layout_height="130dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="10dp"
        android:layout_marginLeft="10dp"
        android:background="@mipmap/joystick_bg"/>

    <com.dji.simulatorDemo.OnScreenJoystick
        android:id="@+id/directionJoystickLeft"
        android:layout_width="130dp"
        android:layout_height="130dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="10dp"
        android:layout_marginRight="10dp"
        android:background="@mipmap/joystick_bg"/>

</RelativeLayout>

在这个xml文件中, 首先,我们实现这个RelativeLayout元素。 我们声明一个 ImageButton(id: ReturnBtnCamera) 元素去结束程序, 还有一个 TextView(id: ConnectStatusTextView) 元素用来展示连接状态。

接下来,创建一个 TextureView(id: textview_simulator) 元素来展示模拟器状态信息。此外,创建4个按钮: "Enable Virtual Stick" button(id: btn_enable_virtual_stick), "Disable Virtual Stick" button(id: btn_disable_virtual_stick), "Take Off" button(id: btn_take_off), "Land" button(id: btn_land),然后创建 "Start Simulator" toggle button(id: btn_start_simulator) ,并设置 textOntextOff 参数为 "Start Simulator" 和 "Stop Simulator"。

最后,我们为操作杆控制创建两个 OnScreenJoystick 元素(id: directionJoystickRight) 和 (id:directionJoystickLeft)。

4. 配置资源文件

完成上述步骤后,我们添加一些资源文件到 res 文件夹。

从教程示例程序的 drawable 文件夹下复制下图中的 image 和 xml文件 到你的项目中,他们可用于 button UI:

drawable

接下来,打开 "colors.xml" 文件,并在底部添加以下代码来声明 “black_overlay”:

<color name="black_overlay">#66000000</color>

此外, 打开 "strings.xml" 文件并添加以下字符串:

<string name="success">Success</string>

最后,打开 "styles.xml" 文件,并添加以下代码来声明 "common_button" :

<!-- Common button style -->
<style name="common_button">
    <item name="android:layout_width">100dp</item>
    <item name="android:layout_height">45dp</item>
    <item name="android:layout_marginTop">10dp</item>
    <item name="android:background">@drawable/round_btn</item>
    <item name="android:paddingLeft">5dp</item>
    <item name="android:paddingRight">5dp</item>
    <item name="android:textAllCaps">false</item>
    <item name="android:textColor">@android:color/white</item>
    <item name="android:textSize">14sp</item>
</style>

在 DJISimulatorApplication 和 MainActivity 中实现注册

当你完成上述步骤后,让我们在大疆开发者网站来注册应用程序,并获取 App Key 。 如果不会,看看这里 Generate an App Key

此外, MApplication, DJISimulatorApplicationMainActivity 的详细实现,可以看看这个教程 Creating an Camera Application ,还有这个 sample project

现在让我们构建运行程序,然后安装到你的 android 设备上。如果一切ok,那么当你注册成功的时候应该可以看到 "success" 。

registerSuccess

实现 MainActivity 类

更新产品连接状态

更详细的实现看本教程的示例代码: sample project

现在,我们构建并运行项目,然后安装到你的Android设备上。然后把demo连接到你的Mavic Pro上 (不会看看这个 Run Application ),如果一切ok,你应该可以看到 title 内容更新为 "MavicPro Connected" :

registerSuccess

实现虚拟杆控制

由于我们实现了虚拟杆控制, 现在我们可以继续发送虚拟杆飞行控制数据到飞机。首先,我们在 onCreate() 方法上面创建一个 FlightController 变量mFlightController,一个 Timer 变量 mSendVirtualStickDataTimer ,一个 SendVirtualStickDataTask (继承自 TimerTask 类) 变量 mSendVirtualStickDataTask 和4个 float 变量,如下所示:

private FlightController mFlightController;
private Timer mSendVirtualStickDataTimer;
private SendVirtualStickDataTask mSendVirtualStickDataTask;

private float mPitch;
private float mRoll;
private float mYaw;
private float mThrottle;

我们可以用 mPitch, mRoll, mYawmThrottle 变量去存储 pitch, roll, yawvertical throttle 虚拟杆飞行控制数据。

接下来,创建 initFlightController() 方法,在 onResume() 方法中调用它,并实现 SendVirtualStickDataTask 类:

private void initFlightController() {

    Aircraft aircraft = DJISimulatorApplication.getAircraftInstance();
    if (aircraft == null || !aircraft.isConnected()) {
        showToast("Disconnected");
        mFlightController = null;
        return;
    } else {
        mFlightController = aircraft.getFlightController();
    }
}

@Override
public void onResume() {
    Log.e(TAG, "onResume");
    super.onResume();
    updateTitleBar();
    initFlightController();
}

class SendVirtualStickDataTask extends TimerTask {

        @Override
        public void run() {

            if (mFlightController != null) {
                mFlightController.sendVirtualStickFlightControlData(
                        new FlightControlData(
                                mPitch, mRoll, mYaw, mThrottle
                        ), new CommonCallbacks.CompletionCallback() {
                            @Override
                            public void onResult(DJIError djiError) {

                            }
                        }
                );
            }
        }
    }

以上代码实现了以下功能:

1.initFlightController() 方法中, 我们首先检查飞机是否 not null 并且已连接, 然后调用 Aircraft 的 getFlightController() 方法获取 mFlightController 变量。

2. 接下来,继承 TimerTask 类创建 SendVirtualStickDataTask 类。在这个类中,重写 run() 方法去调用 FlightController 的sendVirtualStickFlightControlData() 方法去发送虚拟杆飞行控制数据。在这里,我们创建 FlightControlData 对象,并在第一个参数 FlightControlData 中传入之前声明的4个 float 变量: mPitch, mRoll, mYawmThrottle

完成上述步骤后, 让我们在 initUI() 方法底部实现 mScreenJoystickLeftmScreenJoystickRight 变量的setJoystickListener() 方法:

mScreenJoystickLeft.setJoystickListener(new OnScreenJoystickListener(){

    @Override
    public void onTouch(OnScreenJoystick joystick, float pX, float pY) {
        if(Math.abs(pX) < 0.02 ){
            pX = 0;
        }

        if(Math.abs(pY) < 0.02 ){
            pY = 0;
        }
        float pitchJoyControlMaxSpeed = 10;
        float rollJoyControlMaxSpeed = 10;

        mPitch = (float)(pitchJoyControlMaxSpeed * pX);

        mRoll = (float)(rollJoyControlMaxSpeed * pY);

        if (null == mSendVirtualStickDataTimer) {
            mSendVirtualStickDataTask = new SendVirtualStickDataTask();
            mSendVirtualStickDataTimer = new Timer();
            mSendVirtualStickDataTimer.schedule(mSendVirtualStickDataTask, 100, 200);
        }

    }

});

mScreenJoystickRight.setJoystickListener(new OnScreenJoystickListener() {

    @Override
    public void onTouch(OnScreenJoystick joystick, float pX, float pY) {
        if(Math.abs(pX) < 0.02 ){
            pX = 0;
        }

        if(Math.abs(pY) < 0.02 ){
            pY = 0;
        }
        float verticalJoyControlMaxSpeed = 2;
        float yawJoyControlMaxSpeed = 30;

        mYaw = (float)(yawJoyControlMaxSpeed * pX);
        mThrottle = (float)(verticalJoyControlMaxSpeed * pY);

        if (null == mSendVirtualStickDataTimer) {
            mSendVirtualStickDataTask = new SendVirtualStickDataTask();
            mSendVirtualStickDataTimer = new Timer();
            mSendVirtualStickDataTimer.schedule(mSendVirtualStickDataTask, 0, 200);
        }

    }
});

在这里,我们实现了一下功能:

1. 重写 setJoystickListeneronTouch() 方法,并过滤低于 0.02的 pXpY 变量的值。如果值太小,我们应该不会太频繁的发送虚拟杆数据到飞行控制器

2. 获取 pitch 和 roll 控制的最大速度,然后把它们存储到 pitchJoyControlMaxSpeedrollJoyControlMaxSpeed 变量。由于 pX 的值在 -1 (left) 和 1 (right) 之间, pY 的值在 -1 (down) 和 1 (up) 之间,我们使用 pitchJoyControlMaxSpeedrollJoyControlMaxSpeed 值相乘来更新 mPitchmRoll 的数据。这里我们以遥控器的模式2(美国模式)为例。

3. 最后,我们检查 mSendVirtualStickDataTimer 是否为null, 并通过调用 SendVirtualStickDataTask() 方法来创建它。然后创建 mSendVirtualStickDataTimer 并通过传递 mSendVirtualStickDataTask 变量,延迟0毫秒,后续执行间隔200毫秒这3个参数来调用它的 schedule(TimerTask task, long delay, long period) 方法去触发计时器 。

4. 同样的,实现 mScreenJoystickRight 变量的 setJoystickListener() 方法去更新 mYawmThrottle 的值,并调用计时器去发送虚拟杆数据到飞机的飞行控制器。

现在,当你控制左右操纵杆的时候,将发送模拟虚拟杆数据 (包括 Yaw, Pitch, RollVertical Throttle) 到飞机的飞行控制器。

最后,重写 onClick() 方法来实现可用和禁用虚拟杆控制按钮的点击操作:

@Override
  public void onClick(View v) {

     switch (v.getId()) {
        case R.id.btn_enable_virtual_stick:
            if (mFlightController != null){

                mFlightController.setVirtualStickModeEnabled(true, new CommonCallbacks.CompletionCallback() {
                    @Override
                    public void onResult(DJIError djiError) {
                        if (djiError != null){
                            showToast(djiError.getDescription());
                        }else
                        {
                            showToast("Enable Virtual Stick Success");
                        }
                    }
                });
            }
            break;

        case R.id.btn_disable_virtual_stick:
            if (mFlightController != null){
                mFlightController.setVirtualStickModeEnabled(false, new CommonCallbacks.CompletionCallback() {
                    @Override
                    public void onResult(DJIError djiError) {
                        if (djiError != null) {
                            showToast(djiError.getDescription());
                        } else {
                            showToast("Disable Virtual Stick Success");
                        }
                    }
                });
            }
            break;
        }
    }

这将调用 FlightController 的 enableVirtualStickControlMode() and disableVirtualStickControlMode() 方法来启用和禁用虚拟杆控制模式。

实现 DJISimulator

现在让我们来实现 DJISimulator 功能,为了更新mTextView 中的模拟器状态数据,我们需要在 initFlightController() 方法中实现 DJISimulator 的 setStateCallback() 方法:

private void initFlightController() {

    Aircraft aircraft = DJISimulatorApplication.getAircraftInstance();
    if (aircraft == null || !aircraft.isConnected()) {
        showToast("Disconnected");
        mFlightController = null;
        return;
    } else {
        mFlightController = aircraft.getFlightController();
        mFlightController.setRollPitchControlMode(RollPitchControlMode.VELOCITY);
        mFlightController.setYawControlMode(YawControlMode.ANGULAR_VELOCITY);
        mFlightController.setVerticalControlMode(VerticalControlMode.VELOCITY);
        mFlightController.setRollPitchCoordinateSystem(FlightCoordinateSystem.BODY);
        mFlightController.getSimulator().setStateCallback(new SimulatorState.Callback() {
            @Override
            public void onUpdate(final SimulatorState stateData) {
                new Handler(Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {

                        String yaw = String.format("%.2f", stateData.getYaw());
                        String pitch = String.format("%.2f", stateData.getPitch());
                        String roll = String.format("%.2f", stateData.getRoll());
                        String positionX = String.format("%.2f", stateData.getPositionX());
                        String positionY = String.format("%.2f", stateData.getPositionY());
                        String positionZ = String.format("%.2f", stateData.getPositionZ());

                        mTextView.setText("Yaw : " + yaw + ", Pitch : " + pitch + ", Roll : " + roll + "\n" + ", PosX : " + positionX +
                                ", PosY : " + positionY +
                                ", PosZ : " + positionZ);
                    }
                });
            }
        });
    }
}

在以上代码中,我们重写了 onUpdate() 方法来获取最新模拟器状态数据,然后调用 SimulatorStategetYaw(), getPitch(), getRoll(), getPositionX(), getPositionY() and getPositionZ() 方法来获取更新 yaw, pitch, roll, positionX, positionY 和 positionZ 的值,并在mTextView 中显示。

接下来,重写开关按钮的监听事件 mBtnSimulator.setOnCheckedChangeListener()的 的 onCheckedChanged() 方法:

mBtnSimulator.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (isChecked) {

            mTextView.setVisibility(View.VISIBLE);

            if (mFlightController != null) {

                mFlightController.getSimulator()
                        .start(InitializationData.createInstance(new LocationCoordinate2D(23, 113), 10, 10),
                                new CommonCallbacks.CompletionCallback() {
                            @Override
                            public void onResult(DJIError djiError) {
                                if (djiError != null) {
                                    showToast(djiError.getDescription());
                                }else
                                {
                                    showToast("Start Simulator Success");
                                }
                            }
                        });
            }

        } else {

            mTextView.setVisibility(View.INVISIBLE);

            if (mFlightController != null) {
                mFlightController.getSimulator()
                        .stop(new CommonCallbacks.CompletionCallback() {
                                    @Override
                                    public void onResult(DJIError djiError) {
                                        if (djiError != null) {
                                            showToast(djiError.getDescription());
                                        }else
                                        {
                                            showToast("Stop Simulator Success");
                                        }
                                    }
                                }
                        );
            }
        }
    }
});

在以上代码中,我们实现了以下功能:

1. 如果开关按钮 mBtnSimulator 被选中,则显示 mTextView 。接下来,如果 mFlightController 不是 null, 我们就调用 DJISimulator 的 start() 方法, 传一个 InitializationData.createInstance(new LocationCoordinate2D(23, 113), 10, 10) 参数说明LocationCoordinate2D(纬度,经度),更新频率,卫星数量) . 更多 DJISimulatorInitializationData 的详情在这里 Android API Reference.

2. 接下来,重写 start()onResult() 方法, 调用 showToast() 方法向用户显示启动模拟器的结果。

3. 同样的,如果切换按钮 mBtnSimulator 没有被选中,则调用 DJISimulator 的 stop() 方法停止模拟器。此外,重写 onResult() 方法并调用 showToast() 方法向用户显示停止模拟器的结果。

Takeoff 和 AutoLanding 功能(起飞和自动着陆)

最后,让我们在 onClick() 方法底部添加以下代码来实现 Take offLand 按钮的点击操作:

case R.id.btn_take_off:
    if (mFlightController != null){
        mFlightController.startTakeoff(
                new CommonCallbacks.CompletionCallback() {
                    @Override
                    public void onResult(DJIError djiError) {
                        if (djiError != null) {
                            showToast(djiError.getDescription());
                        } else {
                            showToast("Take off Success");
                        }
                    }
                }
        );
    }

    break;

case R.id.btn_land:
    if (mFlightController != null){

        mFlightController.startLanding(
                new CommonCallbacks.CompletionCallback() {
                    @Override
                    public void onResult(DJIError djiError) {
                        if (djiError != null) {
                            showToast(djiError.getDescription());
                        } else {
                            showToast("Start Landing");
                        }
                    }
                }
        );

    }

    break;

对于 "R.id.btn_take_off",我们调用 FlightController 的 startTakeoff() 方法向飞机发送起飞命令。同样的,对于 "R.id.btn_land" ,我们调用 startLanding() 方法发送自动着陆命令。这可以轻松实现。

在本教程中,我们已经走了很长的路,现在让我们构建并运行项目吧,把你的demo程序连接到 Mavic Pro(更多详情 Run Application ) ,然后检查一下我们目前实现的所有功能。

如果一切ok,你应该可以看到一些和下面的git动画一样的东西:

img

摘要

在本教程中,你已经学会了如何使用 DJISimulator 的特性基于虚拟杆控制输入的模拟环境中去模拟飞机的飞行行为,并实时显示模拟器状态(Yaw,Pitch,Roll,PosX,PosY and PosZ) 的改变。你还学习了如何使用虚拟杆控制向飞机发送虚拟杆飞行控制数据。

这个demo是一个使用 DJISimulator 的一个简单演示,为了获取更好的用户体验,你可以使用3D游戏引擎创建一个3D模拟环境,如 Unity3D ,在你的移动应用程序中展示模拟数据和飞机飞行行为(如DJI Go应用程序中的飞行模拟器)。

此外,DJISimulator 允许在持续集成环境中自动化测试(如 Jenkins ),它将帮助你处理基于 DJI-SDK 的程序测试。good luck!

上一篇下一篇

猜你喜欢

热点阅读