拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

Jetson Nano 4GB B01:TensorRT目标检测与手势识别实战

Jetson Nano 4GB B01:TensorRT目标检测与手势识别实战

1. 开篇:Jetson Nano 4GB B01 为什么还值得折腾

Jetson Nano 4GB B01 的系统安装、目标检测和手势识别,是我最近重新翻出来折腾的一套组合。原因很简单:这块板子虽然发布有些年头了,但它把 CUDA、TensorRT、OpenCV、GStreamer 和 Ubuntu 桌面塞进了一张信用卡大小的板子里,价格在二手市场也不算离谱。对于想入门边缘 AI、机器视觉、机器人视觉的学生、创客和转行工程师来说,它仍然是一块很好的跳板。你可以在上面跑 SSD-MobileNet 做目标检测,也可以用 PoseNet 手部关键点模型加上几十行规则代码,做出一个能识别石头剪刀布、点赞、数字手势的实时 Demo。整个过程会逼着你把 Linux 系统安装、供电、散热、CSI 摄像头、GStreamer 管道、TensorRT 模型部署这些环节都摸一遍。

我这次的目标很明确:从官方镜像烧录开始,把系统装好,把远程访问和 Swap 配好,然后编译 jetson-inference,最后分别跑通目标检测和手势识别两个官方 Demo 路线。目标检测用 detectNet,手势识别用 PoseNet 的 resnet18-hand 模型。后者严格来说不是官方直接叫“手势识别”的成品 Demo,而是官方姿态估计 Demo 的一个手部模型分支,需要自己补一层手指伸展判断逻辑。我会把这层逻辑也写出来,方便你直接复现。全文会尽量按真实操作顺序展开,包括我踩过的坑、参数怎么选、性能大概什么水平、遇到问题怎么排查。适合手上已经有一块 Jetson Nano 4GB B01,或者正准备入手、想先看看全流程难度的朋友。

1.1 这块板子适合谁,不适合谁

先说适合谁。如果你是想学 TensorRT 部署、想了解边缘设备上模型推理的完整链路、想做一个小型智能摄像头或者机器人视觉节点,Jetson Nano 4GB B01 非常合适。它有 128 核 Maxwell GPU、四核 ARM A57 CPU、4GB LPDDR4 内存,跑轻量级目标检测和姿态估计能到十几到二十几 FPS,足够做交互 Demo。它的 GPIO 兼容树莓派 40 针,CSI 摄像头接口也有官方 IMX219 支持,硬件生态比较成熟。再配合 JetPack 4.6.x,系统里自带 CUDA 10.2、cuDNN、TensorRT、OpenCV,很多环境不需要自己从零编译,省掉大量时间。

不适合谁?如果你想在本地训练大模型、想跑 YOLOv8 大模型、想同时开多个高分辨率摄像头、想做多路视频分析,Jetson Nano 4GB 会很吃力。它的内存只有 4GB,CPU 性能也有限,编译大项目时很容易爆内存。它的系统版本停留在 Ubuntu 18.04,Python 默认是 3.6,很多新库的新版本不一定兼容。所以我的建议是:把它当成推理端和验证端,训练放在带独显的 PC 或者云平台上。这样定位清楚之后,Jetson Nano 的体验会好很多。我见过不少人一上来就想在 Nano 上训练自定义检测模型,结果卡在内存和散热上,最后误以为板子坏了,其实只是任务选错了。

1.2 这次要跑通的目标和路线

这次我给自己定了三个可验收的目标。第一,系统安装成功,能进桌面、能联网、能 SSH,系统信息里能看到 L4T 版本、CUDA、TensorRT 和 OpenCV。第二,目标检测 Demo 跑通,用 CSI 或 USB 摄像头实时显示检测框,能识别 COCO 常见类别,比如人、杯子、键盘、手机、椅子。第三,手势识别 Demo 跑通,先用 PoseNet 手部模型画出 21 个手部关键点,再用简单几何规则判断手指伸展数量,最后在画面上叠加“fist”“open”“victory”“point”这类文字。过程中我会记录分辨率、FPS、温度、电源模式这些数据,方便你对照自己的环境判断是否正常。

