基于V4L2和MQTT的智能监控(异常报警)摄像头

148 阅读10分钟

1.V4L2摄像头数据采集

在《V4L2摄像头数据采集》代码的基础上增加一些有关MQTT的代码。

2.异常检测MQTT报警和上传

3.1 强光弱光异常报警

3.2 晃动异常报警

3.2 定时拍照上传

3.1 人脸检测报警(该方法可以拍照,但采集的是原始帧数据(如YUYV)  ,不能直接送入人脸检测算法)

3. 硬件框架图

1748156891914.png

1748157050617.png

1748157125837.png

4. 软件模块图

6. 编译运行

6.1 编译

本地编译:gcc video_test.c detection.c mqtt.c -o video_test -lpaho-mqtt3c -lpthread

1747934957900.png

交叉编译: arm-buildroot-linux-gnueabihf-gcc video_test.c detection.c mqtt.c -o video_test -lpaho-mqtt3c -lpthread

1747999126438.png

加上opencv代码的交叉编译:

arm-buildroot-linux-gnueabihf-g++ video_test.c detection.cpp mqtt.c -o video_test \
-I/home/book/opencv-arm-install/include/opencv4 \
-L/home/book/opencv-arm-install/lib \
-lopencv_core -lopencv_imgproc -lopencv_imgcodecs -lopencv_objdetect \
-lopencv_dnn -lopencv_calib3d -lopencv_features2d -lopencv_flann \
-lpaho-mqtt3c -lpthread

6.2 Makefire

# ========== Makefile ==========
# 项目名称
TARGET = video_test

# 交叉编译工具链前缀
CXX = arm-buildroot-linux-gnueabihf-g++
CC  = arm-buildroot-linux-gnueabihf-gcc

# OpenCV 安装路径(交叉编译好的)
OPENCV_DIR = /home/book/opencv-arm-install

# 头文件和库路径
CFLAGS  = -I$(OPENCV_DIR)/include/opencv4
LDFLAGS = -L$(OPENCV_DIR)/lib

# 源文件和对象文件
C_SRCS  = video_test.c mqtt.c
CPP_SRCS = detection.cpp
OBJS = $(C_SRCS:.c=.o) $(CPP_SRCS:.cpp=.o)

# 链接的库(OpenCV + MQTT + pthread)
LDLIBS = -lopencv_core -lopencv_imgproc -lopencv_imgcodecs -lopencv_objdetect -lpaho-mqtt3c -lpthread

# 默认目标
all: $(TARGET)

# 链接目标
$(TARGET): $(OBJS)
	$(CXX) $^ -o $@ $(LDFLAGS) $(LDLIBS)

# 编译 C 文件
%.o: %.c
	$(CC) -c $< -o $@ $(CFLAGS)

# 编译 C++ 文件
%.o: %.cpp
	$(CXX) -c $< -o $@ $(CFLAGS)

# 清理
clean:
	rm -f $(TARGET) *.o

# 伪目标
.PHONY: all clean

7. 编译错误与解决方案

7.1 本地编译出错:fatal error: MQTTClient.h: No such file or directory

# 安装编译工具和依赖
sudo apt update
sudo apt install -y cmake gcc build-essential libssl-dev

# 下载 Paho MQTT C 库源码
wget https://github.com/eclipse/paho.mqtt.c/archive/refs/tags/v1.3.12.tar.gz
tar -xzf v1.3.12.tar.gz
cd paho.mqtt.c-1.3.12

# 编译安装
mkdir build
cd build
cmake -DPAHO_WITH_SSL=OFF ..  # 禁用 SSL 简化依赖
make
sudo make install
sudo ldconfig  # 更新动态库缓存

这是手动安装到系统目录,适合长期开发。以后可以把这头文件和库文件复制到工程目录下就可以了。

ls /usr/local/include/MQTTClient.h  # 确认头文件存在
ls /usr/local/lib/libpaho-mqtt3c*   # 确认库文件存在

交叉编译时,不能直接引用主机的 /usr/local/include 和 /usr/local/lib,因为这些路径下的库是为当前主机架构(如 x86_64)编译的,无法在 ARM 平台上运行。必须使用交叉编译工具链的 sysroot 路径。见5.5所示

