无人机柜

大疆

Posted by LXG on August 13, 2025

航拍之旅-共享无人机柜

硬件部分

模块 功能 典型部件/建议
机柜结构 支撑和保护无人机 金属机柜或高强度塑料,带防雨防尘设计
存放仓位 无人机存放、锁定 可控电子锁或电磁锁;仓位托盘设计,适配不同型号无人机
充电系统 对无人机电池充电 充电模块(智能锂电池充电器),电源管理板
控制板/主控 管理柜子各模块 MCU 或嵌入式Linux主控(如Raspberry Pi, STM32, RK芯片)
通信模块 与服务器和用户APP交互 4G/5G模块、Wi-Fi、蓝牙,或NB-IoT
传感器 安全和状态监控 门磁传感器、红外/光电检测、重量传感器(判断无人机是否在位)
显示与交互 用户操作界面 LCD/触摸屏、LED指示灯、按钮或扫码器
安全防护 防盗、防火 防撬传感器、防火材料、报警器
电源 系统供电 交流电输入、UPS/备用电池,必要时支持太阳能板
环境监控 温湿度控制 温湿度传感器、风扇或小型空调

断路器

power_switch

特性 / 属性 CHINT NXB-63 C20 CHINT NXU-II G 40/275
核心功能 过载与短路保护、断电隔离 防雷击和瞬态过电压保护
典型用途 配电系统及电气设备电流保护 电涌保护,保护系统设备免受过电压损害
额定参数 20A 电流、约 400V 额定电压 40 kA 冲击电流、275 V 持续电压
符合标准 GB/T 10963.1, IEC 60898-1 IEC/EN 61643-11, GB/T 18802.11
保护机制 断电切断保护 吸收或旁路电涌,保护设备
结构特点 传统断路器结构 模块化设计,可在线更换模块

使用建议

  1. 若你的需求是针对电路中的过载或短路事件进行保护——比如当电流过大或发生短路时希望自动断开电路——则应选择 NXB-63 C20 小型断路器。
  2. 若你需要防护来自电网的瞬态高压冲击(如雷击或电压浪涌)——保护后级设备不被高电压损坏——则应选择 NXU-II G 40/275 电涌保护器。
  3. 实际应用中,这两种产品常常可以配套使用:断路器负责常规保护,电涌保护器负责突发高压冲击保护,形成前后协同机制,提高整体电气安全性。

单相电子式导轨智能电能表

用于测量和记录电力消耗。该电能表符合国家标准GB/T 17215.321-2008,并且带有二维码,可能用于远程读取数据或设备信息

微电脑时控开关

ZYT16G微电脑时控开关

ZYT16G

它是一种用于自动控制电器设备在特定时间开启或关闭的电子设备。通过设定时间参数,它可以按照预设的时间表自动控制电路的通断,适用于需要定时控制的场合,如路灯、水泵、空调等

无人机供电和锁控板

power_lock_board

主控芯片STM32F103C8T6

这是 STMicroelectronics(意法半导体) 的一颗 STM32F1 系列 ARM Cortex-M3 内核 MCU,常见于工业控制、物联网和智能设备

  • 通过 RS-485 或 UART 与上位机通讯
  • 控制 MOSFET 驱动锁(LK1~LK5)
  • 读取锁的反馈信号(FB1~FB5)
  • 控制 DC-DC 输出状态
  • 监测电压、电流状态
  • 管理 USB 口的供电控制

电池充电板

battery_board

这块电路板是一个多通道的电源管理板,很可能用于电池充电或平衡应用。它通过六个独立的降压/升压模块,由一个中央控制器进行管理。

主控芯片STM32F103C8T6

USB-A口可能的作用: CDC (Communication Device Class): 模拟一个串口(Serial Port)。这是最简单也最常用的方法。电路板向安卓屏幕“报告”自己是一个虚拟串口,然后就可以像传统的串口通信一样,通过收发字符串或二进制数据来交换信息

读卡器控制板

rfid

这块小板子是一个RFID读卡器模块。它的作用是:

  • 射频收发: 通过板子内部的PCB天线(图片中没有明显的天线线圈,但天线可能集成在板子内层,或通过旁边的电感L1/L2进行匹配),它能产生13.56 MHz的射频场。
  • 卡片感应: 当兼容的RFID标签(如MIFARE卡)靠近时,它会感应到卡片的信号。
  • 数据读写: 通过感应到的信号,它能读取或写入卡片中的数据。
  • 通信接口: 通过底部的4针连接器,它与主控板(例如你之前上传的电池板或控制板)进行通信,通常采用SPI或I2C协议,将读到的数据发送给主控芯片,或者接收主控芯片的指令去写入数据。

