1. 简介
#开发板漂流计划#小车控制由简入繁之按键控制
#开发板漂流计划#小车控制由简入繁之UDP控制
本文在前面两篇帖子的基础上,在Openharmony3.0上实现小车上电后自动连接到指定WIFI,并与指定的MQTT Broker建立链接、订阅小车控制“carControl”主题。电脑Windows系统下使用paho软件连接到相同的MQTT Broker,通过发送主题为“carControl”的消息来控制小车状态。
阅读本文前,推荐阅读连志安老师的以下文章:
MQTT 协议开发入门 - MQTT 简述、设计规范、主要特性、协议原理、协议数据包结构
如何在鸿蒙系统中移植 Paho-MQTT 实现MQTT协议- 基于openharmony1.0移植Paho-MQTT教程
在鸿蒙系统上使用MQTT编程-对应连老师Gitee仓库 harmony_mqtt的使用介绍,本文基于这个版本实现MQTT控制小车
本文主要分享MQTT Broker的搭建、在Openharmony3.0上如何使用harmony_mqtt、并实现MQTT控制小车的Demo。
安装前请确保你的Ubuntu能正常上网并且局网内可以访问到。
安装指令如下:
sudo apt-get install mosquitto sudo apt-get install mosquitto-clients sudo apt-get install mosquitto-dev1.2.3.1.2.3.1.2.3.1.2.3.1.2.3.
service mosquitto status1.1.1.1.1.
正常状态显示如下
这样子测试用的Broker就搭建好了,Broker的IP地址就是你Ubuntu局域网中的IP,端口默认1883,如果搭建有问题欢迎留言交流。
3.在Openharmony3.0上如何使用harmony_mqtt
3.1 让harmony_mqtt成功编译
3.1.1 将harmony_mqtt 下载到Openharmony3.0源码third_party目录下并重命名为pahomqtt
可以用git clone 下载后重命名也可以下载压缩包后解压。如下图Z:\ohos300_iot\是我Openharmony3.0源码的根目录
修改device\hisilicon\hispark_pegasus\sdk_liteos\BUILD.gn在lite_component(“sdk”)中添加"//third_party/pahomqtt:pahomqtt_static"
(注意:此处修改的BUILD.gn 和Openharmony1.0 版本有区别,1.0 路径是vendor\hisi\hi3861\hi3861\BUILD.gn)
lite_component("sdk") {
features = []
deps = [
"//build/lite/config/component/cJSON:cjson_static",
"//device/hisilicon/hispark_pegasus/hi3861_adapter/kal",
"//third_party/pahomqtt:pahomqtt_static",
]
}1.2.3.4.5.6.7.8.9.1.2.3.4.5.6.7.8.9.1.2.3.4.5.6.7.8.9.1.2.3.4.5.6.7.8.9.1.2.3.4.5.6.7.8.9.修改完成后重新执行编译后从编译日志中可以用mqtt看下log,修改成功会有以下信息。
但是编译到最后会有错误提示如下,接下来就是修这个编译错误了。
错误日志截取如下
[OHOS ERROR] riscv32-unknown-elf-ld: ohos/libs/libpahomqtt_static.a(libpahomqtt_static.MQTTLiteOS.o): in function `MutexInit': [OHOS ERROR] MQTTLiteOS.c:(.text.MutexInit+0x0): multiple definition of `MutexInit'; ohos/libs/libdiscovery.a(libdiscovery.os_adapter.o):os_adapter.c:(.text.MutexInit+0x0): first defined here [OHOS ERROR] riscv32-unknown-elf-ld: ohos/libs/libpahomqtt_static.a(libpahomqtt_static.MQTTLiteOS.o): in function `MutexLock': [OHOS ERROR] MQTTLiteOS.c:(.text.MutexLock+0x0): multiple definition of `MutexLock'; ohos/libs/libdiscovery.a(libdiscovery.os_adapter.o):os_adapter.c:(.text.MutexLock+0x0): first defined here [OHOS ERROR] riscv32-unknown-elf-ld: ohos/libs/libpahomqtt_static.a(libpahomqtt_static.MQTTLiteOS.o): in function `MutexUnlock': [OHOS ERROR] MQTTLiteOS.c:(.text.MutexUnlock+0x0): multiple definition of `MutexUnlock'; ohos/libs/libdiscovery.a(libdiscovery.os_adapter.o):os_adapter.c:(.text.MutexUnlock+0x0): first defined here [OHOS ERROR] scons: *** [output/bin/Hi3861_wifiiot_app.out] Error 1 [OHOS ERROR] BUILD FAILED!!!! [OHOS ERROR] Failed building output/bin/Hi3861_wifiiot_app.out: Error 1 [OHOS ERROR] you can check build log in /home/soon/ohos300_iot/out/hispark_pegasus/wifiiot_hispark_pegasus/build.log [OHOS ERROR] command: "/home/soon/ohostool_101/ninja/ninja -w dupbuild=warn -C /home/soon/ohos300_iot/out/hispark_pegasus/wifiiot_hispark_pegasus" failed [OHOS ERROR] return code: 1 [OHOS ERROR] execution path: /home/soon/ohos300_iot soon@soon-u20:~/ohos300_iot $ 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.1.2.3.4.5.6.7.8.9.10.11.12.13.14.1.2.3.4.5.6.7.8.9.10.11.12.13.14.1.2.3.4.5.6.7.8.9.10.11.12.13.14.1.2.3.4.5.6.7.8.9.10.11.12.13.14.
我的修改方式是将
third_party\pahomqtt\MQTTClient-C\src\MQTTClient.c
third_party\pahomqtt\MQTTClient-C\src\liteOS\MQTTLiteOS.c
third_party\pahomqtt\MQTTClient-C\src\liteOS\MQTTLiteOS.h
这三个档案中的所有的
MutexInit(Mutex*);MutexLock(Mutex*);MutexUnlock(Mutex*);1.2.3.1.2.3.1.2.3.1.2.3.1.2.3.
对应替换为
MqttMutexInit(Mutex*);MqttMutexLock(Mutex*);MqttMutexUnlock(Mutex*);1.2.3.1.2.3.1.2.3.1.2.3.1.2.3.
这样子就能正常编译通过了
third_party\pahomqtt\BUILD.gn中以下三个有没有并不会影响编译/使用,所以我把他拿掉了。
"MQTTClient-C\src\liteOS", "//vendor/hisi/hi3861/hi3861/third_party/lwip_sack/include", "//kernel/liteos_m/components/cmsis/2.0",1.2.3.1.2.3.1.2.3.1.2.3.1.2.3.
修改后的代码可以直接从附件下载或者从码云 https://gitee.com/soonliao/pahomqtt 下载。
在应用的BUILD.gn添加以下三行内容才能调用到pahomqtt的相关函数
static_library("car_mqtt") {
sources = [
......
]
include_dirs = [
......
"//third_party/pahomqtt:pahomqtt_static",
"//third_party/pahomqtt/MQTTPacket/src",
"//third_party/pahomqtt/MQTTClient-C/src",
]}1.2.3.4.5.6.7.8.9.10.11.12.1.2.3.4.5.6.7.8.9.10.11.12.1.2.3.4.5.6.7.8.9.10.11.12.1.2.3.4.5.6.7.8.9.10.11.12.1.2.3.4.5.6.7.8.9.10.11.12.主要在以下函数实现,详细的说明可以参考在鸿蒙系统上使用MQTT编程
#include "MQTTClient.h"#define MQTT_BROKER "192.168.123.230"//改成你的MQTT Broker 地址#define MQTT_PORT 1883MQTTMessage ackmsg;int needAck = 0;struct opts_struct{
char* clientid;
int nodelimiter;
char* delimiter;
enum QoS qos;
char* username;
char* password;
char* host;
int port;
int showtopics;} opts ={
(char*)"stdout-subscriber", 0, (char*)"\n", QOS2, NULL, NULL, (char*)MQTT_BROKER, MQTT_PORT, 1};unsigned char buf[100];unsigned char readbuf[100];int car_mqtt(void){
int rc = 0;
MQTTMessage pubmsg;
//小车控制主题carControl
char* topic = "carControl";
if (strchr(topic, '#') || strchr(topic, '+'))
opts.showtopics = 1;
if (opts.showtopics)
printf("topic is %s\n", topic);
Network n;
MQTTClient c;
//网络初始化
NetworkInit(&n);
NetworkConnect(&n, opts.host, opts.port);
//设置MQTT缓存和启动MQTT线程
MQTTClientInit(&c, &n, 1000, buf, 100, readbuf, 100);
MQTTStartTask(&c);
//设置MQTT相关参数
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
data.willFlag = 0;
data.MQTTVersion = 3;
data.clientID.cstring = opts.clientid;
data.username.cstring = opts.username;
data.password.cstring = opts.password;
data.keepAliveInterval = 10;
data.cleansession = 1;
printf("Connecting to %s %d\n", opts.host, opts.port);
//连接到MQTT服务器
rc = MQTTConnect(&c, &data);
printf("Connected %d\n", rc);
//订阅主题和接收消息
printf("Subscribing to %s\n", topic);
rc = MQTTSubscribe(&c, topic, opts.qos, messageArrived);
printf("Subscribed %d\n", rc);
//状态变化后发布主题carStatus,消息内容ackmsg.payload
memset(&ackmsg, '\0', sizeof(ackmsg));
ackmsg.payload = (void*)"ACK";
ackmsg.payloadlen = strlen((char*)ackmsg.payload);
ackmsg.qos = QOS0;
ackmsg.retained = 0;
ackmsg.dup = 0;
while (1)
{
if(needAck == 1)//收到消息后,发送主题carStatus并携带状态消息
{
needAck = 0;
printf("Publish carStatus ackmsg %d %s \n", (int)ackmsg.payloadlen, (char*)ackmsg.payload);
MQTTPublish(&c, "carStatus", &ackmsg);
}
sleep(1);
}
printf("Stopping\n");
MQTTDisconnect(&c);
NetworkDisconnect(&n);
return 0;}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.通过MQTTSubscribe(&c, topic, opts.qos, messageArrived);注册messageArrived回调实现,代码如下
void messageArrived(MessageData* md){
MQTTMessage* message = md->message;
memset(&ackmsg, '\0', sizeof(ackmsg));
ackmsg.qos = QOS0;
ackmsg.retained = 0;
ackmsg.dup = 0;
if (opts.showtopics)
printf("%.*s\t", md->topicName->lenstring.len, md->topicName->lenstring.data);
if (opts.nodelimiter)
printf("%.*s\n", (int)message->payloadlen, (char*)message->payload);
else
printf("%.*s%s\n", (int)message->payloadlen, (char*)message->payload, opts.delimiter);
if(strncmp("forward", message->payload, 7)== 0) {
needAck = 1;
car_go_forward();
ackmsg.payload = (void*)"forward";
}
if(strncmp("back", message->payload, 4) == 0) {
needAck = 1;
car_go_back();
ackmsg.payload = (void*)"back";
}
if(strncmp("left", message->payload, 4) == 0) {
needAck = 1;
car_turn_left();
ackmsg.payload = (void*)"left";
}
if(strncmp("right", message->payload, 5) == 0) {
needAck = 1;
car_turn_right();
ackmsg.payload = (void*)"right";
}
if(strncmp("stop", message->payload, 4) == 0) {
needAck = 1;
car_stop();
ackmsg.payload = (void*)"stop";
}
if(needAck == 1) {
ackmsg.payloadlen = strlen((char*)ackmsg.payload);
}}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.完整的代码请见附件或者Gitee https://gitee.com/soonliao/car_mqtt,使用方式如下

import("//build/lite/config/component/lite_component.gni")lite_component("app") {
features = [
"car_mqtt",
]}1.2.3.4.5.6.7.1.2.3.4.5.6.7.1.2.3.4.5.6.7.1.2.3.4.5.6.7.1.2.3.4.5.6.7.修改applications\sample\wifi-iot\app\car_mqtt\src\car_main.c
#define WIFI_SSID "SSIDABCD"//WIFI账号#define WIFI_PW "MIMA1234"//WIFI密码#define MQTT_BROKER "192.168.123.230"//改成你的MQTT Broker 地址#define MQTT_PORT 1883//改成你的MQTT Broker 端口,默认18831.2.3.4.1.2.3.4.1.2.3.4.1.2.3.4.1.2.3.4.
电机驱动会用到PWM 模块所以要开启
device/hisilicon/hispark_pegasus/sdk_liteos/build/config/usr_config.mk
CONFIG_PWM_SUPPORT is not set1.1.1.1.1.
改为
CONFIG_PWM_SUPPORT=y1.1.1.1.1.
加上第3部分中的pahomqtt相关修改,整个Demo就可以编译通了。
成功连接WIFI,且连上MQTT Broker订阅主题的log如下
测试软件在附件,或者参考连老师的说明下载,控制指令支持前进“forward”、后退“back”、右转“right”、左转“left”、停止“stop”,在小车成功执行指令后会返回一条carStatus的主题并携带状态消息。
接收到指令后串口会有以下打印
以上是本人分享的“小车控制由简入繁之MQTT控制”如有不足欢迎留言指教,如有疑问也欢迎留言。
文中相关设备来源于51CTO 鸿蒙技术社区【开发板漂流计划】



