一、 遥控器链路通信拓扑分析
根据硬件原理图与架构图:
- 私有宽带链路(CX6531CD RF) :通过 PCIe/以太网 PHY(RTL8125/RTL8201)映射为 Android 系统级网络接口(如
eth0),负责 高带宽双向通信(RTSP/RTP 高清图传视频流 + UDP/TCP 遥测数传数据)。 - 独立安全控制链路(GD32 MCU) :摇杆(Hall sticks ≥ 200Hz)、E-stop 急停、按键直通 MCU,MCU 与 CX6531CD 直接走 SBUS/UART,同时与 SLM580 走 UART 通信。
- 备份网络(4G Cat.4 / Wi-Fi):系统标准移动蜂窝/WLAN 接口。
因此,APP 端面对的"链路中断"并非单一网络断开,而是多层级、多通道的复合状态异常。
二、 链路中断判定机制(多维联合判决)
为了防止网络偶发抖动导致的误判,APP 必须采用 "物理/驱动层 + 传输/应用层 + 视频流解码层" 的三层判定漏斗模型。
diff
+------------------------------------------------------------------------+
| 物理/射频状态 (PHY Link Down, RSSI/SNR 跌零, CX6531 RF 丢包率 > 阈值) | L1/L2
+-----------------------------------+------------------------------------+
| 并发融合
+-----------------------------------v------------------------------------+
| 数传遥测心跳 (Heartbeat 超时, RTT 持续恶化, 序列号连续丢失) | L4/L7
+-----------------------------------+------------------------------------+
| 交叉验证
+-----------------------------------v------------------------------------+
| 图传流健康度 (Socket Read Timeout, PTS 停滞, 解码关键帧丢帧) | Video Pipeline
+-----------------------------------+------------------------------------+
| 决策输出
[ APP 状态机裁决 ]
1. 物理与驱动层判定(Fast Detection, ≤200ms)
- 以太网/PHY 接口状态检测 :
- Android 系统层:注册
ConnectivityManager.NetworkCallback监听图传网口(eth0)的onLost与onCapabilitiesChanged。 - 底层 Netlink 广播/Sysfs 节点:监听 RTL8125/RTL8201 PHY 状态。若网线/内部通信链路物理断开(Link Down),系统服务瞬间捕获。
- Android 系统层:注册
- RF 射频链路健康指标监控(私有 HAL/AIDL 服务) :
- 系统开发提供专有 System Service,定期(如 100ms)轮询 CX6531CD 驱动节点,暴露:RSSI、SNR、RF Lock(锁频状态)、PER(误码率)。
- 快速判定规则 :当
RF Lock == false且连续 300ms 未恢复,或RSSI < -95 dBm持续 500ms,判定为 "RF 射频层脱网"。
2. 数传应用层判定(Heartbeat Sliding Window, ≤1000ms)
- 双向自适应滑动窗口心跳 :
- APP 与机载端保持周期性 Ping-Pong 心跳(默认 200ms 一次)。
- 引入 序列号(Seq ID)与滑动窗口,统计最近 10 个心跳周期的丢失率。
- 分级告警与判定阈值 :
- 弱网(Degraded) :RTT >300ms 或连续丢失 2 个心跳包。
- 中断(Link Lost) :连续丢失 4 个心跳包( ≥800ms,工业级阈值推荐 800ms∼1.2s)。
3. 视频流层判定(Video Pipeline Check, ≤1500ms)
- Socket / 解码管道检测 :
- RTSP/RTP Socket 设置
SO_RCVTIMEO为 1.0s。 - MediaCodec 解码器 PTS 监控 :APP 维护一个 PTS Watchdog,当表面渲染纹理(SurfaceTexture)在 1.2s 内未收到新的 Presentation Time Stamp 时,视为"图传冻结/中断"。
- RTSP/RTP Socket 设置
三、 APP 链路重连状态机设计(FSM)
APP 内部维护统一的通信链路状态机,避免无脑死循环重连导致系统资源耗尽或 UI 界面卡死。
scss
[ CONNECTED ]
|
(心跳连续丢失 / RF失锁)
v
[ LINK_WARNING ] (弱网降级: OSD 提示, 降低视频码率请求)
|
(超时达到 1.0s)
v
[ DISCONNECTED ] (链路中断: 触发 Fail-Safe 警告, 通知 MCU)
|
(启动重连策略)
v
[ RECONNECTING ] (退避重连, 通道探测)
/ \
(成功恢复) (连续 N 次重连失败)
/ \
[ CONNECTED ] [ FAIL_SAFE_LOST ] (彻底失联: 引导搜星/返航/切 4G 应急)
状态转移与行为定义:
- CONNECTED(正常连接):全功能可用,实时更新 OSD 延迟、信号强度指示条。
- LINK_WARNING(链路劣化) :
- 触发原因:连续丢包率 >30% 或延时持续增高。
- APP 行为:主动向机载端发送降低分辨率/码率指令;UI 弹出黄色轻量弱网提示。
- DISCONNECTED(中断确认) :
- 触发原因:心跳超时达到 1.0s 或 RF Lock 丢失。
- APP 行为:
- 画面冻结并置灰,叠加 "链路中断,正在重连..." HUD 警告;
- 触发震动马达(通过硬件原理图中的马达驱动 PWM 输出短震);
- 通过 UART 通知 Safety MCU(MCU 可接管或进入自主保活逻辑)。
- RECONNECTING(重连中) :
- 采用 截断二进制指数退避算法(Exponential Backoff with Jitter) 进行重连,防止网络端突发广播风暴。
- 重试间隔计算公式 : Twait=min(Tmax,Tbase×2attempt)±RandomJitter 推荐参数 : Tbase=200ms, Tmax=2000ms, Jitter =±50ms。
- 重连步骤:
- 重新解析与握手 Control Socket(优先恢复遥测/控制指令);
- 发送 TEARDOWN -> SETUP -> PLAY 重建 RTSP 视频 Session;
- 强制请求机载编码器发送 IDR 关键帧。
- FAIL_SAFE_LOST(失控保护) :
- 重连超过阈值(如 10s):APP 端判定为远距离失联,自动切换或弹出 "是否切换 4G 蜂窝链路接管",界面切换为离线地图与机载设备最后已知 GPS 定位轨迹引导。
四、 核心代码架构实现方案
1. 链路状态仲裁管理器(Kotlin 协程架构)
kotlin
class LinkQualityManager(
private val context: Context,
private val rfHalService: IRfHalService // 绑定高通SLM580系统层的AIDL服务
) {
private val _linkState = MutableStateFlow<LinkState>(LinkState.Disconnected)
val linkState: StateFlow<LinkState> = _linkState.asStateFlow()
private var lastHeartbeatTimestamp = 0L
private var lastPtsTimestamp = 0L
private val HEARTBEAT_TIMEOUT_MS = 1000L
private val PTS_STALL_TIMEOUT_MS = 1500L
fun startMonitor(scope: CoroutineScope) {
scope.launch(Dispatchers.Default) {
while (isActive) {
val now = SystemClock.elapsedRealtime()
val rfInfo = rfHalService.currentRfInfo // 获取 CX6531 信号: RSSI, Lock, PER
// 1. 物理层判定
if (!rfInfo.isLocked) {
handleStateTransition(LinkState.Disconnected("RF Lock Lost"))
delay(200)
continue
}
// 2. 遥测应用层心跳判定
val isHeartbeatTimeout = (now - lastHeartbeatTimestamp) > HEARTBEAT_TIMEOUT_MS
// 3. 视频流 PTS 停滞判定
val isVideoStalled = (now - lastPtsTimestamp) > PTS_STALL_TIMEOUT_MS
when {
isHeartbeatTimeout -> {
handleStateTransition(LinkState.Disconnected("Heartbeat Timeout"))
}
isVideoStalled -> {
handleStateTransition(LinkState.Degraded("Video Stream Frozen"))
}
rfInfo.rssi < -90 -> {
handleStateTransition(LinkState.Degraded("Weak RF Signal"))
}
else -> {
handleStateTransition(LinkState.Connected)
}
}
delay(100) // 10Hz 轮询仲裁
}
}
}
fun onHeartbeatReceived(seqId: Long) {
lastHeartbeatTimestamp = SystemClock.elapsedRealtime()
}
fun onVideoFrameDecoded(pts: Long) {
lastPtsTimestamp = SystemClock.elapsedRealtime()
}
private fun handleStateTransition(newState: LinkState) {
if (_linkState.value != newState) {
_linkState.value = newState
notifySystemAndMcu(newState)
}
}
private fun notifySystemAndMcu(state: LinkState) {
// 通过串口通知 MCU,并联动震动/指示灯
}
}
2. 重连引擎实现(平滑重连与防抖)
kotlin
class ReconnectionEngine(
private val commandChannel: CommandChannel,
private val videoPipeline: VideoPipeline
) {
private var reconnectJob: Job? = null
fun triggerReconnect(scope: CoroutineScope) {
if (reconnectJob?.isActive == true) return
reconnectJob = scope.launch(Dispatchers.IO) {
var attempt = 0
val baseDelay = 200L
val maxDelay = 2000L
while (isActive) {
attempt++
val jitter = (-50..50).random()
val backoff = min(maxDelay, baseDelay * (1 shl min(attempt, 6))) + jitter
Log.w("ReconEngine", "Reconnecting attempt #$attempt, backoff: ${backoff}ms")
// Step 1: 尝试重连指令控制通道 (轻量级)
val cmdSuccess = commandChannel.reconnect()
if (cmdSuccess) {
// Step 2: 控制通道成功,立即请求机载端刷新关键帧,并恢复视频管线
val videoSuccess = videoPipeline.reconnectStream()
if (videoSuccess) {
Log.i("ReconEngine", "Link fully restored on attempt #$attempt")
break // 重连成功,跳出循环
}
}
delay(backoff)
}
}
}
fun cancel() {
reconnectJob?.cancel()
reconnectJob = null
}
}
五、 Android 16 系统级深度保障与优化策略
作为搭载 Android 16 的工业级平台,APP 层的健壮性必须由底层 OS 提供协同支持:
- 进程常驻与保活(Keep-Alive) :
- 将遥控器主控 APP 设为系统签名应用(
android:persistent="true"),加入 AOSP Doze 白名单 与系统后台无杀保护。 - 配置实时调度策略:数传和重连线程提升至 Linux
SCHED_FIFO或设置实时优先级(Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO))。
- 将遥控器主控 APP 设为系统签名应用(
- 网络接口独立绑定(Socket Multi-homing) :
- SLM580 同时具备 4G(rmnet)、Wi-Fi(wlan0)和 CX6531CD(eth0)。
- APP 端建立 Socket 时,必须使用
Network.bindSocket(socket)显式绑定到eth0网络,避免在图传链路断开时,Android 系统自动将 Socket 漂移到 4G 导致重连路由混乱。
- 断网与安全闭环(Safety MCU 同步) :
- 当 APP 判定彻底失联后,通过 UART 向 Safety MCU 发送
DISCONNECT_ALARM帧。 - Safety MCU 依据硬件协议触发机载端返航/停机保护,杜绝因 Android 应用层崩溃或重连中产生死锁而导致机载设备飞丢。
- 当 APP 判定彻底失联后,通过 UART 向 Safety MCU 发送