用 .NET 启动你的 DJI Ryze Tello 无人机
大疆的 DJI Ryze Tello 是入门级的无人机,不仅在 STEM 教育中有非常广泛的应用,也可以作为编程入门的首选。通过 UDP 协议调用 DJI Ryze Tello SDK 可以让 DJI Ryze Tello 无人机执行起飞,降落,转向以及不同的花式动作。本文将会通过 .NET 创建应用控制 DJI Ryze Tello。
.NET UDP 编程
▍什么是 UDP
“UDP(用户数据报协议)是一个与IP 协议一起使用的长期协议,用于在传输速度和效率比安全性和可靠性更重要的场合下发送数据。UDP 使用一个简单的、具有最小协议机制的无连接通信模型。UDP 使用校验和保证数据完整性,使用端口号以区分数据发送方和接收方中不同的应用程序。它无需握手会话,即将不可靠的底层网络直接暴露给了用户的应用程序:不保证消息交付、不保证交付顺序也不保证消息不重复。如果需要网络接口层面的纠错功能,则应用程序可以使用为此目的设计的传输控制协议(TCP)或者流控制传输协议(SCTP)。”
在现场实时测控领域,如果有实时、抗干扰性、安全性等要求,都可以采用 UDP 传输数据。我想这也是 DJI Ryze Tello 为何使用 UDP 协议通信的原因。
▍C# 调用 UDP Client
在 System.Net.Sockets 下你可以通过类 UdpClient 来完成 UDP 协议的相关调用。这是官方给我们的例子。
UdpClient 类提供了在阻塞同步模式下发送和接收无连接 UDP 数据报的简单方法。因为 UDP 是一种无连接的传输协议,所以在发送和接收数据之前不需要建立远程主机连接。但是,您确实可以选择通过以下两种方式之一建立默认远程主机:
-
使用远程主机名和端口号作为参数创建 UdpClient 类的实例
-
创建 UdpClient 类的实例,然后调用 Connect 方法
您可以使用 UdpClient 中提供的任何发送方法将数据发送到远程设备。使用 Receive 方法从远程主机接收数据。
用 .NET Polyglot Notebook 连接 DJI Ryze Tello
用 .NET 封装 DJI Ryze Tello SDK 之前我们可以用 Notebooks 连接 DJI Ryze Tello 做相关原型测试。
要连通 DJI Ryze Tello SDK ,需要通过 UDP 连通 192.168.10.1 以及端口 11111.
通过 C# 调用 UDPClient 连接的方式如下:
string telloIP = "192.168.10.1";int telloPort = 8889;UdpClient udpClient = new UdpClient();udpClient.Connect(telloIP,telloPort);
并封装好指令执行的方法
public void Command(UdpClient udpClient,string cmd)
{Byte[] sendCmdBytes = null;sendCmdBytes = Encoding.UTF8.GetBytes(cmd);udpClient.Send(sendCmdBytes, sendCmdBytes.Length);
}
完成上面的设置,你就可以执行对应的指令完成控制 DJI Ryze Tello 的操作
Command(udpClient,"command");Command(udpClient,"takeoff");Command(udpClient,"land");
结合 .NET Polyglot Notebook 就可以完成对 DJI Ryze Tello 的操作以及相关技术测试。以下视频是 Notebooks 控制 DJI Ryze Tello 的具体效果:
用 .NET MAUI 构建 DJI Ryze Tello 应用
.NET MAUI 是跨平台,跨设备的前端应用技术,开发团队使用一种编程语言 C# 就可以完成 iOS / Android / macOS / Windows 的应用开发。现在是多终端的年代,通过不同设备控制你手上的 DJI Ryze Tello , 搭建多应用场景是非常棒的。本系列主要通过 iOS 和 Android 移动设备控制 DJI Ryze Tello, 以下是一些关键步骤:
▍通过 .NET Comet 构建前端 UI
Comet 是⼀种编写跨平台 UI 的现代⽅式 ( https://github.com/dotnet/Comet )。基于 .NET MAUI,它采⽤Model - Views - Update (MVU) 模式,和传统的 XAML 相⽐ , 它有⼏个显著的特点:
-
基于函数式编程;
-
Comet 参考了 SwiftUI 和 Flutter 描述界面的方式,更容易去编写页面层次逻辑,如:
-
用 Comet 开发 .NET MAUI 应用不仅可以在 Visual Studio 上开发 ,也可以在 Visual Studio Code 上开发。
注意:如果需要在 Visual Studio Code 调试 .NET MAUI 应用,请安装 C# 和 .NET Comet 组件
▍绑定 iOS/Android 原生库的技巧
一个好的应用需要整合非常多的场景,如支付,电商,地图等,作为开发团队不需要重复造车,直接可以调用不同的 SDK 来完成相关的操作。.NET MAUI 解决了跨平台应用界面和绝大多数页面逻辑以及业务逻辑的问题。但当我们使用第三方 SDK 时你会发现缺少相关 .NET MAUI 的原生库,通过 Binding 可以让 .NET MAUI 绑定 iOS / Android 的原生库。
从 DJI Ryze Tello SDK 文档可知通过 UDP 可以控制 DJI Ryze Tello , 也可以通过 UDP 实时图传 DJI Ryze Tello 的摄像头信号。这个时候我们需要通过 libVLC 库对 DJI Ryze Tello 摄像头提供的 UDP 信号进行 H264 编码解码的服务并显示在移动应用的界面上。
在 .NET MAUI 上,我一般通过命令行创建 iOS / Android 原生绑定项目,如下:
dotnet new iosbinding -o VLCSharp.iOS dotnet new android-bindinglib -o VLCSharp.Droid
▍绑定 iOS/Android 原生库的技巧
-
用 Sharpie 做初次转换
我们通过安装 Sharpie 针对 iOS 的 libVLC 库 MobileVLCKit.framework 进行绑定,通过执行以下命令可以快速转换 libVLC 的库。
sharpie bind -framework ./MobileVLCKit.framework --namespace MobileVLCKit -sdk iphoneos16.1
注意:iOS 原生库对应的 iOS 版本,否则你是没办法进行转换。
转换后替换项目中的 StructsAndEnums.cs 和 ApiDefinitions.cs 以及把 MobileVLCKit.framework 添加到 iOS 绑定的项目 VLCSharp.iOS 中
-
修改 csproj 文件,把原生库依赖的库都需要添加进去
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>net7.0-ios</TargetFramework><RootNamespace>MobileVLCKit</RootNamespace><Nullable>enable</Nullable><ImplicitUsings>true</ImplicitUsings><IsBindingProject>true</IsBindingProject><AllowUnsafeBlocks>true</AllowUnsafeBlocks><NoBindingEmbedding>false</NoBindingEmbedding></PropertyGroup><ItemGroup><ObjcBindingApiDefinition Include="ApiDefinition.cs" /><ObjcBindingCoreSource Include="StructsAndEnums.cs" /></ItemGroup><ItemGroup><NativeReference Include="MobileVLCKit.framework"><Kind>Framework</Kind><IsCxx>True</IsCxx><ForceLoad>True</ForceLoad><SmartLink>True</SmartLink><Frameworks>MediaPlayer Accelerate AssetsLibrary AVFoundation CoreMedia AudioToolbox CoreData CoreMedia CoreSpotlight MobileCoreServices CoreAudio OpenGLES CFNetwork CoreText QuartzCore CoreGraphics UIKit Security StoreKit SystemConfiguration VideoToolbox</Frameworks><LinkerFlags>-lbz2 -liconv -lstdc++</LinkerFlags></NativeReference></ItemGroup>
</Project>
-
编译,请从 GitHub(https://github.com/kinfey/dotNETMauiHOL/tree/main/code/apps/02.Binding/TelloApp.Bindings/VLCSharp.iOS)下载并替换 StructsAndEnums.cs 和 ApiDefinitions.cs。
替换后编译就成功了
如果希望了解更多 iOS Binding 的知识和相关技巧,你可以通过该链接了解:https://github.com/kinfey/AMapMAUIControls/blob/main/tutorial/cn/01.iOSBinding.md
▍Android 绑定 libVLC 库相关技巧
-
创建 Jars 文件夹,把 Android 的 libVLC 的库 org.videolan.libvlc.aar 添加到绑定的项目 Jars 文件夹中
-
修改 .csproj 文件
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>net7.0-android</TargetFramework><SupportedOSPlatformVersion>21</SupportedOSPlatformVersion><Nullable>enable</Nullable><ImplicitUsings>enable</ImplicitUsings></PropertyGroup><ItemGroup><LibraryProjectZip Include="Jars\org.videolan.libvlc.aar" /></ItemGroup><ItemGroup><TransformFile Include="Transforms\Metadata.xml" /><TransformFile Include="Transforms\EnumFields.xml" /><TransformFile Include="Transforms\EnumMethods.xml" /></ItemGroup>
</Project>
-
编译,和 iOS ⼀样编译出错,请从 GitHub
(https://github.com/kinfey/dotNETMauiHOL/tree/main/code/apps/02.Binding/TelloApp.Bindings/VLCSharp.Droid)下载并替换 EnumMethods.xml。
替换后,编译成功了。
如果希望了解更多 Android Binding 的知识和相关技巧,你可以通过该链接了解:
https://github.com/kinfey/AMapMAUIControls/blob/main/tutorial/cn/02.DroidBinding.md
自定义界面控件
.NET MAUI 可以通过 Handler 构建自定义界面控件,我们通过 Handler 绑定 LibVLC 实现图传,而且和一般自定义页面控件不同虽然用的都是 libVLC 库,但在不同平台上调用方式以及构建方式是不同的,所以在 Platforms 上需要针对不同的控件来完成定义,分别定义 iOS 文件夹新增 VideoPlayerView.ios.cs , Android 文件夹新增 VideoPlayerView.android.cs。
之后再通过继承 Handler 的类分别调用来完成自定义 VLC 控件的定义。
我们可以无缝把自定义的 VLC 控件添加到我们的应用中,和 Commet UI 是无缝对接的。
new VStack{new VlcUI().Padding(20).Alignment(Alignment.TopLeading)
}.Frame(width:400,height:300).Alignment(Alignment.Center),
我们可以看看那安卓上的实现效果,通过图传可以实时在应用端获取 DJI Ryze Tello 的摄像头信号
当我们完成页面逻辑和业务逻辑构建后,我们就可以用 .NET MAUI 构建的 iOS / Android 应用快速启动 DJI Ryze Tello ,下图是在 iPhone 控制 DJI Ryze Tello 起降的效果,以及实时图传。
小结
这就是通过 .NET 控制 DJI Ryze Tello 的主要步骤,如果⼤家希望了解更多细节和更详细内容,请访问 https://github.com/kinfey/dotNETMauiHOL , 这⾥⾯包括了完整的学习内容,还有具体细节,希望各位能更好地掌握⽤ .NET MAUI 跨平台应⽤的技巧,做更多有趣的应⽤。你可以按照以下顺序,依次学习相关内容
相关文档:
1. ⽤ .NET MAUI 构建 DJI Ryze Tello ⽆⼈机应⽤系列
https://github.com/kinfey/dotNETMauiHOL
2. 学习 .NET MAUI
https://aka.ms/mauiBlog.Learn
3. 关于 .NET Polyglot Notebook
https://aka.ms/mauiBlog.Notebook
4. .NET MAUI 绑定 iOS 原⽣库
https://aka.ms/mauiBlog.iOSBinding
5. .NET MAUI 绑定 Android 原⽣库
https://aka.ms/mauiBlog.DroidBinding
6. .NET MAUI ⾃定义⻚⾯控件
https://aka.ms/mauiBlog.CustomUI
7. C# 调⽤ UDP
https://aka.ms/mauiBlog.UDP
相关文章:

用 .NET 启动你的 DJI Ryze Tello 无人机
大疆的 DJI Ryze Tello 是入门级的无人机,不仅在 STEM 教育中有非常广泛的应用,也可以作为编程入门的首选。通过 UDP 协议调用 DJI Ryze Tello SDK 可以让 DJI Ryze Tello 无人机执行起飞,降落,转向以及不同的花式动作。本文将会通…...

sed 功能详解
介绍sedsed是一种流编辑器,它一次处理一行内容,把当前处理的行存储在临时缓冲区中(buffer),称为"模式空间",接着sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕&#…...
整数二分思路详解
题目描述 给定一个按照升序排列的长度为n的整数数组,以及 q 个查询。 对于每个查询,返回一个元素k的起始位置和终止位置(位置从0开始计数)。 如果数组中不存在该元素,则返回“-1 -1”。 输入格式 第一行包含整数n和q&a…...

基于java的进销库存管理系统(Vue+Springboot+Mysql)前后端分离项目,附万字课设论文
1.3 系统实现的功能 本次设计任务是要设计一个超市进销存系统,通过这个系统能够满足超市进销存系统的管理及员工的超市进销存管理功能。系统的主要功能包括:首页、个人中心、员工管理、客户管理、供应商管理、承运商管理、仓库信息管理、商品类别管理、 …...
手动添加 Grub 启动项
1. 问题背景 自己的台式机上装了好几块硬盘,因为自己又菜又喜欢折腾,几乎每块上都有一个操作系统,其中两个 m.2 的硬盘上分别装着一个 windows11 和一个 Ubuntu20.04。但在另外一块机械硬盘中还装着更早的一个 Ubuntu18.04,我电脑…...

工人搬砖-课后程序(JAVA基础案例教程-黑马程序员编著-第八章-课后作业)
【案例8-4】 工人搬砖 【案例介绍】 1.任务描述 在某个工地,需要把100块砖搬运到二楼,现在有工人张三和李四,张三每次搬运3块砖,每趟需要10分钟,李四每次搬运5块砖,每趟需要12分钟。本案例要求编写程序分…...
深度学习中backbone、head、neck等概念
1.backbone 翻译为主干网络的意思,既然说是主干网络,就代表其是网络的一部分。这个主干网络大多时候指的是提取特征的网络,其作用就是提取图片中的信息,供后面的网络使用。这些网络经常使用的是ResNet VGG等,而不是我…...

华为OD机试用Python实现 -【Linux 发行版的数量】(2023-Q1 新题)
华为OD机试题 华为OD机试300题大纲Linux 发行版的数量题目描述输入描述输出描述说明示例一输入输出说明Python 代码实现代码编写逻辑华为OD机试300题大纲 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:blog.csd…...
Http报文解析
http通信流程浏览器->已监听的web服务器->read->write->close http请求报文: a.请求方法: POST GET DELETE HEAD OPTIONS PUT TRACE b.请求地址: /xxx/yyy/zzz c.报文协议: HTTP/1.1 d.请求报文头: Accept Referer Accept-Language Content-Type Host Content-Len…...

Vue下载安装步骤的详细教程(亲测有效) 2 安装与创建默认项目
上篇请移步到Vue下载安装步骤的详细教程(亲测有效) 1_水w的博客-CSDN博客 上一篇博文已经对Node.js的安装与配置进行了详细介绍。 另外:文中项目存放的路径及项目名称可根据自身实际情况进行更改。 目录 三、Vue安装配置 1、搭建Vue脚手架 2、通过NPM安装Vue …...

TIA博途Wincc中自定义配方画面的具体方法示例
TIA博途Wincc中自定义配方画面的具体方法示例 前面和大家分享了通过TIA博途自带的配方视图组态配方功能的具体方法,具体内容可参考以下链接中的内容: TIA PORTAL wincc中配方recipe组态及配方视图的使用方法 但是,使用配方视图的时候感觉不是很方便,同时一部分使用人员也感…...
Java反射系列--方法大全
原文网址:Java反射系列--方法大全_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Java反射相关的方法。 Class相关方法 方法 说明 getName() 返回String形式的该类的名称。 newInstance() 根据某个Class对象产生其对应类的实例,它调用的是此类的默认构…...
LeetCode 169. 多数元素
LeetCode 169. 多数元素 难度:easy\color{Green}{easy}easy 题目描述 给定一个大小为 nnn 的数组 numsnumsnums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊n/2⌋⌊ n/2 ⌋⌊n/2⌋ 的元素。 你可以假设数组是非空的,并且给…...
来了,metaIPC1.0
metaRTC推出metaIPC正式版1.0,基于metaRTC6.0最新版二次开发,metaIPC是为嵌入式/摄像头量身打造的webRTC版IPC Camera,可安装在国内大多数Soc芯片上,如在君正/瑞芯微/MSTAR/海思等等已经有多个成熟产品应用。 New Feature 支持M…...

WireShark如何进行USB包协议分析
USB协议学习的步骤之一就是从抓包看协议通信,进而学习usb设备开发是怎么回事。这里发现一个工具就是wireshark。 WireShark如果要抓取usb设备的包,需要在安装的时候,选择usbpcap一并进行安装。...

蒙特卡洛随机模拟
蒙特卡洛随机模拟 简介 蒙特卡洛模拟是在计算机上模拟项目实施了成千上万次,每次输入都随机选择输入值。由于每个输入很多时候本身就是一个估计区间,因此计算机模型会随机选取每个输入的该区间内的任意值,通过大量成千上万甚至百万次的模拟…...
Android从屏幕刷新到View的绘制(三)之Handler异步消息与同步屏障
0. 相关分享 Android从屏幕刷新到View的绘制(一)之 Window、WindowManager和WindowManagerService之间的关系 Android从屏幕刷新到View的绘制(二)之Choreographer、Vsync与屏幕刷新 1. 相关类 Handler Handler中维护着它所在的…...

最新版axios@1.3.x取消请求-AbortController-初体验-番茄出品
最新版axios1.3.x取消请求-AbortController-初体验-番茄出品 start 前文提到,axios 中的取消请求,包含两种方式: AbortController;CancelToken; 上篇文章讲解了 CancelToken,今天这篇文章来了解一下 Abor…...

Git的简述
Git 文章目录GitGit概述版本控制工具集中式管理控制工具分步式管理控制工具控制机制Git和代码托管中心安装Git软件Git常用命令Git概述 Git是一个免费的、开源的分步式版本控制系统,可以快速的处理从小型到大型的各种项目 Git 易于学习,占地面积小&…...

webpack实战,手写loader和plugin
序言 对于 webpack 来说, loader 和 plugin 可以算是需求程度最为广泛的配置项了。但是呢,单单止步于配置可能还不够。如果我们自己有时候想要 diy 一个需求,但是 webpack 又没有相关的 loader 和 plugin 。那这个时候我们可能就得开始造点轮…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...

消息队列系统设计与实践全解析
文章目录 🚀 消息队列系统设计与实践全解析🔍 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡💡 权衡决策框架 1.3 运维复杂度评估🔧 运维成本降低策略 🏗️ 二、典型架构设计2.1 分布式事务最终一致…...