> 文档中心 > 我用鸿蒙开发一台“萌萌”机器人

我用鸿蒙开发一台“萌萌”机器人


我用鸿蒙开发一台机器人【萌萌的那种】

目录

    • 我用鸿蒙开发一台机器人【萌萌的那种】
    • 0. 说明
    • 1. 方案设计
      • 1.1 功能需求分析
      • 1.2 结构设计与硬件选型
      • 1.3 控制数据流
    • 2. 北向App开发
      • 2.1 新建原子化服务APP
      • 2.2 UI设计
      • 2.3 NAN-JS通信
      • 2.4 真机测试
    • 3. 南向开发
      • 3.1 获取OpenHarmony源码
      • 3.2 MRobot碰一碰配网交互
      • 3.3 互联设备开发
      • 3.4 南向开发框架总结
      • 3.5 趣味配件
    • 4. 机器人 demo
    • 个人总结

0. 说明

大家好我是HelloKun,正式接触鸿蒙也快9个月了,一直想做一个有意思的极客项目:既能用到鸿蒙特性【ArkUI、原子化服务、碰一碰等】、涉及南北向开发,又能融入实际生活。断断续续,从南到北,粗略过了一遍,终于,近期实现了这一想法。今天终于有空编写帖子,向大家展示个人极客项目–智慧终端机器人MRobot,如下图:
我用鸿蒙开发一台“萌萌”机器人
我用鸿蒙开发一台“萌萌”机器人我用鸿蒙开发一台“萌萌”机器人我用鸿蒙开发一台“萌萌”机器人
我用鸿蒙开发一台“萌萌”机器人

1. 方案设计

1.1 功能需求分析

::: hljs-center
MRobot = 快捷启动 + 自由移动 + APP交互 + 多设备互联 + 云端控制 + 其他拓展(语音、趣味功能)
我用鸿蒙开发一台“萌萌”机器人
:::

  • 快捷启动:碰一碰拉起配网页面 | 在“我的服务”中使用卡片启动APP | 桌面卡片 ;
  • 自由移动:具备转向、前进、后退等基本运动能力;
  • APP交互: 控制机器人移动;
  • 多设备互联:通过机器人控制其他设备,如门锁、台灯、风扇、浇水机等;
  • 云端控制:基于mqtt协议控制互联设备,无需与机器人配网即可控制,一是解决机器人不在身边的情形(如归家开门),二是提供web端供其他人使用(如舍友手机不是HarmonyOS系统);
  • 其他拓展:离线语音交互,对机器人喊话就能控制一切; 可控磁吸配件(给小朋友准备的。),如发光环、交通灯、迷你风扇

1.2 结构设计与硬件选型

参考猫、飞船返回舱等元素,花一天设计出了MRobot,萌不萌仁者见仁啦。硬件选型方面,机器人控制核心毫无疑问hi3861模组;N20小功率电机以及驱动;语音模块使用SU03T;一块800mAh锂电池以及TypeC充放管理模块;蓝牙用于与互联设备通信;几块磁铁预备做配件;左耳有触摸传感,提供oled显示模块或MPU6050选择(不同时使用)。
我用鸿蒙开发一台“萌萌”机器人

1.3 控制数据流

  • APP:北向APP
  • Web: 云端iot服务
  • MRobot:智慧终端机器人 小萌
  • Union Devices:互联设备,门锁台灯等
  • Speaker:语音模块
  • Human: 万恶之源
    我用鸿蒙开发一台“萌萌”机器人

2. 北向App开发

APP基于ArkUI的类web开发范式,大部分使用JS开发。APP将完成各功能页面展示、消息下发功能。整个工程主要参考HarmonyOS Connect设备开发实现,去除掉模板JAVA实现板块,使用JS接口替代。

2.1 新建原子化服务APP

使用OneHop模板新建原子化服务工程,命名MRobot。可参考分享贴碰一碰分享总贴
我用鸿蒙开发一台“萌萌”机器人
删除不需要的control模块(基于JAVA),新建一个jscontrol page,这是将是控制主页。参考1.抛除束缚,自定义设备我用鸿蒙开发一台“萌萌”机器人我用鸿蒙开发一台“萌萌”机器人

