当前位置: 首页 > news >正文

大疆无人机 MobileSDK(遥控器/手机端)开发 v4版<1>

大疆无人机飞控开发

  • 大疆无人机
  • SDK开发包
    • 功能概述
    • 飞行控制
    • 相机
    • 实时视频流
    • 传感器数据
    • 下载媒体文件
    • 遥控器,电池和无线链路
    • 连接应用程序和产品
  • v4版sdk 二次开发
    • 注册成为DJI开发者
    • 生成 App Key
    • Android 示例代码配置
    • Android Studio项目集成
      • 创建一个新的应用
      • 配置Gradle 脚本
      • 实现应用注册和SDK回调

大疆无人机

刚刚结束了项目交付,趁热打铁分享一下这次遇到的新东西。首先了解一下大疆的无人机,它大致可以分为三级。

  • 入门级:适合新手,没事干在野外飞一飞拍拍风景啥的。操作也简单,基本上看飞行教程都能懂,也不需要太高的专业性,飞机也相对较小安全系数相对较高。如:御2系列的一些飞机。

  • 消费级:形体上会比入门级的大一点,但是飞机搭载了一些高精度的东西,比如RTK、高精度摄像头、红外镜头等。这类飞机则需要飞手具备一定的专业知识,并且需要考取大疆的初级飞手证书才能上手飞行。如:精灵系列、悟系列的一些飞机。

  • 专业级:形体上更大,操作不当会出现一些严重后果。它的优势在于高续航、高精度定位、热成像镜头、搭载第三方喊话器等。一般用于大型工程作业,使用这个级别的飞机则需要考取大疆专业飞手证书,一般这个会在你购买专业级飞机的时候赠送你培训课程,一般全部听完就能考过。这类飞机的典型代表有:M30系列、M300系列。

SDK开发包

大疆的SDK开发包目前分为两个大版本:

1. v4版

Mobile SDK是一款软件开发套件,旨在让开发者能够访问DJI无人机和手持相机产品的丰富功能。该SDK通过兼顾更底层的功能,诸如飞行稳定,电池管理,信号传输和通信等,简化了应用程序开发的过程。这样,开发者就不需要具备丰富的机器人或嵌入式系统背景知识,而可以专注于DJI产品相关的行业应用开发。

该SDK包括:

  • 可导入Android或iOS应用程序的库/框架,用于访问DJI产品的功能
  • 飞行模拟器和可视化工具
  • 适用于iOS的调试工具和远程logger
  • 示例代码和教程
  • 开发者指南和API文档

功能概述

开发者可以通过SDK访问许多DJI产品的功能。开发者可以实现自主飞行,控制相机和云台,接收实时视频图传和传感器数据,下载保存好的媒体文件,以及监听其他组件的状态。

飞行控制

Mobile SDK提供三种控制无人机飞行的方式:

手动操控: 用户使用遥控器操控无人机,而SDK支持监控实时视频流和传感器数据。
虚拟摇杆命令: SDK支持产生模拟遥控器摇杆的控制指令。
智能任务: 方便,易于实现无人机的高级控制。例如,可以通过航点任务,让无人机按预定义的飞行路径飞行。
虚拟摇杆命令和智能任务允许对DJI无人机进行简单而功能强大的自主飞行控制。

相机

相机和云台的功能都支持编程调用, 例如:

相机模式: 视频和静态图像拍摄
曝光: 快门,ISO,光圈和曝光补偿均支持定制,以实现最大的灵活性
图像参数: 屏幕长宽比,对比度,色相,清晰度,饱和度和滤镜
视频参数: 分辨率和帧频
方向: 使用云台时,相机的朝向和运动可以自动控制

实时视频流

开发者可以通过Mobile SDK获取无人机主摄像头的实时视频流。即使摄像头正在将图像或视频捕获到存储介质中,也可以获取实时视频流。

传感器数据

开发者可以通过SDK获得丰富的传感器数据。GPS位置,指南针,气压计,飞行速度和海拔高度都是通过Mobile SDK获取的一些传感器数据,频率最高可达10 Hz。

下载媒体文件

开发者通过Mobile SDK可以查看和下载保存在相机存储介质(SD卡或固态硬盘)中的照片和视频。预览图和完整的图像数据都可以被访问。

遥控器,电池和无线链路

遥控器,电池和无线链路都可以通过SDK进行访问。通常,这些组件会提供相关的状态信息,但开发者也可以对它们进行一些控制。

连接应用程序和产品

