ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

零基础玩转PYNQ-Z2:Python操控硬件入门指南

零基础玩转PYNQ-Z2:Python操控硬件入门指南

简介:《PYNQ-Z2入门指导手册_v2.01》面向希望借助Python快速上手Xilinx Zynq APSoC开发板的嵌入式初学者与教学人员,重点解决不熟悉可编程逻辑设计却想调用FPGA硬件加速能力的问题。手册从PYNQ开源框架与Jupyter Notebook交互环境讲起,依次覆盖软硬件准备、板卡接口与固件配置、浏览器在线编程连接,并给出按键控制LED、录音及音频处理、动态实时面部识别三个由浅入深的实践例程,帮助读者建立从环境搭建到硬件I/O、音视频处理的完整认知。资源包共1个PDF文件,约1.68MB,篇幅紧凑、目录清晰,便于按章节检索与对照实操。目前已有2698人学习,适合作为课程配套或自学入门的起点,也可为后续Overlay与硬件库调用打下基础。

1. 第一次拿到开发板,别急着写代码:PYNQ-Z2 到底是什么

很多人第一次听说 PYNQ-Z2,脑子里冒出的画面是:一块板子、一堆跳线、满屏英文文档,然后本能地想“这玩意儿我肯定搞不定”。我特别理解这种感觉,因为 FPGA 这三个字母本身就自带劝退气质。但 PYNQ-Z2 入门这件事,恰恰是被人为复杂化了。你可以把它想成一台“能动手改造的迷你电脑”:它上面跑着 Linux,有网口、有 USB、有 HDMI,你打开浏览器就能写 Python,写完点一下运行,板子上的灯就亮了、喇叭就响了、摄像头画面就出来了。它和普通电脑最大的区别,是板子上多了一块可编程逻辑芯片,你可以用 Python 调用它来加速计算,而不用去画电路图。这份《PYNQ-Z2 入门指导手册_v2.01》要带你走的,就是“软硬件准备 → 板卡设置 → 连上 Jupyter → 跑通三个例程”这条最短路径。适合谁?适合完全没碰过 FPGA、但会一点点 Python、想看看硬件编程到底长什么样的零基础新手。

2. 为什么值得学:Python 直接操控硬件的门槛有多低

2.1 传统 FPGA 开发和 PYNQ 的差别在哪

传统 FPGA 开发的流程,对新手来说确实不太友好。你得先写硬件描述语言,做综合、布局布线,生成比特流,再烧进板子,中间任何一个环节报错,你面对的往往是一屏看不懂的日志。这套流程不是不好,而是学习曲线太陡,很多人卡在“灯还没亮”的阶段就放弃了。

PYNQ 框架换了个思路。它把可编程逻辑部分提前封装成“硬件库”,也就是手册里反复提到的 overlay。你不需要自己设计电路,只需要在 Python 里加载一个.bit文件,然后像调用普通软件库一样去操作板子上的 LED、按键、音频、视频接口。手册里那句话说得挺直白:可编程逻辑电路以硬件库的形式导入,通过 API 编程,方式和软件库的导入几乎一样。

这意味着什么?意味着你第一天上手,写的代码可能就长这样:

# 加载基础硬件库,相当于告诉板子“我要用哪些现成硬件功能” from pynq.overlays.base import BaseOverlay base = BaseOverlay("base.bit") # 点亮板子上的 LED for led in base.leds: led.on()

没有综合,没有布线,没有比特流生成。你写的是 Python,跑的是硬件。对零基础的人来说,这种“立刻看到反馈”的体验特别重要,因为它能让你在还没被原理劝退之前,先建立起“我能控制它”的信心。

2.2 三个例程分别能让你摸到什么

手册安排了三个入门例程,难度是递进的,这个顺序对新手很友好。

