教程:VENTUNO Q/MIPI-CSI 相机
概述
本指南介绍了如何从 Arduino® VENTUNO™ Q 上的 MIPI-CSI 摄像头模块 连接、检测和流式传输视频。该板具有由 Qualcomm® Dragonwing™ QCS8275 内置图像信号处理器 (ISP) 驱动的三个专用摄像头连接器,可直接在板上实现多摄像头边缘 AI 应用。
<img src="
" alt="VENTUNO Q MIPI/CSI 连接器" />
说明:
目前仅支持IMX577摄像头模组。
相机硬件由单个后台服务“cam-server”(QMMF、高通多媒体框架、相机守护进程)管理,本指南中的每个捕获管道都作为客户端进行通信。下面进一步提供了三个即用型 Python 脚本,涵盖了查看 feed 的最常见方式:
| 脚本 | 输出 | 查看与 | 质量/效率 |
|---|---|---|---|
camera_test.py
|
连接到 VENTUNO Q 的本地显示器 | 没有什么额外的,视频出现在板上的一个窗口中 | 硬件 H264 往返(编码 + 解码),最适合测量本地管道延迟 |
camera_rtsp_server.py
|
通过网络传输 RTSP 流 | VLC、“ffplay”或任何支持 RTSP 的播放器 | 最佳,低带宽下的硬件 H264 |
camera_mjpeg_server.py
|
网络上的 HTTP MJPEG 流 | 任何网络浏览器、纯 URL 或“<img>”标签 | 最简单的客户端,但带宽更高(每帧完整的 JPEG) |
说明:
一次只能运行这些脚本之一(或任何其他相机客户端),“cam-server”为硬件提供单个活动捕获会话。在开始另一项之前先停止一项。
目标
- 了解三个板载 MIPI CSI-2 相机连接器。
- 安装硬件加速相机捕获所需的 GStreamer 插件。
- 从板的外壳检测连接的摄像头模块。
- 将视频流录制到文件中。
- 将摄像机源本地流式传输到连接到 VENTUNO Q 的显示器。
- 通过网络将摄像机源流式传输到 VLC(或其他 RTSP 播放器)。
- 通过网络将摄像机源流传输到 Web 浏览器 (MJPEG)。
硬件与软件要求
硬件要求
- Arduino® VENTUNO™ Q (1x)
- Arduino® USB-C 电源 (65W) (1x)
- 基于 IMX577 传感器的 MIPI-CSI 相机模块,例如 Arducam IMX577 Mini (1x)
- HDMI 显示器 + 电缆(仅 本地显示流 部分需要)
- 与 VENTUNO Q 位于同一网络的第二台计算机或电话(仅 VLC Stream 和 Browser Stream 部分需要)
软件要求
- Arduino应用实验室
- VLC 媒体播放器(仅 VLC Stream 部分需要),或其他支持 RTSP 的播放器,例如
ffplay - Web 浏览器(仅 浏览器流 部分需要)
硬件概述
VENTUNO Q 具有三个专用 MIPI CSI-2 相机连接器(CAMERA0、CAMERA1、CAMERA2),每个连接器均由 Dragonwing™ QCS8275 内的 Qualcomm® Spectra™ 692 ISP 驱动。这允许同时连接最多三个独立摄像头,用于多摄像头边缘 AI 应用,例如立体视觉、360° 捕捉或多角度物体检测。
每个连接器都是一个 22 针 FPC 连接器(TF31-22S-0.5SH,0.5 mm 间距),带有完整的 4 通道 MIPI CSI-2 接口、一条 I²C 控制总线、一条 GPIO 控制线和一条 3.3 V 电源轨。所有高速数据通道 (RCLAMP0524TCT) 以及电源和 I²C 线路 (DF2B7ASL、L3F) 均提供 ESD 保护。
| 连接器 | 标签 | 界面 | 控制 | 力量 |
|---|---|---|---|---|
| J3_1 | 相机2 | MIPI CSI-2 4 通道 | I²C4 + 1× GPIO (3.3V) | 3.3V |
| J3_3 | 相机1 | MIPI CSI-2 4 通道 | I²C2 + 1× GPIO (3.3V) | 3.3V |
| J3_2 | 相机0 | MIPI CSI-2 4 通道 | I²C0 + 1× GPIO (3.3V) | 3.3V |
每个连接器上的 GPIO 线(引脚 17)通常用于相机重置和电源启用控制。 I²C 总线(SCL/SDA,3.3 V)用于配置相机传感器寄存器。
访问开发板 Shell
要按照本指南中的步骤操作,您需要访问 VENTUNO Q 的 shell。这可以使用 ssh、adb 或通过在单板计算机 (SBC) 模式 下直接在开发板上打开终端来完成。
要通过 adb 连接,用 USB-C® 线缆连接 VENTUNO Q 与电脑,然后运行:
adb shell
要通过 ssh 连接,请确保 VENTUNO Q 与电脑连接到同一网络,然后运行:
ssh arduino@<ip-address>
说明:
有关远程访问开发板的更多替代方法,请参阅VENTUNO Q 用户手册。
连接相机模块
<img src="
" alt="将相机连接到 相机0 CSI 连接器" />
警告:
将摄像头模块连接到 CSI 连接器之一时,请确保 VENTUNO Q 电源已关闭。
将基于 IMX577 的摄像头模块连接到三个 CAMERA 连接器(CAMERA0、CAMERA1 或 CAMERA2)中的任意一个,确保柔性电缆的触点朝向连接器闩锁所示的正确方向。连接后,给开发板通电。
安装 GStreamer
要使用通过 MIPI-CSI 连接的相机,我们需要安装特定版本的“gstreamer”,更具体地说是“gstreamer1.0-plugins-qcom”。
在板上打开一个 shell(如上文所述),然后安装软件包:
sudo apt update
sudo apt upgrade -y
sudo apt install gstreamer1.0-plugins-qcom -y
安装后重启板子:
sudo reboot
检测相机
板重新启动后,打开一个新 shell 并运行以下命令来检查启动过程中是否检测到摄像头传感器:
sudo dmesg | grep Probe
您应该看到类似于以下内容的内容:
[ 28.182686] CAM_INFO: CAM-SENSOR: cam_sensor_driver_cmd: 1250: Probe failed for cmk_imx577 slot:23, slave_addr:0x34, sensor_id:0x577
[ 28.213671] CAM_INFO: CAM-SENSOR: cam_sensor_driver_cmd: 1250: Probe failed for cmk_imx577 slot:24, slave_addr:0x34, sensor_id:0x577
[ 28.231128] CAM_INFO: CAM-SENSOR: cam_sensor_driver_cmd: 1250: Probe failed for cmk_imx577 slot:25, slave_addr:0x34, sensor_id:0x577
[ 28.268640] CAM_INFO: CAM-SENSOR: cam_sensor_driver_cmd: 1290: Probe success for cmk_imx577 slot:26,slave_addr:0x34,sensor_id:0x577
[ 28.688703] CAM_INFO: CAM-SENSOR: cam_sensor_driver_cmd: 1250: Probe failed for cmk_imx577 slot:27, slave_addr:0x34, sensor_id:0x577
查找“探测成功”行(在本例中为第四个条目)。这意味着相机已被识别并且正在工作。
注意:
预计会出现“探测失败”行。内核会扫描多个传感器驱动程序插槽,然后找到与您连接的相机相匹配的传感器驱动程序插槽,只有“探测成功”行才能确认工作连接。
捕捉视频记录
为了测试相机,我们可以录制视频流样本,并将其保存在本地。
运行以下命令,这将开始录制。使用“CTRL + C”结束录制。视频文件将位于运行命令的同一目录中(如果使用“location”标志指定,则位于不同的位置)。
gst-launch-1.0 -e qtiqmmfsrc camera=0 name=camsrc video_0::type=preview ! video/x-raw,format=NV12_Q08C,width=3840,height=2160,framerate=30/1,interlace-mode=progressive,colorimetry=bt601 ! queue ! v4l2h264enc capture-io-mode=4 output-io-mode=5 ! h264parse ! mp4mux ! queue ! filesink location=capture.mp4
说明:
“camera=0”参数选择 CAMERA0。请使用“camera=1”或“camera=2”从 CAMERA1 或 CAMERA2 进行录制。
要在本地计算机上查看录制内容,只需使用“adb pull /home/arduino/<recording>”或通过“scp pull arduino@<board-ip>:/home/arduino/<recording>”从保存视频的位置拉取它。
本地显示流
要在直接连接到 VENTUNO Q(通过 HDMI)的显示器上预览相机源,请使用“camera_test.py”脚本。它从相机捕获,通过硬件 H264 编码/解码来回传输帧,并通过“waylandsink”在窗口中渲染结果,每秒打印一次捕获到显示的延迟。
管道:qtiqmmfsrc → v4l2h264enc → h264parse → v4l2h264dec → waylandsink
注意:
您需要一台通过 HDMI 连接到 VENTUNO Q 的显示器才能使用此示例。
依赖关系
| 包裹 | 提供 |
|---|---|
qcom 相机服务器
|
拥有相机硬件的“cam-server”服务 |
gstreamer1.0-plugins-qcom-qmmfsrc
|
qtiqmmfsrc,相机源元素
|
gstreamer1.0-plugins-qcom-good
|
v4l2h264enc / v4l2h264dec,硬件 H264 编码/解码
|
gstreamer1.0-plugins-qcom-bad
|
h264解析
|
libgstreamer-qcom1.0-0
|
核心管道元素(“队列”、总线) |
python3-gi
|
GStreamer 的 Python 绑定(import gi)
|
上述所有软件包均已预安装在 VENTUNO Q 板映像上。如果缺少一个,例如在自定义映像构建之后,请使用以下命令安装它们:
sudo apt update
sudo apt install -y qcom-camera-server gstreamer1.0-plugins-qcom-qmmfsrc gstreamer1.0-plugins-qcom-good gstreamer1.0-plugins-qcom-bad libgstreamer-qcom1.0-0 python3-gi
创建脚本
使用“nano”直接在板上创建脚本:
nano camera_test.py
或者,如果您想在计算机上写入文件,请使用“scp”或“adb”将其传输到开发板:
scp camera_test.py arduino@<ip-address>:/home/arduino/
# or, over USB-C®:
adb push camera_test.py /home/arduino/
粘贴下面脚本的内容,然后保存并退出(“CTRL+X”,然后“Y”,然后“Enter”)。
camera_test.py
import os
import signal
import sys
import time
# Must be set before GStreamer/Wayland touches the display — do this first,
# so the script works whether it's launched from the graphical session or
# from a plain SSH/serial shell that never inherited these.
os.environ.setdefault("XDG_RUNTIME_DIR", f"/run/user/{os.getuid()}")
os.environ.setdefault("WAYLAND_DISPLAY", "wayland-0")
import gi
gi.require_version("Gst", "1.0")
from gi.repository import Gst, GLib
_wayland_socket = os.path.join(
os.environ["XDG_RUNTIME_DIR"], os.environ["WAYLAND_DISPLAY"]
)
HAS_DISPLAY = os.path.exists(_wayland_socket)
if HAS_DISPLAY:
_SINK = "waylandsink name=sink sync=false"
else:
print(
f"no wayland compositor socket at {_wayland_socket} — "
"running headless, dropping frames via fakesink instead of displaying them",
file=sys.stderr,
)
_SINK = "fakesink name=sink sync=false"
PIPELINE_DESC = (
"qtiqmmfsrc camera=0 name=camsrc video_0::type=preview ! "
"video/x-raw,format=NV12_Q08C,width=1920,height=1080,framerate=30/1,"
"interlace-mode=progressive,colorimetry=bt601 ! "
"queue ! v4l2h264enc capture-io-mode=4 output-io-mode=5 ! h264parse ! "
"v4l2h264dec ! video/x-raw,format=NV12 ! "
f"queue ! {_SINK}"
)
PRINT_INTERVAL_S = 1.0
def main():
Gst.init(None)
pipeline = Gst.parse_launch(PIPELINE_DESC)
sink = pipeline.get_by_name("sink")
sinkpad = sink.get_static_pad("sink")
last_print = [0.0]
def on_probe(pad, info):
buf = info.get_buffer()
if buf is None or buf.pts == Gst.CLOCK_TIME_NONE:
return Gst.PadProbeReturn.OK
now_wall = time.monotonic()
if now_wall - last_print[0] < PRINT_INTERVAL_S:
return Gst.PadProbeReturn.OK
last_print[0] = now_wall
clock = pipeline.get_clock()
if clock is None:
return Gst.PadProbeReturn.OK
running_time = clock.get_time() - pipeline.get_base_time()
latency_ms = (running_time - buf.pts) / 1e6
print(f"latency (capture -> encode -> decode -> display): {latency_ms:.2f} ms")
return Gst.PadProbeReturn.OK
sinkpad.add_probe(Gst.PadProbeType.BUFFER, on_probe)
loop = GLib.MainLoop()
def on_bus_message(bus, message):
t = message.type
if t == Gst.MessageType.ERROR:
err, debug = message.parse_error()
print(f"gst error: {err} ({debug})", file=sys.stderr)
elif t == Gst.MessageType.EOS:
loop.quit()
return True
bus = pipeline.get_bus()
bus.add_signal_watch()
bus.connect("message", on_bus_message)
def shutdown():
print("\nstopping...")
pipeline.set_state(Gst.State.NULL)
loop.quit()
return GLib.SOURCE_REMOVE
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, shutdown)
pipeline.set_state(Gst.State.PLAYING)
try:
loop.run()
finally:
pipeline.set_state(Gst.State.NULL)
if __name__ == "__main__":
main()
运行脚本
python3 camera_test.py
运行脚本后,您应该在终端中看到日志(延迟),并且显示屏上应该出现实时摄像头源。
<img src="
" alt="通过 MIPI-CSI 摄像头进行视频录制" />
VLC 流 (RTSP)
为了远程查看摄像头源,“camera_rtsp_server.py”将相同的捕获和硬件 H264 编码封装在嵌入式 RTSP 服务器(“GstRtspServer”)中,因此网络上任何支持 RTSP 的播放器都可以按需提取流。本地不显示任何内容,客户端自行解码。
管道(由 GstRtspMediaFactory 在内部构建和运行):qtiqmmfsrc → v4l2h264enc → h264parse → rtph264pay (pay0)
依赖关系
它建立在与本地显示流相同的软件包之上,加上:
| 包裹 | 提供 |
|---|---|
libgstrtspserver-1.0-0
|
RTSP服务器共享库 |
gir1.2-gst-rtsp-server-1.0
|
GstRtspServer 的 Python 绑定(from gi.repository import GstRtspServer)
|
libgstrtspserver-1.0-0 已预安装,但 gir1.2-gst-rtsp-server-1.0 未安装。安装它:
sudo apt update
sudo apt install -y gir1.2-gst-rtsp-server-1.0
您还需要在用于观看流的计算机或手机上安装 VLC 媒体播放器(或“ffplay”)。
创建脚本
使用“nano”直接在板上创建脚本:
nano camera_rtsp_server.py
或者,如果您想在计算机上写入文件,请使用“scp”或“adb”将其传输到开发板:
scp camera_rtsp_server.py arduino@<ip-address>:/home/arduino/
# or, over USB-C®:
adb push camera_rtsp_server.py /home/arduino/
粘贴下面脚本的内容,然后保存并退出(“CTRL+X”,然后“Y”,然后“Enter”)。
camera_rtsp_server.py
import os
import signal
import sys
# Must be set before GStreamer touches the display — do this first, before
# any gi import, so the script works from SSH/serial too, not just a
# graphical session.
os.environ.setdefault("XDG_RUNTIME_DIR", f"/run/user/{os.getuid()}")
os.environ.setdefault("WAYLAND_DISPLAY", "wayland-0")
import gi
gi.require_version("Gst", "1.0")
gi.require_version("GstRtspServer", "1.0")
from gi.repository import Gst, GstRtspServer, GLib
RTSP_PORT = "8554"
RTSP_MOUNT = "/test"
# Same qtiqmmfsrc capture + hardware h264 encode as camera_test.py, but
# payloaded as RTP instead of decoded back to a local waylandsink — the
# remote client does its own decoding.
PIPELINE_DESC = (
"qtiqmmfsrc camera=0 name=camsrc video_0::type=preview ! "
"video/x-raw,format=NV12_Q08C,width=1920,height=1080,framerate=30/1,"
"interlace-mode=progressive,colorimetry=bt601 ! "
"queue ! v4l2h264enc capture-io-mode=4 output-io-mode=5 ! h264parse ! "
"rtph264pay name=pay0 pt=96"
)
def main():
Gst.init(None)
server = GstRtspServer.RTSPServer()
server.set_service(RTSP_PORT)
factory = GstRtspServer.RTSPMediaFactory()
factory.set_launch(PIPELINE_DESC)
# Shared: one capture/encode session feeds every connected client,
# instead of trying to open the camera again per client.
factory.set_shared(True)
mounts = server.get_mount_points()
mounts.add_factory(RTSP_MOUNT, factory)
server.attach(None)
loop = GLib.MainLoop()
def shutdown(*_):
print("\nstopping...")
loop.quit()
return GLib.SOURCE_REMOVE
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, shutdown)
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGTERM, shutdown)
print(f"RTSP stream ready — connect from another device with:")
print(f" rtsp://<board-ip>:{RTSP_PORT}{RTSP_MOUNT}")
sys.stdout.flush()
try:
loop.run()
finally:
pass
if __name__ == "__main__":
main()
运行脚本
python3 camera_rtsp_server.py
找到开发板的 IP 地址(需要从其他设备连接):
hostname -I
在 VLC 中查看流
- 在与 VENTUNO Q 连接到同一网络的计算机上打开 VLC,然后转到 文件 > 打开网络...
<img src="
" alt="VLC 中的开放网络" />
- 输入流 URL
rtsp://<board-ip>:8554/test,将<board-ip>替换为您开发板的 IP 地址,然后单击 Open:
<img src="
" alt="VLC播放RTSP摄像头流" />
ffplay rtsp://<board-ip>:8554/test
# or
gst-launch-1.0 rtspsrc location=rtsp://<board-ip>:8554/test ! rtph264depay ! h264parse ! avdec_h264 ! autovideosink
说明:
您还可以从终端使用“ffplay”或“gst-launch-1.0”而不是 VLC:
浏览器流 (MJPEG)
为了获得最简单的客户端体验,“camera_mjpeg_server.py”直接从“qtiqmmfsrc”捕获硬件编码的 JPEG 帧(不需要软件“jpegenc”/“videoconvert”,ISP 本身会发出 JPEG),并通过纯 HTTP 作为“multipart/x-mixed-replace”流提供它们,这是任何浏览器都可以直接渲染的经典 MJPEG 格式,无需额外的插件或播放器。
管道:“qtiqmmfsrc(图像/jpeg 输出)→ appsink”,后台 Python“http.server”在每个新帧到达时将其推送到连接的客户端。
依赖关系
它建立在与本地显示流相同的基础包之上,此外:
| 包裹 | 提供 |
|---|---|
gstreamer1.0-插件库
|
应用程序接收器
|
该脚本所需的所有软件包均已预安装在 VENTUNO Q 板映像上,无需额外安装。除了“python3-gi”之外,脚本本身仅依赖于Python的标准库(“threading”、“http.server”)。
创建脚本
使用“nano”直接在板上创建脚本:
nano camera_mjpeg_server.py
或者,如果您想在计算机上写入文件,请使用“scp”或“adb”将其传输到开发板:
scp camera_mjpeg_server.py arduino@<ip-address>:/home/arduino/
# or, over USB-C®:
adb push camera_mjpeg_server.py /home/arduino/
粘贴下面脚本的内容,然后保存并退出(“CTRL+X”,然后“Y”,然后“Enter”)。
camera_mjpeg_server.py
import os
import signal
import sys
import threading
# Must be set before GStreamer touches the display — do this first, before
# any gi import, so the script works from SSH/serial too, not just a
# graphical session.
os.environ.setdefault("XDG_RUNTIME_DIR", f"/run/user/{os.getuid()}")
os.environ.setdefault("WAYLAND_DISPLAY", "wayland-0")
import gi
gi.require_version("Gst", "1.0")
from gi.repository import Gst, GLib
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
HTTP_PORT = 8080
BOUNDARY = "frame"
# qtiqmmfsrc's video pad can emit hardware-encoded JPEG directly — no
# software jpegenc/videoconvert needed. Lower resolution/framerate than the
# H264 pipeline since each MJPEG frame is a full independent JPEG.
PIPELINE_DESC = (
"qtiqmmfsrc camera=0 name=camsrc video_0::type=preview ! "
"image/jpeg,width=1280,height=720,framerate=15/1 ! "
"appsink name=sink emit-signals=true max-buffers=1 drop=true sync=false"
)
latest_frame = None
frame_lock = threading.Lock()
frame_available = threading.Condition(frame_lock)
def on_new_sample(sink):
global latest_frame
sample = sink.emit("pull-sample")
if sample is None:
return Gst.FlowReturn.OK
buf = sample.get_buffer()
ok, mapinfo = buf.map(Gst.MapFlags.READ)
if not ok:
return Gst.FlowReturn.OK
data = bytes(mapinfo.data)
buf.unmap(mapinfo)
with frame_available:
latest_frame = data
frame_available.notify_all()
return Gst.FlowReturn.OK
class MjpegHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path not in ("/", "/stream"):
self.send_error(404)
return
self.send_response(200)
self.send_header("Age", "0")
self.send_header("Cache-Control", "no-cache, private")
self.send_header("Pragma", "no-cache")
self.send_header(
"Content-Type", f"multipart/x-mixed-replace; boundary={BOUNDARY}"
)
self.end_headers()
last_sent = None
try:
while True:
with frame_available:
frame_available.wait(timeout=2.0)
frame = latest_frame
if frame is None or frame is last_sent:
continue
last_sent = frame
self.wfile.write(f"--{BOUNDARY}\r\n".encode())
self.wfile.write(b"Content-Type: image/jpeg\r\n")
self.wfile.write(f"Content-Length: {len(frame)}\r\n\r\n".encode())
self.wfile.write(frame)
self.wfile.write(b"\r\n")
except (BrokenPipeError, ConnectionResetError):
pass
def log_message(self, format, *args):
pass # quiet by default; comment out to debug per-request logging
def main():
Gst.init(None)
pipeline = Gst.parse_launch(PIPELINE_DESC)
sink = pipeline.get_by_name("sink")
sink.connect("new-sample", on_new_sample)
bus = pipeline.get_bus()
bus.add_signal_watch()
def on_bus_message(bus, message):
if message.type == Gst.MessageType.ERROR:
err, debug = message.parse_error()
print(f"gst error: {err} ({debug})", file=sys.stderr)
return True
bus.connect("message", on_bus_message)
pipeline.set_state(Gst.State.PLAYING)
server = ThreadingHTTPServer(("0.0.0.0", HTTP_PORT), MjpegHandler)
threading.Thread(target=server.serve_forever, daemon=True).start()
loop = GLib.MainLoop()
def shutdown(*_):
print("\nstopping...")
server.shutdown()
pipeline.set_state(Gst.State.NULL)
loop.quit()
return GLib.SOURCE_REMOVE
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, shutdown)
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGTERM, shutdown)
print("MJPEG stream ready — open in a browser at:")
print(f" http://<board-ip>:{HTTP_PORT}/stream")
sys.stdout.flush()
try:
loop.run()
finally:
pipeline.set_state(Gst.State.NULL)
if __name__ == "__main__":
main()
运行脚本
python3 camera_mjpeg_server.py
找到开发板的 IP 地址(需要从其他设备连接):
hostname -I
在浏览器中查看流
在与 VENTUNO Q 连接到同一网络的任何设备上打开浏览器,然后导航至“http://<board-ip>:8080/stream”。
<img src="
" alt="在浏览器中查看 MJPEG 摄像头流" />
您还可以使用普通的“<img>”标记将流嵌入网页中:
<img src="http://<board-ip>:8080/stream">
故障排除
`dmesg` 中没有“探测成功”行
如果找不到“探测成功”行,请验证:
- 摄像头模块基于IMX577传感器。目前不支持其他传感器(将添加更多模块)
- 柔性电缆完全插入并锁定在连接器的闩锁中。请注意,即使是最轻微的未对准也可能足以导致连接错误。另外,请确保电缆的方向正确。
- 安装
gstreamer1.0-plugins-qcom后**重新启动了开发板。
本地流显示黑屏
- 在打开开发板电源之前,确认显示器已通过 HDMI 连接。
- 检查脚本的输出是否报告正在无头运行。如果是,则未找到 Wayland 合成器套接字,请仔细检查显示连接。
“打开相机失败!”错误
cam-server 仅支持单个活动捕获会话。该错误通常意味着:
- 另一个脚本(或客户端)已在使用相机。首先停止它,一次只能运行“camera_test.py”、“camera_rtsp_server.py”或“camera_mjpeg_server.py”之一。
- 之前的脚本被不干净地终止(例如使用“kill -9”或崩溃),导致“cam-server”的内部会话状态卡住。通过重新启动服务来清除它:
sudo systemctl restart cam-server
无法连接到 RTSP 或 MJPEG 流
- 确认开发板和查看设备位于同一网络,并且您使用的是开发板当前的 IP 地址(“主机名 -I”)。
- 检查板上没有任何东西(防火墙或“ufw”)阻止所需的端口,“8554/tcp”(用于 RTSP)或“8080/tcp”(用于 MJPEG)。
- 两个流都不使用身份验证或 TLS,这在受信任的本地网络上很好,但在不添加您自己的身份验证或 VPN 的情况下,端口不应直接暴露到互联网。
总结
在本指南中,您学习了如何将 MIPI-CSI 摄像头模块连接到 Arduino® VENTUNO™ Q、安装所需的 GStreamer 插件、确认检测到摄像头以及使用 GStreamer 录制视频。您还可以设置三种不同的方式来查看实时源:本地在连接的显示器上、通过 RTSP 在 VLC 中远程以及通过 MJPEG 在 Web 浏览器中远程。从这里,您可以在这些管道的基础上进行构建,将相机帧输入到板上本地运行的边缘人工智能应用程序中。
说明:
要了解有关 VENTUNO Q 相机连接器的更多信息,请访问 VENTUNO Q 用户手册。
原文:https://docs.arduino.cc/tutorials/ventuno-q/mipi-csi-camera/ 本页为 Arduino 官方教程的中文翻译,供内部查阅。命令与代码保持原文。