## Modular quadruped robot dog based on OpenHarmony system#### Uses HiSilicon Hi3861 as the main control chip and PCA9685 for servo control, supporting up to 16 channels of servo control. Module composition: Hi3861 core board, PCA9685 steering gear control board, ultrasonic ranging board, MPU-6050 module, etc. (Currently completed HCR-S04 ultrasonic ranging and realized autonomous obstacle avoidance function) ## Core board PCB 3d preview: ![Screenshot (30).png]

## Quadruped robot shell 3d preview:![Screenshot (35) .png]

## Physical display: ![19410ed5fe0cecbd2d68ed38a7fc0e6.jpg]

Front: ![2f498569e373b618a7609dbff0ae8c2.jpg]

Left: ![bc875cafc39ec0055efae9d4ba4a2c9.jpg]

After: ![c575dfa0ebe51d1ef22c706ff6cb516.jpg]

Crouching position: ![22dc99d9c45b2555e7958edf312fa01.jpg]

## Web page Display: ![Screenshot(38).png]

## Program description: #### 1. Basic action code: ``` 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), () => {});} ); ``` Use json strings to implement basic steps, forward, backward and other actions. #### 2.1 HCSR-04 ranging part: ``` cs #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) ;//Set Echo connection IO to normal GPIO mode, no reuse IoTGpioSetDir(Echo, IOT_GPIO_DIR_IN);//Set Echo connection IO to input mode IoTGpioSetDir(Trig, IOT_GPIO_DIR_OUT);//Set Trig connection IO to output mode IoTGpioSetOutputVal(Trig , IOT_GPIO_VALUE1);//Pull Trig high IoTUdelay(20);//20us IoTGpioSetOutputVal(Trig, IOT_GPIO_VALUE0);//Pull Trig low while (1) { IoTGpioGetInputVal(Echo, &value);//Read the level of Echo pin Status if (value == IOT_GPIO_VALUE1 && flag == 0) {//If it is high start_time = IoTGetUs();//Get the time at this time flag = 1; } if (value == IOT_GPIO_VALUE0 && flag == 1) {/ /High level ends and becomes low level time = IoTGetUs() - start_time;//Calculate the high level maintenance time start_time = 0; break; } } distance = time * 0.034 / 2;//Calculate the distance printf("distance is %f cm ", distance);//Print distance} ```` This part is a general code and can be applied to different codes according to the device conditions, without going into details. #### 2.2 Obstacle avoidance part: ``` cs 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; } } } } ``` This part of the principle is based on the above The distance calculated by the ranging part is used to judge the distance to avoid obstacles. ###### ** For example: if the distance is less than or equal to 5cm, then move backward until the measured distance is greater than 5cm; if the distance is less than or equal to 20cm, then turn left on the spot 5 times until the measured distance is greater than 20cm; if the distance is greater than 20cm, proceed forward. ** However, although this part of the code can theoretically implement obstacle avoidance actions, how to put it into the web to implement button calls is an area that I have not covered. For this reason, I searched aimlessly on the Internet for a long time, and finally After an unintentional reminder from an Internet of Things classmate and careful reading of the source code, I finally implemented it. The code is as follows: ``` cs //Add the following function to the genki_web_ohosdog.c file: static int doAuto (genki_web_request_t *request, genki_web_response_t *response ) { for(int k=1; k<=80; k=k+1) //Due to the uninterruptibility of web button calls, a fixed number of times is set to avoid the problem of serious heating of the voltage-reducing chip due to too long action time. { GetDistance();//Measure and calculate the distance dog_auto();//Make corresponding actions based on the measured distance IoTUdelay(100);//Delay 100ms }return 1; } //And add statements in the following function "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); //Name the function "doAuto" as the service of "/dog/auto" //Finally add the button call statement fe(g('k'), () => {fg(u('/ dog/auto'),() => {});});//The button calls the service``` (all codes have been placed in the attachment) ## Summary: ###### As a student majoring in robotics, this is actually my first This is the first time I have such an in-depth understanding of the quadruped robot I made this time. Although some of the underlying logic codes were borrowed from others, I just modified them slightly after taking them. ###### In this process, I experienced from schematic drawing to PCB wiring, from physical soldering to the final successful implementation of the action. These are things I never thought I could do. I followed the teachings from the beginning. I drew a picture step by step in the video, and later I had my own ideas. I looked up pictures of quadruped robots on the Internet, and decided to make a unique robot of my own. I felt embarrassed when I saw the capacitors and resistors in the 0603 package, and my hands shook. Trial and error molding. I have experienced the wrong size of the printouts I received, the unreasonable design structure, accidentally burning the burner, thinking that the battery was broken, and after tinkering for a long time, it turned out that the battery was dead but I never found it because there was no charger. I was faced with a source that I couldn’t understand. I can only check the code bit by bit, and when faced with a program that keeps making errors, I can only keep looking for errors in the middle of the night. I don’t know how many times I stayed up until 4 o’clock in the morning and still felt very motivated, because this is what I like. But if you are dumber than others, you can only spend more time. Although this project took a long time to be completed due to my own reasons, I should continue to update the new progress in the future. I am very grateful to Lichuang for providing us with such an opportunity, which allowed me to not let myself be wasted during the holidays, and provided me with a valuable and interesting experience in my future studies and work. ## Physical demonstration: