<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>东山Π Blog</title>
        <link>https://zephyr.100ask.org/blog</link>
        <description>东山Π Blog</description>
        <lastBuildDate>Tue, 25 Aug 2026 09:59:26 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-Hans</language>
        <item>
            <title><![CDATA[DshanPI-A1buildroot下搭建RKNN环境]]></title>
            <link>https://zephyr.100ask.org/blog/2025-12/DshanPI-A1 buildroot下搭建RKNN环境/buildroot下搭建RKNN环境</link>
            <guid>https://zephyr.100ask.org/blog/2025-12/DshanPI-A1 buildroot下搭建RKNN环境/buildroot下搭建RKNN环境</guid>
            <pubDate>Tue, 25 Aug 2026 09:59:26 GMT</pubDate>
            <description><![CDATA[开发环境]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="开发环境">开发环境<a href="https://zephyr.100ask.org/blog/2025-12/DshanPI-A1%20buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83/buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83#%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83" class="hash-link" aria-label="开发环境的直接链接" title="开发环境的直接链接" translate="no">​</a></h2>
<blockquote>
<p>PC端： ubuntu22.04-x86-64</p>
<p>板端：buildroot</p>
</blockquote>
<p>具体理论部分不再赘述，网上一大把，现在记录整个操作过程，分为两大部分：1.PC端 2.板端</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1pc端">1.PC端<a href="https://zephyr.100ask.org/blog/2025-12/DshanPI-A1%20buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83/buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83#1pc%E7%AB%AF" class="hash-link" aria-label="1.PC端的直接链接" title="1.PC端的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="rknn-toolkit2环境搭建">RKNN-Toolkit2环境搭建<a href="https://zephyr.100ask.org/blog/2025-12/DshanPI-A1%20buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83/buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83#rknn-toolkit2%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA" class="hash-link" aria-label="RKNN-Toolkit2环境搭建的直接链接" title="RKNN-Toolkit2环境搭建的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#代码库下载</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">wget https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/utils/rknn-toolkit2.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">unzip rknn-toolkit2.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">wget https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/utils/rknn_model_zoo.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">unzip rknn_model_zoo.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#coda环境搭建</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">wget -c https://repo.anaconda.com/archive/Anaconda3-2025.06-1-Linux-x86_64.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">bash Anaconda3-2025.06-1-Linux-x86_64.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Please, press ENTER to continue</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	&gt;&gt;&gt; </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Do you accept the license terms? [yes|no]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	&gt;&gt;&gt; yes</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Anaconda3 will now be installed into this location:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    /home/ubuntu/anaconda3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      - Press ENTER to confirm the location</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      - Press CTRL-C to abort the installation</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      - Or specify a different location below</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    [/home/ubuntu/anaconda3] &gt;&gt;&gt; </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	You can undo this by running `conda init --reverse $SHELL`? [yes|no]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	[no] &gt;&gt;&gt; yes</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Thank you for installing Anaconda3!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#激活环境变量</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">source ~/.bashrc</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#创建RKNN环境</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">conda create -n rknn-toolkit2 python=3.8</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">conda activate rknn-toolkit2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#安装RKNN-Toolkit2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd rknn-toolkit2/rknn-toolkit2/packages/x86_64/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">conda install compilers cmake</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pip install -r requirements_cp38-2.3.2.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pip install rknn_toolkit2-2.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#验证安装情况</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    (rknn-toolkit2) ubuntu@ubuntu-2204:~/rknn/rknn-toolkit2/rknn-toolkit2/packages/x86_64$ python3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Python 3.8.20 (default, Oct  3 2024, 15:24:27)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    [GCC 11.2.0] :: Anaconda, Inc. on linux</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Type "help", "copyright", "credits" or "license" for more information.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    &gt;&gt;&gt; from rknn.api import RKNN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    &gt;&gt;&gt; exit()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    (rknn-toolkit2) ubuntu@ubuntu-2204:~/rknn/rknn-toolkit2/rknn-toolkit2/packages/x86_64$</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2连扳推理">2.连扳推理<a href="https://zephyr.100ask.org/blog/2025-12/DshanPI-A1%20buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83/buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83#2%E8%BF%9E%E6%89%B3%E6%8E%A8%E7%90%86" class="hash-link" aria-label="2.连扳推理的直接链接" title="2.连扳推理的直接链接" translate="no">​</a></h2>
<p>首先给出我的环境,我使用的是sdk自带的buildroot，由百问网团队进行了适配，已经开启rknnruntime，并且<strong>我没有更新runtime</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/# uname -a</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Linux rk3576-buildroot 6.1.75 #3 SMP Fri Nov 28 09:41:14 EST 2025 aarch64 GNU/Linux</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/# find ./ -name *rknn*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./rockchip-test/npu2/model/RK356X/mobilenet_v1.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./rockchip-test/npu2/model/RK3588/vgg16_max_pool_fp16.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./sys/kernel/debug/clk/hclk_rknn_root</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./sys/kernel/debug/clk/clk_rknn_dsu0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./sys/kernel/debug/clk/aclk_rknn0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./sys/kernel/debug/clk/aclk_rknn1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./sys/kernel/debug/clk/aclk_rknn_cbuf</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./sys/kernel/debug/clk/hclk_rknn_cbuf</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/share/model/RK3562/mobilenet_v1.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/share/model/RK3566_RK3568/mobilenet_v1.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/share/model/RK3588/mobilenet_v1.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/share/model/RK3576/mobilenet_v1.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/lib/librknnrt.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/bin/start_rknn.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/bin/rknn_common_test</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/bin/restart_rknn.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ./usr/bin/rknn_server</span><br></div></code></pre></div></div>
<p>**tip：**我的buildroot配置./build.sh bconfig</p>
<div class="language-apl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-apl codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"> [*] Rockchip NPU power control for linux                                                  │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] Rockchip NPU power control combine for linux                                          │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] Rockchip recovery for linux                                                           │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] rkadk                                                                                 │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] rknpu                                                                                 │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] rknpu pcie                                                                            │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] python-rknn                                                                           │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [*] rknpu2                                                                                │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [*] rknpu2 example                                                                        │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] rknpu firmware                                                                        │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [ ] RKPARTYBOX demo                                                                       │ │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  │ │                   [*] rockchip script                 </span><br></div></code></pre></div></div>
<p>可以看到，rknpu的配置我没有改动，buildroot已经默认配置好rknpu驱动和rknnruntime</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题1解决pc端adb权限问题">问题1:解决pc端adb权限问题<a href="https://zephyr.100ask.org/blog/2025-12/DshanPI-A1%20buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83/buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83#%E9%97%AE%E9%A2%981%E8%A7%A3%E5%86%B3pc%E7%AB%AFadb%E6%9D%83%E9%99%90%E9%97%AE%E9%A2%98" class="hash-link" aria-label="问题1:解决pc端adb权限问题的直接链接" title="问题1:解决pc端adb权限问题的直接链接" translate="no">​</a></h3>
<p>在pc上进行连扳推理，会报如下错误：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">：(rknn-toolkit2) ubuntu@ubuntu-2204:~/rknn/rknn_model_zoo/examples/yolov8/python$ sudo python3 yolov8.py --target rk3576 --model_path ../model/yolov8.rknn --img_show</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Traceback (most recent call last):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  File "/home/ubuntu/rknn/rknn_model_zoo/examples/yolov8/python/yolov8.py", line 2, in &lt;module&gt;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    import cv2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ModuleNotFoundError: No module named 'cv2'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(rknn-toolkit2) ubuntu@ubuntu-2204:~/rknn/rknn_model_zoo/examples/yolov8/python$ python3 yolov8.py --target rk3576 --model_path ../model/yolov8.rknn --img_show</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I rknn-toolkit2 version: 2.3.2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">--&gt; Init runtime environment</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb: unable to connect for root: insufficient permissions for device: user in plugdev group; are your udev rules wrong?</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">See [http://developer.android.com/tools/device.html] for more information</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I target set by user is: rk3576</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">E init_runtime: Get board target failed, ret code: 1. error: insufficient permissions for device: user in plugdev group; are your udev rules wrong?</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">See [http://developer.android.com/tools/device.html] for more information</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">E init_runtime: Traceback (most recent call last):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  File "rknn/api/rknn_log.py", line 344, in rknn.api.rknn_log.error_catch_decorator.error_catch_wrapper</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  File "rknn/api/rknn_base.py", line 2566, in rknn.api.rknn_base.RKNNBase.init_runtime</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  File "rknn/api/rknn_runtime.py", line 223, in rknn.api.rknn_runtime.RKNNRuntime.__init__</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  File "rknn/api/rknn_platform.py", line 607, in rknn.api.rknn_platform.get_board_info</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">RuntimeError</span><br></div></code></pre></div></div>
<p>注意这一句</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">adb: unable to connect for root: insufficient permissions for device: user in plugdev group; are your udev rules wrong?</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">See [http://developer.android.com/tools/device.html] for more information</span><br></div></code></pre></div></div>
<p>提示adbd权限不足，修改</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 添加udev规则</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="2207", MODE="0666", GROUP="plugdev"' | sudo tee /etc/udev/rules.d/51-android.rules</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 重新加载规则</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo udevadm control --reload-rules</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo udevadm trigger</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 重启ADB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb kill-server</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb start-server</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb devices</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    List of devices attached</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    8074683be1050187        device</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题2解决板端adbd5037端口未打开问题">问题2:解决板端adbd5037端口未打开问题<a href="https://zephyr.100ask.org/blog/2025-12/DshanPI-A1%20buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83/buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83#%E9%97%AE%E9%A2%982%E8%A7%A3%E5%86%B3%E6%9D%BF%E7%AB%AFadbd5037%E7%AB%AF%E5%8F%A3%E6%9C%AA%E6%89%93%E5%BC%80%E9%97%AE%E9%A2%98" class="hash-link" aria-label="问题2:解决板端adbd5037端口未打开问题的直接链接" title="问题2:解决板端adbd5037端口未打开问题的直接链接" translate="no">​</a></h3>
<p>现象：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#进行连扳推理</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> python3 yolov8.py --target rk3576 --model_path ../model/yolov8.rknn --img_show</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I rknn-toolkit2 version: 2.3.2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --&gt; Init runtime environment</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    adbd is already running as root</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I target set by user is: rk3576</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I Get hardware info: target_platform = rk3576, os = Linux, aarch = aarch64</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I Check RK3576 board npu runtime version</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W kill server failed while restarting, ret code: 1. warning: killall: rknn_server: no process killed</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Please skip it if rknn_server not running on board.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I Starting ntp or adb, target is RK3576</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I Start adb...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I Connect to Device success!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I NPUTransfer(3672747): Starting NPU Transfer Client, Transfer version 2.2.2 (12abf2a@2024-09-02T03:22:41)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    E RKNNAPI: rknn_init,  server connect fail!  ret = -9(ERROR_PIPE)!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    E init_runtime: The rknn_server on the concected device is abnormal, please start the rknn_server on the device according to:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                   https://github.com/airockchip/rknn-toolkit2/blob/master/doc/rknn_server_proxy.md</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W init_runtime: ===================== WARN(1) =====================</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    E rknn-toolkit2 version: 2.3.2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    E init_runtime: Traceback (most recent call last):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      File "rknn/api/rknn_log.py", line 344, in rknn.api.rknn_log.error_catch_decorator.error_catch_wrapper</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<p>注意</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">    I NPUTransfer(3672747): Starting NPU Transfer Client, Transfer version 2.2.2 (12abf2a@2024-09-02T03:22:41)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    E RKNNAPI: rknn_init,  server connect fail!  ret = -9(ERROR_PIPE)!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    E init_runtime: The rknn_server on the concected device is abnormal, please start the rknn_server on the device according to:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                   https://github.com/airockchip/rknn-toolkit2/blob/master/doc/rknn_server_proxy.md</span><br></div></code></pre></div></div>
<p>参考提示，去  <a href="https://github.com/airockchip/rknn-toolkit2/blob/master/doc/rknn_server_proxy.md%E6%9F%A5%E6%89%BE%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88" target="_blank" rel="noopener noreferrer" class="">https://github.com/airockchip/rknn-toolkit2/blob/master/doc/rknn_server_proxy.md查找解决方案</a></p>
<p>在这个文档的</p>
<blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-常见问题">6. 常见问题<a href="https://zephyr.100ask.org/blog/2025-12/DshanPI-A1%20buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83/buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83#6-%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98" class="hash-link" aria-label="6. 常见问题的直接链接" title="6. 常见问题的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题1">问题1<a href="https://zephyr.100ask.org/blog/2025-12/DshanPI-A1%20buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83/buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83#%E9%97%AE%E9%A2%981" class="hash-link" aria-label="问题1的直接链接" title="问题1的直接链接" translate="no">​</a></h3>
<p>Debian系统上rknn_server服务已经后台启动, 但是连板推理时依旧有如下报错：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">D NPUTransfer: ERROR: socket read fd = 4, n = -1: Connection reset by peer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">D NPUTransfer: Transfer client closed, fd = 4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">E RKNNAPI: rknn_init,  server connect fail!  ret = -9(ERROR_PIPE)!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">E build_graph: The rknn_server on the concected device is abnormal, please start the rknn_server on the device according to:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               https://github.com/airockchip/rknn-toolkit2/blob/master/doc/rknn_server_proxy.md</span><br></div></code></pre></div></div>
<p><strong>解决方法：</strong> 这通常是由于Debian固件上的adbd程序没有监听5037端口导致的，可以在板子上执行以下命令来判断:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">netstat -n -t -u -a</span><br></div></code></pre></div></div>
<p>如果输出结果中没有<strong>5037端口</strong>,则执行下列命令下载和更新adbd程序, 并重启板子;否则,跳过下列步骤。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">wget -O adbd.zip https://ftzr.zbox.filez.com/v2/delivery/data/7f0ac30dfa474892841fcb2cd29ad924/adbd.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">unzip adbd.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb push adbd/linux-aarch64/adbd /usr/bin/adbd</span><br></div></code></pre></div></div>
<p>进入设备shell命令，增加adbd的可执行权限</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">adb shell "chmod +x /usr/bin/adbd"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb reboot</span><br></div></code></pre></div></div>
<p>重启设备后，按照启动步骤启动rknn_server服务，再次尝试连板推理。</p>
</blockquote>
<p>虽然这个文档用的是Debian固件，我用的是buildroot，现象一直，按照它的解决方案，排查问题：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#这是板端</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/# netstat -n -t -u -a</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Active Internet connections (servers and established)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Proto Recv-Q Send-Q Local Address           Foreign Address         State</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 0.0.0.0:53              0.0.0.0:*               LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 :::53                   :::*                    LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 :::22                   :::*                    LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 :::5555                 :::*                    LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 0.0.0.0:53              0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 0.0.0.0:67              0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 0.0.0.0:68              0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 127.0.0.1:323           0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 :::53                   :::*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 ::1:323                 :::*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 :::546                  :::*</span><br></div></code></pre></div></div>
<p>可以看到<strong>5037端口</strong>确实没有打开</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#这是pc端</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">wget -O adbd.zip https://ftzr.zbox.filez.com/v2/delivery/data/7f0ac30dfa474892841fcb2cd29ad924/adbd.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">unzip adbd.zip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb push adbd/linux-aarch64/adbd /usr/bin/adbd</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb shell "chmod +x /usr/bin/adbd"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb reboot</span><br></div></code></pre></div></div>
<p>重启开发板后重新测试</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#这是板端</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">restart_rknn.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/# netstat -n -t -u -a</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Active Internet connections (servers and established)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Proto Recv-Q Send-Q Local Address           Foreign Address         State</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 127.0.0.1:5037          0.0.0.0:*               LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 0.0.0.0:53              0.0.0.0:*               LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 0.0.0.0:5555            0.0.0.0:*               LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 :::22                   :::*                    LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tcp        0      0 :::53                   :::*                    LISTEN</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 0.0.0.0:53              0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 0.0.0.0:67              0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 0.0.0.0:68              0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 127.0.0.1:323           0.0.0.0:*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 :::546                  :::*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 :::53                   :::*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">udp        0      0 ::1:323                 :::*</span><br></div></code></pre></div></div>
<p>可以看到<strong>5037端口</strong>已经被监听，现在继续尝试连扳推理</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#这是pc端</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(rknn-toolkit2) ubuntu@ubuntu-2204:~/rknn/rknn_model_zoo/examples/yolov8/python$ python3 yolov8.py --target rk3576 --model_path ../model/yolov8.rknn --img_show</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I rknn-toolkit2 version: 2.3.2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">--&gt; Init runtime environment</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb: unable to connect for root: closed</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I target set by user is: rk3576</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I Get hardware info: target_platform = rk3576, os = Linux, aarch = aarch64</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I Check RK3576 board npu runtime version</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I Starting ntp or adb, target is RK3576</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I Start adb...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I Connect to Device success!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I NPUTransfer(3675220): Starting NPU Transfer Client, Transfer version 2.2.2 (12abf2a@2024-09-02T03:22:41)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I NPUTransfer(3675220): TransferBuffer: min aligned size: 1024</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">D RKNNAPI: ==============================================</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">D RKNNAPI: RKNN VERSION:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">D RKNNAPI:   API: 2.3.2 (1842325 build@2025-03-30T09:55:23)</span><br></div></code></pre></div></div>
<p>已经连扳推理成功，显示出人脸识别图像</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3板端推理">3.板端推理<a href="https://zephyr.100ask.org/blog/2025-12/DshanPI-A1%20buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83/buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83#3%E6%9D%BF%E7%AB%AF%E6%8E%A8%E7%90%86" class="hash-link" aria-label="3.板端推理的直接链接" title="3.板端推理的直接链接" translate="no">​</a></h2>
<p>由于使用的是buildroot，rk平台在rk1808之后，buildroot并未支持python部署方式，自行搭建python推理软件栈颇为耗时，且会遇到很多问题，python demo参考百问网<a href="https://wiki.dshanpi.org/docs/DshanPi-A1/AppDev/part3-3/03-3-1_SetupRKNNEnvironment" target="_blank" rel="noopener noreferrer" class="">RKNN环境搭建 | 东山Π</a>这里不再赘述，使用cpp接口，还是使用上述的yolo8进行板端推理：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="准备模型">准备模型<a href="https://zephyr.100ask.org/blog/2025-12/DshanPI-A1%20buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83/buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83#%E5%87%86%E5%A4%87%E6%A8%A1%E5%9E%8B" class="hash-link" aria-label="准备模型的直接链接" title="准备模型的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd ~/rknn/rknn_model_zoo/examples/yolov8/model</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sh download_model.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ls -lah yolov8n.onnx</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	-rw-rw-r-- 1 ubuntu ubuntu 13M Nov 29 07:36 yolov8n.onnx</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="模型转换">模型转换<a href="https://zephyr.100ask.org/blog/2025-12/DshanPI-A1%20buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83/buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83#%E6%A8%A1%E5%9E%8B%E8%BD%AC%E6%8D%A2" class="hash-link" aria-label="模型转换的直接链接" title="模型转换的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd ../python/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(rknn-toolkit2) ubuntu@ubuntu-2204:~/rknn/rknn_model_zoo/examples/yolov8/python$ python convert.py ../model/yolov8n.onnx rk3576 i8 ../model/yolov8n.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python convert.py ../model/yolov5s_relu.onnx rk3576 i8 ../model/yolov5s_relu.rknn </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I rknn-toolkit2 version: 2.3.2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --&gt; Config model</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --&gt; Loading model</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I Loading : 100%|██████████████████████████████████████████████| 126/126 [00:00&lt;00:00, 43282.74it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --&gt; Building model</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I OpFusing 0: 100%|█████████████████████████████████████████████| 100/100 [00:00&lt;00:00, 1590.15it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I OpFusing 1 : 100%|█████████████████████████████████████████████| 100/100 [00:00&lt;00:00, 860.03it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I OpFusing 0 : 100%|█████████████████████████████████████████████| 100/100 [00:00&lt;00:00, 739.11it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I OpFusing 1 : 100%|█████████████████████████████████████████████| 100/100 [00:00&lt;00:00, 652.15it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I OpFusing 2 : 100%|█████████████████████████████████████████████| 100/100 [00:00&lt;00:00, 229.74it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: found outlier value, this may affect quantization accuracy</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                            const name                        abs_mean    abs_std     outlier value</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                            model.0.conv.weight               2.44        2.47        -17.494</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                            model.22.cv3.2.1.conv.weight      0.09        0.14        -10.215</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                            model.22.cv3.1.1.conv.weight      0.12        0.19        13.361, 13.317</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                            model.22.cv3.0.1.conv.weight      0.18        0.20        -11.216</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I GraphPreparing : 100%|████████████████████████████████████████| 161/161 [00:00&lt;00:00, 3291.17it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I Quantizating : 100%|████████████████████████████████████████████| 161/161 [00:04&lt;00:00, 34.87it/s]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default input dtype of 'images' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                           Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of '318' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of 'onnx::ReduceSum_326' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of '331' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of '338' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of 'onnx::ReduceSum_346' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of '350' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of '357' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of 'onnx::ReduceSum_365' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    W build: The default output dtype of '369' is changed from 'float32' to 'int8' in rknn model for performance!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                          Please take care of this change when deploy rknn model with Runtime API!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I rknn building ...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    I rknn building done.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --&gt; Export rknn model</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd ../model</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ls -lah yolov8n.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	-rw-rw-r-- 1 ubuntu ubuntu 6.2M Nov 29 07:39 yolov8n.rknn</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="运行rknn-c-example">运行RKNN C example<a href="https://zephyr.100ask.org/blog/2025-12/DshanPI-A1%20buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83/buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83#%E8%BF%90%E8%A1%8Crknn-c-example" class="hash-link" aria-label="运行RKNN C example的直接链接" title="运行RKNN C example的直接链接" translate="no">​</a></h3>
<p>首先需要编译C example，然后将可执行文件 模型文件 资源文件部署到板端</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="编译">编译<a href="https://zephyr.100ask.org/blog/2025-12/DshanPI-A1%20buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83/buildroot%E4%B8%8B%E6%90%AD%E5%BB%BARKNN%E7%8E%AF%E5%A2%83#%E7%BC%96%E8%AF%91" class="hash-link" aria-label="编译的直接链接" title="编译的直接链接" translate="no">​</a></h4>
<p>编译要使用<code>rknn_model_zoo</code>目录下的<code>build-linux.sh</code>脚本，需要先配置工具链。修改<strong>build-linux.sh</strong>：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">GCC_COMPILER=/home/ubuntu/rk3576/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">chmod +x ./build-linux.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./build-linux.sh -t rk3576 -a aarch64 -d yolov8</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	-- Set runtime path of "/home/ubuntu/rknn/rknn_model_zoo/install/rk3576_linux_aarch64/rknn_yolov8_demo/./rknn_yolov8_demo" to "$ORIGIN/../lib"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Installing: /home/ubuntu/rknn/rknn_model_zoo/install/rk3576_linux_aarch64/rknn_yolov8_demo/model/bus.jpg</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Installing: /home/ubuntu/rknn/rknn_model_zoo/install/rk3576_linux_aarch64/rknn_yolov8_demo/model/coco_80_labels_list.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Installing: /home/ubuntu/rknn/rknn_model_zoo/install/rk3576_linux_aarch64/rknn_yolov8_demo/model/yolov8.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Installing: /home/ubuntu/rknn/rknn_model_zoo/install/rk3576_linux_aarch64/rknn_yolov8_demo/model/yolov8n.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Installing: /home/ubuntu/rknn/rknn_model_zoo/install/rk3576_linux_aarch64/rknn_yolov8_demo/lib/librknnrt.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Installing: /home/ubuntu/rknn/rknn_model_zoo/install/rk3576_linux_aarch64/rknn_yolov8_demo/lib/librga.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#查看一下</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ubuntu@ubuntu-2204:~/rknn/rknn_model_zoo/install$ tree -L 4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── rk3576_linux_aarch64</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    └── rknn_yolov8_demo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ├── lib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │&nbsp;&nbsp; ├── librga.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │&nbsp;&nbsp; └── librknnrt.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ├── model</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │&nbsp;&nbsp; ├── bus.jpg</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │&nbsp;&nbsp; ├── coco_80_labels_list.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │&nbsp;&nbsp; ├── yolov8n.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │&nbsp;&nbsp; └── yolov8.rknn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ├── rknn_yolov8_demo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        └── rknn_yolov8_demo_zero_copy</span><br></div></code></pre></div></div>
<p>这个rknn_yolov8_demo就是要部署到板端的文件集合</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">adb push install/rk3576_linux_aarch64/rknn_yolov8_demo /data/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">install/rk3576_linux_aarch64/rknn_yolov8_demo/: 8 files pushed. 3.6 MB/s (23008641 bytes in 6.049s)</span><br></div></code></pre></div></div>
<p>在板端运行</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/data/rknn_yolov8_demo# ./rknn_yolov8_demo ./model/yolov8.rknn ./model/bus.jpg</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    load lable ./model/coco_80_labels_list.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    model input num: 1, output num: 9</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    input tensors:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=0, name=images, n_dims=4, dims=[1, 640, 640, 3], n_elems=1228800, size=1228800, fmt=NHWC, type=INT8, qnt_type=AFFINE, zp=-128, scale=0.003922</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    output tensors:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=0, name=318, n_dims=4, dims=[1, 64, 80, 80], n_elems=409600, size=409600, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-58, scale=0.117659</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=1, name=onnx::ReduceSum_326, n_dims=4, dims=[1, 80, 80, 80], n_elems=512000, size=512000, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-128, scale=0.003104</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=2, name=331, n_dims=4, dims=[1, 1, 80, 80], n_elems=6400, size=6400, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-128, scale=0.003173</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=3, name=338, n_dims=4, dims=[1, 64, 40, 40], n_elems=102400, size=102400, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-45, scale=0.093747</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=4, name=onnx::ReduceSum_346, n_dims=4, dims=[1, 80, 40, 40], n_elems=128000, size=128000, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-128, scale=0.003594</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=5, name=350, n_dims=4, dims=[1, 1, 40, 40], n_elems=1600, size=1600, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-128, scale=0.003627</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=6, name=357, n_dims=4, dims=[1, 64, 20, 20], n_elems=25600, size=25600, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-34, scale=0.083036</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=7, name=onnx::ReduceSum_365, n_dims=4, dims=[1, 80, 20, 20], n_elems=32000, size=32000, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-128, scale=0.003874</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      index=8, name=369, n_dims=4, dims=[1, 1, 20, 20], n_elems=400, size=400, fmt=NCHW, type=INT8, qnt_type=AFFINE, zp=-128, scale=0.003922</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    model is NHWC input fmt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    model input height=640, width=640, channel=3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    origin size=640x640 crop size=640x640</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    input image: 640 x 640, subsampling: 4:2:0, colorspace: YCbCr, orientation: 1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    scale=1.000000 dst_box=(0 0 639 639) allow_slight_change=1 _left_offset=0 _top_offset=0 padding_w=0 padding_h=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    rga_api version 1.10.1_[0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    rknn_run</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    person @ (211 241 282 507) 0.864</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    person @ (109 235 225 536) 0.856</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    bus @ (99 136 552 455) 0.856</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    person @ (476 223 560 521) 0.848</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    person @ (80 326 116 513) 0.280</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    write_image path: out.png width=640 height=640 channel=3 data=0x3e2e9200</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<p>在pc端查看</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">adb pull /data/rknn_yolov8_demo/out.png ./</span><br></div></code></pre></div></div>
<p>符合预期</p>
<p>至此，rknn环境搭建成功</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[OPENWRT 系统 5：Docker 玩法介绍]]></title>
            <link>https://zephyr.100ask.org/blog/openwrt-docker</link>
            <guid>https://zephyr.100ask.org/blog/openwrt-docker</guid>
            <pubDate>Wed, 10 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[在 OpenWrt 上使用 Docker 部署应用。]]></description>
            <content:encoded><![CDATA[<p>Docker 是一种开源的容器化平台，它通过“容器”来封装应用及其运行环境，使应用能够在不同系统之间快速、稳定地运行。容器轻量、启动快，占用资源少，适合微服务部署与持续集成/交付。Docker 还提供镜像管理、版本控制和环境一致性，让开发、测试、生产环境保持统一，大幅提升部署效率与可移植性。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中，然后发布到任何流行的 Linux 机器上，也可以实现虚拟化。</p>
<p>硬件环境：OpenWrt 跑在 ARM 高性能 SBC 上（比如 本文使用的Dshanpi-A1），家里还有光猫 + 交换机/AC/AP 等常规设备。<br>
<!-- -->目标：在这块 SBC 上用 Docker 跑 <strong>家庭影院 + 下载器 + 网盘 + 广告过滤 + 简单监控</strong>，一机多用。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="家庭网络">家庭网络<a href="https://zephyr.100ask.org/blog/openwrt-docker#%E5%AE%B6%E5%BA%AD%E7%BD%91%E7%BB%9C" class="hash-link" aria-label="家庭网络的直接链接" title="家庭网络的直接链接" translate="no">​</a></h2>
<ul>
<li class="">光猫改桥接，把拨号交给 ARM SBC 上的 OpenWrt</li>
<li class="">ARM SBC 既当主路由，又当“轻量 NAS + 家庭影院服务器”</li>
<li class="">电视盒子、手机、电脑都连在 LAN（有线/无线都行），统一访问 SBC 上的服务</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="机器配置">机器配置<a href="https://zephyr.100ask.org/blog/openwrt-docker#%E6%9C%BA%E5%99%A8%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="机器配置的直接链接" title="机器配置的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><strong>设备</strong>：ARM 64 位架构 SBC，8G 内存版本</li>
<li class=""><strong>系统</strong>：OpenWrt（自己编译/整合固件都可以，关键是要有 Docker）</li>
<li class=""><strong>磁盘</strong>：<!-- -->
<ul>
<li class="">系统盘（eMMC/TF）装 OpenWrt</li>
<li class="">外接 SSD/HDD/大 U 盘做数据盘，挂到 <code>/mnt/data</code></li>
</ul>
</li>
</ul>
<h1>Docker 环境 &amp; 目录规划</h1>
<p>先把环境和目录规划确认好，后续好维护，这步比较关键。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="安装-docker--docker-compose">安装 Docker / Docker Compose<a href="https://zephyr.100ask.org/blog/openwrt-docker#%E5%AE%89%E8%A3%85-docker--docker-compose" class="hash-link" aria-label="安装 Docker / Docker Compose的直接链接" title="安装 Docker / Docker Compose的直接链接" translate="no">​</a></h2>
<p>如果你的固件已经打包了 Docker，可以直接跳过安装，推荐安装 luci-app-dockerman，这是 OpenWrt 上专门的 Docker Web 管理界面插件：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">opkg install luci-lib-docker dockerd luci-lib-jsonc docker ttyd --force-depends</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">opkg install luci-app-dockerman</span><br></div></code></pre></div></div>
<ul>
<li class=""><code>dockerd</code>：Docker 守护进程</li>
<li class=""><code>docker</code>：命令行客户端</li>
<li class=""><code>luci-lib-docker</code> / <code>luci-lib-jsonc</code>：Dockerman 的依赖</li>
<li class=""><code>ttyd</code>：用于 Web 终端与容器控制台</li>
<li class=""><code>luci-app-dockerman</code>：Web 管理界面插件</li>
</ul>
<p>启动并设为开机自启：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">/etc/init.d/dockerd start</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/etc/init.d/dockerd enable</span><br></div></code></pre></div></div>
<p>然后访问 LuCI 后台，菜单里会多出：<strong>服务 / Docker</strong> 或 <strong>服务 / Dockerman</strong>。</p>
<p>也可以通过命令行的方式，确认环境能用，示例如下：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# docker version</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Client:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> Version:           28.0.4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> API version:       1.48</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> Go version:        go1.25.4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> Git commit:        b8034c0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> Built:             Sun Sep  7 14:53:18 2025</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> OS/Arch:           linux/arm64</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> Context:           default</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Server:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> Engine:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Version:          28.0.4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  API version:      1.48 (minimum version 1.24)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Go version:       go1.25.4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Git commit:       6430e49</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Built:            Sun Sep  7 14:53:18 2025</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  OS/Arch:          linux/arm64</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Experimental:     false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> containerd:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Version:          1.7.27</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  GitCommit:        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> runc:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Version:          1.2.6</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  GitCommit:        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> docker-init:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Version:          0.19.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  GitCommit:        de40ad0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# docker ps</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# </span><br></div></code></pre></div></div>
<p>能看到版本信息 &amp; 空容器列表，就说明 OK。</p>
<p><code>docker-compose</code> 推荐也装一个，方便后面多服务一起管理（以 ARM64 为例）：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">wget https://github.com/docker/compose/releases/download/v2.27.0/docker-compose-linux-aarch64 -O /usr/local/bin/docker-compose</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">chmod +x /usr/local/bin/docker-compose</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">docker-compose version</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="数据盘挂载--目录规划">数据盘挂载 &amp; 目录规划<a href="https://zephyr.100ask.org/blog/openwrt-docker#%E6%95%B0%E6%8D%AE%E7%9B%98%E6%8C%82%E8%BD%BD--%E7%9B%AE%E5%BD%95%E8%A7%84%E5%88%92" class="hash-link" aria-label="数据盘挂载 &amp; 目录规划的直接链接" title="数据盘挂载 &amp; 目录规划的直接链接" translate="no">​</a></h2>
<p>首先把emmc剩余空间新建分区，格式化为ext4，然后界面上挂载为docker数据分区使用，当然使用其他外部存储设备保存也是可以的，比如使用TF卡来做为docker数据分区使用，增加对应的挂载目录配置即可，示例如下：</p>
<p>数据盘以/opt/data为根目录，可以这样规划：</p>
<div class="language-plain codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-plain codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">/opt/docker      # Docker 根目录（镜像、容器层等）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/opt/data</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   ├─ media      # 媒体文件（电影、剧集、音乐）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   │   ├─ movies</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   │   └─ tv</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   ├─ downloads  # BT/PT 下载目录</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   └─ configs    # 各容器配置文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">       ├─ jellyfin</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">       ├─ qbittorrent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">       └─ ...</span><br></div></code></pre></div></div>
<p>再把目录建好：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p /opt/data/{configs,downloads,media}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p /opt/data/configs/{jellyfin,emby,transmission,qbittorrent,aria2,adguard,nextcloud}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p /opt/data/media/{movies,tv,anime,music}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p /opt/data/downloads/{bt,aria2,tmp}</span><br></div></code></pre></div></div>
<p>后面所有容器都尽量挂到 <code>/opt/data</code> 下面，避免写爆系统盘。</p>
<p>这样做的好处：</p>
<ul>
<li class="">坏了一个容器就删了重建，数据不受影响</li>
<li class="">换设备时只要把这块盘接过去，改一下路径就能继续用</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置内核选项支持docker运行">配置内核选项支持docker运行<a href="https://zephyr.100ask.org/blog/openwrt-docker#%E9%85%8D%E7%BD%AE%E5%86%85%E6%A0%B8%E9%80%89%E9%A1%B9%E6%94%AF%E6%8C%81docker%E8%BF%90%E8%A1%8C" class="hash-link" aria-label="配置内核选项支持docker运行的直接链接" title="配置内核选项支持docker运行的直接链接" translate="no">​</a></h2>
<p>默认配置编译的kernel，docker运行的时候会有警告信息，提示缺少支持对应的功能支持，如下所示：</p>
<p>这些 WARNING 表示你的 <strong>内核未开启 cgroup v1/v2 的资源限制功能</strong>，导致 Docker 无法对容器进行 CPU、IO、内存 swap 等限制。  需要在我们的系统里面，打开下面对应的配置：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 打开kernel配置页面</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make kernel_menuconfig</span><br></div></code></pre></div></div>
<p>按照下面配置，打开CGroup和Namespace支持：</p>
<p>重新编译，然后升级，启动后发现没有对应的报错信息即可。更多配置支持，请查看代码仓库里面的配置。</p>
<p>注意：有的docker版本，需要打开legacy cgroup v1相关的控制支持，此处保持关闭。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="加速源配置">加速源配置<a href="https://zephyr.100ask.org/blog/openwrt-docker#%E5%8A%A0%E9%80%9F%E6%BA%90%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="加速源配置的直接链接" title="加速源配置的直接链接" translate="no">​</a></h2>
<ol>
<li class="">在安装下面的docker镜像的时候，可能会出现默认的仓库下载失败，可以配置内地的源，加速下载；</li>
</ol>
<p>常见的加速镜像站地址：</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"registry-mirrors"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"https://docker.1panel.live"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"https://registry.docker-cn.com"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"http://hub-mirror.c.163.com"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"https://docker.m.daocloud.io"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<ol start="2">
<li class="">如果发现配置了加速源提示无法访问，可能是安装的openwrt代理插件的问题，修改配置或者禁用代理后重试即可；</li>
<li class="">配置好后，执行 <code>docker pull hello-world</code>看是否可以正常拉取镜像，可以则说明网络配置完成。下面是正常工作的概览示例：</li>
</ol>
<h1>常见的一些玩法</h1>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="jellyfin-家庭影院embyplex-同理">Jellyfin 家庭影院（Emby/Plex 同理）<a href="https://zephyr.100ask.org/blog/openwrt-docker#jellyfin-%E5%AE%B6%E5%BA%AD%E5%BD%B1%E9%99%A2embyplex-%E5%90%8C%E7%90%86" class="hash-link" aria-label="Jellyfin 家庭影院（Emby/Plex 同理）的直接链接" title="Jellyfin 家庭影院（Emby/Plex 同理）的直接链接" translate="no">​</a></h2>
<p>说明：下面用命令行和图文方式进行操作实例，后续章节仅提供命令行示例。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="拉取镜像">拉取镜像<a href="https://zephyr.100ask.org/blog/openwrt-docker#%E6%8B%89%E5%8F%96%E9%95%9C%E5%83%8F" class="hash-link" aria-label="拉取镜像的直接链接" title="拉取镜像的直接链接" translate="no">​</a></h3>
<p>命令行执行：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># [--platform linux/arm64]是可选参数，可以去掉</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">docker pull --platform linux/arm64 jellyfin/jellyfin:latest</span><br></div></code></pre></div></div>
<p>LUCI界面操作：</p>
<p>拉取成功后，可以在页面镜像列表看到，如下图所示：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="启动容器">启动容器<a href="https://zephyr.100ask.org/blog/openwrt-docker#%E5%90%AF%E5%8A%A8%E5%AE%B9%E5%99%A8" class="hash-link" aria-label="启动容器的直接链接" title="启动容器的直接链接" translate="no">​</a></h3>
<p>启动命令示例：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run -d \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --name=jellyfin \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --restart=unless-stopped \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 8096:8096 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v /opt/data/configs/jellyfin:/config \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v /opt/data/media:/media \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  jellyfin/jellyfin:latest</span><br></div></code></pre></div></div>
<p>可以直接复制上面的命令，到界面上的解析CLI，点击命令行按钮，然后粘贴，最后点击应用。</p>
<p>增加后，页面可以看到状态为Created，这个时候选中jellyfin容器，然后点击启动：</p>
<p>如果 SBC 支持硬件解码（GPU 驱动也搞好了），可以尝试加上：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">--device /dev/dri:/dev/dri</span><br></div></code></pre></div></div>
<blockquote>
<p>ARM 平台硬解是个坑比较多的进阶话题，能成功算赚到，不能用就当纯软解顶着，1080p 问题不大。</p>
</blockquote>
<p>启动参数说明：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="web-配置流程">Web 配置流程<a href="https://zephyr.100ask.org/blog/openwrt-docker#web-%E9%85%8D%E7%BD%AE%E6%B5%81%E7%A8%8B" class="hash-link" aria-label="Web 配置流程的直接链接" title="Web 配置流程的直接链接" translate="no">​</a></h3>
<p>浏览器访问：<code>http://路由器IP:8096</code></p>
<ol>
<li class="">
<p>创建管理员账号</p>
</li>
<li class="">
<p>添加媒体库：</p>
<ul>
<li class="">电影 → <code>/media/movies</code></li>
<li class="">电视剧 → <code>/media/tv</code></li>
<li class="">动漫 → <code>/media/anime</code></li>
</ul>
</li>
<li class="">
<p>语言选简体中文，元数据源可以切中文优先（刮削更顺）</p>
</li>
</ol>
<p>之后你可以：</p>
<ul>
<li class="">安卓 TV/电视盒装 Jellyfin 客户端</li>
<li class="">手机、平板、PC 直接 web/客户端访问</li>
<li class="">家里的所有终端都在用 ARM SBC 这台“小服务器”作为服务器</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="使用简介">使用简介<a href="https://zephyr.100ask.org/blog/openwrt-docker#%E4%BD%BF%E7%94%A8%E7%AE%80%E4%BB%8B" class="hash-link" aria-label="使用简介的直接链接" title="使用简介的直接链接" translate="no">​</a></h3>
<p>在上面的初始配置执行完成后，jellyfin就初始化好了，我们通过设置的管理员账户登录进去，可以看到如下界面：</p>
<p>我本地之前通过磁力链下载了Minions的的片源，现在直接点击，就可以在线观看了。</p>
<p>默认影片没有信息，我们可以通过刮削元数据，获取封面等信息，更多玩法请查阅jellyfin的官方文档：</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="核心玩法二运行ubuntu">核心玩法二：运行ubuntu<a href="https://zephyr.100ask.org/blog/openwrt-docker#%E6%A0%B8%E5%BF%83%E7%8E%A9%E6%B3%95%E4%BA%8C%E8%BF%90%E8%A1%8Cubuntu" class="hash-link" aria-label="核心玩法二：运行ubuntu的直接链接" title="核心玩法二：运行ubuntu的直接链接" translate="no">​</a></h2>
<p>有很多服务，依赖完整的ubuntu环境，而不是openwrt的插件方式，这种时候我们可以在openwrt环境下安装docker ubuntu容器，实现拥有一台类似原生ubuntu的环境，实现各种自定义功能。下面以一个基础的Python实现的web服务器作为示例，展示运行容器版本的ubuntu强大的的自定义能力。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="拉取镜像-1">拉取镜像<a href="https://zephyr.100ask.org/blog/openwrt-docker#%E6%8B%89%E5%8F%96%E9%95%9C%E5%83%8F-1" class="hash-link" aria-label="拉取镜像的直接链接" title="拉取镜像的直接链接" translate="no">​</a></h3>
<p>命令执行：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker pull ubuntu:24.04</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="启动容器-1">启动容器<a href="https://zephyr.100ask.org/blog/openwrt-docker#%E5%90%AF%E5%8A%A8%E5%AE%B9%E5%99%A8-1" class="hash-link" aria-label="启动容器的直接链接" title="启动容器的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run -it ubuntu:24.04 bash</span><br></div></code></pre></div></div>
<p>命令行启动示例：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run -it -d \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --name ubt-web \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --restart=unless-stopped \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 8080:8000 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ubuntu:24.04 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  bash</span><br></div></code></pre></div></div>
<p>进入容器，并执行简单HTTP服务器的Python代码，示例如下：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker exec -it ubt-web bash</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">apt update</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">apt install python3 python3-pip -y</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cat &gt; /srv/app.py &lt;&lt; 'EOF'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">from http.server import HTTPServer, SimpleHTTPRequestHandler</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">PORT = 8000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">httpd = HTTPServer(("", PORT), SimpleHTTPRequestHandler)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">print(f"Serving on port {PORT}...")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">httpd.serve_forever()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">EOF</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 上面实现的web server root是当前执行python3的路径</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python3 /srv/app.py</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="web访问测试">web访问测试<a href="https://zephyr.100ask.org/blog/openwrt-docker#web%E8%AE%BF%E9%97%AE%E6%B5%8B%E8%AF%95" class="hash-link" aria-label="web访问测试的直接链接" title="web访问测试的直接链接" translate="no">​</a></h3>
<p>这个时候，通过<code>http://路由器IP:8000</code>，访问ubuntu容器里面python写的http服务器，会出现文件列表，如下图所示：</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="附加玩法全网去广告">附加玩法：全网去广告<a href="https://zephyr.100ask.org/blog/openwrt-docker#%E9%99%84%E5%8A%A0%E7%8E%A9%E6%B3%95%E5%85%A8%E7%BD%91%E5%8E%BB%E5%B9%BF%E5%91%8A" class="hash-link" aria-label="附加玩法：全网去广告的直接链接" title="附加玩法：全网去广告的直接链接" translate="no">​</a></h2>
<p>首先，拉取adgardhome镜像：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker pull adguard/adguardhome:latest</span><br></div></code></pre></div></div>
<p>然后启动容器，使用AdGuard Home：全家 DNS 去广告</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run -d \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --name=adguardhome \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --restart=unless-stopped \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 3000:3000 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 53:53/tcp \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 53:53/udp \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v /opt/data/config/adguard:/opt/adguardhome/conf \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v /opt/data/config/adguard/work:/opt/adguardhome/work \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  adguard/adguardhome</span><br></div></code></pre></div></div>
<ul>
<li class="">
<p>初始化地址：<code>http://路由器IP:3000</code></p>
</li>
<li class="">
<p>配置好之后，在 OpenWrt 的 LAN DHCP 里把 DNS 指向adguardhome容器的53端口，从而实现基于DNS的广告过滤功能。</p>
</li>
</ul>
<p>更多配置详情，请查阅AdGuard Home官方文档。</p>
<h1>FAQ / 踩坑小结</h1>
<p><strong>Q1：外网访问怎么弄？</strong></p>
<ul>
<li class="">推荐：ZeroTier/Tailscale/FRP 做内网穿透，尽量别直接裸露端口在公网</li>
</ul>
<p><strong>Q3：备份怎么搞？</strong></p>
<ul>
<li class="">必备：<code>/opt/data/config</code> 整个目录（所有服务的配置）</li>
<li class="">重要数据：<code>/opt/data/media</code> 和需要保留的下载内容</li>
<li class="">换机只要把这块盘接过去，重新挂载，容器改一下路径就能接着用</li>
</ul>
<p><strong>Q4：出问题怎么看？</strong></p>
<ul>
<li class=""><code>docker logs 容器名</code> 看日志</li>
<li class=""><code>docker exec -it 容器名 /bin/sh</code> 进去容器内部排查</li>
<li class="">检查挂载目录权限、磁盘空间、内存占用这些基础项</li>
</ul>
<h1>参考链接</h1>
<ul>
<li class=""><a href="https://www.runoob.com/docker/docker-tutorial.html" target="_blank" rel="noopener noreferrer" class="">Docker 教程</a></li>
</ul>]]></content:encoded>
            <category>OpenWrt</category>
            <category>Docker</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[OPENWRT 系统 4：轻 NAS 玚法介绍]]></title>
            <link>https://zephyr.100ask.org/blog/openwrt-nas</link>
            <guid>https://zephyr.100ask.org/blog/openwrt-nas</guid>
            <pubDate>Mon, 08 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[在 OpenWrt 上搭建轻量 NAS，介绍玩法。]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案介绍与选择">方案介绍与选择<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E6%96%B9%E6%A1%88%E4%BB%8B%E7%BB%8D%E4%B8%8E%E9%80%89%E6%8B%A9" class="hash-link" aria-label="方案介绍与选择的直接链接" title="方案介绍与选择的直接链接" translate="no">​</a></h2>
<p>让 OpenWrt 上的 轻NAS（局域网文件共享）能在外网访问，也就是说，从任何地方都能安全地访问你的家用存储。  这是最简单的视线自建私有云的方式，只需要开发板要USB接口，3.0接口更佳，就可以接入USB移动硬盘，化身具有轻NAS功能的OpenWrt设备，下面是实现的步骤分析。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="文件共享">文件共享<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB" class="hash-link" aria-label="文件共享的直接链接" title="文件共享的直接链接" translate="no">​</a></h2>
<p>我们首先需要实现局域网文件共享功能，下面是常见的局域网共享场景推荐的方法，我们这里选择samba4，FileBrowser，webDAV，三种常见的共享方式都支持上，下面是具体的场景推荐的协议，可以根据自己场景灵活选择。</p>
<table><thead><tr><th>场景</th><th>推荐协议</th></tr></thead><tbody><tr><td><strong>Windows + Linux 通用文件共享</strong></td><td>Samba4</td></tr><tr><td><strong>Linux 服务器挂载（如 Docker/K8s）</strong></td><td>NFS</td></tr><tr><td><strong>外网访问 NAS（配合 frp/Tailscale）</strong></td><td>FileBrowser（Web）</td></tr><tr><td><strong>最安全的传输（需要加密）</strong></td><td>SFTP</td></tr><tr><td><strong>iPhone/macOS 挂载网盘</strong></td><td>WebDAV</td></tr><tr><td><strong>媒体播放器（电视、DLNA）</strong></td><td>Samba4 或 NFS</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="内网访问">内网访问<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E5%86%85%E7%BD%91%E8%AE%BF%E9%97%AE" class="hash-link" aria-label="内网访问的直接链接" title="内网访问的直接链接" translate="no">​</a></h2>
<p>在完成局域网网络共享后，要想实现轻NAS，还有个关键的功能，就是可以远程随时查看家里共享的文件，那么我们就需要实现内网穿透，下面是常见的内网穿透方法，及以对应的优缺点，我们选择使用frp（自建中转服务器）和现在比较流行的方法DDNSTO，前者需要自己有一个公网的服务器来做数据转发，后者操作简便只需要安装对应的插件，然后在易有云平台绑定自己的设备即可，由易有云服务商的服务器来做数据转发。</p>
<p>下面是常见的内网访问的方案对比：</p>
<table><thead><tr><th>方案</th><th>优点</th><th>缺点</th><th>安全性</th></tr></thead><tbody><tr><td>✅ <strong>公网 IP + 端口映射</strong></td><td>简单直连，速度快</td><td>需要公网 IP（电信一般不给）</td><td>较低（需防火墙）</td></tr><tr><td>🌐 <strong>DDNS + 公网 IP</strong></td><td>适合动态 IP 用户</td><td>同样需要公网访问权限</td><td>中等</td></tr><tr><td>🔐 <strong>ZeroTier / Tailscale VPN</strong></td><td>无需公网 IP，自动穿透 NAT</td><td>需第三方 VPN 控制平面</td><td>高</td></tr><tr><td>☁️ <strong>frp / Cloudflare Tunnel</strong></td><td>自建隧道，无需公网 IP</td><td>依赖中间服务器</td><td>高</td></tr><tr><td><strong>DDNSTO路由远程</strong></td><td>简单操作，无需公网IP</td><td>依赖第三方服务商</td><td>高</td></tr></tbody></table>
<p>这里我们优先使用DDNSTO插件+插件提供商的云服务来实现轻NAS应用的内网穿透，也可在自己的VPS上自建frp云服务来实现轻NAS应用的内网穿透（适合高阶用户，需要配置很多参数和一些网络知识，当然也可以问AI来生成对应的配置），可根据自己的实际情况选择适合自己的方案。</p>
<h1>DDNSTO插件实现轻NAS应用</h1>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="挂载硬盘">挂载硬盘<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E6%8C%82%E8%BD%BD%E7%A1%AC%E7%9B%98" class="hash-link" aria-label="挂载硬盘的直接链接" title="挂载硬盘的直接链接" translate="no">​</a></h2>
<p>首先，我们需要将移动硬盘插入DshanPi A1的USB TYPE-A口上，然后配置对应的挂载目录，并且设置为每次开机自动挂载。这里使用U盘进行测试示例，移动硬盘配置方法完全一样。</p>
<p>首先，在 **系统 -&gt; 挂载点 **页面，配置磁盘自动挂载的目录，并启用。</p>
<p>配置好后，重启设备，观察配置是否断电也有效，生效的话可以看到下面的打印：</p>
<p>/media的默认权限：</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="使能文件共享服务">使能文件共享服务<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E4%BD%BF%E8%83%BD%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="使能文件共享服务的直接链接" title="使能文件共享服务的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="samba共享">Samba共享<a href="https://zephyr.100ask.org/blog/openwrt-nas#samba%E5%85%B1%E4%BA%AB" class="hash-link" aria-label="Samba共享的直接链接" title="Samba共享的直接链接" translate="no">​</a></h3>
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">Samba是在Linux系统上实现SMB协议的一个免费软件，我们可以使用支持SMB协议的终端设备， 来实现局域网内的文件共享。</font>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="安装samba"><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">安装Samba</font><a href="https://zephyr.100ask.org/blog/openwrt-nas#%E5%AE%89%E8%A3%85samba" class="hash-link" aria-label="安装samba的直接链接" title="安装samba的直接链接" translate="no">​</a></h4>
<p><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">首先，我们需要在编译前选中luci-app-samba4，或者刷机后通过在线安装ipk的方式安装samba4服务端程序到系统内。安装完成后，在页面： </font><strong><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">服务 -&gt; 网络共享</font></strong><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)"> 可以看到对应的配置，如下图：</font></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="创建samba用户"><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">创建Samba用户</font><a href="https://zephyr.100ask.org/blog/openwrt-nas#%E5%88%9B%E5%BB%BAsamba%E7%94%A8%E6%88%B7" class="hash-link" aria-label="创建samba用户的直接链接" title="创建samba用户的直接链接" translate="no">​</a></h4>
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">在进行网络共享时，我们应该避免使用root用户来登录samba服务器。 为此，我们单独创建一个用户来用于samba服务器的访问，并为它赋予文件夹的访问权限。</font>
<p>打开 **服务 -&gt; 终端 **，执行下面的命令，创建用户，并给用户开启共享目录的访问权限。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#添加名为samba的用户</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">useradd samba</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#为用户samba创建smb服务的密码，这个和用户名的密码是单独的，可以设置不同</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">smbpasswd -a samba</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#使用户samba获得共享目录的权限</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#注意：只有ext4的文件系统才能修改权限，根据自己磁盘格式做对应调整</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">chown -R samba:samba /media/</span><br></div></code></pre></div></div>
<p>修改/etc/passwd，配置samba用户无法登陆，下面是示例：</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="修改samba4配置">修改samba4配置<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E4%BF%AE%E6%94%B9samba4%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="修改samba4配置的直接链接" title="修改samba4配置的直接链接" translate="no">​</a></h4>
<p><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">打开 </font><strong><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">服务 -&gt; 网络共享</font></strong><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)"> 进行参数的配置。</font></p>
<p><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">选择接口为lan，可以使内网设备访问。勾选</font><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)"> </font><strong><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">允许旧协议与身份验证。</font></strong></p>
<p><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">点击</font><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)"> </font><strong><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">新增</font></strong><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)"> </font><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">一个条目。</font></p>
<ul>
<li class="">
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">名称：共享时显示的文件夹名称，可随意设置，这里设置为media</font>
</li>
<li class=""><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">路径：将要共享的文件夹路径，这里设置为上一章节挂载的目录</font><code>&lt;font style={{color: 'rgb(64, 64, 64)', backgroundColor: 'rgb(252, 252, 252)'}}&gt;/media&lt;/font&gt;</code><font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)"></font></li>
<li class="">
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">允许用户：具有访问权限的用户，这里设置为刚刚创建的用户samba。</font>
</li>
</ul>
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">主要设置就是这些，保存并应用这些配置，其他的设置可自行探索其他高阶配置。</font>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="sftp共享">SFTP共享<a href="https://zephyr.100ask.org/blog/openwrt-nas#sftp%E5%85%B1%E4%BA%AB" class="hash-link" aria-label="SFTP共享的直接链接" title="SFTP共享的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="安装sftp-server">安装SFTP server<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E5%AE%89%E8%A3%85sftp-server" class="hash-link" aria-label="安装SFTP server的直接链接" title="安装SFTP server的直接链接" translate="no">​</a></h4>
<p>Dropbear 不支持 SFTP，但它支持 调用外部 sftp-server。</p>
<p>OpenWrt 已提供独立的 <code>openssh-sftp-server</code> 包：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">opkg update</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">opkg install openssh-sftp-server</span><br></div></code></pre></div></div>
<p>安装好后，sftp-server会放在：<code>/usr/lib/sftp-server</code>，这种方案适合需要有界面配置ssh秘钥的功能，但是也需要sftp server功能的场景，如果全部替换成openssh的全家桶，会因为OpenSSH 在 OpenWrt 中无官方 LuCI 配置界面，导致所以配置都要通过终端来完成。</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置sftp">配置SFTP<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E9%85%8D%E7%BD%AEsftp" class="hash-link" aria-label="配置SFTP的直接链接" title="配置SFTP的直接链接" translate="no">​</a></h4>
<p>在安装好后，不用做其他配置，都可以直接使用，例如用Xftp直接连接，就能看到系统内的文件。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="webdav共享">WebDAV共享<a href="https://zephyr.100ask.org/blog/openwrt-nas#webdav%E5%85%B1%E4%BA%AB" class="hash-link" aria-label="WebDAV共享的直接链接" title="WebDAV共享的直接链接" translate="no">​</a></h3>
<p>在安装完DDNSTO插件后，内部自带了一个轻量的webdav服务，不用再单独安装，直接使用即可。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置内网穿透">配置内网穿透<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E9%85%8D%E7%BD%AE%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F" class="hash-link" aria-label="配置内网穿透的直接链接" title="配置内网穿透的直接链接" translate="no">​</a></h2>
<p>首先登录DDNSTO控制台，注册登录后，记录用户Token，然后在板端配置DDNSTO远程控制页面，配置对应的参数，示例如下：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置samba远程访问">配置Samba远程访问<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E9%85%8D%E7%BD%AEsamba%E8%BF%9C%E7%A8%8B%E8%AE%BF%E9%97%AE" class="hash-link" aria-label="配置Samba远程访问的直接链接" title="配置Samba远程访问的直接链接" translate="no">​</a></h3>
<p>登录DDNSTO控制台，在文件管理栏下，点击添加文件管理，增加Samba协议的文件管理服务，填入对应参数，示例如下：</p>
<ol>
<li class="">
<p>添加配置</p>
</li>
<li class="">
<p>点击连接</p>
</li>
<li class="">
<p>输入Samba4配置中的用户和密码</p>
</li>
<li class="">
<p>连接成功，可以看到对应目录下的文件，如下所示：</p>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置sftp远程访问">配置SFTP远程访问<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E9%85%8D%E7%BD%AEsftp%E8%BF%9C%E7%A8%8B%E8%AE%BF%E9%97%AE" class="hash-link" aria-label="配置SFTP远程访问的直接链接" title="配置SFTP远程访问的直接链接" translate="no">​</a></h3>
<p>登录DDNSTO控制台，在文件管理栏下，点击添加文件管理，增加Sftp协议的文件管理服务，填入对应参数，示例如下：</p>
<ol>
<li class="">
<p>添加配置</p>
</li>
<li class="">
<p>点击访问</p>
</li>
<li class="">
<p>输入ssh可以登录的用户名和密码，这里输入root对应的密码</p>
</li>
<li class="">
<p>连接成功，可以看到对应目录下的文件，如下所示：</p>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置webdav远程访问">配置WebDAV远程访问<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E9%85%8D%E7%BD%AEwebdav%E8%BF%9C%E7%A8%8B%E8%AE%BF%E9%97%AE" class="hash-link" aria-label="配置WebDAV远程访问的直接链接" title="配置WebDAV远程访问的直接链接" translate="no">​</a></h3>
<p>登录DDNSTO控制台，在文件管理栏下，点击添加文件管理，增加webdav协议的文件管理服务，填入对应参数，示例如下：</p>
<ol>
<li class="">
<p>添加配置</p>
</li>
<li class="">
<p>点击访问</p>
</li>
<li class="">
<p>输入路由器系统里面DDSNTO插件中，填写的授权用户名和密码到登录页面中</p>
</li>
<li class="">
<p>连接成功，可以看到对应目录下的文件，如下所示：</p>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置远程访问路由器后台">配置远程访问路由器后台<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E9%85%8D%E7%BD%AE%E8%BF%9C%E7%A8%8B%E8%AE%BF%E9%97%AE%E8%B7%AF%E7%94%B1%E5%99%A8%E5%90%8E%E5%8F%B0" class="hash-link" aria-label="配置远程访问路由器后台的直接链接" title="配置远程访问路由器后台的直接链接" translate="no">​</a></h3>
<p>登录DDNSTO控制台，选择外网域名栏，然后点击添加域名，按照下面示例填写配置：</p>
<p>配置完成后，点击外网域名栏，可以直接跳转到外网域名页面，这样就可以在任何地方远程配置局域网内的路由器了。</p>
<p>总结一下：DDNSTO插件把很多远程场景都整合起来了，轻度使用的话，付费用4Mbps的就可以了，延迟低，省去了各种复杂的环境搭建过程，和自建VPS的繁琐流程，推荐！</p>
<h1>自建Frp云服务实现轻NAS应用</h1>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="挂载硬盘并使能文件共享服务">挂载硬盘并使能文件共享服务<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E6%8C%82%E8%BD%BD%E7%A1%AC%E7%9B%98%E5%B9%B6%E4%BD%BF%E8%83%BD%E6%96%87%E4%BB%B6%E5%85%B1%E4%BA%AB%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="挂载硬盘并使能文件共享服务的直接链接" title="挂载硬盘并使能文件共享服务的直接链接" translate="no">​</a></h2>
<p>自建方案中的挂载硬盘并使能文件共享服务，与使用DDNSTO插件方式完全一致，详细步骤轻查阅上一章节中的内容，此处不再累述。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置内网穿透服务">配置内网穿透服务<a href="https://zephyr.100ask.org/blog/openwrt-nas#%E9%85%8D%E7%BD%AE%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="配置内网穿透服务的直接链接" title="配置内网穿透服务的直接链接" translate="no">​</a></h2>
<p>这里需要配置的参数较多，并且需要考虑安全，需要涉及的配置项和证书等步骤较多，限于篇幅影响，这里不再详细描述，更多的请查阅frp的官方文档，搭建对应的内网穿透服务。</p>]]></content:encoded>
            <category>OpenWrt</category>
            <category>NAS</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[OPENWRT 系统 3：现有功能优化]]></title>
            <link>https://zephyr.100ask.org/blog/openwrt-feature-optimize</link>
            <guid>https://zephyr.100ask.org/blog/openwrt-feature-optimize</guid>
            <pubDate>Sat, 06 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[对 OpenWrt 现有功能进行优化。]]></description>
            <content:encoded><![CDATA[<p>在下载百问网官方适配后的Openwrt源码后，发现使用上有很多功能没有完全适配，出现部分使用过程中体验不好的问题，下面是针对笔者使用中发现的问题的记录与解决办法分析，希望给读者遇到类似问题后，一些解决问题的思路。因为本人知识有限，有什么错误的地方，欢迎交流讨论。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="安装第三方ipk无法使用">安装第三方ipk无法使用<a href="https://zephyr.100ask.org/blog/openwrt-feature-optimize#%E5%AE%89%E8%A3%85%E7%AC%AC%E4%B8%89%E6%96%B9ipk%E6%97%A0%E6%B3%95%E4%BD%BF%E7%94%A8" class="hash-link" aria-label="安装第三方ipk无法使用的直接链接" title="安装第三方ipk无法使用的直接链接" translate="no">​</a></h2>
<p>默认的云端mirror库的libc使用musl，使用glibc后烧进去，发现安装的程序都用不了，默认openwrt都是用的musl libc。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="安装第三方的fdisk无法使用">安装第三方的fdisk无法使用<a href="https://zephyr.100ask.org/blog/openwrt-feature-optimize#%E5%AE%89%E8%A3%85%E7%AC%AC%E4%B8%89%E6%96%B9%E7%9A%84fdisk%E6%97%A0%E6%B3%95%E4%BD%BF%E7%94%A8" class="hash-link" aria-label="安装第三方的fdisk无法使用的直接链接" title="安装第三方的fdisk无法使用的直接链接" translate="no">​</a></h2>
<p>默认的busybox配置，很多工具都没有，fdisk通过opkg安装后某个提示库不存在，需要手动配置Busybox的选项，我们把打开自定义busybox选项，然后配置fdisk使能。</p>
<p>然后重新编译镜像，然后刷入，测试便可以发现fdisk可以使用了。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sysupgrade镜像无法使用">sysupgrade镜像无法使用<a href="https://zephyr.100ask.org/blog/openwrt-feature-optimize#sysupgrade%E9%95%9C%E5%83%8F%E6%97%A0%E6%B3%95%E4%BD%BF%E7%94%A8" class="hash-link" aria-label="sysupgrade镜像无法使用的直接链接" title="sysupgrade镜像无法使用的直接链接" translate="no">​</a></h2>
<p>使用默认生成的sysupgrade镜像，在界面【系统-备份与升级-刷写新的固件】里面选择了编出来的固件的时候，发现无法使用，有如下错误打印信息：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:21 2025 user.info upgrade: Device 100ask,dshanpi-a1 not supported by this image</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:21 2025 user.info upgrade: Supported devices: 100ask,dshanpia1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:21 2025 user.info upgrade: Reading partition table from bootdisk...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:22 2025 user.info upgrade: Reading partition table from image...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:22 2025 user.info upgrade: Device 100ask,dshanpi-a1 not supported by this image</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:22 2025 user.info upgrade: Supported devices: 100ask,dshanpia1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:22 2025 user.info upgrade: Reading partition table from bootdisk...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Tue Dec  2 17:27:22 2025 user.info upgrade: Reading partition table from image..</span><br></div></code></pre></div></div>
<p>检查发现是armv8.mk里面定义的设备名称，和dts中的compatible不一致， 致 sysupgrade 拒绝刷机。</p>
<p>OpenWrt sysupgrade 会读取：</p>
<ol>
<li class="">当前运行设备的标识：</li>
</ol>
<p>来自：</p>
<ul>
<li class=""><code>/proc/device-tree/compatible</code></li>
<li class=""><code>/etc/board.json</code></li>
</ul>
<ol start="2">
<li class="">固件中 embedded 的 supported_devices 列表</li>
</ol>
<p>二者任意一个字符不匹配就报：<code>Device XXX not supported by this image</code></p>
<p>这里知道问题所在了，修改就比较简单了，按照如下方式修改：</p>
<ol>
<li class="">
<p>修改 target/linux/rockchip/image/armv8.mk，保持和dts中的一致</p>
</li>
<li class="">
<p>重新执行make menuconfig，选择target，会自动更新.config文件</p>
</li>
<li class="">
<p>重新执行make V=s -j8，进行镜像编译即可。</p>
</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sftp无法使用">sftp无法使用<a href="https://zephyr.100ask.org/blog/openwrt-feature-optimize#sftp%E6%97%A0%E6%B3%95%E4%BD%BF%E7%94%A8" class="hash-link" aria-label="sftp无法使用的直接链接" title="sftp无法使用的直接链接" translate="no">​</a></h2>
<p>默认的使用的dropbear做为ssh server，没有sftp功能，这里我们修改配置，关掉dropbear，然后在<strong>Network -&gt; SSH</strong>下面打开openssh，如下图所示。</p>
<p>编译无法通过，<code>openssh-sk-helper</code>编译依赖<code>libfido2</code>，我们手动使能这个库，选中为y，然后重新编译即可。</p>
<p>注意：openssh-server和openssh-server-pam无法同时使能，我们打开没有PAM支持的编译即可。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="rootfs空间太小">rootfs空间太小<a href="https://zephyr.100ask.org/blog/openwrt-feature-optimize#rootfs%E7%A9%BA%E9%97%B4%E5%A4%AA%E5%B0%8F" class="hash-link" aria-label="rootfs空间太小的直接链接" title="rootfs空间太小的直接链接" translate="no">​</a></h2>
<p>我们优先刷的squashfs格式的镜像，可以比较方便的恢复出厂配置，因为squashfs格式的rom是基于overlayfs的，更新的配置不会直接改到rom里面的内容。但是我们可以发现默认配置的rootfs的大小比较小，而板载的EMMC有58G，我们可以将rootfs空间扩大到8G，剩下的空间单独分配一个分区。</p>
<p>默认配置的rootfs分区为512M，如下所示：</p>
<p>修改配置，默认rootfs分区大小为2G，修改 Target Images下的Rootfs分区大小配置，如下所示：</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="usb设备无法识别">usb设备无法识别<a href="https://zephyr.100ask.org/blog/openwrt-feature-optimize#usb%E8%AE%BE%E5%A4%87%E6%97%A0%E6%B3%95%E8%AF%86%E5%88%AB" class="hash-link" aria-label="usb设备无法识别的直接链接" title="usb设备无法识别的直接链接" translate="no">​</a></h2>
<p>当我们只简单的在设备树使能usb0和usb1过后，会发现能识别到U盘了，但是usb驱动probe期间会打印dr_mode强制设置为host的打印，查找代码发现是默认配置的otg，但是没有otg对应的配置，并且drd相关的代码都未编译。</p>
<p>需要修改设备树文件，使能usb0和usb1控制器，默认角色为host。使能DRD ROLE SWITCH功能，然后就可以动态配置控制器角色，然后还可以指定默认角色。</p>
<p>必须要打开了 USB Gadget才能是能双角色功能，那么我们打开，然后在Mode Selection里面选中Dual Role mode，这样会在内核生成usb_role的sysfs节点，可以动态配置成host或者peripheral，在dshan pi a1上，usb1固定为host，usb0可以配置为双角色，可以切换，那么我们做如下dts配置：</p>
<div class="language-diff codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-diff codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">--- a/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3576-100ask-dshanpi-a1.dts</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+++ b/target/linux/rockchip/files/arch/arm64/boot/dts/rockchip/rk3576-100ask-dshanpi-a1.dts</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@@ -770,6 +770,20 @@</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        status = "okay";</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> };</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+// usb0 as type-c port, can be host or peripheral.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+&amp;usb_drd0_dwc3 {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+       status = "okay";</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+       usb-role-switch;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+       role-switch-default-mode ="host";</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+};</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+// usb1 as type-a port, fixed to host</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+&amp;usb_drd1_dwc3 {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+       status = "okay";</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+       usb-role-switch;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+       role-switch-default-mode ="host";</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+};</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> &amp;uart0 {</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        pinctrl-0 = &lt;&amp;uart0m0_xfer&gt;;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        status = "okay";</span><br></div></code></pre></div></div>
<p>配置后，usb1可以使用，但是usb0无法使用，并且板载Hynetek HUSB311 Type-C 芯片，可以提供USB PD和USB Type-C的功能。发现默认6.12内核版本的驱动，没有该芯片的支持，查看rockip官方仓库，有这款芯片的支持，需要移植过赖，我们暂时不需要DP功能，屏蔽掉。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pwm风扇一直最大风速">PWM风扇一直最大风速<a href="https://zephyr.100ask.org/blog/openwrt-feature-optimize#pwm%E9%A3%8E%E6%89%87%E4%B8%80%E7%9B%B4%E6%9C%80%E5%A4%A7%E9%A3%8E%E9%80%9F" class="hash-link" aria-label="PWM风扇一直最大风速的直接链接" title="PWM风扇一直最大风速的直接链接" translate="no">​</a></h2>
<p>上电后，风扇一直以最大转速工作，声音比较大，需要修改下，支持按照温度自动调整转速，这样更符合常见的应用场景。排查记录如下：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="查硬件">查硬件<a href="https://zephyr.100ask.org/blog/openwrt-feature-optimize#%E6%9F%A5%E7%A1%AC%E4%BB%B6" class="hash-link" aria-label="查硬件的直接链接" title="查硬件的直接链接" translate="no">​</a></h3>
<p>风扇使用的树莓派5的4针风扇，是标准的4针JST插口，实物图和原理图如下：</p>
<span class="text-content">风扇插口为1mm间距JST SH插座，有四个引脚：</span>
<table><thead><tr><th><strong><span class="text-content">PIN序号</span></strong></th><th><strong><span class="text-content">功能</span></strong></th></tr></thead><tbody><tr><td><span class="text-content">1</span></td><td><span class="text-content">+5V</span></td></tr><tr><td><span class="text-content">2</span></td><td><span class="text-content">PWM</span></td></tr><tr><td><span class="text-content">3</span></td><td><span class="text-content">GND</span></td></tr><tr><td><span class="text-content">4</span></td><td><span class="text-content">转速</span></td></tr></tbody></table>
<p>查看了手册，2脚连接的PWM1，4脚连接的风扇转速口，说明不支持读取转速，只能PWM控制转速。看原理图是PWM1_CH0，dts里面也有对应的配置，根据compatible字段"pwm-fan"到驱动里面搜索，发现存在linux-6.12.43/drivers/hwmon/pwm-fan.c这个文件没有编译，那么就是KCONFIG没有选中，没有编译pwm-fan的驱动。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="使能pwm驱动">使能PWM驱动<a href="https://zephyr.100ask.org/blog/openwrt-feature-optimize#%E4%BD%BF%E8%83%BDpwm%E9%A9%B1%E5%8A%A8" class="hash-link" aria-label="使能PWM驱动的直接链接" title="使能PWM驱动的直接链接" translate="no">​</a></h3>
<p>那么我们直接make kernel_menuconfig，搜索COFNIG_SENSORS_PWM_FAN，然后输入搜索结果对应的序号，然后就会直接跳转到配置对应的地方，直接输入Y使能即可。</p>
<p>编译刷写后，启动过程中发现pwm-fan驱动启动失败，有如下打印：</p>
<p>可以得出，没有找到上游的PWM设备，搜索引用的节点的compatible，发现对应的驱动未打开，在单独的目录下：drivers/soc/rockchip</p>
<p>打开的驱动：</p>
<p>打开后，会出现编译问题，我们修改如下：</p>
<p>修改如下：</p>
<div class="language-diff codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-diff codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">--- a/include/soc/rockchip/utils.h	2025-11-23 03:35:07.695086227 +0800</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+++ b/include/soc/rockchip/utils.h	2025-11-23 03:34:43.946599951 +0800</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@@ -50,6 +50,7 @@</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  *</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  * Return: the value, shifted into place, with the required write-enable bits</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  */</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#if 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> #define REG_UPDATE_WE(_val, _low, _high) ( \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	BUILD_BUG_ON_ZERO(const_true((_low) &gt; (_high))) + \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	BUILD_BUG_ON_ZERO(const_true((_high) &gt; 15)) + \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@@ -57,6 +58,11 @@</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	BUILD_BUG_ON_ZERO(const_true((u64) (_val) &gt; U16_MAX)) + \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	((_val &amp; GENMASK((_high) - (_low), 0)) &lt;&lt; (_low) | \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	(GENMASK((_high), (_low)) &lt;&lt; 16)))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#else</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#define REG_UPDATE_WE(_val, _low, _high) ( \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+	((_val &amp; GENMASK((_high) - (_low), 0)) &lt;&lt; (_low) | \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+	(GENMASK((_high), (_low)) &lt;&lt; 16)))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#endif</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> /**</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  * REG_UPDATE_BIT_WE - update a bit with a write-enable mask</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@@ -68,9 +74,14 @@</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  *</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  * Return: a value with bit @__bit set to @__val and @__bit &lt;&lt; 16 set to ``1``</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  */</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#if 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> #define REG_UPDATE_BIT_WE(__val, __bit) ( \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	BUILD_BUG_ON_ZERO(const_true((__val) &gt; 1)) + \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	BUILD_BUG_ON_ZERO(const_true((__val) &lt; 0)) + \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 	REG_UPDATE_WE((__val), (__bit), (__bit)))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#else</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#define REG_UPDATE_BIT_WE(__val, __bit) ( \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+	REG_UPDATE_WE((__val), (__bit), (__bit)))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+#endif</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> #endif /* __SOC_ROCKCHIP_UTILS_H__ */</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置转速方法">配置转速方法<a href="https://zephyr.100ask.org/blog/openwrt-feature-optimize#%E9%85%8D%E7%BD%AE%E8%BD%AC%E9%80%9F%E6%96%B9%E6%B3%95" class="hash-link" aria-label="配置转速方法的直接链接" title="配置转速方法的直接链接" translate="no">​</a></h3>
<p>手动配置pwm-fan的方法，在sysfs下面查找pwm-fan的目录，进入/sys/class/hwmon/hwmon0/下，即可看到两个文件pwm1_enable和pwm1，先配置pwm1为100，观察风扇声音是否减小，试验发现确实变小了，说明PWM控制生效了。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# ls /sys/class/hwmon/hwmon0/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">device       of_node      pwm1         subsystem</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name         power        pwm1_enable  uevent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# echo 100 &gt; /sys/class/hwmon/hwmon0/pwm1</span><br></div></code></pre></div></div>
<p>参考文档：</p>
<ul>
<li class="">Documentation/hwmon/pwm-fan.rst</li>
<li class="">Documentation/devicetree/bindings/hwmon/pwm-fan.yaml</li>
<li class="">Documentation/driver-api/thermal/sysfs-api.rst</li>
</ul>
<p>也可以根据thermal框架，下面的cooling_device找到pwm-fan。在thermal cooling device框架下有注册的sysfs接口，对应绑定pwm_fan驱动提供的ops，将state数值对应dts中配置的cooling_levels数组索引，进而可以通过配置0..max_state的数值，来配置pwm驱动里面对应的相对速度，在shell里面直接。</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token class-name">thermal_cooling_device_ops</span><span class="token plain"> pwm_fan_cooling_ops </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">get_max_state </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> pwm_fan_get_max_state</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">get_cur_state </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> pwm_fan_get_cur_state</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">set_cur_state </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> pwm_fan_set_cur_state</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//dts</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fan</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> pwm</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">fan </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    status </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"okay"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    compatible </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"pwm-fan"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">cooling</span><span class="token macro property expression operator" style="color:#393A34">-</span><span class="token macro property expression" style="color:#36acaa">cells </span><span class="token macro property expression operator" style="color:#393A34">=</span><span class="token macro property expression" style="color:#36acaa"> </span><span class="token macro property expression operator" style="color:#393A34">&lt;</span><span class="token macro property expression number" style="color:#36acaa">2</span><span class="token macro property expression operator" style="color:#393A34">&gt;</span><span class="token macro property expression punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    pwms </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">pwm1_6ch_0 </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50000</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 这里对应state从0..5</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    cooling</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">levels </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">125</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">150</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">200</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 这里配置的trips，没有生效。我们需要将它放到thermal框架里去</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    rockchip</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">temp</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">trips </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">40000</span><span class="token plain">    </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">50000</span><span class="token plain">    </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">60000</span><span class="token plain">    </span><span class="token number" style="color:#36acaa">3</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">65000</span><span class="token plain">    </span><span class="token number" style="color:#36acaa">4</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">70000</span><span class="token plain">    </span><span class="token number" style="color:#36acaa">5</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# ls /sys/class/thermal/cooling_device0/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cur_state  max_state  power      subsystem  type       uevent</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# cat /sys/class/thermal/cooling_device0/max_state </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">5</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 这里等同于 echo 100 &gt; /sys/class/hwmon/hwmon0/pwm1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@LEDE:~# echo 1 &gt; /sys/class/thermal/cooling_device0/cur_state </span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="增加自动调整转速功能">增加自动调整转速功能<a href="https://zephyr.100ask.org/blog/openwrt-feature-optimize#%E5%A2%9E%E5%8A%A0%E8%87%AA%E5%8A%A8%E8%B0%83%E6%95%B4%E8%BD%AC%E9%80%9F%E5%8A%9F%E8%83%BD" class="hash-link" aria-label="增加自动调整转速功能的直接链接" title="增加自动调整转速功能的直接链接" translate="no">​</a></h3>
<p>自动调整转速，依赖于thermal系统，主要有theraml_zone，cooling_device，trip_point三个组成。</p>
<p>参考文章：<a href="https://blog.csdn.net/Linux_zhicheng/article/details/119361850" target="_blank" rel="noopener noreferrer" class="">Linux Thermal 框架解析-CSDN博客</a></p>
<p>在原本的dts里面配置的thermal_zones节点下新增对应的trip。</p>
<p><del>单独编译dts 失败</del></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">make target/linux/prepare V=s</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make target/linux/compile DTBS=1 V=s</span><br></div></code></pre></div></div>
<p>然后你就可以直接找到生成的：</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">build_dir</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">target</span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">*</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">linux</span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">*</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">linux</span><span class="token operator" style="color:#393A34">-</span><span class="token operator" style="color:#393A34">*</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">arch</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">arm64</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">boot</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">dts</span><span class="token comment" style="color:#999988;font-style:italic">/*.dtb</span><br></div></code></pre></div></div>
<p>配置pwm1或者cur_state=0的时候，风扇转速最大。根据kernel文档关于pwm_fan的sysfs节点说明，可以由pwm1_enable文件进行配置当pwm1=0的时候的具体行为。默认的值为1，即disable pwm, keep regulator enabled。所以设置成0的时候，会直接拉满。</p>
<p>所以这里我们配置cooling-levels数组的时候，第0个元素的值设置为10，以较低速度转动。然后pwm1_enable设置为2，即pwn=0的时候，pwm和regulator都还有输出，即占空比0。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="板载led灯没有驱动">板载LED灯没有驱动<a href="https://zephyr.100ask.org/blog/openwrt-feature-optimize#%E6%9D%BF%E8%BD%BDled%E7%81%AF%E6%B2%A1%E6%9C%89%E9%A9%B1%E5%8A%A8" class="hash-link" aria-label="板载LED灯没有驱动的直接链接" title="板载LED灯没有驱动的直接链接" translate="no">​</a></h2>
<p>这是一个 <strong>由单线串行控制的 RGB LED 灯带链路</strong>：</p>
<ul>
<li class="">芯片：<strong>WS2812C-2020</strong></li>
<li class="">灯的数量：<strong>4 个（RUN × 4）</strong></li>
<li class="">每个 LED 既是 RGB LED，又集成了驱动芯片</li>
<li class="">只需要 <strong>1 根 GPIO 数字信号线</strong> 就能控制一串灯</li>
</ul>
<p>典型用途：</p>
<ul>
<li class="">状态灯</li>
<li class="">跑马灯</li>
<li class="">主板灯光</li>
<li class="">工控指示灯</li>
<li class="">路由器/电视盒子的呼吸灯</li>
</ul>
<p>WS2812 是 <strong>单线 800kHz NRZ 协议，不是普通 PWM</strong>。Linux 内核无法直接 bit-bang 得够快，必须使用能产生精确的波形才能驱动。</p>
<p>通过搜索源码，发现工程里面有提供的两种驱动，一个是leds-ws2812b，一个是ws2812-pio-rp1。仔细检查发现一个是基于spi，一个是基于pio扩展芯片的方式，<del>我们原理图里面只能使用spi hacking的方式。</del></p>
<p>配置方法参考redmi的配置，适配到dshanpi即可。</p>
<p>原理图里面的PIN脚没有MOSI功能，无法使用SPI HACKING，咨询得到，需要使用PWM HACKING方式。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="mmc驱动经常打印报错">MMC驱动经常打印报错<a href="https://zephyr.100ask.org/blog/openwrt-feature-optimize#mmc%E9%A9%B1%E5%8A%A8%E7%BB%8F%E5%B8%B8%E6%89%93%E5%8D%B0%E6%8A%A5%E9%94%99" class="hash-link" aria-label="MMC驱动经常打印报错的直接链接" title="MMC驱动经常打印报错的直接链接" translate="no">​</a></h2>
<p>驱动报错信息：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.988178] mmc0: Timeout waiting for hardware interrupt.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.988672] mmc0: sdhci: ============ SDHCI REGISTER DUMP ===========</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.989235] mmc0: sdhci: Sys addr:  0x00000002 | Version:  0x00000005</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.989800] mmc0: sdhci: Blk size:  0x00007200 | Blk cnt:  0x00000002</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.990364] mmc0: sdhci: Argument:  0x00069e72 | Trn mode: 0x0000003f</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.990929] mmc0: sdhci: Present:   0x03f700f1 | Host ctl: 0x00000035</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.991493] mmc0: sdhci: Power:     0x0000000d | Blk gap:  0x00000000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.992057] mmc0: sdhci: Wake-up:   0x00000000 | Clock:    0x0000030f</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.992621] mmc0: sdhci: Timeout:   0x0000000e | Int stat: 0x00000000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.993185] mmc0: sdhci: Int enab:  0x03ff000b | Sig enab: 0x03ff000b</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.993749] mmc0: sdhci: ACmd stat: 0x00000000 | Slot int: 0x00000000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.994313] mmc0: sdhci: Caps:      0x3a6dc881 | Caps_1:   0x08000007</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.994876] mmc0: sdhci: Cmd:       0x0000123a | Max curr: 0x00000000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.995439] mmc0: sdhci: Resp[0]:   0x00000900 | Resp[1]:  0xfff6dbff</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.996003] mmc0: sdhci: Resp[2]:   0x320f5903 | Resp[3]:  0x00009001</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.996566] mmc0: sdhci: Host ctl2: 0x0000380f</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.996957] mmc0: sdhci: ADMA Err:  0x00000060 | ADMA Ptr: 0x00000000fc300210</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 1344.997581] mmc0: sdhci: ============================================</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<p>dmesg里面probe的信息：</p>
<div class="language-plain codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-plain codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[ 0.438699] mmc0: SDHCI controller on 2a330000.mmc [2a330000.mmc] using ADMA 64-bit</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 0.499319] mmc0: new HS400 Enhanced strobe MMC card at address 0001</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 0.500422] mmcblk0: mmc0:0001 CJNB4R 58.2 GiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 0.502009] mmcblk0: p1 p2 p3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 0.502655] mmcblk0boot0: mmc0:0001 CJNB4R 4.00 MiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 0.503828] mmcblk0boot1: mmc0:0001 CJNB4R 4.00 MiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 0.504873] mmcblk0rpmb: mmc0:0001 CJNB4R 4.00 MiB, chardev (247:0)</span><br></div></code></pre></div></div>
<p>根据AI搜索和DTS里面的信息， 看得出来 eMMC 在上电初始化阶段是 完全正常工作的， 控制器寄存器/时钟/复位/pinctrl 基本没问题，否则根本不会成功切到 HS400 ES、识别分区  。</p>
<p>，可以尝试降档到HS200或者降低频率的方式，来进行测试，找一个稳定工作的版本，本地测试了两种方法：</p>
<ol>
<li class="">降档到HS200，不修改频率</li>
</ol>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">mmc</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">hs200</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token plain">_8v</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//mmc-hs400-1_8v;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">//mmc-hs400-enhanced-strobe;</span><br></div></code></pre></div></div>
<p>测试后发现，HS200工作没问题，启动打印：</p>
<div class="language-plain codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-plain codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[    0.439179] mmc0: SDHCI controller on 2a330000.mmc [2a330000.mmc] using ADMA 64-bit</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.492249] mmc0: new HS200 MMC card at address 0001</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.493187] mmcblk0: mmc0:0001 CJNB4R 58.2 GiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.494771]  mmcblk0: p1 p2 p3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.495416] mmcblk0boot0: mmc0:0001 CJNB4R 4.00 MiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.496586] mmcblk0boot1: mmc0:0001 CJNB4R 4.00 MiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.497629] mmcblk0rpmb: mmc0:0001 CJNB4R 4.00 MiB, chardev (247:0)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<ol start="2">
<li class="">保持HS400不变，降低频率到100M</li>
</ol>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">//max-frequency = &lt;200000000&gt;;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">max</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">frequency </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token number" style="color:#36acaa">100000000</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//work perfect on 100M</span><br></div></code></pre></div></div>
<p>测试后发现，也能正常工作，启动打印：</p>
<div class="language-plain codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-plain codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[    0.439264] mmc0: SDHCI controller on 2a330000.mmc [2a330000.mmc] using ADMA 64-bit</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.492185] mmc0: new HS400 Enhanced strobe MMC card at address 0001</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.493275] mmcblk0: mmc0:0001 CJNB4R 58.2 GiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.494696]  mmcblk0: p1 p2 p3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.495331] mmcblk0boot0: mmc0:0001 CJNB4R 4.00 MiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.496498] mmcblk0boot1: mmc0:0001 CJNB4R 4.00 MiB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[    0.497546] mmcblk0rpmb: mmc0:0001 CJNB4R 4.00 MiB, chardev (247:0)</span><br></div></code></pre></div></div>
<p>但是发现使用docker的时候会有各种错误打印：</p>
<p>就现使用最小修改的方法，设备树删除HS400模式配置，设置HS200模式，测试稳定运行，就先用这种。</p>]]></content:encoded>
            <category>OpenWrt</category>
            <category>优化</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[OPENWRT 系统 2：构建自定义系统]]></title>
            <link>https://zephyr.100ask.org/blog/openwrt-custom-build</link>
            <guid>https://zephyr.100ask.org/blog/openwrt-custom-build</guid>
            <pubDate>Thu, 04 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[构建自定义 OpenWrt 系统镜像。]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="序言">序言<a href="https://zephyr.100ask.org/blog/openwrt-custom-build#%E5%BA%8F%E8%A8%80" class="hash-link" aria-label="序言的直接链接" title="序言的直接链接" translate="no">​</a></h2>
<p><font style="color:rgb(17, 17, 51)">本文档旨在为开发者和爱好者提供一份清晰、简洁的 OpenWrt（LEDE）固件编译指南，专用于 </font><strong><font style="color:rgb(17, 17, 51)">DshanPi A1（基于瑞芯微 RK3576 平台）</font></strong><font style="color:rgb(17, 17, 51)"> 开发板。通过本流程，您将完成从源码获取、依赖更新、配置定制（包括 OP 域与 Kernel 域）、到最终固件生成的完整编译过程。文档同时涵盖最小化配置生成方法、常见问题提示及镜像输出说明，帮助用户高效构建适配硬件的稳定固件，为后续开发、调试或部署奠定基础。无论您是初次接触 OpenWrt 编译，还是希望针对 RK3576 平台进行深度定制，本文均可作为实用参考。</font></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置编译环境">配置编译环境<a href="https://zephyr.100ask.org/blog/openwrt-custom-build#%E9%85%8D%E7%BD%AE%E7%BC%96%E8%AF%91%E7%8E%AF%E5%A2%83" class="hash-link" aria-label="配置编译环境的直接链接" title="配置编译环境的直接链接" translate="no">​</a></h2>
<p>如果是基于WSL编译的，请参考<a href="https://www.yuque.com/jason-0nd0f/ts7m5t/dq8nprtdhgq5lk2a#wQtqk" target="_blank" rel="noopener noreferrer" class="">《一、单板介绍与开发环境搭建 - 开发环境》</a>章节，配置好WSL的基础环境。</p>
<p>然后按照仓库readme安装编译需要的编译工具链，安装好编译相关，示例如下：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y ack antlr3 asciidoc autoconf automake autopoint binutils bison build-essential \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">bzip2 ccache clang cmake cpio curl device-tree-compiler flex gawk gcc-multilib g++-multilib gettext \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">genisoimage git gperf haveged help2man intltool libc6-dev-i386 libelf-dev libfuse-dev libglib2.0-dev \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">libgmp3-dev libltdl-dev libmpc-dev libmpfr-dev libncurses5-dev libncursesw5-dev libpython3-dev \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">libreadline-dev libssl-dev libtool llvm lrzsz msmtp ninja-build p7zip p7zip-full patch pkgconf \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python3 python3-pyelftools python3-setuptools qemu-utils rsync scons squashfs-tools subversion \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">swig texinfo uglifyjs upx-ucl unzip vim wget xmlto xxd zlib1g-dev</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="获取源码">获取源码<a href="https://zephyr.100ask.org/blog/openwrt-custom-build#%E8%8E%B7%E5%8F%96%E6%BA%90%E7%A0%81" class="hash-link" aria-label="获取源码的直接链接" title="获取源码的直接链接" translate="no">​</a></h2>
<p>直接git clone百问网的仓库即可，注意有些环境可能github访问受限，克隆不下来，可以参考<a href="https://www.yuque.com/jason-0nd0f/ts7m5t/dq8nprtdhgq5lk2a#SD6lh" target="_blank" rel="noopener noreferrer" class="">《一、单板介绍与开发环境搭建 - 3.3 WSL网络代理设置》</a>中的内容，配置http/https终端代理即可。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">git clone https://github.com/dshanpi/RK3576-DshanPiA1_LEDE.git</span><br></div></code></pre></div></div>
<p>在下载完源码后，更新feeds，下载对应的包：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd RK3576-DshanPiA1_LEDE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./scripts/feeds update -a</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./scripts/feeds install -a</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="自定义选项">自定义选项<a href="https://zephyr.100ask.org/blog/openwrt-custom-build#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%80%89%E9%A1%B9" class="hash-link" aria-label="自定义选项的直接链接" title="自定义选项的直接链接" translate="no">​</a></h2>
<p>在更新feeds完成后，我们可以先使用默认的minimal配置做为基础，然后在上面做自定义配置即可，示例如下：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cp minimal.config .config</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make defconfig # 会自动补齐缺失的配置项，使其成为可编译的完整配置</span><br></div></code></pre></div></div>
<p>后续的配置可以保存为defconfig，加入版本管理中，具体方法查看本文 《4.5 保存配置》章节。</p>
<p>生成了基础配置后，就可以进行自定义配置了，自定义配置的命令为：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">make menuconfig</span><br></div></code></pre></div></div>
<p>系统的配置，简单划分的话，可以主要分为以下几个部分：</p>
<ul>
<li class="">busybox</li>
</ul>
<p>这部分是基础系统的特性配置，openwrt的基础系统是使用的busybox。</p>
<ul>
<li class="">app</li>
</ul>
<p>这部分对应一些命令或者luci-xxx这类待页面的应用，主要靠这部分扩展路由器的功能，和暴露易用的配置界面。</p>
<ul>
<li class="">libs</li>
</ul>
<p>这部分主要是配置openwrt的系统里面集成的库，可以按需增加，常规情况下是选中某些命令或者luci类的app的时候，会自动选中对应的库。</p>
<ul>
<li class="">kernel</li>
</ul>
<p>这部分主要是配置kernel，包含一些内核功能和驱动，在有新的外设支持的时候，需要配置到。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置编译选项">配置编译选项<a href="https://zephyr.100ask.org/blog/openwrt-custom-build#%E9%85%8D%E7%BD%AE%E7%BC%96%E8%AF%91%E9%80%89%E9%A1%B9" class="hash-link" aria-label="配置编译选项的直接链接" title="配置编译选项的直接链接" translate="no">​</a></h3>
<p>这部分主要配置编译目标文件时候的一些优化参数和编译工具链的一些选项，按照下面的方法打开：</p>
<ol>
<li class="">
<p>首先使能 Advanced configuration options (for developers)：</p>
</li>
<li class="">
<p>使能 Target Options，并填入目标优化的GCC编译参数：</p>
</li>
<li class="">
<p>使能Toolchain Options，配置工具链选项：</p>
</li>
</ol>
<blockquote>
<p>警告：此处C库实现要选择musl，不然刷机完进如系统后，通过Opkg下载的包全都无法使用！（因为默认的包都是musl c库）！</p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置busybox选项">配置busybox选项<a href="https://zephyr.100ask.org/blog/openwrt-custom-build#%E9%85%8D%E7%BD%AEbusybox%E9%80%89%E9%A1%B9" class="hash-link" aria-label="配置busybox选项的直接链接" title="配置busybox选项的直接链接" translate="no">​</a></h3>
<p>在有些场景，openwrt的非busybox类的配置无法覆盖要求，需要通过busybox里面的包来实现，这个时候就需要自定义busybox的选项。可以参考下面的配置方法：</p>
<ol>
<li class="">选中 Base System -&gt;  Customize busybox options</li>
</ol>
<p>其中Settings是一些额外的参数配置，如编译选项等；Applets是一些命令行工具的配置，我们按需进行相应的配置即可。</p>
<p>需要注意的是，当openwrt的包能提供对应的功能的时候，我们不应在busybox的配置里面再提供，不然在编译的最后环节，会提示已经提供但是Busybox里面也有的错误提示。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置应用">配置应用<a href="https://zephyr.100ask.org/blog/openwrt-custom-build#%E9%85%8D%E7%BD%AE%E5%BA%94%E7%94%A8" class="hash-link" aria-label="配置应用的直接链接" title="配置应用的直接链接" translate="no">​</a></h3>
<p>openwrt包含丰富的应用集，可以极大地丰富路由器的功能，包含各种各样的库，命令行工具，带界面的APP（常称为插件）等，这里只对配置一些常见的APP做一些配置示例。</p>
<p>大部分包都按照分类，有序的按照字母顺序排列在各个大项下面，如我们想使能一下sftp-server，那么可以在：Network -&gt; SSH 页面下找到，然后选中即可，示例如下：</p>
<p>还有一种比较快捷的方法，可以通过menuconfig的配置项搜索功能，快速定位到需要配置的页面去选中，下面已sftp-server为目标，搜索打开的方法示例：</p>
<ol>
<li class="">
<p>在menuconfig主界面，输入/，进如搜索页面，然后在搜索页面输入sftp-server</p>
</li>
<li class="">
<p>根据搜索结果页面中(N)对应的数字索引，可以快速跳转到某条结果，如此处只有一个结果，那么索引是1，直接输入1，会直接跳转到对应的页面。</p>
</li>
<li class="">
<p>可以看到目前搜索页面对应的包是=n，未使能的；输入索引值跳转过去后发现确实是未使能，相对应，这个时候我们只需要输入y使能即可。</p>
</li>
<li class="">
<p>针对有多条搜索结果的情况，我们可以通过输入空格键实现整页翻页查看结果，也可以通过输入上下键实现按行翻页查看结果，通过查看搜索页面的详细信息，确定是否是自己要找的包。</p>
</li>
</ol>
<blockquote>
<p>说明：推荐两种方法都灵活使用，可以大大加快开发效率。</p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置kernel选项">配置kernel选项<a href="https://zephyr.100ask.org/blog/openwrt-custom-build#%E9%85%8D%E7%BD%AEkernel%E9%80%89%E9%A1%B9" class="hash-link" aria-label="配置kernel选项的直接链接" title="配置kernel选项的直接链接" translate="no">​</a></h3>
<p>kernel的配置选项和其他不同，不是make menuconfig配置的，而是有单独的make目标，示例如下：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">make kernel_menuconfig</span><br></div></code></pre></div></div>
<p>在未编译过整个工程的情况下，执行上述命令会自动去先编译依赖的工具链，可能比较耗时，推荐先整个工程编译一次，然后再自定义配置kernel选项。</p>
<p>因为第一次整个编译工程的时候，会下载依赖的所有源码包，并编译对应的工具链，比较耗时。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="保存配置">保存配置<a href="https://zephyr.100ask.org/blog/openwrt-custom-build#%E4%BF%9D%E5%AD%98%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="保存配置的直接链接" title="保存配置的直接链接" translate="no">​</a></h3>
<p>针对OP域的配置，使用下面命令，生成最小配置文件：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./scripts/diffconfig.sh &gt; defconfig</span><br></div></code></pre></div></div>
<p>针对kernel域的配置，在配置kernel的时候，会自动更新配置到target下面的config文件里面，不用手动保存。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="编译">编译<a href="https://zephyr.100ask.org/blog/openwrt-custom-build#%E7%BC%96%E8%AF%91" class="hash-link" aria-label="编译的直接链接" title="编译的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="流程">流程<a href="https://zephyr.100ask.org/blog/openwrt-custom-build#%E6%B5%81%E7%A8%8B" class="hash-link" aria-label="流程的直接链接" title="流程的直接链接" translate="no">​</a></h3>
<p>首先执行下载操作，解决完下载过程中可能遇到的问题，然后再执行编译流程。</p>
<p>避免默认的编译过程中下载，可能会某个包失败了后，再编译的时候，会挨个检查之前的包是否下载和编译完成了，这样不利于调试，执行命令如下：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 当下载失败的时候，使用-j1查看具体的失败信息</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 下载的源码包都存放在工程根目录的dl目录下</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make download -j$(nproc)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#第一次编译推荐用单线程，测试多线程编译会失败！</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make V=s -j1</span><br></div></code></pre></div></div>
<p>二次编译的时候，可以执行:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">make V=s -j$(nproc)</span><br></div></code></pre></div></div>
<p>如果需要重新配置，按照下面流程执行：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">rm -rf .config</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make menuconfig</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make V=s -j$(nproc)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="常见编译错误">常见编译错误<a href="https://zephyr.100ask.org/blog/openwrt-custom-build#%E5%B8%B8%E8%A7%81%E7%BC%96%E8%AF%91%E9%94%99%E8%AF%AF" class="hash-link" aria-label="常见编译错误的直接链接" title="常见编译错误的直接链接" translate="no">​</a></h3>
<p>有些程序编译的时候会失败，这个时候我们需要重新使用make V=s -j1的方式重新跑一遍，才能较好的看到编译过程中的错误，比较场景的有未定义或者库找不到的错误，或者Werror导致的报错，下面是一个简单的解决方式示例。</p>
<p>如最开始使用glibc进行编译，发现mbedtls和vlmcsd一直编不过，增加如下修改可以编过：</p>
<div class="language-diff codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-diff codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">diff --git a/package/libs/mbedtls/Makefile b/package/libs/mbedtls/Makefile</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">index 4e0a4a034..54a0b2d45 100644</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">--- a/package/libs/mbedtls/Makefile</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+++ b/package/libs/mbedtls/Makefile</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@@ -121,7 +121,7 @@ This package contains mbedtls helper programs for private key and</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> CSR generation (gen_key, cert_req)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> endef</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-TARGET_CFLAGS += -ffunction-sections -fdata-sections</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+TARGET_CFLAGS += -ffunction-sections -fdata-sections -Wno-error=stringop-overflow</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> TARGET_CFLAGS := $(filter-out -O%,$(TARGET_CFLAGS))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> CMAKE_OPTIONS += </span><br></div></code></pre></div></div>
<div class="language-diff codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-diff codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">--- Makefile.orig       2025-11-14 01:58:43.376952312 +0800</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+++ Makefile    2025-11-14 01:53:50.865983762 +0800</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@@ -37,4 +37,6 @@</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        $(INSTALL_BIN) ./files/vlmcsd.ini $(1)/etc/vlmcsd/vlmcsd.ini</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> endef</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+TARGET_LDFLAGS += -lresolv -lpthread</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">+</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> $(eval $(call BuildPackage,vlmcsd))</span><br></div></code></pre></div></div>
<p>更多编译过程中的错误，灵活使用AI工具和搜索引擎，基本都能解决编译中遇到的问题。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="烧写">烧写<a href="https://zephyr.100ask.org/blog/openwrt-custom-build#%E7%83%A7%E5%86%99" class="hash-link" aria-label="烧写的直接链接" title="烧写的直接链接" translate="no">​</a></h2>
<p>编译完成后，会在对应的bin/target/xxxx目录生成两个类型的镜像包，一个是ext4一个是squashfs的，如果有恢复默认配置需求，需要使用squashfs的镜像包。</p>
<font style="color:rgb(28, 30, 33)">注意：在OpenWrt编译完成后，可以刷写的镜像会被压缩成zip格式文件，需要先执行解压操作，然后才能做为烧录工具的刷机镜像，示例如下：</font>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">jason@ubuntu24:~/LEDE/bin/targets/rockchip/armv8$ gunzip -k openwrt-rockchip-armv8-100ask_dshanpia1-squashfs-sysupgrade.img.gz -f</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gzip: openwrt-rockchip-armv8-100ask_dshanpia1-squashfs-sysupgrade.img.gz: decompression OK, trailing garbage ignored</span><br></div></code></pre></div></div>
<p>解压得到img镜像后，参考《<a href="https://www.yuque.com/jason-0nd0f/ts7m5t/dq8nprtdhgq5lk2a" target="_blank" rel="noopener noreferrer" class="">单板介绍与开发环境搭建 - 4.3开始烧录</a>》内容，进行刷机。</p>
<p>openwrt系统自带的在线刷机功能使用的时候有问题，参考《<a href="https://www.yuque.com/jason-0nd0f/ts7m5t/hru38u3g3erf1yuv#G6G2J" target="_blank" rel="noopener noreferrer" class="">现有功能优化 - 1.3 sysupgrade镜像无法使用</a>》章节进行适配，适配后便可以直接通过web的方式直接刷机，示例如下：</p>
<blockquote>
<p>注意：web页面在线升级选择的为压缩后的镜像包！</p>
</blockquote>]]></content:encoded>
            <category>OpenWrt</category>
            <category>构建</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[OPENWRT 系统 1：A1 主板介绍与开发环境搭建]]></title>
            <link>https://zephyr.100ask.org/blog/openwrt-board-env-setup</link>
            <guid>https://zephyr.100ask.org/blog/openwrt-board-env-setup</guid>
            <pubDate>Tue, 02 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[介绍 DshanPi-A1 主板并搭建 OpenWrt 开发环境。]]></description>
            <content:encoded><![CDATA[<font style="color:rgb(28, 30, 33)">DShanPl-A1 Education专为人工智能教育及项目开发深度优化，基于瑞芯微的RK3576处理器设计，集成了4个Cortex-A72和4个Cortex-A53及支持NEON指令集,支持8K@30fps的H.265,VP9AVS2 和 AV1解码器,4k@60fps的H.264解码器和4K@60fps的AV1解码器;还支持4K@60fps的H.264和H.265编码器。内置3D GPU,能够完全兼容OpenGl ES1.1/2.0/3.2、0penCL2.0和Vulkan 1.1。内嵌的NPU算力高达6TopS,支持INT4/INT8/INT16/FP16混合运算。</font>
<p>板子有丰富的外设接口，板载SOC性能强劲，可以提供<font style="color:rgb(28, 30, 33)">中高端性能 SBC（Single Board Computer-卡片电脑）体验，智能路由器等，下面是一些对应的应用场景示例：</font></p>
<ul>
<li class="">
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">智能单机小电脑，具备办公，教育，编程开发，嵌入式开发等功能</font>
</li>
<li class="">
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">个人git仓库，服务器，nas，软路由，私有云</font>
</li>
<li class="">
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">机器人，无人机等项目</font>
</li>
<li class="">
<font style="color:rgb(64, 64, 64);background-color:rgb(252, 252, 252)">电视机盒子，智能家居中枢，家庭安防监控，智能音箱等智能设备</font>
</li>
</ul>
<font style="color:rgb(28, 30, 33)">OpenWrt 是一个基于 Linux 的开源嵌入式操作系统，主要用于路由器等网络设备。与传统路由器固件相比，OpenWrt 不是固定功能的固件，而是可自由扩展的软件平台，用户可以通过 opkg 软件包系统安装各种组件，实现路由、防火墙、VPN、NAS、内网穿透等多种功能。它提供 SSH 命令行与 LuCI Web 界面，配置灵活，支持 VLAN、IPv6、QoS、多 WAN 等高级网络特性。OpenWrt 结构清晰、模块化，核心包括 UCI 配置系统、netifd 网络管理、dnsmasq、hostapd 和防火墙框架等。凭借高度可定制性和强大的社区支持，OpenWrt 适用于家庭、企业网络以及二次开发，是打造高功能路由器和网络应用平台的理想选择。  </font>
<font style="color:rgb(28, 30, 33)">Lean 的 OpenWrt LEDE 仓库是一个由 Lean 所维护的开源项目，旨在为 OpenWrt 系统提供稳定、高效且功能丰富的支持。作为 OpenWrt 和 LEDE 项目的结合，Lean 版本为广泛的路由器和嵌入式设备提供了优化的固件及增强功能，广泛应用于家庭、企业及实验室环境。Lean 仓库包含了来自全球开源社区的众多补丁、优化、驱动程序以及各种第三方应用，极大地提升了 OpenWrt 系统的可定制性和性能。</font>
<p>本次项目的目标是基于 DShanPl-A1 Education 单板构建一个轻量化 NAS（轻NAS）应用。最佳实现路径是采用成熟且高度可扩展的开源路由系统 OpenWrt LEDE。借助 OpenWrt 完整的 Linux 环境与丰富的生态插件，我们能够在系统中按需安装存储服务、网络服务、内网穿透、安全访问等功能模块。通过这些插件之间的协作配置，再结合 OpenWrt 强大的网络管理能力，即可构建一个基于软路由架构的轻NAS 方案。</p>
<h1>开发环境</h1>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="环境说明">环境说明<a href="https://zephyr.100ask.org/blog/openwrt-board-env-setup#%E7%8E%AF%E5%A2%83%E8%AF%B4%E6%98%8E" class="hash-link" aria-label="环境说明的直接链接" title="环境说明的直接链接" translate="no">​</a></h2>
<p>编译openwrt官方推荐使用原生<font style="color:rgb(51, 51, 51)"> </font><a href="https://openwrt.org/docs/guide-developer/toolchain/install-buildsystem" target="_blank" rel="noopener noreferrer" class=""><font style="color:rgb(51, 122, 183)">GNU/Linux environment</font></a><font style="color:rgb(51, 51, 51)">，但是也支持使用Windows WSL的模式进行编译。在Windows上使用WSL的开发环境，不用去配置虚拟机环境，在某些限制按照vmware的环境下也可以使用，估笔者的编译和开发环境大多数优先使用WSL进行。</font></p>
<p>WSL（Windows Subsystem for Linux）在 Windows 上提供原生级 Linux 环境，适合开发者进行跨平台或 Linux 相关项目开发。其主要优点包括：</p>
<ol>
<li class=""><strong>轻量快速</strong><font style="color:rgb(51, 51, 51)">：无需虚拟机或双系统，启动和运行几乎与原生 Linux 一样快，资源占用低。</font></li>
<li class=""><strong>无缝集成 Windows</strong><font style="color:rgb(51, 51, 51)">：可以直接访问 Windows 文件系统、使用 Windows 工具（如 VSCode、浏览器）与 Linux 工具协同工作。</font></li>
<li class=""><strong>原生 Linux 体验</strong><font style="color:rgb(51, 51, 51)">：支持大多数 Linux 命令、包管理器、构建工具，可直接进行编译、调试、运行服务。</font></li>
<li class=""><strong>易于安装维护</strong><font style="color:rgb(51, 51, 51)">：从 Microsoft Store 一键安装，系统更新、环境切换都非常方便。</font></li>
<li class=""><strong>优秀的开发体验</strong><font style="color:rgb(51, 51, 51)">：支持 Docker（WSL2）、Git、Python、Node.js、C/C++ 等主流开发环境，适合嵌入式、服务器、网络、AI 等领域。</font></li>
<li class=""><strong>跨平台兼容性好</strong><font style="color:rgb(51, 51, 51)">：能在 Windows 上构建 Linux 可运行的软件，如编译 OpenWrt、构建驱动、生成交叉编译包等。</font></li>
</ol>
<font style="color:rgb(51, 51, 51)">总体来说，WSL 让开发者在 Windows 下以最小成本获得接近原生的 Linux 能力，大大提升效率与灵活性，我们采用VSCode远程访问的方式，很方便的可以完成开发工作。</font>
<font style="color:rgb(51, 51, 51)">下面是一些需要在编译前需要配置的WSL环境，把这部分复制到</font>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="环境变量配置"><font style="color:rgb(51, 51, 51)">环境变量配置</font><a href="https://zephyr.100ask.org/blog/openwrt-board-env-setup#%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="环境变量配置的直接链接" title="环境变量配置的直接链接" translate="no">​</a></h2>
<p>参考官方文档：<a href="https://openwrt.org/docs/guide-developer/toolchain/wsl" target="_blank" rel="noopener noreferrer" class="">Build system setup WSL</a></p>
<p>在WSL环境下面，编译用户的.bashrc里面，按照下面说明增加对应的配置信息，解决默认环境下，Windows的环境变量也会在WSL里面默认生效的问题，这样设置过后，基本上环境和原生的GNU/LINUX环境保持一致，不会用WSL的机制导入的问题。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># GO编译配置，如果编译不了打开这个</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#export GO111MODULE=on</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#export GOPROXY=https://goproxy.cn</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># proxy，这里替换成自己的Windows环境的代理服务IP:PORT</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export http_proxy=http://192.168.31.50:6080</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export https_proxy=http://192.168.31.50:6080</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Filter Windows PATH stuff</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export PATH=$(echo $PATH | sed -e 's|:[^:]*WindowsApps[^:]*||g')</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export PATH=$(echo $PATH | tr ':' '\n' | grep -v NVIDIA | tr '\n' ':')</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export PATH=$(echo $PATH | tr ':' '\n' | grep -v 'Files' | paste -sd ':' -)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export PATH=$(echo $PATH | tr ':' '\n' | grep -v 'VS' | paste -sd ':' -)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export PATH=$(echo $PATH | tr ':' '\n' | grep -v '/mnt/' | paste -sd ':' -)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="wsl网络代理设置">WSL网络代理设置<a href="https://zephyr.100ask.org/blog/openwrt-board-env-setup#wsl%E7%BD%91%E7%BB%9C%E4%BB%A3%E7%90%86%E8%AE%BE%E7%BD%AE" class="hash-link" aria-label="WSL网络代理设置的直接链接" title="WSL网络代理设置的直接链接" translate="no">​</a></h2>
<p>针对有的工具包在github上，默认网络下载可能会经常失败，我们可以选择在Windows上运行对应的代理软件，然后开启允许其它设备连接，然后在WSL中配置对应的http_proxy和https_proxy环境变量，就可以很方便的对github访问进行加速了。</p>
<p>下面是一些配置示例：</p>
<ol>
<li class="">
<p>代理软件使能局域网设备连接</p>
</li>
<li class="">
<p>WSL Settings中设置网络模式为Mirrored</p>
</li>
</ol>
<p>更多说明请查阅微软的官方稳文档：<a href="https://learn.microsoft.com/zh-cn/windows/wsl/networking#mirrored-mode-networking" target="_blank" rel="noopener noreferrer" class="">使用 WSL 访问网络应用程序 - 镜像模式网络</a></p>
<ol start="3">
<li class="">
<p>配置好后，先wsl --shutdown，然后再重新启动wsl ubuntu</p>
</li>
<li class="">
<p>检查环境变量WSL_PAC_URL是否已经配置成功，成功的示例如下：</p>
</li>
<li class="">
<p>配置终端http和https代理，自动PAC过滤</p>
</li>
</ol>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">export http_proxy=$WSL_PAC_URL</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export https_proxy=$WSL_PAC_URL</span><br></div></code></pre></div></div>
<blockquote>
<p>Tips: 可以直接写入当前用户的.bashrc里面，这样不用每次都执行一遍代理设置。</p>
</blockquote>
<h1>刷机测试方法</h1>
<p>这里介绍刷入LEDE镜像的基础方法，需要提前掌握刷入镜像的方法，下面是详细步骤介绍。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="硬件连接">硬件连接<a href="https://zephyr.100ask.org/blog/openwrt-board-env-setup#%E7%A1%AC%E4%BB%B6%E8%BF%9E%E6%8E%A5" class="hash-link" aria-label="硬件连接的直接链接" title="硬件连接的直接链接" translate="no">​</a></h2>
<p><font style="color:rgb(28, 30, 33)">烧录系统镜像，除了dshanpi-a1板子，还需要准备 </font><strong><font style="color:rgb(28, 30, 33)">TypeC USB线 、30W PD电源适配器</font></strong><font style="color:rgb(28, 30, 33)"> （建议韦东山店铺购买），如下所示：</font></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="安装驱动和刷机软件">安装驱动和刷机软件<a href="https://zephyr.100ask.org/blog/openwrt-board-env-setup#%E5%AE%89%E8%A3%85%E9%A9%B1%E5%8A%A8%E5%92%8C%E5%88%B7%E6%9C%BA%E8%BD%AF%E4%BB%B6" class="hash-link" aria-label="安装驱动和刷机软件的直接链接" title="安装驱动和刷机软件的直接链接" translate="no">​</a></h2>
<p>需要下载的工具包和镜像文件如下：</p>
<ul>
<li class=""><strong><font style="color:rgb(28, 30, 33)">OpenWrt 系统镜像：</font></strong><font style="color:rgb(28, 30, 33)"> </font><a href="https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/openwrt-rockchip-armv8-100ask_dshanpia1-squashfs-sysupgrade.7z" target="_blank" rel="noopener noreferrer" class=""><font style="color:rgb(46, 133, 85)">DshanPi-A1_OpenWrt_Image</font></a><font style="color:rgb(46, 133, 85)">（百问网提供的）</font></li>
<li class=""><strong><font style="color:rgb(28, 30, 33)">烧录工具 RKDevTool：</font></strong><font style="color:rgb(28, 30, 33)"> </font><a href="https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/RKDevTool_Release_v3.32.zip" target="_blank" rel="noopener noreferrer" class=""><font style="color:rgb(46, 133, 85)">RKDevTool_Release_v3.32.zip</font></a></li>
<li class=""><strong><font style="color:rgb(28, 30, 33)">驱动安装工具包 DriverAssitant：</font></strong><font style="color:rgb(28, 30, 33)"> </font><a href="https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/DriverAssitant_v5.1.1.zip" target="_blank" rel="noopener noreferrer" class=""><font style="color:rgb(46, 133, 85)">DriverAssitant_v5.1.1.zip</font></a></li>
<li class=""><strong><font style="color:rgb(28, 30, 33)">DshanPi-A1 引导固件：</font></strong><font style="color:rgb(28, 30, 33)"> </font><a href="https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/rk3576_spl_loader_v1.09.107.bin" target="_blank" rel="noopener noreferrer" class=""><font style="color:rgb(46, 133, 85)">rk3576_spl_loader_v1.09.107.bin</font></a></li>
</ul>
<font style="color:rgb(28, 30, 33)">在前面下载的资料里找到驱动安装工具包 DriverAssitant_v5.1.1.zip，解压 ，然后打开启动下载程序 DriverInstall.exe ，点击驱动安装即，如下：</font>
<p>解压前面下载链接下载的烧录工具RKDevTool_Release_v3.32.zip，然后直接双击RKDevTool.exe即可。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="开始烧录">开始烧录<a href="https://zephyr.100ask.org/blog/openwrt-board-env-setup#%E5%BC%80%E5%A7%8B%E7%83%A7%E5%BD%95" class="hash-link" aria-label="开始烧录的直接链接" title="开始烧录的直接链接" translate="no">​</a></h2>
<font style="color:rgb(28, 30, 33)">准备工作完成后，按照下面的步骤操作，使设备进如MASKROM烧录模式：</font>
<p><font style="color:rgb(28, 30, 33)">① 接上 </font><strong><font style="color:rgb(28, 30, 33)">usb2.0/3.0 otg</font></strong><font style="color:rgb(28, 30, 33)"> 线（也即type-c烧录数据线，数据线另一端接电脑的 USB2.0/3.0 蓝色接口）；</font></p>
<p><font style="color:rgb(28, 30, 33)">② 按住 </font><code>**&lt;font style={{color: 'rgb(28, 30, 33)', backgroundColor: 'rgb(246, 247, 248)'}}&gt;MASKROM&lt;/font&gt;**</code><font style="color:rgb(28, 30, 33)"> 按键，</font><strong><font style="color:rgb(28, 30, 33)">先不松开</font></strong><font style="color:rgb(28, 30, 33)"> ；</font></p>
<p><font style="color:rgb(28, 30, 33)">③ 再接上电源，dshanpi-a1 就会进入 </font><code>**&lt;font style={{color: 'rgb(28, 30, 33)', backgroundColor: 'rgb(246, 247, 248)'}}&gt;MASKROM&lt;/font&gt;**</code><font style="color:rgb(28, 30, 33)"> 烧录模式；</font></p>
<font style="color:rgb(28, 30, 33)">打开烧录工具，按照下面的选择界面参数，配置烧录镜像和参数，然后点击执行，等待下载完成，在刷入完成后，会自动重启单板，然后出现LEDE的像素LOGO，即刷入完成。</font>
<font style="color:rgb(28, 30, 33)">注意：在OpenWrt编译完成后，可以刷写的镜像会被压缩成zip格式文件，需要先执行解压操作，然后才能做为烧录工具的刷机镜像，示例如下：</font>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">jason@ubuntu24:~/LEDE/bin/targets/rockchip/armv8$ gunzip -k openwrt-rockchip-armv8-100ask_dshanpia1-squashfs-sysupgrade.img.gz -f</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gzip: openwrt-rockchip-armv8-100ask_dshanpia1-squashfs-sysupgrade.img.gz: decompression OK, trailing garbage ignored</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 待输入img镜像文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">jason@ubuntu24:~/LEDE/bin/targets/rockchip/armv8$ ls -lh openwrt-rockchip-armv8-100ask_dshanpia1-squashfs-sysupgrade.img</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-rw-r--r-- 1 jason jason 640M Nov 28 02:24 openwrt-rockchip-armv8-100ask_dshanpia1-squashfs-sysupgrade.img</span><br></div></code></pre></div></div>
<h1>参考文档</h1>
<ul>
<li class=""><a href="https://wiki.dshanpi.org/docs/DshanPi-A1/intro/" target="_blank" rel="noopener noreferrer" class="">百问网 DshanPi-A1介绍</a></li>
<li class=""><a href="https://wiki.dshanpi.org/docs/DshanPi-A1/OtherSystem/OpenWrt-LEDE/FlasheMMC" target="_blank" rel="noopener noreferrer" class="">百问网 OpenWrt 系统镜像烧录至 EMMC</a></li>
<li class=""><a href="https://openwrt.org/docs/guide-developer/start" target="_blank" rel="noopener noreferrer" class="">https://openwrt.org/docs/guide-developer/start</a></li>
<li class=""><a href="https://www.cnblogs.com/lx2035/p/17961653" target="_blank" rel="noopener noreferrer" class="">openwrt编译记录 - LX2020 - 博客园</a></li>
</ul>]]></content:encoded>
            <category>OpenWrt</category>
            <category>开发环境</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 音频录制播放与噪声分析]]></title>
            <link>https://zephyr.100ask.org/blog/audio-record-noise-analysis</link>
            <guid>https://zephyr.100ask.org/blog/audio-record-noise-analysis</guid>
            <pubDate>Sun, 30 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[在 RK3576 上实现音频录制与播放，并对噪声进行频谱分析。]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="音频播放">音频播放<a href="https://zephyr.100ask.org/blog/audio-record-noise-analysis#%E9%9F%B3%E9%A2%91%E6%92%AD%E6%94%BE" class="hash-link" aria-label="音频播放的直接链接" title="音频播放的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="扬声器设备">扬声器设备<a href="https://zephyr.100ask.org/blog/audio-record-noise-analysis#%E6%89%AC%E5%A3%B0%E5%99%A8%E8%AE%BE%E5%A4%87" class="hash-link" aria-label="扬声器设备的直接链接" title="扬声器设备的直接链接" translate="no">​</a></h3>
<p>先看以下这个扬声器如何使用，先列出音频播放设备</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">aplay -l</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    **** List of PLAYBACK Hardware Devices ****</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    card 0: rockchipes8388 [rockchip-es8388], device 0: dailink-multicodecs ES8323 HiFi-0 [dailink-multicodecs ES8323 HiFi-0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevices: 1/1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevice #0: subdevice #0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    card 1: rockchiphdmiin [rockchip,hdmiin], device 0: 2a640000.sai-dummy_codec dummy_codec-0 [2a640000.sai-dummy_codec dummy_codec-0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevices: 1/1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevice #0: subdevice #0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    card 2: rockchipdp0 [rockchip-dp0], device 0: rockchip-dp0 spdif-hifi-0 [rockchip-dp0 spdif-hifi-0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevices: 1/1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevice #0: subdevice #0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    card 3: rockchiphdmi [rockchip-hdmi], device 0: rockchip-hdmi i2s-hifi-0 [rockchip-hdmi i2s-hifi-0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevices: 1/1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      Subdevice #0: subdevice #0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<p>可以看出，总共检测到 <strong>4张音频卡</strong>（card 0 ~ card 3）</p>
<ul>
<li class=""><strong>播放音频到扬声器/耳机</strong>：使用 <code>card 0, device 0</code></li>
<li class=""><strong>HDMI音频输出</strong>：使用 <code>card 3, device 0</code></li>
<li class=""><strong>DisplayPort音频</strong>：使用 <code>card 2, device 0</code></li>
<li class=""><strong>捕获HDMI输入音频</strong>：使用 <code>card 1, device 0</code></li>
</ul>
<p>扬声器是<strong>card0：subdevice#0</strong>，对应alsa设备就是<strong>hw:0,0</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">**** List of PLAYBACK Hardware Devices ****</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">card 0: rockchipes8388 [rockchip-es8388], device 0: dailink-multicodecs ES8323 HiFi-0 [dailink-multicodecs ES8323 HiFi-0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Subdevices: 1/1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  Subdevice #0: subdevice #0</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="创建并播放简单测试音"><strong>创建并播放简单测试音</strong><a href="https://zephyr.100ask.org/blog/audio-record-noise-analysis#%E5%88%9B%E5%BB%BA%E5%B9%B6%E6%92%AD%E6%94%BE%E7%AE%80%E5%8D%95%E6%B5%8B%E8%AF%95%E9%9F%B3" class="hash-link" aria-label="创建并播放简单测试音的直接链接" title="创建并播放简单测试音的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 创建8kHz采样率的1kHz正弦波WAV文件（5秒）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ffmpeg -f lavfi -i "sine=frequency=1000:duration=5" -c:a pcm_s16le -ar 8000 test_tone.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 播放该文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay test_tone.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Playing WAVE 'test_tone.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Mono</span><br></div></code></pre></div></div>
<p>测试的命令都成功了，但是没有听到声音，需要查看这个扬声器的属性，很可能是音频路由问题，首先需要确定排查思路：</p>
<p>音频芯片（ES8388）设计是：</p>
<ul>
<li class=""><strong>软件控制层</strong>：<code>Speaker Switch</code> - 控制音频流是否发送到芯片</li>
<li class=""><strong>硬件控制层</strong>：<code>OUT1/OUT2 Switch</code> - 控制芯片物理引脚输出</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="音频播放调试">音频播放调试<a href="https://zephyr.100ask.org/blog/audio-record-noise-analysis#%E9%9F%B3%E9%A2%91%E6%92%AD%E6%94%BE%E8%B0%83%E8%AF%95" class="hash-link" aria-label="音频播放调试的直接链接" title="音频播放调试的直接链接" translate="no">​</a></h3>
<p>先打开音频可视化工具看一下</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">alsamixer -c 0</span><br></div></code></pre></div></div>
<p>可以看出playback的状态不正常： <strong>MM 00</strong>，需要进一步确认是哪个配置的问题，使用 <strong>PulseAudio控制工具</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">pactl list short sinks</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    0       alsa_output.0.HiFi__hw_rockchipes8388__sink     module-alsa-card.c      s16le 2ch 44100Hz       SUSPENDED</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    1       alsa_output.1.stereo-fallback   module-alsa-card.c      s16le 2ch 44100Hz       SUSPENDED</span><br></div></code></pre></div></div>
<p>作一些解释：</p>
<ul>
<li class=""><strong>Sink</strong>（接收器）：音频输出的终点</li>
<li class=""><strong>PulseAudio架构</strong></li>
</ul>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">应用程序 → 音频流 → PulseAudio服务器 → Sink → 硬件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(播放器)          (混音器)        (输出设备)   (声卡)</span><br></div></code></pre></div></div>
<p><strong>状态说明</strong></p>
<ul>
<li class=""><strong>RUNNING</strong>：正在播放音频</li>
<li class=""><strong>IDLE</strong>：空闲，准备就绪</li>
<li class=""><strong>SUSPENDED</strong>：挂起，节能模式</li>
<li class=""><strong>UNLINKED</strong>：未连接</li>
</ul>
<p><strong>设备详情</strong></p>
<ul>
<li class=""><strong>sink 0</strong>：<code>alsa_output.0.HiFi__hw_rockchipes8388__sink</code>
<ul>
<li class="">对应ALSA声卡0（ES8388音频芯片）</li>
<li class="">高保真（HiFi）输出</li>
</ul>
</li>
<li class=""><strong>sink 1</strong>：<code>alsa_output.1.stereo-fallback</code>
<ul>
<li class="">备用/回退输出设备</li>
<li class="">当主设备不可用时使用</li>
</ul>
</li>
</ul>
<p><strong>两个音频sink都处于SUSPENDED状态</strong></p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">0 ... SUSPENDED</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1 ... SUSPENDED</span><br></div></code></pre></div></div>
<p><strong>SUSPENDED状态意味着</strong>：</p>
<ul>
<li class="">PulseAudio认为没有音频流需要播放</li>
<li class="">为了节能，自动挂起了音频输出</li>
<li class="">系统准备好接收音频，但当前没有活跃的音频流</li>
</ul>
<p><strong>根本原因链条</strong>：</p>
<ol>
<li class="">
<p><strong>系统启动时</strong> → PulseAudio加载音频设备</p>
</li>
<li class="">
<p><strong>没有活跃音频流</strong> → PulseAudio挂起设备（SUSPENDED）</p>
</li>
<li class="">
<p><strong>硬件路由未激活</strong> → OUT1/OUT2开关默认关闭</p>
</li>
<li class="">
<p><strong>开始播放音频时</strong>：</p>
<ul>
<li class="">PulseAudio唤醒设备</li>
<li class=""><strong>但</strong>硬件开关（OUT/OUT2）还是关闭状态</li>
<li class="">需要手动 <code>amixer -c 0 sset 'OUT1' on</code></li>
</ul>
<p>经过我测试，在打开</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 sset 'OUT2' on</span><br></div></code></pre></div></div>
<p>之后，扬声器音频就可以正常播放了，这里作为记录，列出我调试过程中使用到的一些有用的命令</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#1. 查看更详细的sink信息</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pactl list sinks</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Sink #0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Sink #1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">		...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 2. 查看当前音频流</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pactl list sink-inputs</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#3.alsa内容控制</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 scontents</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 get 'Speaker'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 get 'Master'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 get 'Headphone'</span><br></div></code></pre></div></div>
</li>
</ol>
<p>对于这个问题有多个解决方案，下面列出</p>
<p><strong>方案1：阻止自动挂起</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 编辑PulseAudio配置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">vi /etc/pulse/default.pa</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # 防止自动挂起</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    load-module module-suspend-on-idle timeout=0  # 0表示永不挂起</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    # 增加超时时间</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    load-module module-suspend-on-idle timeout=3600  # 1小时</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 重启PulseAudio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pulseaudio -k</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pulseaudio --start</span><br></div></code></pre></div></div>
<p><strong>方案2：启动时自动激活硬件</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 创建启动脚本 /etc/pulse/audio-init.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#!/bin/bash</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 等待PulseAudio启动</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 激活硬件输出</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 sset 'OUT2' on</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 sset 'Speaker' on</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置合适音量</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 sset 'Output 2' 90%</span><br></div></code></pre></div></div>
<p><strong>方案3：使用udev规则</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 创建 /etc/udev/rules.d/90-audio.rules</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ACTION=="add", SUBSYSTEM=="sound", KERNEL=="card0", \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    RUN+="/usr/bin/amixer -c 0 sset 'OUT2' on"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#重启后生效</span><br></div></code></pre></div></div>
<p><strong>方案4：最简单的临时测试</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 先激活设备再播放</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 sset 'Speaker' on</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 sset 'OUT2' on</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">amixer -c 0 sset 'Output 2' 90%</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#也可以永久保存设置（并未生效）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">alsactl store</span><br></div></code></pre></div></div>
<p><strong>总结：问题实际上是：</strong></p>
<ul>
<li class=""><strong>软件层</strong>：PulseAudio正常</li>
<li class=""><strong>驱动层</strong>：ALSA正常识别设备</li>
<li class=""><strong>硬件层</strong>：OUT2物理开关需要手动激活</li>
</ul>
<p><strong>tips：音频路由</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 假设有多个音频设备：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 0 - 内置扬声器</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 1 - USB耳机</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 2 - HDMI输出</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 将Chrome音频发送到耳机</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pactl move-sink-input $(pactl list short sink-inputs | grep chrome | awk '{print $1}') 1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 将音乐播放器发送到HDMI</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pactl move-sink-input $(pactl list short sink-inputs | grep spotify | awk '{print $1}') 2</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="音频录制">音频录制<a href="https://zephyr.100ask.org/blog/audio-record-noise-analysis#%E9%9F%B3%E9%A2%91%E5%BD%95%E5%88%B6" class="hash-link" aria-label="音频录制的直接链接" title="音频录制的直接链接" translate="no">​</a></h2>
<p>使用得硬件是百问网200w usb摄像头+音频mems一体化模块，如下图所示</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="设备信息获取">设备信息获取<a href="https://zephyr.100ask.org/blog/audio-record-noise-analysis#%E8%AE%BE%E5%A4%87%E4%BF%A1%E6%81%AF%E8%8E%B7%E5%8F%96" class="hash-link" aria-label="设备信息获取的直接链接" title="设备信息获取的直接链接" translate="no">​</a></h3>
<p>首先需要获得整个mems得信息，它是通过usb与rk3576通信得，有几个方法能看出它得信息</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">v4l2-sysfs-path</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Video device: video36</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            video: video37</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            sound card: hw:4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            pcm capture: hw:4,0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            mixer: hw:4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Video device: video37</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            sound card: hw:4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            pcm capture: hw:4,0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            mixer: hw:4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   .....</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">alsactl info</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ......</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    - card: 4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      id: Camera</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      name: USB 2.0 Camera</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      longname: lihappe8 Corp. USB 2.0 Camera at usb-xhci-hcd.8.auto-1.2.2, high speed</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      driver_name: USB-Audio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      mixer_name: USB Mixer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      components: USB038f:0541</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      controls_count: 4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      pcm:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        - stream: CAPTURE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          devices:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            - device: 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">              id: USB Audio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">              name: USB Audio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">              subdevices:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                - subdevice: 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  name: subdevice #0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    .....</span><br></div></code></pre></div></div>
<p>可以看出在alsa里这个设备得name是<strong>hw:4,0</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="音频录制测试">音频录制测试<a href="https://zephyr.100ask.org/blog/audio-record-noise-analysis#%E9%9F%B3%E9%A2%91%E5%BD%95%E5%88%B6%E6%B5%8B%E8%AF%95" class="hash-link" aria-label="音频录制测试的直接链接" title="音频录制测试的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#录制一段背景噪声</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">arecord -D hw:4,0 -f S16_LE -r 8000 -c 2 -d 10 noise</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Recording WAVE 'noise.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay noise.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Playing WAVE 'noise.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo</span><br></div></code></pre></div></div>
<p>可以听到明显得”吱吱“声，这个mems的底噪还是很大的，后续需要对其进行降噪，才可以进行正常的语音通讯。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="噪声分析">噪声分析<a href="https://zephyr.100ask.org/blog/audio-record-noise-analysis#%E5%99%AA%E5%A3%B0%E5%88%86%E6%9E%90" class="hash-link" aria-label="噪声分析的直接链接" title="噪声分析的直接链接" translate="no">​</a></h3>
<p>用sox生成频谱图</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">sox noise.wav -n spectrogram -o noise_spectrogram.pn</span><br></div></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#全局频谱</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sox noise.wav -n spectrogram -d 10 -x 1200 -z 80 -o noise_full.png</span><br></div></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">sox noise.wav -r 2000 -c 1 noise_2k.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sox noise_2k.wav -n spectrogram -d 10 -x 1200 -z 80 -o noise_low.png</span><br></div></code></pre></div></div>
<p><strong>整体观察背景噪声属于「近似白噪声 + 低频强峰 + 中频轻微纹理噪声」</strong></p>
<p><strong>1. 0～200Hz 附近有非常明显的低频能量团（尤其 &lt;100Hz）</strong></p>
<p>这一般意味着：</p>
<ul>
<li class=""><strong>机械/电源相关噪声</strong></li>
<li class=""><strong>风扇、震动、机箱共振</strong></li>
<li class=""><strong>电源纹波（50Hz / 60Hz + 基波）</strong></li>
<li class=""><strong>麦克风指向性/箱体耦合放大超低频噪声</strong></li>
</ul>
<p><strong>2. 1kHz～4kHz 范围是随机噪声（近似白噪声），能量较低</strong></p>
<p>说明麦克风底噪属于典型：</p>
<ul>
<li class="">MEMS 麦克风本底噪声</li>
<li class="">ADC 自噪声</li>
<li class="">放大器输入噪声</li>
</ul>
<p>这部分是<strong>系统底噪</strong>。</p>
<p><strong>3. 高频（&gt;6kHz）完全没有奇怪峰值</strong></p>
<p>这非常好 → 没有明显：</p>
<ul>
<li class="">数字 EMI</li>
<li class="">时钟泄漏</li>
<li class="">采样抖动噪声</li>
</ul>
<hr>
<p><strong>4. 没有明显「啸叫模式」出现</strong></p>
<p>三张图都没有看到典型啸叫特征：</p>
<ul>
<li class="">啸叫通常是固定频率一条亮线持续不变</li>
<li class="">图中只有<strong>起始瞬间的脉冲（可能是开始录音时的点击声）</strong></li>
</ul>
<p>没有稳定峰随时间持续。</p>
<p><strong>逐图分析</strong></p>
<hr>
<p><strong>(A) 第一张图：全频谱（到 4kHz）</strong></p>
<p>看起来特点是：</p>
<p>整体偏红/紫，噪声密度高但均匀
50Hz 左右有明显竖线
100Hz、150Hz 也有轻微能量</p>
<p>➜ 这几乎肯定是：</p>
<p><strong>工频噪声（50/60Hz）+ 谐波（100/150Hz）</strong></p>
<p><strong>原因：</strong></p>
<ul>
<li class="">USB 供电带来的大量 50/60Hz hum</li>
<li class="">声卡或麦克风的模拟前端隔离不好</li>
<li class="">地线不干净（如 USB 共地回路）</li>
</ul>
<hr>
<p><strong>(B) 第二张图：动态范围压窄的版本（-80dBFS）</strong></p>
<p>这一张另外暴露出：</p>
<p>在 1.8kHz ～ 2.2kHz 有一条非常窄的横线</p>
<p>非常淡，但稳定存在。</p>
<p>这表示：</p>
<p><strong>系统时钟/PLL 干扰泄漏</strong></p>
<p>常见于：</p>
<ul>
<li class="">I2S/MCLK 泄漏</li>
<li class="">PCB 上麦克风的时钟耦合</li>
<li class="">数字电源噪声叠加到麦克风模拟部分</li>
</ul>
<p>这部分不会导致啸叫，但会降低 SNR。</p>
<hr>
<p><strong>(C) 第三张图：低频到 1000Hz</strong></p>
<p>非常典型：</p>
<p>&lt;150Hz 区域噪声比其他频段高很多</p>
<p>像一个大“灯泡”形状，非常明显。</p>
<p>这说明：</p>
<p><strong>低频振动 + 电源噪声是主要底噪来源</strong></p>
<p>包括：</p>
<ul>
<li class="">机箱震动、风扇、台面共振</li>
<li class="">电源 50/60Hz + 谐波</li>
<li class="">麦克风本身的 LF roll-off 不够</li>
</ul>
<hr>
<p><strong>综合判断：背景噪声构成比例</strong></p>
<table><thead><tr><th>噪声类型</th><th>占比</th><th>特征</th></tr></thead><tbody><tr><td><strong>低频机械/电源噪声 (&lt;200Hz)</strong></td><td>50%</td><td>最大来源，来自电源、机箱、振动</td></tr><tr><td><strong>工频泄漏 50/60Hz + 谐波</strong></td><td>25%</td><td>图中最强的固定峰</td></tr><tr><td><strong>麦克风本底白噪声</strong></td><td>20%</td><td>散布在 1k~4kHz 随机噪声</td></tr><tr><td><strong>数字时钟泄漏（2kHz 附近）</strong></td><td>5%</td><td>很弱但可见的一条细线</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="psd噪声模型分析">PSD噪声模型分析<a href="https://zephyr.100ask.org/blog/audio-record-noise-analysis#psd%E5%99%AA%E5%A3%B0%E6%A8%A1%E5%9E%8B%E5%88%86%E6%9E%90" class="hash-link" aria-label="PSD噪声模型分析的直接链接" title="PSD噪声模型分析的直接链接" translate="no">​</a></h3>
<p>使用python生成PSD噪声模型</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> numpy </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> np</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> matplotlib</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">pyplot </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> plt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> scipy</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">io </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> wavfile</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> scipy</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">signal </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> welch</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> find_peaks</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> spectrogram</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> butter</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> sosfilt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> IPython</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">display </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> ipd</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> os</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> data </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> wavfile</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">read</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/mnt/data/noise.wav"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ndim</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    data </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">mean</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">axis</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">data </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">astype</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">float32</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">N </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">len</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">duration </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> N </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> rate</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Calculate overall RMS and dBFS</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Assuming 16-bit PCM if dtype was int16; determine scale</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># infer max possible value from original dtype by reloading header:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> struct</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Determine dtype max</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># but we'll normalize by max of int16 if dtype came as int16, else use max(abs(data))</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">max_possible </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">32768.0</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rms </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sqrt</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">mean</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token operator" style="color:#393A34">**</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">dbfs_rms </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">20</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">log10</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rms </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> max_possible</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> rms</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">inf</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Welch PSD</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Pxx </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> welch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fs</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">rate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nperseg</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">4096</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> scaling</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'density'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># find peaks in PSD (in linear)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">peaks</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> props </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> find_peaks</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">Pxx</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> height</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">Pxx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">*</span><span class="token number" style="color:#36acaa">0.15</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> distance</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">peak_freqs </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">peaks</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">peak_heights </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> props</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'peak_heights'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Find dominant low-frequency peak under 500Hz</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">low_idx </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">where</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">f</span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token number" style="color:#36acaa">500</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">low_f </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">low_idx</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">low_P </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> Pxx</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">low_idx</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">lp_peaks</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lp_props </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> find_peaks</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">low_P</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> height</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">low_P</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">*</span><span class="token number" style="color:#36acaa">0.2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">lp_freqs </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> low_f</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">lp_peaks</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">lp_heights </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> lp_props</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'peak_heights'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Short-time energy to find transient (e.g., first second pulse)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">frame_ms </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">20</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">frame_len </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rate </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> frame_ms</span><span class="token operator" style="color:#393A34">/</span><span class="token number" style="color:#36acaa">1000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">hop </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> frame_len</span><span class="token operator" style="color:#393A34">//</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">frames </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> start </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> N</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">frame_len</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> hop</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    frames</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">sum</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">start</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">start</span><span class="token operator" style="color:#393A34">+</span><span class="token plain">frame_len</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">**</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">frames </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frames</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">frame_times </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">arange</span><span class="token punctuation" style="color:#393A34">(</span><span class="token builtin">len</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frames</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">hop</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">rate</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># detect where energy spikes relative to median</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">median_e </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">median</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frames</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">spikes </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">where</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frames </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> median_e</span><span class="token operator" style="color:#393A34">*</span><span class="token number" style="color:#36acaa">8</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 8x median</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">spike_times </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> frame_times</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">spikes</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Spectrogram</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">f_s</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> t_s</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Sxx </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> spectrogram</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fs</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">rate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nperseg</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2048</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> noverlap</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1024</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> scaling</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'density'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mode</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'magnitude'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Plot PSD with peaks marked</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">figure</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">figsize</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">semilogy</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Pxx</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> color</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'tab:orange'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">scatter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">peak_freqs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> peak_heights</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> color</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'k'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> zorder</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> pf</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ph </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">zip</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">peak_freqs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> peak_heights</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">text</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">pf</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ph</span><span class="token operator" style="color:#393A34">*</span><span class="token number" style="color:#36acaa">1.1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">pf</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">:</span><span class="token string-interpolation interpolation format-spec">.0f</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> Hz"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> fontsize</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">8</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ha</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'center'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">xlim</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> rate</span><span class="token operator" style="color:#393A34">/</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">xlabel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Frequency (Hz)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ylabel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"PSD"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">title</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Welch PSD with detected peaks"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">grid</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">alpha</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tight_layout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">savefig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/mnt/data/psd_peaks.png"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Plot spectrogram (dB)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Sxx_db </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">20</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">log10</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">Sxx </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1e-12</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">figure</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">figsize</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">pcolormesh</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">t_s</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> f_s</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Sxx_db</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> shading</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'gouraud'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">colorbar</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">label</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">'dB'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ylim</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">xlabel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Time (s)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ylabel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Frequency (Hz)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">title</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Spectrogram (dB)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tight_layout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">savefig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/mnt/data/spectrogram_db.png"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Prepare summary</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">summary </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"sampling_rate"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> rate</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"duration_s"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> duration</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"rms"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rms</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"dbfs_rms"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">dbfs_rms</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"dominant_peaks_hz"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> p </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> peak_freqs</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token number" style="color:#36acaa">8</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"dominant_peaks_vals"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> p </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> peak_heights</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token number" style="color:#36acaa">8</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"low_freq_peaks_hz"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> p </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> lp_freqs</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"low_freq_peaks_vals"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">p</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> p </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> lp_heights</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"spike_times_s"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">float</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">s</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> s </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> spike_times</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"spectrogram_image"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/mnt/data/spectrogram_db.png"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"psd_image"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/mnt/data/psd_peaks.png"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> json</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">with</span><span class="token plain"> </span><span class="token builtin">open</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/mnt/data/noise_analysis_summary.json"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"w"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    json</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">dump</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">summary</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> indent</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Display small tables and figures</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> caas_jupyter_tools </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> display_dataframe_to_user</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> pandas </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> pd</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">df_peaks </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> pd</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">DataFrame</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"freq_hz"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> peak_freqs</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"psd_val"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> peak_heights</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">display_dataframe_to_user</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Detected PSD Peaks"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> df_peaks</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">head</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">20</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">figure</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">figsize</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">plot</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frame_times</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">log10</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frames</span><span class="token operator" style="color:#393A34">+</span><span class="token number" style="color:#36acaa">1e-12</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">xlabel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Time (s)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ylabel</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Frame energy (dB)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">title</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Short-time frame energy (20ms frames)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">grid</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">alpha</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tight_layout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">savefig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/mnt/data/frame_energy.png"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">plt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">show</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Show audio player</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ipd</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">display</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ipd</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Audio</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/mnt/data/noise.wav"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">summary</span><br></div></code></pre></div></div>
<p><strong>得出关键量化结果：</strong></p>
<ul>
<li class="">采样率：<strong>8000 Hz</strong></li>
<li class="">时长：<strong>10.0 s</strong></li>
<li class="">全段 RMS = <strong>223.11 (样点)</strong>，换算为 <strong>-43.34 dBFS</strong>（以 16-bit 满量程 32768 作归一）： <strong>说明底噪中等偏高</strong>。</li>
<li class="">检测到的<strong>显著频率峰</strong>（Welch PSD peak，按强度顺序，列出前几项）：<!-- -->
<ul>
<li class="">约 <strong>74.2 Hz</strong>, <strong>85.94 Hz</strong>, <strong>103.52 Hz</strong>, <strong>113.28 Hz</strong>, <strong>146.48 Hz</strong>, <strong>167.97 Hz</strong>, 以及较小的 396 Hz 等。</li>
</ul>
</li>
<li class="">低频段（≤500 Hz）主要峰：<strong>85.94, 95.70, 103.52, 113.28, 146.48 Hz</strong> —— 多个近频段峰，像是工频/开关电源谐波或机械谐振的集合。</li>
<li class="">瞬态能量峰（短时能量帧，20 ms）检测到在：<strong>约 0.36–0.38 s</strong> 有几个短脉冲（可能是启动点击/人为触碰/瞬态事件）。</li>
</ul>
<p>结论：<strong>噪声由明显的低频“hum/纹波/振动”组成 + 宽带白噪声</strong>（中高频），低频是主要能量所在。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="降噪方案">降噪方案<a href="https://zephyr.100ask.org/blog/audio-record-noise-analysis#%E9%99%8D%E5%99%AA%E6%96%B9%E6%A1%88" class="hash-link" aria-label="降噪方案的直接链接" title="降噪方案的直接链接" translate="no">​</a></h3>
<p><strong>1.在音频链路上加 2 阶高通 (fc = 80 Hz)</strong></p>
<ul>
<li class="">直接把大部分机械/供电低频去掉，不损伤语音带宽（语音主要 &gt;100Hz）。</li>
<li class="">实现：用 DSP 库里的 butter/sos 或自行实现biquad（Direct Form I 或 II）。</li>
</ul>
<p><strong>2 针对性陷波（notch）</strong></p>
<ul>
<li class="">若 HPF 后仍留有几个极窄强峰（如 103Hz），加一两个 Q=20~40 的陷波。Q 越高带宽越窄，越不伤及邻近频段，但系数更接近 1。</li>
<li class="">考虑实时性需要串联 <code>hp -&gt; notch(强峰1) -&gt; notch(强峰2)</code>。</li>
</ul>
<p><strong>3 本质还是硬件</strong></p>
<ul>
<li class="">更换或改善模拟供电（低噪 LDO、更多旁路电容、星形接地）或使用SNR更好的数字 MEMS 麦克风。</li>
<li class="">在嵌入式板子上，尽量远离开关电源走线与麦克风差分/模拟线。</li>
</ul>
<p><strong>对实时音质的考虑</strong></p>
<ul>
<li class="">如果需要非常低延迟（例如回声取消 / 实时 loopback），得使用 IIR（biquad）单向实时实现（延迟极低），但注意相位会改变，若不允许相位改变（比如做更精确的定位），用 FIR + zero-phase 会有延迟代价。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="参考滤波系数">参考滤波系数<a href="https://zephyr.100ask.org/blog/audio-record-noise-analysis#%E5%8F%82%E8%80%83%E6%BB%A4%E6%B3%A2%E7%B3%BB%E6%95%B0" class="hash-link" aria-label="参考滤波系数的直接链接" title="参考滤波系数的直接链接" translate="no">​</a></h3>
<blockquote>
<p>说明：下面给出的系数是标准二阶节（biquad）格式，按 <code>[b0, b1, b2, a0, a1, a2]</code>（a0 已正规化为 1 或者给出时需要归一化）排列。实现时通常把 a0 规一化为 1，然后按 Direct Form I/II 实现。</p>
</blockquote>
<p><strong>高通：2nd-order Butterworth（fc = 80 Hz, fs = 8000 Hz）</strong></p>
<p><code>sos_hp</code> 第一节系数（已归一化 a0=1）：</p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">b0 = 0.9565432255568767</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b1 = -1.9130864511137533</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b2 = 0.9565432255568767</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a0 = 1.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a1 = -1.911197067426073</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a2 = 0.9149758348014336</span><br></div></code></pre></div></div>
<p><strong>若干陷波（notch, Q=30）</strong></p>
<blockquote>
<p>（示例三条，取自检测到的峰位）格式同上（b0,b1,b2,a0,a1,a2），a0 已正规化为 1 在下面输出中：</p>
</blockquote>
<ul>
<li class="">notch @ <strong>103.515625 Hz</strong></li>
</ul>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">b0 = 0.998648305437691</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b1 = -1.99069933085876</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b2 = 0.998648305437691</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a0 = 1.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a1 = -1.99069933085876</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a2 = 0.9972966108753819</span><br></div></code></pre></div></div>
<ul>
<li class="">notch @ <strong>146.484375 Hz</strong></li>
</ul>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">b0 = 0.9980904047539934</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b1 = -1.9829844796660758</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b2 = 0.9980904047539934</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a0 = 1.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a1 = -1.9829844796660758</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a2 = 0.9961808095079867</span><br></div></code></pre></div></div>
<ul>
<li class="">notch @ <strong>74.21875 Hz</strong></li>
</ul>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">b0 = 0.9990299707952924</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b1 = -1.9946663265604048</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">b2 = 0.9990299707952924</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a0 = 1.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a1 = -1.9946663265604048</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">a2 = 0.9980599415905849</span><br></div></code></pre></div></div>
<p>这些噪声分析是作传统<strong>频减法</strong>音频滤波必要的素材，采用标准的rnnoise AI降噪则不需要，但如果自己改进rnnoise，做模型微调则需要参考，以获得更好的降噪效果。</p>]]></content:encoded>
            <category>音频</category>
            <category>录制</category>
            <category>噪声分析</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 测评五：NPU 实战 YOLOv5 实时目标检测加速]]></title>
            <link>https://zephyr.100ask.org/blog/npu-yolov5-detection</link>
            <guid>https://zephyr.100ask.org/blog/npu-yolov5-detection</guid>
            <pubDate>Fri, 28 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[使用板载 NPU 加速 YOLOv5 深度学习推理，榨干 RK3576 硬件潜力实现实时目标检测。]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="前言">前言<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#%E5%89%8D%E8%A8%80" class="hash-link" aria-label="前言的直接链接" title="前言的直接链接" translate="no">​</a></h2>
<p>在前面的文章中,我们已经实现了基于CPU的MediaPipe手势识别,虽然能跑起来,但15-25 FPS的性能还是有点吃力,而且CPU占用率很高。这次我要榨干RK3576的硬件潜力——使用板载的NPU(神经网络处理单元)来加速深度学习推理。首先外我们需要要来了解一下一些概念</p>
<p><strong>什么是NPU?</strong>
NPU(Neural Processing Unit)是专门为AI运算设计的硬件加速器。和CPU/GPU不同,NPU针对神经网络的矩阵运算、卷积等操作做了深度优化。RK3576芯片内置了双核NPU,理论算力达到6 TOPS,能大幅提升模型推理速度并降低功耗。</p>
<p><strong>为什么选YOLOv5?</strong>
其实我本来是打算继续优化我前面的MediaPipe的TFLite模型转换遇到了依赖地狱(这个坑我踩了好久...),所以这次先用官方提供的YOLOv5模型来验证NPU功能。YOLOv5是目前最流行的实时目标检测算法之一,能同时检测图像中的多个物体及其位置。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="一环境准备">一、环境准备<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#%E4%B8%80%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87" class="hash-link" aria-label="一、环境准备的直接链接" title="一、环境准备的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="11-硬件连接">1.1 硬件连接<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#11-%E7%A1%AC%E4%BB%B6%E8%BF%9E%E6%8E%A5" class="hash-link" aria-label="1.1 硬件连接的直接链接" title="1.1 硬件连接的直接链接" translate="no">​</a></h3>
<ul>
<li class="">RK3576开发板(已刷Buildroot系统)</li>
<li class="">IMX415摄像头(接在/dev/video11)</li>
<li class="">HDMI显示器</li>
<li class="">串口连接(用于命令行操作)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="12-检查npu硬件">1.2 检查NPU硬件<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#12-%E6%A3%80%E6%9F%A5npu%E7%A1%AC%E4%BB%B6" class="hash-link" aria-label="1.2 检查NPU硬件的直接链接" title="1.2 检查NPU硬件的直接链接" translate="no">​</a></h3>
<p>首先登录板子,检查NPU是否正常工作:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 查看NPU负载(应该显示Core0和Core1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cat /sys/kernel/debug/rknpu/load</span><br></div></code></pre></div></div>
<p>这说明NPU双核都是空闲状态,可以开始干活了!</p>
<p><strong>小知识:</strong> RK3576的NPU采用双核架构,可以并行处理两个模型,或者让一个大模型的不同层在两个核心上流水线执行。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="13-检查python环境">1.3 检查Python环境<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#13-%E6%A3%80%E6%9F%A5python%E7%8E%AF%E5%A2%83" class="hash-link" aria-label="1.3 检查Python环境的直接链接" title="1.3 检查Python环境的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 查看Python版本</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python3 --version</span><br></div></code></pre></div></div>
<p>我的输出是 <code>Python 3.11.8</code>,这个版本很重要,后面安装库的时候要匹配。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="二安装rknn运行时环境">二、安装RKNN运行时环境<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#%E4%BA%8C%E5%AE%89%E8%A3%85rknn%E8%BF%90%E8%A1%8C%E6%97%B6%E7%8E%AF%E5%A2%83" class="hash-link" aria-label="二、安装RKNN运行时环境的直接链接" title="二、安装RKNN运行时环境的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="21-什么是rknn">2.1 什么是RKNN?<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#21-%E4%BB%80%E4%B9%88%E6%98%AFrknn" class="hash-link" aria-label="2.1 什么是RKNN?的直接链接" title="2.1 什么是RKNN?的直接链接" translate="no">​</a></h3>
<p>RKNN(Rockchip Neural Network)是瑞芯微为自家NPU开发的深度学习推理框架。整个工具链分两部分:</p>
<ul>
<li class=""><strong>rknn-toolkit2</strong>(PC端): 用于模型转换,把TensorFlow/PyTorch/ONNX模型转成.rknn格式</li>
<li class=""><strong>rknn-toolkit-lite2</strong>(板端): 轻量级运行时库,用于在RK芯片上加载和推理.rknn模型</li>
</ul>
<p>我们这次只用板端推理,所以只装lite版。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="22-安装安装包">2.2 安装安装包<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#22-%E5%AE%89%E8%A3%85%E5%AE%89%E8%A3%85%E5%8C%85" class="hash-link" aria-label="2.2 安装安装包的直接链接" title="2.2 安装安装包的直接链接" translate="no">​</a></h3>
<p>好消息是我们如果不想在github上下载觉得慢或者不稳定，我们可以选择我们百问网提供的下载连接:
<a href="https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/utils/rknn-toolkit2.zip" target="_blank" rel="noopener noreferrer" class="">https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/utils/rknn-toolkit2.zip</a>
下载完成传到我们的Dshanpi-A1上。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd /rknn-toolkit2/rknn-toolkit-lite2/packages/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ls -lh</span><br></div></code></pre></div></div>
<p>可以看到有多个Python版本的.whl安装包,我们需要的是cp311(Python 3.11)的ARM64版本。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="23-安装rknn-toolkit-lite2">2.3 安装rknn-toolkit-lite2<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#23-%E5%AE%89%E8%A3%85rknn-toolkit-lite2" class="hash-link" aria-label="2.3 安装rknn-toolkit-lite2的直接链接" title="2.3 安装rknn-toolkit-lite2的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 先强制安装主包(不检查依赖,因为依赖后面单独装)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pip3 install --no-deps rknn_toolkit_lite2-2.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 再用清华镜像安装缺失的依赖</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple psutil ruamel.yaml</span><br></div></code></pre></div></div>
<p>这样做就不用耗费我们下载一些没必要的包了。</p>
<p>看到 <code>Successfully installed</code> 就成功了!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="24-验证安装">2.4 验证安装<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#24-%E9%AA%8C%E8%AF%81%E5%AE%89%E8%A3%85" class="hash-link" aria-label="2.4 验证安装的直接链接" title="2.4 验证安装的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">python3 -c "from rknnlite.api import RKNNLite; print('✅ rknn-toolkit-lite2 安装成功!')"</span><br></div></code></pre></div></div>
<p>输出勾勾标志就OK!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="三npu基准测试">三、NPU基准测试<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#%E4%B8%89npu%E5%9F%BA%E5%87%86%E6%B5%8B%E8%AF%95" class="hash-link" aria-label="三、NPU基准测试的直接链接" title="三、NPU基准测试的直接链接" translate="no">​</a></h2>
<p>在跑实时检测之前,先用一个简单的图像分类模型测试一下NPU的性能。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="31-使用resnet18测试">3.1 使用ResNet18测试<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#31-%E4%BD%BF%E7%94%A8resnet18%E6%B5%8B%E8%AF%95" class="hash-link" aria-label="3.1 使用ResNet18测试的直接链接" title="3.1 使用ResNet18测试的直接链接" translate="no">​</a></h3>
<p>进入示例目录:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd /rknn-toolkit2/rknn-toolkit-lite2/examples/resnet18</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ls -lh</span><br></div></code></pre></div></div>
<p>可以看到有:</p>
<ul>
<li class=""><code>resnet18_for_rk3576.rknn</code> - 专门为RK3576优化的模型</li>
<li class=""><code>space_shuttle_224.jpg</code> - 测试图片</li>
<li class=""><code>test.py</code> - 推理脚本</li>
</ul>
<p>运行测试:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">python3 test.py</span><br></div></code></pre></div></div>
<p>我的结果:</p>
<ul>
<li class="">识别结果: Space Shuttle(航天飞机) - 99.96%置信度</li>
<li class="">推理延迟: 11.21 ms</li>
<li class="">平均FPS: 89.24</li>
</ul>
<p>这意味着NPU可以每秒处理89张图片,比我之前CPU跑MediaPipe快3-6倍!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="32-性能基准测试">3.2 性能基准测试<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#32-%E6%80%A7%E8%83%BD%E5%9F%BA%E5%87%86%E6%B5%8B%E8%AF%95" class="hash-link" aria-label="3.2 性能基准测试的直接链接" title="3.2 性能基准测试的直接链接" translate="no">​</a></h3>
<p>为了更准确地测试NPU性能,我写了个循环100次的脚本（可以自行测试）:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd ~</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p npu_test</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd npu_test</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 复制模型和图片</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cp /rknn-toolkit2/rknn-toolkit-lite2/examples/resnet18/resnet18_for_rk3576.rknn ./</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cp /rknn-toolkit2/rknn-toolkit-lite2/examples/resnet18/space_shuttle_224.jpg ./</span><br></div></code></pre></div></div>
<p>创建测试脚本 <code>benchmark.py</code>:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> cv2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> numpy </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> np</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> time</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> rknnlite</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">api </span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> RKNNLite</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rknn </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> RKNNLite</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rknn</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">load_rknn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'resnet18_for_rk3576.rknn'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rknn</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">init_runtime</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">core_mask</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">RKNNLite</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">NPU_CORE_0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">img </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">imread</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'space_shuttle_224.jpg'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">img </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cvtColor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">img</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">COLOR_BGR2RGB</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">img </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">expand_dims</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">img</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 预热</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> _ </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    rknn</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">inference</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">inputs</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">img</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 测试100次</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">times </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> i </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    start </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">time</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    rknn</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">inference</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">inputs</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">img</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    times</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">time</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> start</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f'平均延迟: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">np</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">.</span><span class="token string-interpolation interpolation">mean</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">(</span><span class="token string-interpolation interpolation">times</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">)</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">:</span><span class="token string-interpolation interpolation format-spec">.2f</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> ms'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f'最小延迟: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">np</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">.</span><span class="token string-interpolation interpolation builtin">min</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">(</span><span class="token string-interpolation interpolation">times</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">)</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">:</span><span class="token string-interpolation interpolation format-spec">.2f</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> ms'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f'最大延迟: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">np</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">.</span><span class="token string-interpolation interpolation builtin">max</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">(</span><span class="token string-interpolation interpolation">times</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">)</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">:</span><span class="token string-interpolation interpolation format-spec">.2f</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> ms'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f'平均FPS: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation number" style="color:#36acaa">1000</span><span class="token string-interpolation interpolation operator" style="color:#393A34">/</span><span class="token string-interpolation interpolation">np</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">.</span><span class="token string-interpolation interpolation">mean</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">(</span><span class="token string-interpolation interpolation">times</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">)</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">:</span><span class="token string-interpolation interpolation format-spec">.2f</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rknn</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">release</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>运行:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">python3 benchmark.py</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="四yolov5目标检测">四、YOLOv5目标检测<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#%E5%9B%9Byolov5%E7%9B%AE%E6%A0%87%E6%A3%80%E6%B5%8B" class="hash-link" aria-label="四、YOLOv5目标检测的直接链接" title="四、YOLOv5目标检测的直接链接" translate="no">​</a></h2>
<p>现在进入正题——用NPU跑实时目标检测!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="41-什么是yolov5">4.1 什么是YOLOv5?<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#41-%E4%BB%80%E4%B9%88%E6%98%AFyolov5" class="hash-link" aria-label="4.1 什么是YOLOv5?的直接链接" title="4.1 什么是YOLOv5?的直接链接" translate="no">​</a></h3>
<p>YOLO(You Only Look Once)是一种单阶段目标检测算法,能在一次前向传播中同时预测多个物体的位置和类别。相比两阶段的R-CNN系列,YOLO速度更快,非常适合实时场景。</p>
<p>YOLOv5是该系列的第五代,支持检测80种常见物体(人、车、动物、家具等)。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="42-准备模型和测试图片">4.2 准备模型和测试图片<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#42-%E5%87%86%E5%A4%87%E6%A8%A1%E5%9E%8B%E5%92%8C%E6%B5%8B%E8%AF%95%E5%9B%BE%E7%89%87" class="hash-link" aria-label="4.2 准备模型和测试图片的直接链接" title="4.2 准备模型和测试图片的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd ~</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkdir -p npu_yolo_test</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd npu_yolo_test</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 复制RK3576专用的YOLOv5模型</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cp /rknn-toolkit2/rknpu2/examples/rknn_yolov5_demo/model/RK3576/yolov5s-640-640.rknn ./</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 复制测试图片(一张公交车照片)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cp /rknn-toolkit2/rknpu2/examples/rknn_yolov5_demo/model/bus.jpg ./</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ls -lh</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="43-单张图片检测测试">4.3 单张图片检测测试<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#43-%E5%8D%95%E5%BC%A0%E5%9B%BE%E7%89%87%E6%A3%80%E6%B5%8B%E6%B5%8B%E8%AF%95" class="hash-link" aria-label="4.3 单张图片检测测试的直接链接" title="4.3 单张图片检测测试的直接链接" translate="no">​</a></h3>
<p>这里完整的后处理代码比较长(包含NMS非极大值抑制等算法),我把它整理成了一个脚本。</p>
<p>创建 <code>yolo_npu_test.py</code>(完整代码见附录A),然后运行:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">python3 yolo_npu_test.py</span><br></div></code></pre></div></div>
<p>我的结果:</p>
<ul>
<li class="">检测到5个目标:<!-- -->
<ul>
<li class="">3个人(person): 88.0%, 87.1%, 82.8%</li>
<li class="">1辆公交车(bus): 70.1%</li>
<li class="">1个部分遮挡的人: 30.7%</li>
</ul>
</li>
<li class="">NPU推理延迟: 87.94 ms</li>
<li class="">FPS: 11.37</li>
</ul>
<p>检测结果保存在 <code>result_npu.jpg</code>,可以传到PC上查看:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 在PC的PowerShell中执行(替换&lt;板子IP&gt;为实际IP)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scp root@&lt;板子IP&gt;:/npu_yolo_test/result_npu.jpg .</span><br></div></code></pre></div></div>
<p><strong>【检测结果图片】</strong></p>
<p><strong>为什么YOLOv5比ResNet18慢?</strong></p>
<ul>
<li class="">ResNet18只做分类,输出1000个类别的概率(简单)</li>
<li class="">YOLOv5要检测多个物体的位置+类别,输出3个不同尺度的特征图(复杂)</li>
<li class="">但11 FPS对于目标检测来说已经很不错了!</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="五实时摄像头检测">五、实时摄像头检测<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#%E4%BA%94%E5%AE%9E%E6%97%B6%E6%91%84%E5%83%8F%E5%A4%B4%E6%A3%80%E6%B5%8B" class="hash-link" aria-label="五、实时摄像头检测的直接链接" title="五、实时摄像头检测的直接链接" translate="no">​</a></h2>
<p>单张图片测试成功了,现在来个真正的实战——用IMX415摄像头做实时检测并显示在屏幕上!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="51-显示方案--gstreamer">5.1 显示方案<!-- -->:FIFO<!-- --> + GStreamer<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#51-%E6%98%BE%E7%A4%BA%E6%96%B9%E6%A1%88--gstreamer" class="hash-link" aria-label="51-显示方案--gstreamer的直接链接" title="51-显示方案--gstreamer的直接链接" translate="no">​</a></h3>
<p>还是和之前的一样由于Buildroot没有图形界面,OpenCV的<code>imshow()</code>不能用,我们采用<strong>命名管道(FIFO) + GStreamer</strong>的方案:</p>
<ol>
<li class="">Python读摄像头 → NPU推理 → 画框 → 编码成JPEG</li>
<li class="">写入FIFO管道</li>
<li class="">GStreamer从管道读取 → 解码 → 显示到屏幕</li>
</ol>
<p>这是Linux下常用的进程间通信方式,之前手势识别项目也用的这个。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="52-创建一键启动脚本">5.2 创建一键启动脚本<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#52-%E5%88%9B%E5%BB%BA%E4%B8%80%E9%94%AE%E5%90%AF%E5%8A%A8%E8%84%9A%E6%9C%AC" class="hash-link" aria-label="5.2 创建一键启动脚本的直接链接" title="5.2 创建一键启动脚本的直接链接" translate="no">​</a></h3>
<p>为了方便使用,我把整个流程打包成了一个Shell脚本 <code>yolo_npu_display.sh</code>:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd /npu_yolo_test</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cat &gt; yolo_npu_display.sh &lt;&lt; 'EOF'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#!/bin/bash</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "=========================================="</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "YOLOv5 NPU Real-time Detection - RK3576"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "=========================================="</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo ""</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 重启3A服务器(摄像头自动曝光/白平衡/自动对焦)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Restarting 3A server..."</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">killall rkaiq_3A_server 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rm -f /tmp/.rkaiq_3A* 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/etc/init.d/S40rkaiq_3A start &gt;/dev/null 2&gt;&amp;1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 创建FIFO管道</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">FIFO_PATH="/tmp/yolo_fifo"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rm -f $FIFO_PATH</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mkfifo $FIFO_PATH</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Starting display pipeline..."</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 -q filesrc location=$FIFO_PATH ! jpegparse ! jpegdec ! videoconvert ! videoscale ! video/x-raw,width=1280,height=720 ! waylandsink fullscreen=true sync=false &amp;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">GST_PID=$!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Starting YOLOv5 NPU detection..."</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python3 - &lt;&lt;'PYTHON_CODE' &amp;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">import cv2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">import numpy as np</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">import time</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">from rknnlite.api import RKNNLite</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">from collections import deque</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">RKNN_MODEL = '/npu_yolo_test/yolov5s-640-640.rknn'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">CAMERA_ID = 11</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">IMG_SIZE = 640</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">OBJ_THRESH = 0.25</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">NMS_THRESH = 0.45</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">FIFO_PATH = '/tmp/yolo_fifo'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">CLASSES = ("person", "bicycle", "car", "motorbike", "aeroplane", "bus", "train", "truck", "boat", "traffic light",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow", </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple", </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "sofa",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "pottedplant", "bed", "diningtable", "toilet", "tvmonitor", "laptop", "mouse", "remote", "keyboard", </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           "scissors", "teddy bear", "hair drier", "toothbrush")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">def xywh2xyxy(x):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    y = np.copy(x)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    y[:, 0] = x[:, 0] - x[:, 2] / 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    y[:, 1] = x[:, 1] - x[:, 3] / 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    y[:, 2] = x[:, 0] + x[:, 2] / 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    y[:, 3] = x[:, 1] + x[:, 3] / 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    return y</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">def process(input, mask, anchors):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    anchors = [anchors[i] for i in mask]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    grid_h, grid_w = map(int, input.shape[0:2])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_confidence = np.expand_dims(input[..., 4], axis=-1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_class_probs = input[..., 5:]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_xy = input[..., :2]*2 - 0.5</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    col = np.tile(np.arange(0, grid_w), grid_w).reshape(-1, grid_w)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    row = np.tile(np.arange(0, grid_h).reshape(-1, 1), grid_h)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    col = col.reshape(grid_h, grid_w, 1, 1).repeat(3, axis=-2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    row = row.reshape(grid_h, grid_w, 1, 1).repeat(3, axis=-2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    grid = np.concatenate((col, row), axis=-1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_xy += grid</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_xy *= int(IMG_SIZE/grid_h)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_wh = pow(input[..., 2:4]*2, 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_wh = box_wh * anchors</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box = np.concatenate((box_xy, box_wh), axis=-1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    return box, box_confidence, box_class_probs</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">def filter_boxes(boxes, box_confidences, box_class_probs):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    boxes = boxes.reshape(-1, 4)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_confidences = box_confidences.reshape(-1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_class_probs = box_class_probs.reshape(-1, box_class_probs.shape[-1])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    _box_pos = np.where(box_confidences &gt;= OBJ_THRESH)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    boxes = boxes[_box_pos]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_confidences = box_confidences[_box_pos]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    box_class_probs = box_class_probs[_box_pos]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    class_max_score = np.max(box_class_probs, axis=-1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    classes = np.argmax(box_class_probs, axis=-1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    _class_pos = np.where(class_max_score &gt;= OBJ_THRESH)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    boxes = boxes[_class_pos]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    classes = classes[_class_pos]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    scores = (class_max_score * box_confidences)[_class_pos]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    return boxes, classes, scores</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">def nms_boxes(boxes, scores):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    x, y = boxes[:, 0], boxes[:, 1]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    w, h = boxes[:, 2] - boxes[:, 0], boxes[:, 3] - boxes[:, 1]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    areas = w * h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    order = scores.argsort()[::-1]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    keep = []</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    while order.size &gt; 0:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        i = order[0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        keep.append(i)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        xx1 = np.maximum(x[i], x[order[1:]])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        yy1 = np.maximum(y[i], y[order[1:]])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        xx2 = np.minimum(x[i] + w[i], x[order[1:]] + w[order[1:]])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        yy2 = np.minimum(y[i] + h[i], y[order[1:]] + h[order[1:]])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        w1 = np.maximum(0.0, xx2 - xx1 + 0.00001)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        h1 = np.maximum(0.0, yy2 - yy1 + 0.00001)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        inter = w1 * h1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ovr = inter / (areas[i] + areas[order[1:]] - inter)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        inds = np.where(ovr &lt;= NMS_THRESH)[0]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        order = order[inds + 1]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    return np.array(keep)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">def yolov5_post_process(input_data):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    masks = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    anchors = [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45],</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               [59, 119], [116, 90], [156, 198], [373, 326]]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    boxes, classes, scores = [], [], []</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    for input, mask in zip(input_data, masks):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        b, c, s = process(input, mask, anchors)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        b, c, s = filter_boxes(b, c, s)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        boxes.append(b)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        classes.append(c)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        scores.append(s)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    if len(boxes) == 0:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        return None, None, None</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    boxes = np.concatenate(boxes)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    boxes = xywh2xyxy(boxes)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    classes = np.concatenate(classes)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    scores = np.concatenate(scores)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    nboxes, nclasses, nscores = [], [], []</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    for c in set(classes):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        inds = np.where(classes == c)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        b, c, s = boxes[inds], classes[inds], scores[inds]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        keep = nms_boxes(b, s)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        nboxes.append(b[keep])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        nclasses.append(c[keep])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        nscores.append(s[keep])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    if not nclasses:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        return None, None, None</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    return np.concatenate(nboxes), np.concatenate(nclasses), np.concatenate(nscores)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">class YOLODetector:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    def __init__(self):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self.fps_queue = deque(maxlen=30)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self.last_time = time.time()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self.fps = 0.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    def calc_fps(self):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        t = time.time()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        if t - self.last_time &gt; 0:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            self.fps_queue.append(1.0 / (t - self.last_time))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            self.fps = sum(self.fps_queue) / len(self.fps_queue)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self.last_time = t</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    def draw_detections(self, frame, boxes, scores, classes, scale_x, scale_y):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        for box, score, cl in zip(boxes, scores, classes):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            x1 = int(box[0] * scale_x)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            y1 = int(box[1] * scale_y)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            x2 = int(box[2] * scale_x)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            y2 = int(box[3] * scale_y)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            label = f'{CLASSES[cl]} {score:.2f}'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            cv2.putText(frame, label, (x1, y1 - 10),</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                       cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    def run(self):</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        print("Initializing NPU...")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        rknn_lite = RKNNLite()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        rknn_lite.load_rknn(RKNN_MODEL)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        rknn_lite.init_runtime(core_mask=RKNNLite.NPU_CORE_0)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        print("NPU ready!")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        print(f"Opening camera /dev/video{CAMERA_ID}...")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cap = cv2.VideoCapture(CAMERA_ID, cv2.CAP_V4L2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cap.set(cv2.CAP_PROP_FPS, 30)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        print(f"Camera: {width}x{height}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        print("Detection running...\n")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        fifo = open(FIFO_PATH, 'wb')</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        frame_count = 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        scale_x = width / IMG_SIZE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        scale_y = height / IMG_SIZE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        try:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            while True:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                ret, frame = cap.read()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                if not ret:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    time.sleep(0.1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    continue</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                img_resized = cv2.resize(frame_rgb, (IMG_SIZE, IMG_SIZE))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                img_input = np.expand_dims(img_resized, 0)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                inf_start = time.time()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                outputs = rknn_lite.inference(inputs=[img_input])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                inf_time = (time.time() - inf_start) * 1000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                input0 = outputs[0].reshape([3, -1] + list(outputs[0].shape[-2:]))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                input1 = outputs[1].reshape([3, -1] + list(outputs[1].shape[-2:]))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                input2 = outputs[2].reshape([3, -1] + list(outputs[2].shape[-2:]))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                input_data = [</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    np.transpose(input0, (2, 3, 0, 1)),</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    np.transpose(input1, (2, 3, 0, 1)),</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    np.transpose(input2, (2, 3, 0, 1))</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                ]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                boxes, classes, scores = yolov5_post_process(input_data)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                if boxes is not None:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    self.draw_detections(frame, boxes, scores, classes, scale_x, scale_y)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    obj_count = len(boxes)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                else:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    obj_count = 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                self.calc_fps()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                cv2.rectangle(frame, (5, 5), (400, 120), (0, 100, 0), -1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                cv2.putText(frame, f'FPS: {self.fps:.1f}', (15, 35),</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                           cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                cv2.putText(frame, f'NPU: {inf_time:.1f}ms', (15, 70),</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                           cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                cv2.putText(frame, f'Objects: {obj_count}', (15, 105),</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                           cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 0), 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                _, jpeg = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 85])</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                fifo.write(jpeg.tobytes())</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                fifo.flush()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                frame_count += 1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                if frame_count % 50 == 0:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    print(f"Frame {frame_count}: FPS={self.fps:.1f}, NPU={inf_time:.1f}ms, Objects={obj_count}")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        except KeyboardInterrupt:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            print("\nStopping...")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        finally:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            fifo.close()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            cap.release()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            rknn_lite.release()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            print("Released resources")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">YOLODetector().run()</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">PYTHON_CODE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">PYTHON_PID=$!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo ""</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "=========================================="</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "System started!"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Screen should show real-time detection"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Press Ctrl+C to exit"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "=========================================="</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo ""</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">trap "echo ''; echo 'Stopping...'; kill $PYTHON_PID $GST_PID 2&gt;/dev/null; rm -f $FIFO_PATH; echo 'Cleaned up'; exit" INT</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">wait $PYTHON_PID</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">kill $GST_PID 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rm -f $FIFO_PATH</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Cleaned"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">EOF</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">chmod +x yolo_npu_display.sh</span><br></div></code></pre></div></div>
<p><strong>【截图13:脚本创建完成】</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="53-运行实时检测">5.3 运行实时检测<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#53-%E8%BF%90%E8%A1%8C%E5%AE%9E%E6%97%B6%E6%A3%80%E6%B5%8B" class="hash-link" aria-label="5.3 运行实时检测的直接链接" title="5.3 运行实时检测的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./yolo_npu_display.sh</span><br></div></code></pre></div></div>
<p>会看到:</p>
<ol>
<li class="">重启3A服务器</li>
<li class="">创建FIFO管道</li>
<li class="">启动GStreamer显示管道</li>
<li class="">启动YOLOv5检测</li>
</ol>
<p>终端会每50帧输出一次性能统计,例如:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Frame 50: FPS=10.2, NPU=52.3ms, Objects=2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Frame 100: FPS=10.5, NPU=48.7ms, Objects=1</span><br></div></code></pre></div></div>
<ul>
<li class="">绿色检测框标注物体</li>
<li class="">左上角显示FPS、NPU延迟、检测数量</li>
</ul>
<p>按 <code>Ctrl+C</code> 停止程序。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="六性能分析">六、性能分析<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#%E5%85%AD%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90" class="hash-link" aria-label="六、性能分析的直接链接" title="六、性能分析的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="61-实测数据">6.1 实测数据<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#61-%E5%AE%9E%E6%B5%8B%E6%95%B0%E6%8D%AE" class="hash-link" aria-label="6.1 实测数据的直接链接" title="6.1 实测数据的直接链接" translate="no">​</a></h3>
<p>我的实时检测结果:</p>
<table><thead><tr><th>指标</th><th>数值</th></tr></thead><tbody><tr><td>平均FPS</td><td>10.0-10.8</td></tr><tr><td>NPU推理延迟</td><td>47-59 ms</td></tr><tr><td>总延迟(含采集/绘制/显示)</td><td>84-101 ms</td></tr><tr><td>最多检测目标数</td><td>13个物体</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="62-和cpu方案对比">6.2 和CPU方案对比<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#62-%E5%92%8Ccpu%E6%96%B9%E6%A1%88%E5%AF%B9%E6%AF%94" class="hash-link" aria-label="6.2 和CPU方案对比的直接链接" title="6.2 和CPU方案对比的直接链接" translate="no">​</a></h3>
<table><thead><tr><th>方案</th><th>FPS</th><th>CPU占用</th><th>功耗</th></tr></thead><tbody><tr><td>MediaPipe(CPU)</td><td>15-25</td><td>50-65%</td><td>高</td></tr><tr><td>YOLOv5(NPU)</td><td>10-11</td><td>15-25%</td><td>低</td></tr></tbody></table>
<p>虽然YOLOv5的FPS略低于MediaPipe手势识别,但要注意:</p>
<ul>
<li class="">YOLOv5是<strong>全场景目标检测</strong>(80类物体),MediaPipe只做手部检测(任务简单得多)</li>
<li class="">YOLOv5用的是NPU,<strong>CPU占用率降低了60%以上</strong></li>
<li class="">NPU功耗远低于CPU全速运行,<strong>发热明显减少</strong></li>
<li class="">如果只用YOLOv5检测人体(person类),可以进一步优化后处理,FPS还能提升</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="63-为什么没达到理论89-fps">6.3 为什么没达到理论89 FPS?<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#63-%E4%B8%BA%E4%BB%80%E4%B9%88%E6%B2%A1%E8%BE%BE%E5%88%B0%E7%90%86%E8%AE%BA89-fps" class="hash-link" aria-label="6.3 为什么没达到理论89 FPS?的直接链接" title="6.3 为什么没达到理论89 FPS?的直接链接" translate="no">​</a></h3>
<p>ResNet18单张图片能跑89 FPS,为什么实时检测只有10 FPS?瓶颈在哪?</p>
<p>经过profiling分析:</p>
<ul>
<li class=""><strong>NPU推理</strong>: ~50ms (主要瓶颈)</li>
<li class="">摄像头采集: ~5ms</li>
<li class="">后处理(NMS等): ~15ms</li>
<li class="">绘制框和文字: ~8ms</li>
<li class="">JPEG编码: ~10ms</li>
<li class="">FIFO传输+GStreamer: ~5ms</li>
</ul>
<p><strong>总结:</strong></p>
<ol>
<li class="">YOLOv5模型比ResNet18大得多(7.9MB vs 12MB),计算量也更大</li>
<li class="">后处理的NMS算法是纯Python实现,比较慢(可以改用C++或CUDA加速)</li>
<li class="">JPEG编码也占了不少时间(可以改用H.264硬件编码)</li>
</ol>
<p><strong>优化方向:</strong></p>
<ul>
<li class="">使用YOLOv5-nano(更小的模型)</li>
<li class="">后处理用Cython加速</li>
<li class="">启用NPU双核并行</li>
<li class="">用RK3576的硬件视频编码器</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="七遇到的坑和解决方法">七、遇到的坑和解决方法<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#%E4%B8%83%E9%81%87%E5%88%B0%E7%9A%84%E5%9D%91%E5%92%8C%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95" class="hash-link" aria-label="七、遇到的坑和解决方法的直接链接" title="七、遇到的坑和解决方法的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="71-pc端模型转换依赖地狱">7.1 PC端模型转换依赖地狱<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#71-pc%E7%AB%AF%E6%A8%A1%E5%9E%8B%E8%BD%AC%E6%8D%A2%E4%BE%9D%E8%B5%96%E5%9C%B0%E7%8B%B1" class="hash-link" aria-label="7.1 PC端模型转换依赖地狱的直接链接" title="7.1 PC端模型转换依赖地狱的直接链接" translate="no">​</a></h3>
<p><strong>问题:</strong> 想在PC上用rknn-toolkit2把MediaPipe的TFLite模型转成.rknn格式,结果遇到protobuf版本冲突——TensorFlow要求<code>&lt;3.20,但rknn-toolkit2要求&gt;</code>=4.25,完全不兼容。</p>
<p><strong>尝试的解决方法:</strong></p>
<ul>
<li class="">换TensorFlow版本 → 失败</li>
<li class="">用虚拟环境 → 用户拒绝(我太懒了...)</li>
<li class="">清华镜像加速 → 依然冲突</li>
</ul>
<p><strong>最终方案:</strong> 放弃PC端转换,直接用官方提供的.rknn模型测试NPU功能。以后有需要再用Docker跑转换工具。</p>
<p><strong>教训:</strong> Python依赖管理真是个大坑,尤其是深度学习框架。强烈建议使用Docker或conda环境隔离。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="72-摄像头打不开">7.2 摄像头打不开<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#72-%E6%91%84%E5%83%8F%E5%A4%B4%E6%89%93%E4%B8%8D%E5%BC%80" class="hash-link" aria-label="7.2 摄像头打不开的直接链接" title="7.2 摄像头打不开的直接链接" translate="no">​</a></h3>
<p><strong>问题:</strong> 直接用<code>cv2.VideoCapture(11)</code>打开失败。</p>
<p><strong>原因:</strong> 没有重启rkaiq_3A服务器(负责摄像头的自动曝光/白平衡)。</p>
<p><strong>解决:</strong> 在脚本开头加上:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">killall rkaiq_3A_server 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rm -f /tmp/.rkaiq_3A* 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/etc/init.d/S40rkaiq_3A start &gt;/dev/null 2&gt;&amp;1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 3</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="73-gstreamer找不到videoparse">7.3 GStreamer找不到videoparse<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#73-gstreamer%E6%89%BE%E4%B8%8D%E5%88%B0videoparse" class="hash-link" aria-label="7.3 GStreamer找不到videoparse的直接链接" title="7.3 GStreamer找不到videoparse的直接链接" translate="no">​</a></h3>
<p><strong>问题:</strong> 一开始想用<code>videoparse</code>插件,结果提示没这个插件。</p>
<p><strong>原因:</strong> Buildroot精简系统,很多GStreamer插件没装。</p>
<p><strong>解决:</strong> 改用JPEG流传输:</p>
<ul>
<li class="">Python编码成JPEG → FIFO → GStreamer的<code>jpegparse</code>解码</li>
<li class="">这个插件是默认安装的</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="74-python脚本中文编码错误">7.4 Python脚本中文编码错误<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#74-python%E8%84%9A%E6%9C%AC%E4%B8%AD%E6%96%87%E7%BC%96%E7%A0%81%E9%94%99%E8%AF%AF" class="hash-link" aria-label="7.4 Python脚本中文编码错误的直接链接" title="7.4 Python脚本中文编码错误的直接链接" translate="no">​</a></h3>
<p><strong>问题:</strong> 脚本里有中文注释,运行报错:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">SyntaxError: Non-UTF-8 code starting with '\xe5'</span><br></div></code></pre></div></div>
<p><strong>解决:</strong> 把所有中文注释改成英文,或者在文件开头加:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># -*- coding: utf-8 -*-</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="八总结与展望">八、总结与展望<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#%E5%85%AB%E6%80%BB%E7%BB%93%E4%B8%8E%E5%B1%95%E6%9C%9B" class="hash-link" aria-label="八、总结与展望的直接链接" title="八、总结与展望的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="81-本次实战收获">8.1 本次实战收获<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#81-%E6%9C%AC%E6%AC%A1%E5%AE%9E%E6%88%98%E6%94%B6%E8%8E%B7" class="hash-link" aria-label="8.1 本次实战收获的直接链接" title="8.1 本次实战收获的直接链接" translate="no">​</a></h3>
<ol>
<li class="">
<p><strong>成功验证了RK3576的NPU硬件加速能力</strong></p>
<ul>
<li class="">ResNet18: 89 FPS(11ms延迟)</li>
<li class="">YOLOv5: 10 FPS(50ms NPU延迟)</li>
<li class="">CPU占用降低60%,功耗显著下降</li>
</ul>
</li>
<li class="">
<p><strong>掌握了RKNN工具链的使用</strong></p>
<ul>
<li class="">rknn-toolkit-lite2的安装和API</li>
<li class="">.rknn模型的加载和推理</li>
<li class="">NPU核心的指定和配置</li>
</ul>
</li>
<li class="">
<p><strong>建立了完整的实时检测pipeline</strong></p>
<ul>
<li class="">摄像头采集 → NPU推理 → 后处理 → 显示</li>
<li class="">FIFO + GStreamer的显示方案</li>
<li class="">性能监控和FPS计算</li>
</ul>
</li>
<li class="">
<p><strong>踩过了各种坑</strong></p>
<ul>
<li class="">依赖冲突、摄像头初始化、显示管道等</li>
<li class="">积累了宝贵的debug经验</li>
</ul>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="82-感想">8.2 感想<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#82-%E6%84%9F%E6%83%B3" class="hash-link" aria-label="8.2 感想的直接链接" title="8.2 感想的直接链接" translate="no">​</a></h3>
<p>RK3576的NPU确实很强大,6 TOPS的算力在边缘设备中算是顶级配置了。虽然用起来有一些坑(主要是依赖管理),但整体体验还是不错的。</p>
<p>最大的感触是:<strong>AI落地不容易啊!</strong> 从模型训练到部署,要考虑的东西太多了——精度、速度、功耗、成本...每个环节都需要权衡取舍。但看到实时检测画面流畅运行的那一刻,所有的付出都值了!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="九参考资料">九、参考资料<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#%E4%B9%9D%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99" class="hash-link" aria-label="九、参考资料的直接链接" title="九、参考资料的直接链接" translate="no">​</a></h2>
<ol>
<li class=""><a href="https://github.com/airockchip/rknn-toolkit2" target="_blank" rel="noopener noreferrer" class="">RKNN-Toolkit2官方文档</a></li>
<li class=""><a href="https://www.rock-chips.com/" target="_blank" rel="noopener noreferrer" class="">RK3576 NPU技术白皮书</a></li>
<li class=""><a href="https://github.com/ultralytics/yolov5" target="_blank" rel="noopener noreferrer" class="">YOLOv5官方仓库</a></li>
<li class=""><a href="https://gstreamer.freedesktop.org/documentation/" target="_blank" rel="noopener noreferrer" class="">GStreamer Pipeline设计指南</a></li>
<li class="">我的前期文章</li>
</ol>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="附录a完整的yolov5推理脚本">附录A:完整的YOLOv5推理脚本<a href="https://zephyr.100ask.org/blog/npu-yolov5-detection#%E9%99%84%E5%BD%95a%E5%AE%8C%E6%95%B4%E7%9A%84yolov5%E6%8E%A8%E7%90%86%E8%84%9A%E6%9C%AC" class="hash-link" aria-label="附录A:完整的YOLOv5推理脚本的直接链接" title="附录A:完整的YOLOv5推理脚本的直接链接" translate="no">​</a></h2>
<p>由于篇幅限制,完整的Python代码已经集成在 <code>yolo_npu_display.sh</code> 脚本中。</p>
<p>关键函数说明:</p>
<ul>
<li class=""><code>xywh2xyxy()</code>: 边界框坐标转换</li>
<li class=""><code>process()</code>: YOLO输出解析</li>
<li class=""><code>filter_boxes()</code>: 置信度过滤</li>
<li class=""><code>nms_boxes()</code>: 非极大值抑制(去除重叠框)</li>
<li class=""><code>yolov5_post_process()</code>: 完整后处理流程</li>
</ul>]]></content:encoded>
            <category>NPU</category>
            <category>YOLOv5</category>
            <category>目标检测</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 测评四：开源手势项目改造]]></title>
            <link>https://zephyr.100ask.org/blog/open-gesture-project-modify</link>
            <guid>https://zephyr.100ask.org/blog/open-gesture-project-modify</guid>
            <pubDate>Wed, 26 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[从兼容性、流畅性、屏幕显示和摄像头调用等方面改造开源手势项目。]]></description>
            <content:encoded><![CDATA[<p>本次所有的项目改造主要基于兼容性、流畅性、屏幕显示方式和摄像头调用等方面。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="显示输出适配">显示输出适配<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E6%98%BE%E7%A4%BA%E8%BE%93%E5%87%BA%E9%80%82%E9%85%8D" class="hash-link" aria-label="显示输出适配的直接链接" title="显示输出适配的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="主要的适配问题">主要的适配问题<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E4%B8%BB%E8%A6%81%E7%9A%84%E9%80%82%E9%85%8D%E9%97%AE%E9%A2%98" class="hash-link" aria-label="主要的适配问题的直接链接" title="主要的适配问题的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-rk3576运行纯wayland环境">1. RK3576运行纯Wayland环境<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#1-rk3576%E8%BF%90%E8%A1%8C%E7%BA%AFwayland%E7%8E%AF%E5%A2%83" class="hash-link" aria-label="1. RK3576运行纯Wayland环境的直接链接" title="1. RK3576运行纯Wayland环境的直接链接" translate="no">​</a></h4>
<p>RK3576运行纯Wayland环境，没有X11和libGL支持，无法使用传统的<code>cv2.imshow()</code>显示图像。</p>
<p><strong>【解决方案】</strong></p>
<p>采用FIFO + GStreamer + Wayland的显示管线:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Python端代码</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fifo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">open</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/tmp/gesture_fifo'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'wb'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    _</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> jpeg </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">imencode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> processed_frame</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">IMWRITE_JPEG_QUALITY</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">85</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    fifo</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">write</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">jpeg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tobytes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    fifo</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">flush</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Shell端代码</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># GStreamer从管道读取JPEG流并显示</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 filesrc location=/tmp/gesture_fifo ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    jpegparse ! jpegdec ! videoconvert ! waylandsink fullscreen=true</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-imx415摄像头第二次启动色彩异常">2. IMX415摄像头第二次启动色彩异常<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#2-imx415%E6%91%84%E5%83%8F%E5%A4%B4%E7%AC%AC%E4%BA%8C%E6%AC%A1%E5%90%AF%E5%8A%A8%E8%89%B2%E5%BD%A9%E5%BC%82%E5%B8%B8" class="hash-link" aria-label="2. IMX415摄像头第二次启动色彩异常的直接链接" title="2. IMX415摄像头第二次启动色彩异常的直接链接" translate="no">​</a></h4>
<p>IMX415摄像头第二次启动时出现色彩异常，内核报错"no first iq setting"。</p>
<p><strong>【解决方案】</strong></p>
<p>在每次打开摄像头前重启rkaiq_3A_server:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">restart_3a</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">system</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"killall rkaiq_3A_server 2&gt;/dev/null"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">system</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"rm -f /tmp/.rkaiq_3A* 2&gt;/dev/null"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">system</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/etc/init.d/S40rkaiq_3A start &gt;/dev/null 2&gt;&amp;1"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="项目一贪吃蛇游戏">项目一：贪吃蛇游戏<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E9%A1%B9%E7%9B%AE%E4%B8%80%E8%B4%AA%E5%90%83%E8%9B%87%E6%B8%B8%E6%88%8F" class="hash-link" aria-label="项目一：贪吃蛇游戏的直接链接" title="项目一：贪吃蛇游戏的直接链接" translate="no">​</a></h2>
<p>项目开源地址：<a href="https://github.com/WLHSDXN/Project2/blob/main/SnakeGame/main.py" target="_blank" rel="noopener noreferrer" class="">Project2/SnakeGame/main.py at main · WLHSDXN/Project2</a></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="改造过程">改造过程<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E6%94%B9%E9%80%A0%E8%BF%87%E7%A8%8B" class="hash-link" aria-label="改造过程的直接链接" title="改造过程的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-多层级检测器架构">1. 多层级检测器架构<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#1-%E5%A4%9A%E5%B1%82%E7%BA%A7%E6%A3%80%E6%B5%8B%E5%99%A8%E6%9E%B6%E6%9E%84" class="hash-link" aria-label="1. 多层级检测器架构的直接链接" title="1. 多层级检测器架构的直接链接" translate="no">​</a></h4>
<p>为了适配不同的依赖环境，设计了三层检测器回退机制:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">优先级1: cvzone (MediaPipe封装,精度高)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ↓ 不可用</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">优先级2: 原生MediaPipe (21个关键点)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ↓ 不可用  </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">优先级3: HSV肤色检测 (轻量级备用)</span><br></div></code></pre></div></div>
<p>代码实现:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 检测器选择逻辑</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> USE_CVZONE</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    detector </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> CvzoneHandDetector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">detectionCon</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.8</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> maxHands</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">elif</span><span class="token plain"> USE_MEDIAPIPE</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    detector </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> MediapipeHandDetector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">maxHands</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    detectionCon</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    drawLandmarks</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">False</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">else</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    detector </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> SimpleHandDetector</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># HSV备用方案</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-mediapipe集成与封装">2. MediaPipe集成与封装<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#2-mediapipe%E9%9B%86%E6%88%90%E4%B8%8E%E5%B0%81%E8%A3%85" class="hash-link" aria-label="2. MediaPipe集成与封装的直接链接" title="2. MediaPipe集成与封装的直接链接" translate="no">​</a></h4>
<p>实现了MediapipeHandDetector类，返回与cvzone兼容的数据格式:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MediapipeHandDetector</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">findHands</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> frame</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> flipType</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">False</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        img_rgb </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cvtColor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frame</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">COLOR_BGR2RGB</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        results </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">hands</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">process</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">img_rgb</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        hands </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> results</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">multi_hand_landmarks</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> hand_landmarks </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> results</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">multi_hand_landmarks</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic"># 提取21个关键点坐标</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                lmList </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> lm </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> hand_landmarks</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">landmark</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    x_px </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lm</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">x </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> width</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    y_px </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lm</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">y </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> height</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    lmList</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">x_px</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> y_px</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> lm</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">z</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                hands</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token string" style="color:#e3116c">'lmList'</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> lmList</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> hands</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> frame</span><br></div></code></pre></div></div>
<p><strong>【关键点】</strong></p>
<p>食指指尖是lmList[8]，直接用作蛇头控制点。</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-hsv肤色检测备用方案">3. HSV肤色检测备用方案<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#3-hsv%E8%82%A4%E8%89%B2%E6%A3%80%E6%B5%8B%E5%A4%87%E7%94%A8%E6%96%B9%E6%A1%88" class="hash-link" aria-label="3. HSV肤色检测备用方案的直接链接" title="3. HSV肤色检测备用方案的直接链接" translate="no">​</a></h4>
<p>当MediaPipe不可用时，使用简单的肤色检测:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">detect_hand_simple</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frame</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    hsv </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cvtColor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frame</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">COLOR_BGR2HSV</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    mask </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">inRange</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hsv</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">30</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">60</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 形态学去噪</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    kernel </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ones</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">7</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">7</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">uint8</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    mask </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">morphologyEx</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mask</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">MORPH_CLOSE</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> kernel</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> iterations</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    mask </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">morphologyEx</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mask</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">MORPH_OPEN</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> kernel</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> iterations</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    contours</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> _ </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">findContours</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mask</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">RETR_EXTERNAL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CHAIN_APPROX_SIMPLE</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> contours</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">contours</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> key</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">contourArea</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        hull </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">convexHull</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">c</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># 提取最高点作为"指尖"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        topmost </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> hull</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">hull</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">argmin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> topmost</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-mediapipe性能调优">4. MediaPipe性能调优<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#4-mediapipe%E6%80%A7%E8%83%BD%E8%B0%83%E4%BC%98" class="hash-link" aria-label="4. MediaPipe性能调优的直接链接" title="4. MediaPipe性能调优的直接链接" translate="no">​</a></h4>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="优化1-使用轻量级模型">优化1: 使用轻量级模型<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E4%BC%98%E5%8C%961-%E4%BD%BF%E7%94%A8%E8%BD%BB%E9%87%8F%E7%BA%A7%E6%A8%A1%E5%9E%8B" class="hash-link" aria-label="优化1: 使用轻量级模型的直接链接" title="优化1: 使用轻量级模型的直接链接" translate="no">​</a></h5>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">hands </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> mp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">solutions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">hands</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Hands</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    model_complexity</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 0=lite, 1=full (默认)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    max_num_hands</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    min_detection_confidence</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 降低阈值换速度</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    min_tracking_confidence</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">0.5</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="优化2-关闭可视化绘制">优化2: 关闭可视化绘制<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E4%BC%98%E5%8C%962-%E5%85%B3%E9%97%AD%E5%8F%AF%E8%A7%86%E5%8C%96%E7%BB%98%E5%88%B6" class="hash-link" aria-label="优化2: 关闭可视化绘制的直接链接" title="优化2: 关闭可视化绘制的直接链接" translate="no">​</a></h5>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 移除耗时的关键点绘制</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># mp_drawing.draw_landmarks(frame, landmarks, connections)  # 注释掉</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">drawLandmarks</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">False</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 新增开关</span><br></div></code></pre></div></div>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="优化3-减少输入分辨率">优化3: 减少输入分辨率<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E4%BC%98%E5%8C%963-%E5%87%8F%E5%B0%91%E8%BE%93%E5%85%A5%E5%88%86%E8%BE%A8%E7%8E%87" class="hash-link" aria-label="优化3: 减少输入分辨率的直接链接" title="优化3: 减少输入分辨率的直接链接" translate="no">​</a></h5>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 640x480 已经是最优平衡点</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 若进一步降低到320x240可提升FPS,但会影响检测精度</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cap</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CAP_PROP_FRAME_WIDTH</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">640</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cap</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CAP_PROP_FRAME_HEIGHT</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">480</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="优化4-优化相机缓冲">优化4: 优化相机缓冲<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E4%BC%98%E5%8C%964-%E4%BC%98%E5%8C%96%E7%9B%B8%E6%9C%BA%E7%BC%93%E5%86%B2" class="hash-link" aria-label="优化4: 优化相机缓冲的直接链接" title="优化4: 优化相机缓冲的直接链接" translate="no">​</a></h5>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cap</span><span class="token punctuation" style="color:#393A34">.</span><span class="token builtin">set</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CAP_PROP_BUFFERSIZE</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 减少延迟</span><br></div></code></pre></div></div>
<p><strong>【优化效果】</strong></p>
<p>FPS从5-10提升至15-25 FPS，满足游戏交互需求。</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-文件控制接口">5. 文件控制接口<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#5-%E6%96%87%E4%BB%B6%E6%8E%A7%E5%88%B6%E6%8E%A5%E5%8F%A3" class="hash-link" aria-label="5. 文件控制接口的直接链接" title="5. 文件控制接口的直接链接" translate="no">​</a></h4>
<p>由于FIFO模式下无法直接捕获键盘，采用控制文件方式:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Shell脚本部分</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 读取按键并写控制文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">stty echo icanon</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">while read n1 t 0.1 key; do</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    if [ "$key" = "r" ]; then</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        touch /tmp/snake_restart</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    elif [ "$key" = "q" ]; then</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        touch /tmp/snake_quit</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    fi</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">done</span><br></div></code></pre></div></div>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Python部分</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 检测控制文件</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">exists</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/tmp/snake_quit'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Quit command detected'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">break</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">exists</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/tmp/snake_restart'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/tmp/snake_restart'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 重置游戏状态</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">game</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">gameOver </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">False</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">game</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">points </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">game</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">previousHead </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="效果展示">效果展示<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E6%95%88%E6%9E%9C%E5%B1%95%E7%A4%BA" class="hash-link" aria-label="效果展示的直接链接" title="效果展示的直接链接" translate="no">​</a></h4>
<p>代码和演示视频均在附件当中</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="项目二虚拟画板">项目二：虚拟画板<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E9%A1%B9%E7%9B%AE%E4%BA%8C%E8%99%9A%E6%8B%9F%E7%94%BB%E6%9D%BF" class="hash-link" aria-label="项目二：虚拟画板的直接链接" title="项目二：虚拟画板的直接链接" translate="no">​</a></h2>
<p>开源项目：【基于手部关键点检测，隔空控制鼠标/隔空绘画】<a href="https://www.bilibili.com/video/BV1364y1h7PS?vd_source=a16ca768198c38baa684546cf5060811" target="_blank" rel="noopener noreferrer" class="">https://www.bilibili.com/video/BV1364y1h7PS?vd_source=a16ca768198c38baa684546cf5060811</a></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="改造过程-1">改造过程<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E6%94%B9%E9%80%A0%E8%BF%87%E7%A8%8B-1" class="hash-link" aria-label="改造过程的直接链接" title="改造过程的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-核心逻辑提取">1. 核心逻辑提取<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#1-%E6%A0%B8%E5%BF%83%E9%80%BB%E8%BE%91%E6%8F%90%E5%8F%96" class="hash-link" aria-label="1. 核心逻辑提取的直接链接" title="1. 核心逻辑提取的直接链接" translate="no">​</a></h4>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="手势识别逻辑">手势识别逻辑:<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E6%89%8B%E5%8A%BF%E8%AF%86%E5%88%AB%E9%80%BB%E8%BE%91" class="hash-link" aria-label="手势识别逻辑:的直接链接" title="手势识别逻辑:的直接链接" translate="no">​</a></h5>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">fingers </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> detector</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">fingersUp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 返回5个值,1表示手指伸直</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 模式1: 选择工具(食指+中指伸直)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> fingers</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">and</span><span class="token plain"> fingers</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> y1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">153</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 在顶部工具栏区域</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> x1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">320</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">    color </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">128</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">250</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 蓝色</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">elif</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">320</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> x1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">640</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">  color </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 红色</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">elif</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">640</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> x1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">960</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">  color </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 绿色</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">elif</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">960</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> x1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1280</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> color </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">     </span><span class="token comment" style="color:#999988;font-style:italic"># 橡皮擦</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 模式2: 绘画(仅食指伸直)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">elif</span><span class="token plain"> fingers</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">and</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">not</span><span class="token plain"> fingers</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">line</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">imgCanvas</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">xp</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> yp</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> y1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> color</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> brushThickness</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="画布合成逻辑">画布合成逻辑:<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E7%94%BB%E5%B8%83%E5%90%88%E6%88%90%E9%80%BB%E8%BE%91" class="hash-link" aria-label="画布合成逻辑:的直接链接" title="画布合成逻辑:的直接链接" translate="no">​</a></h5>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 1. 将画布转为灰度图并二值化</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">imgGray </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cvtColor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">imgCanvas</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">COLOR_BGR2GRAY</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> imgInv </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">threshold</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">imgGray</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">THRESH_BINARY_INV</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 2. 使用位运算合成</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">img </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">bitwise_and</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">img</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> imgInv</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 摄像头画面保留非绘画区域</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">img </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">bitwise_or</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">img</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> imgCanvas</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic"># 叠加绘画内容</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-显示系统重构">2. 显示系统重构<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#2-%E6%98%BE%E7%A4%BA%E7%B3%BB%E7%BB%9F%E9%87%8D%E6%9E%84" class="hash-link" aria-label="2. 显示系统重构的直接链接" title="2. 显示系统重构的直接链接" translate="no">​</a></h4>
<p>复用贪吃蛇游戏的显示方案: FIFO + GStreamer</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-工具栏内置化">3. 工具栏内置化<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#3-%E5%B7%A5%E5%85%B7%E6%A0%8F%E5%86%85%E7%BD%AE%E5%8C%96" class="hash-link" aria-label="3. 工具栏内置化的直接链接" title="3. 工具栏内置化的直接链接" translate="no">​</a></h4>
<p>原项目依赖4张PNG图片作为工具栏，在嵌入式系统上不便管理外部资源。</p>
<p><strong>【解决方案】</strong></p>
<p>用OpenCV绘图API生成工具栏</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">create_header</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#e3116c">"""动态生成工具栏"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    header </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">width</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">uint8</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    header</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">:</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">200</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">200</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">200</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 灰色背景</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    tools </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">250</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">128</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Blue"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># BGR格式</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Red"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Green"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Eraser"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    section_width </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">width </span><span class="token operator" style="color:#393A34">//</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> i</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">color</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> label</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">enumerate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tools</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        x1 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> section_width</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        x2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> section_width</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># 绘制颜色块</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">rectangle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">header</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x1 </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">20</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x2 </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">80</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> color</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">rectangle</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">header</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x1 </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">20</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x2 </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">80</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 白色边框</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># 文字标签</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">putText</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">header</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> label</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x1 </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">20</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">95</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">              cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">FONT_HERSHEY_SIMPLEX</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0.5</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> header</span><br></div></code></pre></div></div>
<p>这样就可以对外部产生零依赖，更有利于移植和项目开发！</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-摄像头与3a服务适配">4. 摄像头与3A服务适配<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#4-%E6%91%84%E5%83%8F%E5%A4%B4%E4%B8%8E3a%E6%9C%8D%E5%8A%A1%E9%80%82%E9%85%8D" class="hash-link" aria-label="4. 摄像头与3A服务适配的直接链接" title="4. 摄像头与3A服务适配的直接链接" translate="no">​</a></h4>
<p>复用贪吃蛇游戏的解决办法</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-分辨率与性能权衡">5. 分辨率与性能权衡<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#5-%E5%88%86%E8%BE%A8%E7%8E%87%E4%B8%8E%E6%80%A7%E8%83%BD%E6%9D%83%E8%A1%A1" class="hash-link" aria-label="5. 分辨率与性能权衡的直接链接" title="5. 分辨率与性能权衡的直接链接" translate="no">​</a></h4>
<p><strong>【原版配置】</strong>：</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">width </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1280</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> height </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">720</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">画布</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> imgCanvas </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">720</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1280</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">uint8</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p><strong>【RK3576优化】</strong></p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">width </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">640</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> height </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">480</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 降低50%分辨率</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">画布</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> imgCanvas </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">480</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">640</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">uint8</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p><strong>【原因】</strong></p>
<ol>
<li class="">MediaPipe在640x480下FPS提升约2倍</li>
<li class="">画板应用对分辨率要求不如视觉识别高</li>
<li class="">JPEG编码/传输速度更快</li>
</ol>
<p><strong>【工具栏适配】</strong></p>
<p>原版: 顶部153像素高,分4个320像素宽的区域
RK3576: 顶部100像素高,分4个160像素宽的区域</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">section_width </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">width </span><span class="token operator" style="color:#393A34">//</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 自适应宽度</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> y1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 工具栏高度</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> x1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> section_width</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">color </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">250</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">128</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 蓝色</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">elif</span><span class="token plain"> section_width </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> x1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> section_width </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">color </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic"># 红色</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># ...</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-交互控制改进">6. 交互控制改进<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#6-%E4%BA%A4%E4%BA%92%E6%8E%A7%E5%88%B6%E6%94%B9%E8%BF%9B" class="hash-link" aria-label="6. 交互控制改进的直接链接" title="6. 交互控制改进的直接链接" translate="no">​</a></h4>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-清空画布机制">1. 清空画布机制<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#1-%E6%B8%85%E7%A9%BA%E7%94%BB%E5%B8%83%E6%9C%BA%E5%88%B6" class="hash-link" aria-label="1. 清空画布机制的直接链接" title="1. 清空画布机制的直接链接" translate="no">​</a></h5>
<p><strong>【原版】</strong></p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token builtin">all</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">x </span><span class="token operator" style="color:#393A34">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> x </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> fingers</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    imgCanvas </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">720</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1280</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">uint8</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p><strong>【问题】</strong></p>
<p>误触发率高，不便于精细控制。</p>
<p><strong>【RK3576改进】</strong></p>
<p>使用按键控制:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Shell端</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">while read -n1 -t 0.1 key; do</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    if [ "$key" = "c" ]; then</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        touch /tmp/painter_clear</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    fi</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">done</span><br></div></code></pre></div></div>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Python端</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">exists</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/tmp/painter_clear'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/tmp/painter_clear'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">imgCanvas </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">zeros</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">height</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">width</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">uint8</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Canvas cleared"</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-退出控制">2. 退出控制<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#2-%E9%80%80%E5%87%BA%E6%8E%A7%E5%88%B6" class="hash-link" aria-label="2. 退出控制的直接链接" title="2. 退出控制的直接链接" translate="no">​</a></h5>
<p><strong>【原版】</strong></p>
<p>只能通过<code>cv2.waitKey(1)</code>捕获键盘，依赖窗口焦点。</p>
<p><strong>【RK3576】</strong></p>
<p>双重退出机制:</p>
<ol>
<li class="">
<p>按键控制:
touch /tmp/painter_quit → Python检测并退出</p>
</li>
<li class="">
<p>Ctrl+C:
Shell脚本trap信号 → kill所有进程 → 清理FIFO</p>
</li>
</ol>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="效果展示-1">效果展示<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E6%95%88%E6%9E%9C%E5%B1%95%E7%A4%BA-1" class="hash-link" aria-label="效果展示的直接链接" title="效果展示的直接链接" translate="no">​</a></h4>
<p>代码和演示视频均在附件当中</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="技术总结与经验">技术总结与经验<a href="https://zephyr.100ask.org/blog/open-gesture-project-modify#%E6%8A%80%E6%9C%AF%E6%80%BB%E7%BB%93%E4%B8%8E%E7%BB%8F%E9%AA%8C" class="hash-link" aria-label="技术总结与经验的直接链接" title="技术总结与经验的直接链接" translate="no">​</a></h2>
<ol>
<li class="">
<p><strong>跨平台显示适配</strong>
PC上的GUI方案不适用嵌入式，必须根据系统特性(Wayland/Framebuffer)选择输出方式。</p>
</li>
<li class="">
<p><strong>资源内置化</strong>
嵌入式系统倾向于单文件部署，外部资源应转为代码生成或打包进程序。</p>
</li>
<li class="">
<p><strong>性能分级优化</strong></p>
<ul>
<li class="">算法层: 轻量级模型</li>
<li class="">实现层: 关闭非必要绘制</li>
<li class="">硬件层: 缓冲区/分辨率调优</li>
</ul>
</li>
<li class="">
<p><strong>交互方式适配</strong>
GUI依赖的键盘/鼠标事件需改为文件控制或GPIO触发。</p>
</li>
</ol>]]></content:encoded>
            <category>手势识别</category>
            <category>项目改造</category>
            <category>MediaPipe</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 测评三：OpenCV 调试与 CPU 推理识别手势]]></title>
            <link>https://zephyr.100ask.org/blog/opencv-cpu-gesture</link>
            <guid>https://zephyr.100ask.org/blog/opencv-cpu-gesture</guid>
            <pubDate>Mon, 24 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[在 RK3576 Buildroot 上基于 OpenCV 实现实时手势识别，识别五种手势并在屏幕显示。]]></description>
            <content:encoded><![CDATA[<p>前面我们已经调试好了摄像头和屏幕，终于可以开始我们的手势识别啦！</p>
<p>这次我会在RK3576 Buildroot系统上实现一个基于OpenCV的实时手势识别系统。系统能够识别五种手势（拳头/一指、二指、三指、四指、五指），并在屏幕上实时显示处理结果。</p>
<p>由于嵌入式系统的特殊性，我们将重点讲解如何在无X11、无OpenGL的Wayland环境下实现图像显示。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="手势识别算法">手势识别算法<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E6%89%8B%E5%8A%BF%E8%AF%86%E5%88%AB%E7%AE%97%E6%B3%95" class="hash-link" aria-label="手势识别算法的直接链接" title="手势识别算法的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="原理">原理<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E5%8E%9F%E7%90%86" class="hash-link" aria-label="原理的直接链接" title="原理的直接链接" translate="no">​</a></h3>
<p>因为我们张开的手指之间会形成凹陷，通过计算凹陷点的角度和深度，可以准确识别手指数量。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-肤色检测">1. 肤色检测<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#1-%E8%82%A4%E8%89%B2%E6%A3%80%E6%B5%8B" class="hash-link" aria-label="1. 肤色检测的直接链接" title="1. 肤色检测的直接链接" translate="no">​</a></h3>
<p>使用HSV色彩空间提取肤色区域：</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">detect_hand</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> frame</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    hsv </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cvtColor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frame</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">COLOR_BGR2HSV</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    mask </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">inRange</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">hsv</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">30</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">60</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">25</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">255</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 肤色范围</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 形态学处理去噪</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    kernel </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ones</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">7</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">7</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">uint8</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    mask </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">morphologyEx</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mask</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">MORPH_CLOSE</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> kernel</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> iterations</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    mask </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">morphologyEx</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mask</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">MORPH_OPEN</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> kernel</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> iterations</span><span class="token operator" style="color:#393A34">=</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 查找最大轮廓</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    contours</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> _ </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">findContours</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">mask</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">RETR_EXTERNAL</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CHAIN_APPROX_SIMPLE</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> contours</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">max</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">contours</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> key</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">contourArea</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">contourArea</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">c</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3000</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 面积阈值过滤噪声</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mask</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mask</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-手指计数凸包缺陷法">2. 手指计数（凸包缺陷法）<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#2-%E6%89%8B%E6%8C%87%E8%AE%A1%E6%95%B0%E5%87%B8%E5%8C%85%E7%BC%BA%E9%99%B7%E6%B3%95" class="hash-link" aria-label="2. 手指计数（凸包缺陷法）的直接链接" title="2. 手指计数（凸包缺陷法）的直接链接" translate="no">​</a></h3>
<p>通过检测手掌轮廓的凹陷点来识别手指：</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">recognize</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> contour</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    hull </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">convexHull</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">contour</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> returnPoints</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">False</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    defects </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">convexityDefects</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">contour</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> hull</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    finger_count </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> i </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">defects</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">shape</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        s</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> f</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> d </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> defects</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        start </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">tuple</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">contour</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">s</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 凸点1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        end </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">tuple</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">contour</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 凸点2</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        far </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">tuple</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">contour</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">f</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 凹点(指间)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># 计算角度判断是否为有效指尖</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        a </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">linalg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">norm</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">start</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">end</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        b </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">linalg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">norm</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">start</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">far</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        c </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">linalg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">norm</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">end</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">array</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">far</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        angle </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">arccos</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">b</span><span class="token operator" style="color:#393A34">**</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> c</span><span class="token operator" style="color:#393A34">**</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> a</span><span class="token operator" style="color:#393A34">**</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> b </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> angle </span><span class="token operator" style="color:#393A34">&lt;=</span><span class="token plain"> np</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">pi </span><span class="token operator" style="color:#393A34">/</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2.2</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">and</span><span class="token plain"> d </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">8000</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic"># 角度和深度阈值</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            finger_count </span><span class="token operator" style="color:#393A34">+=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    gestures </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"Fist/One"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Two"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Three"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Four"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Five"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> gestures</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">finger_count</span><span class="token punctuation" style="color:#393A34">]</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="如何显示opencv处理的图像">如何显示OpenCV处理的图像<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E5%A6%82%E4%BD%95%E6%98%BE%E7%A4%BAopencv%E5%A4%84%E7%90%86%E7%9A%84%E5%9B%BE%E5%83%8F" class="hash-link" aria-label="如何显示OpenCV处理的图像的直接链接" title="如何显示OpenCV处理的图像的直接链接" translate="no">​</a></h2>
<p>有了前面的理论知识还是不够的，我们还需要实践才可以啊！如何显示OpenCV处理的图像这是本教程的重点。通常我们用<code>cv2.imshow()</code>显示图像，但在无X11/OpenGL的嵌入式系统上，这个方法不可用。我们需要使用<strong>GStreamer+Wayland</strong>方案（这个也是我们上一篇文章的方案）。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案探索过程">方案探索过程<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E6%96%B9%E6%A1%88%E6%8E%A2%E7%B4%A2%E8%BF%87%E7%A8%8B" class="hash-link" aria-label="方案探索过程的直接链接" title="方案探索过程的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案a-stdin管道传输">方案A: stdin管道传输<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E6%96%B9%E6%A1%88a-stdin%E7%AE%A1%E9%81%93%E4%BC%A0%E8%BE%93" class="hash-link" aria-label="方案A: stdin管道传输的直接链接" title="方案A: stdin管道传输的直接链接" translate="no">​</a></h4>
<p>最直观的想法是通过stdin管道传输图像数据：</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">proc </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> subprocess</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Popen</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'gst-launch-1.0'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'fdsrc'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'!'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> stdin</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">subprocess</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">PIPE</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">proc</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">stdin</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">write</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">frame_data</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p><strong>结果</strong>：频繁出现Broken pipe错误，数据传输不稳定，这个我怀疑是管道超时自动关闭了又或者是我的格式不对。所以我直接尝试用fifo来传输原始的数据</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案b-命名管道fifo传输原始数据">方案B: 命名管道(FIFO)传输原始数据<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E6%96%B9%E6%A1%88b-%E5%91%BD%E5%90%8D%E7%AE%A1%E9%81%93fifo%E4%BC%A0%E8%BE%93%E5%8E%9F%E5%A7%8B%E6%95%B0%E6%8D%AE" class="hash-link" aria-label="方案B: 命名管道(FIFO)传输原始数据的直接链接" title="方案B: 命名管道(FIFO)传输原始数据的直接链接" translate="no">​</a></h4>
<p>尝试用FIFO传输原始RGB数据：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">mkfifo /tmp/video_fifo</span><br></div></code></pre></div></div>
<p>很遗憾啊，这个太容易动不动就内核奔溃了。到这个时候我面临几个问题：如果我单纯的用命令行看识别结果，我就不知道我的摄像头能不能正常运行；但是如果OpenCV和GStreamer同时读取摄像头是不可以的（摄像头只能被一个进程读取）。后面又觉得GStreamer的显示不需要实时读取摄像头的画面，我只要显示OpenCV处理过的就好了。说干就干，于是我尝试直接在OpenCV里面把处理后的图像通过GStreamer传到屏幕上面，但技术不达标无果，管道不是报错就是关闭。停下来慢慢思考，最后有了方案C（搞到这步已经花费三天了）。</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案c-多文件序列">方案C: 多文件序列<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E6%96%B9%E6%A1%88c-%E5%A4%9A%E6%96%87%E4%BB%B6%E5%BA%8F%E5%88%97" class="hash-link" aria-label="方案C: 多文件序列的直接链接" title="方案C: 多文件序列的直接链接" translate="no">​</a></h4>
<p>改变思路，将处理后的图像保存为JPEG文件序列：</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Python端</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">imwrite</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f'/dev/shm/gesture_frames/frame_</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">frame_index</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">:</span><span class="token string-interpolation interpolation format-spec">03d</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> processed</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># GStreamer端</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 multifilesrc location=frame_%03d.jpg loop=true ! jpegdec ! ...</span><br></div></code></pre></div></div>
<p><strong>结果</strong>：屏幕终于可以有变动了，开心坏了！但是效果很差，重影严重，而且因为是循环读出文件夹的图片导致一直在循环播放，影响美观和体验度。于是我打算利用FIFO，基于前面的思路升级为现在的方案：</p>
<p><strong>OpenCV处理完一帧 → 立即编码JPEG → 直接写入FIFO → GStreamer立即解码显示</strong></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="方案d-fifojpeg流最终方案">方案D: FIFO+JPEG流（最终方案！）<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E6%96%B9%E6%A1%88d-fifojpeg%E6%B5%81%E6%9C%80%E7%BB%88%E6%96%B9%E6%A1%88" class="hash-link" aria-label="方案D: FIFO+JPEG流（最终方案！）的直接链接" title="方案D: FIFO+JPEG流（最终方案！）的直接链接" translate="no">​</a></h4>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Python端: 直接往FIFO写JPEG数据</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fifo </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">open</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/tmp/gesture_fifo'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'wb'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> jpeg </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">imencode</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'.jpg'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> processed</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">cv2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">IMWRITE_JPEG_QUALITY</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">85</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fifo</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">write</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">jpeg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">tobytes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fifo</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">flush</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># GStreamer端: 用jpegparse自动分割JPEG帧</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 filesrc location=/tmp/gesture_fifo ! jpegparse ! jpegdec ! ...</span><br></div></code></pre></div></div>
<p><strong>补充：为什么JPEG流可行？</strong></p>
<ol>
<li class="">JPEG格式自带开始(0xFFD8)和结束(0xFFD9)标记</li>
<li class="">GStreamer的<code>jpegparse</code>插件能自动识别边界，分割独立的JPEG帧</li>
<li class="">避免了原始数据流的粘包问题</li>
</ol>
<p><strong>结果</strong>：总算是可以流畅地观察到画面了（流程不卡顿，甚至比直接点屏幕上的摄像头图标看摄像头画面都流畅）。演示视频和代码我会放在附件里面。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="番外篇摄像头第二次启动色彩偏绿偏暗">番外篇—摄像头第二次启动色彩偏绿偏暗<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E7%95%AA%E5%A4%96%E7%AF%87%E6%91%84%E5%83%8F%E5%A4%B4%E7%AC%AC%E4%BA%8C%E6%AC%A1%E5%90%AF%E5%8A%A8%E8%89%B2%E5%BD%A9%E5%81%8F%E7%BB%BF%E5%81%8F%E6%9A%97" class="hash-link" aria-label="番外篇—摄像头第二次启动色彩偏绿偏暗的直接链接" title="番外篇—摄像头第二次启动色彩偏绿偏暗的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题描述">问题描述<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E9%97%AE%E9%A2%98%E6%8F%8F%E8%BF%B0" class="hash-link" aria-label="问题描述的直接链接" title="问题描述的直接链接" translate="no">​</a></h3>
<p>我在RK3576 Buildroot系统上使用IMX415摄像头，通过GStreamer+Wayland显示画面。遇到了一个诡异的问题：<strong>第一次启动摄像头色彩正常，但第二次启动后画面就变得偏暗偏绿</strong>。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="初步分析对比启动日志">初步分析：对比启动日志<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E5%88%9D%E6%AD%A5%E5%88%86%E6%9E%90%E5%AF%B9%E6%AF%94%E5%90%AF%E5%8A%A8%E6%97%A5%E5%BF%97" class="hash-link" aria-label="初步分析：对比启动日志的直接链接" title="初步分析：对比启动日志的直接链接" translate="no">​</a></h3>
<p>我首先对比了两次启动的kernel日志，发现了关键差异：</p>
<p><strong>第一次启动（色彩正常）</strong>：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[20.528641] rkisp_hw 27c00000.isp: set isp clk = 594000000Hz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[20.529097] rkcif-mipi-lvds 3: stream[0] start streaming</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[20.529317] rockchip-csi2-dphy 3: dphy3, data_rate_mbps 892</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[20.529356] imx415 3-0037: s_stream: 1.3864x2192, hdr: 0, bpp: 10</span><br></div></code></pre></div></div>
<p><strong>第二次启动（色彩异常）</strong>：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[79.209321] rkisp_hw 27c00000.isp: set isp clk = 594000000Hz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[79.209967] rkisp rkisp-vir3: first params buf queue</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[79.210051] rkisp rkisp-vir3: id: 0 no first iq setting cfg_upd: c000dfecc7fe473b en_upd: 0 en s: 5ffcc7fe473b</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[79.210351] rkcif-mipi-lvds 3: stream[0] start streaming</span><br></div></code></pre></div></div>
<p>关键发现：<strong>第二次启动多了一条警告</strong> <code>no first iq setting</code>。这说明ISP的图像质量参数没有正确加载，导致使用了错误的默认参数，造成色彩偏暗偏绿。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题解决过程">问题解决过程<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3%E8%BF%87%E7%A8%8B" class="hash-link" aria-label="问题解决过程的直接链接" title="问题解决过程的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="第一阶段尝试硬件层面解决">第一阶段：尝试硬件层面解决<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E7%AC%AC%E4%B8%80%E9%98%B6%E6%AE%B5%E5%B0%9D%E8%AF%95%E7%A1%AC%E4%BB%B6%E5%B1%82%E9%9D%A2%E8%A7%A3%E5%86%B3" class="hash-link" aria-label="第一阶段：尝试硬件层面解决的直接链接" title="第一阶段：尝试硬件层面解决的直接链接" translate="no">​</a></h4>
<p>一开始我以为是ISP驱动状态没有正确复位，尝试了几种方法：</p>
<ol>
<li class="">
<p><strong>尝试unbind/bind ISP驱动</strong>：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">echo "27c00000.isp" &gt; /sys/bus/platform/drivers/rkisp_hw/unbind</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "27c00000.isp" &gt; /sys/bus/platform/drivers/rkisp_hw/bind</span><br></div></code></pre></div></div>
<p>结果：<strong>摄像头直接打不开了</strong>，操作太激进导致驱动状态完全错乱。</p>
</li>
<li class="">
<p><strong>尝试使用v4l2-ctl重置、media-ctl reset</strong>等方法，都没有解决问题。</p>
</li>
</ol>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="第二阶段深入诊断系统配置">第二阶段：深入诊断系统配置<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E7%AC%AC%E4%BA%8C%E9%98%B6%E6%AE%B5%E6%B7%B1%E5%85%A5%E8%AF%8A%E6%96%AD%E7%B3%BB%E7%BB%9F%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="第二阶段：深入诊断系统配置的直接链接" title="第二阶段：深入诊断系统配置的直接链接" translate="no">​</a></h4>
<p>我开始系统性地诊断整个摄像头子系统：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 查找IQ参数文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">find / -name "*imx415*.xml" -o -name "*imx415*.json" 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 结果: 找到了 /etc/iqfiles/imx415_CMK-OT2022-PX1_IR0147-50IRC-8M-F20.json</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 检查3A服务器</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ps aux | grep rkaiq_3A_server</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 结果: 服务器正在运行</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查看设备拓扑</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">v4l2-ctl --list-devices</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 确认 /dev/video-camera0 -&gt; video11</span><br></div></code></pre></div></div>
<p><strong>关键发现</strong>：</p>
<ul>
<li class="">IQ参数文件存在</li>
<li class="">3A服务器(rkaiq_3A_server)正在运行</li>
<li class="">但为什么IQ参数没有加载?</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="第三阶段抓取3a服务器日志">第三阶段：抓取3A服务器日志<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E7%AC%AC%E4%B8%89%E9%98%B6%E6%AE%B5%E6%8A%93%E5%8F%963a%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%97%A5%E5%BF%97" class="hash-link" aria-label="第三阶段：抓取3A服务器日志的直接链接" title="第三阶段：抓取3A服务器日志的直接链接" translate="no">​</a></h4>
<p>我决定前台运行3A服务器，查看详细输出：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">killall rkaiq_3A_server</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/usr/bin/rkaiq_3A_server 2&gt;&amp;1 &amp;</span><br></div></code></pre></div></div>
<p>启动日志显示：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">DBG: get rkisp-isp-subdev devname: /dev/v4l-subdev3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">DBG: get rkisp-input-params devname: /dev/video18</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">DBG: get rkisp-statistics devname: /dev/video17</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">XCORE: K: cid[1] rk_aiq_uapi2_sysctl_init success. iq: /etc/iqfiles//imx415_CMK-OT2022-PX1_IR0147-50IRC-8M-F20.json</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">XCORE: K: cid[1] rk_aiq_uapi2_sysctl_prepare success. mode: 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">DBG: /dev/media1: wait stream start event..</span><br></div></code></pre></div></div>
<p><strong>重大发现</strong>：3A服务器实际上工作正常！IQ文件已经成功加载了！</p>
<p>这时我进行了第二次摄像头启动测试，观察到：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[625.216117] rkisp-vir3: waiting on params stream one event timeout</span><br></div></code></pre></div></div>
<p><strong>真相大白</strong>：第二次启动时，3A服务器超时无响应！</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="第四阶段找到根本原因">第四阶段：找到根本原因<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E7%AC%AC%E5%9B%9B%E9%98%B6%E6%AE%B5%E6%89%BE%E5%88%B0%E6%A0%B9%E6%9C%AC%E5%8E%9F%E5%9B%A0" class="hash-link" aria-label="第四阶段：找到根本原因的直接链接" title="第四阶段：找到根本原因的直接链接" translate="no">​</a></h4>
<p>通过多次测试和日志分析，我终于理解了问题的本质：</p>
<p><strong>第一次启动流程（正常）</strong>：</p>
<ol>
<li class="">系统启动时，3A服务器自动启动</li>
<li class="">3A服务器加载IQ参数文件到内存</li>
<li class="">3A服务器预先准备好IQ参数缓冲区</li>
<li class="">GStreamer启动摄像头</li>
<li class="">ISP请求IQ参数</li>
<li class="">3A服务器立即响应并推送IQ参数</li>
<li class="">色彩正常</li>
</ol>
<p><strong>第二次启动流程（异常）</strong>：</p>
<ol>
<li class="">停止第一次的GStreamer进程</li>
<li class="">3A服务器还在运行，但进入了某种等待状态</li>
<li class="">IQ参数缓冲区已经被消费</li>
<li class="">立即重启GStreamer</li>
<li class="">ISP请求IQ参数</li>
<li class=""><strong>3A服务器来不及响应或状态异常</strong></li>
<li class="">ISP使用默认参数处理第一帧</li>
<li class="">出现<code>no first iq setting</code>警告</li>
<li class="">色彩偏暗偏绿</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="解决方案">解决方案<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88" class="hash-link" aria-label="解决方案的直接链接" title="解决方案的直接链接" translate="no">​</a></h3>
<p>问题的根源是：<strong>3A服务器在摄像头第一次运行后进入异常状态，无法正确响应第二次启动的IQ参数请求</strong>。</p>
<p>最终的解决方法很简单：<strong>每次启动摄像头前，重启3A服务器</strong>。</p>
<p>我编写了一个封装脚本：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#!/bin/sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "=== Starting Camera with 3A Server Reset ==="</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 1. 停止所有摄像头进程</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pkill -9 gst-launch 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 2. 重启3A服务器</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">killall rkaiq_3A_server 2&gt;/dev/null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rm -f /tmp/.rkaiq_3A*</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 3. 启动3A服务器</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/etc/init.d/S40rkaiq_3A start</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Waiting for 3A server to initialize..."</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sleep 5</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 4. 确认3A服务器运行正常</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">if ! pgrep rkaiq_3A_server &gt; /dev/null; then</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    echo "ERROR: 3A server failed to start!"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    exit 1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fi</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "3A server ready, starting camera..."</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 5. 启动摄像头</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 v4l2src device=/dev/video11 ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    video/x-raw,format=NV12,width=640,height=480,framerate=30/1 ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    waylandsink</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "Camera stopped"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">exit 0</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="验证结果">验证结果<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E9%AA%8C%E8%AF%81%E7%BB%93%E6%9E%9C" class="hash-link" aria-label="验证结果的直接链接" title="验证结果的直接链接" translate="no">​</a></h3>
<p>使用新脚本后，连续多次启动摄像头，色彩始终正常，日志中不再出现<code>no first iq setting</code>或超时错误。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="经验总结">经验总结<a href="https://zephyr.100ask.org/blog/opencv-cpu-gesture#%E7%BB%8F%E9%AA%8C%E6%80%BB%E7%BB%93" class="hash-link" aria-label="经验总结的直接链接" title="经验总结的直接链接" translate="no">​</a></h3>
<ol>
<li class="">
<p><strong>对比日志是发现问题的关键</strong>：通过对比正常和异常情况的日志，快速定位到<code>no first iq setting</code>这个关键线索</p>
</li>
<li class="">
<p><strong>系统性诊断</strong>：不要盲目尝试，先检查各个组件（IQ文件、3A服务器、设备节点）的状态</p>
</li>
<li class="">
<p><strong>前台运行看详细日志</strong>：很多后台服务的问题需要前台运行才能看到详细输出</p>
</li>
<li class="">
<p><strong>理解组件间的协作关系</strong>：RK平台的摄像头涉及ISP驱动、3A服务器、IQ参数文件三者的协作，任何一个环节出问题都会导致异常</p>
</li>
<li class="">
<p><strong>状态管理很重要</strong>：嵌入式系统的服务重启问题往往是状态机管理不当导致的，彻底重置是最可靠的方案。</p>
</li>
</ol>]]></content:encoded>
            <category>OpenCV</category>
            <category>手势识别</category>
            <category>CPU推理</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 测评二：手势识别编程环境搭建与屏幕调试]]></title>
            <link>https://zephyr.100ask.org/blog/gesture-env-screen</link>
            <guid>https://zephyr.100ask.org/blog/gesture-env-screen</guid>
            <pubDate>Sat, 22 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[安装手势识别系统必要工具并完成屏幕调试，为后续手势识别实战打基础。]]></description>
            <content:encoded><![CDATA[<p>本次测评我将会安装手势识别系统的必要工具和调试屏幕</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="硬件与环境准备">硬件与环境准备<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E7%A1%AC%E4%BB%B6%E4%B8%8E%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87" class="hash-link" aria-label="硬件与环境准备的直接链接" title="硬件与环境准备的直接链接" translate="no">​</a></h2>
<p>在开始之前，我们先明确手头的装备和环境：</p>
<ul>
<li class="">
<p><strong>核心板</strong>：Dshanpi-A1，主控为瑞芯微RK3576芯片。</p>
</li>
<li class="">
<p><strong>屏幕</strong>：一块480x800分辨率的MIPI屏幕。</p>
</li>
<li class="">
<p><strong>系统</strong>：Buildroot Linux系统。</p>
</li>
<li class="">
<p><strong>官方的SDK</strong></p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="安装开发工具">安装开发工具<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E5%AE%89%E8%A3%85%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7" class="hash-link" aria-label="安装开发工具的直接链接" title="安装开发工具的直接链接" translate="no">​</a></h2>
<p>下面是本次的清单：</p>
<table><thead><tr><th>软件包/配置类别</th><th>推荐选项与作用</th></tr></thead><tbody><tr><td>Python环境</td><td>python3: 核心解释器。 python-pip: 用于安装未包含在Buildroot中的Python包。 python-numpy: 为OpenCV等库提供高效的数值计算支持。 python-setuptools: 一些Python包的基础构建依赖。</td></tr><tr><td>计算机视觉与图像处理</td><td>opencv4: 务必启用 python3 支持。提供核心的计算机视觉库，用于图像处理和手势识别算法。 opencv4 贡献模块: 包含额外的、更先进的算法。</td></tr><tr><td>摄像头与显示支持</td><td>gstreamer1 及相关插件: 构建摄像头图像采集和屏幕显示的管道。 gst1-plugins-base, gst1-plugins-good, gst1-plugins-bad, gst1-plugins-ugly: 提供丰富的编解码器和功能元件。 gst1-python: 允许在Python中创建和操作GStreamer管道。</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sdk配置流程">SDK配置流程<a href="https://zephyr.100ask.org/blog/gesture-env-screen#sdk%E9%85%8D%E7%BD%AE%E6%B5%81%E7%A8%8B" class="hash-link" aria-label="SDK配置流程的直接链接" title="SDK配置流程的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-选择芯片类型">1. 选择芯片类型<a href="https://zephyr.100ask.org/blog/gesture-env-screen#1-%E9%80%89%E6%8B%A9%E8%8A%AF%E7%89%87%E7%B1%BB%E5%9E%8B" class="hash-link" aria-label="1. 选择芯片类型的直接链接" title="1. 选择芯片类型的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./build.sh chip</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-进入buildroot配置">2. 进入buildroot配置<a href="https://zephyr.100ask.org/blog/gesture-env-screen#2-%E8%BF%9B%E5%85%A5buildroot%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="2. 进入buildroot配置的直接链接" title="2. 进入buildroot配置的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd buildroot</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make menuconfig</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-选择target-packages">3. 选择Target packages<a href="https://zephyr.100ask.org/blog/gesture-env-screen#3-%E9%80%89%E6%8B%A9target-packages" class="hash-link" aria-label="3. 选择Target packages的直接链接" title="3. 选择Target packages的直接链接" translate="no">​</a></h3>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-安装python环境">4. 安装Python环境<a href="https://zephyr.100ask.org/blog/gesture-env-screen#4-%E5%AE%89%E8%A3%85python%E7%8E%AF%E5%A2%83" class="hash-link" aria-label="4. 安装Python环境的直接链接" title="4. 安装Python环境的直接链接" translate="no">​</a></h3>
<p>当找不到安装路径时，可按<code>/</code>键进入搜索：</p>
<p>输入<code>python3</code>进行搜索：</p>
<p>进入显示的Location路径进行配置：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-保存配置并编译">5. 保存配置并编译<a href="https://zephyr.100ask.org/blog/gesture-env-screen#5-%E4%BF%9D%E5%AD%98%E9%85%8D%E7%BD%AE%E5%B9%B6%E7%BC%96%E8%AF%91" class="hash-link" aria-label="5. 保存配置并编译的直接链接" title="5. 保存配置并编译的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">make</span><br></div></code></pre></div></div>
<p>回到SDK主目录运行：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./build.sh rootfs</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./build.sh updateimg</span><br></div></code></pre></div></div>
<p>最后烧录运行到开发板</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="开发板调试">开发板调试<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E5%BC%80%E5%8F%91%E6%9D%BF%E8%B0%83%E8%AF%95" class="hash-link" aria-label="开发板调试的直接链接" title="开发板调试的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="检查工具安装情况">检查工具安装情况<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E6%A3%80%E6%9F%A5%E5%B7%A5%E5%85%B7%E5%AE%89%E8%A3%85%E6%83%85%E5%86%B5" class="hash-link" aria-label="检查工具安装情况的直接链接" title="检查工具安装情况的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">python3 --version</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pip3 --version</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python3 -c "import numpy; print('NumPy version:', numpy.__version__)"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">python3 -c "import cv2; print('OpenCV version:', cv2.__version__)"</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="屏幕调试">屏幕调试<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E5%B1%8F%E5%B9%95%E8%B0%83%E8%AF%95" class="hash-link" aria-label="屏幕调试的直接链接" title="屏幕调试的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题分析">问题分析<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90" class="hash-link" aria-label="问题分析的直接链接" title="问题分析的直接链接" translate="no">​</a></h3>
<p>系统已运行Weston合成器，这意味着我们有一个图形界面环境。尝试直接操作FrameBuffer(/dev/fb0)无效，因为Weston已占用显示接口。</p>
<p>通过系统检查发现：</p>
<ul>
<li class=""><code>/dev/fb0</code>设备存在</li>
<li class="">屏幕状态为<code>connected</code></li>
<li class="">分辨率为480x800</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="解决方案gstreamer--wayland">解决方案：GStreamer + Wayland<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88gstreamer--wayland" class="hash-link" aria-label="解决方案：GStreamer + Wayland的直接链接" title="解决方案：GStreamer + Wayland的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="gstreamer基础测试">GStreamer基础测试<a href="https://zephyr.100ask.org/blog/gesture-env-screen#gstreamer%E5%9F%BA%E7%A1%80%E6%B5%8B%E8%AF%95" class="hash-link" aria-label="GStreamer基础测试的直接链接" title="GStreamer基础测试的直接链接" translate="no">​</a></h4>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 videotestsrc pattern=smpte ! video/x-raw,width=480,height=800 ! waylandsink sync=false</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="摄像头直连显示测试">摄像头直连显示测试<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E6%91%84%E5%83%8F%E5%A4%B4%E7%9B%B4%E8%BF%9E%E6%98%BE%E7%A4%BA%E6%B5%8B%E8%AF%95" class="hash-link" aria-label="摄像头直连显示测试的直接链接" title="摄像头直连显示测试的直接链接" translate="no">​</a></h4>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 v4l2src device=/dev/video11 ! video/x-raw,width=640,height=480 ! videoconvert ! waylandsink sync=false</span><br></div></code></pre></div></div>
<blockquote>
<p>注意：请将device参数替换为您的摄像头设备节点</p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="测试脚本">测试脚本<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E6%B5%8B%E8%AF%95%E8%84%9A%E6%9C%AC" class="hash-link" aria-label="测试脚本的直接链接" title="测试脚本的直接链接" translate="no">​</a></h3>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">#!/usr/bin/env python3</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># fixed_display_test.py</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> subprocess</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> time</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> os</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">check_camera_devices</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#e3116c">"""检查可用的摄像头设备"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"=== 摄像头设备检查 ==="</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">try</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># 使用v4l2-ctl检查设备</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> subprocess</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">run</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"v4l2-ctl"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"--list-devices"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                        capture_output</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> text</span><span class="token operator" style="color:#393A34">=</span><span class="token boolean" style="color:#36acaa">True</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">returncode </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"找到的视频设备:"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">n            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">stdout</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">else</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"v4l2-ctl命令执行失败"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">except</span><span class="token plain"> Exception </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"检查摄像头设备失败: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">e</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 测试常见的摄像头设备</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    camera_devices </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"/dev/video11"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/dev/video0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/dev/video1"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/dev/video2"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"\n测试摄像头设备:"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> device </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> camera_devices</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">exists</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">device</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"测试设备: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">device</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">try</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic"># 尝试使用GStreamer测试摄像头</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                cmd </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  </span><span class="token string" style="color:#e3116c">"gst-launch-1.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  </span><span class="token string" style="color:#e3116c">"-v"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  </span><span class="token string" style="color:#e3116c">"v4l2src"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"device=</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">device</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  </span><span class="token string" style="color:#e3116c">"video/x-raw,width=640,height=480,framerate=15/1"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  </span><span class="token string" style="color:#e3116c">"videoconvert"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  </span><span class="token string" style="color:#e3116c">"waylandsink"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"sync=false"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                process </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> subprocess</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Popen</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cmd</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># 显示3秒</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">terminate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">wait</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f" </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">device</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">: 摄像头工作正常"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> device</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">except</span><span class="token plain"> Exception </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">device</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">: 测试失败 - </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">e</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">else</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">device</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">: 设备不存在"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">test_static_patterns</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#e3116c">"""测试静态图案（不会变化）"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"\n=== 静态图案测试 ==="</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 设置Wayland环境</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    os</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">environ</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'WAYLAND_DISPLAY'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'wayland-0'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 测试静态图案（不会变化）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    static_patterns </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"smpte100"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"SMPTE 100%色彩条"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"ball"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"时钟图案"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"blink"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"闪烁图案"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"pinwheel"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"风车图案"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"spokes"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"辐条图案"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> pattern</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> description </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> static_patterns</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"显示: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">description</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">try</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            cmd </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"gst-launch-1.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"videotestsrc"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:#e3116c">f"pattern=</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">pattern</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"video/x-raw,width=480,height=800,framerate=15/1"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"waylandsink"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"sync=false"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            process </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> subprocess</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Popen</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cmd</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">terminate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">wait</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">description</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> 显示成功"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">except</span><span class="token plain"> Exception </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">description</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> 显示失败: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">e</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">test_custom_resolution</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:#e3116c">"""测试自定义分辨率显示"""</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"\n=== 自定义分辨率测试 ==="</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    resolutions </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">480</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">800</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"竖屏 480x800"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">800</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">480</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"横屏 800x480"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">640</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">480</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"标准 640x480"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">400</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">800</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"竖屏 400x800"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> width</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> height</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> desc </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> resolutions</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"测试分辨率: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">desc</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">try</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            cmd </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"gst-launch-1.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"videotestsrc"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"pattern=smpte100"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string-interpolation string" style="color:#e3116c">f"video/x-raw,width=</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">width</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">,height=</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">height</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">,framerate=15/1"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"videoconvert"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"!"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token string" style="color:#e3116c">"waylandsink"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"sync=false"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            process </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> subprocess</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Popen</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cmd</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">terminate</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">wait</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f" </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">desc</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> 显示成功"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">except</span><span class="token plain"> Exception </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f" </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">desc</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c"> 显示失败: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">e</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> __name__ </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"__main__"</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"="</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 1. 检查摄像头</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    camera_device </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> check_camera_devices</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 2. 测试静态图案</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    test_static_patterns</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># 3. 测试不同分辨率</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    test_custom_resolution</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"\n"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"="</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> camera_device</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-interpolation string" style="color:#e3116c">f"可用的摄像头设备: </span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">{</span><span class="token string-interpolation interpolation">camera_device</span><span class="token string-interpolation interpolation punctuation" style="color:#393A34">}</span><span class="token string-interpolation string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"未找到可用的摄像头设备"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">print</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"所有测试完成"</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="运行结果">运行结果<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E8%BF%90%E8%A1%8C%E7%BB%93%E6%9E%9C" class="hash-link" aria-label="运行结果的直接链接" title="运行结果的直接链接" translate="no">​</a></h3>
<blockquote>
<p>演示视频我会放在附件里面</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="番外篇filezilla文件传输">番外篇：FileZilla文件传输<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E7%95%AA%E5%A4%96%E7%AF%87filezilla%E6%96%87%E4%BB%B6%E4%BC%A0%E8%BE%93" class="hash-link" aria-label="番外篇：FileZilla文件传输的直接链接" title="番外篇：FileZilla文件传输的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="filezilla连接设置">FileZilla连接设置<a href="https://zephyr.100ask.org/blog/gesture-env-screen#filezilla%E8%BF%9E%E6%8E%A5%E8%AE%BE%E7%BD%AE" class="hash-link" aria-label="FileZilla连接设置的直接链接" title="FileZilla连接设置的直接链接" translate="no">​</a></h3>
<p><a href="https://filezilla-project.org/" target="_blank" rel="noopener noreferrer" class="">FileZilla - The free FTP solution</a></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="检查ssh服务">检查SSH服务<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E6%A3%80%E6%9F%A5ssh%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="检查SSH服务的直接链接" title="检查SSH服务的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ss -tuln | grep 22</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="网络共享设置">网络共享设置<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E7%BD%91%E7%BB%9C%E5%85%B1%E4%BA%AB%E8%AE%BE%E7%BD%AE" class="hash-link" aria-label="网络共享设置的直接链接" title="网络共享设置的直接链接" translate="no">​</a></h3>
<p>选择能上网的网络，点击属性：</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="连接开发板">连接开发板<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E8%BF%9E%E6%8E%A5%E5%BC%80%E5%8F%91%E6%9D%BF" class="hash-link" aria-label="连接开发板的直接链接" title="连接开发板的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ifconfig</span><br></div></code></pre></div></div>
<p>使用FileZilla连接：</p>
<ul>
<li class="">IP：开发板IP地址</li>
<li class="">用户名：root</li>
<li class="">密码：rockchip</li>
<li class="">端口：22</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://zephyr.100ask.org/blog/gesture-env-screen#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>回顾整个调试过程，以下几个关键点值得特别注意：</p>
<ol>
<li class="">
<p><strong>显示路径选择</strong>：在运行Weston这类合成器的系统上，优先使用GStreamer + waylandsink的方案来显示图像，而非直接操作FrameBuffer。</p>
</li>
<li class="">
<p><strong>摄像头设备节点</strong>：务必使用<code>v4l2-ctl --list-devices</code>命令确认摄像头对应的设备节点，并在代码中正确指定。</p>
</li>
<li class="">
<p><strong>屏幕分辨率</strong>：注意系统识别到的屏幕分辨率（可通过<code>cat /sys/class/drm/card0-DSI-1/modes</code>查询）可能与物理分辨率略有不同，在创建显示帧时需以此为准或进行调整。</p>
</li>
</ol>
<p>至此，我们成功地在Dshanpi A1开发板上搭建起了手势识别的编程环境，并解决了MIPI屏幕和摄像头的显示问题。虽然过程曲折，但为后续实际编写手势识别算法奠定了坚实的基础。希望我的这些经验能对大家有所帮助！</p>]]></content:encoded>
            <category>手势识别</category>
            <category>屏幕</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 测评一：构建 buildroot 系统调试 IMX415 摄像头]]></title>
            <link>https://zephyr.100ask.org/blog/buildroot-imx415-camera</link>
            <guid>https://zephyr.100ask.org/blog/buildroot-imx415-camera</guid>
            <pubDate>Thu, 20 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[基于 RK3576 的 DshanPi-A1 构建 buildroot 系统，调试 IMX415 摄像头并解决常见问题。]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="板子介绍">板子介绍<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E6%9D%BF%E5%AD%90%E4%BB%8B%E7%BB%8D" class="hash-link" aria-label="板子介绍的直接链接" title="板子介绍的直接链接" translate="no">​</a></h2>
<p>DshanPi-A1是深圳百问网(韦东山团队)开发的一款高性能AI嵌入式开发板，基于瑞芯微RK3576芯片设计，专为AI教育、边缘计算和智能设备开发打造。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="核心参数">核心参数<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E6%A0%B8%E5%BF%83%E5%8F%82%E6%95%B0" class="hash-link" aria-label="核心参数的直接链接" title="核心参数的直接链接" translate="no">​</a></h2>
<table><thead><tr><th>参数项</th><th>规格</th></tr></thead><tbody><tr><td>主控芯片</td><td>瑞芯微RK3576，8nm工艺，八核64位4×Cortex-A72(2.2GHz)+4×Cortex-A53(1.8GHz)瑞芯微电子股份有限公司</td></tr><tr><td>AI算力</td><td>内置独立NPU，6TOPS计算能力，支持INT4/INT8/INT16混合运算</td></tr><tr><td>内存/存储</td><td>板载LPDDR4/4X内存支持eMMC、UFS存储扩展SD卡插槽</td></tr><tr><td>显示接口</td><td>HDMIv2.1/eDPv1.3组合接口MIPIDSI(4通道)瑞芯微电子股份有限公司</td></tr><tr><td>视频解码</td><td>支持8K@30fps、4K@120fps高清视频</td></tr><tr><td>网络连接</td><td>支持WiFi6/BLE5.2(需外接模块)千兆网口(部分版本)</td></tr><tr><td>USB接口</td><td>多个USB3.0/2.0(Type-C和A型)瑞芯微电子股份有限公司</td></tr><tr><td>其他接口</td><td>UART、I2C、SPI、GPIO、音频接口、CAN总线(部分版本)</td></tr><tr><td>电源</td><td>支持30WPD快充(Type-C接口)</td></tr><tr><td>尺寸</td><td>紧凑型设计(具体尺寸未公开)</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="产品特点">产品特点<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E4%BA%A7%E5%93%81%E7%89%B9%E7%82%B9" class="hash-link" aria-label="产品特点的直接链接" title="产品特点的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1️⃣-强大的ai处理能力">1️⃣ 强大的AI处理能力<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#1%EF%B8%8F%E2%83%A3-%E5%BC%BA%E5%A4%A7%E7%9A%84ai%E5%A4%84%E7%90%86%E8%83%BD%E5%8A%9B" class="hash-link" aria-label="1️⃣ 强大的AI处理能力的直接链接" title="1️⃣ 强大的AI处理能力的直接链接" translate="no">​</a></h3>
<p>· 6TOPS独立NPU可流畅运行DeepSeek、Qwen等轻量级大语言模型</p>
<p>· 支持主流AI框架(TensorFlow、PyTorch、MXNet等)</p>
<p>· 适用于图像识别、语音处理、智能监控等AI应用开发</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2️⃣-丰富的多媒体性能">2️⃣ 丰富的多媒体性能<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#2%EF%B8%8F%E2%83%A3-%E4%B8%B0%E5%AF%8C%E7%9A%84%E5%A4%9A%E5%AA%92%E4%BD%93%E6%80%A7%E8%83%BD" class="hash-link" aria-label="2️⃣ 丰富的多媒体性能的直接链接" title="2️⃣ 丰富的多媒体性能的直接链接" translate="no">​</a></h3>
<p>· 支持8K视频解码，可作为高清媒体中心</p>
<p>· HDMIIN功能可将开发板作为电脑副屏使用</p>
<p>· 内置音频编解码器，支持3.5mm音频输出</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3️⃣-完善的开发支持">3️⃣ 完善的开发支持<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#3%EF%B8%8F%E2%83%A3-%E5%AE%8C%E5%96%84%E7%9A%84%E5%BC%80%E5%8F%91%E6%94%AF%E6%8C%81" class="hash-link" aria-label="3️⃣ 完善的开发支持的直接链接" title="3️⃣ 完善的开发支持的直接链接" translate="no">​</a></h3>
<p>· 搭载DShanOS系统(百问网自研Linux发行版)</p>
<p>· 配套免费教学课程和文档，降低学习门槛</p>
<p>· 支持Armbian系统，提供官方镜像下载</p>
<p>· 提供完整SDK和示例代码，便于二次开发</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4️⃣-灵活的扩展能力">4️⃣ 灵活的扩展能力<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#4%EF%B8%8F%E2%83%A3-%E7%81%B5%E6%B4%BB%E7%9A%84%E6%89%A9%E5%B1%95%E8%83%BD%E5%8A%9B" class="hash-link" aria-label="4️⃣ 灵活的扩展能力的直接链接" title="4️⃣ 灵活的扩展能力的直接链接" translate="no">​</a></h3>
<p>· 引出全部GPIO接口，方便连接各类传感器和执行器</p>
<p>· 支持多种通信协议，适合IoT应用开发</p>
<p>· 可外接摄像头、显示屏、WiFi/4G模块等扩展功能</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="应用场景">应用场景<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF" class="hash-link" aria-label="应用场景的直接链接" title="应用场景的直接链接" translate="no">​</a></h2>
<p><strong>·</strong> AI教育与学习：适合嵌入式AI课程教学和实验</p>
<p><strong>·</strong> 边缘计算设备：可部署轻量级AI模型，实现本地智能决策</p>
<p><strong>·</strong> 智能家居中控：构建高性能、低功耗的智能家居控制中心</p>
<p><strong>·</strong> 工业自动化：适用于智能设备监控和数据采集</p>
<p><strong>·</strong> 商业显示：支持8K显示，可用于广告机和信息发布系统</p>
<p><strong>·</strong> AI视觉系统：可用于人脸识别、物体检测等场景</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="配套资源">配套资源<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E9%85%8D%E5%A5%97%E8%B5%84%E6%BA%90" class="hash-link" aria-label="配套资源的直接链接" title="配套资源的直接链接" translate="no">​</a></h2>
<p><strong>·</strong> 官方文档站点：<a href="https://wiki.dshanpi.org/docs/dshanpi-a1/" target="_blank" rel="noopener noreferrer" class="">https://wiki.dshanpi.org/docs/dshanpi-a1/</a></p>
<p><strong>·</strong> 开发社区：韦东山嵌入式开发者社区(<a href="https://100ask.org/" target="_blank" rel="noopener noreferrer" class="">100ask.org</a>)</p>
<p><strong>·</strong> QQ技术交流群：798273638</p>
<p><strong>·</strong> 免费教程：提供从基础到高级的AI开发课程</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="buildroot-sdk安装">buildroot SDK安装<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#buildroot-sdk%E5%AE%89%E8%A3%85" class="hash-link" aria-label="buildroot SDK安装的直接链接" title="buildroot SDK安装的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-官方虚拟机获取">1. 官方虚拟机获取<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#1-%E5%AE%98%E6%96%B9%E8%99%9A%E6%8B%9F%E6%9C%BA%E8%8E%B7%E5%8F%96" class="hash-link" aria-label="1. 官方虚拟机获取的直接链接" title="1. 官方虚拟机获取的直接链接" translate="no">​</a></h3>
<p><a href="https://pan.baidu.com/s/15M8zuHOwl_SITl6cSk_7Vg?pwd=eaax%E6%8F%90%E5%8F%96%E7%A0%81:eaax" target="_blank" rel="noopener noreferrer" class="">https://pan.baidu.com/s/15M8zuHOwl_SITl6cSk_7Vg?pwd=eaax提取码:eaax</a></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-安装打开vmware运行虚拟机">2. 安装打开vmware,运行虚拟机<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#2-%E5%AE%89%E8%A3%85%E6%89%93%E5%BC%80vmware%E8%BF%90%E8%A1%8C%E8%99%9A%E6%8B%9F%E6%9C%BA" class="hash-link" aria-label="2. 安装打开vmware,运行虚拟机的直接链接" title="2. 安装打开vmware,运行虚拟机的直接链接" translate="no">​</a></h3>
<p>进去ubuntu系统，账号密码为ubuntu</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-编译sdk">3. 编译SDK<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#3-%E7%BC%96%E8%AF%91sdk" class="hash-link" aria-label="3. 编译SDK的直接链接" title="3. 编译SDK的直接链接" translate="no">​</a></h3>
<p>打开虚拟机，执行以下命令，进入SDK根目录：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cd ~/100ask-rk3576_SDK/</span><br></div></code></pre></div></div>
<p>选择好配置文件：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./build.sh lunch</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-编译">4. 编译<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#4-%E7%BC%96%E8%AF%91" class="hash-link" aria-label="4. 编译的直接链接" title="4. 编译的直接链接" translate="no">​</a></h3>
<p>运行下列命令</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./build.sh</span><br></div></code></pre></div></div>
<p>等待编译结束</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="设备树修改打开摄像头节点">设备树修改打开摄像头节点<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E8%AE%BE%E5%A4%87%E6%A0%91%E4%BF%AE%E6%94%B9%E6%89%93%E5%BC%80%E6%91%84%E5%83%8F%E5%A4%B4%E8%8A%82%E7%82%B9" class="hash-link" aria-label="设备树修改打开摄像头节点的直接链接" title="设备树修改打开摄像头节点的直接链接" translate="no">​</a></h2>
<p>进入</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">/home/ubuntu/100ask-rk3576_SDK/kernel/arch/arm64/boot/dts/rockchip</span><br></div></code></pre></div></div>
<p>修改图片中的文件</p>
<p>改为if1</p>
<p>回到sdk目录使用</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./build.sh kernel</span><br></div></code></pre></div></div>
<p>最后再</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./build.sh updateimg</span><br></div></code></pre></div></div>
<p>最后上传烧录（记得进入MASKROM）</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="成果展示">成果展示<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E6%88%90%E6%9E%9C%E5%B1%95%E7%A4%BA" class="hash-link" aria-label="成果展示的直接链接" title="成果展示的直接链接" translate="no">​</a></h2>
<p>但是依然有bug但是屏幕摄像头色彩还是显示不对。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="问题解决">问题解决<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3" class="hash-link" aria-label="问题解决的直接链接" title="问题解决的直接链接" translate="no">​</a></h2>
<p>最开始我是怀疑是摄像头的.xml（.json）没有加载出来，通过调试了好久仍没有结果但是没有结果</p>
<p>经过了多方面的调试最终我找到了解决方案:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第一步从media-ctl输出发现关键线索">第一步：从media-ctl输出发现关键线索<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E7%AC%AC%E4%B8%80%E6%AD%A5%E4%BB%8Emedia-ctl%E8%BE%93%E5%87%BA%E5%8F%91%E7%8E%B0%E5%85%B3%E9%94%AE%E7%BA%BF%E7%B4%A2" class="hash-link" aria-label="第一步：从media-ctl输出发现关键线索的直接链接" title="第一步：从media-ctl输出发现关键线索的直接链接" translate="no">​</a></h3>
<p>在<code>media-ctl -p -d /dev/media0</code>输出中，我注意到了这个关键信息：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">entity 63: m00_b_rk628-csi9-0051 (1 pad, 1 link)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	type V4L2 subdev subtype Sensor flags 0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	device node name /dev/v4l-subdev2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	 pad 0: Source</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	  [fmt:UYVY8_2X8/64x64@10000/600000 field:none]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	  -&gt; "rockchip-csi2-dphy0":0 [ENABLED] ←注意这里的[ENABLED]</span><br></div></code></pre></div></div>
<p><strong>分析点</strong>：</p>
<p>· 系统中存在一个rk628-csi传感器实体</p>
<p>· 它的链路状态是[ENABLED]，意味着它正在占用CSI硬件资源</p>
<p>· 但分辨率只有64x64，这显然不是正常的摄像头输出</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第二步从dmesg日志发现imx415驱动正常">第二步：从dmesg日志发现IMX415驱动正常<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E7%AC%AC%E4%BA%8C%E6%AD%A5%E4%BB%8Edmesg%E6%97%A5%E5%BF%97%E5%8F%91%E7%8E%B0imx415%E9%A9%B1%E5%8A%A8%E6%AD%A3%E5%B8%B8" class="hash-link" aria-label="第二步：从dmesg日志发现IMX415驱动正常的直接链接" title="第二步：从dmesg日志发现IMX415驱动正常的直接链接" translate="no">​</a></h3>
<p>从<code>dmesg | grep -i imx415</code>输出中：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[3.459474] imx415 3-0037: Detected imx415 id 0000e0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[3.515523] imx415 3-0037: Consider updating driver imx415 to match on endpoints</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[3.515557] rockchip-csi2-dphy csi2-dphy3: dphy3 matches m01_f_imx415 3-0037: bustype 5</span><br></div></code></pre></div></div>
<p><strong>分析点</strong>：</p>
<p>· IMX415传感器被正确检测到（ID:0000e0）</p>
<p>· 驱动加载成功，甚至建立了与CSI-DPHY的匹配关系</p>
<p>· 但没有出现V4L2子设备创建成功的消息</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第三步从设备树结构推断硬件连接">第三步：从设备树结构推断硬件连接<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E7%AC%AC%E4%B8%89%E6%AD%A5%E4%BB%8E%E8%AE%BE%E5%A4%87%E6%A0%91%E7%BB%93%E6%9E%84%E6%8E%A8%E6%96%AD%E7%A1%AC%E4%BB%B6%E8%BF%9E%E6%8E%A5" class="hash-link" aria-label="第三步：从设备树结构推断硬件连接的直接链接" title="第三步：从设备树结构推断硬件连接的直接链接" translate="no">​</a></h3>
<p>从设备树片段：</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">csi2_dphy3 </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    port@</span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        mipi_in_ucam3</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> endpoint@</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            remote</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">endpoint </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">imx415_out0</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> ←IMX415连接到这里</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            data</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">lanes </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">4</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    port@</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        csidphy3_out</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> endpoint@</span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            remote</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">endpoint </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">mipi3_csi2_input</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p><strong>分析点</strong>：</p>
<p>· IMX415通过CSI-DPHY3连接到系统</p>
<p>· 但实际的media-ctl输出显示的是rockchip-csi2-dphy0被占用</p>
<p>· 这表明可能存在多个CSI接口的资源分配问题</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第四步从v4l2子设备缺失推断注册失败">第四步：从V4L2子设备缺失推断注册失败<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E7%AC%AC%E5%9B%9B%E6%AD%A5%E4%BB%8Ev4l2%E5%AD%90%E8%AE%BE%E5%A4%87%E7%BC%BA%E5%A4%B1%E6%8E%A8%E6%96%AD%E6%B3%A8%E5%86%8C%E5%A4%B1%E8%B4%A5" class="hash-link" aria-label="第四步：从V4L2子设备缺失推断注册失败的直接链接" title="第四步：从V4L2子设备缺失推断注册失败的直接链接" translate="no">​</a></h3>
<p>运行检查命令时：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ls /sys/bus/i2c/devices/3-0037/v4l-subdev*/media_device/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 输出：No such file or directory</span><br></div></code></pre></div></div>
<p><strong>分析点</strong>：</p>
<p>· I2C设备3-0037存在且驱动绑定正常</p>
<p>· 但没有创建对应的V4L2子设备</p>
<p>· 这通常意味着驱动探测成功，但后续的V4L2注册失败</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第五步连接所有线索形成完整画面">第五步：连接所有线索形成完整画面<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E7%AC%AC%E4%BA%94%E6%AD%A5%E8%BF%9E%E6%8E%A5%E6%89%80%E6%9C%89%E7%BA%BF%E7%B4%A2%E5%BD%A2%E6%88%90%E5%AE%8C%E6%95%B4%E7%94%BB%E9%9D%A2" class="hash-link" aria-label="第五步：连接所有线索形成完整画面的直接链接" title="第五步：连接所有线索形成完整画面的直接链接" translate="no">​</a></h3>
<p>把以上线索串联起来：</p>
<p><strong>1.</strong> <strong>现象</strong>：IMX415驱动加载但无V4L2设备</p>
<p><strong>2.</strong> <strong>证据1</strong>：rk628-csi占用着CSI链路且状态为[ENABLED]</p>
<p><strong>3.</strong> <strong>证据2</strong>：IMX415 I2C通信正常但媒体设备缺失</p>
<p><strong>4.</strong> <strong>证据3</strong>：设备树显示两者可能共享CSI硬件资源</p>
<p><strong>逻辑推理</strong>：</p>
<p>· 如果IMX415硬件故障→I2C探测应该失败</p>
<p>· 如果IMX415驱动问题→dmesg应该有错误日志</p>
<p>· 如果设备树配置错误→CSI匹配不会成功</p>
<p><strong>·</strong> 唯一合理的解释：硬件资源被其他设备占用</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第六步开始实践">第六步：开始实践<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E7%AC%AC%E5%85%AD%E6%AD%A5%E5%BC%80%E5%A7%8B%E5%AE%9E%E8%B7%B5" class="hash-link" aria-label="第六步：开始实践的直接链接" title="第六步：开始实践的直接链接" translate="no">​</a></h3>
<p>重新编译设备树烧录开发板完美运行！</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://zephyr.100ask.org/blog/buildroot-imx415-camera#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<ol>
<li class="">
<p>嵌入式设备中硬件资源冲突是常见隐性问题，尤其多设备共享 CSI、I2C 等链路时，需重点排查设备占用状态。</p>
</li>
<li class="">
<p>开发过程中应充分利用media-ctl、dmesg等工具，结合设备树配置分析，快速定位资源分配问题，避免盲目调试。</p>
</li>
<li class="">
<p>对于驱动加载正常但功能异常的场景，优先排查硬件资源占用、V4L2 子设备注册等关键环节，缩小问题范围。</p>
</li>
<li class="">
<p>DshanPi-A1 开发板的 CSI 接口资源分配需通过设备树精准配置，修改后需严格遵循 Buildroot 编译流程重新生成镜像，确保配置生效。</p>
</li>
</ol>]]></content:encoded>
            <category>Buildroot</category>
            <category>IMX415</category>
            <category>摄像头</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[RK3576 实现 sox 降噪和 rnnoise 降噪]]></title>
            <link>https://zephyr.100ask.org/blog/sox-rnnoise-denoise</link>
            <guid>https://zephyr.100ask.org/blog/sox-rnnoise-denoise</guid>
            <pubDate>Tue, 18 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[使用 sox 的 noisered 谱减法与 rnnoise AI 模型两种方案处理音频降噪，对比稳态与非稳态噪声效果。]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="概述">概述<a href="https://zephyr.100ask.org/blog/sox-rnnoise-denoise#%E6%A6%82%E8%BF%B0" class="hash-link" aria-label="概述的直接链接" title="概述的直接链接" translate="no">​</a></h2>
<p>音频降噪技术的发展，经历了从对抗物理噪声到智能识别分离的演变。</p>
<p><strong>模拟时代（20世纪中期）</strong></p>
<ul>
<li class=""><strong>杜比A型（1965年）</strong>：开创性的动态降噪技术，采用“压缩-扩张”原理降低磁带本底噪声。</li>
<li class=""><strong>杜比B型（1968年）</strong>：A型的消费简化版，让卡式磁带走入千家万户。</li>
<li class=""><strong>dbx（1971年）</strong>：更激进的压缩-扩张系统，动态范围更大。</li>
<li class=""><strong>后续发展</strong>：Dolby C、SR等更先进的模拟系统相继问世。</li>
</ul>
<p><strong>数字时代早期（1980-1990年代）</strong></p>
<ul>
<li class="">数字信号处理芯片的出现，让实时数字滤波和谱减法成为可能</li>
<li class="">算法开始从时域转向频域处理</li>
<li class="">自适应滤波理论成熟并应用于通信领域</li>
</ul>
<p><strong>数字算法普及期（1990-2010年代）</strong></p>
<ul>
<li class="">个人电脑性能提升，专业音频软件（如Audition、iZotope RX）普及了数字降噪工具</li>
<li class="">心理声学模型的应用提升了降噪音质</li>
<li class="">主动降噪耳机开始商业化（Bose等厂商推动）</li>
</ul>
<p><strong>人工智能时代（2010年代至今）</strong></p>
<ul>
<li class="">深度学习彻底改变了降噪方式，能够处理复杂的非平稳噪声</li>
<li class="">技术广泛应用于视频会议、语音助手、音乐流媒体等领域</li>
<li class="">研究方向从单纯降噪扩展到语音分离、人声提取等精细化任务</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="主要降噪方法">主要降噪方法<a href="https://zephyr.100ask.org/blog/sox-rnnoise-denoise#%E4%B8%BB%E8%A6%81%E9%99%8D%E5%99%AA%E6%96%B9%E6%B3%95" class="hash-link" aria-label="主要降噪方法的直接链接" title="主要降噪方法的直接链接" translate="no">​</a></h3>
<p><strong>基于频谱的降噪</strong>
核心思路是在频域上区分噪声和信号：</p>
<ul>
<li class="">谱减法：从音频中减去噪声频谱</li>
<li class="">维纳滤波：更优的统计降噪方法</li>
<li class="">掩蔽效应法：利用人耳特性保留音质</li>
</ul>
<p><strong>机器学习降噪</strong></p>
<ul>
<li class="">使用深度学习模型（RNN、CNN、Transformer等）从数据中学习降噪</li>
<li class="">能够有效处理复杂场景和非平稳噪声</li>
<li class="">支持端到端的波形或频谱处理</li>
</ul>
<p><strong>滤波降噪</strong></p>
<ul>
<li class="">自适应滤波：需要参考噪声信号，用于电话和主动降噪耳机</li>
<li class="">固定滤波：去除特定频率噪声，如50Hz工频干扰</li>
</ul>
<p><strong>多麦克风技术</strong></p>
<ul>
<li class="">通过麦克风阵列形成指向性波束</li>
<li class="">增强目标方向声音，抑制环境噪声</li>
<li class="">常见于手机、会议设备和智能音箱</li>
</ul>
<p><strong>传统处理方法</strong></p>
<ul>
<li class="">噪声门：通过阈值静音低电平信号</li>
<li class="">简单有效，常用于音乐制作和直播场景</li>
</ul>
<hr>
<p>下面使用两种方法来进行音频降噪的处理：<strong>sox降噪</strong>和<strong>rnnoise降噪</strong>。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sox降噪">sox降噪<a href="https://zephyr.100ask.org/blog/sox-rnnoise-denoise#sox%E9%99%8D%E5%99%AA" class="hash-link" aria-label="sox降噪的直接链接" title="sox降噪的直接链接" translate="no">​</a></h2>
<p>sox的 <code>noisered</code> 是一个经典的、基于噪声采样和谱减法的非AI降噪工具，原理直观，实现相对简单，对稳态噪声（如风扇声、空调声、恒定电流声）效果显著，<strong><code>noisered</code> 效果器</strong>是其降噪的核心，核心原理步骤如下：</p>
<ol>
<li class=""><strong>分析/训练阶段</strong>：核心是<strong>建立噪声指纹</strong>。SoX需要先“学习”噪声是什么样的。可以提供一段<strong>纯噪声片段</strong>（例如录音前的环境底噪），或者让它自动检测音频中能量较低的“静音”部分。它会分析这些片段，计算出一个<strong>平均噪声频谱</strong>，并保存为一个<code>.prof</code>文件。这个文件就是后续降噪的参考基准。</li>
<li class=""><strong>降噪处理阶段</strong>：核心是<strong>频谱减法</strong>。<!-- -->
<ul>
<li class=""><strong>分帧与变换</strong>：将连续的音频信号切成短时重叠的帧，并通过FFT转换到<strong>频域</strong>。在频域，信号表现为不同频率的能量（幅度）和相位。</li>
<li class=""><strong>关键操作 - 谱减法</strong>：这是最核心的一步。算法会比较当前帧的频谱和之前学到的<strong>噪声样本频谱</strong>。基本思想非常简单：<strong><code>干净信号频谱 ≈ 带噪信号频谱 - 噪声频谱</code></strong>。<!-- -->
<ul>
<li class=""><strong>能量相减</strong>：主要操作是在<strong>能量/幅度谱</strong>上进行减法。当前帧某个频率的能量如果低于或接近噪声样本在该频率的能量，就会被大幅抑制；如果远高于，则会被保留。</li>
<li class=""><strong>相位保留</strong>：相位信息对于重建声音波形至关重要。谱减法通常<strong>不改变原始信号的相位</strong>，直接用降噪后的幅度谱和原始相位谱合成新信号。</li>
<li class=""><strong>抑制因子</strong>：SoX的 <code>amount</code> 参数（0.0 到 1.0）控制减法力度。<code>0.5</code>意味着只减去一半的噪声能量，更为保守，能减少失真。</li>
</ul>
</li>
<li class=""><strong>合成与输出</strong>：处理后的频域数据通过IFFT变回时域波形，再通过<strong>重叠相加</strong>方法将短时帧合成连续的音频信号，最终得到降噪后的音频。</li>
</ul>
</li>
</ol>
<p>看起来很复杂，但操作起来很简单，现在使用sox命令操纵一下就明白了。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="sox命令降噪">sox命令降噪<a href="https://zephyr.100ask.org/blog/sox-rnnoise-denoise#sox%E5%91%BD%E4%BB%A4%E9%99%8D%E5%99%AA" class="hash-link" aria-label="sox命令降噪的直接链接" title="sox命令降噪的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#noise.wav是背景噪声，在安静状态下录制的一段10s的音频</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ls</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	noise.wav speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#生成噪声profile（手动截取纯噪声5-10秒）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sox noise.wav -n noiseprof noise.prof</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#降噪，0.21是经验值，绝大部分素材不会出现水声</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sox speech.wav noisered_speech.wav noisered noise.prof 0.21</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#对比播放，可以看出效果明显</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay noise.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Playing WAVE 'noise.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Playing WAVE 'speech.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay noisered_speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Playing WAVE 'noisered_speech.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo</span><br></div></code></pre></div></div>
<p>只是使用sox命令降噪，无法集成到嵌入式系统中，下面采用C语言，使用sox的库和API来进行音频降噪。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="使用sox的库和api来进行音频降噪">使用sox的库和API来进行音频降噪<a href="https://zephyr.100ask.org/blog/sox-rnnoise-denoise#%E4%BD%BF%E7%94%A8sox%E7%9A%84%E5%BA%93%E5%92%8Capi%E6%9D%A5%E8%BF%9B%E8%A1%8C%E9%9F%B3%E9%A2%91%E9%99%8D%E5%99%AA" class="hash-link" aria-label="使用sox的库和API来进行音频降噪的直接链接" title="使用sox的库和API来进行音频降噪的直接链接" translate="no">​</a></h3>
<p>代码结构如下：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">(base) ubuntu@ubuntu-2204:~/baiwen/sox_noise_reduction$ tree -L 2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── CMakeLists.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── deps</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│&nbsp;&nbsp; ├── include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│&nbsp;&nbsp; └── lib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│&nbsp;&nbsp; ├── custom_effects.h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│&nbsp;&nbsp; └── sox_noise_reduction.h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── Makefile</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── src</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ├── custom_effects.c</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ├── main.c</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    └── sox_noise_reduction.c</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">5 directories, 7 files</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="编译">编译<a href="https://zephyr.100ask.org/blog/sox-rnnoise-denoise#%E7%BC%96%E8%AF%91" class="hash-link" aria-label="编译的直接链接" title="编译的直接链接" translate="no">​</a></h4>
<p>要编译这个demo，需要设置cmakelist.txt中得工具链</p>
<div class="language-cmake codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cmake codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 指定交叉编译器</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_C_COMPILER /home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/host/bin/aarch64-buildroot-linux-gnu-gcc)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_CXX_COMPILER /home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/host/bin/aarch64-buildroot-linux-gnu-g++)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置sysroot</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_SYSROOT /home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/staging)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 添加链接库</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">target_link_libraries(sox_noise_reduction </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    sox</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">)</span><br></div></code></pre></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#ubuntu22.04编译</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(base) ubuntu@ubuntu-2204:~/baiwen/sox_noise_reduction$ make</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Configuring CMake...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- The C compiler identification is GNU 11.4.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Detecting C compiler ABI info</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Detecting C compiler ABI info - done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Check for working C compiler: /usr/bin/cc - skipped</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Detecting C compile features</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Detecting C compile features - done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Configuring done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Generating done</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">-- Build files have been written to: /home/ubuntu/baiwen/sox_noise_reduction/build</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Building with 16 jobs...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[1]: Entering directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[2]: Entering directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[3]: Entering directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[3]: Leaving directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[3]: Entering directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 75%] Building C object CMakeFiles/sox_noise_reduction.dir/src/sox_noise_reduction.c.o</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 75%] Building C object CMakeFiles/sox_noise_reduction.dir/src/custom_effects.c.o</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[ 75%] Building C object CMakeFiles/sox_noise_reduction.dir/src/main.c.o</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[100%] Linking C executable sox_noise_reduction</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[3]: Leaving directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[100%] Built target sox_noise_reduction</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[2]: Leaving directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make[1]: Leaving directory '/home/ubuntu/baiwen/sox_noise_reduction/build'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#make push会通过adb 将sox_noise_reduction可执行文件推送到buildroot的/develo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(base) ubuntu@ubuntu-2204:~/baiwen/sox_noise_reduction$ make push</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Running build/sox_noise_reduction...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">build/sox_noise_reduction: 1 file pushed. 10.6 MB/s (23840 bytes in 0.002s)</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="运行">运行<a href="https://zephyr.100ask.org/blog/sox-rnnoise-denoise#%E8%BF%90%E8%A1%8C" class="hash-link" aria-label="运行的直接链接" title="运行的直接链接" translate="no">​</a></h4>
<p>在rk3576上</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/develop# ls</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">live_life.mp3  noise.wav  sox_noise_reduction  speech.wav</span><br></div></code></pre></div></div>
<p>先在安静环境下录制一段 noise.wav的背景噪声，再对着麦克风说一段话speech.wav</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/develop# ./sox_noise_reduction</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    SoX音频噪声降低处理开始</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    =======================</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    噪声文件:   noise.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    输入文件:   speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    输出文件:   noisered_output.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    降噪敏感度: 0.21</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    -----------------------</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Processing...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    [1/2] Creating noise profile...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Creating noise profile from: noise.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Processing noise profile...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Noise profile created: /tmp/noise_profile_NFk1uN.prof</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    [2/2] Applying noise reduction...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Applying noise reduction to: speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Processing audio with noise reduction...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Noise reduction applied. Output: noisered_output.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Done!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    处理成功! 输出文件: noisered_output.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#使用aplay播放可以对比</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay noise.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">aplay noisered_output.wav</span><br></div></code></pre></div></div>
<p>可以听到 noisered_output.wav明显改善，但还有一些微弱的**“音乐噪声”<strong>，这是采用sox</strong>谱减法<strong>降噪固有的副作用，要完全去除，需要再设计一个</strong>维纳滤波**效果插件，进一步去除。</p>
<p>sox_noise_reduction的使用可以看-h的帮助信息</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/develop# ./sox_noise_reduction -h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">SoX音频噪声降低工具</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">====================</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">使用方法: ./sox_noise_reduction [选项]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">选项:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -n 文件   噪声样本文件 (默认: noise.wav)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -i 文件   输入语音文件 (默认: speech.wav)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -o 文件   输出文件 (默认: noisered_output.wav)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -s 数值   降噪敏感度 0.0-1.0 (默认: 0.21)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -h        显示此帮助信息</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">参数说明:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  敏感度: 0.0表示最强降噪(可能损伤语音)，1.0表示最弱降噪</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  推荐值: 0.21 (经验值，适用于大多数音频素材)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">使用示例:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ./sox_noise_reduction                    # 使用所有默认设置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ./sox_noise_reduction -n mynoise.wav    # 指定噪声文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ./sox_noise_reduction -i myspeech.wav   # 指定输入文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ./sox_noise_reduction -s 0.3            # 调整降噪强度</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ./sox_noise_reduction -o clean.wav      # 指定输出文件</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="rnnoise降噪">rnnoise降噪<a href="https://zephyr.100ask.org/blog/sox-rnnoise-denoise#rnnoise%E9%99%8D%E5%99%AA" class="hash-link" aria-label="rnnoise降噪的直接链接" title="rnnoise降噪的直接链接" translate="no">​</a></h2>
<p><strong>RNNoise</strong> 是一个优秀的开源音频降噪工具，非常适合<strong>入门学习、快速集成和中等性能需求</strong>的场景。</p>
<ol>
<li class=""><strong>技术原理</strong>：<!-- -->
<ul>
<li class="">结合<strong>传统信号处理</strong>（谱分析）与<strong>深度学习</strong>（RNN神经网络）。</li>
<li class="">输入音频分帧→提取特征（如频带能量、基音）→RNN预测每个频带的增益掩码（VAD也集成在其中）→输出降噪后的频谱→重建波形。</li>
</ul>
</li>
<li class=""><strong>轻量化设计</strong>：<!-- -->
<ul>
<li class="">模型仅<strong>约86KB</strong>，适合嵌入式或实时处理。</li>
<li class="">单核CPU即可实时处理。</li>
</ul>
</li>
</ol>
<p><strong>优点</strong>：</p>
<ul>
<li class=""><strong>开源且易用</strong>：代码清晰，提供C语言API，易于集成到各类项目。</li>
<li class=""><strong>低延迟</strong>：帧处理延迟约10ms（默认帧长20ms），适合实时通信。</li>
<li class=""><strong>兼容性强</strong>：无第三方深度学习框架依赖，纯C实现。</li>
<li class=""><strong>语音保护较好</strong>：在抑制稳态噪声（如风扇声）的同时，对语音损伤较小。</li>
</ul>
<p><strong>局限性</strong>：</p>
<ul>
<li class=""><strong>非通用降噪</strong>：主要针对<strong>语音通信优化</strong>，对音乐、突发噪声（如键盘声）效果有限。</li>
<li class=""><strong>参数固定</strong>：模型为通用场景训练，难以针对特定噪声定制。</li>
<li class=""><strong>残留“音乐噪声”</strong>：某些场景下可能引入类似水波的残留噪声。</li>
<li class=""><strong>不支持高采样率</strong>：默认仅支持48kHz/16kHz单声道，音乐降噪需调整。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="编译-1">编译<a href="https://zephyr.100ask.org/blog/sox-rnnoise-denoise#%E7%BC%96%E8%AF%91-1" class="hash-link" aria-label="编译的直接链接" title="编译的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">## 设置交叉编译工具链路径</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export TOOLCHAIN_DIR="/home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/host/bin"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export CC="${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu-gcc"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export CXX="${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu-g++"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export AR="${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu-ar"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export LD="${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu-ld"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export RANLIB="${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu-ranlib"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export STRIP="${TOOLCHAIN_DIR}/aarch64-buildroot-linux-gnu-strip"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置目标架构</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export ARCH="aarch64"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export CROSS_COMPILE="aarch64-buildroot-linux-gnu-"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置sysroot（重要！）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export SYSROOT="/home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/staging"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export CFLAGS="--sysroot=${SYSROOT} -O2"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export LDFLAGS="--sysroot=${SYSROOT}"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "工具链设置完成"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">echo "CC = $CC"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 克隆项目并编译</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">git clone https://github.com/xiph/rnnoise.git</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd rnnoise</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./autogen.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./configure \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --host=aarch64-buildroot-linux-gnu \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --build=x86_64-pc-linux-gnu \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --prefix=$(pwd)/tmp \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --enable-static \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    --enable-shared \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    CFLAGS="--sysroot=${SYSROOT} -O2" \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    LDFLAGS="--sysroot=${SYSROOT}" \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    CC="${CC}" \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    CXX="${CXX}" \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    AR="${AR}" \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    LD="${LD}"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#编译</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#安装到./tmp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make install </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(base) ubuntu@ubuntu-2204:~/rnnoise$ tree -L 2 tmp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    tmp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ├── include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    │&nbsp;&nbsp; └── rnnoise.h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ├── lib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    │&nbsp;&nbsp; ├── librnnoise.a</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    │&nbsp;&nbsp; ├── librnnoise.la</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    │&nbsp;&nbsp; ├── librnnoise.so -&gt; librnnoise.so.0.4.1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    │&nbsp;&nbsp; ├── librnnoise.so.0 -&gt; librnnoise.so.0.4.1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    │&nbsp;&nbsp; ├── librnnoise.so.0.4.1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    │&nbsp;&nbsp; └── pkgconfig</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    └── share</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        └── doc</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">(base) ubuntu@ubuntu-2204:~/rnnoise$ ls examples/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	rnnoise_demo  rnnoise_demo.c  rnnoise_demo.o</span><br></div></code></pre></div></div>
<p>./tmp目录下的文件就是需要使用的编译出来的rnnoise的头文件和库，用来做集成，examples下的rnnoise_demo就是参考实现，还有.c文件可以参考</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">adb push examples/.libs/rnnoise_demo /usr/bin/rnnoise_demo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">adb push  tmp/lib/librnnoise.so* /usr/lib/</span><br></div></code></pre></div></div>
<p>现在可以到开发板进行简单的测试了</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="测试">测试<a href="https://zephyr.100ask.org/blog/sox-rnnoise-denoise#%E6%B5%8B%E8%AF%95" class="hash-link" aria-label="测试的直接链接" title="测试的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 先检查原始WAV文件信息</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">soxi speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 如果采样率不是48000，先转换到48000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sox speech.wav -r 48000 speech_48k.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 调整输入音量到合适范围（-3dB到-6dB）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># RNNoise要求：48000Hz，单声道，16位有符号整数PCM</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sox speech_48k.wav -r 48000 -c 1 -e signed-integer -b 16 -t raw speech.pcm  gain -n -3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 运行RNNoise降噪</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rnnoise_demo speech.pcm rnnoise.pcm</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#转换回WAV格式</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sox -r 48000 -c 1 -e signed-integer -b 16 -t raw rnnoise.pcm rnnoise.wav</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="使用rnnoise的库和api来进行音频降噪">使用rnnoise的库和API来进行音频降噪<a href="https://zephyr.100ask.org/blog/sox-rnnoise-denoise#%E4%BD%BF%E7%94%A8rnnoise%E7%9A%84%E5%BA%93%E5%92%8Capi%E6%9D%A5%E8%BF%9B%E8%A1%8C%E9%9F%B3%E9%A2%91%E9%99%8D%E5%99%AA" class="hash-link" aria-label="使用rnnoise的库和API来进行音频降噪的直接链接" title="使用rnnoise的库和API来进行音频降噪的直接链接" translate="no">​</a></h3>
<p>代码结构</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">(base) ubuntu@ubuntu-2204:~/baiwen/rnnoise_reduction$ tree -L 3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── CMakeLists.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── deps</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│&nbsp;&nbsp; ├── include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│&nbsp;&nbsp; │&nbsp;&nbsp; └── rnnoise.h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│&nbsp;&nbsp; └── lib</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│&nbsp;&nbsp;     └── librnnoise.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── include</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── Makefile</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── src</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    └── main.c</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">5 directories, 5 files</span><br></div></code></pre></div></div>
<p>其中 rnnnoise.h librnnoise.s0来自rnnoise的编译产物，直接复制就行，CMakeLists.txt需要更改工具链路径</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 指定交叉编译器</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_C_COMPILER /home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/host/bin/aarch64-buildroot-linux-gnu-gcc)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_CXX_COMPILER /home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/host/bin/aarch64-buildroot-linux-gnu-g++)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 设置sysroot</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_SYSROOT /home/ubuntu/rk3576_AI/buildroot/output/rockchip_rk3576/staging)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})</span><br></div></code></pre></div></div>
<p>编译</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">make clean</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#push adb到开发板的develop目录</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make push</span><br></div></code></pre></div></div>
<p>在开发板测试</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/develop# ./rnnoise_reduction speech.wav rnnoise.wav -3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">=== RNNoise音频降噪处理 ===</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">1. 读取WAV文件: speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   采样率: 8000Hz, 声道: 2, 采样点数: 40000 (5.00秒)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">2. 应用增益: -3.0dB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">3. 重采样到48kHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   重采样后: 240000采样点 (5.00秒)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">4. RNNoise降噪处理</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    处理帧数: 500, 每帧480个样本</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    第一帧前5个原始样本值: -34 -28 -23 -17 -11</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   处理后: 240000采样点 (5.00秒)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">5. 保存为WAV文件: rnnoise.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">=== 处理完成 ===</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/develop# aplay speech.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Playing WAVE 'speech.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Stereo</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/develop# aplay rnnoise.wav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Playing WAVE 'rnnoise.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Mono</span><br></div></code></pre></div></div>
<p>可以听出明显的降噪效果</p>]]></content:encoded>
            <category>sox</category>
            <category>rnnoise</category>
            <category>降噪</category>
            <category>音频</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 Weston 多屏配置]]></title>
            <link>https://zephyr.100ask.org/blog/weston-multi-screen</link>
            <guid>https://zephyr.100ask.org/blog/weston-multi-screen</guid>
            <pubDate>Fri, 14 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[基于 Weston 配置 RK3576 的多屏显示，实现异屏同显与扩展显示。]]></description>
            <content:encoded><![CDATA[<p>在嵌入式系统开发中，显示配置是用户界面实现的基础环节。Weston作为Wayland合成器的参考实现，广泛应用于嵌入式设备和桌面环境。面对不同的硬件配置和应用场景，需要精确控制显示输出。下面基于DShanPi-A1的buildroot固件版本，提供Weston在单屏独占、双屏同显和双屏异显三种典型场景下的配置方法，提供详细的操作指南。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="weston基础架构与配置原理">Weston基础架构与配置原理<a href="https://zephyr.100ask.org/blog/weston-multi-screen#weston%E5%9F%BA%E7%A1%80%E6%9E%B6%E6%9E%84%E4%B8%8E%E9%85%8D%E7%BD%AE%E5%8E%9F%E7%90%86" class="hash-link" aria-label="Weston基础架构与配置原理的直接链接" title="Weston基础架构与配置原理的直接链接" translate="no">​</a></h2>
<p>在进行配置之前，有比较简单了解一下基本原理。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="weston显示系统架构">Weston显示系统架构<a href="https://zephyr.100ask.org/blog/weston-multi-screen#weston%E6%98%BE%E7%A4%BA%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84" class="hash-link" aria-label="Weston显示系统架构的直接链接" title="Weston显示系统架构的直接链接" translate="no">​</a></h3>
<p>Weston采用模块化设计，其核心组件包括：</p>
<ul>
<li class=""><strong>后端（Backend）</strong>：负责与底层图形系统交互，如DRM、X11、Wayland等</li>
<li class=""><strong>合成器（Compositor）</strong>：管理窗口合成、渲染和输出</li>
<li class=""><strong>Shell</strong>：提供用户界面框架，如桌面、面板等</li>
</ul>
<p>在嵌入式系统中，通常使用DRM后端drm-backend.so，它直接与Linux内核的Direct Rendering Manager交互，提供了高效的硬件加速支持。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="配置文件结构解析">配置文件结构解析<a href="https://zephyr.100ask.org/blog/weston-multi-screen#%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%BB%93%E6%9E%84%E8%A7%A3%E6%9E%90" class="hash-link" aria-label="配置文件结构解析的直接链接" title="配置文件结构解析的直接链接" translate="no">​</a></h3>
<p>Weston的主要配置文件位于<code>/etc/xdg/weston/weston.ini</code>，采用INI格式组织。关键的配置段包括：</p>
<ul>
<li class=""><code>[core]</code>：核心配置，定义后端行为和全局参数</li>
<li class=""><code>[output]</code>：显示输出配置，控制每个物理接口的属性</li>
<li class=""><code>[shell]</code>：桌面环境相关设置</li>
<li class=""><code>[libinput]</code>：输入设备配置</li>
<li class=""><code>[device]</code>：特定设备的高级配置</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="hdmi独占显示配置">HDMI独占显示配置<a href="https://zephyr.100ask.org/blog/weston-multi-screen#hdmi%E7%8B%AC%E5%8D%A0%E6%98%BE%E7%A4%BA%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="HDMI独占显示配置的直接链接" title="HDMI独占显示配置的直接链接" translate="no">​</a></h2>
<p>在某些嵌入式应用场景中，设备需要强制使用HDMI接口作为唯一显示输出，同时禁用内置屏幕（如DSI接口的LCD）。这种配置常见于：</p>
<ul>
<li class="">工业控制台固定连接外接显示器</li>
<li class="">数字标牌系统使用大屏显示</li>
<li class="">需要高分辨率输出的专业应用</li>
</ul>
<p>以下为详细的配置</p>
<p><strong>首先需要配置环境变量</strong></p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">export WESTON_DRM_MIRROR=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export WESTON_DRM_PREFER_EXTERNAL=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export WESTON_DRM_SINGLE_HEAD=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export WESTON_DRM_MASTER_OUTPUT="HDMI-A-1"</span><br></div></code></pre></div></div>
<p><strong>再写入：/etc/xdg/weston/weston.ini</strong></p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[core]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">backend=drm-backend.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-input=true         # 必须连接输入设备才能启动</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-outputs=true       # 必须检测到输出设备</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">idle-time=0                # 禁用屏幕休眠</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">repaint-window=16          # 重绘窗口，约60Hz刷新率</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 禁用自动检测</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">use-udev=false             # 关闭udev自动检测，手动控制输出</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=HDMI-A-1             # 指定HDMI-A-1接口</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=1920x1080@60         # 分辨率1080p，60Hz刷新率</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">transform=normal          # 无旋转变换</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scale=1.5                 # 150%缩放，适应高DPI</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 禁用DSI接口</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=DSI-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=off                  # 关闭该输出</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[shell]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">panel-scale=2             # 面板元素200%缩放</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cursor-size=32            # 鼠标指针大小</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">locking=false             # 禁用屏幕锁定</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">startup-animation=none    # 禁用启动动画</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[keyboard]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">vt-switching=true         # 允许虚拟终端切换</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[libinput]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">touchscreen_calibrator=true  # 启用触摸屏校准</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">enable-tap=true           	 # 启用点击手势</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">natural-scroll=true          # 自然滚动方向</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[device]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=wch.cn USB2IIC_CTP_CONTROL   # 特定触摸设备</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rotation=normal                   # 正常方向</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="测试">测试<a href="https://zephyr.100ask.org/blog/weston-multi-screen#%E6%B5%8B%E8%AF%95" class="hash-link" aria-label="测试的直接链接" title="测试的直接链接" translate="no">​</a></h3>
<p>启动</p>
<p>运行3D测试</p>
<p>在实际应用中，应关闭DSI的驱动输出</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="tips注意了这里有一个坑导致我一开始hdmi屏幕无法启动">tips：注意了，这里有一个坑，导致我一开始hdmi屏幕无法启动<a href="https://zephyr.100ask.org/blog/weston-multi-screen#tips%E6%B3%A8%E6%84%8F%E4%BA%86%E8%BF%99%E9%87%8C%E6%9C%89%E4%B8%80%E4%B8%AA%E5%9D%91%E5%AF%BC%E8%87%B4%E6%88%91%E4%B8%80%E5%BC%80%E5%A7%8Bhdmi%E5%B1%8F%E5%B9%95%E6%97%A0%E6%B3%95%E5%90%AF%E5%8A%A8" class="hash-link" aria-label="tips：注意了，这里有一个坑，导致我一开始hdmi屏幕无法启动的直接链接" title="tips：注意了，这里有一个坑，导致我一开始hdmi屏幕无法启动的直接链接" translate="no">​</a></h3>
<p>看这个weston启动输出日志</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">root@rk3576-buildroot:/# weston</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Date: 2025-12-03 UTC</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">..........</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[03:20:26.528] Output HDMI-A-1 (crtc 72) video modes:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1024x600@59.8, preferred, 50.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080@60.0 16:9, 148.5 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080@59.9 16:9, 148.4 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080i@60.0, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080i@60.0 16:9, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080i@59.9 16:9, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080@50.0, current, 148.5 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080@50.0 16:9, 148.5 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080i@50.0, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1920x1080i@50.0 16:9, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1280x1024@75.0, 135.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1280x720@60.0 16:9, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1280x720@59.9 16:9, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1280x720@50.0, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1280x720@50.0 16:9, 74.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1024x768@75.0, 78.8 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1024x768@70.1, 75.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               1024x768@60.0, 65.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               832x624@74.6, 57.3 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               800x600@75.0, 49.5 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               800x600@72.2, 50.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               800x600@60.3, 40.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               800x600@56.2, 36.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x576@50.0, 27.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x576@50.0 4:3, 27.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x576@50.0 16:9, 27.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x480@60.0 4:3, 27.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x480@60.0 16:9, 27.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x480@59.9 4:3, 27.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x480@59.9 16:9, 27.0 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               640x480@75.0, 31.5 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               640x480@72.8, 31.5 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               640x480@60.0 4:3, 25.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               640x480@59.9, 25.2 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">               720x400@70.1, 28.3 MHz</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">.....</span><br></div></code></pre></div></div>
<p>注意这个分辨率</p>
<p>1024x600@59.8, preferred, 50.2 MH这是我的屏幕的实际物理分辨率，是默认配置，如果直接配置</p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 强制指定输出</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=HDMI-A-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#mode=1920x1080@50</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=1024x600@59.8</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">transform=normal</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scale=1.5</span><br></div></code></pre></div></div>
<p>启动时：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">xkbcommon: ERROR: couldn't find a Compose file for locale "en_US.UTF-8" (mapped to "en_US.UTF-8")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">could not create XKB compose table for locale 'en_US.UTF-8'.  Disabiling compose</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">xkbcommon: ERROR: couldn't find a Compose file for locale "en_US.UTF-8" (mapped to "en_US.UTF-8")</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">could not create XKB compose table for locale 'en_US.UTF-8'.  Disabiling compose</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.260819] dwhdmi-rockchip 27da0000.hdmi: use tmds mode</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.279593] rockchip-vop2 27d00000.vop: [drm:vop2_crtc_atomic_enable] Update mode to 1024x600p60, type: 11(if:HDMI0, flag:0x0) for vp0 dclk: 50250000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.279636] rockchip-hdptx-phy-hdmi 2b000000.hdmiphy: hdptx_ropll_cmn_config bus_width:7aae4 rate:1485000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.279810] rockchip-hdptx-phy-hdmi 2b000000.hdmiphy: hdptx phy pll locked!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.279872] rockchip-hdptx-phy-hdmi 2b000000.hdmiphy: hdptx_ropll_cmn_config bus_width:7aae4 rate:502500</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.280061] rockchip-hdptx-phy-hdmi 2b000000.hdmiphy: hdptx phy pll locked!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.280069] rockchip-vop2 27d00000.vop: [drm:vop2_crtc_atomic_enable] set dclk_vp0 to 50250000, get 50250000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.280120] dwhdmi-rockchip 27da0000.hdmi: final tmdsclk = 50250000</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.280189] dwhdmi-rockchip 27da0000.hdmi: don't use dsc mode</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.280198] dwhdmi-rockchip 27da0000.hdmi: dw hdmi qp use tmds mode</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.280206] rockchip-hdptx-phy-hdmi 2b000000.hdmiphy: bus_width:0x7aae4,bit_rate:502500</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.285263] rockchip-hdptx-phy-hdmi 2b000000.hdmiphy: hdptx phy lane can't ready!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.285271] phy phy-2b000000.hdmiphy.4: phy poweron failed --&gt; -22</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.285278] dwhdmi-rockchip 27da0000.hdmi: dw_hdmi_qp_setup hdmi set operation mode failed</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.285317] dwhdmi-rockchip 27da0000.hdmi: Rate 50250000 missing; compute N dynamically</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.286726] dwhdmi-rockchip 27da0000.hdmi: Rate 50250000 missing; compute N dynamically</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.315462] dwhdmi-rockchip 27da0000.hdmi: use tmds mode</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div></code></pre></div></div>
<p>注意：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[  695.285263] rockchip-hdptx-phy-hdmi 2b000000.hdmiphy: hdptx phy lane can't ready!</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[  695.285271] phy phy-2b000000.hdmiphy.4: phy poweron failed --&gt; -22</span><br></div></code></pre></div></div>
<p><strong>屏幕是无法启动的，所以这里有一个经验：</strong></p>
<p><strong>在测试屏幕时，物理分辨率可能会不兼容，需要测试多个分辨率，找到兼容的分辨率</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="关键配置点">关键配置点<a href="https://zephyr.100ask.org/blog/weston-multi-screen#%E5%85%B3%E9%94%AE%E9%85%8D%E7%BD%AE%E7%82%B9" class="hash-link" aria-label="关键配置点的直接链接" title="关键配置点的直接链接" translate="no">​</a></h3>
<p><strong>use-udev=false的重要性</strong>：
默认情况下，Weston通过udev自动检测所有连接的显示设备。设置为<code>false</code>后，Weston将仅使用配置文件中明确指定的输出，这为实现精确控制提供了基础。</p>
<p><strong>输出优先级控制</strong>：
当多个<code>[output]</code>段存在时，Weston按配置文件顺序处理。将需要禁用的输出放在激活的输出之后，并设置<code>mode=off</code>，可以确保正确的显示控制。</p>
<p><strong>缩放配置策略</strong>：
嵌入式设备通常需要调整UI元素的物理尺寸。通过<code>scale</code>参数可以独立控制每个输出的缩放比例，这对于连接不同DPI的显示器尤为重要。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="dsi独占模式">dsi独占模式<a href="https://zephyr.100ask.org/blog/weston-multi-screen#dsi%E7%8B%AC%E5%8D%A0%E6%A8%A1%E5%BC%8F" class="hash-link" aria-label="dsi独占模式的直接链接" title="dsi独占模式的直接链接" translate="no">​</a></h2>
<p>与HDMI独占相反，某些应用需要仅使用设备内置屏幕，如：</p>
<ul>
<li class="">移动设备或便携式仪器</li>
<li class="">节省功耗的电池供电设备</li>
<li class="">不需要外接显示的应用场景</li>
</ul>
<p><strong>/etc/xdg/weston/weston.ini</strong></p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[core]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">backend=drm-backend.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Allow running without input devices</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-input=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Allow running without output devices</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-outputs=none</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Disable screen idle timeout by default</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">idle-time=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 关键：禁用自动检测所有连接</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">use-udev=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># The repaint-window is used to calculate repaint delay(ms) after flipped.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#   value &lt;= 0: delay = abs(value)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">#   value &gt; 0: delay = vblank_duration - value</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">repaint-window=-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Allow blending with lower drm planes</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># gbm-format=argb8888</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[shell]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># top(default)|bottom|left|right|none, none to disable panel</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># panel-position=none</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Scale panel size</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">panel-scale=2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Set cursor size</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cursor-size=32</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># none|minutes(default)|minutes-24h|seconds|seconds-24h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># clock-format=minutes-24h</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">clock-with-date=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Disable screen locking</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">locking=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Disable the desktop starting up animation</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">startup-animation=none</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[libinput]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Uncomment below to enable touch screen calibrator(weston-touch-calibrator)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># touchscreen_calibrator=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># calibration_helper=/bin/weston-calibration-helper.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[keyboard]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Comment this to enable vt switching</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">vt-switching=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Configs for auto key repeat</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># repeat-rate=40</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># repeat-delay=400</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=DSI-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=480x800</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">transform=rotate-180</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scale=0.2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 明确禁用 DSI-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=HDMI-A-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=off</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="测试-1">测试<a href="https://zephyr.100ask.org/blog/weston-multi-screen#%E6%B5%8B%E8%AF%95-1" class="hash-link" aria-label="测试的直接链接" title="测试的直接链接" translate="no">​</a></h3>
<p>开机</p>
<p>运行3D测试</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="关键点">关键点<a href="https://zephyr.100ask.org/blog/weston-multi-screen#%E5%85%B3%E9%94%AE%E7%82%B9" class="hash-link" aria-label="关键点的直接链接" title="关键点的直接链接" translate="no">​</a></h3>
<p><strong>旋转配置</strong>：
嵌入式设备的屏幕安装方向可能不同。<code>transform</code>参数支持多种旋转选项：</p>
<ul>
<li class=""><code>normal</code>：无旋转</li>
<li class=""><code>rotate-90</code>：顺时针90度</li>
<li class=""><code>rotate-180</code>：180度</li>
<li class=""><code>rotate-270</code>：顺时针270度</li>
<li class=""><code>flipped</code>：水平翻转</li>
<li class=""><code>flipped-rotate-180</code>：组合变换</li>
</ul>
<p><strong>DPI适配策略</strong>：
小尺寸高分辨率屏幕需要适当的UI缩放。通过试验不同<code>scale</code>值，找到物理尺寸合适的UI元素大小。本配置中使用0.2（20%）缩放，确保在480x800分辨率下UI元素可正常操作。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="双屏同显">双屏同显<a href="https://zephyr.100ask.org/blog/weston-multi-screen#%E5%8F%8C%E5%B1%8F%E5%90%8C%E6%98%BE" class="hash-link" aria-label="双屏同显的直接链接" title="双屏同显的直接链接" translate="no">​</a></h2>
<p>双屏同显（镜像模式）适用于：</p>
<ul>
<li class="">演示和教学场景</li>
<li class="">主控台与观察屏同步显示</li>
<li class="">故障排除和调试</li>
</ul>
<p><strong>/etc/xdg/weston/weston.ini</strong></p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[core]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">backend=drm-backend.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-input=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-outputs=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">idle-time=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">repaint-window=16</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=mirror</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">use-udev=true  # 双屏需要启用udev</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=HDMI-A-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=1920x1080</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">transform=rotate-270</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scale=0.25</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=DSI-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=1920x1080</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">transform=rotate-270</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scale=0.25</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[shell]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">panel-scale=2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cursor-size=32</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">locking=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">startup-animation=none</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[keyboard]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">vt-switching=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[libinput]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">touchscreen_calibrator=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">enable-tap=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">natural-scroll=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 关键修正：将触摸设备明确绑定到HDMI输出</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[device]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=wch.cn USB2IIC_CTP_CONTROL</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">output=HDMI-A-1  # 明确指定到HDMI屏幕</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rotation=normal  # 根据实际方向调整</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="测试-2">测试<a href="https://zephyr.100ask.org/blog/weston-multi-screen#%E6%B5%8B%E8%AF%95-2" class="hash-link" aria-label="测试的直接链接" title="测试的直接链接" translate="no">​</a></h3>
<p>开机</p>
<p>运行3D测试</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="关键点-1">关键点<a href="https://zephyr.100ask.org/blog/weston-multi-screen#%E5%85%B3%E9%94%AE%E7%82%B9-1" class="hash-link" aria-label="关键点的直接链接" title="关键点的直接链接" translate="no">​</a></h3>
<p><strong>分辨率对齐</strong>：
镜像模式下，两个输出应使用相同的分辨率，否则Weston会以较低分辨率或缩放显示。本配置中统一使用1920x1080，确保显示内容一致。</p>
<p><strong>触摸输入绑定</strong>：
在多屏环境中，触摸输入需要明确绑定到特定屏幕。通过<code>output=HDMI-A-1</code>配置，确保触摸操作仅影响HDMI显示，避免在镜像模式下产生混淆。</p>
<p><strong>性能优化考虑</strong>：
镜像模式需要合成器渲染相同内容两次，对系统性能有一定影响。适当调整<code>repaint-window</code>参数可以平衡流畅度和系统负载。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="双屏异显">双屏异显<a href="https://zephyr.100ask.org/blog/weston-multi-screen#%E5%8F%8C%E5%B1%8F%E5%BC%82%E6%98%BE" class="hash-link" aria-label="双屏异显的直接链接" title="双屏异显的直接链接" translate="no">​</a></h2>
<p>双屏异显（扩展模式），适用于：</p>
<ul>
<li class="">多任务工作环境</li>
<li class="">控制面板与数据显示分离</li>
<li class="">复杂的专业应用界面</li>
</ul>
<p>以下为配置</p>
<p><strong>weston.ini配置</strong></p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[core]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">backend=drm-backend.so</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-input=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">require-outputs=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">idle-time=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">repaint-window=16</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=extend  # 关键：改为extend模式</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">use-udev=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># HDMI屏幕（右侧）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=HDMI-A-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=1920x1080</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">transform=rotate-270</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scale=0.25</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">x=200  # DSI在左侧，从DSI宽度开始</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">y=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># DSI屏幕（左侧）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[output]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=DSI-1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mode=480x800</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">transform=rotate-270</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">scale=0.25</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">x=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">y=0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[shell]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">panel-scale=2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cursor-size=32</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">locking=false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">startup-animation=none</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[keyboard]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">vt-switching=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[libinput]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">touchscreen_calibrator=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">enable-tap=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">natural-scroll=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[device]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">name=wch.cn USB2IIC_CTP_CONTROL</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">output=HDMI-A-1  # 触摸绑定到HDMI屏幕</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">rotation=normal</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="测试-3">测试<a href="https://zephyr.100ask.org/blog/weston-multi-screen#%E6%B5%8B%E8%AF%95-3" class="hash-link" aria-label="测试的直接链接" title="测试的直接链接" translate="no">​</a></h3>
<p>启动时</p>
<p>需要设置环境变量，关闭镜像模式</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">#环境变量</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export WESTON_DRM_MIRROR=0         # 关闭镜像模式</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export WESTON_DRM_PREFER_EXTERNAL=0 # 不优先外部显示</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">export WESTON_DRM_SINGLE_HEAD=0     # 启用多head支持</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pkill weston</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">weston &amp;</span><br></div></code></pre></div></div>
<p>启动后，系统识别两个独立显示器，桌面可以跨屏延伸。每个屏幕可以运行不同的应用程序，实现真正的多任务环境。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="关键点-2">关键点<a href="https://zephyr.100ask.org/blog/weston-multi-screen#%E5%85%B3%E9%94%AE%E7%82%B9-2" class="hash-link" aria-label="关键点的直接链接" title="关键点的直接链接" translate="no">​</a></h3>
<p><strong>屏幕排列控制</strong>：
Weston默认的屏幕排列可能不符合实际物理布局。可以通过<code>weston.ini</code>中的位置参数或启动后手动调整来优化。</p>
<p><strong>跨屏窗口管理</strong>：
在扩展模式下，窗口可以在屏幕间移动。需要确保窗口管理器和应用程序支持多屏幕环境。</p>
<p><strong>性能考量</strong>：
扩展模式对图形性能要求更高，特别是当两个屏幕分辨率差异较大时。需要根据硬件能力调整渲染设置。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://zephyr.100ask.org/blog/weston-multi-screen#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="总结的直接链接" title="总结的直接链接" translate="no">​</a></h2>
<p>Weston多屏配置虽然有一定复杂性，但通过深入理解其配置原理和掌握关键参数，可以实现高度定制化的显示解决方案。无论是单屏独占、双屏同显还是双屏异显，都需要综合考虑硬件特性、应用需求和用户体验。</p>
<p>实际配置过程中，建议采取逐步测试的方法：<strong>先从基本配置开始，验证单个功能，然后逐步添加复杂特性。</strong></p>]]></content:encoded>
            <category>Weston</category>
            <category>多屏</category>
            <category>Wayland</category>
            <category>RK3576</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 RK3576 GStreamer 播放 16 路视频与硬件加速]]></title>
            <link>https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration</link>
            <guid>https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration</guid>
            <pubDate>Wed, 12 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[使用 GStreamer 在 RK3576 上实现 16 路视频硬解播放，充分利用 MPP 硬件加速。]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="演示视频">演示视频<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91" class="hash-link" aria-label="演示视频的直接链接" title="演示视频的直接链接" translate="no">​</a></h2>
<p><a href="https://www.bilibili.com/video/BV1m34VziE2s" target="_blank" rel="noopener noreferrer" class="">https://www.bilibili.com/video/BV1m34VziE2s</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="一实验环境">一、实验环境<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#%E4%B8%80%E5%AE%9E%E9%AA%8C%E7%8E%AF%E5%A2%83" class="hash-link" aria-label="一、实验环境的直接链接" title="一、实验环境的直接链接" translate="no">​</a></h2>
<table><thead><tr><th>类别</th><th>具体配置</th></tr></thead><tbody><tr><td>板卡</td><td>DshanPI-A1</td></tr><tr><td>主控芯片</td><td>RK3576</td></tr><tr><td>操作系统</td><td>Armbian</td></tr><tr><td>桌面系统</td><td>GNOME</td></tr><tr><td>窗口系统</td><td>Wayland</td></tr><tr><td>GPU 驱动</td><td>Panfrost</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="核心硬件加速单元说明">核心硬件加速单元说明<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#%E6%A0%B8%E5%BF%83%E7%A1%AC%E4%BB%B6%E5%8A%A0%E9%80%9F%E5%8D%95%E5%85%83%E8%AF%B4%E6%98%8E" class="hash-link" aria-label="核心硬件加速单元说明的直接链接" title="核心硬件加速单元说明的直接链接" translate="no">​</a></h3>
<p>RK3576 芯片集成三类关键硬件加速单元，分别负责不同环节的视频处理：</p>
<ul>
<li class="">
<p><strong>VPU（视频处理单元）</strong>：负责视频解码（如 H.264 硬解），核心元件 <code>mppvideodec</code> 调用此单元；</p>
</li>
<li class="">
<p><strong>RGA（图像加速单元）</strong>：负责图像缩放、格式转换（如 NV12→RGBA），可通过 <code>mppvideodec</code> 参数启用；</p>
</li>
<li class="">
<p><strong>GPU（图形处理单元）</strong>：负责视频渲染、多画面拼接（如 <code>glvideomixer</code> 拼接画面），由 Panfrost 驱动管理。</p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="二gstreamer-工具与插件安装">二、GStreamer 工具与插件安装<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#%E4%BA%8Cgstreamer-%E5%B7%A5%E5%85%B7%E4%B8%8E%E6%8F%92%E4%BB%B6%E5%AE%89%E8%A3%85" class="hash-link" aria-label="二、GStreamer 工具与插件安装的直接链接" title="二、GStreamer 工具与插件安装的直接链接" translate="no">​</a></h2>
<p>执行以下命令安装全套 GStreamer 工具及 RK3576 硬件加速插件：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 基础工具（gst-launch-1.0 等）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y gstreamer1.0-tools</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 基础插件集（音频/视频基础功能）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y gstreamer1.0-plugins-base</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y gstreamer1.0-plugins-good</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y gstreamer1.0-plugins-bad</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># FFmpeg 集成插件（软解 fallback）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y gstreamer1.0-libav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># RK3576 硬件加速插件（VPU/RGA 支持）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y gstreamer1.0-rockchip1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># GPU 渲染依赖（glvideomixer 等）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y libgstreamer-gl1.0-0</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="三基础硬解码播放实践">三、基础硬解码播放实践<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#%E4%B8%89%E5%9F%BA%E7%A1%80%E7%A1%AC%E8%A7%A3%E7%A0%81%E6%92%AD%E6%94%BE%E5%AE%9E%E8%B7%B5" class="hash-link" aria-label="三、基础硬解码播放实践的直接链接" title="三、基础硬解码播放实践的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-最简硬解码命令">1. 最简硬解码命令<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#1-%E6%9C%80%E7%AE%80%E7%A1%AC%E8%A7%A3%E7%A0%81%E5%91%BD%E4%BB%A4" class="hash-link" aria-label="1. 最简硬解码命令的直接链接" title="1. 最简硬解码命令的直接链接" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 filesrc location=/root/bad_apple.mp4 ! qtdemux ! h264parse ! mppvideodec ! waylandsink</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="命令链路解析">命令链路解析<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#%E5%91%BD%E4%BB%A4%E9%93%BE%E8%B7%AF%E8%A7%A3%E6%9E%90" class="hash-link" aria-label="命令链路解析的直接链接" title="命令链路解析的直接链接" translate="no">​</a></h4>
<table><thead><tr><th>元件</th><th>功能说明</th></tr></thead><tbody><tr><td><code>filesrc</code></td><td>读取本地视频文件（需替换为实际路径，如 <code>/root/bad_apple.mp4</code>）</td></tr><tr><td><code>qtdemux</code></td><td>解封装 MP4 文件，分离视频流与音频流（MP4 属于 QuickTime 容器格式）</td></tr><tr><td><code>h264parse</code></td><td>解析 H.264 码流，将 MP4 中的 AVCC 格式转为解码器支持的 Annex B 裸流</td></tr><tr><td><code>mppvideodec</code></td><td>调用 RK3576 VPU 硬解码，输出 NV12 格式图像（硬件解码默认格式）</td></tr><tr><td><code>waylandsink</code></td><td>调用 GPU 渲染，在 Wayland 窗口显示视频（自动将 NV12 转为 RGB 格式）</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-关键环节补充说明">2. 关键环节补充说明<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#2-%E5%85%B3%E9%94%AE%E7%8E%AF%E8%8A%82%E8%A1%A5%E5%85%85%E8%AF%B4%E6%98%8E" class="hash-link" aria-label="2. 关键环节补充说明的直接链接" title="2. 关键环节补充说明的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="1解封装与码流解析">（1）解封装与码流解析<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#1%E8%A7%A3%E5%B0%81%E8%A3%85%E4%B8%8E%E7%A0%81%E6%B5%81%E8%A7%A3%E6%9E%90" class="hash-link" aria-label="（1）解封装与码流解析的直接链接" title="（1）解封装与码流解析的直接链接" translate="no">​</a></h4>
<ul>
<li class="">
<p>MP4 文件是「容器」，需通过 <code>qtdemux</code> 分离出内部的视频流（H.264）和音频流；</p>
</li>
<li class="">
<p>H.264 流有两种格式：MP4 中默认是 <strong>AVCC 格式</strong>，而硬件解码器仅支持 <strong>Annex B 裸流</strong>，因此必须通过 <code>h264parse</code> 转换。</p>
</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="2解码">（2）解码<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#2%E8%A7%A3%E7%A0%81" class="hash-link" aria-label="（2）解码的直接链接" title="（2）解码的直接链接" translate="no">​</a></h4>
<ul>
<li class="">h264解码得到nv12图像;
在没有硬解码的系统中，可以使用元件 avdec_h264 代替 ;
avdec_h264 就是调用ffmpeg的软件解码器;
也可以用来对比硬解软解的性能差距。</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="3渲染wayland-vs-x11">（3）渲染（Wayland vs X11）<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#3%E6%B8%B2%E6%9F%93wayland-vs-x11" class="hash-link" aria-label="（3）渲染（Wayland vs X11）的直接链接" title="（3）渲染（Wayland vs X11）的直接链接" translate="no">​</a></h4>
<ul>
<li class="">wayland窗口系统中，可以直接传入nv12图像，自动调用gpu转成rgb渲染显示出来;
x11窗口系统中，需要额外元件将nv12图像转成rgb才能渲染;
这里因为用的wayland窗口系统，所以渲染元件是waylandsink;
如果是x11 则要用xvimagesink或者glimagesink。</li>
</ul>
<table><thead><tr><th>窗口系统</th><th>渲染元件</th><th>支持输入格式</th><th>额外说明</th></tr></thead><tbody><tr><td>Wayland</td><td><code>waylandsink</code></td><td>NV12、RGBA/BGRA</td><td>自动用 GPU 转 NV12→RGB 渲染</td></tr><tr><td>X11</td><td><code>xvimagesink</code></td><td>RGB/RGBA（不支持 NV12）</td><td>需用 RGA/GPU 提前转格式</td></tr><tr><td>X11</td><td><code>glimagesink</code></td><td>RGB/RGBA（不支持 NV12）</td><td>依赖 GPU 转格式，性能优于 XV</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-硬件负载查看命令">3. 硬件负载查看命令<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#3-%E7%A1%AC%E4%BB%B6%E8%B4%9F%E8%BD%BD%E6%9F%A5%E7%9C%8B%E5%91%BD%E4%BB%A4" class="hash-link" aria-label="3. 硬件负载查看命令的直接链接" title="3. 硬件负载查看命令的直接链接" translate="no">​</a></h3>
<p>通过以下命令实时监控 VPU/RGA/GPU 占用率（建议用 <code>tmux</code> 分屏同时查看）：</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="1查看-rga-占用率">（1）查看 RGA 占用率<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#1%E6%9F%A5%E7%9C%8B-rga-%E5%8D%A0%E7%94%A8%E7%8E%87" class="hash-link" aria-label="（1）查看 RGA 占用率的直接链接" title="（1）查看 RGA 占用率的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">watch -n 1 cat /sys/kernel/debug/rkrga/load</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="2查看-gpu-占用率panfrost-驱动">（2）查看 GPU 占用率（Panfrost 驱动）<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#2%E6%9F%A5%E7%9C%8B-gpu-%E5%8D%A0%E7%94%A8%E7%8E%87panfrost-%E9%A9%B1%E5%8A%A8" class="hash-link" aria-label="（2）查看 GPU 占用率（Panfrost 驱动）的直接链接" title="（2）查看 GPU 占用率（Panfrost 驱动）的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">watch -n 1 cat /sys/class/devfreq/27800000.gpu/load</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="3查看-gpu-占用率mali-官方驱动可选">（3）查看 GPU 占用率（Mali 官方驱动，可选）<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#3%E6%9F%A5%E7%9C%8B-gpu-%E5%8D%A0%E7%94%A8%E7%8E%87mali-%E5%AE%98%E6%96%B9%E9%A9%B1%E5%8A%A8%E5%8F%AF%E9%80%89" class="hash-link" aria-label="（3）查看 GPU 占用率（Mali 官方驱动，可选）的直接链接" title="（3）查看 GPU 占用率（Mali 官方驱动，可选）的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">watch -n 1 cat /sys/devices/platform/fb000000.gpu/utilisation</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="四rga-硬件加速的应用场景">四、RGA 硬件加速的应用场景<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#%E5%9B%9Brga-%E7%A1%AC%E4%BB%B6%E5%8A%A0%E9%80%9F%E7%9A%84%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF" class="hash-link" aria-label="四、RGA 硬件加速的应用场景的直接链接" title="四、RGA 硬件加速的应用场景的直接链接" translate="no">​</a></h2>
<p>RGA 主要用于<strong>图像缩放</strong>和<strong>格式转换</strong>，可减轻 GPU 负载，尤其适合多视频播放场景。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-rga-实现视频缩放全屏播放">1. RGA 实现视频缩放（全屏播放）<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#1-rga-%E5%AE%9E%E7%8E%B0%E8%A7%86%E9%A2%91%E7%BC%A9%E6%94%BE%E5%85%A8%E5%B1%8F%E6%92%AD%E6%94%BE" class="hash-link" aria-label="1. RGA 实现视频缩放（全屏播放）的直接链接" title="1. RGA 实现视频缩放（全屏播放）的直接链接" translate="no">​</a></h3>
<p>若视频分辨率为 720P，需全屏适配 1080P 屏幕，通过 <code>mppvideodec</code> 的 <code>width</code>/<code>height</code> 参数调用 RGA 缩放：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 filesrc location=/root/bad_apple.mp4 ! qtdemux ! h264parse ! mppvideodec width=1920 height=1080 ! waylandsink</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="对比gpu-缩放方案">对比：GPU 缩放方案<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#%E5%AF%B9%E6%AF%94gpu-%E7%BC%A9%E6%94%BE%E6%96%B9%E6%A1%88" class="hash-link" aria-label="对比：GPU 缩放方案的直接链接" title="对比：GPU 缩放方案的直接链接" translate="no">​</a></h4>
<p>若不启用 RGA，仅通过 <code>waylandsink</code> 的 <code>fullscreen=true</code> 让 GPU 缩放，可对比两者负载差异：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 filesrc location=/root/bad_apple.mp4 ! qtdemux ! h264parse ! mppvideodec ! waylandsink fullscreen=true</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-rga-实现图像格式转换">2. RGA 实现图像格式转换<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#2-rga-%E5%AE%9E%E7%8E%B0%E5%9B%BE%E5%83%8F%E6%A0%BC%E5%BC%8F%E8%BD%AC%E6%8D%A2" class="hash-link" aria-label="2. RGA 实现图像格式转换的直接链接" title="2. RGA 实现图像格式转换的直接链接" translate="no">​</a></h3>
<p>Wayland 中 <code>waylandsink</code> 不支持 RGB/BGR 格式，仅支持 <strong>RGBA/BGRA</strong>（带透明度）；X11 中 <code>xvimagesink</code> 不支持 NV12，需转 RGB 格式。通过 <code>mppvideodec</code> 的 <code>format</code> 参数调用 RGA 转格式：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Wayland 场景：NV12→RGBA（减轻 GPU 转格式负载）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 filesrc location=/root/bad_apple.mp4 ! qtdemux ! h264parse ! mppvideodec format=RGBA ! waylandsink</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># X11 场景：NV12→RGB（适配 xvimagesink）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 filesrc location=/root/bad_apple.mp4 ! qtdemux ! h264parse ! mppvideodec format=RGB ! xvimagesink</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-rga-与-gpu-选择原则">3. RGA 与 GPU 选择原则<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#3-rga-%E4%B8%8E-gpu-%E9%80%89%E6%8B%A9%E5%8E%9F%E5%88%99" class="hash-link" aria-label="3. RGA 与 GPU 选择原则的直接链接" title="3. RGA 与 GPU 选择原则的直接链接" translate="no">​</a></h3>
<table><thead><tr><th>维度</th><th>RGA</th><th>GPU</th></tr></thead><tbody><tr><td>负载情况</td><td>低占用、波动小，多核心支持</td><td>高占用、波动大，易超 50%</td></tr><tr><td>功能侧重</td><td>图像缩放、格式转换（专用）</td><td>渲染、多画面拼接（通用）</td></tr><tr><td>适用场景</td><td>单视频缩放、格式转换</td><td>多视频拼接、3D 渲染</td></tr><tr><td>选择建议</td><td>能用 RGA 则优先用，平衡负载</td><td>RGA 不支持的场景（如拼接）</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="五多画面拼接实践">五、多画面拼接实践<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#%E4%BA%94%E5%A4%9A%E7%94%BB%E9%9D%A2%E6%8B%BC%E6%8E%A5%E5%AE%9E%E8%B7%B5" class="hash-link" aria-label="五、多画面拼接实践的直接链接" title="五、多画面拼接实践的直接链接" translate="no">​</a></h2>
<p>多画面拼接依赖 <code>glvideomixer</code>（GPU 实现），需注意<strong>多路流冲突处理</strong>和<strong>队列缓冲优化</strong>。
实际上rga也可以拼接，但是gst的元件上没有实现 直接用rga编程是可以拼接的。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-2-路画面拼接基础版">1. 2 路画面拼接（基础版）<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#1-2-%E8%B7%AF%E7%94%BB%E9%9D%A2%E6%8B%BC%E6%8E%A5%E5%9F%BA%E7%A1%80%E7%89%88" class="hash-link" aria-label="1. 2 路画面拼接（基础版）的直接链接" title="1. 2 路画面拼接（基础版）的直接链接" translate="no">​</a></h3>
<p>多路视频需为 <code>qtdemux</code> 命名（避免冲突），通过 <code>xpos</code>/<code>ypos</code> 定义画面位置：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">qtdemux name=demux_left ! h264parse ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=1080 ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">qtdemux name=demux_right ! h264parse ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=1080 ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_1 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer name=glvideomixer \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_0::xpos=0 sink_0::ypos=0 \ </span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_1::xpos=960 sink_1::ypos=0 ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">waylandsink</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-2-路画面拼接优化版增加队列">2. 2 路画面拼接（优化版，增加队列）<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#2-2-%E8%B7%AF%E7%94%BB%E9%9D%A2%E6%8B%BC%E6%8E%A5%E4%BC%98%E5%8C%96%E7%89%88%E5%A2%9E%E5%8A%A0%E9%98%9F%E5%88%97" class="hash-link" aria-label="2. 2 路画面拼接（优化版，增加队列）的直接链接" title="2. 2 路画面拼接（优化版，增加队列）的直接链接" translate="no">​</a></h3>
<p>多路视频处理耗时增加，需添加 <code>queue</code> 缓冲防止卡顿（每路流关键节点均需加队列）：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">qtdemux name=demux_left ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=1080 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">qtdemux name=demux_right ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=1080 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_1 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer name=glvideomixer \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_0::xpos=0 sink_0::ypos=0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_1::xpos=960 sink_1::ypos=0 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">waylandsink</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-4-路画面拼接22-网格">3. 4 路画面拼接（2×2 网格）<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#3-4-%E8%B7%AF%E7%94%BB%E9%9D%A2%E6%8B%BC%E6%8E%A522-%E7%BD%91%E6%A0%BC" class="hash-link" aria-label="3. 4 路画面拼接（2×2 网格）的直接链接" title="3. 4 路画面拼接（2×2 网格）的直接链接" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux1 ! queue ! h264parse ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=540 ! queue ! glvideomixer.sink_0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux2 ! queue ! h264parse ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=540 ! queue ! glvideomixer.sink_1 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux3 ! queue ! h264parse ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=540 ! queue ! glvideomixer.sink_2 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux4 ! queue ! h264parse ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=960 height=540 ! queue ! glvideomixer.sink_3 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer name=glvideomixer \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_0::xpos=0    sink_0::ypos=0    sink_0::width=960 sink_0::height=540 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_1::xpos=960  sink_1::ypos=0    sink_1::width=960 sink_1::height=540 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_2::xpos=0    sink_2::ypos=540  sink_2::width=960 sink_2::height=540 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_3::xpos=960  sink_3::ypos=540  sink_3::width=960 sink_3::height=540 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">waylandsink</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-16-路画面拼接44-网格高负载场景">4. 16 路画面拼接（4×4 网格，高负载场景）<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#4-16-%E8%B7%AF%E7%94%BB%E9%9D%A2%E6%8B%BC%E6%8E%A544-%E7%BD%91%E6%A0%BC%E9%AB%98%E8%B4%9F%E8%BD%BD%E5%9C%BA%E6%99%AF" class="hash-link" aria-label="4. 16 路画面拼接（4×4 网格，高负载场景）的直接链接" title="4. 16 路画面拼接（4×4 网格，高负载场景）的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="1解决文件描述符上限问题">（1）解决文件描述符上限问题<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#1%E8%A7%A3%E5%86%B3%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6%E4%B8%8A%E9%99%90%E9%97%AE%E9%A2%98" class="hash-link" aria-label="（1）解决文件描述符上限问题的直接链接" title="（1）解决文件描述符上限问题的直接链接" translate="no">​</a></h4>
<p>16 路视频会创建大量 DMA 缓冲区（占用 Linux 文件描述符 FD），需先提高 FD 上限：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ulimit -n 4096  # 临时生效，重启后需重新设置</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="216-路拼接命令">（2）16 路拼接命令<a href="https://zephyr.100ask.org/blog/gstreamer-16ch-hw-acceleration#216-%E8%B7%AF%E6%8B%BC%E6%8E%A5%E5%91%BD%E4%BB%A4" class="hash-link" aria-label="（2）16 路拼接命令的直接链接" title="（2）16 路拼接命令的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux1 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux2 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_1 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux3 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_2 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux4 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_3 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux5 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_4 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux6 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_5 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux7 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_6 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux8 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_7 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux9 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_8 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux10 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_9 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux11 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_10 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux12 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_11 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux13 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_12 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux14 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_13 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux15 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_14 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">filesrc location=/root/bad_apple.mp4 ! qtdemux name=demux16 ! queue ! h264parse ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mppvideodec format=RGBA width=480 height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer.sink_15 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">glvideomixer name=glvideomixer \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_0::xpos=0 sink_0::ypos=0 sink_0::width=480 sink_0::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_1::xpos=480 sink_1::ypos=0 sink_1::width=480 sink_1::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_2::xpos=960 sink_2::ypos=0 sink_2::width=480 sink_2::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_3::xpos=1440 sink_3::ypos=0 sink_3::width=480 sink_3::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_4::xpos=0 sink_4::ypos=270 sink_4::width=480 sink_4::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_5::xpos=480 sink_5::ypos=270 sink_5::width=480 sink_5::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_6::xpos=960 sink_6::ypos=270 sink_6::width=480 sink_6::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_7::xpos=1440 sink_7::ypos=270 sink_7::width=480 sink_7::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_8::xpos=0 sink_8::ypos=540 sink_8::width=480 sink_8::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_9::xpos=480 sink_9::ypos=540 sink_9::width=480 sink_9::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_10::xpos=960 sink_10::ypos=540 sink_10::width=480 sink_10::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_11::xpos=1440 sink_11::ypos=540 sink_11::width=480 sink_11::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_12::xpos=0 sink_12::ypos=810 sink_12::width=480 sink_12::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_13::xpos=480 sink_13::ypos=810 sink_13::width=480 sink_13::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_14::xpos=960 sink_14::ypos=810 sink_14::width=480 sink_14::height=270 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sink_15::xpos=1440 sink_15::ypos=810 sink_15::width=480 sink_15::height=270 ! queue ! \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">waylandsink</span><br></div></code></pre></div></div>]]></content:encoded>
            <category>RK3576</category>
            <category>GStreamer</category>
            <category>硬件加速</category>
            <category>MPP</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 RK3576 gmrender-resurrect B站投屏]]></title>
            <link>https://zephyr.100ask.org/blog/gmrender-bilibili-cast</link>
            <guid>https://zephyr.100ask.org/blog/gmrender-bilibili-cast</guid>
            <pubDate>Mon, 10 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[使用 gmrender-resurrect 在 RK3576 上实现 DLNA 投屏，将 B 站等内容投放到开发板播放。]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="演示效果">演示效果<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#%E6%BC%94%E7%A4%BA%E6%95%88%E6%9E%9C" class="hash-link" aria-label="演示效果的直接链接" title="演示效果的直接链接" translate="no">​</a></h2>
<p><a href="https://www.bilibili.com/video/BV1Z646zhEBP" target="_blank" rel="noopener noreferrer" class="">https://www.bilibili.com/video/BV1Z646zhEBP</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="一环境信息">一、环境信息<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#%E4%B8%80%E7%8E%AF%E5%A2%83%E4%BF%A1%E6%81%AF" class="hash-link" aria-label="一、环境信息的直接链接" title="一、环境信息的直接链接" translate="no">​</a></h2>
<table><thead><tr><th>类别</th><th>具体配置</th></tr></thead><tbody><tr><td>板卡</td><td>DshanPI-A1</td></tr><tr><td>主控芯片</td><td>RK3576</td></tr><tr><td>操作系统</td><td>Armbian</td></tr><tr><td>桌面系统</td><td>GNOME</td></tr><tr><td>窗口系统</td><td>Wayland</td></tr><tr><td>GPU 驱动</td><td>Panfrost</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="二实现原理">二、实现原理<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#%E4%BA%8C%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86" class="hash-link" aria-label="二、实现原理的直接链接" title="二、实现原理的直接链接" translate="no">​</a></h2>
<ol>
<li class="">
<p><strong>核心组件</strong>：<code>gmrender-resurrect</code> 是一款接收 DLNA 服务内容，并通过 GStreamer 播放的工具，可直接配置为 DLNA 客户端。</p>
</li>
<li class="">
<p><strong>硬件加速基础</strong>：已提前实现 GStreamer 硬件加速播放视频，满足高清流解码需求。</p>
</li>
<li class="">
<p><strong>B 站投屏适配</strong>：B 站 DLNA 投屏时，会发送 <strong>FLV 封装的 H264 流</strong>（类似直播流），通过 <code>gmrender-resurrect</code> 可直接调用硬件加速播放。</p>
</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="三环境搭建安装依赖">三、环境搭建（安装依赖）<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#%E4%B8%89%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%E5%AE%89%E8%A3%85%E4%BE%9D%E8%B5%96" class="hash-link" aria-label="三、环境搭建（安装依赖）的直接链接" title="三、环境搭建（安装依赖）的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-安装基础编译工具">1. 安装基础编译工具<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#1-%E5%AE%89%E8%A3%85%E5%9F%BA%E7%A1%80%E7%BC%96%E8%AF%91%E5%B7%A5%E5%85%B7" class="hash-link" aria-label="1. 安装基础编译工具的直接链接" title="1. 安装基础编译工具的直接链接" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt-get install build-essential \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            autoconf \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            automake \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            libtool \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            pkg-config</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-安装-dlna-与-gstreamer-核心依赖">2. 安装 DLNA 与 GStreamer 核心依赖<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#2-%E5%AE%89%E8%A3%85-dlna-%E4%B8%8E-gstreamer-%E6%A0%B8%E5%BF%83%E4%BE%9D%E8%B5%96" class="hash-link" aria-label="2. 安装 DLNA 与 GStreamer 核心依赖的直接链接" title="2. 安装 DLNA 与 GStreamer 核心依赖的直接链接" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 更新软件源</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt-get update</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 安装 DLNA 依赖与 GStreamer 组件（含编解码、输出插件）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt-get install libupnp-dev libgstreamer1.0-dev \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            gstreamer1.0-plugins-base gstreamer1.0-plugins-good \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">			gstreamer1.0-rockchip1 sudo apt install -y libgstreamer-gl1.0-0 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            gstreamer1.0-libav</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 安装音频输出插件（PulseAudio + ALSA）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install -y gstreamer1.0-pulseaudio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt-get install gstreamer1.0-alsa</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 安装 Git（用于拉取源码）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt-get install git</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="四编译-gmrender-resurrect">四、编译 gmrender-resurrect<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#%E5%9B%9B%E7%BC%96%E8%AF%91-gmrender-resurrect" class="hash-link" aria-label="四、编译 gmrender-resurrect的直接链接" title="四、编译 gmrender-resurrect的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-拉取源码">1. 拉取源码<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#1-%E6%8B%89%E5%8F%96%E6%BA%90%E7%A0%81" class="hash-link" aria-label="1. 拉取源码的直接链接" title="1. 拉取源码的直接链接" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">git clone https://github.com/hzeller/gmrender-resurrect.git</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-编译与构建">2. 编译与构建<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#2-%E7%BC%96%E8%AF%91%E4%B8%8E%E6%9E%84%E5%BB%BA" class="hash-link" aria-label="2. 编译与构建的直接链接" title="2. 编译与构建的直接链接" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 进入源码目录</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd gmrender-resurrect</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 生成配置文件</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./autogen.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 配置编译参数</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./configure</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-复制-logo-文件避免启动报错">3. 复制 Logo 文件（避免启动报错）<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#3-%E5%A4%8D%E5%88%B6-logo-%E6%96%87%E4%BB%B6%E9%81%BF%E5%85%8D%E5%90%AF%E5%8A%A8%E6%8A%A5%E9%94%99" class="hash-link" aria-label="3. 复制 Logo 文件（避免启动报错）的直接链接" title="3. 复制 Logo 文件（避免启动报错）的直接链接" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 复制图标到系统默认目录</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cp data/grender-128x128.png /usr/local/share/gmediarender/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cp data/grender-64x64.png /usr/local/share/gmediarender/</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="五启动-dlna-投屏服务">五、启动 DLNA 投屏服务<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#%E4%BA%94%E5%90%AF%E5%8A%A8-dlna-%E6%8A%95%E5%B1%8F%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="五、启动 DLNA 投屏服务的直接链接" title="五、启动 DLNA 投屏服务的直接链接" translate="no">​</a></h2>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># -f "DshanPI-A1"：设置设备在 DLNA 列表中的显示名称</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># --gstout-videopipe：自定义视频输出 pipeline，强制 Wayland 全屏</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./src/gmediarender  -f "DshanPI-A1" --gstout-videopipe "waylandsink fullscreen=true"</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="六问题排查与解决音频导致视频卡顿">六、问题排查与解决（音频导致视频卡顿）<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#%E5%85%AD%E9%97%AE%E9%A2%98%E6%8E%92%E6%9F%A5%E4%B8%8E%E8%A7%A3%E5%86%B3%E9%9F%B3%E9%A2%91%E5%AF%BC%E8%87%B4%E8%A7%86%E9%A2%91%E5%8D%A1%E9%A1%BF" class="hash-link" aria-label="六、问题排查与解决（音频导致视频卡顿）的直接链接" title="六、问题排查与解决（音频导致视频卡顿）的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-问题现象">1. 问题现象<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#1-%E9%97%AE%E9%A2%98%E7%8E%B0%E8%B1%A1" class="hash-link" aria-label="1. 问题现象的直接链接" title="1. 问题现象的直接链接" translate="no">​</a></h3>
<ul>
<li class="">仅播放视频时正常，添加音频后视频直接卡住。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-排查步骤">2. 排查步骤<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#2-%E6%8E%92%E6%9F%A5%E6%AD%A5%E9%AA%A4" class="hash-link" aria-label="2. 排查步骤的直接链接" title="2. 排查步骤的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="步骤-1检查声卡状态发现挂起">步骤 1：检查声卡状态（发现挂起）<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#%E6%AD%A5%E9%AA%A4-1%E6%A3%80%E6%9F%A5%E5%A3%B0%E5%8D%A1%E7%8A%B6%E6%80%81%E5%8F%91%E7%8E%B0%E6%8C%82%E8%B5%B7" class="hash-link" aria-label="步骤 1：检查声卡状态（发现挂起）的直接链接" title="步骤 1：检查声卡状态（发现挂起）的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 查看所有音频输出设备状态</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pactl list sinks short</span><br></div></code></pre></div></div>
<ul>
<li class="">输出显示所有声卡均处于 <strong>SUSPENDED（挂起）</strong> 状态，且执行 <code>suspend-sink</code> 后无法激活，说明 PulseAudio 与硬件连接异常。</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="步骤-2检查音频服务占用发现冲突">步骤 2：检查音频服务占用（发现冲突）<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#%E6%AD%A5%E9%AA%A4-2%E6%A3%80%E6%9F%A5%E9%9F%B3%E9%A2%91%E6%9C%8D%E5%8A%A1%E5%8D%A0%E7%94%A8%E5%8F%91%E7%8E%B0%E5%86%B2%E7%AA%81" class="hash-link" aria-label="步骤 2：检查音频服务占用（发现冲突）的直接链接" title="步骤 2：检查音频服务占用（发现冲突）的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 查看占用音频设备的进程</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fuser -v /dev/snd/*</span><br></div></code></pre></div></div>
<ul>
<li class="">输出显示 <strong>PulseAudio、WirePlumber、PipeWire</strong> 三个音频服务同时占用设备，存在服务冲突（PipeWire 与 PulseAudio 功能重叠，争夺声卡控制权）。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-解决方案屏蔽-pulseaudio-冲突服务">3. 解决方案（屏蔽 PulseAudio 冲突服务）<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#3-%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E5%B1%8F%E8%94%BD-pulseaudio-%E5%86%B2%E7%AA%81%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="3. 解决方案（屏蔽 PulseAudio 冲突服务）的直接链接" title="3. 解决方案（屏蔽 PulseAudio 冲突服务）的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="步骤-1屏蔽-pulseaudio-自动启动用户级">步骤 1：屏蔽 PulseAudio 自动启动（用户级）<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#%E6%AD%A5%E9%AA%A4-1%E5%B1%8F%E8%94%BD-pulseaudio-%E8%87%AA%E5%8A%A8%E5%90%AF%E5%8A%A8%E7%94%A8%E6%88%B7%E7%BA%A7" class="hash-link" aria-label="步骤 1：屏蔽 PulseAudio 自动启动（用户级）的直接链接" title="步骤 1：屏蔽 PulseAudio 自动启动（用户级）的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 屏蔽服务，阻止自动启动</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">systemctl --user mask pulseaudio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">systemctl --user mask pulseaudio.socket</span><br></div></code></pre></div></div>
<blockquote>
<p>注：此操作会暂时让系统无法识别 PulseAudio 设备，需恢复时执行解除屏蔽命令。</p>
</blockquote>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="步骤-2强制杀死残留-pulseaudio-进程">步骤 2：强制杀死残留 PulseAudio 进程<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#%E6%AD%A5%E9%AA%A4-2%E5%BC%BA%E5%88%B6%E6%9D%80%E6%AD%BB%E6%AE%8B%E7%95%99-pulseaudio-%E8%BF%9B%E7%A8%8B" class="hash-link" aria-label="步骤 2：强制杀死残留 PulseAudio 进程的直接链接" title="步骤 2：强制杀死残留 PulseAudio 进程的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">pkill -9 pulseaudio</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-功能验证确保音频--视频正常">4. 功能验证（确保音频 / 视频正常）<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#4-%E5%8A%9F%E8%83%BD%E9%AA%8C%E8%AF%81%E7%A1%AE%E4%BF%9D%E9%9F%B3%E9%A2%91--%E8%A7%86%E9%A2%91%E6%AD%A3%E5%B8%B8" class="hash-link" aria-label="4. 功能验证（确保音频 / 视频正常）的直接链接" title="4. 功能验证（确保音频 / 视频正常）的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="验证-1音频输出测试">验证 1：音频输出测试<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#%E9%AA%8C%E8%AF%81-1%E9%9F%B3%E9%A2%91%E8%BE%93%E5%87%BA%E6%B5%8B%E8%AF%95" class="hash-link" aria-label="验证 1：音频输出测试的直接链接" title="验证 1：音频输出测试的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 播放 1000Hz 测试音，检查喇叭是否出声</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 audiotestsrc freq=1000 ! audioconvert ! pulsesink</span><br></div></code></pre></div></div>
<ul>
<li class="">
<p>屏蔽PulseAudio后 gst会用alsa来播放音频</p>
</li>
<li class="">
<p>可以通过alsamixer控制音量</p>
</li>
<li class="">
<p>正常出声音，说明音频链路恢复。</p>
</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="验证-2本地视频播放测试">验证 2：本地视频播放测试<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#%E9%AA%8C%E8%AF%81-2%E6%9C%AC%E5%9C%B0%E8%A7%86%E9%A2%91%E6%92%AD%E6%94%BE%E6%B5%8B%E8%AF%95" class="hash-link" aria-label="验证 2：本地视频播放测试的直接链接" title="验证 2：本地视频播放测试的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 播放本地视频，检查音画是否同步</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gst-launch-1.0 playbin uri=file:///root/bad_apple.mp4</span><br></div></code></pre></div></div>
<ul>
<li class="">正常播放且有声音，说明音视频协同正常。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-重新启动-dlna-服务">5. 重新启动 DLNA 服务<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#5-%E9%87%8D%E6%96%B0%E5%90%AF%E5%8A%A8-dlna-%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="5. 重新启动 DLNA 服务的直接链接" title="5. 重新启动 DLNA 服务的直接链接" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">./src/gmediarender  -f "DshanPI-A1" --gstout-videopipe "waylandsink fullscreen=true"</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="七补充恢复-pulseaudio-服务如需">七、补充：恢复 PulseAudio 服务（如需）<a href="https://zephyr.100ask.org/blog/gmrender-bilibili-cast#%E4%B8%83%E8%A1%A5%E5%85%85%E6%81%A2%E5%A4%8D-pulseaudio-%E6%9C%8D%E5%8A%A1%E5%A6%82%E9%9C%80" class="hash-link" aria-label="七、补充：恢复 PulseAudio 服务（如需）的直接链接" title="七、补充：恢复 PulseAudio 服务（如需）的直接链接" translate="no">​</a></h2>
<p>若后续需要使用 PulseAudio，执行以下命令解除屏蔽：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">systemctl --user unmask pulseaudio</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">systemctl --user unmask pulseaudio.socket</span><br></div></code></pre></div></div>]]></content:encoded>
            <category>RK3576</category>
            <category>gmrender</category>
            <category>投屏</category>
            <category>DLNA</category>
        </item>
        <item>
            <title><![CDATA[DshanPI-A1 RK3576 Armbian 远程桌面]]></title>
            <link>https://zephyr.100ask.org/blog/armbian-remote-desktop</link>
            <guid>https://zephyr.100ask.org/blog/armbian-remote-desktop</guid>
            <pubDate>Sat, 08 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[在 Wayland 与开源 GPU 驱动环境下，使用 Armbian 自带远程桌面解决 NoMachine 虚拟桌面与 GPU 加速失效问题。]]></description>
            <content:encoded><![CDATA[<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="背景与问题">背景与问题<a href="https://zephyr.100ask.org/blog/armbian-remote-desktop#%E8%83%8C%E6%99%AF%E4%B8%8E%E9%97%AE%E9%A2%98" class="hash-link" aria-label="背景与问题的直接链接" title="背景与问题的直接链接" translate="no">​</a></h3>
<ul>
<li class="">
<p>使用设备：DshanPI-A1，搭载 Armbian 系统，窗口系统为 Wayland，GPU 采用开源驱动。</p>
</li>
<li class="">
<p>初始尝试：使用 NoMachine 实现远程桌面，但存在两个问题：</p>
</li>
</ul>
<ol>
<li class="">
<p>默认创建虚拟桌面，而非物理桌面；</p>
</li>
<li class="">
<p>对 Wayland 支持不佳，会以兼容模式开启 X11 桌面，导致 OpenGL 无法调用 GPU 加速。</p>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="解决方案使用-armbian-自带远程桌面">解决方案：使用 Armbian 自带远程桌面<a href="https://zephyr.100ask.org/blog/armbian-remote-desktop#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E4%BD%BF%E7%94%A8-armbian-%E8%87%AA%E5%B8%A6%E8%BF%9C%E7%A8%8B%E6%A1%8C%E9%9D%A2" class="hash-link" aria-label="解决方案：使用 Armbian 自带远程桌面的直接链接" title="解决方案：使用 Armbian 自带远程桌面的直接链接" translate="no">​</a></h3>
<ol>
<li class="">
<p><strong>安装必要环境</strong></p>
<p>由于系统默认未预装远程桌面组件，先通过命令安装：</p>
</li>
</ol>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install gnome-remote-desktop</span><br></div></code></pre></div></div>
<ol start="2">
<li class=""><strong>配置远程桌面</strong></li>
</ol>
<ul>
<li class="">
<p>重启设置窗口（关闭后重新打开），依次进入 <code>Settings → System → Remote Desktop</code>。</p>
</li>
<li class="">
<p>勾选 <code>Desktop Sharing</code>（桌面共享）和 <code>Remote Control</code>（远程控制）。</p>
</li>
<li class="">
<p>初始密码为随机生成，需手动修改为自定义密码。</p>
</li>
</ul>
<ol start="3">
<li class=""><strong>连接与验证</strong></li>
</ol>
<ul>
<li class="">
<p>在 Windows 端打开「远程桌面连接」，输入设备 IP、用户名及密码。</p>
</li>
<li class="">
<p>首次登录可能黑屏，重启设备后连接成功。</p>
</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="功能验证">功能验证<a href="https://zephyr.100ask.org/blog/armbian-remote-desktop#%E5%8A%9F%E8%83%BD%E9%AA%8C%E8%AF%81" class="hash-link" aria-label="功能验证的直接链接" title="功能验证的直接链接" translate="no">​</a></h3>
<p>通过命令测试 GPU 加速是否正常：</p>
<ul>
<li class="">
<p>执行 <code>glxinfo -B</code>，输出显示 Mali GPU 信息（OpenGL 支持正常）；</p>
</li>
<li class="">
<p>执行 <code>es2_info</code>，同样检测到 Mali GPU（OpenGLES 支持正常）。</p>
</li>
</ul>
<p>结论：远程桌面可正常调用 GPU 加速，满足需求。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="参考资料">参考资料<a href="https://zephyr.100ask.org/blog/armbian-remote-desktop#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99" class="hash-link" aria-label="参考资料的直接链接" title="参考资料的直接链接" translate="no">​</a></h3>
<ul>
<li class="">
<p>《Armbian 25.5.1 Noble Gnome 开启远程桌面功能》</p>
<p>（<a href="https://blog.csdn.net/u013833472/article/details/149032655" target="_blank" rel="noopener noreferrer" class="">https://blog.csdn.net/u013833472/article/details/149032655</a>）</p>
</li>
</ul>]]></content:encoded>
            <category>RK3576</category>
            <category>Armbian</category>
            <category>远程桌面</category>
            <category>Wayland</category>
        </item>
        <item>
            <title><![CDATA[DshanPi-A1 介绍]]></title>
            <link>https://zephyr.100ask.org/blog/welcome</link>
            <guid>https://zephyr.100ask.org/blog/welcome</guid>
            <pubDate>Thu, 06 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[DshanPi-A1 聚焦 AI 教育场景，以单板计算机加专题项目的一体化形态，为从入门到高阶的教学需求提供可持续演进的软硬件生态。]]></description>
            <content:encoded><![CDATA[<p>DshanPi-A1 聚焦 AI 教育场景，以“单板计算机  + 专题项目（付费）”的一体化形态，为从入门到高阶的教学需求提供可持续演进的软硬件生态。
提供中高端性能 SBC 体验，包括 PCIe、USB3.0、双千兆、HDMI、HDMI-IN、DP等丰富的接口。</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>提示</div><div class="admonitionContent_BuS1"><ul>
<li class="">源码仓库：<a href="https://github.com/dshanpi/" target="_blank" rel="noopener noreferrer" class="">https://github.com/dshanpi/</a></li>
<li class="">QQ交流群：798273638</li>
<li class="">商品链接：<a href="https://detail.tmall.com/item.htm?id=953384132961" target="_blank" rel="noopener noreferrer" class="">https://detail.tmall.com/item.htm?id=953384132961</a></li>
<li class="">镜像站点：<a href="https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/" target="_blank" rel="noopener noreferrer" class="">https://dl.100ask.net/Hardware/MPU/RK3576-DshanPi-A1/</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="dshanpl-a1-education">DShanPl-A1 Education<a href="https://zephyr.100ask.org/blog/welcome#dshanpl-a1-education" class="hash-link" aria-label="DShanPl-A1 Education的直接链接" title="DShanPl-A1 Education的直接链接" translate="no">​</a></h2>
<p>DShanPl-A1 Education专为人工智能教育及项目开发深度优化，基于瑞芯微的RK3576处理器设计，集成了4个Cortex-A72和4个Cortex-A53及支持NEON指令集,支持8K@30fps的H.265,VP9AVS2
和 AV1解码器,4k@60fps的H.264解码器和4K@60fps的AV1解码器;还支持4K@60fps的H.264和H.265编码器。内置3D GPU,能够完全兼容OpenGl ES1.1/2.0/3.2、0penCL2.0和Vulkan 1.1。内嵌的NPU算力高达6TopS,支持INT4/INT8/INT16/FP16混合运算。</p>
<!-- -->
<div class="theme-tabs-container tabs-container tabList__CuJ"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_LNqP tabs__item--active">正面功能示意图</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">背面功能示意图</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">产品宣传主图</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_Ymn6"></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""></div></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="规格参数">规格参数<a href="https://zephyr.100ask.org/blog/welcome#%E8%A7%84%E6%A0%BC%E5%8F%82%E6%95%B0" class="hash-link" aria-label="规格参数的直接链接" title="规格参数的直接链接" translate="no">​</a></h3>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>DshanPI-A1 Education RK3576 SBC详细规格参数介绍： </summary><div><div class="collapsibleContent_i85q"><div></div></div></div></details>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="系统支持的外设驱动">系统支持的外设驱动<a href="https://zephyr.100ask.org/blog/welcome#%E7%B3%BB%E7%BB%9F%E6%94%AF%E6%8C%81%E7%9A%84%E5%A4%96%E8%AE%BE%E9%A9%B1%E5%8A%A8" class="hash-link" aria-label="系统支持的外设驱动的直接链接" title="系统支持的外设驱动的直接链接" translate="no">​</a></h3>
<p>✅: 支持—  ❌: 暂不支持 —  🚫: 无计划支持   —⚠：支持但未完整测试</p>
<table><thead><tr><th>系统版本</th><th>Armbian</th><th>Buildroot</th><th>OpenWrt-LEDE</th><th>ArchLinux</th><th>OpenEuler</th><th>Fedora</th></tr></thead><tbody><tr><td>SPI</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>I2C</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>PWM</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>UART</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>MMC</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>✅</td></tr><tr><td>GPIO</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td>NPU</td><td>✅</td><td>✅</td><td>⚠</td><td>✅</td><td>❌</td><td>❌</td></tr><tr><td>USB2.0</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td></tr><tr><td>USB3.0</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td></tr><tr><td>PCI-e</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td></tr><tr><td>视频编码</td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td><td>❌</td></tr><tr><td>视频解码</td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td><td>❌</td></tr><tr><td>MIPI CSI</td><td>❌</td><td>✅</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td></tr><tr><td>Audio</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td></tr><tr><td>WIFI</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="dshanpl-r1">DShanPl-R1+<a href="https://zephyr.100ask.org/blog/welcome#dshanpl-r1" class="hash-link" aria-label="DShanPl-R1+的直接链接" title="DShanPl-R1+的直接链接" translate="no">​</a></h2>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>提示</div><div class="admonitionContent_BuS1"><p>进度：批量生产中</p></div></div>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>DshanPI-R1+ RK3568 SBC 产品图： </summary><div><div class="collapsibleContent_i85q"><div></div></div></div></details>]]></content:encoded>
            <category>DshanPi-A1</category>
            <category>介绍</category>
            <category>RK3576</category>
        </item>
    </channel>
</rss>