下图说明了Mobile SDK如何与移动应用程序进行融合以及如何与DJI飞行器进行连接。
在这里插入图片描述
对于手持摄像机产品,遥控器已替换为手持控制器,并且没有飞行器或其他无线链路。

移动应用程序由Mobile SDK,平台SDK(iOS或Android)构建而成,并在移动设备(Apple iPhone,iPad,Nexus手机,Nexus平板电脑等)上运行。

移动设备可以通过WiFi无线连接到DJI产品上,也可以通过USB线缆连接到DJI产品上。

2. v5版
v5版现在只适用于M30、M300系列,目前还在持续更新,因为是新版的SDK,大疆的工程师也是在不断地再完善里面的内容,这里就不详细说了,下篇文章会详细说这个v5版的SDK。

v4版sdk 二次开发

多的不说少的不唠,上主菜。“工欲善其事,必先利其器”,首先准备好开发软件,因为我们使用的是Android版的SDK所以开发软件我们使用Android Studio,本人使用的是Android Studio Fox版,版本之间感觉都一样没有什么开发上的区别。准备好工具之后,先去大疆无人机的开发者官网注册一个开发者账号,并且注册好自己的应用,拿到sdk的专用Key值,申请的方法大疆官网有我就不赘述了。给大家个地址【大疆开发者官网】自己看吧,挺简单的。

注册成为DJI开发者

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

本指南假定您使用 Xcode 7.3 以及 Android Studio 2.1.1 以上版本。

生成 App Key

每个应用程序都需要一个唯一的应用程序密钥(App Key)来初始化SDK。

要创建一个应用程序App Key:

请访问DJI开发者网站的 开发者中心

  • 选择左侧栏的 "应用 "。
  • 选择右侧的 “创建应用” 按钮。
  • 输入应用程序的名称, 开发平台, Package Name,分类和描述信息。
  • 会收到一封应用程序激活邮件,以完成App Key的生成。
  • 可以在开发者中心中找到AppKey,复制粘贴到应用程序配置中。

Android 示例代码配置

下载或者克隆Github上的Android示例代码工程。

在Android Studio中打开项目工程,将生成的App Key字符串粘贴到 “AndroidManifest.xml” 文件中 “com.dji.sdk.API_KEY” meda-data element下的 android:value。

<!--ADD API_KEY HERE and make sure youare connected to the Internet beforethe app is launched
-->
<meta-dataandroid:name="com.dji.sdk.API_KEY"android:value="" />

Android Studio项目集成

本节中的屏幕截图是使用Android Studio 4.1生成的。

创建一个新的应用

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

  • 打开Android Studio,然后在初始屏幕上选择Start a new Android Studio project

在这里插入图片描述

  • 在 New Project 界面:
    • 设置 Application name 为 “ImportSDKDemo”。
    • 设置 Company Domain 和Package name 为 “com.dji.ImportSDKDemo”。

在这里插入图片描述

注意: Package name是 生成App Key 所需的标识字符串。在这个工程中Package name为“com.dji.ImportSDKDemo”

  • 在 Target Android Devices 界面:

    • 选择 Phone and Tablet 尺寸。
    • 选择API 23:Android 6.0 (Marshmallow)。
      在这里插入图片描述
  • 在 Add an Activity to Mobile 界面选择 Empty Activity。

在这里插入图片描述

  • 在Configure Activity 界面:
  • 设置 Activity Name: 为 “MainActivity”。
  • 确认勾选Generate Layout File 。
  • 设置Layout Name: 为"activity_main"。
  • 点击Finish 。
    在这里插入图片描述

配置Gradle 脚本

  • 在Gradle Scripts 中双击 build.gradle (Module: app)
    在这里插入图片描述

