Arduino通过MQTT发送消息到树莓派
一、场景描述
Arduino Uno R4和树莓派4B+均配备WiFi通讯模块,当连接到同一网络时,两者可以通过MQTT协议进行无线通讯。
如图所示,本教程介绍Arduino Uno R4(简称Ar)通过MQTT发送消息到Raspberry Pi 4B+(简称Pi)的实现方案。
二、准备工作
1、无线网络:互联网或局域网
2、计算机:用于配置Ar和Pi,与Ar和Pi连接到同一网络中
3、Ar:主板与数据线
4、Pi:主板与电源线
本教程中的Pi运行无桌面版本。如果对系统安装、网络配置、SSH连接、网络加速等不熟悉,可先阅读以下两个教程。
树莓派4/5:在无显示器(无屏幕)下的Lite系统安装与远程控制_raspberry pi os lite-CSDN博客
树莓派4/5:设置apt、pip、conda首选清华镜像源_树莓派清华源-CSDN博客
三、设置Pi
在使用Pi作为接收端之前,需要安装并启用MQTT服务。
MQTT Broker(MQTT 代理) 是 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)协议中的核心组件,负责接收、处理和转发消息。它类似于邮局或交换机,协调客户端(Publisher 发布者 和 Subscriber 订阅者)之间的通信。
Pi要成为MQTT服务器,需要安装mosquitto和paho-mqtt库。
1、安装和配置mosquitto
(1)安装mosquitto
sudo apt update
sudo apt install mosquitto mosquitto-clients -y
sudo systemctl enable mosquitto
sudo systemctl start mosquitto
(2)创建用户名和密码
# mqttuser可以自定义,指的是mqtt的用户名,例如yu
sudo mosquitto_passwd -c /etc/mosquitto/passwd mqttuser
(3)配置mosquitto
首先,打开配置文件。
sudo nano /etc/mosquitto/mosquitto.conf
在所打开的conf文件中,添加#Add后面的三行内容。
pid_file /run/mosquitto/mosquitto.pidpersistence true
persistence_location /var/lib/mosquitto/log_dest file /var/log/mosquitto/mosquitto.log# Add
listener 1883 0.0.0.0
allow_anonymous false
password_file /etc/mosquitto/passwd
编辑完成后,依次按Ctrl+X,按Y,按Enter。
(4)重启mosquitto
sudo systemctl restart mosquitto
(5)确认mosquitto
sudo systemctl status mosquitto
如果显示active (running),说明mosquitto(MQTT服务)已开启。
2、安装paho-mqtt
paho-mqtt是 Eclipse Foundation 旗下的开源 MQTT 客户端项目,提供多种编程语言的 MQTT 实现,适用于 IoT(物联网)、嵌入式系统和服务器应用。
建议使用miniforge创建虚拟环境。
假设已经安装miniforge,安装paho-mqtt示例如下。
# 创建mqtt虚拟环境
mamba create -n mqtt python=3.9# 激活mqtt虚拟环境
conda activate mqtt# 安装paho-mqtt库
pip install paho-mqtt
3、编写接收端程序
Pi作为接收端,需要指定自身的IP地址、用户名和密码,即BROKER、USERNAME、PASSWORD,TOPIC不建议修改。
import paho.mqtt.client as mqtt# raspberrypi IP address
BROKER = "192.168.X.XXX"
PORT = 1883
# username
USERNAME = "pi"
# password
PASSWORD = "raspberry"
# topic
TOPIC = "arduino/simple"def on_connect(client, userdata, flags, rc):if rc == 0:print("Connected to MQTT Broker!")client.subscribe(TOPIC)else:print("Failed to connect, return code %d\n", rc)def on_message(client, userdata, msg):print(f"Received message: {msg.payload.decode()} from topic: {msg.topic}")client = mqtt.Client()
client.username_pw_set(USERNAME, PASSWORD)
client.on_connect = on_connect
client.on_message = on_messageclient.connect(BROKER, PORT, keepalive=60)
client.loop_forever()
四、设置Ar
Ar只需要编写程序即可。
1、编写发送端程序
注意,ssid[]、pass[]、broker、mqttClient.setUsernamePassword等参数需要自定义。
#include <ArduinoMqttClient.h>
#include <WiFiS3.h># WiFi账号密码
char ssid[] = "WiFi";
char pass[] = "raspberrypi"; WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);# 树莓派IP地址
const char broker[] = "192.168.X.XXX";
int port = 1883;
const char topic[] = "arduino/simple";const long interval = 1000;
unsigned long previousMillis = 0;
int count = 0;void setup() {// 初始化串口通信Serial.begin(9600);Serial.println("=== Serial communication started ===");// 等待串口连接(仅对有USB CDC功能的板卡有效)unsigned long startWait = millis();while (!Serial && (millis() - startWait) < 5000) {; // 等待最多5秒}Serial.println("Attempting to connect to WiFi...");Serial.print("SSID: ");Serial.println(ssid);int wifiStatus = WL_IDLE_STATUS;while (wifiStatus != WL_CONNECTED) {wifiStatus = WiFi.begin(ssid, pass);Serial.print("WiFi connection attempt. Status: ");Serial.println(wifiStatus);delay(5000);}Serial.println("\nConnected to WiFi!");Serial.print("IP Address: ");Serial.println(WiFi.localIP());Serial.print("Signal Strength (RSSI): ");Serial.print(WiFi.RSSI());Serial.println(" dBm");// 设置MQTT凭证,MQTT服务器的账号密码mqttClient.setUsernamePassword("pi", "raspberry");Serial.println("Attempting to connect to MQTT broker...");Serial.print("Broker: ");Serial.print(broker);Serial.print(":");Serial.println(port);while (!mqttClient.connect(broker, port)) {Serial.print("MQTT connection failed! Error code = ");Serial.println(mqttClient.connectError());delay(5000);}Serial.println("Connected to MQTT broker!");Serial.println("Setup complete. Starting main loop...");
}void loop() {// 必须定期调用poll()来保持连接活跃mqttClient.poll();unsigned long currentMillis = millis();if (currentMillis - previousMillis >= interval) {previousMillis = currentMillis;String message = "hello " + String(count);Serial.print("Preparing to send message: ");Serial.println(message);// 发送MQTT消息mqttClient.beginMessage(topic);mqttClient.print(message);mqttClient.endMessage();Serial.print("Message sent at ");Serial.print(currentMillis);Serial.print(" ms. Count: ");Serial.println(count);count++;}// 添加一个小延迟以避免过于频繁的循环delay(10);
}
五、运行Pi和Ar程序
Pi是服务器和接收端,运行Pi程序(Pi_Receiver.py)。
python Pi_Receiver.py
Ar是客户端和发送端,运行Ar程序(Ar_Sender.ino)。