Skip to content

Releases

OpenRC2 1.48.3

Choose a tag to compare

@456erddgr 456erddgr released this 06 Nov 11:35

OpenRC2 1.48.3

作者:软糖布丁

22 · 「别人 22Hz」之谜 —— 结论

承接 21-高频通路与按键普查-20261106.md。
本篇只回答一个问题:能不能拿到比 10Hz 更快的真摇杆?


一、结论

不能。10Hz 就是这台机器摇杆数据的上限。

我用「DUML 序号连续性」把这件事证死了,不是推测:

ETX-Duml: stat hz=23 stickHz=9  stick=79  frames=190 bad=0 gap150=1 seq=518 lost=0 gapN=0
ETX-Duml: stat hz=23 stickHz=10 stick=89  frames=213 bad=0 gap150=1 seq=518 lost=0 gapN=0
ETX-Duml: stat hz=22 stickHz=8  stick=98  frames=236 bad=0 gap150=1 seq=518 lost=0 gapN=0
ETX-Duml: stat hz=25 stickHz=10 stick=108 frames=261 bad=0 gap150=1 seq=518 lost=0 gapN=0
  • lost=0:累计跳号量 0 —— 服务端发的每一帧我们都收到了
  • gapN=0:从未发生过跳号
  • bad=0:没有一帧 CRC 校验失败
  • stickHz=9~10:摇杆帧就是 9~10 帧/秒

如果源是 22Hz 而我们只收到 10Hz,那么 lost 会以每秒 12 的速度增长。它一直是 0。

注:seq 一直显示 518,是因为固件对同一批推送复用同一个序号(不是逐帧自增)。
这本身也是个证据:它压根没打算按帧序号节奏推 —— 有变化才推。


二、那别人的「22Hz」到底是什么

一句话:跟我们做的插值是一回事,不是采样率。

我们的摇杆链已经是 10Hz 源 → 100Hz 输出:

  • StickSmooth 在两帧真值之间做线性插值(窗口 60ms,不外推)
  • 控制环 CTRL_MS=10(100Hz)
  • 推流环 PUSH_MS=4(250Hz)

PC 端实测过:hz=9.56(源)、push_hz=226~229(推给 ViGEm)。这已经是 24 倍插值。

别人说的 "22Hz",从数字上很像:

  • 要么是把 10Hz 源做成 22Hz 输出的插值系数
  • 要么是另一条低频通路(比如 binder 60Hz 空转,人家只取有效变化的那部分)

但无论哪种,都没有改变 10Hz 这个源头。 插值能救手感,救不了延迟——
物理上,你推杆到画面响应,最少要等 1/10 秒才拿到第一个真值点。


三、为什么这台机器只有 10Hz

dji_link 对本地客户端做了明确限制:

  1. 同样的数在 40009 上也一样:独占 30 秒收 10 帧(0.33Hz 甚至更慢),且全是 1024 占位
  2. binder 60Hz 是空转:replyHz=59 但 changeHz=0,连采 30 分钟一次没变
  3. 只注册一次回调后它根本不推:实测 30 秒内只回最初 3 次,之后完全静默

三条路都指向同一个事实:真值只在 40007 上,由固件按 ~10Hz 主动推,问不出来也逼不出来。


四、对用户那两个诉求的诚实回答

你要的 能不能做到 说明
摇杆高频接收 ❌ 不可能超过 10Hz 源头限制。但手感已经用 100Hz 插值优化过了
切档(后面两个自定义键) ⚠️ 拨轮可以,自定义键还没找到 拨轮 = 06/AE 的 raw[4]/raw[5],已实现。自定义键在 40007 上从未出现过
前面拍照 / 录像键 ⚠️ 未确认 按参照实现应在 06/174 的 p0 位域,但本机 3000+ 帧里 06/174 只出现 1 次且 p0=0

四之补:现有平滑实现已经是对的

查了 StickSmooth.value()(app/src/com/rc2/etx/radio/StickSmooth.java:230-267),
当前做法正是正确的那种:

float win = (tLast <= tPrev) ? 1f : (float)(tLast - tPrev);
if (win > 45f) win = 45f;     // 窗口上限 45ms
if (win < 20f) win = 20f;     // 下限 20ms
float u = (nowMs - tLast) / win;   // u 夹在 [0,1]
out = yPrev + (yLast - yPrev) * u; // 帧间线性插值
  • 只插值,不外推 —— u 上限是 1,永远停在最新真值上,不会越过
  • 窗口 45ms 而不是整段 100ms —— 避免"晚一帧"的滞后感
  • 档位 LVL_CAP/LEVEL 只控制低通混合比例,不改插值框架

所以「10Hz 源 → 100Hz/250Hz 输出」这条路我们已经在走了,
不需要重写,只需要调参(smoothLevel 当前 = 2)。


五、下一步真正值得做的

既然频率上限定死了,唯一能改善手感的方向是降低延迟,不是提高频率:

  1. 把插值窗口从 60ms 压到 20~30ms
    现在 WIN=60ms 是为了在 10Hz 下掩盖抖动。压小会更跟手,但抖动更明显。这个可以做成可调,让用户自己选。
  2. 预测补偿(有风险)
    在插值基础上加一点点速度外推。StickSmooth 之前试过外推,结果是"冲出再回拉"(单拍跳变 539),
    所以当前版本故意不做外推。要加只能加非常小的量。
  3. 找 40007 的订阅唤醒动作 —— 这才是唯一有可能突破 10Hz 的地方。
    force-stop 后 40007 会彻底哑掉,说明存在一个"重新订阅"的动作我们没找到。
    如果能找到,并且它支持更高频率的推送模式,那才是真正的突破。

六、本轮代码改动(1.48.0 ~ 1.48.3)

版本 改动
1.48.0 加 bindscan / bindraw 探针(扫描全部 cmdId)
1.48.1 加 bindlisten 探针(只注册一次,验证是否自己打断订阅)
1.48.2 DumlStick 加 DUML seq 追踪(判断丢帧)
1.48.3 修正 seq 偏移(载荷 [4..5],原来错写成 [6..7])

⚠️ 顺带修的一个大坑:versionCode 计算错误

build-apk.ps1 原来把版本号里所有数字直接拼起来当 versionCode:

1.46.44  →  14644
1.48.0   →   1480     ← 比 14644 小!

于是 adb install 报 INSTALL_FAILED_VERSION_DOWNGRADE,
而 adb 的这条失败信息夹在长输出里很容易看漏 —— 设备上跑的其实一直还是 1.46.44。

我为此白查了近两小时:代码明明改了,logcat 里却一行新日志都没有,
一度怀疑是 onNewIntent 没触发、线程没起来、日志被过滤……

已经修成 主*10000 + 次*100 + 修订:

1.46.44  →  14644
1.48.0   →  14800

教训:以后改完代码,第一件事是 dumpsys package <pkg> | grep versionName
确认装上去的到底是哪一版。光看 install 返回值不够。


七、可供复现的命令

# 看真实丢帧率(关键指标:lost 应该一直为 0)
adb logcat -s ETX-Duml | grep "stat hz"

# 扫描某个 cmdSet 下哪些 cmdId 有回包
adb shell am start -n com.rc2.etx/.MainActivity \
  --es action bindscan --ei cs 6 --ei from 0 --ei to 200

# 验证「只注册一次回调,服务端会不会主动推」
adb shell am start -n com.rc2.etx/.MainActivity \
  --es action bindlisten --ei cs 6 --ei id 4 --ei sec 30

OpenRC2 1.46.44

Choose a tag to compare

@456erddgr 456erddgr released this 03 Nov 14:36

先说清楚:这一版没在真机上验过

开发到一半遥控器 USB 掉线了,无线 adb 也连不上(把本机所在的 192.168.3.0/24 扫了一遍,5555 端口一个都没响应)。
所以下面是"改了什么",不是"修好了什么"。等机器回来我会补验证记录。


模型管理页一开就闪退

崩在这里:

signal 11 addr 0x10 pc off 0x43d4b8   →  std::set<unsigned int>::insert