uart_24

主控芯片Geehy APM32 F072RBT6

  • 用户将RFID卡靠近读卡器模块(ANT522-M2)。
  • 读卡器模块读取卡片上的唯一ID或数据。
  • 读卡器模块通过SPI或I2C接口将数据发送给24路板子上的主控芯片。
  • 主控芯片(APM32)根据卡片ID,在程序中进行身份验证。
  • 如果验证通过,主控芯片会控制相应的输出通道(例如,开启第5路和第12路),并点亮相应的LED指示灯。

软件逻辑

  • android_serialport_api: 用于通过串口与外部硬件设备进行通信。
  • com.alibaba.android.arouter: 一个Android路由框架。
  • com.bumptech.glide: 一个流行的图片加载和缓存库。
  • com.google.zxing: 用于处理条形码和二维码的库。
  • com.tendcloud.tenddata: 移动应用数据分析平台。
  • com.youth.banner: 一个用于创建横幅视图的库。
  • com.zhy.view.flowlayout: 一个用于实现流式布局的库。
  • io.reactivex: 用于实现响应式编程的库。

软件需求-1

android app 产品需求:

  1. app启动后先全屏播放一个本地准备好的mp4视频(循环播放)
  2. 视频界面的底部显示当前设备的无线信号和设备序列号,内容悬浮在视频上方显示
  3. app启动的同时请求接口,如果接口返回有新的视频文件需要下载,则下载新的视频文件
  4. 新的视频文件下载到本地后替换掉初始的视频文件播放显示
  5. app启动后连接到后台的MQTT服务
  6. app启动后打开RS485串口ttyS3, 读取串口设备信息并通过mqtt上报
  7. app启动后打开TTL串口ttyS7, 读取串口信息并通过mqtt上报
  8. 服务器下发指令,然后通过串口发送指令到串口设备,串口设备反馈结果更新到UI
  9. 串口设备主动上报信息也需要更新UI

帮我设计个实现上述需求的架构

架构设计


+----------------------------------------------------------------------------------------------+
|                                      Android App                                             |
+----------------------+----------------------+----------------------+-----------------------+
|       UI 层          |     视频播放层       |      后台服务层       |   串口 & MQTT层       |
+----------------------+----------------------+----------------------+-----------------------+
| SplashVideoActivity  | VideoManager         | ApiService            | MqttManager           |
| - 全屏播放视频       | - 播放本地视频       | - 请求视频更新接口    | - 连接 MQTT Broker    |
| - 底部悬浮UI显示    | - 循环播放           | DownloadService       | - 上报串口数据        |
|   WiFi & 设备序列号 | - 切换新视频源       | - 校验文件完整性      | - 接收服务器指令      |
| - 更新UI显示串口数据 |                      | - 替换本地视频        | - 将指令下发到串口    |
|                      |                      |                      | - 串口反馈更新UI       |
+----------------------+----------------------+----------------------+-----------------------+
| 数据存储层           |
+----------------------+
| FileStorage          |
| - /files/video.mp4   |
| - /cache/new_video.mp4|
+----------------------+


时序图


┌─────────────────┐       ┌───────────────┐       ┌──────────────────┐       ┌──────────────────────┐
 SplashVideoActivity         ExoPlayer 播放器         ApiService 接口层         DownloadService 下载器 
└─────────┬─────────┘       └──────┬────────┘       └─────────┬────────┘       └──────────┬─────────┘
                                                                                      
           1. 启动 Activity                                                           
          │────────────────────────>                                                   
                                                                                      
           2. 加载本地 video.mp4                                                      
          │────────────────────────>                                                   
                                                                                      
                                    3. 循环播放(REPEAT_ALL)                           
                                   │────────────────────────>                          
                                                                                      
           4. 并发发起接口请求                                                        
          │──────────────────────────────────────────────────>                          
                                                                                      
                                                             5. 返回新视频下载地址    
                                                            │─────────────────────────>
                                                                                      
                                                                                       6. 下载新视频到缓存
                                                                                      │──────────────────▶
                                                                                      
                                                                                       7. 校验 MD5 通过
                                                                                      
                                                                                       8. 替换本地 video.mp4
                                                                                      
                                    9. 切换播放源 setMediaItem(new.mp4)                
          <────────────────────────│                                                   
                                                                                      
           10. 循环播放新视频                                                          
          │────────────────────────>                                                   


