ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RK3506嵌入式Qt HMI开发实战:从交叉编译到systemd自启动

RK3506嵌入式Qt HMI开发实战:从交叉编译到systemd自启动 最近接了一个工业设备控制面板的项目要在瑞芯微 RK3506 工业开发板上跑一套 Qt GUI 应用。从交叉编译工具链的搭建到 Qt 界面在 /dev/fb0 上亮起来再到最后用 systemd 做开机自启动整套流程走下来踩了不少坑也沉淀出一套能直接复用的路径。这篇就把选型逻辑、环境搭建、应用层几个典型问题以及自启动配置完整记录下来适合正打算在 ARM 嵌入式板上做 Qt 界面、或者刚拿到 RK3506 开发板想快速跑通 demo 的朋友参考。1. 为什么是 RK3506 这块板子工业 HMI 选型与硬件资源盘点1.1 RK3506 在瑞芯微产品线里的定位瑞芯微现在被大家熟悉的是 RK3568、RK3588 这类偏应用处理器的芯片RK3506 在普通玩家圈子里存在感没那么高但放在工业场景里其实非常合适。它属于嵌入式 SoC面向的是工业 HMI、数据采集终端、设备控制器这类对实时性和稳定性要求更高的场景。相比 RK3568 这种四核 A55 平台RK3506 在性能和功耗之间取了另一个平衡点跑界面不需要多强的算力但工业接口必须齐全、启动必须快、功耗必须低、长期供货必须有保障。当时在 RK3506 和 RK3568 之间犹豫了一下。后来想清楚一个问题这个项目只是做一块 7 寸屏的控制面板界面上主要是设备状态、参数配置、历史曲线没有视频编解码、没有深度学习推理RK3568 的性能有一大半是浪费的。RK3506 的优势反而更契合成本更低、PCB 设计更简单、整板功耗小不需要主动散热片。如果你的项目也是这种“轻量级 GUI 工业控制”的组合RK3506 这个定位是对的。1.2 拿到开发板后建议先做的三件事不要一上来就折腾 Qt先把板子的底子摸清楚。我建议按下面三步走确认固件和内核版本用官方 SDK 构建的 Linux 镜像烧进去确认内核版本、rootfs 类型Buildroot 还是 Debian这决定了后面 Qt 是放板子上本地编译还是走交叉编译。确认显示接口和触摸屏方案RK3506 开发板一般带 MIPI DSI、RGB 或者 LVDS 接口。项目用的屏是 RGB 并口加电容触摸这点必须在硬件阶段确认因为 Qt 的 linuxfb 或者 eglfs 后端都直接依赖 /dev/fb0。打通两条调试通道一条是串口 console用于内核和系统启动阶段的日志另一条是网络方便后面用 NFS 挂载 rootfs 或者直接通过 SSH 往板子里拷文件。没有这两条通道后面排错会非常痛苦。1.3 显示链路的基本概念framebuffer 是什么嵌入式 Qt 开发绕不开 framebuffer 这个概念。可以把 /dev/fb0 理解成一块“直接映射到屏幕的内存画布”应用程序往这块内存里写像素数据显示控制器就把它刷到 LCD 上。Qt 的 linuxfb 插件做的事情很简单打开 /dev/fb0通过 mmap 把显存映射到用户空间然后所有绘图操作都是对这一块内存的操作。这块画布的分辨率和像素格式由内核里的 display 驱动和 bootloader 里的 lcd 参数决定。如果启动之后 /dev/fb0 不存在或者 fbset 看到的分辨率不对后面 Qt 界面显示必然是花的、偏移的甚至完全黑屏。所以我在搭 Qt 环境之前先确保 bcat /dev/urandom /dev/fb0 能直接把屏幕刷成雪花这一步能确认显示链路是通的。2. 交叉编译环境搭建从 SDK 到第一行 Qt 代码上屏2.1 交叉编译工具链的选择用 SDK 自带的别自己折腾在 RK3506 开发板上本地编译 Qt 不是不行但效率太低而且嵌入式板子的存储资源有限源码包解压一遍就要占掉不少空间。正确的做法是在 x86 的 Ubuntu 主机上做交叉编译产物拷到板子上运行。交叉编译工具链优先用 SDK 里预编译好的那套通常是arm-buildroot-linux-gnueabihf-或者类似前缀。不要自己去 Linaro 官网随意下版本不匹配会在链接阶段出现各种奇怪报错。工具链不需要“安装”解压之后把 bin 目录加进 PATH 就行。验证方式很简单写一个 hello.c用交叉 GCC 编译然后 file 一下确认生成的是 ARM 架构的 ELF。export PATH/opt/arm-buildroot-linux-gnueabihf/bin:$PATH export CCarm-buildroot-linux-gnueabihf-gcc export CXXarm-buildroot-linux-gnueabihf-g这里要提醒一个细节编译 Qt 和 tslib 时CC、CXX这两个环境变量的值会不一样。因为configure脚本会显式传-xplatform所以不一定依赖环境变量但为了保险先 export 出来能减少很多问题。2.2 Qt 版本选择为什么锁定了 Qt 5.15.2Qt 现在都出到 Qt 6 了但嵌入式领域大家依然对 Qt 5.15 情有独钟因为它有 LTS 维护周期而且生态里大量的第三方模块还是针对 Qt 5 的。我当时下载的是 Qt 5.15.2 的源码包qt-everywhere-opensource-src-5.15.2.tar.xz体积不算小解压后源码目录 2-3 个 GB编译前确认主机磁盘足够。很多人会问为什么不用 Qt 6嵌入式场景下 Qt 6 的图形后端对 OpenGL ES / Vulkan 的依赖更重而 RK3506 这类入门级工业 SoC 的 GPU 能力相对有限在 linuxfb 这种 2D 场景下 Qt 5 反而更轻快。而且 Qt 5.15.2 的交叉编译资料非常多踩坑时能搜到的参考也多。configure 的时候我的常用配置参考如下./configure \ -prefix /opt/qt_arm \ -xplatform linux-arm-gnueabihf-g \ -release \ -no-opengl \ -no-xcb \ -linuxfb \ -tslib \ -no-sql-mysql \ -no-sql-sqlite \ -no-gtk \ -no-cups \ -nomake examples \ -nomake tests几个关键参数说明-xplatform linux-arm-gnueabihf-g指定平台配置qmake 会根据这个名字找mkspecs目录下对应的配置文件。-no-opengl关掉 OpenGL因为 linuxfb 根本用不上如果后面想用 eglfs 做硬件加速再单独开。-linuxfb启用 linuxfb 平台插件这是最核心的显示后端。-tslib启用 tslib 支持后面触摸屏校准要靠它。-no-xcb去掉 X11 支持嵌入式板上没有 X server。2.3 tslib 的交叉编译触摸屏校准的前置条件触摸屏有两种常见方案电阻屏和电容屏。电阻屏需要校准电容屏一般出厂就带了坐标映射但为了保险起见工业项目里通常还是会接一层 tslib。tslib 的作用是把触摸驱动上报的裸坐标转换成屏幕像素坐标并做滤波和校准。编译 tslib 也比较标准./autogen.sh ./configure --hostarm-buildroot-linux-gnueabihf --prefix/opt/tslib --enable-input make make install编译完之后把/opt/tslib整个目录拷贝到开发板然后在板子上设置环境变量export TSLIB_ROOT/opt/tslib export TSLIB_CONSOLEDEVICEnone export TSLIB_FBDEVICE/dev/fb0 export TSLIB_TSDEVICE/dev/input/event1 export TSLIB_PLUGINDIR$TSLIB_ROOT/lib/ts export TSLIB_CALIBFILE/etc/pointercal注意TSLIB_TSDEVICE如果不对ts_calibrate会提示打不开设备。开发板上有多个输入设备时可以先cat /proc/bus/input/devices确认触摸屏对应哪个 event 节点。2.4 用 NFS 挂载调试改代码后不用反复烧写 rootfs开发调试阶段我不建议每次把编译好的 Qt 库和应用都拷到板载 flash 里。先在 Ubuntu 主机上搭一个 NFS 共享目录把 Qt 的 lib、plugins 和应用放里面板子启动后通过 NFS 挂载来运行。这样在主机上交叉编译出新版本板子重启一下就生效迭代速度会快很多。板子端挂载命令大致是mkdir -p /mnt/qt mount -t nfs 192.168.1.100:/opt/qt_arm /mnt/qt挂载成功之后设置 Qt 运行环境变量export QTDIR/mnt/qt export LD_LIBRARY_PATH$QTDIR/lib:$QTDIR/plugins/platforms export QT_QPA_PLATFORMlinuxfb export QT_QPA_PLATFORM_PLUGIN_PATH$QTDIR/plugins/platforms export QT_QPA_FB_TSLIB1然后运行一个最简单的 Qt Widgets 程序。如果屏幕上能出现窗口说明从编译到显示这条链路已经通了接下来就可以安心搞应用层。3. 应用层三大硬骨头型号校准、中文字体、串口模块3.1 触摸坐标异常从“越点越偏”到校准文件的作用Qt 界面跑起来之后第一个让人头疼的问题就是触摸不准。我当时碰到的情况是点屏幕左上角鼠标箭头在右下角点击事件落点完全对不上。这个问题在电气上一般两种可能屏幕没有校准或者内核触摸驱动坐标轴方向和屏不一致。先做校准。在板子上运行 tslib 自带的工具ts_calibrate它会依次显示五个十字光标依次点完后会在/etc/pointercal里生成一组校准参数。如果你的 Qt 启动脚本里没有ts_calibrate这一步可以直接拷贝别人板子上做好的 pointercal 文件注意别拷错了平台因为不同触摸屏的校准参数不通用。但校准完了还有一个坑Qt 的 linuxfb 插件默认不认 tslib。需要在环境变量里显式告诉 Qt 使用 tslib 作为输入设备export QT_QPA_GENERIC_PLUGINStslib:/dev/input/event1这里有一个很容易踩的细节QT_QPA_FB_TSLIB1是 Qt 5 之前的老用法Qt 5.15 里更推荐通过QT_QPA_GENERIC_PLUGINS指定。如果你发现触摸没反应检查一下环境变量里是否同时设置了这两个有时候老变量会把新逻辑搅乱。如果校准后依然不对那就不是用户态的问题了。可以用evtest /dev/input/event1看看裸触摸事件上报的原始坐标范围。比如屏幕分辨率是 1024x600但上报的 X 范围是 0~32767那说明驱动没有做 coordinate scaling这种情况靠 pointercal 救不回来得修改内核设备树里的touchscreen-inverted-x/y或者调整 X/Y 坐标翻转标志。3.2 中文显示成方块字体文件与 fontconfig 的关系界面上的英文和数字显示正常中文全部变成一个个“口口口”这是嵌入式 Qt 里出现频率最高的问题本质就是系统里没有中文字体文件。解决思路有三步缺一不可。第一准备字体文件。我在主机上下载了开源的文泉驿微米黑或者思源黑体的 TTF 文件拷贝到板子的/usr/share/fonts/truetype/目录下。文件名不要用中文用wqy-microhei.ttf这种纯英文命名避免一些底层代码对非 ASCII 路径处理有问题。第二确认 Qt 的字体引擎支持 TTF。这取决于 Qt 编译时有没有带 FreeType 支持。如果 configure 的时候指定了-no-freetype那不管你怎么拷字体文件都没用。用下面命令验证一下板子上的 Qt 库是否链接了 freetypeldd libQt5Gui.so | grep freetype没有输出的话只能回主机重新配置编译 Qt。第三在应用里指定字体。可以在 main.cpp 里设置全局字体QFont font(wqy-microhei); font.setPixelSize(18); QApplication::setFont(font);也可以把字体文件放在应用目录运行时动态加载这种方式对系统目录不可写的情况更友好QFontDatabase::addApplicationFont(/usr/share/fonts/truetype/wqy-microhei.ttf);我个人的习惯是优先用QFontDatabase::addApplicationFont因为它在应用层就能解决不用依赖系统 fontconfig 的配置调试的时候隔离性更好。3.3 Qt SerialPort 模块报错unknown module(s) in qt: serialport这个坑在热搜词里反复出现说明不是只有我一个人碰见。在 pro 文件里写了QT serialport编译时却在 qmake 阶段就报Project ERROR: unknown module(s) in QT: serialport原因是Qt 的 SerialPort 模块不是默认编译的。在 Qt 5.15.2 里SerialPort 属于独立的qtserialport模块如果下载的是 Qt base 源码包qtbase里面根本不会包含这个模块。要单独拿到qtserialport-everywhere-src-5.15.2.tar.xz解压后交叉编译安装cd qtserialport-everywhere-src-5.15.2 /path/to/qt_arm/bin/qmake make -j4 make install编译完成后确认/opt/qt_arm/lib下生成了libQt5SerialPort.so并且mkspecs/modules目录下出现了对应的 pri 文件。然后再回到应用工程里qmake 能正常识别。写代码的时候还要注意一个点SerialPort 的打开和读写千万不要放在 UI 线程里同步阻塞。嵌入式板上串口波特率 115200一次读几十字节问题不大但如果数据量大或者对端设备响应慢UI 线程会被阻塞界面卡死。我的做法是把串口对象放进一个 QThread或者用 Qt 的moveToThread把 QSerialPort 对象迁移到工作线程class SerialWorker : public QObject { Q_OBJECT public: explicit SerialWorker(QSerialPort *port) : m_port(port) { connect(m_port, QSerialPort::readyRead, this, SerialWorker::onReadyRead); } void onReadyRead() { QByteArray data m_port-readAll(); emit dataReceived(data); } signals: void dataReceived(const QByteArray data); };3.4 一个辅助思路用 Qt 模拟鼠标点击事件排查触摸问题如果你碰到触摸事件不响应但不确定是硬件问题还是应用层事件处理问题可以在应用里用 QTest 模拟鼠标点击事件来定位。在 main.cpp 里写一小段测试代码QTimer::singleShot(3000, []() { QTest::mouseClick(QApplication::activeWindow(), Qt::LeftButton); });如果模拟点击能触发按钮响应说明 Qt 事件系统没问题问题在触摸设备驱动或 tslib如果模拟点击也没反应说明应用自身的信号槽连接或者事件过滤器有问题。这个方法能快速把问题范围缩小一半非常实用。4. GUI 框架选型与运行性能观测QWidget 还是 QML4.1 工业 HMI 界面的选择逻辑RK3506 的 CPU 性能在 ARM 嵌入式里不算强所以 GUI 框架选型直接决定了最终体验。QWidget 和 QML 选了哪一个后面整个项目路径都不一样。QWidget 是传统的 C 图形组件编译型、贴近系统底层内存占用相对可控在低性能设备上启动速度更快。QML 是声明式语言做动画、过渡、滑动效果天然流畅但运行时多一层 QML 引擎资源占用会高一些。如果你做的界面主要是“参数表格 状态指示灯 曲线绘制”这种偏工控的布局QWidget 完全够用而且开发调试简单。如果你需要做一个带动态转场、手势滑动、皮肤换色效果的精美界面QML 体验会好很多。我个人在这个 RK3506 项目里选了 QWidget原因很直接产品需求里没有酷炫动效操作人员每天面对的是固定的几个页面稳定性比灵活性更重要。4.2 资源占用与插件裁剪减少 40% 体积的打包策略Qt 应用部署到板子上第一件事是瘦身。默认安装的 Qt 库体积很大全部塞进 rootfs 会影响烧录和启动速度。我当时用两个手段压缩体积。第一个手段是只拷贝需要的库和插件依赖库通过ldd命令追踪。比如项目里用到了 Widgets、SerialPort、Network那就只拷贝对应的libQt5Widgets.so、libQt5SerialPort.so、libQt5Network.so以及它们依赖的基础库libQt5Core.so、libQt5Gui.so。插件目录里只保留platforms/libqlinuxfb.so和imageformats/libqjpeg.so、libqpng.so不要整个 plugins 目录直接拷过去。第二个手段是用 strip 去掉符号表。嵌入式系统的 rootfs 不需要调试符号strip后每个 so 能缩减 20%~30% 体积arm-buildroot-linux-gnueabihf-strip libQt5Core.so libQt5Widgets.so一个 Qt Widgets 应用依赖裁剪 strip 之后从原来的几百 MB 打包目录缩减到 60~80 MB 左右对 eMMC 和启动时间都友好得多。4.3 UI 线程刷新与数据采集线程的协作模式在工控设备里串口或者 TCP 会不停上报数据UI 需要实时更新状态、曲线和日志。如果直接在底层线程里改控件属性轻则界面卡顿重则直接崩溃。Qt 应对这个问题的正统做法是信号槽利用队列连接QueuedConnection在线程间传递数据。我在代码里把数据采集和 UI 刷新彻底解耦SerialWorker 负责读串口读取完成后通过信号把原始数据发出去MainWindow 里连接这个信号在槽函数里解析数据、更新表格和曲线跨线程的信号槽会自动转换为队列连接槽函数在 UI 线程执行不会抢占 UI 线程的执行权。刷新频率也要注意。有些数据一秒来 100 帧如果每一帧都触发一次控件重绘CPU 会扛不住。实际项目里我会用定时器做限流每 100ms 触发一次 UI 刷新把最近一次的数据批量更新上去既能保证显示不滞后又大幅降低重绘次数。5. 上电自启动systemd 服务、开机黑屏的排查5.1 用 systemd 管理自启动应用一个标准的 service 文件如果 rootfs 用的是 Buildroot 加 systemd那开机自启 Qt 应用最标准的方式是写一个 systemd service 文件。先创建一个/etc/systemd/system/qt-hmi.service[Unit] DescriptionQt HMI Application Aftersystemd-user-sessions.service Afterlocal-fs.target [Service] Typesimple WorkingDirectory/home/app/hmi EnvironmentQT_QPA_PLATFORMlinuxfb EnvironmentQT_QPA_GENERIC_PLUGINStslib:/dev/input/event1 EnvironmentLD_LIBRARY_PATH/usr/local/qt/lib:/usr/local/qt/plugins/platforms EnvironmentQTDIR/usr/local/qt ExecStart/home/app/hmi/hmi_app Restarton-failure RestartSec3 [Install] WantedBymulti-user.target有几个细节值得注意restarton-failure是工控项目里的刚需。应用在运行中如果因为野指针、内存碎片崩溃了systemd 会自动拉起避免设备面板变成一块黑屏。环境变量不要靠应用内部 setenv全部收敛在 service 文件里这样调试阶段可以通过systemctl show qt-hmi看到 ApplicationEnvironment 里实际生效的参数方便排查。Typesimple适合长时间运行的 GUI 应用如果你的启动脚本里还有复杂的初始化顺序可以考虑Typeforking但多数情况 simple 就够了。写完之后执行systemctl daemon-reload systemctl enable qt-hmi systemctl start qt-hmi systemctl status qt-hmi5.2 没有 systemd 的老 rootfsinit.d 脚本的写法有些 RK3506 的官方出厂系统是基于 Buildroot 但没启用 systemd用的是 BusyBox init。这种情况下自启动逻辑放在/etc/init.d/S99qt-hmiS99 表示在 init 脚本排序里最后一个执行。脚本内容大致是#!/bin/sh case $1 in start) echo Start Qt HMI Application export QT_QPA_PLATFORMlinuxfb export QT_QPA_GENERIC_PLUGINStslib:/dev/input/event1 export LD_LIBRARY_PATH/usr/local/qt/lib /home/app/hmi/hmi_app ;; stop) killall hmi_app ;; esac exit 0这里使用放到后台执行因为 init 脚本不能阻塞住后面的系统初始化。同样要加上 chmod x保证脚本可执行。5.3 开机黑屏问题从服务启动顺序到设备节点就绪自启动最容易翻车的场景就是“手动运行没问题开机自启就黑屏”。我在 RK3506 上遇到过一次当时的表现是systemd 显示服务已经 active但屏幕始终是黑的SSH 进去手动执行二进制又可以正常显示。排查思路是这样的第一步确认应用进程是否真的起来。ps | grep hmi_app如果进程在说明启动脚本本身没有错。第二步看 Qt 日志。linuxfb 插件启动失败会在 stderr 打印类似 “Could not open /dev/fb0” 或者 “Failed to open input device” 的信息。通过journalctl -u qt-hmi能看到。当时的问题就是/dev/fb0在应用启动时还没创建。原因是 systemd 的多用户目标里显示驱动的加载和应用服务的启动顺序没有强制约束应用启动太早帧缓冲设备还没注册。解决办法有两种。第一种粗暴而有效在 service 里加一个小的 sleep 等待ExecStartPre/bin/sleep 2第二种更正规写成一条脚本判断设备节点存在后再执行例如ExecStartPre/bin/sh -c until [ -e /dev/fb0 ]; do sleep 0.5; done生产环境我一般用第二种因为它不依赖固定延迟系统启动快慢都能适配。还有一个被忽略的坑是 tty 抢占。如果启动过程中有其他服务往 tty1 打印大量启动日志Qt 的 framebuffer 应用在 tty1 上显示可能被覆盖屏幕看起来像花屏。这时候可以把 qt 应用的虚拟终端切到 tty2 或 tty3内核启动参数里加fbconmap:2Qt 应用跑在 tty2 上启动日志就不会和界面混在一起。5.4 应用崩溃后的兜底日志记录与远程查看自启动的应用最好把 stdout 和 stderr 重定向到日志文件这样即使 systemd 的场景下 journalctl 没抓到信息也能保留一份现场日志。service 里可以加StandardOutputfile:/home/app/logs/hmi.log StandardErrorfile:/home/app/logs/hmi_err.log同时建议在应用内部做一个简单的心跳机制每隔一段时间往 /tmp/hmi_alive 写时间戳。现场排查时只要看这个文件最近修改时间就能判断应用是否还活着比登进去看进程状态更快更直观。6. 现场调试与部署连接方式、日志与固件固化6.1 开发调试阶段NFS 挂载 rootfs 的完整流程如果只是编译一个 Qt 程序通过 SSH/scp 拷到板子就能跑。但如果你还在频繁修改 Qt 库、或者需要调整系统级的库依赖反复拷贝太浪费时间。我习惯在开发阶段用 NFS 挂载整个 rootfs这样板子上的根文件系统直接用主机上的一个目录主机改代码、板子重启即生效。开发机 Ubuntu 上配置/etc/exports/home/workspace/rk3506_rootfs 192.168.1.0/24(rw,sync,no_root_squash,no_subtree_check)板子 u-boot 启动参数里指定 root/dev/nfs或者先启动到一个小的 initramfs再手动挂载 NFS 后 pivot_root。各家的 SDK 脚本不一样这里给的思路是通用的只要能通过 NFS 看到主机上的 rootfs后面改库、改应用都变得非常高效。调试稳定之后再切回 eMMC 固化避免现场设备网络不稳定导致系统启动失败。6.2 现场排查的优先级console 日志永远是第一现场嵌入式设备部署到现场之后出问题没法像在实验室那样随时接显示器。这时候第一现场永远是串口 console。我建议开发板上留一个 TTL 串口波特率 1500000 或 115200通过 USB 转串口连接电脑始终开着日志输出。排查优先级我通常这样定串口 console 有没有报错内核 panic、驱动加载失败、OOM 都会在串口体现。systemd 服务状态确认 qt-hmi 服务是否 active、退出码是什么。查看应用日志文件如果应用有完整日志输出可以把崩溃前的最后几行和串口日志交叉比对。设备节点检查确认 /dev/fb0、/dev/input/eventX、/dev/ttyS3 等是否存在。在这个项目里有一次现场反应“设备启动后偶尔屏幕没反应”我通过串口日志发现是应用在轮询串口时读到了超时数据然后陷入一个死循环CPU 满载UI 无法刷新。这类问题如果不看日志光看“屏幕没反应”这个表象根本猜不到根因。6.3 固件固化从 NFS 切回 eMMC 的正确姿势开发收敛之后把 NFS rootfs 打包成可烧录的镜像。打包根文件系统一般用 tar 打包在主机上处理后生成 ext4 镜像再用 SDK 的烧录工具烧到板子 eMMC 里。dd if/dev/zero ofrootfs.ext4 bs1M count1024 mkfs.ext4 rootfs.ext4 mkdir -p /mnt/rootfs mount rootfs.ext4 /mnt/rootfs cp -a /home/workspace/rk3506_rootfs/* /mnt/rootfs/ umount /mnt/rootfs烧录之前记得把启动参数里的root/dev/nfs改回root/dev/mmcblk0pX不然板子还是会试图从网络找 rootfs。这个问题我踩过一次烧完新的 rootfs 一拔网线就起不来。固化完成之后还要验证一个关键场景断电重启 10 次、20 次确认每次都能正常进入到 Qt 界面。嵌入式系统里偶发性的启动失败往往在 10 次以内就能暴露出来。6.4 现场部署的一个小经验留一个 reset 入口工控面板在现场如果陷入死机状态操作人员能做的只有断电重启。但有些场景不太方便断电这时候最好在界面上留一个隐藏的“退出到命令行”入口或者在系统层做一个看门狗。硬件看门狗如果 kernel 里有可以直接用/dev/watchdog软件层面则在 systemd 里配置Restarton-failure RestartSec3如果应用在运行中崩溃systemd 3 秒后自动重新拉起绝大多数场景下面板都能恢复到正常显示。我在实际部署中发现配合这个机制设备在无人值守环境下跑两三个月没有出现需要人工干预的情况。至于说应用卡死但进程还活着的情况那就得上硬件看门狗了让内核定时喂狗一旦应用假死导致喂狗中断系统自动重启这也是工业现场稳定运行的最后一道保险。
返回列表