大疆文档(3)-开发流程

本节全篇为开发流程,内容较多,只记录android部分

开发流程(1)

预备知识

使用DJI Mobile SDK开发应用程序需要几个通用的和平台特定的先决条件。

生成

  • 了解如何去开发一个IOS或Android应用程序
  • 一个与DJI Mobile SDK兼容的DJI产品。兼容产品列表
  • 信用卡或电话号码用于大疆开发者注册验证(不收费)。
  • 至少一个兼容iOS或Android的移动设备。

注意: 对于iOS,可以使用两个移动设备来更轻松地进行调试和分析。

iOS

  • Xcode 7.0+或更高版本
  • iOS 8.1或更高版本的部署目标
  • iOS开发者帐户
  • 设备支持
    • iPhone 5s或更高版本
    • iPad Pro,iPad Air 2,iPad Mini 2或更高版本
    • iPod Touch 5或更高版本

Android

  • Android API等级19或更高
  • Android Studio 1.5或更高版本
  • 设备支持:Samsung S7, Samsung S8, Samsung tabs 705c, Samsung S6, Samsung S5, Samsung NOTE4, Samsung NOTE3, Google Pixel, Google Nexus 9, Google Nexus 7 II, Ascend Mate7, Huawei Mate 8, Nubia Z7 mini, SONY Xperia Z3, MI 3, MI PAD

注意:随着测试和开发的继续,支持更多的Android设备。

注册为DJI开发者并下载SDK

注册为开发者

注册一个DJI开发者账号在这里

在注册过程中,需要提供电子邮件信息和信用卡或电话号码以验证注册。所提供的任何信用卡信息仅用于验证,不会收取费用。

下载DJI Mobile SDK

从这里下载适用于iOS或Android的DJI Mobile SDK:http://developer.dji.com/mobile-sdk/downloads.

集成SDK到应用程序

下面的示例将DJI SDK导入一个新的iOS和Android项目。同样的步骤也可以用于集成到现有的应用程序中。

Xcode项目集成

详情

Android Studio 项目集成

截图使用 Android Studio 3.0

创建一个新项目

一个新的应用程序可以用来展示如何将DJI SDK集成到Android Studio项目中。

  • 打开 Android Studio 并且在初始屏幕上选择Start a new Android Studio project

  • New Project 框中:

    • Application name 设置为“ImportSDKDemo”。
    • Set the Company Domain and Package name to "com.dji.importSDKDemo".(注意:大疆文档这里的import是Import,改成小写即可,见下图)
img

注意: Package name 是生成App Key 所必需的标识字符串。下面的activity.javamanifest.xml和Gradle脚本代码假定包名为“com.dji.ImportSDKDemo”

  • Target Android Devices中:
    • 选择 Phone and Tablet
    • 选择 API 19: Android 4.4 (KitKat).
img
  • Add an Activity to Mobile 中选择 Empty Activity.

  • Configure Activity 中:

    • 设置 Activity Name: 为 "MainActivity".
    • 勾选 Generate Layout File
    • 设置 Layout Name: 为 "activity_main".
    • 点击完成
img
配置Grade脚本
  • 打开 build.gradle (Module: app)
AndroidConfigureGradleInitial
  • 更新内容如下:
apply plugin: 'com.android.application'

android {

    ...
    defaultConfig {
        ...
    }

    ...

    packagingOptions{
        doNotStrip "*/*/libdjivideo.so"
        doNotStrip "*/*/libSDKRelativeJNI.so"
        doNotStrip "*/*/libFlyForbid.so"
        doNotStrip "*/*/libduml_vision_bokeh.so"
        doNotStrip "*/*/libyuv2.so"
        doNotStrip "*/*/libGroudStation.so"
        doNotStrip "*/*/libFRCorkscrew.so"
        doNotStrip "*/*/libUpgradeVerify.so"
        doNotStrip "*/*/libFR.so"
        exclude 'META-INF/rxjava.properties'
    }
}

