基于PiKVM制作M1 Mac Mini KVM

Table of Contents

背景

因科研需求,让实验室购买了一台M1芯片的Mac Mini进行相关测试。但由于我的操作会涉及大量Kernel Panic,且希望将机器丢在远端,因此需要有一种方法能够让我远程进行真机的键盘鼠标操作以及按电源键的操作。

相关工作

之前有了解到PiKVM项目,通过树莓派的OTG功能接上HDMI采集卡,就可以实现远程控制电脑的键盘鼠标,并可以自定义各种GPIO的设备,实现连接开关按钮、LED指示灯,甚至还支持伺服电机,能够直接连接机械手完成按电源键的操作。

此外,它还可以通过OTG模拟一个ncm/rndis网卡、USB串口、USB光驱、U盘等设备。但值得注意的是,这些设备在macOS与Linux中均可使用,但U-Boot不支持ncm/rndis网卡与USB串口,甚至打开后会导致U-Boot中无法使用PiKVM键盘控制(原因待研究)。

挑战

最大的挑战在于,Apple Silicon的Mac不再像之前的x86机器那样,通过按住键盘上的option就可以进入启动菜单,而需要长按电源键,这就给远程管理带来了困难。

受到twd2的这三篇文章启发(远程控制Apple M1 Mac Mini制作Apple M1 Mac Mini远程控制装置安装Apple M1 Mac Mini远程控制装置),决定用同款手指机器人实现,但我打算在他的基础上做一些简化,不使用PiKVM扩展板(为了直接暴露GPIO,这样就不用再使用Arduino),以降低成本并利用已有的树莓派和CSI HDMI采集卡。

设计

为了基于PiKVM解决挑战,我采购了以下物料:

名称 用途 参考价格
Type-C扩展坞(3*USB+千兆网卡) 连接USB网卡与PiKVM的USB OTG 80
HDMI线 连接Mac Mini与PiKVM的采集卡 10
树莓派4B 运行PiKVM系统 400
CSI HDMI采集卡 采集Mac Mini HDMI输出的图像(可用30元的USB2.0采集卡的替代,但延迟更高) 150
手指机器人 按M1电源键 150
数字光敏电阻 给PiKVM反馈Mac Mini电源指示灯状态(注:树莓派GPIO没有模拟输入) 10
杜邦线若干 连接手指机器人和光敏电阻 10
USB Type C带辅助供电数据线 将树莓派的Type C接口的供电与OTG数据功能分离 25
USB 2.0延长线 连接树莓派Type C OTG与Type-C扩展坞。并需要自己动手断开红色的VCC 10
智能插座 控制M1 Mac Mini的电源输入(推荐选带计量功能的,可以知道当前状态) 50
32G TF卡 装PiKVM系统 30
合计 (其中树莓派4B和CSI采集卡应该容易报销) 925

工具包括:电工胶布、剪刀、螺丝刀、热熔胶(用于固定光敏电阻)。

这里我需要完成2个Mod,一个是断开USB2.0延长线的VCC针脚(通常是红色),另一个是拆开手指机器人,将伺服电机直接连接到树莓派的GPIO。

手指机器人伺服电机连接杜邦线

USB延长线断开VCC,隔离供电。(注:GND不可断开,否则数据线失去共地。)

之后用电工胶布包好即可。

PiKVM配置

硬件连接

根据此图,将光敏电阻数字输出连接到树莓派GPIO 24(18引脚),将手指机器人的伺服电机控制信号连接到树莓派的GPIO 18(12引脚)。

电源根据选购元件的规格,查阅树莓派GPIO定义的电压即可。

其他硬件应该不需要说吧?

软件配置

首先将PiKVM镜像烧入SD卡。

SSH进入PiKVM,首先将root remount为rw,在PiKVM中可通过rw命令完成,然后进入/etc/kvmd/override.yaml,增加以下配置:

kvmd:
    gpio:
        drivers:
            servo1:
                type: pwm
                chip: 0                      # PWM Chip Number
                period: 20000000             # Servo Motor SG90 Period in nano-seconds
                duty_cycle_push: 850000     # Servo Motor SG90 duty_cycle for pushing button
                duty_cycle_release: 2000000  # Servo Motor SG90 duty_cycle for releasing button
        scheme:
            short_press:
                driver: servo1
                pin: 0  # Pin number is the PWM channel number on the PWM Chip
                mode: output
                switch: false
                pulse:
                    delay: 1
                    max_delay: 2
            extra_long_press:
                driver: servo1
                pin: 0
                mode: output
                switch: false
                pulse:
                    delay: 15
                    max_delay: 20
        view:
            header:
                title: Controls
            table:
                - ["#Servo - Short Press", "short_press|Press"]
                - ["#Servo - Recovery Mode", "extra_long_press|Press"]

其中,修改duty_cycle_push可以改变手指机器人伺服电机的移动幅度,个人建议固定伺服电机与M1相对位置后调整一个刚好能按下的值即可,这样哪一天Mac Mini位移了我们也可以通过增加移动幅度来保证按钮能够按下。此外,我买的手指机器人全部按下可以将duty_cycle_push调整到750000,再低的话就会在按下时伺服电机会无法到达对应的位置一直处于工作状态(此时能听到声音),导致过高的功耗。