2.2 UI设计

根据需求分析设计UI,因为第一次写APP,渲染样式没有概念,所以在图片上做文章,对设计的MRobot模型进行渲染后导出图片置于APP中,所有的UI主要用到button、switch、swiper组件,先基于可视化低代码开发,后转为hml(jsctronl page是)。ui总览如下;
我用鸿蒙开发一台“萌萌”机器人

  • 碰一碰拉起,进入配网页面,提供两个选项,一是正常配网,二是直接进入云端web页面秒控设备。
  • 首页作为主控页面(jscontrol page),从上往下依次是:MRobot机器人运动控制、秒控设备(发送消息给机器人,实现互联设备控制)、表情聊天(点击表情发送消息给机器人,机器人做出运动、语音反应);
  • 点击更多,将会打开一些隐藏页面,如随机计算、认识宇宙等,主要是面对小朋友,未来增加通关解锁相应技能。
    下面总结常用的一些UI能力,方便调试与开发:
//弹窗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通信接口,因为是调用JS接口,获取NAN通道deviceInfo十分容易。
例如,发送机器人前进核心代码如下:

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

我用鸿蒙开发一台“萌萌”机器人

:::

3. 南向开发

南向完成MRobot开发、互联设备开发。基于OpenHarmony 1.0.1 LTS对 hi3861 进行资源分配、各模块调试、整机调试、功能验证。
南向难免要面向硬件,MRobot与互联设备电气原理图如下:
我用鸿蒙开发一台“萌萌”机器人我用鸿蒙开发一台“萌萌”机器人我用鸿蒙开发一台“萌萌”机器人

3.1 获取OpenHarmony源码

以下是我获取源码的操作以及过程遇到的问题以及解决方法。

/***************** openharmony 1.0.1源码 ******************/repo下载【安装git、repo】,#特别注意:请下载OpenHarmony 1.0.1 版本,后续会更新支持OpenHarmony其他版本mkdir ~/OpenHarmony1.01cd ~/OpenHarmony1.01repo init -u git@gitee.com:openharmony/manifest.git -b OpenHarmony_1.0.1_release --no-repo-verifyrepo sync -crepo 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。

3.2 MRobot碰一碰配网交互

结合winder demo很快就能找出配网接口,配网之后即可接收数据进行设备控制。整体控制流程如下:
::: hljs-center
我用鸿蒙开发一台“萌萌”机器人
:::

核心代码如下(详情可参考:3.南向开发-设备配网):

include:│   ├── netcfg.h   // 无感配网注册相关接口│   ├── network_config_service.h //无感配网相关头文件。libs:├── libs│   ├── libhilinkadapter_3861.a // 无感配网相关库文件。│   └── libnetcfgdevicesdk.a // 无感配网相关库文件。src:    ├── netcfg.c // NAN相关操作和联网动作
//注册回调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 互联设备开发

我用鸿蒙开发一台“萌萌”机器人
互联设备包括门锁、风扇、台灯、浇水机均使用hi3861模组作为核心板,若有更多设备可以快捷添加。每台设备支持使用蓝牙串口控制、基于mqtt的云端控制。增加web端选择也让非HarmonyOS移动设备控制互联设备,让更多的人享受便利。
下面以门锁为例,给出开发方案:

/** *  *  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 1000static 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 driverret = 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){//初始化GPIOGpioInit();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/180angle = k * angle;for (j = 0; j < 5; j++){GpioSetOutputVal(WIFI_IOT_GPIO_IDX_10, 1);//hi_udelay(angle); // angle msusleep(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); // hellokunprintf("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_btnrc = 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 waterif ((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文件框架:
我用鸿蒙开发一台“萌萌”机器人
互联设备文件框架:
我用鸿蒙开发一台“萌萌”机器人

3.5 趣味配件

给小朋友准备的,大朋友跳过吧。
我用鸿蒙开发一台“萌萌”机器人

4. 机器人 demo

直接见视频吧:MRobot、B站

个人总结

没什么好说的,很多不会,继续坚持,深挖、死磕。
520,恰好生日,给个免费的赞吧! (biu~❤)