dependencies {
   ...
    compile ('com.dji:dji-sdk:4.9')
    provided ('com.dji:dji-sdk-provided:4.9')
}
  • 主要变更应为:

    • 添加 packagingOptions 以防止应用程序发生任何意外崩溃。
    • 添加 compileprovided 依赖来导入最新的DJI Android SDK Maven依赖。
    • 点击 Sync Now 并等待Gradle项目同步完成。

    note: 这里要注意的是,compile和provided会产生两个警告,声明作废:分别用implementation和compileOnly代替,本例还是继续跟随大疆文档进行,实际开发中注意修正。

AndroidConfigureGradleAfterChange
  • 双重检查 Maven依赖

    • 选择 File->Project Structure 来打开“Project Structure”窗口。然后选择 "app" 模块并且点击 Dependencies . 你应该看到最新的DJI SDK已经编译完成,并且提供了已经导入的依赖。
img
实现应用注册和SDK回调

右键点击com.dji.importSDKDemo,并选择New->Java Class创建一个新的Java类,并将其命名为“MApplication”。

createJaveClass

打开 MApplication.java 并替代如下内容:

package com.dji.importSDKDemo;

import android.app.Application;
import android.content.Context;

import com.secneo.sdk.Helper;

public class MApplication extends Application {

    @Override
    protected void attachBaseContext(Context paramContext) {
        super.attachBaseContext(paramContext);
        Helper.install(MApplication.this);
    }

}

这里我们重写attachBaseContext()方法来添加Helper.install(MApplication.this);这行代码。

注意: 由于现在需要在使用之前加载一些SDK类,所以加载过程由Helper.install()完成。开发者需要在使用任何SDK功能之前调用此方法。如果不这样做,将导致意外的崩溃。

AndroidImplementationMainActivity

打开 MainActivity.java

AndroidImplementationMainActivity

MainActivity类需要注册应用程序才能获得使用DJI Mobile SDK的授权。它还需要实现SDK期望的回调方法。

MainActivity类将首先被修改为包含几个类变量,包括“mProduct”,该对象表示连接到移动设备的DJI产品。

此外,onCreate方法将被修改为调用checkAndRequestPermissions方法来检查和请求运行时权限。此外,checkAndRequestPermissions方法将帮助调用startSDKRegistration()方法来注册应用程序。而且,重写onRequestPermissionsResult方法将帮助检查应用程序是否有足够的权限,如果有,调用startSDKRegistration()方法来注册应用程序。

现在,替换 MainActivity 类为:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getName();
    public static final String FLAG_CONNECTION_CHANGE = "dji_sdk_connection_change";
    private static BaseProduct mProduct;
    private Handler mHandler;

    private static final String[] REQUIRED_PERMISSION_LIST = new String[]{
            Manifest.permission.VIBRATE,
            Manifest.permission.INTERNET,
            Manifest.permission.ACCESS_WIFI_STATE,
            Manifest.permission.WAKE_LOCK,
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_NETWORK_STATE,
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.CHANGE_WIFI_STATE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.BLUETOOTH,
            Manifest.permission.BLUETOOTH_ADMIN,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.READ_PHONE_STATE,
    };
    private List<String> missingPermission = new ArrayList<>();
    private AtomicBoolean isRegistrationInProgress = new AtomicBoolean(false);
    private static final int REQUEST_PERMISSION_CODE = 12345;

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

        // When the compile and target version is higher than 22, please request the following permission at runtime to ensure the SDK works well.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            checkAndRequestPermissions();
        }

        setContentView(R.layout.activity_main);

        //Initialize DJI SDK Manager
        mHandler = new Handler(Looper.getMainLooper());

    }

    /**
     * Checks if there is any missing permissions, and
     * requests runtime permission if needed.
     */
    private void checkAndRequestPermissions() {
        // Check for permissions
        for (String eachPermission : REQUIRED_PERMISSION_LIST) {
            if (ContextCompat.checkSelfPermission(this, eachPermission) != PackageManager.PERMISSION_GRANTED) {
                missingPermission.add(eachPermission);
            }
        }
        // Request for missing permissions
        if (missingPermission.isEmpty()) {
            startSDKRegistration();
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            showToast("Need to grant the permissions!");
            ActivityCompat.requestPermissions(this,
                    missingPermission.toArray(new String[missingPermission.size()]),
                    REQUEST_PERMISSION_CODE);
        }

    }

    /**
     * Result of runtime permission request
     */
    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        // Check for granted permission and remove from missing list
        if (requestCode == REQUEST_PERMISSION_CODE) {
            for (int i = grantResults.length - 1; i >= 0; i--) {
                if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                    missingPermission.remove(permissions[i]);
                }
            }
        }
        // If there is enough permission, we will start the registration
        if (missingPermission.isEmpty()) {
            startSDKRegistration();
        } else {
            showToast("Missing permissions!!!");
        }
    }
}