路线选择上,我优先走官方 jetson-inference 项目,因为它的模型下载、TensorRT 引擎生成、摄像头管道都已经封装好了,适合快速验证硬件和软件栈。手势识别部分我没有直接找第三方 MediaPipe 方案,因为 MediaPipe 在 Jetson Nano 的 Ubuntu 18.04 上安装依赖比较折腾,而 jetson-inference 的 PoseNet 本身就带手部模型,复用同一套摄像头和显示代码更省事。这个选择背后的逻辑是:先用官方生态把推理链路跑通,再考虑替换模型或接入自己的业务逻辑。这样出问题时排查范围小,不会一上来就陷进依赖地狱。

2. 系统安装前的准备:电源、SD 卡、镜像与散热

Jetson Nano 4GB B01 的系统安装本身不复杂,但硬件准备如果马虎,后面会出现各种玄学问题。我遇到最多的就是供电不足导致反复重启、SD 卡速度太慢导致系统卡死、散热不够导致跑 Demo 几分钟就降频。所以这一章先把物料和烧录讲清楚。你不需要买最贵的配件,但电源、SD 卡、散热这三样不能省。尤其是 B01 版本有 DC 桶形供电口和 J48 跳线,很多新手不知道要短接跳线,结果插了 DC 电源仍然从 USB 口取电,带不动摄像头和 GPU 满载。

2.1 硬件清单与供电避坑

我的建议清单如下:Jetson Nano 4GB B01 开发板一块;DC 5V 4A 电源一个,插头规格 5.5mm x 2.1mm,中心正极;跳线帽一个,用来短接 J48;microSD 卡一张,容量至少 32GB,推荐 64GB,速度等级 UHS-I U3、A1 或 A2;USB 读卡器一个;散热片加 5V 风扇一套;HDMI 显示器、USB 键盘鼠标一套,用于首次开机;网线一根,或者兼容的 USB WiFi 模块;CSI 摄像头 IMX219 一个,或者 USB 摄像头一个;可选 USB 转 TTL 串口模块,用于无显示器调试。这里每一项都有原因:DC 5V 4A 是为了给 GPU 满载和摄像头留余量;U3 卡是为了减少系统卡顿;J48 跳线决定 DC 口是否真正供电;散热片和风扇决定长时间跑 Demo 会不会降频。

供电部分我要单独强调。Jetson Nano B01 的 DC 口旁边有 J48 跳线,使用 DC 电源时需要用跳线帽短接。如果你用 USB-C 或者 microUSB 供电,电流通常只有 5V 2A 左右,跑目标检测时很容易触发欠压保护,表现为突然重启、画面卡住、SSH 断开。我用 5V 2A 电源跑 detectnet 时,刚开始几秒正常,一旦模型加载完 GPU 拉满,板子就重启。换成 5V 4A DC 电源并短接 J48 之后,同样场景稳定运行。这个坑非常典型,如果你遇到跑 AI Demo 就重启,先检查供电,不要先怀疑系统。

2.2 官方镜像烧录与首次开机

系统镜像我选择 NVIDIA 官方为 Jetson Nano 提供的 JetPack 4.6.x SD 卡镜像。下载下来是一个压缩包,解压后得到 img 文件。烧录工具用 balenaEtcher 最省心,Windows、Linux、macOS 都有版本。操作步骤是:插入读卡器,打开 Etcher,选择镜像文件,选择目标 SD 卡,点击 Flash,等待校验完成。注意不要选错盘,否则会覆盖电脑硬盘。烧录完成后,如果 Windows 提示格式化,直接取消,不要格式化。把 SD 卡插到 Nano 背面卡槽,接好显示器、键盘鼠标、网线,短接 J48,插 DC 电源,板子会自动开机。

首次开机进入 Ubuntu 18.04 的初始设置向导。依次选择语言、键盘布局、时区,然后设置用户名、密码、主机名。这里建议用户名不要用中文,密码记牢,因为后面 sudo 和 SSH 都要用。设置完成后系统会进行一些初始化,可能黑屏几次,耐心等。进入桌面后,先看右上角网络图标是否联网。如果插网线,一般会自动获取 IP。如果是 WiFi,需要选择热点并输入密码。第一次开机后不要急着跑 Demo,先确认系统信息。打开终端,执行cat /etc/nv_tegra_release,应该能看到 L4T 版本,比如 R32.7.x。执行nvcc --version,应该能看到 CUDA 10.2。执行python3 --version,应该是 Python 3.6.x。这些信息正常,说明基础系统没问题。

2.3 首次启动后的基础检查与更新

基础检查还包括 TensorRT 和 OpenCV。可以执行dpkg -l | grep tensorrt查看 TensorRT 包,执行python3 -c "import cv2; print(cv2.__version__)"查看 OpenCV 版本。JetPack 4.6.x 一般自带 OpenCV 4.1.1。接下来可以更新系统,但要有心理准备:Jetson Nano 的 apt 更新可能比较慢,而且升级内核相关包有风险。我的习惯是只做sudo apt update和必要的软件安装,不盲目sudo apt upgrade全部包。如果你确实要升级,先确保 SD 卡有足够空间,电源稳定,最好接显示器操作。更新完成后重启一次,确认还能正常进桌面。

还有一个容易被忽略的点:检查磁盘空间。df -h看一下根分区剩余空间。jetson-inference 编译和模型下载会占用不少空间,建议至少留 10GB 以上。如果 SD 卡是 32GB,系统占掉一部分后可能比较紧张。我一般会用 64GB 卡,这样编译、模型、录制的视频都有地方放。如果你打算长期用,也可以考虑把系统迁移到 SSD,但 Jetson Nano 的 USB 3.0 启动需要刷写 bootloader 和改配置,属于进阶操作,第一次玩建议先用 SD 卡跑通全流程。

3. 把系统调顺:远程、Swap、风扇与性能模式

系统能进桌面只是第一步。要舒服地跑 Demo,还需要把远程访问、Swap、风扇和性能模式配好。Jetson Nano 4GB 的内存不大,编译 jetson-inference 时容易爆内存,Swap 几乎是必加项。风扇如果不转,跑目标检测几分钟后温度就会上去,GPU 降频,FPS 掉得厉害。电源模式也决定性能上限,默认可能是 5W 模式,需要手动切到 MAXN 10W。这些配置都不难,但提前做好能省掉很多“为什么我的 FPS 这么低”的困惑。

3.1 SSH 与文件传输

我更习惯用 SSH 从主力电脑操作 Jetson Nano,因为 Nano 桌面在 VNC 下跑 OpenGL 程序会非常卡,而且 AI Demo 的显示窗口通过 VNC 看也不流畅。启用 SSH 的命令是:

sudo apt update sudo apt install openssh-server sudo systemctl enable ssh sudo systemctl start ssh hostname -I

hostname -I会显示 Nano 的 IP 地址。之后在主力电脑上执行ssh 用户名@IP就能登录。文件传输用scp或者sftp,比如把模型文件传到 Nano:scp model.onnx 用户名@IP:/home/用户名/。如果你要用 VNC 做桌面配置,可以在 Ubuntu 设置里打开“共享”,启用屏幕共享,但记住:VNC 只适合改配置、看文件,不适合跑实时摄像头 Demo。跑 detectnet 和 posenet 时,最好直接接 HDMI 显示器,或者用 SSH 看终端输出,把显示输出关掉。

3.2 增加 Swap,防止编译爆内存

Jetson Nano 4GB 的物理内存跑推理够用,但编译大型项目时不够。jetson-inference 编译过程中会调用 CMake、g++、Python 绑定生成等,内存峰值很容易超过 4GB。我的做法是加 4GB Swap 文件。命令如下:

sudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile free -h echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

执行完free -h应该能看到 Swap 变成 4GB。最后一行写入/etc/fstab是为了重启后自动挂载。注意:Swap 放在 SD 卡上,速度比内存慢很多,只能救急,不能当内存用。编译时如果发现系统非常卡,说明 Swap 正在频繁读写,这时候可以把编译并行数降到-j1或-j2。我一般用make -j2,再高就容易卡死。如果你用的是低速 SD 卡,Swap 体验会更差,所以前面强调 U3 卡是有道理的。

3.3 风扇、时钟与电源模式

散热方面,如果你装了 5V 风扇,可以手动控制转速。Jetson Nano 的风扇接口一般对应/sys/devices/pwm-fan/target_pwm,写入 0 到 255 之间的值。开机默认可能是 0 或者较低值,跑 Demo 时建议临时拉满:

sudo sh -c 'echo 255 > /sys/devices/pwm-fan/target_pwm'

想让它自动随温度调节,可以写一个简单的 systemd 服务或者脚本,但第一次跑 Demo 手动拉满就够。温度监控用tegrastats,可以看到 CPU、GPU、内存、温度、功耗。电源模式用sudo nvpmodel -m 0切到 MAXN 10W,用sudo nvpmodel -m 1切到 5W。跑目标检测和手势识别时,我建议用 MAXN。锁定最高频率用sudo jetson_clocks,这会把 CPU、GPU、EMC 拉到最高频率,代价是发热和功耗增加。实测在散热到位的情况下,nvpmodel -m 0加jetson_clocks能让 detectnet 的 FPS 提升几帧,稳定性也更好。