使用以下内容进行更新:

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"doNotStrip "*/*/libDJIFlySafeCore.so"doNotStrip "*/*/libdjifs_jni.so"doNotStrip "*/*/libsfjni.so"exclude 'META-INF/rxjava.properties'}
}dependencies {...implementation('com.dji:dji-sdk:4.15', {exclude module: 'library-anti-distortion'})compileOnly 'com.dji:dji-sdk-provided:4.15
}
  • 主要变更为:

  • 添加 packagingOptions以防止应用程序意外崩溃。

  • 添加compile和provided依赖项以导入最新的DJIAndroid SDK Maven依赖项。
    在这里插入图片描述

    • 选择 Tools -> Android -> Sync Project with Gradle Files 然后等待Gradle项目同步完成。
  • 再次确认 Maven 依赖

    • 在Android Studio菜单中选择File->Project Structure,以打开"Project Structure"界面。然后选择“app”模块,然后单击Dependencies选项卡。
      在这里插入图片描述

实现应用注册和SDK回调

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

在这里插入图片描述

打开MApplication.java文件,并将内容替换为以下内容:

package com.dji.importSDKDemo;import android.app.Application;
import android.content.Context;import com.secneo.sdk.Helper;public class MApplication extends Application {@Overrideprotected void attachBaseContext(Context paramContext) {super.attachBaseContext(paramContext);Helper.install(MApplication.this);}
}
  • 在这里,重写了attachBaseContext()方法,添加了Helper.install(MApplication.this);代码。

注意:由于某些SDK类现在需要在使用之前进行加载,因此加载过程由Helper.install()完成。开发人员需要在使用任何SDK功能之前调用此方法, 否则可能会导致意外崩溃。

在这里插入图片描述

修改完成后需要在AndroidManifest中 配置 Application name。
在这里插入图片描述

双击app模块中的MainActivity.java。
在这里插入图片描述

MainActivity类需要注册应用程序以获得使用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;@Overrideprotected 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 ManagermHandler = new Handler(Looper.getMainLooper());}/*** Checks if there is any missing permissions, and* requests runtime permission if needed.*/private void checkAndRequestPermissions() {// Check for permissionsfor (String eachPermission : REQUIRED_PERMISSION_LIST) {if (ContextCompat.checkSelfPermission(this, eachPermission) != PackageManager.PERMISSION_GRANTED) {missingPermission.add(eachPermission);}}// Request for missing permissionsif (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*/@Overridepublic void onRequestPermissionsResult(int requestCode,@NonNull String[] permissions,@NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);// Check for granted permission and remove from missing listif (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 registrationif (missingPermission.isEmpty()) {startSDKRegistration();} else {showToast("Missing permissions!!!");}}
}

DJISDKManager的registerApp()方法具有一个回调,该回调需要处理两种方法:
一、用于处理应用程序注册结果。
二、用于通知硬件产品和移动设备的连接变更。

继续添加如下所示的 startSDKRegistration() 方法,并实现 onRegister(), onProductDisconnect(), onProductConnect(), onComponentChange(), onInitProcess() and onDatabaseDownloadProgress() 和SDKManagerCallback方法:

private void startSDKRegistration() {if (isRegistrationInProgress.compareAndSet(false, true)) {AsyncTask.execute(new Runnable() {@Overridepublic void run() {showToast("registering, pls wait...");DJISDKManager.getInstance().registerApp(MainActivity.this.getApplicationContext(), new DJISDKManager.SDKManagerCallback() {@Overridepublic 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());}@Overridepublic void onProductDisconnect() {Log.d(TAG, "onProductDisconnect");showToast("Product Disconnected");notifyStatusChange();}@Overridepublic void onProductConnect(BaseProduct baseProduct) {Log.d(TAG, String.format("onProductConnect newProduct:%s", baseProduct));showToast("Product Connected");notifyStatusChange();}@Overridepublic void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent oldComponent,BaseComponent newComponent) {if (newComponent != null) {newComponent.setComponentListener(new BaseComponent.ComponentListener() {@Overridepublic 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));}@Overridepublic void onInitProcess(DJISDKInitEvent djisdkInitEvent, int i) {}@Overridepublic void onDatabaseDownloadProgress(long l, long l1) {}});}});}
}

最后需要实现 notifyStatusChange, Runnable 和 showToast 方法:


private void notifyStatusChange() {mHandler.removeCallbacks(updateRunnable);mHandler.postDelayed(updateRunnable, 500);
}private Runnable updateRunnable = new Runnable() {@Overridepublic 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() {@Overridepublic void run() {Toast.makeText(getApplicationContext(), toastMsg, Toast.LENGTH_LONG).show();}});}

必须授予应用程序权限,DJI SDK才能运行。

  • 双击 app 模块中的 AndroidManifest.xml 。

在这里插入图片描述

在 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-featureandroid:name="android.hardware.usb.host"android:required="false" />
<uses-featureandroid:name="android.hardware.usb.accessory"android:required="true" /><!-- Permissions and features -->
  • 在 application 元素的开发添加 android:name=“.MApplication” :
