美文网首页程序员
大疆文档(8)-Android教程-模拟器App

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

作者: 世外大帝 | 来源:发表于2019-04-15 10:43 被阅读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 依赖

    • 创建名为 DJISimulatorDemo 的新项目
    • 包名 com.dji.simulatorDemo
    • 最低版本 API 19: Android 4.4 (KitKat)
    • 选择 "Empty Activity" 然后其他默认

    在我们之前的教程中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
    • 如果demo程序和 Mavic Pro 连接成功,你应该可以看到 title 内容更新为 "MavicPro Connected"。
    • 按下 Enable Virtual Stick 按钮可以启动虚拟杆控制,然后按 Start Simulator 就可以开启模拟器了。
    • 此外,按 Take Off 按钮可以向飞机发送起飞命令, 如果命令执行成功,你可以看到 PosZ 值开始改变,意味着飞机在上升。
    • 现在你可以拖动左右虚拟杆来模拟飞行。
    • 最后,按 Land 按钮可以让飞机开始自动着陆,一旦完成,你就会发现 PosZ 的值变成 "0.00" 了。按 Stop Simulator 按钮停止模拟器,按 Disable Virtual Stick 可以禁用虚拟杆控制。

    摘要

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

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

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

    相关文章

      网友评论

        本文标题:大疆文档(8)-Android教程-模拟器App

        本文链接:https://www.haomeiwen.com/subject/xwgywqtx.html