4. 官方 Demo 环境搭建:jetson-inference 编译与模型下载

jetson-inference 是 NVIDIA 工程师维护的推理示例集合,包含图像分类、目标检测、语义分割、姿态估计等。它把 TensorRT 推理、摄像头输入、OpenGL 显示封装成了 C++ 和 Python API,适合快速验证。编译这个项目是本次系统安装后最关键的一步,也是最容易出问题的一步。只要这一步过了,后面的 detectnet 和 posenet 基本都是命令参数调整。我建议在编译前先确认 Swap 已经启用,电源稳定,SD 卡剩余空间足够。

4.1 源码获取与依赖安装

先安装基础依赖:

sudo apt-get install git cmake libpython3-dev python3-numpy

然后克隆源码,注意要加--recursive,因为子模块里有 TensorRT 工具和模型下载脚本:

git clone --recursive https://github.com/dusty-nv/jetson-inference cd jetson-inference

如果你的网络下载 GitHub 比较慢,可以提前在别的机器上下载 zip 包,再用 scp 传到 Nano。不要用不可靠的第三方修改版,避免引入后门或兼容问题。克隆完成后,可以看一下目录结构,tools目录下有模型下载脚本,python目录下有 Python 示例,c目录下有 C++ 示例。接下来创建 build 目录并配置 CMake:

mkdir build cd build cmake ../

CMake 过程中可能会提示是否下载 PyTorch 等组件,按默认选择即可。如果提示下载模型,也可以先跳过,后面单独下载。注意看终端输出,如果有依赖缺失,按提示安装。常见缺失包括libpython3-dev、python3-numpy、git、cmake。安装完重新执行 CMake。

4.2 编译参数与内存控制

配置完成后开始编译:

make -j2 sudo make install sudo ldconfig

make -j2表示用两个并行任务。Jetson Nano 四核 CPU,理论上可以-j4,但 4GB 内存很容易被撑爆。我用-j2比较稳,编译时间大概几十分钟到一两个小时,取决于 SD 卡速度和散热。如果中途报错virtual memory exhausted或者进程被 killed,说明内存不够,降到-j1再试。编译成功后执行sudo make install,把库和可执行文件安装到系统目录。sudo ldconfig刷新动态库缓存。之后可以进入build/aarch64/bin目录,看到detectnet-camera、posenet-camera、imagenet-camera等可执行文件。

编译过程中如果风扇没转,建议手动拉满,并且用tegrastats观察温度。温度长期超过 80 摄氏度,GPU 会降频,编译时间会变长。如果编译到一半断电,可能留下不完整的 build 目录,最好删掉build重新来。我的经验是:编译前先free -h确认 Swap 生效,编译时不要开桌面浏览器和视频播放器,尽量用 SSH 操作,减少桌面占用。这样一次成功的概率高很多。

4.3 模型下载与 TensorRT 引擎生成

编译完成后下载预训练模型:

cd ~/jetson-inference/tools ./download-models.sh

脚本会列出可下载的模型,包括图像分类、目标检测、语义分割、姿态估计。目标检测我选ssd-mobilenet-v2,手势识别我选resnet18-hand。你可以用空格键选择,回车确认。模型会下载到jetson-inference/data/networks目录。下载完成后,第一次运行 Demo 时,TensorRT 会把 ONNX 或 Caffe 模型转换成.engine文件。这个过程可能需要几分钟,终端会显示进度。转换完成后,后续启动会直接加载 engine,速度快很多。

这里有一个重要细节:TensorRT engine 和具体的 TensorRT 版本、GPU 架构绑定。如果你换了 JetPack 版本,或者把 engine 拷到别的设备,可能无法使用,需要重新生成。所以不要把 engine 当成通用模型文件。模型下载如果中断,可以重新运行脚本,它会跳过已完成的文件。如果你手动下载模型,注意目录结构要和脚本预期一致,否则运行时找不到。下载完可以用ls -lh data/networks查看模型大小,确认文件完整。

5. 目标检测官方 Demo 实测