第一个是按键控制 LED。听起来简单,但它覆盖了嵌入式开发最核心的动作:读输入、写输出。你按下按键 0,彩色 LED 换颜色;按下按键 1 或 2,流水灯往不同方向跑;按下按键 3,程序结束。代码里用base.buttons[0].read()读按键状态,用base.rgbleds[led].write(color)写 LED 颜色。这一读一写,就是硬件编程的基本功。

第二个是录音及音频处理。这个例程让你接触模拟信号的世界:选择 Line_in 输入、录五秒音频、保存成 wav、再播放出来,最后用 matplotlib 把波形和频谱画出来。你会第一次直观地看到“声音”在代码里是一串数字,而且能画成图。这一步对建立“数据感”很有帮助。

第三个是动态实时面部识别。把 USB 摄像头插到板子的 USB HOST 口,HDMI OUT 接显示器,跑 OpenCV 的人脸检测。代码里用cv2.CascadeClassifier加载分类器,检测到人脸就画蓝框,检测到眼睛就画绿框。这个例程的代码量比前两个大,但逻辑并不复杂:读一帧、转灰度、检测、画框、输出。它让你看到 PYNQ-Z2 在图像处理上的实际能力,也让你对“实时”两个字有体感。

三个例程走完,你对板子的输入输出、音频、视频就有了基本手感。这时候再回头去看那些原理文档,就不会觉得是在读天书了。

2.3 学它对你后面有什么用

往近了说,PYNQ-Z2 是一个很好的嵌入式 Linux 和 Python 硬件编程的练习平台。你会熟悉 Jupyter Notebook 这种交互式开发方式,会知道怎么通过浏览器连到一台远程设备上写代码,会理解“硬件库”和“软件库”在调用方式上的相似性。这些经验换个开发板、换个项目照样能用。

往远了说,它帮你建立一种分层思维:底层是可编程逻辑,中间是 overlay 和驱动,上层是 Python API。你不需要一上来就扎进最底层,但你知道每一层大概负责什么。以后遇到更复杂的项目,你会知道该在哪一层动手,而不是所有问题都从画电路图开始想。这种“知道边界在哪”的判断力,比记住几个 API 名字值钱得多。

3. 动手前的准备:软件、硬件和那张 SD 卡

3.1 硬件清单:别少买一根线

手册列得很清楚,我按新手容易漏掉的顺序重新说一遍。

物品说明新手容易忽略的点
PYNQ-Z2 开发板核心板卡注意别和同系列其他型号搞混
以太网线连接板子和路由器/电脑建议用质量好一点的,接触不良很折腾
Micro USB 数据线供电 + 串口通信必须是数据线,纯充电线不行
空白 Micro SD 卡至少 8GB建议 16GB 以上,烧镜像更从容
USB 摄像头第三个例程要用普通免驱摄像头即可
HDMI 显示器第三个例程输出画面板子 HDMI OUT 接显示器

这里有个血泪经验:Micro USB 线一定要确认能传数据。我见过有人拿了一根只能充电的线,板子通电了但串口死活连不上,排查半天以为是驱动问题,最后换根线就好了。这种坑不复杂,但很耗时间。

3.2 软件准备:浏览器和烧录工具

电脑这边不需要装庞大的开发环境,手册的要求很克制:一个支持 Jupyter 的浏览器就行。Chrome、Firefox、Safari 的较新稳定版本都可以。注意手册里明确提了,老版本浏览器和部分基于旧内核的浏览器可能跑不起来,因为 Jupyter 依赖 WebSockets。入门阶段别在这上面较劲,直接用主流浏览器的当前版本。

烧录镜像需要工具。Windows 下用 win32DiskImager,选择下载好的镜像文件,设备选 SD 卡对应的盘符,点写入。Linux 或 Mac 下用系统自带的dd命令。烧录过程会把 SD 卡整个覆盖,所以卡里别放重要东西。

