你能用树莓派制作 Wii U 游戏手柄吗?
摘要
一篇详细的技术回顾,记录了尝试将树莓派改装成 Wii U 游戏手柄克隆体的过程,重点介绍了 Wi-Fi 芯片组兼容性问题,并发现 Orange Pi Zero 2W 的表现出人意料地更好。
<p><a href="https://lobste.rs/s/fu3icq/can_you_make_wii_u_gamepad_from_raspberry">评论</a></p>
查看缓存全文
缓存时间: 2026/08/03 01:37
TL;DR:树莓派可以改造成运行 Vanilla 的 Wii U 手柄克隆,但 Wi-Fi 芯片限制、解码器延迟和性能问题使它不实用——而 Orange Pi Zero 2W 出人意料地好用得多。
## 回顾:Vanilla 与 Wi-Fi 问题
Wii U 手柄本质上就是一台微型电脑。它通过 Wi-Fi 连接主机,使用与蓝光光盘和 YouTube 相同的视频编解码器,理论上应该很容易被复刻。最大的障碍是任天堂对 Wi-Fi 协议的混淆处理。
此前的成果是 Vanilla,一个基于十年前概念验证项目 drc-sim 的 Wii U 手柄重实现,由 memahaxx 开发,后来 rolandoislas 接手。Vanilla 主要在 Linux 上运行,因为 Linux 提供了足够的底层控制能力来执行任天堂混淆过的 Wi-Fi 握手。但桌面 Linux 并不是一个好的手柄替代品,所以真正的目标是把 Vanilla 移植到能够真正看起来、用起来都像掌上控制器的硬件上。
这意味着要面对一个混乱的硬件兼容性问题。
## 并非所有 Wi-Fi 适配器都一样
早期测试表明,许多 Wi-Fi 适配器都能工作,但有些却莫名其妙地不行。drc-sim 只推荐了一种芯片组:Ralink RT2800,以堪称最亲 Linux 的 Wi-Fi 芯片组之一而闻名。Vanilla 的目标是支持更多。
随着用户报告陆续出现,两个规律浮现出来:
- Realtek 芯片组通常不行。
- Broadcom 芯片组通常不行。
这很烦人,因为 Realtek 和 Broadcom 是世界上最常见的两个 Wi-Fi 厂商。Realtek 主导 USB Wi-Fi 适配器市场;Broadcom 主导便携设备——手机、平板、笔记本电脑、树莓派,甚至任天堂 Switch。
### Realtek:驱动问题
Realtek 适配器在 Linux 上很特殊,因为它们需要安装驱动。大多数 Linux 硬件由内核直接支持,但 Realtek 最流行的芯片组却没有。更糟糕的是,这个驱动并不是某个随意的社区项目——它是由 Realtek 自己开发的,却始终没有进入内核。
用 Realtek 适配器测试 Vanilla 时,在尝试与 Wii U 同步时早期就失败了,出现了一个神秘的 `CTRL-EVENT-ASSOC-REJECT` 错误。
翻查驱动源码后发现有许多分支,其中一个来自 rolandoislas——drc-sim 的维护者之一——显然是在尝试让它与 Wii U 配合工作。这个分支只能在超过十年的旧 Linux 版本上编译,并且与任何现代适配器都不兼容。将其补丁移植到更新的驱动上也无济于事。
接着出现了关键发现:有一个 Realtek 驱动完全不同。它不是 Realtek 代码的分支,而是从头开始编写的新代码,属于 `wireless-next`——一个用于在主线合并前开发新驱动的 Linux 内核分支。GitHub 用户 lwfinger 维护了一个反向移植,使其能在当前 Linux 版本上使用。
那个驱动与 Vanilla 配合完美。所以 Realtek 自己的驱动写得如此错误,以至于内核开发者从头重写了一遍,而原版驱动也破坏了 Vanilla。只要安装了正确的驱动,那些极其常见的 Realtek 适配器最终还是兼容的。
### Broadcom 与 FullMAC 之墙
Broadcom 带来了另一个问题。Broadcom 适配器实际上可以同步,然后在连接时抛出同样的 `ASSOC-REJECT` 错误。但与 Realtek 不同,Broadcom 驱动已经在内核中,而且似乎通过了 Realtek 驱动未能通过的标准。仔细检查驱动后,发现它并没有阻止 Vanilla——它实际上几乎什么都没做。
问题归结为两种类型的 Wi-Fi 适配器:
- **SoftMAC 适配器** 只是“笨”无线电。它们在比特和无线电波之间转换;所有 Wi-Fi 协议工作——安全握手、解析传入数据、格式化传出数据——都在主机 CPU 上以软件方式完成,通常由 `wpa_supplicant` 之类的程序处理。SoftMAC 设备是最便宜、最简单、最常见的设计。
- **FullMAC 适配器** 有自己的 CPU、内存和固件。它们本质上是一个完整的独立片上系统,自行处理 Wi-Fi 协议处理。
FullMAC 对 Vanilla 来说是个问题,因为认证握手被固化在芯片里。没有办法修改它以兼容 Wii U。即使尝试破解芯片的二进制 blob,也意味着要在完全没有文档的代码中摸索,而且为每个 FullMAC 芯片都这么做是不切实际的。
Broadcom 是 FullMAC 芯片的老手——现在基本上只做这个——这使得它们成了 Wii U 几乎无法逾越的墙。
Realtek 适配器之所以幸免,只是因为他们制造的是 SoftMAC 硬件,却写了一个 FullMAC 风格的驱动,自带一套独立的 Wi-Fi 标准实现。他们确实是把驱动写错了,所以一个更好的驱动能立刻修复问题。
## 将 Vanilla 移植到树莓派
对于真正的手柄形状设备,观众投票选择了树莓派。从纸面上看这很合理:它运行 Linux,而且即使是最便宜的树莓派 Zero 也有 Wi-Fi、传感器、显示器和摄像头。
问题是:树莓派的 Wi-Fi 芯片是 Broadcom 的。另外,手柄工作在 5GHz,而树莓派板载 Wi-Fi 只有 2.4GHz。所以板载 Wi-Fi 无论如何都没用。但因为树莓派运行 Linux,可以插入一个兼容的 SoftMAC USB Wi-Fi 适配器来替代。
再看看其他单板计算机,Orange Pi Zero 3 和 2W——讽刺的是颜色是蓝色——是很强的竞争者,因为它们标配 5GHz Wi-Fi 和小天线。但测试其中一个时,又出现了另一个 FullMAC Wi-Fi 芯片,给出熟悉的 `ASSOC-REJECT` 错误。这使树莓派成了主要目标。
## 让 Pi Zero 足够快
主要挑战是让 Vanilla 在入门级硬件上运行良好。开箱即用时,它跑得很差。选定的基线是 2015 年的原版树莓派 Zero——一台拇指大小的十年旧硬件。它很慢,但如果 Vanilla 能在那里运行,那它就能在任何地方运行。
计划是把一切精简到极致:
- 不要 Qt 界面
- 不要桌面环境
- 不要窗口管理器
- 以尽可能少的开销直接绘制到 GPU
在十五天的直播开发中,一个新的前端用 SDL 编写,这是一个比 Qt 底层得多的库。SDL 提供了一条直接绘制到 GPU 的路径,使用的是 Linux 内核特性 **KMSDRM**——内核模式设置直接渲染管理器。
显示视频更困难。Pi Zero 的 CPU 无法实时解码 Wii U 的 480p 视频流。但 Pi Zero 有一个独立的硬件解码器芯片,能够解码高达 1080p30,绰绰有余。目标是让硬件解码的帧直接送到 GPU,而不经过 CPU 往返。
这出奇地复杂。树莓派支持这一点,但官方文档很难找到。一个 GitHub 上的示例项目作为参考,FFmpeg 也不得不替换为分支版本,因为连 FFmpeg 都无法开箱即用地做到这一点。几天之后,视频流终于通了。
出乎意料的是,视频流很流畅。屏幕上显示的一切,除了演示者的脸,都运行在一台 2015 年的 5 美元电脑上。
## 半秒延迟问题
视频确实有一个巨大的问题:接近半秒的延迟,足以让游戏几乎无法玩。在 PC 上完全没有延迟。
一个 2013 年的晦涩论坛帖子描述了完全相同的问题:延迟在半秒到数秒之间。有回复甚至提到了 Wii U 手柄,同时想知道如何实现零延迟视频。楼主最终发现,调整 H.264 的一个 SPS 参数就能消除所有可感知的延迟。
H.264 是世界上最大的视频压缩算法之一,用于蓝光、网络视频和 Wii U 手柄。SPS,即 **序列参数集**,是嵌入在所有 H.264 视频流中的一个组件,存储了视频编码方式以及如何解码。这里的关键参数是 `max_dec_frame_buffering`,它告诉解码器要缓冲多少帧。
Vanilla 根本没有提供这个选项,所以解码器只能靠自己的最佳判断。PC 上 FFmpeg 的软件解码器选择不缓冲帧,但树莓派解码器会缓冲。缓冲帧存在是因为 H.264 使用时间压缩——存储帧之间的差异,包括同时引用过去和未来帧的双向帧。Wii U 不使用双向帧,但树莓派解码器还是加了延迟以防万一——除非通过 `max_dec_frame_buffering` 明确告知不要。
问题是:Wii U 实际上从不发送 SPS 参数。任天堂把它们硬编码在了手柄里。Vanilla 必须自己编造这些参数。而且 SPS 参数不是以常规方式存储的——它们使用 **Exp-Golomb** 编码压缩,使得在不编写完整解析器的情况下很难修改。
解决方案是让 Vanilla 动态生成自己的 SPS 参数。这花了一整天来弄清楚编码方式、理解每个参数、处理字节序。它成功了:半秒延迟终于消失了。
但仍有 4 帧延迟——好多了,但在游戏过程中仍然明显。
## 为弱硬件优化 Vanilla
性能优化工作更有趣。简单的性能分析工具可以识别程序的慢速部分,不过 Pi Zero 太原始了,这些工具实际上无法在它上面运行。所以测试在主 PC 上进行,理论依据是慢代码在哪里都是慢的。
### 数据包处理中的位反转
Wii U 发送的数据包头有反转的位。drc-sim 和 Vanilla 会把整个数据包进行位反转,然后再把数据部分反转回来。位反转在 x86 上开销很大,而且 Pi Zero 太旧,无法使用 ARM 专用的位反转指令。这每帧要花掉几毫秒——而 60 FPS 的一帧也只有 16 毫秒。
只对实际读取的头字段做位反转,跳过了 99% 的处理。测试不同的反转方法后,找到了一个明显更快的优胜者,比 drc-sim 的手动方法快好几倍,使 Pi 上的位反转降到 1 毫秒以下。
### 电池状态错误
Vanilla 尝试把 Linux 的实际电池状态发送给 Wii U,但只应每两秒发送一次。限流器包含一个致命错误,导致它什么也没做,所以 Vanilla 每帧都会读取电池状态。这对 CPU 造成了很大压力,尽管 PC 和树莓派都不是靠电池运行的。
几个月后,这个错误被重新发现,并且在另一段代码中写了第二个限流器。直到剪辑视频时,演示者才意识到两个限流器都存在。坏掉的那个被移除了。
### 绕过管道
Vanilla 分为两部分:前端和管道。管道负责 Wii U 连接,并将数据包中继给前端。这有好处——root 权限被限制在管道内,管道可以在虚拟机或另一台计算机上运行——但在同一台机器上,它只是浪费时间复制数据。优化版本允许前端直接接收数据包,在单机运行时完全绕过管道。
### wpa_ctrl_recv 错误
管道有一个中心循环来检测断开连接,调用 `wpa_supplicant` 的 `wpa_ctrl_recv` 函数。演示者假设这是一个阻塞函数——它会等待直到有消息到达。事实并非如此。在 while 循环中疯狂调用它,占满了一个完整的 CPU 线程,这对 Pi Zero 来说是个大问题。由于 Wi-Fi 断开不需要毫秒级响应,检查改为每秒一次,处理开销可以忽略不计。
## 一个新的通用前端
下一步是菜单系统。原计划是为每个平台编写不同的前端,但在它们之间保持功能一致将是一场噩梦。取而代之的是,一个用 SDL 构建的前端可以在任何地方工作,专为小型触摸屏设计,并贴合 Wii U 的美学风格。
这意味着要停止原来的 Qt 界面。桌面 PC 是 Wii U 手柄最不合理的平台,为它们维护单独的前端没有意义。新的 SDL 前端成为 Vanilla 的主力前端,可在 Pi 和任何其他平台上使用。
## Pi Zero 2:仍然不够好
所有优化都让 Vanilla 运行得更流畅,但没有解决 4 帧视频延迟。2022 年发布的 Pi Zero 2 速度明显更快,价格与原版 Pi Zero 相同。它消除了偶发的卡顿点,但它的解码器仍然有同样的 4 帧延迟。
一个发送和接收解码器帧的小测试程序揭示了原因:必须先发送三帧,解码器才会返回任何内容,而且视频流永远落后三帧。再加上一帧用于垂直同步,就解释了总共 4 帧的延迟。
FFmpeg 的软件解码器没有延迟,但对 Pi Zero 1 来说太慢了。Pi Zero 2 能处理得更好,但还不够好——CPU 勉强跟不上,导致严重的视频损坏。
结论:两款树莓派 Zero 都不是真正适合的手柄替代品。它们能做到,但体验明显更差。
## Orange Pi 的惊喜
抽屉里那个 Orange Pi 没有关于解码器延迟的文档,但值得一试。测试程序被重新适配到 Orange Pi 的解码器——它立即返回了帧。没有强制延迟。
花了几天时间让 Orange Pi 的解码器-显示管线在 Vanilla 中工作之后,出现了新问题:Orange Pi 的 GPU 要求纹理宽度能被 64 整除。Wii U 的视频宽度不满足这个要求。解码器已经将宽度填充到能被 16 整除,但这还不够。解码器的对齐方式可以配置,但只能通过修改 Linux 驱动的源代码。
回报是:一个无延迟的手柄克隆。不是字面意义上的零延迟,但实际上与原版手柄相当。而且 Orange Pi Zero 比树莓派 Zero 强大得多,没有明显的卡顿点。
讽刺的是,让 Orange Pi 有吸引力的 5GHz Wi-Fi 最终没用上。而那个未宣传的零延迟解码器让它遥遥领先于竞争对手。
## 这真的实用吗?
即使 Orange Pi 能工作,也有很大的保留意见。Orange Pi Zero 2W 两年前很容易买到,13 美元,但当前的存储芯片危机已使一些报价推高到 150 美元。
单板计算机本身不是手柄。它还需要:
- 屏幕
- 扬声器
- 麦克风
- 运动传感器
- 摄像头
- 外壳
这些零件至少需要 100 美元,还不算你用的板子。
相似文章
Raspberry Pi Pico W 作为 USB Wi-Fi 适配器
一个将 Raspberry Pi Pico W 转变为 USB Wi-Fi 适配器的项目,提供了一种通过 USB 为设备添加无线连接的简单方法。
Nintendo Wii U games running from a 1980's Bernoulli disk [video]
通过SCSI转USB适配器将1980年代的90MB伯努利磁盘连接到Wii U,成功安装并运行了Game Boy Advance游戏《银河战士 融合》,展示了复古存储介质与现代游戏机的兼容性实验。
Windows NT 用于 GameCube/Wii
该项目将 Windows NT 移植到任天堂 GameCube 和 Wii 主机,支持多种输入设备和驱动程序。它是开源的,可在 GitHub 上获取。
Show HN:Pokémon Emerald 移植到 Raspberry Pi Pico 2
一位开发者将 Pokémon Emerald 移植到 Raspberry Pi Pico 2 (RP2350) 微控制器上原生运行,通过将 GBA 游戏重新编译为 Cortex-M33,并在第二个核心上重新实现 PPU,实现了 60 fps 的 HDMI 输出。
Pico W固件创建无驱动USB WiFi桥接器(Layer-2)
一个针对树莓派Pico W的开源固件项目,通过透明的Layer-2桥接将其转换为无驱动USB WiFi适配器,支持WPA2/3协议并附带管理控制台,但受限于USB 1.1的传输速率。