目标检测是 Jetson Nano 最经典的 Demo 之一。jetson-inference 提供的 detectNet 支持 SSD-MobileNet-v2、SSD-Inception-v2 等模型,在 COCO 数据集上训练,可以识别 80 类常见物体。实测下来,SSD-MobileNet-v2 在 640x480 分辨率下能到 20 FPS 左右,具体取决于电源模式、散热、摄像头和背景复杂度。这个性能做交互 Demo 够用,但不要期望像桌面显卡那样流畅。目标检测跑通之后,你可以很直观地看到模型输入、推理、后处理、叠加框、显示整个链路。

5.1 摄像头选择与 GStreamer 管道

Jetson Nano 支持 CSI 摄像头和 USB 摄像头。CSI 摄像头通过 MIPI CSI-2 接口连接,延迟低,CPU 占用少,官方 IMX219 驱动支持好。USB 摄像头即插即用,但会占用 USB 带宽和 CPU。我的建议是优先用 CSI 摄像头。连接 CSI 摄像头时注意排线方向:金属触点朝向散热片方向,排线插到底,卡扣压紧。接好后执行ls /dev/video*,应该能看到/dev/video0。如果看不到,检查排线和驱动。USB 摄像头一般也是/dev/video0或/dev/video1,可以用v4l2-ctl --list-devices查看。

jetson-inference 内部用 GStreamer 抓取摄像头。CSI 摄像头的管道通常是nvarguscamerasrc,USB 摄像头是v4l2src。如果你直接用默认参数运行 Demo,程序会自动选择。但为了稳定,我建议手动指定分辨率。比如 CSI 摄像头可以用:

./detectnet-camera --camera=/dev/video0 --width=640 --height=480 --network=ssd-mobilenet-v2

如果报错找不到摄像头,可以尝试指定csi://0或v4l2:///dev/video0。GStreamer 报错信息通常比较长,重点看最后几行,常见原因是摄像头被其他进程占用、排线接触不良、分辨率不支持。跑之前可以用nvgstcapture-1.0测试 CSI 摄像头,用cheese或fswebcam测试 USB 摄像头。

5.2 detectnet-camera 运行与参数

进入可执行文件目录:

cd ~/jetson-inference/build/aarch64/bin ./detectnet-camera /dev/video0 --network=ssd-mobilenet-v2 --width=640 --height=480 --threshold=0.5

第一次运行会生成 TensorRT engine,等待几分钟。看到视频窗口后,画面中的人、杯子、键盘等物体会被框出来,并显示类别和置信度。--threshold=0.5表示只显示置信度大于 0.5 的检测框,调低会显示更多框,但误检也更多。--overlay=box,labels,conf可以控制叠加内容。如果你想保存检测结果,可以用--output-codec=h264和--output=/path/output.mp4,但会占用额外 CPU。Python 版本命令类似:

python3 detectnet-camera.py --network=ssd-mobilenet-v2 --width=640 --height=480

实测中,SSD-MobileNet-v2 在 640x480 下比较流畅,人物、椅子、瓶子、手机识别率不错。小物体、遮挡物体、逆光场景容易漏检。置信度阈值不要设太低,否则背景纹理也可能被误认为目标。如果你的应用需要检测特定类别,可以用--filter参数只显示某些类别,比如--filter=person,cup,这样画面更干净,后处理也更容易。

5.3 性能记录与优化

我在 MAXN 10W 模式、jetson_clocks开启、风扇 255 的条件下做了几组记录。SSD-MobileNet-v2 在 640x480 下大约 18 到 24 FPS,1280x720 下降到 10 到 14 FPS。SSD-Inception-v2 精度略高,但速度明显慢一些,640x480 大约 10 到 14 FPS。温度方面,不加散热片只靠被动散热,几分钟后温度超过 80 度,FPS 会掉到个位数。加了散热片和风扇后,温度稳定在 55 到 65 度,FPS 波动小很多。功耗方面,MAXN 模式下整板峰值可以到 10W 左右,5V 4A 电源完全够用。

优化技巧有几个。第一,降低输入分辨率到 640x480,对 FPS 提升最明显。第二,使用 SSD-MobileNet-v2 而不是 Inception 系列。第三,锁定 MAXN 和 jetson_clocks。第四,关闭桌面动画和浏览器,减少 CPU 占用。第五,如果不需要实时显示,可以用--headless模式只保存结果,FPS 会更高。第六,确保 TensorRT 使用 FP16,jetson-inference 默认会尝试 FP16,如果模型不支持会回退 FP32。第七,摄像头帧率不要设太高,30fps 足够,设 60fps 反而增加 USB 带宽和 CPU 负担。实测这些调整叠加后,SSD-MobileNet-v2 可以稳定在 20 FPS 以上。