# Linux/Mac 下用 dd 烧录的典型写法,of= 后面换成你实际的 SD 卡设备 # 注意:设备名写错会覆盖你电脑的硬盘,执行前务必用 lsblk 或 diskutil list 确认 sudo dd if=pynq_z2_image.img of=/dev/sdX bs=4M status=progress

这段命令里,if=是输入文件,也就是你解压出来的镜像;of=是输出设备,必须确认是 SD 卡而不是你的系统盘;bs=4M是块大小,影响写入速度;status=progress让你能看到进度。Windows 用户不用记这个,图形界面点选就行。

3.3 烧好镜像之后先别急着上电

镜像烧完,把 SD 卡插回板子之前,先做两件事。第一,确认卡插到位,PYNQ-Z2 的卡槽在板子下方,插的时候轻一点,别用蛮力。第二,把 Boot 跳线拨到 SD 位置,这一步是告诉板子“从 SD 卡启动”。手册里专门强调了这一点,跳线不对,板子起来就是空的。

电源跳线也要看一眼。用 Micro USB 供电就把跳线设到 USB 位置;如果要用外部 12V 电源,就设到 REG。新手建议先用 USB 供电,简单,一根线解决供电和串口两件事。

4. 板卡设置和连网:让板子“活”过来

4.1 上电顺序和启动判断

硬件连接按这个顺序来:插好 SD 卡、接好网线、用 Micro USB 线把 PROG UART 接口连到电脑、最后把开关拨到 ON。手册说大约一分钟后,两个蓝色 LED 和四个红色 LED 会同时闪动,随后蓝色 LED 关闭、四个红色 LED 常亮,这时候系统启动完毕。

这个灯语要记住。很多新手第一次上电,看到灯闪就以为出问题了,其实那正是启动过程。如果等了很久灯的状态不对,先检查 SD 卡有没有插好、镜像有没有烧成功、Boot 跳线对不对。别一上来就怀疑板子坏了,入门阶段绝大多数问题都出在这三样上。

4.2 两种连网方式,选适合你的那种

手册给了两条路,我建议新手优先走第一条。

第一条是板子通过网线连到路由器或交换机,和你的电脑在同一个网络下。这种方式下,板子会自动从 DHCP 拿到 IP,你在浏览器里访问http://pynq:9090就行。用户名和密码都是xilinx。这条路的好处是板子能上网,后面更新软件、装包都方便。

第二条是板子直接用网线连电脑。这时候需要给电脑配一个静态 IP,然后访问http://192.168.2.99:9090。手册提醒得很清楚:这种直连方式下,除非你把电脑的网络共享给板子,否则板子上不了外网,也就没法更新软件包。入门跑例程够用,但如果你后面想装东西,还是建议走路由器。

提示:如果你所在网络里可能有多块同型号板子,建议连上后第一时间改主机名,避免地址冲突。手册给了命令:sudo /home/xilinx/scripts/hostname.sh 新主机名,改完用sudo shutdown -r now重启生效。

4.3 进不去 Jupyter 时先查什么

连不上是新手最常见的翻车点,按这个顺序排查,能解决大部分情况。

先看网线两端的灯亮不亮,不亮就是物理连接问题。再看你访问的地址对不对:走路由器是pynq:9090,直连是192.168.2.99:9090,别混着用。然后确认电脑和板子是不是在同一网段,直连模式下电脑静态 IP 要配成192.168.2.x这一段。如果这些都对还是打不开,用 Micro USB 接串口终端看看板子到底起没起来。手册给了串口参数:波特率 115200、8 数据位、1 停止位、无校验、无流控。用 PuTTY 或 Tera Term 连上对应 COM 口,按回车看到xilinx@pynq:~$就说明系统是活的,问题出在网络层。

串口终端里可以敲ifconfig看板子拿到的 IP,敲hostname看主机名。这两个命令在排查时很管用,建议先记住。

5. 跑通第一个例程:按键控制 LED 的每一步

5.1 找到 notebook 并理解它的结构

