1.V4L2摄像头数据采集
在《V4L2摄像头数据采集》代码的基础上增加一些有关MQTT的代码。
2.异常检测MQTT报警和上传
3.1 强光弱光异常报警
3.2 晃动异常报警
3.2 定时拍照上传
3.1 人脸检测报警(该方法可以拍照,但采集的是原始帧数据(如YUYV) ,不能直接送入人脸检测算法)
3. 硬件框架图
4. 软件模块图
6. 编译运行
6.1 编译
本地编译:gcc video_test.c detection.c mqtt.c -o video_test -lpaho-mqtt3c -lpthread
交叉编译: arm-buildroot-linux-gnueabihf-gcc video_test.c detection.c mqtt.c -o video_test -lpaho-mqtt3c -lpthread
加上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 警告
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/
在开发板更新动态库缓存
# 在开发板执行
ldconfig
——————————
出现 ldconfig 警告的原因有两个:
/etc/ld.so.conf文件缺失:系统缺少动态库配置文件。libpaho-mqtt3c.so.1不是符号链接:动态库的版本管理符号链接未正确创建。
1. 修复 /etc/ld.so.conf 缺失问题
echo "/usr/lib" > /etc/ld.so.conf
cat /etc/ld.so.conf
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*
错误 1:找不到分类器 XML 文件
- 查找XML文件:
find /home/book/opencv/ -name haarcascade_frontalface_default.xml
-
文件路径: /home/book/opencv/data/haarcascades/haarcascade_frontalface_default.xml
-
拷贝到目标板(如 NFS 根目录):
cp /home/book/opencv/data/haarcascades/haarcascade_frontalface_default.xml ~/nfs_rootfs/haarcascade/
- 修改代码中 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
9.2 PC端使用window启动Mosquitto Broker—服务器(Broker)
Window的以太网(有线)IP地址和开发板在同一子网,所以可以连接,见10.3
9.3 PC端使用MQTTX工具查看报警信息—订阅端(Subscriber)
-
订阅报警主题:
-
打开 MQTTX,点击 New Connection。
-
输入以下信息:
- Name:
PC_Subscriber - Host: 填写 PC 的 IP 地址(若 Broker 在本地,填
127.0.0.1)。 - Port:
1883
- Name:
-
点击 Connect 连接 Broker。
-
点击 + New Subscription,输入主题
alarm/events,点击 Confirm。
-
9.3.1 三种 MQTT 连接的区别
1. 127.0.0.1:1883 —— 本地回环地址
- 只适用于你自己的电脑本身(localhost)
- 如果 Mosquitto 启动并监听
127.0.0.1或0.0.0.0,这能成功连接 - 其它设备(如手机、树莓派)无法连接这个地址
常见用途:本地测试通信是否成功,例如 mosquitto_pub 和 mosquitto_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 一样)
- 仅用于临时测试或学习,不适合生产环境
10. ARM板连接
ARM 开发板连接PC端服务器(Broker)-发布端(Publisher)。
-
无线局域网适配器(Wi-Fi) ,开发板通过Wi-Fi连接同一无线网络
-
以太网适配器(有线网络) , 开发板通过网线直连PC或同一有线局域网
-
VMnet1 和 VMnet8 是VMware虚拟机专用网络,除非开发板运行在虚拟机中并通过虚拟网络桥接,否则这些地址无法被物理开发板访问。
| 网络适配器 | 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查看驱动名称
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)。
- PC的IP:
-
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 是否运行
- 确保MQTT 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 通信
- 在 PC 上订阅主题:
```
mosquitto_sub -h 192.168.5.10 -t "test"
```
-
在开发板上发布消息:
mosquitto_pub -h 192.168.5.10 -t "test" -m "hello"
————————————————————————————————————
开发板连接PC端最终验证步骤:
-
物理连接:确保网线连接正确。
-
IP 配置:开发板和 PC 在同一子网(
192.168.5.x/24)。 -
防火墙:Windows 允许 ICMP 入站请求。
-
双向测试:
- 开发板 Ping PC →
ping 192.168.5.10 - PC Ping 开发板 →
ping 192.168.5.9
- 开发板 Ping PC →
10.4 Mosquitto端口占用问题
查看占用 1883 端口的进程
Error: 通常每个套接字地址(协议/网络地址/端口)只允许使用一次。
这个是经典的 端口已被占用 错误,说明 端口 1883 已经被其他进程占用了。Mosquitto 无法再次绑定到该端口。
打开 PowerShell 或命令提示符(cmd),执行:netstat -aon | findstr :1883
tasklist /FI "PID eq 21936"
关闭已经运行的 Mosquitto 的方法
方法一:通过任务管理器结束进程(最推荐)
- 按下
Ctrl + Shift + Esc打开 任务管理器 - 切换到 "详细信息" 选项卡
- 找到进程名为
mosquitto.exe - 右键点击它,选择 结束任务
如果没有看到 PID,可以右键表头 → 选择列 → 勾选“PID”来查看具体进程号。
方法二:通过命令行杀死进程 taskkill /PID 21936 /F
10.4 使用替代工具验证 Broker 状态、验证服务运行
如果window上的mosquitto在运行,但是MQTTX连不上,可以对Broker进行测试