<applicationandroid: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”> 之后, 之前插入如下代码:
<!-- DJI SDK -->
<uses-library android:name="com.android.future.usb.accessory" />
<meta-dataandroid:name="com.dji.sdk.API_KEY"android:value="Please enter your App Key here." />
<activityandroid: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-dataandroid:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"android:resource="@xml/accessory_filter" />
</activity>
<service android:name="dji.sdk.sdkmanager.DJIGlobalService" >
</service>
<!-- DJI SDK -->
  • 如下所示,在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>

生成App Key, 然后用App Key 字符串替换AndroidManifest.xml文件内Please enter your App Key here. 字段。

相关文章:

大疆无人机 MobileSDK(遥控器/手机端)开发 v4版<1>

大疆无人机飞控开发 大疆无人机SDK开发包功能概述飞行控制相机实时视频流传感器数据下载媒体文件遥控器&#xff0c;电池和无线链路连接应用程序和产品 v4版sdk 二次开发注册成为DJI开发者生成 App KeyAndroid 示例代码配置Android Studio项目集成创建一个新的应用配置Gradle 脚…...

mysql数据库之事务

1.事务的概念 事务是一种机制、一个操作序列&#xff0c;包含了一组数据库操作命令&#xff0c;并且把所有的命令作为一个 整体一起向系统提交或撤销操作请求&#xff0c;即这一组数据库命令要么都执行&#xff0c;要么都不执行。 事务是一个不可分割的工作逻辑单元&#xf…...

安装运行Hyperf

安装运行Hyperf 上回讲到&#xff0c;我们对一个普通的 Laravel 框架进行了改造&#xff0c;让它可以在 Swoole 环境下使用&#xff0c;不过其中会有很多问题可能我们一时考虑不到&#xff0c;就会造成程序的稳定性出现问题。那么&#xff0c;今天我们就来学习一个原生的 Swoo…...

回收站文件恢复,分享4个巧妙解决方法!

案例&#xff1a;回收站文件怎么恢复 【清理电脑时一不小心清空了我的回收站&#xff0c;有朋友知道该怎么恢复吗&#xff1f;急急急&#xff01;】 回收站对于电脑用户来说&#xff0c;可以带来很多的方便&#xff0c;能让用户能够在删除文件后将其恢复。但是&#xff0c;有…...

CTF权威指南 笔记 -第三章汇编基础-3.2-x86/x64汇编基础

这节介绍PC最常见的架构 x86和扩展 x64框架 CPU操作模式 对x86处理器而言 有三个最主要的保护模式 保护模式 实地址模式 系统管理模式还有一个保护模式的子模式 虚拟8086模式 保护模式 保护模式是处理原生状态 这个时候所有指令和特性都是可以使用的 分配给程序的独立内…...

争夺汽车芯片「高地」

一直以来&#xff0c;汽车芯片无论是工艺制程&#xff0c;还是新技术的导入&#xff0c;都要落后消费类产品几年时间。不过&#xff0c;如今&#xff0c;随着汽车智能化进一步推动汽车制造商与上游芯片设计公司、晶圆代工厂的紧密互动&#xff0c;历史即将翻篇。 同时&#xf…...

SuperMap GIS基础产品三维GIS FAQ集锦(2)

SuperMap GIS基础产品三维GIS FAQ集锦&#xff08;2&#xff09; 【WebGL】桌面对三维缓存设置了最大最小可见高度&#xff0c;在iServer发布三维服务并进行预览是可以看到该效果的&#xff0c;但在前端代码打开该服务&#xff0c;最大最小可见高度效果丢失&#xff0c;请问怎…...

11.streamFile

1.Stream流 1.1体验Stream流【理解】 案例需求 按照下面的要求完成集合的创建和遍历 创建一个集合&#xff0c;存储多个字符串元素把集合中所有以"张"开头的元素存储到一个新的集合把"张"开头的集合中的长度为3的元素存储到一个新的集合遍历上一步得到的集…...

如何裁剪图片大小尺寸?

如何裁剪图片大小尺寸&#xff1f;平时我们在工作或者学习的时候&#xff0c;会经常需要将图片上传到不同的网站或者平台上&#xff0c;然而上传的时候经常会受到尺寸的限制&#xff0c;有时候尺寸太大就需要变小&#xff0c;为了确保上传成功&#xff0c;我们需要将图片进行裁…...

深度学习笔记之梯度下降、反向传播与内置优化器