7.2 error: unknown type name ‘uint8_t’; did you mean ‘u_int8_t

#include <sys/types.h>  // 包含 u_int8_t 的定义
typedef u_int8_t uint8_t;  // 手动定义别名

7.3 error: ‘EXIT_FAILURE’ undeclared (first use in this function); did you mean ‘_IO_FILE’?

包含标准库头文件 stdlib.h

这个头文件定义了 EXIT_FAILURE 和 EXIT_SUCCESS 宏,用于表示程序的退出状态码。

7.4 警告

1747970467590.png

7.5 交叉编译时出现 MQTTClient.h 未找到的错误

方法一:交叉编译并安装 Paho MQTT C 库(重点)

在 Ubuntu 上交叉编译 Paho MQTT C 库

# 进入工具链目录
cd /home/book/100ask_imx6ull-sdk/ToolChain/

# 设置环境变量
export TOOLCHAIN_PATH=$(pwd)/arm-buildroot-linux-gnueabihf_sdk-buildroot
export SYSROOT=$TOOLCHAIN_PATH/arm-buildroot-linux-gnueabihf/sysroot

# 下载并解压源码
wget https://github.com/eclipse/paho.mqtt.c/archive/refs/tags/v1.3.12.tar.gz
tar -xzf v1.3.12.tar.gz
cd paho.mqtt.c-1.3.12

# 配置交叉编译
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=$SYSROOT/usr -DCMAKE_SYSROOT=$SYSROOT -DPAHO_WITH_SSL=OFF -DCMAKE_C_COMPILER=$TOOLCHAIN_PATH/bin/arm-buildroot-linux-gnueabihf-gcc ..

# 编译并安装
make
sudo make install

验证安装结果

# 检查头文件
ls $SYSROOT/usr/include/MQTTClient.h

# 检查库文件
ls $SYSROOT/usr/lib/libpaho-mqtt3c.so

# 验证库文件架构
file $SYSROOT/usr/lib/libpaho-mqtt3c.so

方法二: 手动指定路径(错误)

如果 Paho MQTT 库未安装到工具链的 sysroot,可以直接指定本地路径:

这种情况必须是交叉编译得到的库文件和头文件才可以,本地编译不可以。

arm-buildroot-linux-gnueabihf-gcc \
  video_test.c detection.c mqtt.c \
  -o video_test \
  -I/usr/local/include \        # 手动指定头文件路径
  -L/usr/local/lib \  # 手动指定库文件路径
  -lpaho-mqtt3c \
  -lpthread

方法三:复制库文件和头文件到工程目录

这种情况也必须是交叉编译得到的库文件和头文件才可以,本地编译不可以。

7.6 OpenCV交叉编译和运行

如果编译成功,但是运行时出现找不到文件:./video_test: error while loading shared libraries: libopencv_core.so.412: cannot open shared object file: No such file or directory。