泳道图

drone_cabinet

用到的库

功能模块 库/组件 说明
视频播放 ExoPlayer 循环播放本地视频,可动态切换视频源
网络请求 Retrofit + OkHttp 请求视频更新接口
后台下载 WorkManager / ForegroundService 下载新视频到缓存并替换
JSON解析 Gson / Moshi 解析接口返回信息
UI布局 ConstraintLayout / FrameLayout 视频上方悬浮显示 WiFi & 序列号和串口数据
WiFi/设备信息 Android 原生 API 获取信号强度和设备序列号
MQTT通信 Eclipse Paho / HiveMQ MQTT Client 上报串口数据,接收服务器指令
串口操作 jSerialComm / Android NDK 打开 ttyS3 / ttyS7,读写数据
UI数据绑定 LiveData / StateFlow / Flow 实时更新 UI 显示串口数据和反馈结果

时序图

drone_cabinet_2

drone_cabinet_3

A133 视频编解码

a133_soc_diagram

A133支持的硬件编解码能力:

  • 视频编码能力: H.264 的最大编码性能为 1080p@60fps。
  • 视频解码能力: HEVC (H.265) 和 H.264 的最大解码性能为 4K@30fps。

查看视频源信息


Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'test.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.76.100
  Duration: 00:00:36.27, start: 0.000000, bitrate: 3202 kb/s   <-- 总码率约 3.2Mbps(比较高,对低端 SoC 有压力)
  Stream #0:0(und): 
    Video: h264 (High) (avc1 / 0x31637661)                     <-- H.264 High Profile,Allwinner 硬解常见不兼容点
    yuv420p(tv, bt709), 1080x1920 [SAR 1:1 DAR 9:16]           <-- 分辨率 1080x1920(竖屏 Full HD,部分硬件更习惯 1920x1080)
    2999 kb/s, 30 fps, 30 tbr, 15360 tbn, 60 tbc (default)     <-- 30fps,参考时钟 15360,说明码流比较规范
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
  Stream #0:1(und): 
    Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 193 kb/s (default) <-- AAC LC,没问题
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]

报错-1

player_video_error

修改视频帧率命令

ffmpeg -i test_60fps.mp4 -vf “fps=30” -c:a copy test_30fps.mp4

报错-2


ACodec                  E  signalError(omxError 0x80001001, internalError -62)
MediaCodec              E  Codec reported err 0xffffffc2, actionCode 0, while in state 6
ACodec                  W  not dequeuing from native window due to fatal error
ACodec                  W  not dequeuing from native window due to fatal error
SurfaceUtils            D  disconnecting from surface 0xc5137808, reason disconnectFromSurface
ACodec                  W  not dequeuing from native window due to fatal error
MediaCodecVideoRenderer E  Video codec error (Ask Gemini)
                java.lang.IllegalStateException
		at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)
		at android.media.MediaCodec.dequeueOutputBuffer(MediaCodec.java:2789)
		at androidx.media3.exoplayer.mediacodec.SynchronousMediaCodecAdapter.dequeueOutputBufferIndex(SynchronousMediaCodecAdapter.java:112)
		at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.drainOutputBuffer(MediaCodecRenderer.java:2104)
		at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:896)
		at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.render(MediaCodecVideoRenderer.java:1314)
		at androidx.media3.exoplayer.RendererHolder.render(RendererHolder.java:391)
		at androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:1367)
		at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:697)
		at android.os.Handler.dispatchMessage(Handler.java:103)
		at android.os.Looper.loop(Looper.java:214)
		at android.os.HandlerThread.run(HandlerThread.java:67)