文章目录 1. 梯度下降法2. 反向传播算法3. PyTorch内置的优化器3.1 SGD优化器3.2 RMSprop优化器3.3 Adam优化器 1. 梯度下降法 笔者往期的机器学习笔记&#xff1a; 机器学习之梯度下降算法 梯度下降法是一种致力于找到函数极值点的算法。 所谓“训练”或“学习”就是改进…...

Visual Studio 2022 搭建GLFW OpenGL开发环境

最近工作需要 需要写一个全景的视频播放器 网上搜了下大概解决方案是 ffmpegopengl b站有很多视频 按照视频 搭建了OpenGL的开发环境 先去GLFW的网站下载 windows平台的库文件 为什么使用GLFW 因为GLFW是跨平台的 我下的是64位版本解压后有目录如下 包含了动态库和静态…...

四元数快速入门【Quaternion】

四元数&#xff08;Quaternion&#xff09;是用于旋转和拉伸向量的数学运算符。 本文提供了一个概述&#xff0c;以帮助理解在空间导航等应用程序中对四元数的需求。 推荐&#xff1a;用 NSDT场景设计器 快速搭建3D场景。 可以通过多种方式在空间中准确定位、移动和旋转物体。 …...

为什么我们要使用向量化运算

问题背景 如果你是matlab用户&#xff0c;你一般都会使用向量化运算进行编程。原因也许很简单&#xff0c;因为matlab针对向量化运算在底层做了深度优化&#xff0c;尤其是针对矩阵乘法调用了MKL之类的高度优化的第三库来加速。所以我们在推演算法的阶段&#xff0c;尽量的以向…...

Makefile零基础教学(一)初识makefile

从这篇文章开始就开始进入 Makefile 的零基础教程&#xff0c;相信只要看了本教程的都可以对 Makefile 有一个清晰的理解和正确的运用。那么现在就开始我们的 Makefile 学习之路。 文章目录 一、什么是 Makefile&#xff0c;优点&#xff1f;二、什么是 make, 为什么使用make?…...

如何使用SpringMVC之常用注解

❣️关注专栏&#xff1a;JavaEE Spring MVC ⌛️ 1. Spring MVC 创建和连接⌛️ 1.1 RequestMapping⌛️ 1.2 GetMapping⌛️ 1.3 PostMapping ⌛️ 2. 获取参数⌛️ 2.1 传递/获取单个参数⌛️ 2.2 传递/获取多个参数⌛️ 2.3 传递/获取对象⌛️ 2.4 参数重命名⌛️ 2.4.1 …...

Vue3的axios请求封装,请求拦截,相应拦截

对于三者放在Service.js中封装&#xff0c;方便使用 axios.create 的作用是创建一个新的 axios 实例&#xff0c;该实例可以具有自定义配置。通过使用 axios.create&#xff0c;您可以为任何 API 生成一个客户端&#xff0c;并在使用同一客户端的任何调用中重复使用相同的配置…...

ZC706P试验PL_DDR3内存条的步骤方法

ZC706P 板卡完全兼容XILINX官方的ZC706,当然也支持PL外挂的1G的DDR3内存条&#xff0c;这个片BLOG我提供从官方下载的一个文档和一个项目&#xff0c;演示一下验证DDR3的步骤。 步骤1&#xff1a;准备好板子&#xff0c;安装好软件。 链接&#xff1a;https://pan.baidu.com/s…...

通达信W底形态选股公式,也称双底形态

W底形态&#xff0c;也称双底形态&#xff0c;是一种经典的技术分析形态&#xff0c;代表了跌势的逆转。看起来像字母 "W"&#xff0c;描述了一波下跌&#xff0c;反弹&#xff0c;再次下跌到与上一波下跌相同或相近的位置&#xff0c;最后是另一波反弹。W底形态两次…...

java语言与算法、数据结构的用法

Java语言是一种广泛使用的计算机编程语言&#xff0c;也是开发各种软件和操作系统的重要工具之一。除了具有高效性和可移植性之外&#xff0c;Java语言还具有丰富的算法和数据结构支持&#xff0c;可以帮助程序员轻松地解决各种问题。 算法和数据结构是计算机科学中的两个基本…...

中国社科院与美国杜兰大学金融管理硕士项目,引领你走在金融行业前沿

作为金融领域从业人员时刻都在关注行业最新资讯&#xff0c;只有掌握一手的前沿讯息&#xff0c;才能在职场上无往不胜。针对在职的你&#xff0c;如何利用业余时间让自己更增值呢&#xff0c;中国社科院与美国杜兰大学金融管理硕士项目引领你走在金融行业前沿。 金融管理硕士…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...