方法一:运行前设置环境变量(推荐

export LD_LIBRARY_PATH=./lib:$/home/book/opencv-arm-install/lib
./video_test /dev/video1

临时告诉系统:“把当前目录下的 ./lib 目录作为库查找路径

方法二:在编译时设置 rpath(推荐做法)

你可以在编译时加上:-Wl,-rpath=./lib

arm-buildroot-linux-gnueabihf-g++ video_test.c detection.c mqtt.c -o video_test \
    -I/home/book/opencv-arm-install/include \
    -L./lib -Wl,-rpath=./lib \
    -lopencv_core -lopencv_imgcodecs -lopencv_imgproc -lpaho-mqtt3c -lpthread

8. 运行错误与解决方法

error while loading shared libraries: libpaho-mqtt3c.so.1: cannot open shared object file: No such file or directory

错误的原因是:交叉编译生成的程序依赖动态库 libpaho-mqtt3c.so.1,但该库未正确部署到 ARM 开发板的文件系统中。

解决方法:

使用 scp 或 adb 将库文件传输到开发板的 /usr/lib 目录:

scp /home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/lib/libpaho-mqtt3c.so* root@192.168.5.9:/usr/lib/

1748004898795.png

在开发板更新动态库缓存

# 在开发板执行
ldconfig

——————————

出现 ldconfig 警告的原因有两个:

  1. /etc/ld.so.conf 文件缺失:系统缺少动态库配置文件。
  2. libpaho-mqtt3c.so.1 不是符号链接:动态库的版本管理符号链接未正确创建。

1. 修复 /etc/ld.so.conf 缺失问题

echo "/usr/lib" > /etc/ld.so.conf
cat /etc/ld.so.conf

1748006022779.png

2. 修复符号链接问题

# 进入开发板的库目录
cd /usr/lib

# 创建版本符号链接
ln -sf libpaho-mqtt3c.so.1.3.12 libpaho-mqtt3c.so.1

# 创建通用符号链接
ln -sf libpaho-mqtt3c.so.1 libpaho-mqtt3c.so

#验证符号连接
ls -l /usr/lib/libpaho-mqtt3c.so*

1748006231432.png

错误 1:找不到分类器 XML 文件

  1. 查找XML文件:

find /home/book/opencv/ -name haarcascade_frontalface_default.xml

  1. 文件路径: /home/book/opencv/data/haarcascades/haarcascade_frontalface_default.xml

  2. 拷贝到目标板(如 NFS 根目录):

cp /home/book/opencv/data/haarcascades/haarcascade_frontalface_default.xml ~/nfs_rootfs/haarcascade/

  1. 修改代码中 XML 的路径: face_cascade.load("/mnt/haarcascade/haarcascade_frontalface_default.xml");

错误 2:内存分配失败(严重)

video_test: page allocation failure: order:0, mode:0x2080020(GFP_ATOMIC)

原因:

这是内核分配内存失败的错误,可能是因为你的程序占用了过多内存(OpenCV + 图像缓冲 + objdetect)超出了 i.MX6ULL 板子的内存限制(通常 256MB)。

9. PC端连接

  • ARM开发板:作为MQTT客户端(Publisher),检测异常后发布消息。

  • PC端:作为MQTT代理(Broker)和客户端(Subscriber)。

    • Mosquitto:作为MQTT代理服务器(Broker),负责消息中转。
    • MQTTX:作为MQTT客户端工具,用于订阅报警主题并接收消息。

9.1 PC端使用Ubuntu启动Mosquitto Broker—服务器(Broker)

Ubuntu上安装并配置 Mosquitto Broker

Ubuntu的IP地址和开发板不在同一子网,所以不能连接,但是window可以通过公网和Ubuntu的IP地址连接。

sudo apt-get update
sudo apt-get install mosquitto mosquitto-clients

sudo mkdir -p /etc/mosquitto
sudo touch /etc/mosquitto/mosquitto.conf
echo -e "listener 1883 0.0.0.0\nallow_anonymous true" | sudo tee /etc/mosquitto/mosquitto.conf

find / -name "mosquitto.conf" 2>/dev/null

# 启动Broker临时测试
mosquitto -c /etc/mosquitto/mosquitto.conf -d

# 重启broker
sudo systemctl restart mosquitto

# 验证 Broker 是否运行
netstat -tuln | grep 1883

1748099925393.png

9.2 PC端使用window启动Mosquitto Broker—服务器(Broker)

Window的以太网(有线)IP地址和开发板在同一子网,所以可以连接,见10.3 1748026614666.png

9.3 PC端使用MQTTX工具查看报警信息—订阅端(Subscriber)

  • 订阅报警主题

    1. 打开 MQTTX,点击 New Connection

    2. 输入以下信息:

      • NamePC_Subscriber
      • Host: 填写 PC 的 IP 地址(若 Broker 在本地,填 127.0.0.1)。
      • Port1883
    3. 点击 Connect 连接 Broker。

    4. 点击  + New Subscription,输入主题 alarm/events,点击 Confirm

1748630659795.png

9.3.1 三种 MQTT 连接的区别

1748630194636.png

1. 127.0.0.1:1883 —— 本地回环地址

  • 只适用于你自己的电脑本身(localhost)
  • 如果 Mosquitto 启动并监听 127.0.0.10.0.0.0,这能成功连接
  • 其它设备(如手机、树莓派)无法连接这个地址

常见用途:本地测试通信是否成功,例如 mosquitto_pubmosquitto_sub 在同一台电脑上通信。

2. 192.168.5.10:1883 —— 局域网访问

  • 是你电脑的局域网 IP 地址
  • 可以让 局域网内的其他设备(手机、开发板、树莓派) 访问到你的 Mosquitto 服务
  • 本机上连接这个地址也没问题,但通常用于外部设备访问

需要注意:

  • Mosquitto 的监听地址不能限制为 127.0.0.1,否则外部设备连不上
  • Windows 防火墙要放行 1883 端口(入站规则)

3. broker.emqx.io:1883 —— 公网 MQTT 测试服务器

  • 是 EMQ 提供的公开 MQTT Broker
  • 你通过 Internet 连接这个服务器,适用于测试 MQTT 连接
  • 服务端运行在远程,与本地 Mosquitto 无关

特点:

  • 你发布消息后,所有连接到这个服务器的人都可能订阅到(如果 topic 一样)
  • 仅用于临时测试或学习,不适合生产环境

1748630470599.png

10. ARM板连接

ARM 开发板连接PC端服务器(Broker)-发布端(Publisher)。

  • 无线局域网适配器(Wi-Fi) ,开发板通过Wi-Fi连接同一无线网络

  • 以太网适配器(有线网络) , 开发板通过网线直连PC或同一有线局域网

  • VMnet1 和 VMnet8 是VMware虚拟机专用网络,除非开发板运行在虚拟机中并通过虚拟网络桥接,否则这些地址无法被物理开发板访问。

1748096577358.png

网络适配器IPv4地址适用场景
以太网适配器(有线网络)192.168.5.10开发板通过网线直连PC或同一有线局域网
无线局域网适配器(Wi-Fi)192.168.0.3开发板通过Wi-Fi连接同一无线网络
VMware虚拟网络适配器192.168.157.1 192.168.237.1不推荐(仅适用于虚拟机内部通信)

10.1 方法一:使用公共 MQTT Broker——WIFI连接(未完成)

  • 开发板是否能访问互联网
    确保开发板已正确连接到互联网(如通过 Wi-Fi 或以太网)。尝试在开发板上执行 ping broker.emqx.io,确认网络可达。
#define BROKER_URL "tcp://broker.emqx.io:1883"

10.2 开发板连接Wi-Fi(未完成)

1. 检查是否预装 wpa_supplicant

which wpa_supplicant  # 查看是否存在可执行文件
# 安装
sudo apt-get install wpasupplicant

2. 扫描可用 Wi-Fi 网络

sudo iwlist wlan0 scan | grep ESSID

3. 创建 Wi-Fi 配置文件

方法一:使用 echo 直接写入文件,无需交互式编辑器,直接通过重定向创建文件:

方法二:使用 cat 命令创建文件,逐行输入内容并保存:

echo 'network={ ssid="Your_WiFi_SSID" psk="Your_WiFi_Password" }' | sudo tee /etc/wpa_supplicant.conf

cat > /etc/wpa_supplicant.conf << EOF
network={
    ssid="Your_WiFi_SSID"
    psk="Your_WiFi_Password"
}
EOF

配置文件/etc/wpa_supplicant/wpa_supplicant.conf不存在的解决方法: 创建/etc/wpa_supplicant,然后把配置文件放入文件中: mkdir -p /etc/wpa_supplicant

3. Wi-Fi 驱动未安装、安装驱动

使用lsusb查看驱动名称

1748092709122.png

4. 连接 Wi-Fi

10.3 方法二:使用局域网IP连接

以下操作是在window或者Ubuntu上执行,不是开发板上。

  • 1. 开发板与PC在同一子网。

    • PC的IP:192.168.5.10(有线)或 192.168.0.3(无线)。
    • 开发板的IP:与PC在同一子网(如 192.168.5.20 或 192.168.0.100)。
  • 2. 防火墙开放MQTT端口。在PC上开放MQTT Broker的端口(默认1883)

sudo ufw allow 1883/tcp  # Linux
或通过Windows防火墙设置允许端口
  • 3. MQTT Broker正确绑定IP并运行。(见7.1)

    • 确保MQTT Broker绑定到 0.0.0.0(所有接口)或具体IP(如 192.168.5.10
    • (1) 编辑配置文件:
    • (2)重启 Broker 服务:
    • 验证 Broker 是否运行
  • 5. 连接测试 在开发板上使用 mosquitto_pub 或代码测试连接

# 示例(使用PC有线网络IP)
mosquitto_pub -h 192.168.5.10 -t "test" -m "hello"

# 或使用PC无线网络IP
mosquitto_pub -h 192.168.0.3 -t "test" -m "hello"

—————————————————————————————————————

开发板连接到 PC 端 MQTT Broker(重点)

步骤 1:确保开发板与 PC 的有线网络连接正确

ifconfig eth0 192.168.5.9 netmask 255.255.255.0

# 开发板上执行 ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.5.9  netmask 255.255.255.0  broadcast 192.168.5.255
        RX packets 100  bytes 12000 (12.0 KB)
        TX packets 80  bytes 9600 (9.6 KB)

步骤 2:在 Windows PC 上禁用无关网络适配器

打开 Windows 的 网络连接 界面,禁用VMnet1,VMnet8,WLAN

步骤 3:配置 Windows 防火墙

需要临时关闭 Windows 防火墙:

1. 控制面板 → Windows Defender 防火墙 → 启用或关闭防火墙 → 全部关闭。(一定要记得确定)

netsh advfirewall firewall add rule name="ICMPv4" protocol=icmpv4:8,any dir=in action=allow
netsh advfirewall firewall add rule name="MQTT" dir=in action=allow protocol=TCP localport=1883

步骤 4:在 Windows PC 上配置并启动 MQTT Broker

编辑配置文件 mosquitto.conf:在文件末尾添加

# 允许所有 IP 连接(0.0.0.0 表示监听所有接口)
listener 1883 0.0.0.0

# 允许匿名连接(开发板无需用户名密码)
allow_anonymous true

# 日志输出级别(可选,debug 信息更详细)
log_type all

启动 Mosquitto 并指定配置文件:打开命令提示符(管理员权限),运行:

mosquitto -v -c "C:\Program Files\mosquitto\mosquitto.conf"

启动 Broker:mosquitto -v -c mosquitto.conf

mosquitto -v -c mosquitto.conf

步骤 5:验证双向网络连通性

ping 192.168.5.10
ping 192.168.5.9

步骤 6:测试 MQTT 通信

  1. 在 PC 上订阅主题

```
mosquitto_sub -h 192.168.5.10 -t "test"
```
  1. 在开发板上发布消息

    mosquitto_pub -h 192.168.5.10 -t "test" -m "hello"
    

————————————————————————————————————

开发板连接PC端最终验证步骤:

  1. 物理连接:确保网线连接正确。

  2. IP 配置:开发板和 PC 在同一子网(192.168.5.x/24)。

  3. 防火墙:Windows 允许 ICMP 入站请求。

  4. 双向测试

    • 开发板 Ping PC → ping 192.168.5.10
    • PC Ping 开发板 → ping 192.168.5.9

10.4 Mosquitto端口占用问题

查看占用 1883 端口的进程

Error: 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。

这个是经典的 端口已被占用 错误,说明 端口 1883 已经被其他进程占用了。Mosquitto 无法再次绑定到该端口。 打开 PowerShell 或命令提示符(cmd),执行:netstat -aon | findstr :1883

1748632068361.png

tasklist /FI "PID eq 21936"

1748632248640.png

关闭已经运行的 Mosquitto 的方法

方法一:通过任务管理器结束进程(最推荐)

  1. 按下 Ctrl + Shift + Esc 打开 任务管理器
  2. 切换到 "详细信息" 选项卡
  3. 找到进程名为 mosquitto.exe
  4. 右键点击它,选择 结束任务

如果没有看到 PID,可以右键表头 → 选择列 → 勾选“PID”来查看具体进程号。

方法二:通过命令行杀死进程 taskkill /PID 21936 /F

10.4 使用替代工具验证 Broker 状态、验证服务运行

如果window上的mosquitto在运行,但是MQTTX连不上,可以对Broker进行测试

11. 实验结果

1748154515242.png

1748154781332.png

1748631054295.png

1748631748001.png

1748154841631.png

1748636890564.png

1748637241011.png

1749055364304.png

1749055568602.png

1749055690509.png

12. 总结