DJISDKManagerregisterApp()方法有一个回调函数,它需要处理两个方法来处理APP注册结果,以及当连接到移动设备的产品发生变更时。

继续添加如下所示的startSDKRegistration()方法,并实现SDKManagerCallbackonRegister(), onProductDisconnect(), onProductConnect()onComponentChange()方法:

private void startSDKRegistration() {
    if (isRegistrationInProgress.compareAndSet(false, true)) {
        AsyncTask.execute(new Runnable() {
            @Override
            public void run() {
                showToast("registering, pls wait...");
                DJISDKManager.getInstance().registerApp(MainActivity.this.getApplicationContext(), new DJISDKManager.SDKManagerCallback() {
                    @Override
                    public void onRegister(DJIError djiError) {
                        if (djiError == DJISDKError.REGISTRATION_SUCCESS) {
                            showToast("Register Success");
                            DJISDKManager.getInstance().startConnectionToProduct();
                        } else {
                            showToast("Register sdk fails, please check the bundle id and network connection!");
                        }
                        Log.v(TAG, djiError.getDescription());
                    }

                    @Override
                    public void onProductDisconnect() {
                        Log.d(TAG, "onProductDisconnect");
                        showToast("Product Disconnected");
                        notifyStatusChange();

                    }
                    @Override
                    public void onProductConnect(BaseProduct baseProduct) {
                        Log.d(TAG, String.format("onProductConnect newProduct:%s", baseProduct));
                        showToast("Product Connected");
                        notifyStatusChange();

                    }
                    @Override
                    public void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent oldComponent,
                                                  BaseComponent newComponent) {

                        if (newComponent != null) {
                            newComponent.setComponentListener(new BaseComponent.ComponentListener() {

                                @Override
                                public void onConnectivityChange(boolean isConnected) {
                                    Log.d(TAG, "onComponentConnectivityChanged: " + isConnected);
                                    notifyStatusChange();
                                }
                            });
                        }
                        Log.d(TAG,
                                String.format("onComponentChange key:%s, oldComponent:%s, newComponent:%s",
                                        componentKey,
                                        oldComponent,
                                        newComponent));

                    }
                });
            }
        });
    }
}

最后,需要实现 notifyStatusChangeRunnableshowToast方法:

private void notifyStatusChange() {
    mHandler.removeCallbacks(updateRunnable);
    mHandler.postDelayed(updateRunnable, 500);
}

private Runnable updateRunnable = new Runnable() {

    @Override
    public void run() {
        Intent intent = new Intent(FLAG_CONNECTION_CHANGE);
        sendBroadcast(intent);
    }
};

private void showToast(final String toastMsg) {

    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(new Runnable() {
        @Override
        public void run() {
            Toast.makeText(getApplicationContext(), toastMsg, Toast.LENGTH_LONG).show();
        }
    });

}

为了让DJI SDK运行,应用程序必须被授权。

  • 打开 app 模块中的AndroidManifest.xml