6. 手势识别 Demo 实测

手势识别部分我走的是 PoseNet 手部模型路线。jetson-inference 的 PoseNet 支持人体姿态和手部姿态,resnet18-hand模型可以输出 21 个手部关键点。官方 Demo 运行后会在手上画出骨架,但它不会直接告诉你这是“石头”还是“布”。所以我加了一层几何规则:计算每根手指的指尖到手腕距离,和对应指节到手腕距离比较,判断手指是否伸直。这个方法简单、可解释、不需要训练,适合快速做出交互 Demo。当然,它对遮挡和光照比较敏感,后面也可以换成训练分类器。

6.1 PoseNet 手部模型跑通

先运行官方 PoseNet 手部 Demo:

cd ~/jetson-inference/build/aarch64/bin ./posenet-camera /dev/video0 --network=resnet18-hand --width=640 --height=480 --threshold=0.5

第一次运行会生成 TensorRT engine,等待几分钟。之后视频窗口会显示手部关键点骨架。实测在 640x480 下,resnet18-hand 大约 12 到 18 FPS,比 SSD-MobileNet-v2 稍慢,但足以做手势交互。手部离摄像头太远、光线太暗、背景杂乱时,关键点会抖动或丢失。建议手部占据画面较大比例,背景简单,光线均匀。如果画面中没有手,模型不会输出姿态,程序也不会报错。Python 版本命令类似:

python3 posenet-camera.py --network=resnet18-hand --width=640 --height=480

注意,PoseNet 的手部模型输出的是关键点坐标,不是手势类别。你要先确认关键点稳定,再做分类。如果关键点本身跳动很厉害,分类结果也会不稳定。我的做法是在关键点上加一个简单的滑动平均滤波,比如保存最近 5 帧的坐标,取平均后再判断手指伸展。这样手势文字不会频繁闪烁。

6.2 手部关键点索引与规则分类

手部 21 个关键点的常见索引是:0 手腕,1 到 4 拇指,5 到 8 食指,9 到 12 中指,13 到 16 无名指,17 到 20 小指。每根手指的 4 个点从根部到指尖排列。判断手指伸直的一个简单规则是:指尖到手腕的距离大于第二指节到手腕的距离乘以一个阈值。比如食指指尖是 8,第二指节是 6,如果dist(8,0) > dist(6,0) * 1.15,就认为食指伸直。拇指因为结构不同,可以用指尖 4 和指节 3 到手腕的距离比较,或者结合拇指和食指根部的距离。阈值 1.15 是我实测下来比较稳的经验值,你也可以根据手的大小调整。

根据伸直手指数量,可以粗略分类:0 根伸直是握拳,1 根是点赞或指方向,2 根是剪刀手,5 根是张开手掌,3 根或 4 根可以定义为数字手势。实际测试中,拇指判断最容易出错,因为拇指活动范围大,关键点容易和掌心重叠。我的建议是先把食指、中指、无名指、小指四根判断准,拇指单独处理或者先忽略。对于石头剪刀布,你只需要判断 0 根、2 根、5 根三种状态,稳定性会好很多。先把简单场景做稳,再扩展复杂手势。

6.3 一个可运行的手势识别脚本

下面这段代码是在 jetson-inference Python API 基础上改的,核心逻辑是读取 PoseNet 关键点,判断手指伸展,然后在画面上叠加手势文字。你可以在jetson-inference/build/aarch64/bin目录下新建gesture.py,根据你的摄像头类型调整输入源。