连上 Jupyter 之后,主页上能看到Getting_Started文件夹,手册还提到示例按common、base、logictools分类。第一个例程在base > board文件夹里的board_btn_leds.ipynb。

打开之后你会看到一个个“单元格”,有的写说明文字,有的放代码。Jupyter 的逻辑是:选中单元格,点工具栏的运行按钮,或者按 Shift+Enter,代码就在板子上执行。手册特别提醒,运行中的单元格会显示[*],这时候要等它跑完变成数字,再进行下一步。这个细节新手容易忽略,连着点运行导致状态乱掉,然后以为代码有问题。

5.2 逐段看代码:每一行在干什么

第一个例程的代码不长,但信息量够。我按功能拆开说。

# 导入时间模块和 PYNQ 的基础硬件库 from time import sleep from pynq.overlays.base import BaseOverlay # 加载 base.bit,这一步把板子上的 LED、按键、音频等基础外设准备好 base = BaseOverlay("base.bit") # 两个延时参数,控制流水灯快慢 Delay1 = 0.3 Delay2 = 0.1 color = 0 # 指定用哪两个 RGB LED 来显示颜色 rgbled_position = [4, 5] # 先把所有普通 LED 点亮,作为初始状态 for led in base.leds: led.on()

BaseOverlay("base.bit")这行是入口,它加载的是现成的硬件库文件,你不需要自己生成。base.leds是一个 LED 对象集合,可以遍历。base.buttons同理,后面用下标访问具体按键。base.rgbleds是彩色 LED,write(color)里的 color 是一个 0 到 7 的整数,对应不同颜色组合。

主循环的逻辑是轮询四个按键:

# 只要按键 3 没被按下,就一直循环 while (base.buttons[3].read() == 0): # 按键 0:切换 RGB LED 颜色 if (base.buttons[0].read() == 1): color = (color + 1) % 8 for led in rgbled_position: base.rgbleds[led].write(color) sleep(Delay1) # 按键 1:从左到右流水灯 elif (base.buttons[1].read() == 1): for led in base.leds: led.off() sleep(Delay2) for led in base.leds: led.toggle() sleep(Delay2) # 按键 2:从右到左流水灯 elif (base.buttons[2].read() == 1): for led in reversed(base.leds): led.off() sleep(Delay2) for led in reversed(base.leds): led.toggle() sleep(Delay2)

read()返回 1 表示按下,返回 0 表示松开。toggle()是翻转状态,亮变灭、灭变亮。reversed()把 LED 顺序倒过来,所以流水灯方向相反。sleep()控制节奏,数值越小跑得越快。你可以试着把Delay2改成 0.05,流水灯会明显加快,这种小改动是建立手感的好办法。

按键 3 按下后跳出循环,代码做收尾:

print('End of this demo ...') for led in base.leds: led.off() for led in rgbled_position: base.rgbleds[led].off()

把所有 LED 关掉,打印结束信息。整个例程没有复杂算法,但它把“读输入、做判断、写输出、控节奏”这条链路完整走了一遍。你跑通它,就等于拿到了后面两个例程的钥匙。

5.3 改一改参数,看看会发生什么

跑通原版之后,别急着往下翻。做两个小实验:把Delay1改成 0.1,看颜色切换是不是更跟手;把rgbled_position改成[0, 1],看是不是换了一组灯在变色。改完记得重新运行对应单元格。

这种“改一个参数、看一个变化”的循环,是入门阶段最有效的学习方式。它让你从“照着跑”过渡到“我知道改哪里会发生什么”。后面音频例程里的录音时长、视频例程里的检测参数,都可以用同样的方式去试。

6. 后两个例程怎么跟:音频和摄像头别慌

6.1 音频例程:先跑通播放,再碰绘图

音频例程在base > audio下的audio_playback.ipynb。手册说代码被分成一个个代码块,每块前面有说明,依次运行就行。我的建议是分两段看。