AndroidManifest
  • package=com.dji.ImportSDKDemo 之后和 <application 之前插入:
<!-- Permissions and features -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature
    android:name="android.hardware.usb.host"
    android:required="false" />
<uses-feature
    android:name="android.hardware.usb.accessory"
    android:required="true" />

<!-- Permissions and features -->
  • application 元素开头添加 android:name=".MApplication"
<application
    android:name=".MApplication"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme" >
  • android:theme="@style/AppTheme"> 之后和 <activity android:name=".MainActivity">之前插入以下内容:
<!-- DJI SDK -->
<uses-library android:name="com.android.future.usb.accessory" />
<meta-data
    android:name="com.dji.sdk.API_KEY"
    android:value="Please enter your App Key here." /> // 这里替换为注册的App Key
<activity
    android:name="dji.sdk.sdkmanager.DJIAoaControllerActivity"
    android:theme="@android:style/Theme.Translucent" >
    <intent-filter>
        <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
    </intent-filter>
    <meta-data
        android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
        android:resource="@xml/accessory_filter" />
</activity>
<service android:name="dji.sdk.sdkmanager.DJIGlobalService" >
</service>
<!-- DJI SDK -->

生成App Key, 并替换 "Please enter your App Key here."

  • activity元素中插入android:configChanges="orientation"android:screenOrientation="portrait",如下图所示,防止activity在屏幕方向改变时重启,并将activity的屏幕方向设置为竖屏模式:
<activity android:name=".MainActivity"
          android:configChanges="orientation"
          android:screenOrientation="portrait">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
运行导入SDK Demo

ImportSDKDemo 项目现在可以运行了。也可以从 Github 下载这个项目的示例代码。

由于此应用程序只检查注册,而不直接与产品交互,因此不需要将任何产品连接到应用程序即可运行。因此,该应用程序既可以在移动设备上运行(连不连接DJI产品都行),也可以在Android模拟器中运行。应用程序需要网络连接才能成功地执行注册。(不知道为什么我用模拟器注册失败,sdk中间件jni报错,真机注册成功)

如果App Key生成正确,且Android模拟器或移动设备具备网络连接,则应看到:

img
FFmpeg License

DJI Android SDK是动态链接到LGPLv2.1许可的未修改的FFmpeg库。Github提供了这些FFmpeg库的源代码、编译说明和LGPL v2.1许可。Github提供了这些FFmpeg库的源代码、编译说明和LGPL v2.1许可。

运行APP

准备产品