ExoPlayerImplInternal   E  Playback error (Ask Gemini)
		androidx.media3.exoplayer.ExoPlaybackException: MediaCodecVideoRenderer error, index=0, format=Format(1, null, video/mp4, video/avc, avc1.640028, 2999664, und, [1080, 1920, 30.000004, ColorInfo(BT709, Limited range, SDR SMPTE 170M, false, 8bit Luma, 8bit Chroma)], [-1, -1]), format_supported=YES
		at androidx.media3.exoplayer.BaseRenderer.createRendererException(BaseRenderer.java:545)
		at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:926)
		at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.render(MediaCodecVideoRenderer.java:1314)
		at androidx.media3.exoplayer.RendererHolder.render(RendererHolder.java:391)
		at androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:1367)
		at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:697)
		at android.os.Handler.dispatchMessage(Handler.java:103)
		at android.os.Looper.loop(Looper.java:214)
		at android.os.HandlerThread.run(HandlerThread.java:67)
		Caused by: androidx.media3.exoplayer.video.MediaCodecVideoDecoderException: Decoder failed: OMX.allwinner.video.decoder.avc
		at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.createDecoderException(MediaCodecVideoRenderer.java:2468)
		at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:920)
		at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.render(MediaCodecVideoRenderer.java:1314) 
		at androidx.media3.exoplayer.RendererHolder.render(RendererHolder.java:391) 
		at androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:1367) 
		at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:697) 
		at android.os.Handler.dispatchMessage(Handler.java:103) 
		at android.os.Looper.loop(Looper.java:214) 
		at android.os.HandlerThread.run(HandlerThread.java:67) 
		Caused by: java.lang.IllegalStateException
		at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)
		at android.media.MediaCodec.dequeueOutputBuffer(MediaCodec.java:2789)
		at androidx.media3.exoplayer.mediacodec.SynchronousMediaCodecAdapter.dequeueOutputBufferIndex(SynchronousMediaCodecAdapter.java:112)
		at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.drainOutputBuffer(MediaCodecRenderer.java:2104)
		at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:896)
		at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.render(MediaCodecVideoRenderer.java:1314) 
		at androidx.media3.exoplayer.RendererHolder.render(RendererHolder.java:391) 
		at androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:1367) 
		at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:697) 
		at android.os.Handler.dispatchMessage(Handler.java:103) 
		at android.os.Looper.loop(Looper.java:214) 
		at android.os.HandlerThread.run(HandlerThread.java:67) 
ExoPlayerImplInternal   E  Disable failed. (Ask Gemini)
		java.lang.IllegalStateException
		at android.media.MediaCodec.native_flush(Native Method)
		at android.media.MediaCodec.flush(MediaCodec.java:2194)
		at androidx.media3.exoplayer.mediacodec.SynchronousMediaCodecAdapter.flush(SynchronousMediaCodecAdapter.java:160)
		at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.flushCodec(MediaCodecRenderer.java:1033)
		at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.flushOrReleaseCodec(MediaCodecRenderer.java:964)
		at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.onDisabled(MediaCodecRenderer.java:797)
		at androidx.media3.exoplayer.video.MediaCodecVideoRenderer.onDisabled(MediaCodecVideoRenderer.java:1081)
		at androidx.media3.exoplayer.BaseRenderer.disable(BaseRenderer.java:247)
		at androidx.media3.exoplayer.RendererHolder.disableRenderer(RendererHolder.java:673)
		at androidx.media3.exoplayer.RendererHolder.disable(RendererHolder.java:567)
		at androidx.media3.exoplayer.ExoPlayerImplInternal.disableRenderer(ExoPlayerImplInternal.java:2164)
		at androidx.media3.exoplayer.ExoPlayerImplInternal.disableRenderers(ExoPlayerImplInternal.java:2157)
		at androidx.media3.exoplayer.ExoPlayerImplInternal.resetInternal(ExoPlayerImplInternal.java:1890)
		at androidx.media3.exoplayer.ExoPlayerImplInternal.stopInternal(ExoPlayerImplInternal.java:1847)
		at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:876)
		at android.os.Handler.dispatchMessage(Handler.java:103)
		at android.os.Looper.loop(Looper.java:214)
		at android.os.HandlerThread.run(HandlerThread.java:67)
Surface                 E  getSlotFromBufferLocked: unknown buffer: 0xc4ea98c0
ACodec                  W  [OMX.allwinner.video.decoder.avc] can not return buffer 22 to native window
Surface                 E  getSlotFromBufferLocked: unknown buffer: 0xc4ea91c0
ACodec                  W  [OMX.allwinner.video.decoder.avc] can not return buffer 17 to native window
Surface                 E  getSlotFromBufferLocked: unknown buffer: 0xeefe9900
ACodec                  W  [OMX.allwinner.video.decoder.avc] can not return buffer 16 to native window

当前修改方案

定时重建exoplayer