社区编辑申请
注册/登录
小车控制由简入繁之MQTT控制
开发 前端
本文主要分享MQTT Broker的搭建、在Openharmony3.0上如何使用harmony_mqtt、并实现MQTT控制小车的Demo。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

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。

2. 在Ubuntu20.04虚拟机安装mosquitto搭建Broker

安装前请确保你的Ubuntu能正常上网并且局网内可以访问到。

2.1 Ubuntu下mosquitto 安装

安装指令如下:

  1. sudo apt-get install mosquitto 
  2. sudo apt-get install mosquitto-clients 
  3. sudo apt-get install mosquitto-dev 

2.2 安装完成后可以用以下指令查看状态

  1. service mosquitto status 

 正常状态显示如下

#开发板漂流计划#小车控制由简入繁之MQTT控制-鸿蒙HarmonyOS技术社区

这样子测试用的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源码的根目录

#开发板漂流计划#小车控制由简入繁之MQTT控制-鸿蒙HarmonyOS技术社区

3.1.2 将pahomqtt添加到hispark_pegasus编译

修改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)

  1. lite_component("sdk") { 
  2.   features = [] 
  3.  
  4.   deps = [ 
  5.     "//build/lite/config/component/cJSON:cjson_static"
  6.     "//device/hisilicon/hispark_pegasus/hi3861_adapter/kal"
  7.     "//third_party/pahomqtt:pahomqtt_static"
  8.   ] 

修改完成后重新执行编译后从编译日志中可以用mqtt看下log,修改成功会有以下信息。

#开发板漂流计划#小车控制由简入繁之MQTT控制-鸿蒙HarmonyOS技术社区

但是编译到最后会有错误提示如下,接下来就是修这个编译错误了。

#开发板漂流计划#小车控制由简入繁之MQTT控制-鸿蒙HarmonyOS技术社区

3.1.3 修改编译错误

错误日志截取如下

  1. [OHOS ERROR] riscv32-unknown-elf-ld: ohos/libs/libpahomqtt_static.a(libpahomqtt_static.MQTTLiteOS.o): in function `MutexInit': 
  2. [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 
  3. [OHOS ERROR] riscv32-unknown-elf-ld: ohos/libs/libpahomqtt_static.a(libpahomqtt_static.MQTTLiteOS.o): in function `MutexLock': 
  4. [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 
  5. [OHOS ERROR] riscv32-unknown-elf-ld: ohos/libs/libpahomqtt_static.a(libpahomqtt_static.MQTTLiteOS.o): in function `MutexUnlock': 
  6. [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 
  7. [OHOS ERROR] scons: *** [output/bin/Hi3861_wifiiot_app.out] Error 1 
  8. [OHOS ERROR] BUILD FAILED!!!! 
  9. [OHOS ERROR] Failed building output/bin/Hi3861_wifiiot_app.out: Error 1 
  10. [OHOS ERROR] you can check build log in /home/soon/ohos300_iot/out/hispark_pegasus/wifiiot_hispark_pegasus/build.log 
  11. [OHOS ERROR] command: "/home/soon/ohostool_101/ninja/ninja -w dupbuild=warn -C /home/soon/ohos300_iot/out/hispark_pegasus/wifiiot_hispark_pegasus" failed 
  12. [OHOS ERROR] return code: 1 
  13. [OHOS ERROR] execution path: /home/soon/ohos300_iot 
  14. soon@soon-u20:~/ohos300_iot $  

 我的修改方式是将

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

这三个档案中的所有的

  1. MutexInit(Mutex*); 
  2. MutexLock(Mutex*); 
  3. MutexUnlock(Mutex*); 

 对应替换为

  1. MqttMutexInit(Mutex*); 
  2. MqttMutexLock(Mutex*); 
  3. MqttMutexUnlock(Mutex*); 

 这样子就能正常编译通过了

3.1.4 其他修改和修改后的代码

third_party\pahomqtt\BUILD.gn中以下三个有没有并不会影响编译/使用,所以我把他拿掉了。

  1. "MQTTClient-C\src\liteOS"
  2.       "//vendor/hisi/hi3861/hi3861/third_party/lwip_sack/include"
  3.       "//kernel/liteos_m/components/cmsis/2.0"

修改后的代码可以直接从附件下载或者从码云 https://gitee.com/soonliao/pahomqtt 下载。

3.2 MQTT控制小车代码的实现

3.2.1 applications\sample\wifi-iot\app\car_mqtt\BUILD.gn 的修改

在应用的BUILD.gn添加以下三行内容才能调用到pahomqtt的相关函数

  1. static_library("car_mqtt") { 
  2.     sources = [ 
  3.         ...... 
  4.     ] 
  5.  
  6.     include_dirs = [ 
  7.         ......     
  8.         "//third_party/pahomqtt:pahomqtt_static"
  9.         "//third_party/pahomqtt/MQTTPacket/src"
  10.         "//third_party/pahomqtt/MQTTClient-C/src"
  11.     ] 

 3.2.2 MQTT 初始化主题订阅

主要在以下函数实现,详细的说明可以参考在鸿蒙系统上使用MQTT编程

  1. #include "MQTTClient.h" 
  2.  
  3.  
  4. #define MQTT_BROKER                "192.168.123.230"//改成你的MQTT Broker 地址 
  5. #define MQTT_PORT                  1883 
  6.  
  7. MQTTMessage ackmsg; 
  8. int needAck = 0; 
  9.  
  10. struct opts_struct 
  11.     char* clientid; 
  12.     int nodelimiter; 
  13.     char* delimiter; 
  14.     enum QoS qos; 
  15.     char* username; 
  16.     charpassword
  17.     char* host; 
  18.     int port; 
  19.     int showtopics; 
  20. }  
  21. opts = 
  22.     (char*)"stdout-subscriber", 0, (char*)"\n", QOS2, NULLNULL, (char*)MQTT_BROKER, MQTT_PORT, 1 
  23. }; 
  24.  
  25. unsigned char buf[100]; 
  26. unsigned char readbuf[100]; 
  27.  
  28. int car_mqtt(void) 
  29.     int rc = 0; 
  30.      
  31.     MQTTMessage pubmsg; 
  32.     //小车控制主题carControl 
  33.     char* topic = "carControl"
  34.  
  35.     if (strchr(topic, '#') || strchr(topic, '+')) 
  36.         opts.showtopics = 1; 
  37.     if (opts.showtopics) 
  38.         printf("topic is %s\n", topic); 
  39.  
  40.     Network n; 
  41.     MQTTClient c; 
  42.     //网络初始化 
  43.     NetworkInit(&n); 
  44.     NetworkConnect(&n, opts.host, opts.port); 
  45.     //设置MQTT缓存和启动MQTT线程 
  46.     MQTTClientInit(&c, &n, 1000, buf, 100, readbuf, 100); 
  47.     MQTTStartTask(&c); 
  48.     //设置MQTT相关参数 
  49.     MQTTPacket_connectData data = MQTTPacket_connectData_initializer;        
  50.     data.willFlag = 0; 
  51.     data.MQTTVersion = 3; 
  52.     data.clientID.cstring = opts.clientid; 
  53.     data.username.cstring = opts.username; 
  54.     data.password.cstring = opts.password
  55.  
  56.     data.keepAliveInterval = 10; 
  57.     data.cleansession = 1; 
  58.     printf("Connecting to %s %d\n", opts.host, opts.port); 
  59.     //连接到MQTT服务器 
  60.     rc = MQTTConnect(&c, &data); 
  61.     printf("Connected %d\n", rc); 
  62.     //订阅主题和接收消息 
  63.     printf("Subscribing to %s\n", topic); 
  64.     rc = MQTTSubscribe(&c, topic, opts.qos, messageArrived); 
  65.     printf("Subscribed %d\n", rc); 
  66.     //状态变化后发布主题carStatus,消息内容ackmsg.payload 
  67.     memset(&ackmsg, '\0', sizeof(ackmsg)); 
  68.     ackmsg.payload = (void*)"ACK"
  69.     ackmsg.payloadlen = strlen((char*)ackmsg.payload); 
  70.     ackmsg.qos = QOS0; 
  71.     ackmsg.retained = 0; 
  72.     ackmsg.dup = 0;  
  73.  
  74.     while (1) 
  75.     { 
  76.         if(needAck == 1)//收到消息后,发送主题carStatus并携带状态消息 
  77.         { 
  78.             needAck = 0; 
  79.             printf("Publish carStatus ackmsg %d %s \n", (int)ackmsg.payloadlen, (char*)ackmsg.payload);  
  80.             MQTTPublish(&c, "carStatus", &ackmsg); 
  81.         } 
  82.         sleep(1);    
  83.     } 
  84.      
  85.     printf("Stopping\n"); 
  86.  
  87.     MQTTDisconnect(&c); 
  88.     NetworkDisconnect(&n); 
  89.  
  90.     return 0; 

3.2.1 小车控制代码

通过MQTTSubscribe(&c, topic, opts.qos, messageArrived);注册messageArrived回调实现,代码如下

  1. void messageArrived(MessageData* md) 
  2.  
  3.     MQTTMessage* message = md->message; 
  4.  
  5.     memset(&ackmsg, '\0', sizeof(ackmsg)); 
  6.     ackmsg.qos = QOS0; 
  7.     ackmsg.retained = 0; 
  8.     ackmsg.dup = 0; 
  9.  
  10.     if (opts.showtopics) 
  11.         printf("%.*s\t", md->topicName->lenstring.len, md->topicName->lenstring.data); 
  12.     if (opts.nodelimiter) 
  13.         printf("%.*s\n", (int)message->payloadlen, (char*)message->payload); 
  14.     else 
  15.         printf("%.*s%s\n", (int)message->payloadlen, (char*)message->payload, opts.delimiter); 
  16.  
  17.     if(strncmp("forward", message->payload, 7)== 0) { 
  18.         needAck = 1; 
  19.         car_go_forward(); 
  20.         ackmsg.payload = (void*)"forward"
  21.     } 
  22.     if(strncmp("back", message->payload, 4) == 0) { 
  23.         needAck = 1; 
  24.         car_go_back(); 
  25.         ackmsg.payload = (void*)"back"
  26.     } 
  27.     if(strncmp("left", message->payload, 4) == 0) { 
  28.         needAck = 1; 
  29.         car_turn_left(); 
  30.         ackmsg.payload = (void*)"left"
  31.     } 
  32.     if(strncmp("right", message->payload, 5) == 0) { 
  33.         needAck = 1; 
  34.         car_turn_right(); 
  35.         ackmsg.payload = (void*)"right"
  36.     } 
  37.     if(strncmp("stop", message->payload, 4) == 0) { 
  38.         needAck = 1; 
  39.         car_stop(); 
  40.         ackmsg.payload = (void*)"stop"
  41.     } 
  42.     if(needAck == 1) { 
  43.         ackmsg.payloadlen = strlen((char*)ackmsg.payload); 
  44.     } 

4.编译及测试

4.1 小车控制代码的编译

完整的代码请见附件或者Gitee https://gitee.com/soonliao/car_mqtt,使用方式如下

4.1.1 将car_mqtt解压或者git clone 到applications\sample\wifi-iot\app\路径下

#开发板漂流计划#小车控制由简入繁之MQTT控制-鸿蒙HarmonyOS技术社区

4.1.2 修改applications\sample\wifi-iot\app\BUILD.gn

  1. import("//build/lite/config/component/lite_component.gni"
  2.  
  3. lite_component("app") { 
  4.     features = [ 
  5.         "car_mqtt"
  6.     ] 

4.1.3 修改WIFI SSID、密码及MQTT Broker IP

修改applications\sample\wifi-iot\app\car_mqtt\src\car_main.c

  1. #define WIFI_SSID                  "SSIDABCD"//WIFI账号 
  2. #define WIFI_PW                    "MIMA1234"//WIFI密码 
  3. #define MQTT_BROKER                "192.168.123.230"//改成你的MQTT Broker 地址 
  4. #define MQTT_PORT                  1883//改成你的MQTT Broker 端口,默认1883 

4.1.4 开启PWM 功能,开启方式如下

电机驱动会用到PWM 模块所以要开启

device/hisilicon/hispark_pegasus/sdk_liteos/build/config/usr_config.mk

  1. CONFIG_PWM_SUPPORT is not set 

改为

  1. CONFIG_PWM_SUPPORT=y 

加上第3部分中的pahomqtt相关修改,整个Demo就可以编译通了。

4.2 小车控制代码的测试

4.2.1 从串口log查看

成功连接WIFI,且连上MQTT Broker订阅主题的log如下

#开发板漂流计划#小车控制由简入繁之MQTT控制-鸿蒙HarmonyOS技术社区

4.2.2 电脑Windows系统下paho软件发送测试指令

测试软件在附件,或者参考连老师的说明下载,控制指令支持前进“forward”、后退“back”、右转“right”、左转“left”、停止“stop”,在小车成功执行指令后会返回一条carStatus的主题并携带状态消息。

#开发板漂流计划#小车控制由简入繁之MQTT控制-鸿蒙HarmonyOS技术社区

接收到指令后串口会有以下打印

#开发板漂流计划#小车控制由简入繁之MQTT控制-鸿蒙HarmonyOS技术社区

文章相关附件可以点击下面的原文链接前往下载

https://harmonyos.51cto.com/resource/1319

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

责任编辑:jianghua 来源: 鸿蒙社区

同话题下的热门内容

字节的前端监控 SDK 是怎样设计的TestOps完全手册:工作流、生命周期、团队和流程使用Python快速搭建接口自动化测试脚本实战总结你需要知道的TypeScript高级类型不要在 Python 中使用循环,这些方法其实更棒!哪种编程语言最适合开发网页抓取工具?从 Islands Architecture 看前端有多卷反应式JavaScript:前端架构的演变

编辑推荐

太厉害了,终于有人能把TCP/IP协议讲的明明白白了!牛人5次面试腾讯不成功的经验HBase原理–所有Region切分的细节都在这里了Javascript如何监听页面刷新和关闭事件如何搭建一个HTTPS服务端
我收藏的内容
点赞
收藏

51CTO技术栈公众号