应检查每个产品的用户手册以理解完整的产品设置(访问http://www.dji.com并导航到每个产品的下载页)。本节详细介绍了一些需要记住的要点。

充电电池

通常,在运行应用程序之前,应对产品的所有电池充电以获得最佳体验。这可能包括飞机电池,遥控器电池,手持云台电池和飞机安装的云台电池(用于Ronin MX)。当电池电量过低时,飞机可能会在应用程序中更早的返航或着陆,或者根本不起飞。

激活产品

在首次使用之前,任何新产品都需要通过DJI GO激活。DJI GO可在 iOS App StoreGoogle Store 上使用,可用于激活产品。

重定向到DJI Go 应用程序

如果SDK应用程序需要重定向到DJI Go Apps来做像激活DJI产品这样的操作,你可以使用以下代码来实现它:

iOS
  • 重定向到DJI Go 4 App:使用URL方案 "djiVideoNew://"
  • 重定向到DJI Go App:使用URL方案 "djiVideo://"
Android
  • 重定向到DJI Go 4 App:
Intent launchIntent = getPackageManager().getLaunchIntentForPackage("dji.go.v4");
if (launchIntent != null) { //null pointer check in case package name was not found 空指针检查以防包名没被找到
    startActivity(launchIntent); 
}
  • 重定向到DJI Go App:
Intent launchIntent = getPackageManager().getLaunchIntentForPackage("dji.pilot");
if (launchIntent != null) { //null pointer check in case package name was not found
    startActivity(launchIntent);
}

有关更多详细信息,请查看Github示例代码: iOS SDK Github Sample, Android SDK Github Sample.

升级产品固件

飞机、遥控器和/或手持控制器固件应在开始应用程序测试和调试之前更新到最新版本。不同的产品有时会有不同的检查固件版本和升级固件的过程。在 http://www.dji.com 中每个产品页的 Downloads 模块都有升级固件的说明。

遥控器飞行模式开关

对于飞机,遥控器FAP或ASP飞行模式开关需要处于特定位置才能接收改变飞行方向和自动飞行的SDK命令。遥控器和飞机有时可以互换,因为FAP / ASP开关配置有多种选择。

Aircraft Remote Controller Switch
P3, Inspire (all models) P3, Inspire (all models) F
P3, Inspire (all models) P4 A
P4 P3, Inspire (all models) P
P4 P4 P

网络连接

任何SDK应用程序在首次运行时都需要互联网连接才能向DJI注册并获得使用SDK的授权。首次成功注册后,授权将存储在本地,且注册时无需网络连接。

连接移动设备并运行应用程序

移动设备和产品之间有几种连接配置:

  • 移动设备 -> USB -> 遥控器 -> Lightbridge / OcuSync -> 飞机
  • 移动设备 -> WiFi -> 遥控器 -> WiFi - >飞机
  • 移动设备 -> WiFi -> 手持云台

有几种方法可以初始化所有产品并运行应用程序。下面给出USB和WiFi连接场景的示例。

USB连接程序

Mavic Pro,Phantom 4,Phantom 4 Professional,Phantom 3 Professional,Phantom 3 Advanced,Inspire系列,Matrice系列:

打开遥控器。

  • 打开飞机并等待遥控器与飞机连接。
  • 使用 Lightning(iOS)或 USB(Android)导线将 iOS / Android 移动设备连接到遥控器。
  • 在移动设备上运行应用程序。

注意:

如果使用Android设备,DJI遥控器需要支持AOA . 所有最新版本的固件都支持AOA。如果Sample Application与Android设备连接,则会支持AOA,会出现类似下面的对话框:

dialog

要了解如何更改USB附件的默认应用程序,请查看以下两个常见问答:Android Device, Samsung Device.

WiFi连接程序

Phantom 3 Standard,Phantom 3 4K,Spark:

打开遥控器

  • 将移动设备连接到遥控器创建的WiFi网络。
  • 打开飞机并等待遥控器与飞机连接。
  • 在移动设备上运行应用程序。

Osmo,Mavic Pro,Spark:

  1. 打开产品(Osmo或飞机)。
  • 将移动设备连接到产品创建的WiFi网络。
  • 在移动设备上运行应用程序

测试、分析和调试

应用程序开发需要大量的测试、分析和调试。DJI提供的工具包括飞机模拟器、无线桥接app和远程日志功能,使开发更快更方便。

飞行模拟器

DJI飞机产品包括一个驻留在飞行控制器中的模拟器,可以:

  • 从遥控器(手动飞行)或应用程序(SDK命令)获取飞机控制输入
  • 基于输入在模拟环境中模拟飞机行为
  • 基于模拟行为输出飞机状态信息

这使得手动和自动飞行都可以模拟,而无需实际驾驶飞机。

DJI提供Windows和Mac工具,可用于初始化模拟器,并根据模拟器提供的状态信息显示飞机的行为:

  • DJI Assistant 2 ( Windows Mac ) 用于Spark,Mavic Pro,Phantom 4系列和Matrice系列等新型飞机。
  • DJI PC Simulator ( Windows ) 用于Phantom 3系列,Inspire 1系列飞机。

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

DJI Assistant 2模拟器

DJI Assistant 2工具是专门为SDK开发人员构建的,可以初始化、终止并提供在DJI飞机飞行控制器中运行的飞机模拟器的可视化。DJI Assistant 2通过USB连接到飞机。

  • 支持大疆产品:Spark、Mavic Pro、Matrice系列、Phantom 4系列、Inspire 2。
  • 支持的操作系统:Mac OS X 10、Windows 7、Windows 8和Windows 8.1

注意: Windows 10不受官方支持,但通常可以工作。

安装和设置

Mac

  • 从Mac下载 DJI Assistant 2
  • 双击驱动程序并按照说明安装它。
  • 打开下载的 DMG 文件。
  • Assistant.app 拖进系统的 Applications 文件夹。

Windows

  • 从Windows下载 DJI Assistant 2
  • 运行安装程序
  • 按照说明安装
  • 在安装过程中,确认安装程序的请求。
使用 DJI Assistant 2

在启动时,将出现一个请求将DJI Assistant 2连接到飞机的窗口。

assistantLaunch

通过 USB连接线 连接到Mac或PC的飞机。

打开遥控器,然后打开飞机。几秒钟后,应用程序将检测到飞机。

在连接设备页选择 "Mavic Pro" ,然后选择左侧的 Simulator 选项卡。应该看到以下屏幕:

P4Connected

Open 按钮,输入所需的起始纬度和经度以及所需的风速。

按下 Start Emulating 按钮。将会显示连接的产品,以及一些位置和速度状态信息。

simulatorOld

Note: 正向世界坐标系X,Y和Z分别为北,东和上方向。

使用遥控器起飞和飞行以试验模拟器。

视图角度可以通过在可视化窗口中左键单击和拖动来更改。在窗口内滚动可以缩放。

飞行时,可以通过右击可视化并选择 Setup 来追踪飞行路径。

setupButton

然后在模拟器UI配置选项卡下选择 show trace 显示飞行轨迹,如下图所示:

showTrace

然后将飞行路径跟踪添加到可视化中。

simulator
DJI PC 模拟器

DJI PC模拟器工具是专门为SDK开发人员开发的,可以对DJI飞机飞行控制器中运行的飞机模拟器进行初始化、终止和可视化。DJI PC模拟器工具通过USB连接到飞机。

  • 支持大疆产品:Phantom 3系列、Inspire 1系列。
  • 支持的操作系统:Windows 7、Windows 8、Windows 8.1

Note: Windows 10不受官方支持,但通常可以工作。

安装和设置

  • 下载 DJI PC模拟器安装程序和用户手册 以及 WIN驱动安装程序http://developer.dji.com/mobile-sdk/downloads/
  • 运行 Win Driver Installer
    • 对于早期产品兼容性,会出现一个显示消息内容为 Please power on MC and connect it to PC via USB! 的对话框。
    • 现在不需要任何操作,按 Yes 继续。
    • 按照其余的安装步骤操作。
  • 运行DJI PC Simulator Installer
    • 按照安装步骤完成安装。

使用 DJI PC 模拟器

DJI PC Simulator 既可以运行在Windows PC上,也可以运行在Mac的虚拟机上(如Parallels或VMWare)。

首先使用USB将Windows PC连接到飞机并打开飞机。

启动 DJI PC Simulator 来配置和初始化飞机模拟器。设置经度和经度进行模拟。

Config

Note: 如果经纬度太接近或进入GEO区域,飞机将无法起飞。

如果飞机处于开机状态并与PC机连接,则序列号应显示在 ** SN:** 文本视图中。

选择 Log Settings 选项卡下的 show log window 以显示日志窗口。

showLog

返回 Simulator Control 选项卡,按 Start Simulation 启动飞机模拟器。此时,飞机将在不实际启动电机的情况下模拟飞行。

Display Simulation 以启动可视化。

使用遥控器起飞和飞行以试验模拟器。

可视化将显示连接的产品(在本例中为Inspire 1),以及一些位置和速度状态信息。

display

Note: 正向世界坐标系的X,Y和Z分别为北,东和上方向。

视图角度可以通过在可视化窗口中左击并拖动来更改。在窗口内滚动可以缩放。

zoomIn

While flying, the flight path can be traced by right clicking on the visualization and selecting Setup.

飞行时,可以通过右击可视化并选择 Setup 来跟踪飞行路径。

simulatorSetup

然后在模拟器UI配置选项卡下选择 show trace 以显示飞行轨迹,如下所示:

showTrace

然后飞行路径轨迹将添加到可视化中。

flightTrace

Simulator Config 窗口中,可以按下 Stop Simulation 来停止模拟。

重要提示: 要在中途停止Waypoint Mission,请从应用程序中停止任务,然后停止模拟器。否则,模拟器可以在重启时继续运行先前的Waypoint Mission。

有关更多 DJI PC Simulator 的信息,请在查看下载的 DJI PC Simulator 中包含的用户手册pdf文件

持续集成模拟

DJI Assistant 2DJI PC Simulator 都提供飞机模拟器的可视化,这需要PC或Mac连接到飞机。

如果不需要可视化,DJI SDK可用于启动和停止模拟器。这意味着可以在没有飞机连接到Mac或PC的情况下执行模拟,从而允许在连续集成环境中进行自动测试。

DJIFlightController 中的 DJISimulator 类被用于控制模拟。该类提供以下功能:

  • 启动和停止模拟
  • 使用GPS定位进行播放模拟 Seed the simulation with a GPS location
  • 检索飞机对于世界的状态信息。

在项目中使用模拟器提供示例代码:iOS | Android.

无线桥接App

对于Android和iOS,当移动设备通过USB线直接连接到Android Studio或Xcode时,应用程序开发最有效率。

然而,一些DJI飞机需要飞机的遥控器和移动设备之间的直接连接。这意味着应用程序无法通过USB直接连接到开发环境。

BridgeAppNeeded

对于Android,ADB通过WiFi可以实现实时开发,但iOS没有这样的选项。

因此,DJI提供无线桥接App或 Bridge App

  • Bridge App直接连接到遥控器。
  • 运行开发者的应用程序的移动设备已连接到Mac。
  • SDK将所有飞机通信从USB重新路由到与Bridge App设备的WiFi连接。
BridgeApp

Note: 如果只有一个移动设备可用,Bridge App也可以在iOS模拟器上运行。在这种情况下,移动设备将承载 bridge app,而开发者应用程序在iOS模拟器上运行。

SDK Bridge App由DJI提供,可以从 Apple App Store 下载。

使用 DJI Bridge App 的教程 here.

远程日志

在现场测试应用程序时,通常需要某种形式的日志记录来理解行为。

对于iOS,可以设置DJI Mobile SDK来允许远程日志记录。如果移动设备有网络连接,则可以将在飞行期间生成的消息记录到远程服务器。

这里有一个描述如何使用远程日志的教程。 here.

部署

使用DJI Mobile SDK部署Android应用程序不需要任何典型流程之外的额外步骤。

然而iOS应用程序需要适当的Xcode配置。如果支持的DJI产品是MFi附件,还需要MFi附件授权。

详情点击

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容

  • 相关度较低的略,提取了与安卓相关的文档进行翻译,以便于加深理解和方便以后的翻阅,本节包括包括介绍,立即开始,概念理...
    世外大帝阅读 2,162评论 1 1
  • 专业考题类型管理运行工作负责人一般作业考题内容选项A选项B选项C选项D选项E选项F正确答案 变电单选GYSZ本规程...
    小白兔去钓鱼阅读 8,981评论 0 13
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • 我还是决心,宁可被毁灭,也不要被打败。 什么东西都不能和爱情相比。 有时我认真怀疑,爱情究竟有什么好的? 我们说了...
    吴启央阅读 319评论 8 2
  • 小时候,眼力好 如果没有山的阻隔 仿佛可以望到天边 常常憧憬着 远方的世界 会是更精彩的存在么 小时候,天蓝又蓝 ...
    Annie大讲堂阅读 143评论 0 1