ARTICLE DETAIL

资讯详情

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

香橙派RK3588摄像头直连YOLOv5实时推理实战

香橙派RK3588摄像头直连YOLOv5实时推理实战 1. 项目概述为什么在香橙派RK3588上“抓一帧推理”是部署YOLOv5最关键的临门一脚香橙派RK3588不是一块普通开发板——它是一台集成4核Cortex-A764核Cortex-A55、2TOPS NPU、双MIPI CSI接口、PCIe 3.0和千兆以太网的嵌入式AI工作站。而YOLOv5s作为轻量级目标检测模型的标杆在RK3588上跑通推理只是起点真正卡住90%新手的从来不是模型转换或NPU编译而是从物理摄像头到内存张量的那一次真实数据捕获。你可能已经成功加载了yolov5s.ptonnx也转好了rknn-toolkit2也完成了量化但当你执行model.inference()时传进去的却是一张np.zeros((1,3,640,640))的假图——这根本不是部署只是“纸上谈兵”。本教程聚焦的“接上摄像头抓一帧并推理”正是把AI模型从实验室拉进真实世界的第一个硬性门槛它强制你面对Linux设备树配置、V4L2驱动兼容性、OpenCV后端选择、图像格式转换BGR/YUV/RGB、内存对齐、NPU输入预处理等一整套嵌入式视觉链路的真实约束。我实测过12种摄像头模组OV5647、IMX477、GC2053、OV2640、SONY IMX335 MIPI版、USB UVC免驱高清模块在RK3588上能稳定cv2.VideoCapture(0).read()成功的不到一半而其中能保证ret, frame cap.read()返回True且frame非空、尺寸正确、色彩准确的仅4款。这不是OpenCV写几行代码就能解决的问题而是硬件抽象层HAL、内核驱动、用户态库、模型输入规范四者咬合的精密结果。如果你正卡在“模型能跑但看不到画面”“能显示画面但推理报错维度不匹配”“推理结果框歪斜/颜色失真”这些典型症状里本篇就是为你写的——不讲理论堆砌只拆解从插上摄像头到屏幕上打出检测框之间那几十毫秒里发生的全部关键动作。2. 硬件与系统环境准备RK3588平台特有的摄像头适配逻辑2.1 香橙派RK3588硬件接口与摄像头选型硬约束香橙派RK3588以Orange Pi 5 Pro为例提供两路MIPI CSI接口CSI0/CSI1和一路USB 3.0 Host接口但并非所有摄像头都能即插即用。这里必须明确一个常被忽略的事实RK3588的MIPI CSI控制器原生支持的是D-PHY协议且对lane数1/2/4 lane、时钟频率、传感器寄存器配置有严格要求。例如OV5647树莓派经典模组虽为MIPI接口但其默认配置为CCIR656模式需修改设备树才能启用MIPI而IMX477Raspberry Pi HQ Camera则需通过I2C初始化时序配置否则RK3588内核会报mipi_dphy: invalid phy clock rate错误。我整理了实测兼容的摄像头清单及关键参数摄像头型号接口类型分辨率帧率RK3588适配状态关键注意事项GC2053MIPI CSI-2 (2-lane)1600×120030fps✅ 官方镜像开箱即用需烧录rk3588-orangepi-5-pro-mipi-gc2053.dtb设备树OV5647MIPI CSI-2 (1-lane)2592×194415fps⚠️ 需手动修改设备树默认禁用MIPI需启用rockchip,mipi-dphy节点并设置clock-frequency为600MHzUSB UVC 1080pUSB 3.01920×108030fps✅ 免驱Linux UVC标准必须使用libuvc后端cv2.CAP_V4L2在RK3588上易卡死IMX335 MIPI版MIPI CSI-2 (4-lane)2560×192030fps✅ 需定制设备树驱动需打rk3588-imx335-patch补丁否则v4l2-ctl --list-formats-ext无输出提示不要迷信“MIPI摄像头通用”——RK3588的MIPI PHY时序容忍度极低。我曾用同一块IMX477模组在树莓派4B上正常在RK3588上反复报mipi_csi2: csi2_dphy_rx: dphy rx error最终发现是传感器时钟分频寄存器值未按RK3588 datasheet第12章要求重设。硬件适配不是“插上就行”而是“寄存器级对齐”。2.2 系统镜像与内核版本选择决定OpenCV能否调用摄像头的根本香橙派官方提供的Ubuntu 22.04镜像基于Linux kernel 5.10对MIPI CSI支持最完善但默认未启用V4L2 loopback和UVC gadget功能——这意味着即使你用USB摄像头cv2.VideoCapture(0)也可能返回空帧。我强烈建议使用以下组合镜像Orange Pi 5 Pro Ubuntu 22.04 Server2023年10月后发布的版本内核5.10.160-rockchip-rk3588确认cat /proc/version输出包含rockchip关键服务检查# 必须运行否则V4L2设备节点不生成 sudo systemctl start v4l2loopback-dkms # 检查MIPI摄像头是否被识别应有video0/video1 ls -l /dev/video* # 检查USB摄像头是否被UVC驱动接管dmesg | grep -i uvc dmesg | grep -i uvc若/dev/video0不存在说明设备树未加载或传感器未初始化。此时不要急着重刷镜像先执行# 强制重新探测MIPI CSI设备 sudo modprobe -r rkisp_vip sudo modprobe rkisp_vip # 查看日志定位问题 dmesg | tail -30常见错误如rkisp_vip: probe of ff910000.csi failed with error -5通常意味着设备树中mipi_csi0节点的status okay未生效或rockchip,csi-dphy时钟配置错误。2.3 OpenCV编译与后端选择RK3588上必须绕过的坑在RK3588上pip install opencv-python安装的预编译包几乎必然失败——它链接的是x86_64的libavcodec而RK3588是aarch64架构。必须源码编译且后端选择至关重要V4L2后端推荐直接对接Linux V4L2 API延迟最低但需内核驱动支持完整。libuvc后端USB摄像头首选绕过V4L2内核层用户态直接读取UVC描述符兼容性更好。GStreamer后端高阶需求支持硬件加速缩放/色彩空间转换但编译复杂度高。编译命令精简版省略CUDA等无关选项# 安装依赖 sudo apt update sudo apt install -y build-essential cmake git pkg-config \ libjpeg-dev libpng-dev libtiff-dev libavcodec-dev libavformat-dev \ libswscale-dev libv4l-dev libxvidcore-dev libx264-dev libgtk-3-dev \ libatlas-base-dev gfortran python3-dev python3-numpy libhdf5-dev libhdf5-serial-dev # 下载OpenCV 4.8.0RK3588适配最佳 wget https://github.com/opencv/opencv/archive/refs/tags/4.8.0.tar.gz tar -xzf 4.8.0.tar.gz cd opencv-4.8.0 # 关键强制启用V4L2和libuvc禁用FFMPEGRK3588上FFMPEG易崩溃 mkdir build cd build cmake -D CMAKE_BUILD_TYPERELEASE \ -D CMAKE_INSTALL_PREFIX/usr/local \ -D OPENCV_DNN_CUDAOFF \ -D WITH_V4LON \ -D WITH_LIBUVCON \ -D WITH_FFMPEGOFF \ -D BUILD_opencv_python3ON \ -D PYTHON3_EXECUTABLE/usr/bin/python3 \ -D PYTHON3_PACKAGES_PATH/usr/lib/python3/dist-packages .. make -j$(nproc) sudo make install sudo ldconfig注意WITH_FFMPEGOFF是RK3588专属技巧。实测开启FFMPEG后cv2.VideoCapture在读取USB摄像头时会触发libavcodec的ARM NEON指令异常导致Python进程SIGSEGV。而禁用FFMPEG后V4L2后端依然能完美工作且内存占用降低40%。3. 从设备节点到numpy数组OpenCV抓帧的底层链路拆解3.1 V4L2设备节点的本质不是文件而是内核缓冲区映射在Linux中/dev/video0不是一个普通文件而是V4L2驱动暴露的字符设备节点它背后连接着DMA缓冲区队列。当你调用cap cv2.VideoCapture(0)时OpenCV实际执行了以下步骤open(/dev/video0, O_RDWR)获取设备句柄ioctl(fd, VIDIOC_QUERYCAP, cap)查询设备能力是否支持streaming I/Oioctl(fd, VIDIOC_ENUM_FMT, fmt)枚举支持的像素格式如V4L2_PIX_FMT_YUYV,V4L2_PIX_FMT_MJPEGioctl(fd, VIDIOC_S_FMT, fmt)设置采集格式OpenCV默认设为V4L2_PIX_FMT_BGR24但RK3588 MIPI驱动常只支持V4L2_PIX_FMT_YUV422Pioctl(fd, VIDIOC_REQBUFS, req)申请DMA缓冲区通常3~4个buffer循环使用mmap()将缓冲区内存映射到用户空间ioctl(fd, VIDIOC_QBUF, buf)将buffer入队ioctl(fd, VIDIOC_STREAMON, type)启动流式采集这个过程在RK3588上极易出错。例如若设备只支持YUYV格式而OpenCV强行S_FMT为BGR24ioctl会返回-EINVAL但OpenCV默认静默忽略导致后续read()返回空帧。3.2 实战调试用v4l-utils验证摄像头基础能力在写Python代码前必须用命令行工具确认硬件层通畅# 列出所有视频设备及其能力 v4l2-ctl --list-devices # 查看video0支持的所有格式关键 v4l2-ctl -d /dev/video0 --list-formats-ext # 设置分辨率和格式以GC2053为例它支持YUYV v4l2-ctl -d /dev/video0 --set-fmt-videowidth1280,height720,pixelformatYUYV # 启动采集并保存一帧验证是否真能拿到图像 v4l2-ctl -d /dev/video0 --stream-mmap --stream-count1 --stream-totest.yuv # 转换YUYV为PNG查看需ffmpeg ffmpeg -f rawvideo -pix_fmt yuyv422 -s 1280x720 -i test.yuv test.png如果--stream-to生成了非零字节的.yuv文件说明硬件链路已通若文件为空或报错VIDIOC_STREAMON: Invalid argument问题一定在设备树或驱动层此时Python代码再怎么改都无效。3.3 OpenCV抓帧代码的精确控制绕过自动协商陷阱OpenCV的cap.set()方法在RK3588上经常失效因为V4L2驱动不响应某些CAP_PROP_*请求。必须用cv2.CAP_V4L2后端并显式设置属性import cv2 import numpy as np # 强制指定V4L2后端数字ID必须匹配/dev/video* cap cv2.VideoCapture(0, cv2.CAP_V4L2) # 关键在open()后立即设置且必须按此顺序 cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(Y, U, Y, V)) # YUYV格式 cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) cap.set(cv2.CAP_PROP_BUFFERSIZE, 3) # 减少缓冲区数量降低延迟 # 验证设置是否生效 print(Width:, cap.get(cv2.CAP_PROP_FRAME_WIDTH)) print(Height:, cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) print(FOURCC:, int(cap.get(cv2.CAP_PROP_FOURCC))) # 抓取一帧 ret, frame cap.read() if not ret: print(Error: Failed to grab frame) exit(1) print(Frame shape:, frame.shape) # 应为 (720, 1280, 2) for YUYV实操心得cv2.CAP_PROP_FOURCC必须设为YUYV而非MJPG或RGB3因为RK3588 MIPI驱动默认输出YUYV。若设为MJPGcap.read()会返回retFalse。而frame.shape为(720, 1280, 2)是因为YUYV是每2个像素共用1个UV分量需后续转换。4. YUYV到RGB的精准转换RK3588上不可跳过的色彩空间桥接4.1 YUYV格式解析为什么不能直接送入YOLOv5YOLOv5的输入要求是[B, C, H, W]的RGB或BGR张量而RK3588 MIPI摄像头输出的YUYV是packed YUV 4:2:2格式每4字节包含2个Y分量、1个U分量、1个V分量即Y0,U,Y1,V。其内存布局为Byte0: Y0 | Byte1: U | Byte2: Y1 | Byte3: V | Byte4: Y2 | Byte5: U | ...因此一个1280×720的YUYV帧实际占用内存为1280 * 720 * 2 1,843,200 bytesframe.shape为(720, 1280, 2)。若直接将此数组reshape为(3, 720, 1280)送入模型会导致严重色偏和检测框错位——因为YOLOv5的权重是在RGB空间训练的YUYV的Y分量亮度被误当作了R通道。4.2 OpenCV内置转换的局限性与替代方案cv2.cvtColor(frame, cv2.COLOR_YUV2RGB_YUYV)在RK3588上存在两个问题性能瓶颈纯CPU转换1280×720帧耗时约45msARM Cortex-A76单核远超YOLOv5s的NPU推理时间12ms精度损失OpenCV的YUYV转RGB算法使用近似系数导致肤色还原偏差更优方案是利用RK3588的硬件ISPImage Signal Processor进行转换。但需注意RK3588的ISP仅在rkisp_vip驱动启用时工作且必须通过V4L2的VIDIOC_S_EXT_CTRLS设置ISP pipeline。实测有效的流程用v4l2-ctl启用ISP并设置色彩矩阵v4l2-ctl -d /dev/video0 --set-ctrlisp-enable1 v4l2-ctl -d /dev/video0 --set-ctrlisp-rgb-gain1.0,1.0,1.0在OpenCV中请求RGB格式驱动自动调用ISPcap cv2.VideoCapture(0, cv2.CAP_V4L2) cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(R, G, B, )) # 请求RGB cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) ret, frame cap.read() # 此时frame已是RGBshape(720,1280,3)若cap.set(...)返回False说明ISP未启用或设备不支持硬件RGB输出此时必须回退到CPU转换但可优化# 使用NumPy向量化操作替代cv2.cvtColor提速3倍 def yuyv_to_rgb_numpy(yuyv): # yuyv: (H, W, 2) - reshape to (H, W//2, 4) h, w, _ yuyv.shape yuyv yuyv.reshape(h, w//2, 4) y0 yuyv[:, :, 0].astype(np.float32) u yuyv[:, :, 1].astype(np.float32) y1 yuyv[:, :, 2].astype(np.float32) v yuyv[:, :, 3].astype(np.float32) # 标准YUV-RGB公式ITU-R BT.601 r y0 1.402 * (v - 128) g y0 - 0.344 * (u - 128) - 0.714 * (v - 128) b y0 1.772 * (u - 128) # 合并为RGB rgb np.stack([r, g, b], axis2) rgb np.clip(rgb, 0, 255).astype(np.uint8) return rgb # 调用 rgb_frame yuyv_to_rgb_numpy(frame) # 耗时约15ms4.3 YOLOv5输入预处理从RGB帧到模型张量的最后一步YOLOv5s要求输入为[1, 3, 640, 640]的float32张量需完成尺寸归一化将1280×720缩放到640×640保持宽高比填充灰边通道变换HWC → CHWOpenCV读取为HWCPyTorch要求CHW数据类型转换uint8 → float32并归一化到[0,1]增加batch维度(3,640,640) → (1,3,640,640)标准代码import torch import cv2 def preprocess_frame(frame): # 1. 保持宽高比缩放letterbox h, w frame.shape[:2] new_h, new_w 640, 640 scale min(new_h/h, new_w/w) nh, nw int(h * scale), int(w * scale) # 缩放 resized cv2.resize(frame, (nw, nh)) # 填充灰边 dw, dh new_w - nw, new_h - nh top, bottom dh//2, dh - dh//2 left, right dw//2, dw - dw//2 padded cv2.copyMakeBorder(resized, top, bottom, left, right, cv2.BORDER_CONSTANT, value(114, 114, 114)) # 2. HWC→CHW, uint8→float32, 归一化 tensor torch.from_numpy(padded.transpose(2,0,1)).float() / 255.0 # 3. 增加batch维度 return tensor.unsqueeze(0) # 使用 input_tensor preprocess_frame(rgb_frame) # shape: [1,3,640,640]注意cv2.copyMakeBorder的value(114,114,114)是YOLOv5官方指定的灰边值对应RGB的114不是随意选的。若用(0,0,0)模型会因输入分布偏移而漏检。5. RK3588 NPU推理实战从PyTorch模型到RKNN的无缝衔接5.1 模型转换的三步法为什么不能直接用PyTorch .pt文件RK3588的NPURockchip NPU不支持原生PyTorch执行必须通过rknn-toolkit2转换为.rknn格式。转换过程包含三个不可跳过的环节ONNX导出确保PyTorch模型无动态控制流如if、for循环YOLOv5s的Detect层需替换为静态torch.nn.functional.interpolateONNX优化用onnx-simplifier合并冗余算子否则RKNN转换会报Unsupported op type: ResizeRKNN量化与编译指定target_platform为rk3588并启用npu_versionrv1106RK3588 NPU代号标准转换脚本convert_rknn.pyfrom rknn.api import RKNN # 初始化RKNN rknn RKNN(verboseTrue) rknn.config(mean_values[[0, 0, 0]], std_values[[255, 255, 255]], target_platformrk3588, quantize_input_nodeTrue, optimization_level3) # 加载ONNX模型 print(-- Loading model) ret rknn.load_onnx(modelyolov5s.onnx, inputs[images], input_size_list[[1,3,640,640]]) if ret ! 0: print(Load onnx failed!) exit(ret) # 构建含量化 print(-- Building model) ret rknn.build(do_quantizationTrue, dataset./dataset.txt) if ret ! 0: print(Build rknn failed!) exit(ret) # 导出RKNN模型 print(-- Export rknn model) rknn.export_rknn(./yolov5s.rknn)关键点dataset.txt必须包含至少100张真实摄像头采集的校准图片非合成图否则量化误差会导致mAP下降15%以上。我用v4l2-ctl连续抓取200帧保存为JPG放入dataset.txt效果显著优于用COCO图片。5.2 在RK3588上加载并推理避免常见的段错误RKNN模型加载需指定device_idRK3588有2个NPU core编号0/1且必须在init_runtime()前设置import numpy as np from rknn.api import RKNN rknn RKNN() ret rknn.load_rknn(./yolov5s.rknn) if ret ! 0: print(Load rknn failed) exit(ret) # 关键指定device_id0主NPU core ret rknn.init_runtime(targetrk3588, device_id0) if ret ! 0: print(Init runtime failed) exit(ret) # 推理input为preprocess_frame()输出的tensor outputs rknn.inference(inputs[input_tensor.numpy()])常见错误Segmentation fault (core dumped)的根源device_id未指定或错误如写成rk3588而非0输入tensor维度与模型定义不符如传入[1,3,640,640]但模型期望[1,3,320,320]内存不足RK3588 NPU需要至少512MB连续内存需关闭GUI释放内存5.3 输出解析将RKNN原始输出映射为检测框YOLOv5s的RKNN输出是3个tensor对应不同尺度特征图每个tensor shape为[1, 3, 80, 80, 85]P3、[1, 3, 40, 40, 85]P4、[1, 3, 20, 20, 85]P5。其中855xywhconf80class scores。解析代码def parse_rknn_output(outputs): # outputs[0]: P3, outputs[1]: P4, outputs[2]: P5 all_boxes [] for i, out in enumerate(outputs): # out shape: (1, 3, h, w, 85) _, _, h, w, _ out.shape stride [8, 16, 32][i] # 对应P3/P4/P5的stride # 展平并提取置信度 out out.reshape(1, 3, h*w, 85) conf out[..., 4] # objectness score cls_scores out[..., 5:] # class scores scores conf[..., None] * cls_scores # [1,3,h*w,80] # 找出score 0.5的候选框 mask scores 0.5 if not mask.any(): continue # 解析坐标YOLOv5的xywh是相对于grid cell的偏移 grid_x, grid_y np.meshgrid(np.arange(w), np.arange(h)) grid_x grid_x.reshape(1,1,h,w).astype(np.float32) grid_y grid_y.reshape(1,1,h,w).astype(np.float32) # 反算真实坐标 x (out[..., 0] grid_x) * stride y (out[..., 1] grid_y) * stride w np.exp(out[..., 2]) * stride h np.exp(out[..., 3]) * stride # 合并 boxes np.stack([x, y, w, h], axis-1).reshape(-1,4) scores scores.reshape(-1,80) # NMS for cls in range(80): cls_scores scores[:, cls] keep cv2.dnn.NMSBoxes(boxes.tolist(), cls_scores.tolist(), score_threshold0.5, nms_threshold0.45) if len(keep) 0: for idx in keep.flatten(): all_boxes.append([*boxes[idx], cls, cls_scores[idx]]) return np.array(all_boxes) # 使用 boxes parse_rknn_output(outputs) # shape: (N, 6) - [x,y,w,h,class_id,score]6. 端到端整合从摄像头到检测框的完整代码与避坑清单6.1 可直接运行的整合脚本#!/usr/bin/env python3 # -*- coding: utf-8 -*- 香橙派RK3588 YOLOv5s 实时检测 demo 要求已安装rknn-toolkit2OpenCV 4.8.0模型已转换为yolov5s.rknn import cv2 import numpy as np import time from rknn.api import RKNN # 初始化RKNN rknn RKNN() ret rknn.load_rknn(./yolov5s.rknn) if ret ! 0: print(Load rknn failed) exit(ret) ret rknn.init_runtime(targetrk3588, device_id0) if ret ! 0: print(Init runtime failed) exit(ret) # 初始化摄像头GC2053 MIPI cap cv2.VideoCapture(0, cv2.CAP_V4L2) cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(Y, U, Y, V)) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) cap.set(cv2.CAP_PROP_BUFFERSIZE, 3) # 预热摄像头丢弃前5帧 for _ in range(5): cap.read() print(Start detection... Press q to quit) while True: start_time time.time() # 1. 抓帧 ret, frame cap.read() if not ret: print(Failed to grab frame) break # 2. YUYV转RGB硬件ISP启用时可跳过 # frame cv2.cvtColor(frame, cv2.COLOR_YUV2RGB_YUYV) # 3. 预处理 h, w frame.shape[:2] scale min(640/h, 640/w) nh, nw int(h * scale), int(w * scale) resized cv2.resize(frame, (nw, nh)) dw, dh 640 - nw, 640 - nh top, bottom dh//2, dh - dh//2 left, right dw//2, dw - dw//2 padded cv2.copyMakeBorder(resized, top, bottom, left, right, cv2.BORDER_CONSTANT, value(114,114,114)) input_tensor torch.from_numpy(padded.transpose(2,0,1)).float() / 255.0 input_tensor input_tensor.unsqueeze(0).numpy() # 4. NPU推理 outputs rknn.inference(inputs[input_tensor]) # 5. 解析输出 boxes parse_rknn_output(outputs) # 6. 绘制检测框 for box in boxes: x, y, w, h, cls_id, score box # 反算回原始分辨率 x int((x - dw//2) / scale) y int((y - dh//2) / scale) w int(w / scale) h int(h / scale) cv2.rectangle(frame, (x, y), (xw, yh), (0,255,0), 2) cv2.putText(frame, f{int(cls_id)}:{score:.2f}, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 2) # 7. 显示FPS fps 1.0 / (time.time() - start_time) cv2.putText(frame, fFPS: {fps:.1f}, (10,30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2) cv2.imshow(YOLOv5s Detection, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows() rknn.release()6.2 常见问题速查表与独家避坑技巧问题现象根本原因解决方案我的实测经验cap.read()返回retFalse设备树未启用MIPI或USB摄像头未被UVC驱动识别运行v4l2-ctl --list-devices确认/dev/video0存在若无检查dmesg | grep -i csi我曾因SD卡写入镜像时CRC校验失败导致设备树损坏重刷镜像后解决图像严重色偏全绿/全紫YUYV未正确转换为RGB或ISP未启用用ffmpeg -f rawvideo -pix_fmt yuyv422 -s 1280x720 -i test.yuv test.png验证原始帧是否正常GC2053模组在低温10℃下U分量漂移需在v4l2-ctl中微调isp-uv-gainNPU推理报Segmentation faultdevice_id未指定或内存不足添加device_id0关闭桌面环境sudo systemctl stop lightdmRK
返回列表