# OpenHarmonyProject **Repository Path**: ckunkun/open-harmony-project ## Basic Information - **Project Name**: OpenHarmonyProject - **Description**: 这是个人基于OpenHarmony开发的项目合集 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 8 - **Forks**: 4 - **Created**: 2022-05-04 - **Last Updated**: 2025-05-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # OpenHarmonyProject #### 智慧终端机器人MRobot ![输入图片说明](smile.png) [MRobot演示-记得三连](https://www.bilibili.com/video/BV1o34y1E7Gu?share_source=copy_web) ####文件架构说明 1. MRobotAPP目录 :MRobot移动端APP源码 基于ArkUI框架编写,类WEB开发,包括控制UI实现全JS编写; APP为原子化服务,整体大小不超过10M,默认开启了服务卡片; (源码默认安装桌面icon) 碰一碰弹出界面除NAN配网外还提供web端控制选项,通过web直接控制其他硬件设备,不需要连接MRobot; 2. MRobotDesign ---model: 模型文件,stl格式为零件,step格式为装配体 ---electric: 电气原理图 3. MRobotWifi_iot MRobot控制源码; 基于OpenHarmony1.0.1编写 工程包含了oled、mpu6050、蓝牙串口、sut03语言识别模块驱动样例; 4. MRobotUnionDevice :互联设备控制源码 互联设备有:风扇、门锁、台灯、植物浇水机 每台设备可受MRobot控制,使用普通蓝牙连接设备,每次只能连接一台,MRobot已设置为主机模式,其他设备开机会自动连接; 每台设备还提供了mqtt接口,订阅云端主题,(对应配网页面--云端选项),可通过云端实现秒控 ![输入图片说明](light_circle.png) ![输入图片说明](heibot_inner.png) ![输入图片说明](mrobot.png) 以下为开发指导: ## (首发)我用鸿蒙开发一台机器人【萌萌的那种】 @[toc](目录) ## 0. 说明 大家好我是Hello Kun,正式接触鸿蒙也快9个月了,一直想做一个有意思的极客项目:既能用到鸿蒙特性【ArkUI、原子化服务、碰一碰等】、涉及南北向开发,又能融入实际生活。断断续续,从南到北,粗略过了一遍,终于,近期实现了这一想法。今天,向大家展示个人极客项目--**智慧终端机器人MRobot**,如下图: ![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/e74b80804311c4bca094922dcdf0272f9655f3.png?x-oss-process=image/resize,w_818,h_795) ![碰一碰2.gif](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/f7d78712786e1917e5311064728e3129464854.gif)![11.gif](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/27d37b1848bfd2729556731ee261c6f9694834.gif)![22.gif](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/f6e8fa846b4e2baa7b367985ab58d004aec4cf.gif) ![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/7985051326716847d4a14061a99bb0295f7e0e.png?x-oss-process=image/resize,w_820,h_785) ## 1. 方案设计 ### 1.1 功能需求分析 ::: hljs-center **MRobot = 快捷启动 + 自由移动 + APP交互 + 多设备互联 + 云端控制 + 其他拓展(语音、趣味功能)** ![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/71fdc1e23c9d0b6b66f84872bc36ba9f825dbd.png?x-oss-process=image/resize,w_820,h_528) ::: - 快捷启动:碰一碰拉起配网页面 | 在“我的服务”中使用卡片启动APP | 桌面卡片 ; - 自由移动:具备转向、前进、后退等基本运动能力; - APP交互: 控制机器人移动; - 多设备互联:通过机器人控制其他设备,如门锁、台灯、风扇、浇水机等; - 云端控制:基于mqtt协议控制互联设备,无需与机器人配网即可控制,一是解决机器人不在身边的情形(如归家开门),二是提供web端供其他人使用(如舍友手机不是HarmonyOS系统); - 其他拓展:离线语音交互,对机器人喊话就能控制一切; 可控磁吸配件(给小朋友准备的。),如发光环、交通灯、迷你风扇 ### 1.2 结构设计与硬件选型 参考猫、飞船返回舱等元素,花一天设计出了MRobot,萌不萌仁者见仁啦。硬件选型方面,机器人控制核心毫无疑问hi3861模组;N20小功率电机以及驱动;语音模块使用SU03T;一块800mAh锂电池以及TypeC充放管理模块;蓝牙用于与互联设备通信;几块磁铁预备做配件;左耳有触摸传感,提供oled显示模块或MPU6050选择(不同时使用)。 ![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/674476799096bc0f3dd88549dfdd94b68a8a6a.png?x-oss-process=image/resize,w_820,h_719) ### 1.3 控制数据流 - APP:北向APP - Web: 云端iot服务 - MRobot:智慧终端机器人 小萌 - Union Devices:互联设备,门锁台灯等 - Speaker:语音模块 - Human: 万恶之源 ![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/c187ab74936b8628b913915f8999bed0d6d3f6.png?x-oss-process=image/resize,w_700,h_314) ## 2. 北向App开发 APP基于ArkUI的类web开发范式,大部分使用JS开发。APP将完成各功能页面展示、消息下发功能。整个工程主要参考[HarmonyOS Connect设备开发](https://device.harmonyos.com/cn/docs/documentation/guide/onehop-overview-0000001205391463)实现,去除掉模板JAVA实现板块,使用JS接口替代。 ### 2.1 新建原子化服务APP 使用OneHop模板新建原子化服务工程,命名MRobot。可参考分享贴[碰一碰分享总贴](https://ost.51cto.com/posts/12658) ![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/22fb085173b159e29762135aa81a9a71e5d1a2.png?x-oss-process=image/resize,w_820,h_1507) 删除不需要的control模块(基于JAVA),新建一个jscontrol page,这是将是控制主页。参考[1.抛除束缚,自定义设备](https://ost.51cto.com/posts/12758)![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/07ec2cc084d9da56247849da8edd90e42ef6ff.png?x-oss-process=image/resize,w_464,h_617)![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/01fc9ea849d2a9c6b23900185c53b72411e0f8.png?x-oss-process=image/resize,w_820,h_594) ### 2.2 UI设计 根据需求分析设计UI,因为第一次写APP,渲染样式没有概念,所以在图片上做文章,对设计的MRobot模型进行渲染后导出图片置于APP中,所有的UI主要用到button、switch、swiper组件,先基于可视化低代码开发,后转为hml(jsctronl page是)。ui总览如下; ![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/083f60b23fc395fe2ec642c312717d51edb754.png?x-oss-process=image/resize,w_820,h_697) - 碰一碰拉起,进入配网页面,提供两个选项,一是正常配网,二是直接进入云端web页面秒控设备。 - 首页作为主控页面(jscontrol page),从上往下依次是:MRobot机器人运动控制、秒控设备(发送消息给机器人,实现互联设备控制)、表情聊天(点击表情发送消息给机器人,机器人做出运动、语音反应); - 点击更多,将会打开一些隐藏页面,如随机计算、认识宇宙等,主要是面对小朋友,未来增加通关解锁相应技能。 下面总结常用的一些UI能力,方便调试与开发: ```js //弹窗 import prompt from '@system.prompt'; { prompt.showToast({ message: "Hello Kun", duration: 1000, }); //页面路由 push back replace import router from '@system.router'; router.push({ uri: 'pages/netconfig/netconfig' }); // switch 状态检测 switchChange(e){ console.log(e.checked); if( e.checked){ prompt.showToast({ message: "连接" }); } else{ this.talk_msg = "reset MRobot"; prompt.showToast({ message: "断开" }); }; } ``` ### 2.3 NAN-JS通信 在新建的jsctronl 中需要调用JS通信接口在建立的NAN通道中发送数据,详细参考:[2.拥抱JS通信接口](https://ost.51cto.com/posts/12772),因为是调用JS接口,获取NAN通道deviceInfo十分容易。 例如,**发送机器人前进核心代码如下:** ```js import {getApp} from '../../common.js'; //运动控制 Forward(){ this.front_img='/common/images/up0.png'; this.work_status ="萌萌退下"; this.talk_msg = "F"; this.sendMessage(); }, //发送消息 sendMessage(){ var ret =1; var message = this.talk_msg; let commonInfo = { sessionId: getApp(this).ConfigParams.deviceInfo.sessionId }; getApp(this).NetConfig.sendMessage(commonInfo, message, (result)=>{ if(result.code==0) { prompt.showToast({ message: "发送成功", duration: 1000, }); ret =0;} else { prompt.showToast({ message: "发送失败", duration: 1000, }); ret= -1;}; }); if(ret==0) { return 0; } else return -1; }, ``` 在南向开发中对消息进行匹配即可进行相应动作。 ### 2.4 真机测试 APP真机调试算基本技能了,为什么我要单独拿出来呢,因为我入门北向时,遇到一个坑。装双系统的深有体会,Windows时间会慢,于是我给直接调到了UTC+14:00 圣诞岛,现在我已经在过520了(doge); **那么问题来了:AGC平台签名会校验时间,时间不对签名会失败,所以一直用另一台电脑做应用开发,折腾好久才发现自己笔记本时间不对导致签名失败。。。** 事实证明,有些问题,坚持下去总会解决的。 ::: hljs-center ![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/89498a4708a4515f66d1689c33687b964524d9.png?x-oss-process=image/resize,w_440,h_669) ::: ## 3. 南向开发 **南向完成MRobot开发、互联设备开发。基于OpenHarmony 1.0.1 LTS对 hi3861 进行资源分配、各模块调试、整机调试、功能验证。** 南向难免要面向硬件,MRobot与互联设备电气原理图如下: ![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/094ec8c0741053cd2078804f7e265775cacf8f.png?x-oss-process=image/resize,w_739,h_696)![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/b79a21e31e524cccf1d668fd16dc2ae51b5b69.png?x-oss-process=image/resize,w_820,h_1862)![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/167a88414c4f9a9fea62845b7687690bf0953f.png?x-oss-process=image/resize,w_820,h_1963) ### 3.1 获取OpenHarmony源码 以下是我获取源码的操作以及过程遇到的问题以及解决方法。 ``` /***************** openharmony 1.0.1源码 ******************/ repo下载【安装git、repo】,#特别注意:请下载OpenHarmony 1.0.1 版本,后续会更新支持OpenHarmony其他版本 mkdir ~/OpenHarmony1.01 cd ~/OpenHarmony1.01 repo init -u git@gitee.com:openharmony/manifest.git -b OpenHarmony_1.0.1_release --no-repo-verify repo sync -c repo forall -c 'git lfs pull' 来自 或者https://repo.huaweicloud.com/harmonyos/os/ 下载解压 /********** 编译1.0.1源码时,遇到问题以及解决方法: ******************* / -使用hb 、python build.py 指令编译 (1) hb -h执行之后遇到 please run in source root,因为1.0.1的ohos-build是0.2.1 , 与3.0的不通用, 【解决方法】卸载掉 pip uninstall ohos-build 再在1.0源码根目录安装hb 执行 pip install build/lite (2)在源码处可以hb set,但hb build -f编译时遇到 clang not install 【解决方法】 ~/.bashrc中添加python环境变量即可 -使用DevEcoTools编译 (1)找不到gn、ninja 【解决方法】所有解压的工具链,如gcc、ninja、gn等,需要在 ~/.bashrc中添加环境变量,示例 export ----- (2)找不到clang 【解决方法】 ~/.bashrc中添加python、gcc、ninja、gn等环境变量即可 ``` 顺便提一下,我并没有使用ubuntu环境进行设备开发,因为我发现 DevEco Tools Beta3.1 可以直接编译1.0.1源码。大家可以尝试下windows一站式开发。源码需要修改,配置build选项开启I2C、UART等(MRobot使用了两个串口)。具体操作可参考:[0.1.2](https://ost.51cto.com/posts/12658)。 ### 3.2 MRobot碰一碰配网交互 结合winder demo很快就能找出配网接口,配网之后即可接收数据进行设备控制。整体控制流程如下: ::: hljs-center ![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/76459b60987aeee1d9811945baede957fdf61d.png?x-oss-process=image/resize,w_692,h_308) ::: 核心代码如下(详情可参考:[3.南向开发-设备配网](https://ost.51cto.com/posts/12786)): ``` include: │ ├── netcfg.h // 无感配网注册相关接口 │ ├── network_config_service.h //无感配网相关头文件。 libs: ├── libs │ ├── libhilinkadapter_3861.a // 无感配网相关库文件。 │ └── libnetcfgdevicesdk.a // 无感配网相关库文件。 src: ├── netcfg.c // NAN相关操作和联网动作 ``` ```c //注册回调 static void *MRobotTask(const char *arg) { (void)arg; ···· NetCfgRegister(MRobotNetEventHandler); // 进入配网状态并注册网络监听事件 ···· } //回调任务 static int MRobotNetEventHandler(NET_EVENT_TYPE event, void *data) { switch (event) { case NET_EVENT_CONNECTTED: // 网络连接成功 m_netstatus = true; printf("m_netstatus:%d\n\n", m_netstatus); // 显示网络已连接 break; case NET_EVENT_RECV_DATA: // 接收到网络信息(FA发送的消息) MRobotProcessAppMessage((const char *)data, strlen(data)); // 处理对应的信息 break; default: break; } return 0; } //接收数据 static void MRobotProcessAppMessage(const char *data, int data_len) { if (data_len != MESSAGE_LEN) { strcpy(app_msg, data); // app_msg=data; printf("------app_msg:%s \r\n", app_msg); printf("----- data:%s\r\n", data); WINERR("data len invalid! \n"); return; } } //消息处理 // app运动控制 static void AppCtrMRobot() { switch (*app_msg) { case 'F': { printf("退下\r\n"); // OledFillScreen(0x00); // OledShowString(25, 2, "Forward", 2); Backward(circle_time); Stop_motor(); return; //每次仅有一种情况,满足直接return回main } ··· } ``` ### 3.3 互联设备开发 ![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/54341ae327633a908440752e918429cad58e83.png?x-oss-process=image/resize,w_633,h_266) 互联设备包括门锁、风扇、台灯、浇水机均使用hi3861模组作为核心板,若有更多设备可以快捷添加。每台设备支持使用蓝牙串口控制、基于mqtt的云端控制。增加web端选择也让非HarmonyOS移动设备控制互联设备,让更多的人享受便利。 下面以门锁为例,给出开发方案: ```C /** * * V2 版本 所有union设备都融合在一起,共用一套代码 * 缺点是浪费时间作其他设备的事; * 也提供了各设备单独的版本 对应fan_mqtt.c door_mqtt.c lamb_mqtt.c water_mqtt.c 编译记得修改 BUILD.gn * */ #include #include #include #include #include "ohos_init.h" #include "cmsis_os2.h" #include "wifi_connect.h" #include "MQTTClient.h" #include "wifiiot_errno.h" #include "wifiiot_gpio.h" #include "wifiiot_gpio_ex.h" #include "wifiiot_adc.h" #include "wifiiot_uart.h" #include "wifiiot_pwm.h" #include "hi_uart.h" #define UART_BUFF_SIZE 1000 #define MQTT_BUFF_SIZE 1000 static const char *data = "MRobot_door\r\n"; uint8_t uart_buff[UART_BUFF_SIZE] = {0}; uint8_t *uart_buff_ptr = uart_buff; char mqtt_buff[MQTT_BUFF_SIZE] = {0}; static unsigned char sendBuf[1000]; static unsigned char readBuf[1000]; Network network; void messageArrived(MessageData *data) { printf("Message arrived on topic %.*s: %.*s\n", data->topicName->lenstring.len, data->topicName->lenstring.data, data->message->payloadlen, data->message->payload); strcpy(mqtt_buff,data->message->payload); printf("mqtt_buff%s \n",mqtt_buff); } /************* MRobotUnionDevices Control ******************/ // GPIO 接口与原理图对应 使用哪个就在主函数加入Init、 Ctr函数。 static void MyUartInit(void) { uint32_t ret; WifiIotUartAttribute uart_attr = { .baudRate = 115200, // data_bits: 8bits .dataBits = 8, .stopBits = 1, .parity = 0, }; // Initialize uart driver ret = UartInit(WIFI_IOT_UART_IDX_1, &uart_attr, NULL); if (ret != WIFI_IOT_SUCCESS) { printf("Failed to init uart! Err code = %d\n", ret); return; } } /*****************Door*************************/ static void DoorInit(void) { //初始化GPIO GpioInit(); IoSetFunc(WIFI_IOT_IO_NAME_GPIO_10, WIFI_IOT_IO_FUNC_GPIO_10_GPIO); GpioSetDir(WIFI_IOT_GPIO_IDX_10, WIFI_IOT_GPIO_DIR_OUT); GpioSetOutputVal(WIFI_IOT_GPIO_IDX_10, 1); } /* @brief Servo control * @param angle input value: 0-200 * */ void My_servo(int angle) { int j = 0; int k = 20000 / 200; //实际应该是20000/180 angle = k * angle; for (j = 0; j < 5; j++) { GpioSetOutputVal(WIFI_IOT_GPIO_IDX_10, 1); //hi_udelay(angle); // angle ms usleep(angle); GpioSetOutputVal(WIFI_IOT_GPIO_IDX_10, 0); usleep(20000-angle); } // 20ms 控制舵机 } static void DoorCtr(void) { //UartRead(WIFI_IOT_UART_IDX_1, uart_buff_ptr, UART_BUFF_SIZE); hi_uart_read_timeout(WIFI_IOT_UART_IDX_1, uart_buff_ptr, UART_BUFF_SIZE,10); printf("Uart1 read door data:%s \n", uart_buff_ptr); if (uart_buff[0] == '2' && uart_buff[1] == '1') { //模拟20ms周期 PWM 控制舵机开门 printf("******* 开 门 *****\n"); My_servo(100); //开门 uart_buff[0] ='5'; } if (mqtt_buff[0] == '2' && mqtt_buff[1] == '1') { //模拟20ms周期 PWM 控制舵机开门 printf("******* 开 门 *****\n"); My_servo(100); //开门 mqtt_buff[0] ='5'; } My_servo(180); //自动复位 模拟舵机有点迷。值是测试出来的,上面的延时<0 居然可以实现舵机控制 printf("******* 门 机 械 复 位 *****\n"); } static void MQTT_DoorTask(void) { WifiConnect("r1", "88888889"); printf("Starting ...\n"); int rc, count = 0; MQTTClient client; NetworkInit(&network); printf("NetworkConnect ...\n"); MyUartInit(); DoorInit(); begin: NetworkConnect(&network, "我的服务器地址iot页面", 1883); // hellokun printf("MQTTClientInit ...\n"); MQTTClientInit(&client, &network, 2000, sendBuf, sizeof(sendBuf), readBuf, sizeof(readBuf)); MQTTString clientId = MQTTString_initializer; clientId.cstring = "MRobot"; MQTTPacket_connectData data = MQTTPacket_connectData_initializer; data.clientID = clientId; data.willFlag = 0; data.MQTTVersion = 3; data.keepAliveInterval = 0; data.cleansession = 1; printf("MQTTConnect ...\n"); rc = MQTTConnect(&client, &data); if (rc != 0) { printf("MQTTConnect: %d\n", rc); NetworkDisconnect(&network); MQTTDisconnect(&client); osDelay(200); goto begin; } printf("MQTTSubscribe ...\n"); //其他设备 web_fan_btn web_lamb_btn web_water_btn rc = MQTTSubscribe(&client, "web_door_btn", 2, messageArrived); //回调 if (rc != 0) { printf("MQTTSubscribe: %d\n", rc); osDelay(200); goto begin; } while (++count) { //使用哪个设备就在加入对应Init、 Ctr。 DoorCtr(); //串口、mqtt数据控制门 MQTTMessage message; char payload[30]; message.qos = 2; message.retained = 0; message.payload = payload; sprintf(payload, "message number %d", count); message.payloadlen = strlen(payload); //其他设备 发布fan lamb water if ((rc = MQTTPublish(&client, "door", &message)) != 0) { printf("Return code from MQTT publish is %d\n", rc); NetworkDisconnect(&network); MQTTDisconnect(&client); goto begin; } osDelay(50); printf("----- count = %d ------\r\n",count); } //无需发布 // while (++count) // { // MQTTMessage message; // char payload[30]; // message.qos = 2; // message.retained = 0; // message.payload = payload; // sprintf(payload, "message number %d", count); // message.payloadlen = strlen(payload); // //其他设备 发布fan lamb water // if ((rc = MQTTPublish(&client, "door", &message)) != 0){ // printf("Return code from MQTT publish is %d\n", rc); // NetworkDisconnect(&network); // MQTTDisconnect(&client); // goto begin; // } // osDelay(50); // } } static void MQTT_Door(void) { osThreadAttr_t attr; attr.name = "MQTT_DoorTask"; attr.attr_bits = 0U; attr.cb_mem = NULL; attr.cb_size = 0U; attr.stack_mem = NULL; attr.stack_size = 10240; attr.priority = osPriorityNormal; if (osThreadNew((osThreadFunc_t)MQTT_DoorTask, NULL, &attr) == NULL) { printf("[MQTT_Door] Falied to create MQTT_DoorTask!\n"); } } APP_FEATURE_INIT(MQTT_Door); ``` ### 3.4 南向开发框架总结 MRobot文件框架: ![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/73d5a7361de14f83ce6753a514e46cc214b5c1.png?x-oss-process=image/resize,w_820,h_808) 互联设备文件框架: ![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/d8b462225875682a590849e4f659410f8c231c.png?x-oss-process=image/resize,w_820,h_787) ### 3.5 趣味配件 给小朋友准备的,大朋友跳过吧。 ![image.png](https://harmonyos.oss-cn-beijing.aliyuncs.com/images/202205/2779ddd15415fb4247b5435b90f4480dd2b61f.png?x-oss-process=image/resize,w_820,h_447) ## 4. 机器人 demo 直接见视频吧:[MRobot演示-记得三连](https://www.bilibili.com/video/BV1o34y1E7Gu?share_source=copy_web) ## 个人总结 没什么好说的,很多不会,继续坚持,深挖、死磕。 520,恰好生日,给个免费的赞吧! (biu~❤)