addr 0x10 意思是在一个空的 std::set 上做插入。两件事叠在一起:

  1. 启动大约 70 ms 后,modelslist 所在的一整段 1888 字节 BSS 被外部清零
    (加了 clear() 钩子,确认不是 ModelsList::clear() 干的)。
  2. setSelected(getLabels().size() - 1) 在空标签表上无符号下溢成 0xFFFFFFFF,然后在空 set 上插入,崩。

改了:进页前若模型库为空先重建;标签表为空就直接短路返回;另加运行时探针,检测到"库空但 SD 有模型"会自动重建(2 秒节流)。

没改:那个 1888 字节到底是谁 memset 的,还没揪出来。现在只有检测 + 自愈。


RC Pro 六轴全 −100%,怎么动都不动

根因是一个判活判据把整条链子判死了:stickSourceAlive() 用 duml.connected,
而 RC Pro 的 40007 是"连一次收一帧就 EOF",这个标志几乎恒 false,于是
不喂混控 → 走合成假值(正好每轴 −100%)→ 旁键那段代码也不执行。

  • 判活改成"最近一帧有多新"(单调时钟,400 ms 窗口)
  • DumlStick 快照模式重连间隔:注释写 10 ms,代码是 5000 ms,改成 10 ms(连续失败 200 次熔断回 5 s)
  • RcProStick.raw 初值 0 → 1024,因为 (0-1024)/660 正好等于 −100%,是个完美的骗局

旁键 / 拨轮(RC Plus 2)

加了两条通路,和 RC2 原来那条并列:

  • binder 06/174 帧轮询,250 ms 一次
  • 无障碍服务:物理键在内核里是普通输入设备事件,binder 拿不到,只有 AccessibilityService.onKeyEvent 能收

铁律:KeysService 必须和 libetx 同进程,绝不能加 android:process。
核心状态是进程内的,换进程等于加载一份空核心,按了没人看见。


顺手修的

  • Radio.lastBinderMs 时钟混用:elapsedRealtime() 减 currentTimeMillis(),恒为 true,每 20 ms 空转一次
  • 构建脚本:重链完忘同步 so 会静默用旧内核出包,而版本号让 sha 看起来变了。现在 out/ 比 keep/ 新就直接 [FATAL]

包

大小 13855339 B
sha256 ca0fb6f7f567649bddc3f80658744ec77526796135f77c044d9271a185e79b5a

1.46.41 ~ 1.46.44 这四版的 libetx.so 逐字节相同,APK 大小也全一样。
想确认补丁进没进包,只能看 sha256 —— 看大小、看版本号都会认错。


详细记录:docs/20-本轮修复总记录-20261103.md

OpenRC2 1.46.24

Choose a tag to compare

@456erddgr 456erddgr released this 03 Nov 12:06

OpenRC2 1.46.24

作者:软糖布丁

OpenRC2 1.46.18

Choose a tag to compare

@456erddgr 456erddgr released this 02 Nov 09:10

OpenRC2 1.46.18

作者:软糖布丁

OpenRC2 1.46.17

Choose a tag to compare

@456erddgr 456erddgr released this 02 Nov 08:46

OpenRC2 1.46.17

作者:软糖布丁

OpenRC2 1.46.14

Choose a tag to compare

@456erddgr 456erddgr released this 02 Nov 08:38

OpenRC2 1.46.14

作者:软糖布丁

OpenRC2 1.46.10

Choose a tag to compare

@456erddgr 456erddgr released this 02 Nov 08:28

OpenRC2 1.46.10

作者:软糖布丁

OpenRC2 1.46.9

Choose a tag to compare

@456erddgr 456erddgr released this 02 Nov 08:23

OpenRC2 1.46.9

作者:软糖布丁

OpenRC2 1.46.5

Choose a tag to compare

@456erddgr 456erddgr released this 02 Nov 08:12

OpenRC2 1.46.5

作者:软糖布丁

OpenRC2 1.46.3

Choose a tag to compare

@456erddgr 456erddgr released this 02 Nov 08:07

OpenRC2 1.46.3

作者:软糖布丁