第一段是音频对象的基本操作:

# 加载基础硬件库,拿到音频对象 from pynq.overlays.base import BaseOverlay base = BaseOverlay("base.bit") pAudio = base.audio # 选择 Line_in 作为输入,直通 5 秒,方便你确认输入通路是通的 pAudio.select_line_in() pAudio.bypass(seconds=5) # 录 5 秒音频 pAudio.record(5) # 播放刚录的内容(注意文件路径要和实际保存的一致) pAudio.load("/home/xilinx/jupyter_notebooks/base/audio/recording_0.wav") pAudio.play()

select_line_in()选输入源,bypass(seconds=5)是把输入直接送到输出五秒,用来验证线路。record(5)录五秒,load()加载 wav 文件,play()播放。这里有个容易翻车的点:手册示例里保存那行是注释掉的,如果你没保存就直接 load 一个不存在的文件,会报错。要么先取消保存那行的注释,要么用目录里现成的recording_0.wav。

第二段是用 matplotlib 画波形和频谱。这段代码长,但结构清晰:用wave模块读 wav 文件头,拿到采样率、声道数、采样宽度,把原始字节转成数组,然后用fft算频谱、用specgram画时频谱。新手不需要逐行吃透,先跑通、看到图,知道“声音在代码里是数组”就够了。后面想深究,再回头查numpy和scipy的用法。

6.2 摄像头例程:接线和路径是两个关键

第三个例程在base > video下的opencv_face_detect_webcam.ipynb。硬件上要做两件事:USB 摄像头插到板子的 USB HOST 口,HDMI OUT 接显示器。软件上,代码先初始化 HDMI 输出和摄像头:

from pynq.overlays.base import BaseOverlay from pynq.lib.video import * base = BaseOverlay("base.bit") # 配置 HDMI 输出为 640x480,像素格式 BGR Mode = VideoMode(640, 480, 24) hdmi_out = base.video.hdmi_out hdmi_out.configure(Mode, PIXEL_BGR) hdmi_out.start() # 用 OpenCV 打开摄像头,设置分辨率 import cv2 videoIn = cv2.VideoCapture(0) videoIn.set(cv2.CAP_PROP_FRAME_WIDTH, 640) videoIn.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) print("Capture device is open: " + str(videoIn.isOpened()))

VideoMode(640, 480, 24)里 24 是色深,PIXEL_BGR是像素排列顺序。cv2.VideoCapture(0)的 0 是摄像头编号,如果你插了多个摄像头可能要改。isOpened()打印 True 才说明摄像头被识别到了。

检测部分的核心是加载两个分类器文件:

# 分类器文件路径必须和板子上的实际路径一致 face_cascade = cv2.CascadeClassifier( '/home/xilinx/jupyter_notebooks/base/video/data/haarcascade_frontalface_default.xml') eye_cascade = cv2.CascadeClassifier( '/home/xilinx/jupyter_notebooks/base/video/data/haarcascade_eye.xml') gray = cv2.cvtColor(np_frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3, 5) for (x, y, w, h) in faces: cv2.rectangle(np_frame, (x, y), (x + w, y + h), (255, 0, 0), 2)

detectMultiScale的第二个参数 1.3 是缩放步长,第三个参数 5 是最小邻居数,调大这两个值检测会更严格但可能漏检,调小则更敏感但误检多。新手先按原值跑,看到框出来再试着微调。分类器路径是新手最容易踩的坑,路径不对会直接报错,复制的时候注意别多空格。

7. 新手避坑清单:这五个地方最容易卡住

7.1 板子通电但浏览器打不开 Jupyter

现象是板子灯正常,但访问pynq:9090一直转圈或报错。原因通常是网络模式选混了:走路由器却用了直连地址,或者直连却没配电脑静态 IP。解决办法是先确认网线接法,再对照手册用对应地址;直连模式下把电脑 IP 配到192.168.2.x网段;还不行就接串口终端敲ifconfig看板子实际拿到的地址。

