
【训练营】基于OpenHarmony系统的四足机器狗
简介
基于OpenHarmony系统的模块化四足机器狗
简介:基于OpenHarmony系统的模块化四足机器狗开源协议
:Public Domain
描述
基于OpenHarmony系统的模块化四足机器狗
使用海思Hi3861作为主控芯片,PCA9685作舵机控制,最高支持16路舵机控制。
模块组成:Hi3861核心板、PCA9685舵机控制板、超声波测距板、MPU-6050模块等。
(目前完成HCR-S04超声波测距并实现自主避障功能)
核心板PCB 3d预览:
四足机器人外壳 3d预览:
实物展示:
前:
左:
后:
蹲姿:
网页展示:
程序说明:
1. 基本动作代码:
fe(g('a'), () => {fg(u('/dog/init'), () => {});});
fe(g('b'), () => {let data = {\"type\": 3, \"count\": 10, \"list\": [[-15, 130, -35, 150, -35, 150, -15, 130, 100], [-35, 150, -15, 130, -15, 130, -35, 150, 100]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
fe(g('b'), () => {let data = {\"type\": 3, \"count\": 1, \"list\": [[-15, 130, -15, 130, -15, 130, -15, 130, 300]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
fe(g('c'), () => {let data = {\"type\": 3, \"count\": 10, \"list\": [[31, 96, 54, 144, 63, 139, 19, 100, 50], [35, 112, 5, 134, 15, 136, 25, 115, 50], [60, 138, 5, 106, 16, 104, 51, 142, 50], [48, 144, 20, 103, 31, 98, 40, 147, 50], [-1, 118, 38, 132, 48, 128, -12, 118, 50]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
fe(g('c'), () => {let data = {\"type\": 3, \"count\": 1, \"list\": [[-15, 130, -15, 130, -15, 130, -15, 130, 300]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
fe(g('d'), () => {let data = {\"type\": 3, \"count\": 10, \"list\": [[63, 139, 19, 100, 31, 96, 54, 144, 50], [48, 128, -37, 115, -22, 116, 38, 132, 50], [31, 98, 35, 148, 42, 146, 20, 103, 50], [9, 106, 51, 142, 60, 138, -1, 107, 50], [-2, 132, 25, 115, 35, 112, -14, 125, 50]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
fe(g('d'), () => {let data = {\"type\": 3, \"count\": 1, \"list\": [[-15, 130, -15, 130, -15, 130, -15, 130, 300]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
fe(g('e'), () => {let data = {\"type\": 3, \"count\": 10, \"list\": [[56, 135, 21, 107, 56, 135, 21, 107, 50], [46, 126, -11, 119, 12, 133, 26, 117, 50], [32, 104, 33, 142, 18, 109, 45, 138, 50], [42, 139, 22, 108, 32, 104, 33, 142, 50], [0, 120, 36, 130, 46, 126, -11, 119, 50]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
fe(g('e'), () => {let data = {\"type\": 3, \"count\": 1, \"list\": [[-15, 130, -15, 130, -15, 130, -15, 130, 300]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
fe(g('f'), () => {let data = {\"type\": 3, \"count\": 10, \"list\": [[32, 103, 47, 139, 32, 103, 47, 139, 50], [36, 114, 3, 132, 0, 120, 36, 130, 50], [54, 134, 7, 111, 42, 139, 22, 108, 50], [18, 109, 45, 138, 54, 134, 7, 111, 50], [12, 133, 26, 117, 36, 114, 3, 132, 50]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
fe(g('f'), () => {let data = {\"type\": 3, \"count\": 1, \"list\": [[-15, 130, -15, 130, -15, 130, -15, 130, 300]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
fe(g('g'), () => {let data = {\"type\": 3, \"count\": 1, \"list\": [[-15, 130, -15, 130, -15, 130, -15, 130, 500]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
fe(g('h'), () => {let data = {\"type\": 3, \"count\": 1, \"list\": [[45, 130, -45, 180, 45, 130, -45, 180, 700]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
fe(g('i'), () => {let data = {\"type\": 3, \"count\": 1, \"list\": [[-45, 180, -45, 180, -45, 180, -45, 180, 700]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
fe(g('j'), () => {let data = {\"type\": 3, \"count\": 1, \"list\": [[60, 210, 60, 225, 60, 210, 60, 225, 700]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
fe(g('k'), () => {fg(u('/dog/auto'), () => {});});
fe(g('k'), () => {let data = {\"type\": 3, \"count\": 1, \"list\": [[-15, 130, -15, 130, -15, 130, -15, 130, 300]]};fp(u('/dog/cmds'), JSON.stringify(data), () => {});});
采用json串的形式实现基本的踏步、前进、后退等动作。
2.1 HCSR-04测距部分:
#include
#include
#include
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_gpio.h"
#include "iot_io.h"
#include "genki_pin.h"
#include "dog.h"
#include "iot_time.h"
#include "pca9685.h"
#include "hi_nvm.h"
#include
#include
#include
#include "cJSON.h"
#include "kinematics.h"
#define Echo 8 //Echo //GPIO8
#define Trig 7 //Trig //GPIO7
#define GPIO_FUNC 0
float distance;
float GetDistance (void) {
static unsigned long start_time = 0, time = 0;
distance = 0.0;
IotGpioValue value = IOT_GPIO_VALUE0;
unsigned int flag = 0;
IoTIoSetFunc(Echo, GPIO_FUNC);//设置Echo连接IO为普通GPIO模式,无复用
IoTGpioSetDir(Echo, IOT_GPIO_DIR_IN);//设置Echo连接IO为输入模式
IoTGpioSetDir(Trig, IOT_GPIO_DIR_OUT);//设置Trig连接IO为输出模式
IoTGpioSetOutputVal(Trig, IOT_GPIO_VALUE1);//拉高Trig
IoTUdelay(20);//20us
IoTGpioSetOutputVal(Trig, IOT_GPIO_VALUE0);//拉低Trig
while (1) {
IoTGpioGetInputVal(Echo, &value);//读取Echo脚的电平状态
if ( value == IOT_GPIO_VALUE1 && flag == 0) {//如果为高
start_time = IoTGetUs();//获取此时时间
flag = 1;
}
if (value == IOT_GPIO_VALUE0 && flag == 1) {//高电平结束变成低电平
time = IoTGetUs() - start_time;//计算高电平维持时间
start_time = 0;
break;
}
}
distance = time * 0.034 / 2;//计算距离
printf("distance is %f cm\n", distance);//打印距离
}
这一部分作为通用代码,可根据设备情况套用到不同代码中,不做过多赘述。
2.2 避障部分:
void dog_auto () {
while (1) {
if (distance <= 5) {
dog_execJson("{\"type\": 3, \"count\": 1, \"list\": [[63, 139, 19, 100, 31, 96, 54, 144, 50], [48, 128, -37, 115, -22, 116, 38, 132, 50], [31, 98, 35, 148, 42, 146, 20, 103, 50], [9, 106, 51, 142, 60, 138, -1, 107, 50], [-2, 132, 25, 115, 35, 112, -14, 125, 50]]}",
294);
break;
} else {
if (distance <= 20) {
dog_execJson("{\"type\": 3, \"count\": 5, \"list\": [[56, 135, 21, 107, 56, 135, 21, 107, 50], [46, 126, -11, 119, 12, 133, 26, 117, 50], [32, 104, 33, 142, 18, 109, 45, 138, 50], [42, 139, 22, 108, 32, 104, 33, 142, 50], [0, 120, 36, 130, 46, 126, -11, 119, 50]]}",
294);
break;
} else {
dog_execJson("{\"type\": 3, \"count\": 1, \"list\": [[31, 96, 54, 144, 63, 139, 19, 100, 50], [35, 112, 5, 134, 15, 136, 25, 115, 50], [60, 138, 5, 106, 16, 104, 51, 142, 50], [48, 144, 20, 103, 31, 98, 40, 147, 50], [-1, 118, 38, 132, 48, 128, -12, 118, 50]]}",
294);
break;
}
}
}
}
这部分原理是通过上述测距部分计算得出的距离做判断,以此来进行避障动作。
** 如:若距离小于等于5cm,则进行后退的动作直到测得距离大于5cm;若距离小于等于20cm,则进行原地左转的动作5次,直到测得距离大于20cm;若距离大于20cm,则进行前进的动作。**
然而,这部分代码虽然理论上能够实现避障动作,但是,如何将其放入web中实现按钮调用却是我未曾涉及的领域,为此我在网上漫无目的地寻找了很久,最终通过一个物联网同学的无意提醒和仔细阅读源代码之后,终于将其实现,代码如下:
//在 genki_web_ohosdog.c 文件中添加如下函数:
static int doAuto (genki_web_request_t *request, genki_web_response_t *response) {
for(int k=1 ; k<=80; k=k+1) //由于web按钮调用的无法中断性,故设置固定次数以避免由于动作时间过长导致降压芯片发热严重的问题
{
GetDistance();//测距并计算距离
dog_auto();//根据测得距离做出相应动作
IoTUdelay(100);//延时100ms
}return 1;
}
//并在如下函数中添加语句 “service->addFilter(service, "/dog/auto", doAuto);”
genki_web_service_t *newDogService(void) {
genki_web_service_t *service = genki_web_newService("DOG");
service->addFilter(service, "/dog", doHtml);
service->addFilter(service, "/dog/init", doInit);
service->addFilter(service, "/dog/cmds", doCmds);
service->addFilter(service, "/dog/auto", doAuto);//将函数"doAuto"命名为"/dog/auto"的服务
//最后在script中加入按钮调用语句
fe(g('k'), () => {fg(u('/dog/auto'), () => {});});//按钮调用服务
(所有代码已全部放于附件)
总结:
作为一个机器人专业的学生,其实这是我第一次这么深入地了解这次所做的四足机器人,虽然一些底层的逻辑代码是借用人家已经编好的,自己只是拿来之后稍作修改而已。
在这个过程中我经历了从原理图绘制到pcb布线,从实物焊接到最后成功实现动作,这都是我从未想到过我能做到的事情,从一开始跟着教学视频一步一步画图,到后面有了自己的想法,自己到网上查找四足机器人的图片,决定做出一只独一无二属于自己的机器人;从看到0603封装的电容电阻感到为难手抖,到后来不断试错一板成型。经历过拿到的打印件尺寸出错、设计的结构不合理、不小心烧坏烧录器、以为电池坏了捣鼓半天其实是没电但是因为没有充电器一直没发现、面对看不懂的源代码只能一点一点边查边看、面对不断出错的程序只能不断找错找到后半夜,不知道有多少次熬到凌晨4点仍觉得干劲十足,因为这是我喜欢的东西,但是自己比别人笨,就只能付出更多的时间。虽然这次的项目因为自己的原因拖了很久才完成,但我在以后应该还会继续更新新的进度。很感谢立创能提供这样的机会给我们,让我能在放假之余不让自己荒废,为我之后的无论学习、工作也好提供了一次宝贵且有趣的经验。
实物演示:
设计图

BOM


评论