import jetson.inference import jetson.utils net = jetson.inference.poseNet("resnet18-hand", threshold=0.5) camera = jetson.utils.videoSource("csi://0", argv=["--input-width=640", "--input-height=480", "--input-rate=30"]) display = jetson.utils.videoOutput("display://0") finger_tips = [4, 8, 12, 16, 20] finger_pips = [3, 6, 10, 14, 18] hand_pairs = [ (0,1),(1,2),(2,3),(3,4), (0,5),(5,6),(6,7),(7,8), (0,9),(9,10),(10,11),(11,12), (0,13),(13,14),(14,15),(15,16), (0,17),(17,18),(18,19),(19,20) ] def dist(a, b): return ((a.x - b.x) ** 2 + (a.y - b.y) ** 2) ** 0.5 while display.IsStreaming(): img = camera.Capture() poses = net.Process(img) gesture = "none" for pose in poses: kps = {kp.ID: kp for kp in pose.Keypoints} if all(i in kps for i in finger_tips + [0]): extended = 0 for tip, pip in zip(finger_tips, finger_pips): if dist(kps[tip], kps[0]) > dist(kps[pip], kps[0]) * 1.15: extended += 1 if extended == 0: gesture = "fist" elif extended == 5: gesture = "open" elif extended == 2: gesture = "victory" elif extended == 1: gesture = "point" else: gesture = "{} fingers".format(extended) for a, b in hand_pairs: if a in kps and b in kps: jetson.utils.cudaDrawLine( img, (kps[a].x, kps[a].y), (kps[b].x, kps[b].y), (0, 255, 0, 200), 2) for kp in pose.Keypoints: jetson.utils.cudaDrawCircle(img, (kp.x, kp.y), 3, (255, 0, 0, 200)) if gesture != "none": jetson.utils.cudaDrawText( img, (10, 10), "Gesture: " + gesture, (255, 255, 0, 255), 24) display.Render(img) display.SetStatus("Hand Gesture | FPS {:.1f}".format(net.GetNetworkFPS()))

运行命令是python3 gesture.py。如果使用 USB 摄像头,把csi://0改成/dev/video0。如果显示窗口打不开,确认你是本地 HDMI 显示而不是 VNC。实测这个脚本在 640x480 下能稳定识别张开手掌、握拳、剪刀手。手势文字偶尔会跳变,可以加一个队列,连续 3 帧同一结果才更新显示。另外,cudaDrawText的字体大小和位置可以根据画面调整,别让文字挡住手部关键点。

6.4 训练自己的手势分类器思路

规则分类适合快速验证,但如果你要识别复杂手势,比如数字 1 到 10、特定手势指令,最好训练一个分类器。思路是:先用 jetson-inference 的camera-capture工具采集手势图片,每个类别拍几百张,注意变换背景、光照、手部角度。然后在 PC 上用 PyTorch 训练一个轻量级分类网络,比如 MobileNetV2 或 ResNet18,输入 224x224 图片,输出手势类别。训练完成后导出 ONNX,再在 Jetson Nano 上用 TensorRT 加载。这样推理速度可以做到实时,而且比规则分类更鲁棒。不要在 Jetson Nano 本地训练大模型,它的 CPU 和内存不适合,训练放在 PC 上更实际。

如果你不想自己搭训练流程,也可以考虑 Edge Impulse 这类边缘 AI 平台,采集数据、训练、导出 TensorRT 或 TFLite 模型,流程比较完整。不过要注意模型输入输出和 jetson-inference 的封装不同,可能需要自己写后处理。我的建议是先用规则版跑通交互,再根据实际需求决定是否训练。很多场景下,五指伸展规则加手势轨迹判断已经够用。训练分类器的价值在于处理复杂手势和不同用户的手型差异,但工作量也更大。

7. 常见问题与排查速查表

Jetson Nano 的坑大多集中在几个地方:供电、SD 卡、摄像头、编译内存、TensorRT 模型。下面是我整理的问题速查表,按现象、可能原因、解决方法组织。你可以先查表,再针对性看日志。排查时尽量一次只改一个变量,否则很难定位。比如摄像头不工作,先换官方 CSI 摄像头测试,再换 USB 摄像头,再检查 GStreamer 管道,不要同时改分辨率、摄像头类型和电源模式。

7.1 启动与供电类问题

现象可能原因解决方法
插电后绿灯亮但无显示HDMI 线或显示器不兼容、SD 卡未插好换 HDMI 线、换显示器、重新插卡
开机反复重启电源电流不足、J48 未短接换 5V 4A DC 电源,短接 J48
系统卡在启动 LogoSD 卡速度慢或镜像写坏换 U3 卡,重新烧录并校验
跑 Demo 几分钟后重启GPU 满载导致欠压检查电源、散热、Swap,降低分辨率
SSH 突然断开网络不稳或供电不足插网线,检查电源,查看温度

供电问题我遇到最多。尤其是用 USB 口供电时,目标检测一跑起来,电流瞬间拉高,板子直接重启。不要用手机充电器凑合,最好用官方推荐的 DC 5V 4A 电源。J48 跳线也要确认短接。如果你不知道跳线帽怎么插,可以看板子 DC 口旁边的丝印,通常标着 J48,短接两个针脚即可。