其中,对于我们常见的进入恢复模式功能,我也已在上面定义好,通过按下15s实现。

修改完成后systemctl restart kvmd即可生效。

网络配置

还记得我们前面提到的智能插座吗?如果把它扔在学校的机房,只有校园网这样需要认证的WiFi,也无法连上网。

这时,我们可以考虑使用树莓派自带的WiFi开一个热点,而PiKVM也恰好预置了hostapd软件。这里将树莓派发射的WiFi直接与有线网桥接:

删除/etc/systemd/network/*

/etc/systemd/network/下添加以下配置文件:

==> br0.netdev <==
[NetDev]
Name=br0
Kind=bridge

==> br0.network <==
[Match]
Name=br0

[Network]
DHCP=ipv4

==> eth0.network <==
[Match]
Name=eth0

[Network]
Bridge=br0

==> usb0.network <==
[Match]
Name=usb0

[Network]
Bridge=br0

其中,usb0是pikvm的otg网卡,与WiFi无关,但我们后续如果要使用PiKVM的网卡功能,也就可以直接使用了。

修改完成后,使用systemctl restart systemd-networkd重启systemd-networkd,此时树莓派IP地址可能发生变化(如果你继续使用DHCP)。

然后,配置/etc/hostapd/hostapd.conf,添加以下修改,配置SSID和密码,并让WiFi接入网桥br0:

21c21
< bridge=br0
---
> #bridge=br0
87c87
< ssid=PiKVM
---
> ssid=test
1625c1625
< wpa=2
---
> #wpa=2
1645c1645
< wpa_passphrase=secret passphrase
---
> #wpa_passphrase=secret passphrase
1702c1702
< rsn_pairwise=CCMP
---
> #rsn_pairwise=CCMP

然后,运行:systemctl enable hostapd; systemctl start hostapd;

此时,我们会创建一个2.4GHz的PiKVM的网络,密码为secret passphrase,它与我们树莓派的LAN口桥接。

这样,我们就可以让智能插座连上网了。

如果你的树莓派上接的网络是静态IP,而智能插座不支持,这种情况下就不能将wifi接入网桥,可以去掉bridge的选项,然后安装dnsmasq并配置作为DHCP和DNS服务器,并给hostapd开启后的wlan0网卡配置静态IP,然后配置IPv4 MASQUERADE,就可以上网了,具体可以参阅各种教程。

结果展示

进入恢复模式展示:

按键展示:

运行U-Boot

直接跑asahilinux的安装脚本安装一个UEFI runtime即可。默认是2-stage的m1n1,其中第一级会启动到第二级的m1n1,该文件位于asahi安装脚本创建的ESP分区中的m1n1/boot.bin,我们可以替换掉这个文件,改成自己编译的任何东西,或在这个文件追加字符,以增加U-Boot启动参数。

当前Asahilinux安装脚本自动放置的U-Boot版本较老,且无法针对我的CSI采集卡输出合适的分辨率,为了解决这问题,我参考了m1 Debian的安装过程,其中的bootstrap.sh脚本提到,可以在m1n1+u-boot payload的binary中追加display=1920x1080,经过测试,修改后能够正确在PiKVM中运行。

其他几个问题

  1. U-Boot与Linux的USB

    不知道是什么原因,我的机器上无论在U-Boot还是Linux中,USB-A口均无法使用,USB-C口可以使用但是速度为USB2.0,且热插拔设备很容易挂掉。

  2. U-Boot的USB键盘问题

    在U-Boot检测USB设备阶段必须按几下键盘,给USB一些中断,否则USB键盘会报错,进入Linux Kernel前USB键盘也无法使用。

    所以我通常想要通过m1n1->u-boot->grub->linux这样的启动方式,修改grub中的启动参数时,需要先在u-boot中按键盘,此时不会自动启动,再敲boot进入grub,此时grub下才可正确使用键盘。

  3. U-Boot网卡的小坑

    截止目前(U-Boot 2022.07-rc6),U-Boot不支持M1 Mac Mini的有线网卡,但支持的USB网卡包括AX8817X、AX88179、RTL8152B/8153、MSC7830、SMSC LAN95x等网卡。当然,我们需要重新编译后自己在config中打开。我们常见的USB千兆网卡主要就是AX88179和RTL8153,因此通常随意买一个USB千兆网卡即可使用。而常见的2.5G的RTL8156是不支持的。

    此外,U-Boot打开网络支持CONFIG_NET时,默认不会打开CONFIG_DM_ETH,而CONFIG_EFI_LOADER依赖DM_ETH [=y] || !NET [=y],导致若没有手动打开DM_ETH会导致无法使用EFI启动。

  4. U-Boot界面卡死

    在U-Boot和GRUB中,经常会遇到界面卡着不动的情况,但每次按一下键盘又能继续运行,我怀疑是时钟中断适配还存在问题导致,当遇到这种觉得系统卡住的情况多按按键盘给几个中断就行。

  5. 按电源键需要的力度

    之前买过某40元左右的直线舵机,拉力达35g,想拿来替代机械手,但很可惜,实际测试中,它的力气不够大,无法按下Mac Mini的电源键。

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to Top