7.2 代码运行一直显示 [*] 不结束

现象是单元格左边一直是星号,等很久也不变成数字。原因多半是代码里有死循环,比如按键例程里没按按键 3,while就不会退出。解决办法是点工具栏的中断按钮,或者重启内核,然后检查循环退出条件。跑按键例程时记住:按键 3 是结束键,不按它程序本来就不会停。

7.3 音频例程报文件找不到

现象是执行pAudio.load(...)时报错,提示文件不存在。原因是手册示例里保存那行是注释状态,你没生成文件就直接加载。解决办法是先把pAudio.save("recording_1.wav")的注释去掉、运行一次生成文件,或者直接加载目录里现成的recording_0.wav,并确认路径拼写和实际一致。

7.4 摄像头打开了但检测不到人脸

现象是isOpened()返回 True,但画面里没人脸框。原因可能是光线太暗、脸离镜头太远,或者detectMultiScale参数偏严格。解决办法是先保证光照充足、正脸对着镜头,再把 1.3 调到 1.1 左右试试;同时确认分类器文件路径没写错,路径错会直接抛异常而不是静默失败。

7.5 改了主机名之后连不上了

现象是执行改主机名命令并重启后,原来地址访问不了。原因是主机名变了,pynq这个地址不再指向你的板子。解决办法是用新主机名访问,或者直连模式下继续用静态 IP;如果完全找不到,接串口终端敲hostname确认当前名字,再决定访问地址。改主机名前最好记下原来的名字,给自己留个后悔药。

8. 下一步学什么:从跑通例程到能改能扩

跑完三个例程,你已经跨过了最难的那道门槛:知道板子怎么起、代码在哪写、硬件怎么调。接下来别急着去啃 FPGA 原理,按这个顺序往前走会更顺。

第一步,把例程当起点而不是终点。按键例程可以试着加一个“按键长按才触发”的逻辑,音频例程可以试着改录音时长、换不同的绘图方式,摄像头例程可以试着调检测参数、换分类器。每次只改一个地方,改完看结果,这种小步迭代比通读文档有效得多。

第二步,熟悉 Jupyter 里的文件操作和终端。手册提到板子上跑着 Samba 服务,Windows 下可以访问\\pynq\xilinx,Linux 下用smb://pynq/xilinx,用户名密码都是xilinx。学会在电脑和板子之间传文件,你就能把自己的脚本、图片、数据放到板子上跑,不再局限于自带示例。

第三步,理解 overlay 的概念。你现在用的base.bit是一个基础硬件库,PYNQ 生态里还有别的 overlay。入门阶段不需要自己生成,但要知道“换一个 bit 文件,板子的硬件功能就换一套”。等你对 Python API 熟了,再去看怎么用现成 overlay 做更专门的事情,比如逻辑分析、图像加速。

第四步,补一点 Linux 和 Python 的基础。串口终端里常用的ls、cd、ifconfig、shutdown,Python 里的列表、循环、函数、模块导入,这些不需要精通,但会了之后排查问题和改代码会顺手很多。手册里的示例代码本身就是很好的阅读材料,逐行看懂比泛读十篇教程强。

我自己的习惯是:每跑通一个例程,就在 notebook 里新建一个单元格,用自己的话写三行注释——这个例程输入是什么、输出是什么、我改了哪个参数。这个动作花不了一分钟,但过一周再回来看,能省掉大量“我当时怎么跑的”这种回忆成本。从那以后我每次碰新板子都强制走一遍这个流程,翻车次数明显少了。

希望这份路径能帮你把 PYNQ-Z2 从“看不懂的板子”变成“敢动手的平台”。手册就在那里,第一个例程的代码也不长,打开浏览器,连上板子,从点亮第一排 LED 开始就行。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进