2026/8/29 23:08:54

树莓派接入Qwen:打造能看能听能说的车载AI

树莓派接入Qwen:打造能看能听能说的车载AI 把 Qwen 接入树莓派做成一台能看、能听、能开口的车载 AI是不少树莓派玩家想尝试的选题。它既不是普通智能音箱那样只做语音问答也不只是一个摄像头监控而是把相机、语音、模型推理和 GPIO 控制组合在一个能随车携带的小盒子里。这篇文章会以树莓派 4B/5、OV5647 摄像头、USB 麦克风和音箱为硬件基础分两条主线实现一条走 DashScope 兼容接口调用 Qwen 云端能力另一条在本机用 GGUF 量化模型跑通推理。最后会得到一个可交互的car_ai.py程序支持拍一张照片交给 Qwen-VL 描述也支持文本问答并把结果输出到终端或语音播报。做一个这样的车载 AI与桌面实验有一个明显区别所有模块都必须能在有限供电、有限内存和可能的弱网环境下协作。摄像头、麦克风、模型接口、语音合成任何一环不稳定整个程序就不可用。所以我建议先理清链路再逐层准备环境最后再写主程序。1. 先理清车载 AI 的核心链路看、听、想、说1.1 一个最小的“看-想-说”闭环车载 AI 的最小功能闭环可以拆成四个环节。输入侧是摄像头画面、用户文本或语音指令。树莓派上的 OV5647 摄像头负责采集画面USB 麦克风负责采集声音。处理侧是 Qwen 模型它接收一段文本或者“文本 图片”返回一段自然语言回答。输出侧是屏幕、终端和扬声器把答案展示出来或者用语音播报。如果还接了舵机、风扇、LED模型输出的控制指令还可以落到 GPIO 上。一个典型的最小闭环是终端输入photo 描述一下前方画面。主程序调用摄像头拍照得到frame.jpg。主程序把“描述一下前方画面”和图片一起发给 Qwen-VL。Qwen 返回“前方是一条马路路中间有白色车道线远处有一辆银色轿车”。程序把这句话打印到终端并用扬声器语音播报。这个闭环不需要做复杂的语音唤醒、不需要训练模型、不需要高配显卡所有模块都是成熟工具重点在集成。1.2 为什么车载场景比桌面实验更挑条件同样一份代码在桌面 Linux 上可能运行得很顺畅但放到车里就容易出问题。原因集中在三处。第一是供电。树莓派官方建议 5V/3A 供电但在车辆启动瞬间点烟器或 USB 车充的输出电压可能抖动。如果供电不足树莓派会频繁提示低电压出现黄色闪电图标严重的会直接重启。所以车载项目不能随便用一个手机充电头至少要用稳定的车充并确认输出电流是否满足树莓派、摄像头、风扇、USB 麦克风和音箱的总功耗。第二是网络。如果走云端 Qwen API车辆经过地下车库、隧道或偏远路段时网络会断。程序必须做好超时处理和重试逻辑至少不能让断网导致进程崩溃。如果走本地量化模型网络压力小但模型效果会受量化等级和模型参数规模限制。第三是算力和内存。树莓派内存有限不适合直接运行几十上百亿参数的模型。云端 API 模式几乎不占用本地算力但本地模型模式必须认真选型号。1.5B 参数量、4bit 量化的模型在树莓派上能跑出可用的速度更大参数量的模型通常只适合在 8GB 内存的树莓派 5 上实验并且要做好推理很慢的心理准备。1.3 两条模型接入路线云端 API 与本地量化模型第一条路线是云端 API。Qwen 在阿里云百炼 DashScope 上以 OpenAI 兼容模式开放接口可以用openaiPython SDK 调用。好处是模型质量高支持视觉理解代码量少。缺点是必须在线而且需要到控制台申请 API Key。第二条路线是本地量化模型。用 llama.cpp 加载 GGUF 格式的量化权重例如 Qwen2.5-1.5B-Instruct 的 Q4_K_M 版本在树莓派本地推理。好处是离线可用、隐私更好缺点是图片理解能力通常不如云端视觉模型内存和 CPU 占用也明显更高。对比项DashScope API本地 GGUF 量化网络依赖需要不需要文本回复效果更好受模型大小和量化影响图片理解可使用 Qwen-VL 模型一般需要单独处理图片本地内存占用低较高起步成本申请 API Key下载模型文件适合场景视觉问答、能联网的演示离线文本问答、模型学习后续章节会先把环境准备好然后分别给出这两种模式的接入代码。2. 树莓派环境准备系统、远程连接与国内镜像源2.1 硬件选型先从内存和供电开始我建议先确认树莓派型号和内存再决定走哪条模型路线。如果你的目的是把整套链路跑通树莓派 4B 4GB 已经够用如果要本地跑 1.5B 量化模型至少选 4GB最好选 8GB如果只打算用云端 API树莓派 3B 也能完成基础实验但拍照和语音合成的体验会差一些。器材建议型号说明主控板树莓派 4B 或树莓派 58GB 版本更适合本地模型摄像头OV5647 摄像头模块树莓派 CSI 接口500 万像素麦克风USB 麦克风或免驱麦克风阵列避免使用树莓派板载音频口采集音箱3.5mm 音箱或 USB 音箱用于语音播报电源5V/3A 车充如果带风扇和摄像头建议更大余量散热散热片加 PWM 风扇树莓派 4B/5 高负载时温度会明显升高树莓派 5 与 4B 的差异主要体现在 CPU 性能和 PCIe 接口上但本文的 Python 代码在两者上都能运行。需要注意树莓派 5 使用新的电源管理方式对个别旧 GPIO 库兼容性不同如果遇到 GPIO 控制失败优先升级系统并改用gpiod或lgpio。2.2 系统烧录与 SSH 连接推荐使用 Raspberry Pi Imager 烧录系统。写系统时可以选择 Raspberry Pi OS Desktop 或 Lite。如果只做命令行版车载 AI用 Lite 更省内存如果还想要桌面和 VNC 调试用 Desktop 会更方便。烧录完成后在 Imager 的“高级选项”里可以提前启用 SSH、设置用户名和密码。这样第一次启动后不需要接显示器直接用网线或 Wi-Fi 连到同一个局域网通过 SSH 登录ssh pi192.168.1.100如果不知道树莓派 IP可以在路由器后台查看或者执行arp -a搜索局域网设备。登录后可以用hostname -I查看当前 IP。为了方便后续安装依赖建议先更新系统sudo apt update sudo apt full-upgrade -y2.3 VNC 连不上时的排查顺序在树莓派上启用 VNC 之后很多新手会在 VNC Viewer 里遇到连接超时或黑屏。排查时要按下面这个顺序来。先检查 VNC 服务是否启用sudo raspi-config在Interface Options - VNC中启用。启用后查看服务状态sudo systemctl status vncserver-x11-serviced如果服务没有运行可以手动启动sudo systemctl enable vncserver-x11-serviced sudo systemctl start vncserver-x11-serviced第二种典型原因是系统装的是 Lite 版本没有桌面环境。VNC 本质上是在远程显示桌面如果系统没有桌面会话VNC 自然连不上。这种情况可以直接用 SSH 操作不需要执意打开 VNC。第三种原因是防火墙或隐藏 IP。树莓派默认通常不启动防火墙但如果你自己安装了ufw要放行 5900 端口sudo ufw allow 5900/tcp另外VNC 打不开时先确认同一网络下其他主机能否ping通树莓派。网络不通时VNC、SSH 和 API 请求都会同时失败。2.4 换源与 VSCode 远程开发国内网络环境下树莓派默认的 apt 源速度可能很慢。修改源时先看系统类型因为新版 Raspberry Pi OS 的源目录可能拆成了多个文件ls /etc/apt/sources.list /etc/apt/sources.list.d/找到对应的.list文件后把deb.debian.org和archive.raspberrypi.org替换成可用的国内镜像域名。修改后执行sudo apt update换源不要太着急。先确认系统版本再根据镜像站说明修改避免把源改成不兼容的发行版。开发阶段推荐用 VSCode 远程开发。在 VSCode 中安装 Remote-SSH 扩展连接到树莓派后就可以像编辑本地代码一样修改car_ai.py并且能直接在树莓派终端里执行命令。# 在树莓派上确保 SSH 服务已开启 sudo systemctl enable ssh --now连接成功后再创建一个 Python 虚拟环境。这里有一个关键点picamera2是系统 Python 包直接创建的普通虚拟环境可能访问不到它所以要用--system-site-packages让虚拟环境继承系统包。python3 -m venv --system-site-packages ~/.venvs/car_ai source ~/.venvs/car_ai/bin/activate python -m pip install --upgrade pip后续所有依赖都安装到这个虚拟环境里。这样既不会污染系统 Python又能复用系统自带的摄像头库。3. 验证摄像头、麦克风、音箱和 PWM 风扇3.1 启用 OV5647 摄像头并完成第一次拍照OV5647 是树莓派常见的 CSI 摄像头模块。先通过raspi-config开启摄像头接口sudo raspi-config在Interface Options - Camera中启用然后重启。如果是新系统摄像头可能默认自动检测但手动检查一遍更稳妥。用下面的命令确认摄像头是否被识别libcamera-hello --list-cameras如果能看到类似Camera id的信息说明摄像头已经工作。接着拍一张测试照片libcamera-still -o test.jpg --width 1024 --height 768 --quality 85拍完用图片查看工具打开test.jpg确认画面不是黑的也没有花屏。Python 端可以用picamera2拍照。把拍照功能封装成一个函数后面主程序直接调用from picamera2 import Picamera2 import time def take_photo(pathframe.jpg, width1024, height768): picam2 Picamera2() config picam2.still_configuration(main{size: (width, height)}) picam2.configure(config) picam2.start() time.sleep(1.5) picam2.capture_file(path) picam2.stop() return path这里延迟 1.5 秒是为了等摄像头完成自动曝光。如果拍照速度要求高可以缩短到 1 秒但画面亮度稳定性会变差。3.2 用 arecord 和 aplay 验证 USB 麦克风与音箱语音输入和输出不是必须的但加上语音播报后车载 AI 的体验会更完整。先插上 USB 麦克风列出所有录音设备arecord -l输出中会看到card 1: Microphone [USB Microphone], device 0之类的编号。如果只有一个 USB 麦克风通常会出现在card 1。可以用下面的命令录音 5 秒arecord -D plughw:1,0 -d 5 -f cd test.wav播放刚录的音频aplay test.wav如果录音设备默认不是 USB 麦克风可以写一个~/.asoundrc把默认设备固定下来。不过设备号会随 USB 接口顺序变化更好的做法是在程序里通过subprocess动态查询设备列表而不是写死1,0。扬声器测试类似先列出播放设备aplay -l然后用aplay播放刚才的测试文件。如果能听到声音说明音频输出链路正常。3.3 通过 GPIO PWM 控制散热风扇或舵机树莓派在高负载跑模型时发热明显使用 PWM 风扇比直接接常转风扇更合理。PWM 可以通过控制占空比来调节风扇转速。先安装或确认 GPIO 库可用。在较老的树莓派上可以这样测试import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BCM) GPIO.setup(18, GPIO.OUT) pwm GPIO.PWM(18, 25000) # 25kHz减少风扇电机啸叫 pwm.start(50) # 初始占空比 50% time.sleep(3) pwm.stop() GPIO.cleanup()这里把频率设置在 25kHz主要是为了让风扇电机运行更安静。如果控制的是舵机需要把频率改成 50Hz并通过改变占空比控制角度。舵机接线时要注意信号线、电源线和地线不要接错而且要共地否则信号不稳定。对于树莓派 5 或新内核RPi.GPIO可能会出现兼容性问题。如果上面代码报错可以考虑使用gpiod通过 GPIO chip 和 line 来控制用法会比RPi.GPIO更接近内核接口。4. 接入 Qwen兼容 API 与本地 GGUF 模型4.1 使用 DashScope 兼容接口处理文本和图片Qwen 在 DashScope 上提供 OpenAI 兼容模式所以不需要额外写复杂的签名逻辑直接安装openaiSDK 就能调用。安装依赖python -m pip install openai把 API Key 放到环境变量里避免写死在代码中export DASHSCOPE_API_KEYsk-your-key创建一个qwen_engine.py封装文本和图片问答import base64 import os from openai import OpenAI client OpenAI( api_keyos.environ.get(DASHSCOPE_API_KEY), base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1, ) def ask_text(text, modelqwen-plus): resp client.chat.completions.create( modelmodel, messages[{role: user, content: text}], temperature0.7, ) return resp.choices[0].message.content def encode_image(image_path): with open(image_path, rb) as f: return base64.b64encode(f.read()).decode(utf-8) def ask_image(question, image_path, modelqwen-vl-plus): content [ {type: text, text: question}, { type: image_url, image_url: { url: data:image/jpeg;base64, encode_image(image_path) } }, ] resp client.chat.completions.create( modelmodel, messages[{role: user, content: content}], temperature0.3, ) return resp.choices[0].message.content这里把图片转成 base64 data URL是为了让图片不需要部署到公网就能直接传给 API。本地图片转成 data URL 后接口端可以直接读取。需要注意几个会直接影响成功率的地方。图片文件不能太大建议拍照时把宽度控制在 1024 像素以内否则请求体过大可能出现超时或接口报错。模型名称也要以你账号下实际可见的模型为准因为模型列表会随着平台调整而变化。API Key 没设置时代码会自动读取None请求时会报鉴权错误所以要先在终端执行echo $DASHSCOPE_API_KEY确认环境变量已经生效。4.2 在本地用 llama.cpp 加载量化 Qwen如果车在行驶中经常进入地下车库或隧道云端 API 会中断。这时可以准备一个本地离线方案。本地跑大模型通常用 GGUF 量化格式。GGUF 是 llama.cpp 社区广泛使用的模型格式量化后的模型文件体积比完整权重小很多。以常见的 1.5B 参数模型为例Q4_K_M 量化后的文件大小大约在 1GB 上下树莓派 4B 4GB 有机会跑起来但实际速度取决于上下文长度、线程数和散热条件。先编译 llama.cppgit clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build -DCMAKE_BUILD_TYPERelease cmake --build build -j4然后把下载好的 GGUF 模型放到指定目录。下载时需要关注模型许可证和版本信息不要只凭文件名判断模型能力。用