7.2 摄像头与显示类问题

现象可能原因解决方法
找不到 /dev/video0CSI 排线接反或未插紧关机重插排线,金属触点朝向散热片
CSI 摄像头画面全黑分辨率或帧率不支持用 nvgstcapture 测试,改 1280x720
USB 摄像头卡顿USB 带宽不足或 CPU 占用高换 USB 3.0 口,降低分辨率
GStreamer 报错管道参数错误或摄像头被占用关闭其他摄像头进程,检查管道
VNC 下无法显示 AI 窗口OpenGL 远程渲染受限接 HDMI 本地显示,SSH 看日志

显示方面,jetson-inference 的窗口使用 OpenGL。VNC 虽然能看到桌面,但跑实时视频窗口体验很差。我的建议是:配置阶段用 SSH,跑 Demo 时接 HDMI 显示器。如果必须无头运行,可以用--headless参数,把结果保存成视频文件,再传到电脑看。CSI 摄像头的排线很脆弱,插拔时先关机,不要带电操作。

7.3 编译与模型类问题

现象可能原因解决方法
make 报内存不足4GB 内存不够加 4GB Swap,用 make -j1
CMake 找不到 Python缺少 libpython3-dev安装依赖,重新 cmake
模型下载中断网络不稳或磁盘满重新运行下载脚本,清理空间
TensorRT engine 生成失败模型文件损坏或版本不匹配删除 engine 重新生成,检查 JetPack 版本
Python 导入 jetson.inference 失败未 make install 或 ldconfig执行 sudo make install 和 sudo ldconfig

编译类问题里,内存不足最常见。症状是终端突然显示Killed,或者编译进程消失。加 Swap 并降低并行数基本能解决。模型下载和 TensorRT 引擎生成需要耐心,第一次可能比较慢。如果 engine 生成失败,先看终端输出的错误,常见是模型文件不完整。删除data/networks下对应的 engine 文件,重新运行 Demo 让它再生成一次。

7.4 性能与稳定性类问题

现象可能原因解决方法
FPS 很低5W 模式、未锁频、分辨率高nvpmodel -m 0,jetson_clocks,降到 640x480
温度过高降频散热不足加散热片和风扇,风扇 PWM 拉满
画面延迟大摄像头管道缓冲多降低分辨率,减少缓冲,用 CSI 摄像头
手势识别抖动关键点不稳定滑动平均滤波,连续多帧确认
检测框闪烁阈值太低或模型误检提高阈值,使用 filter 过滤类别

性能优化没有银弹,就是分辨率、模型、电源模式、散热四个变量一起调。我的经验是:640x480 是 Jetson Nano 的甜点分辨率,再高 FPS 掉得厉害。SSD-MobileNet-v2 和 resnet18-hand 都是轻量模型,适合 Nano。散热一定要做好,温度一高,什么优化都白搭。如果你发现 FPS 突然从 20 掉到 5,先看温度,再看电源模式,最后看是否有其他进程占用 CPU。

8. 最后聊几句实际体会

我在 Jetson Nano 4GB B01 上反复装过几次系统,最大的体会是:这块板子的性能瓶颈往往不在 GPU,而在供电、散热和存储。同样的 detectnet 代码,用 5V 2A 电源跑几分钟就重启,换 5V 4A DC 电源加风扇后稳定运行;同样的 SD 卡,U1 卡编译时卡到怀疑人生,U3 卡顺畅很多。所以如果你刚开始玩,不要急着换模型、改代码,先把硬件基础打好。系统安装、Swap、风扇、电源模式这几步做扎实,后面的目标检测和手势识别会顺很多。

手势识别部分,PoseNet 手部模型给了我很大惊喜,21 个关键点足够做很多交互。虽然它有抖动和遮挡问题,但加一个滑动平均和连续帧确认,体验就能接受。如果你的项目需要更稳定的手势分类,再考虑采集数据训练轻量分类器。目标检测部分,SSD-MobileNet-v2 在 Nano 上性价比很高,20 FPS 左右足够做智能监控、物体计数、简单机器人视觉。后续你还可以把检测结果通过串口或 GPIO 发给单片机,做联动控制。这个扩展方向比单纯在屏幕上画框更有意思,也更能体现边缘计算的价值。

返回列表