#基于DAYU200开发一个好玩的图传智能小车--demo样例# 原创 精华

yukoyu
发布于 2022-5-30 15:07
浏览
14收藏

#基于DAYU200开发一个好玩的图传智能小车–demo样例#

一、项目背景

随着计算机和电子技术的迅猛发展,智能产品的研究与开发愈发受到各领域学者们的重视,其中,智能小车技术的发展日新月异,在工业生产、军工及民用生活等领域都发挥了重要作用。

​智能小车综合了计算机、传感器及机械等多学科技术,在众多领域被广泛应用,能够替代人类在一些特定环境工作,例如美国的“勇气”号和“机遇”号火星探测机器人为人类探索火星做出了贡献,我国自主研发的“月球车”所应用的技术也处于世界前列;智能小车也应用于自动货运、无人驾驶等场合,并取得了相当不错的成绩。智能小车的应用正逐步渗入到工业和生活的各个层面,提高了生产效率并减少了人为失误,提升了人们的生活品质。

​再加上目前编程教育,要么比较理论,要么项目比较枯燥无味,所以本次的项目智能小车定位为一个有趣的教育学习类智能小车。

二、项目介绍

功能介绍:

1、实现图传功能
2、实现控制小车行驶
3、模拟倒车雷达功能
4、实现舵机控制摄像头转动方向

硬件介绍:

1、dayu200 开发板当控制端
2、esp32cam开发板当摄像头
3、 HiSpark Wi-Fi IoT智能小车套件

本次代码开源地址:

https://gitee.com/yukoyu/openharmony_camera_car

整体视图:

小车展示视频

#基于DAYU200开发一个好玩的图传智能小车--demo样例#-鸿蒙开发者社区

#基于DAYU200开发一个好玩的图传智能小车--demo样例#-鸿蒙开发者社区

三、代码介绍

1、代码目录介绍

代码请在附件中下载
├─CameraWebServer					 //ESP32_CAM 代码
├─carcamera					 		 //dayu200 openharmonyAPP 代码
├─flask								 //服务器代码
├─media								 //图片
└─wificamera						 //小车端代码

2、DAYU200 openharmonyAPP 分析

①、httpclient安装

请在DevEco Studio 3.0.0.900 -> Terminal输入以下命令
npm config set @ohos:registry=https://repo.harmonyos.com/npm/
npm install @ohos/httpclient --save
导入包方式:
import httpclient from '@ohos/httpclient';

②、carcamera 代码讲解

import httpClient from '@ohos/httpclient'
import socket from '@ohos.net.socket';
var datathis;

let httpClientImpl = new httpClient.HttpClient.Builder()
  .setConnectTimeout(15, httpClient.TimeUnit.SECONDS)
  .setReadTimeout(15, httpClient.TimeUnit.SECONDS)
  .build();

var thiss ;
let flag = false;
let tcp = socket.constructTCPSocketInstance();

let ok = tcp.bind({address: '0.0.0.0', port: 12121, family: 1});
ok.then(() => {
  console.log('bind success');
}).catch(err => {
  console.log('bind fail');
});

tcp.on('message', value => {
  //let da= new DataView(value.message)
  let da = resolveArrayBuffer(value.message)
  let objs = JSON.parse(da);
  datathis.CmValue = objs.cm;
  //thiss.text = ""+da.getUint8(0)+"  "+da.getUint8(1)+"  "+da.getUint8(2)+"  "+"len:"+value.message.byteLength;
  //console.log("okokok on message");
});

function resolveArrayBuffer(message){	//转string类型

    if (message instanceof ArrayBuffer) {
      let dataView = new DataView(message)
      let str = ""
      for (let i = 0;i < dataView.byteLength; ++i) {
        let c = String.fromCharCode(dataView.getUint8(i))
        if (c !== "\n") {
          str += c
        }
      }
      return str;
    }
}


let promise;

async function send(b,c)	//tcp send
{
  var cc=new Uint8Array([170,b,c]);
  if(flag)
  {
    tcp.send({
      data:cc.buffer
    },err => {
      if (err) {
        console.log('send fail');
        return;
      }
      console.log('send success');

    })
  }else{

    promise = tcp.connect({ address: {address: '192.168.0.11', port: 20222, family: 1} , timeout: 6000});


    promise.then(() => {
      console.log('connect success');
      flag = true;
      tcp.send({
        data:cc.buffer
      },err => {
        if (err) {
          console.log('send fail');
          return;
        }
        console.log('send success');

      })
    }).catch(err => {
      console.log('connect fail');
    });

  }
}


var intervalID = setInterval(function() {	//定时
  datathis.getimage();
}, 300);

@Entry
@Component
struct Index {
  @State inSetValue:number = 90;
  @State CmValue:number = 0;
  @State base64str: string = 'http://www.news.cn/titlepic/112868/1128686652_1653567882005_title0h.jpg';//默认图片设置
  @State flag:boolean = true;
  intervalID : any;

  onPageShow() {
    datathis = this;
  }
  getimage(){
    let request = new httpClient.Request.Builder()
      .url("http://192.168.0.36:5000")                    // 请求地址
      .method("GET")                                      // 请求方式
      .addHeader("Content-Type", "application/json")      // Header设置
      .build();

    httpClientImpl.newCall(request).enqueue((result) => {
      console.log("success test: " + JSON.stringify(result.data))   // 成功回调
      this.base64str= result.data;
    }, (error) => {
      console.log("error: " + JSON.stringify(error))      // 失败回调
    })
  }

  build() {
    Row() {
      Column() {

        Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
          Text('图传小车')
            .fontSize(50)
            .fontWeight(FontWeight.Bold)
            .fontColor('#2359be')
        }
        .backgroundColor('#ffdba46a')
        .width('100%')
        .height('10%')
        .borderRadius(10)

        Image(this.base64str) //网络图片
          .width('100%')
          .height('40%')
          .border({ width: 1 })
          .borderStyle(BorderStyle.Dashed)
          .syncLoad(false)
        Slider({
          value: this.inSetValue,
          min: 0,
          max: 180,
          step: 1,
          style: SliderStyle.InSet
        })
          .blockColor(Color.Red)
          .trackColor(0xCCCCCC)
          .selectedColor(0xCCCCCC)
          .showSteps(false)
          .showTips(false)
          .onChange((value: number, mode: SliderChangeMode) => {
            this.inSetValue = value
            send(2,value);
            console.info('value:' + value + 'mode:' + mode.toString())
          })
          .height('5%')

        Row(){

        Column() {
          Row() {
            Button('上')                                // 显示一个+按钮
              .size({width: 170, height: 170})           // 按钮大小
              .fontSize(50)                            // 按钮文字大小
              .onClick(() => {                         // 按钮点击事件
                send(1,1);
              })
          }.height('28%')
          Row() {
            Button('左')                                // 显示一个+按钮
              .size({width: 170, height: 170})           // 按钮大小
              .fontSize(50)                            // 按钮文字大小
              .onClick(() => {                         // 按钮点击事件
                send(1,4);
              })
            Button('停')                                // 显示一个+按钮
              .size({width: 170, height: 170})           // 按钮大小
              .fontSize(50)                            // 按钮文字大小
              .onClick(() => {                         // 按钮点击事件
                send(1,0);
              })
            Button('右')                                // 显示一个+按钮
              .size({width: 170, height: 170})           // 按钮大小
              .fontSize(50)                            // 按钮文字大小
              .onClick(() => {                         // 按钮点击事件
                send(1,2);
              })
          }.height('28%')
          Row() {
            Button('退')                                // 显示一个+按钮
              .size({width: 170, height: 170})           // 按钮大小
              .fontSize(50)                            // 按钮文字大小
              .onClick(() => {                         // 按钮点击事件
                send(1,3);
              })
          }.height('28%')
        }.width('90%')


        Slider({
          value: this.CmValue,
          min: 0,
          max: 220,
          step: 1,
          style: SliderStyle.InSet,
          direction: Axis.Vertical
        })
          .blockColor(Color.Red)
          .trackColor(Color.Red)
          .selectedColor(Color.Green)
          .showSteps(false)
          .showTips(false)
          .width('10%')

        }.height('40%')
      }
      .width('100%')
    }
    .height('100%')
  }
}

3、HiSpark Wi-Fi IoT智能小车代码分析

①.新建文件夹

路径:openharmony\applications\sample\wifi-iot\app\

mkdir wificamera

②.编写小车电机驱动

路径:openharmony\applications\sample\wifi-iot\app\wificamera\robot_l9110s.c

代码:

#define GPIO0 0
#define GPIO1 1
#define GPIO9 9
#define GPIO10 10
#define GPIOFUNC 0
#define PWM_FREQ_FREQUENCY  (60000)

void gpio_control (unsigned int  gpio, IotGpioValue value) {
  hi_io_set_func(gpio, GPIOFUNC);
  IoTGpioSetDir(gpio, IOT_GPIO_DIR_OUT);
  IoTGpioSetOutputVal(gpio, value);
}
//后退
void car_backward(void) {
  gpio_control(GPIO0, IOT_GPIO_VALUE0);
  gpio_control(GPIO1, IOT_GPIO_VALUE1);
  gpio_control(GPIO9, IOT_GPIO_VALUE0);
  gpio_control(GPIO10, IOT_GPIO_VALUE1);
}
//前进
void car_forward(void) {
  gpio_control(GPIO0, IOT_GPIO_VALUE1);
  gpio_control(GPIO1, IOT_GPIO_VALUE0);
  gpio_control(GPIO9, IOT_GPIO_VALUE1);
  gpio_control(GPIO10, IOT_GPIO_VALUE0);
}
//左转
void car_left(void) {
  gpio_control(GPIO0, IOT_GPIO_VALUE0);
  gpio_control(GPIO1, IOT_GPIO_VALUE0);
  gpio_control(GPIO9, IOT_GPIO_VALUE1);
  gpio_control(GPIO10, IOT_GPIO_VALUE0);
}
//右转
void car_right(void) {
  gpio_control(GPIO0, IOT_GPIO_VALUE1);
  gpio_control(GPIO1, IOT_GPIO_VALUE0);
  gpio_control(GPIO9, IOT_GPIO_VALUE0);
  gpio_control(GPIO10, IOT_GPIO_VALUE0);
}
//停止转动
void car_stop(void) {
  gpio_control(GPIO0, IOT_GPIO_VALUE1);
  gpio_control(GPIO1, IOT_GPIO_VALUE1);
  gpio_control(GPIO9, IOT_GPIO_VALUE1);
  gpio_control(GPIO10, IOT_GPIO_VALUE1);
}

③.编写舵机驱动

路径:openharmony\applications\sample\wifi-iot\app\wificamera\robot_sg90.c

代码:

#define GPIO2 2
void set_angle( unsigned int duty) {
    IoTGpioInit(GPIO2);
    IoTGpioSetDir(GPIO2, IOT_GPIO_DIR_OUT);
    IoTGpioSetOutputVal(GPIO2, IOT_GPIO_VALUE1);
    hi_udelay(duty);
    IoTGpioSetOutputVal(GPIO2, IOT_GPIO_VALUE0);
    hi_udelay(20000 - duty);
}

/*Steering gear turn left*/
void engine_turn_left(void)
{
    for (int i = 0; i <10; i++) {
        set_angle(1000);
    }
}

/*Steering gear turn right*/
void engine_turn_right(void)
{
    for (int i = 0; i <10; i++) {
        set_angle(2000);
    }
}

/*Steering gear return to middle*/
void regress_middle(void)
{
    for (int i = 0; i <10; i++) {
        set_angle(1500);
    }
}

void custom(int delay)
{
    for (int i = 0; i <10; i++) {
        set_angle(delay);
    }
}

④.编写超声波驱动

路径:openharmony\applications\sample\wifi-iot\app\wificamera\robot_hcsr04.c

代码:

#define GPIO_8 8
#define GPIO_7 7
#define GPIO_FUNC 0
extern int cmm;
void GetDistance  (float *distance) {
    static unsigned long start_time = 0, time = 0;
    IotGpioValue value = IOT_GPIO_VALUE0;
    unsigned int flag = 0;
    IoTWatchDogDisable();

    hi_io_set_func(GPIO_8, GPIO_FUNC);
    IoTGpioSetDir(GPIO_8, IOT_GPIO_DIR_IN);

    IoTGpioSetDir(GPIO_7, IOT_GPIO_DIR_OUT);
    IoTGpioSetOutputVal(GPIO_7, IOT_GPIO_VALUE1);
    hi_udelay(20);
    IoTGpioSetOutputVal(GPIO_7, IOT_GPIO_VALUE0);

    while (1) {
        IoTGpioGetInputVal(GPIO_8, &value);
        if ( value == IOT_GPIO_VALUE1 && flag == 0) {
            start_time = hi_get_us();
            flag = 1;
        }
        if (value == IOT_GPIO_VALUE0 && flag == 1) {
            time = hi_get_us() - start_time;
            start_time = 0;
            break;
        }
    }
    *distance = time * 0.034 / 2;
    printf("distance is %f\r\n",*distance);
    return ;
}

⑤.编写wifi和socket server

路径:openharmony\applications\sample\wifi-iot\app\wificamera\wifi_sockets.c

代码:

// 接收、发送的数据
static char request[256] = "";
// 未连接热点=0,已连接热点=1
static int g_connected = 0;

int connfd = -1;

// 输出连接信息字符串
// 打印内容样例--> bssid: 38:47:BC:49:01:FA, rssi: 0, connState: 0, reason: 0, ssid: MyMobile
void PrintLinkedInfo(WifiLinkedInfo* info) {
    if (!info) return;
    static char macAddress[32] = {0};
    unsigned char* mac = info->bssid;
    snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    printf("bssid: %s, rssi: %d, connState: %d, reason: %d, ssid: %srn", macAddress, info->rssi, info->connState, info->disconnectedReason, info->ssid);
}

// 连接状态改变事件处理
void OnWifiConnectionChanged(int state, WifiLinkedInfo* info) {
    if (!info) return;

    // 输出类似内容:OnWifiConnectionChanged 31, state = 1, info =
    printf("%s %d, state = %d, info = rn", __FUNCTION__, __LINE__, state);
    PrintLinkedInfo(info);

    // 根据连接状态设置g_connected
    if (state == WIFI_STATE_AVALIABLE) {
        g_connected = 1;
    } else {
        g_connected = 0;
    }
}

// 扫描状态改变事件处理
void OnWifiScanStateChanged(int state, int size) {
    printf("%s %d, state = %X, size = %drn", __FUNCTION__, __LINE__, state, size);
}

void DisconnectTcpSocket(int connfd) {
    sleep(1);
    printf("do_disconnect...rn");
    lwip_close(connfd);
    sleep(1); // for debug
}

void CloseTcpSocket(int socketfd) {
    printf("do_cleanup...rn");

    lwip_close(socketfd);
}

static void TcpServerHandler(void) {
    ssize_t retval = 0;
    unsigned short port = 20222;

    // 创建一个通信的Socket,并返回一个Socket文件描述符。第一个参数IpV4,第二个参数SOCK_STREAM类型,第三个指用到的协议
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    // 客户端地址和地址长度
    struct sockaddr_in clientAddr = {0};
    socklen_t clientAddrLen = sizeof(clientAddr);

    // 服务端地址
    struct sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;
    // htons是将整型变量从主机字节顺序转变成网络字节顺序,就是整数在地址空间存储方式变为高位字节存放在内存的低地址处
    serverAddr.sin_port = htons(port);
    // 监听本机的所有IP地址,INADDR_ANY=0x0
    // 将主机数转换成无符号长整型的网络字节顺序
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    // 服务端绑定端口
    retval = bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
    if (retval < 0) {
        printf("bind failed, %ld!rn", retval);
        CloseTcpSocket(sockfd);
        return;
    }
    printf("bind to port %d success!rn", port);

    // 开始监听,backlog指Pending连接队列增长到的最大长度。队列满了,再有新连接请求到达,则客户端ECONNREFUSED错误。如果支持重传,则请求忽略。
    int backlog = 1;
    retval = listen(sockfd, backlog);
    if (retval < 0) {
        printf("listen failed!rn");
        CloseTcpSocket(sockfd);
        return;
    }
    printf("listen with %d backlog success!rn", backlog);

    int outerFlag = 1;
    while (outerFlag) {
        // 接受客户端连接,成功会返回一个表示连接的 socket。clientAddr参数将会携带客户端主机和端口信息;失败返回 -1
        // 从Pending连接队列中获取第一个连接,根据sockfd的socket协议、地址族等内容创建一个新的socket文件描述,并返回。
        // 此后的 收、发 都在 表示连接的 socket 上进行;之后 sockfd 依然可以继续接受其他客户端的连接,
        // UNIX系统上经典的并发模型是“每个连接一个进程”——创建子进程处理连接,父进程继续接受其他客户端的连接
        // 鸿蒙liteos-a内核之上,可以使用UNIX的“每个连接一个进程”的并发模型liteos-m内核之上,可以使用“每个连接一个线程”的并发模型
        connfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrLen);
        if (connfd < 0) {
        printf("accept failed, %d, %drn", connfd, errno);
        CloseTcpSocket(sockfd);
        //outerFlag = 0;
        }
        printf("accept success, connfd = %d !rn", connfd);
        // inet_ntoa:网络地址转换成“.”点隔的字符串格式。ntohs:16位数由网络字节顺序转换为主机字节顺序。
        printf("client addr info: host = %s, port = %drn", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));

        int innerFlag = 1;
        // 接收消息,然后发送回去
        while (innerFlag) {
        // 后续 收、发 都在 表示连接的 socket 上进行;
        // 在新的Socket文件描述上接收信息.
        retval = recv(connfd, request, sizeof(request), 0);
        if (retval < 0) {
            printf("recv request failed, %ld!rn", retval);
            innerFlag = 0;
        } else if (retval == 0) {
            // 对方主动断开连接
            printf("client disconnected!rn");
            innerFlag = 0;
        } else {
            //printf("recv request{%s} from client done!rn", request);
            // 发送数据

            printf("cc = %d %d %d \r\n",request[0],request[1],request[2]);

            if (retval <= 0) {
            printf("send response failed, %ld!rn", retval);
            innerFlag = 0;
            }

            if(retval == 3 &&  request[0] == -86)
            {
                if(request[1] == 0x00){
                    retval = send(connfd, "aaok", strlen("aaok"), 0);
                }
                if(request[1] == 0x01)
                {
                    switch (request[2])
                    {
                    case 1: car_forward();break;
                    case 2: car_right();break;
                    case 3: car_backward();break;
                    case 4: car_left();break;
                    case 0: car_stop();break;
                    }
                }else if(request[1] == 0x02)
                {
                    custom(((unsigned char)request[2])*11+500);
                }
            }

            //printf("send response{%s} to client done!rn", request);

            // 清空缓冲区
            memset(&request, 0, sizeof(request));
        }
        if(innerFlag == 0)
        {
            DisconnectTcpSocket(connfd);
            //outerFlag = 0;
        }

    }

    CloseTcpSocket(sockfd);
    }
}

void *TcpServerTask(void *arg) {

    (void)arg;

    // 先定义两个Wifi监听器,一个连接改变、一个状态改变
    WifiEvent eventListener = {
    .OnWifiConnectionChanged = OnWifiConnectionChanged,
    .OnWifiScanStateChanged = OnWifiScanStateChanged
    };

    // 等待10个系统Ticks。每个ticks多少个us,计算方式= 1000 * 1000 / osKernelGetTickFreq()
    osDelay(10);

    // 注册监听器
    WifiErrorCode errCode = RegisterWifiEvent(&eventListener);
    printf("RegisterWifiEvent: %drn", errCode);

    // 设置Wifi热点信息
    WifiDeviceConfig apConfig = {};
    strcpy(apConfig.ssid, "PDCN");
    strcpy(apConfig.preSharedKey, "1234567888");
    apConfig.securityType = WIFI_SEC_TYPE_PSK;

    int netId = -1;

    // 启用Wifi
    errCode = EnableWifi();
    printf("EnableWifi: %drn", errCode);
    osDelay(10);

    // 设置Wifi热点配置信息,返回生成的网络Id-netId。
    errCode = AddDeviceConfig(&apConfig, &netId);
    printf("AddDeviceConfig: %drn", errCode);

    // 根据网络Id连接到Wifi热点
    g_connected = 0;
    errCode = ConnectTo(netId);
    printf("ConnectTo(%d): %drn", netId, errCode);
    // 未连接完成,则一直等待。g_connected状态会在事件中设置。
    while (!g_connected) {
    osDelay(10);
    }
    printf("g_connected: %drn", g_connected);
    osDelay(50);

    // 联网业务开始,找到netifname=wlan0的netif。
    struct netif* iface = netifapi_netif_find("wlan0");
    if (iface) {
    // 启动DHCP客户端,获取IP地址
    err_t ret = netifapi_dhcp_start(iface);
    printf("netifapi_dhcp_start: %drn", ret);
    // 等待DHCP服务器反馈给予地址
    osDelay(300);
    // 执行线程安全的网络方法,第二个参数是voidFunc,第三个参数是errFunc。如果没有errFunc,那么就执行voidFunc。
    // netifapi_dhcp_start/netifapi_dhcp_stop等都是调用的netifapi_netif_common方法。
    // dhcp_clients_info_show显示信息
    /*
    server :
        server_id : 192.168.43.1
        mask : 255.255.255.0, 1
        gw : 192.168.43.1
        T0 : 3600
        T1 : 1800
        T2 : 3150
    clients <1> :
        mac_idx mac             addr            state   lease   tries   rto
        0       b4c9b9af69f8    192.168.0.10   10      0       1       2
    */
    ret = netifapi_netif_common(iface, dhcp_clients_info_show, NULL);
    printf("netifapi_netif_common: %drn", ret);
    }

    TcpServerHandler();

    // 联网业务结束,断开DHCP
    err_t ret = netifapi_dhcp_stop(iface);
    printf("netifapi_dhcp_stop: %drn", ret);

    // 断开Wifi热点连接
    Disconnect();

    // 移除Wifi热点的配置
    RemoveDevice(netId);

    // 关闭Wifi
    errCode = DisableWifi();
    printf("DisableWifi: %drn", errCode);
    osDelay(200);
}





void WifiSockets(void)
{

    osThreadAttr_t wifisocket;
    wifisocket.name = "TcpServerTask";
    wifisocket.attr_bits = 0U;
    wifisocket.cb_mem = NULL;
    wifisocket.cb_size = 0U;
    wifisocket.stack_mem = NULL;
    wifisocket.stack_size = 10240;
    wifisocket.priority = 25;

    if (osThreadNew(TcpServerTask, NULL, &wifisocket) == NULL) {
        printf("[Ssd1306TestDemo] Falied to create TcpServerTask!\n");
    }
}
APP_FEATURE_INIT(WifiSockets);

⑥.编写主控制代码

路径:openharmony\applications\sample\wifi-iot\app\wificamera\robot_control.c

代码:

static char data[128] = "";
extern int connfd;

void *RobotCarTestTask(void* param)
{
    (void)param;
    float cmm = 0.0;
	printf("switch\r\n");
    while (1) {
        //custom((i%11)*100 + 1000);
        GetDistance(&cmm);

        sprintf(data,"{\"cm\":%f}",cmm);

        send(connfd, data, strlen(data), 0);//发送距离到APP
        //printf("\r\n cos = %d  cm =%f\r\n",i,cmm);
        osDelay(25); //延时 250ms
    }
}



void RobotCarDemo(void)
{
    osThreadAttr_t attr;
    attr.name = "RobotCarTestTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = 25;

    if (osThreadNew(RobotCarTestTask, NULL, &attr) == NULL) {
        printf("[Ssd1306TestDemo] Falied to create RobotCarTestTask!\n");
    }

}
APP_FEATURE_INIT(RobotCarDemo);

⑦.编写编译描述文件

路径:openharmony\applications\sample\wifi-iot\app\wificamera\BUILD.gn

代码:

static_library("car_camera") {
    sources = [
        "robot_l9110s.c",
        "robot_sg90.c",
        "robot_control.c",
        "robot_hcsr04.c",
        "wifi_sockets.c",
    ]

    deps =[
    ]

    include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/kal/cmsis",
        "//base/iot_hardware/peripheral/interfaces/kits",
        "//device/hisilicon/hispark_pegasus/hi3861_adapter/hals/communication/wifi_lite/wifiservice",
        "//device/hisilicon/hispark_pegasus/hi3861_adapter/kal",
        "//device/hisilicon/hispark_pegasus/sdk_liteos/third_party/lwip_sack/include",
        "//foundation/communication/wifi_lite/interfaces/wifiservice"
    ]
}

⑧.加入编译

路径:openharmony\applications\sample\wifi-iot\app\BUILD.gn

代码:

import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
    features = [
        "wificamera:car_camera"
    ]
}

复制

⑨.编译

1).设置编译路径
hb set
.(英文字符)
2).选择wifiiot_hispark_pegasus
3).执行编译
hb build -f

4).输出路径

openharmony\out\hispark_pegasus\wifiiot_hispark_pegasus

⑩.烧录

参考烧录:https://ost.51cto.com/posts/11118

4、ESP32_CAM代码分析

#include "esp_camera.h"
#include <WiFi.h>
#define CAMERA_MODEL_AI_THINKER // Has PSRAM
#include "camera_pins.h"
const char* ssid = "PDCN";
const char* password = "1234567888";
void startCameraServer();
void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println();
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  if(psramFound()){
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

#if defined(CAMERA_MODEL_ESP_EYE)
  pinMode(13, INPUT_PULLUP);
  pinMode(14, INPUT_PULLUP);
#endif

  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  sensor_t * s = esp_camera_sensor_get();
  if (s->id.PID == OV3660_PID) {
    s->set_vflip(s, 1); // flip it back
    s->set_brightness(s, 1); // up the brightness just a bit
    s->set_saturation(s, -2); // lower the saturation
  }
  s->set_framesize(s, FRAMESIZE_QVGA);

#if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM)
  s->set_vflip(s, 1);
  s->set_hmirror(s, 1);
#endif

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  startCameraServer();

  Serial.print("Camera Ready! Use 'http://");
  Serial.print(WiFi.localIP());
  Serial.println("' to connect");
}

void loop() {
  delay(10000);
}

5、flask代码分析

#!/usr/bin/env python
import flask
import base64
import requests

# Create the application.
APP = flask.Flask(__name__)
image_url = "http://192.168.0.154/capture"
@APP.route('/')
def index():
    file = requests.get("http://192.168.0.154/capture")
    #print(file.status_code)
    s = base64.b64encode(file.content)
    #print(s.decode('ascii'))
    return ("data:image/jpg;base64,"+s.decode('ascii'))

if __name__ == '__main__':
    APP.run()

四、功能测试

1、实时图传效果

#基于DAYU200开发一个好玩的图传智能小车--demo样例#-鸿蒙开发者社区

2、实现舵机控制摄像头转动方向

#基于DAYU200开发一个好玩的图传智能小车--demo样例#-鸿蒙开发者社区

#基于DAYU200开发一个好玩的图传智能小车--demo样例#-鸿蒙开发者社区

3、模拟倒车雷达功能

#基于DAYU200开发一个好玩的图传智能小车--demo样例#-鸿蒙开发者社区

#基于DAYU200开发一个好玩的图传智能小车--demo样例#-鸿蒙开发者社区

4、实现控制小车行驶

请跳转到看视频
小车展示视频

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
openharmony_camera_car.zip 8.99M 120次下载
已于2022-5-30 15:58:50修改
25
收藏 14
回复
举报
5条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

这实现的功能挺厉害的。

回复
2022-5-30 17:45:18
Soon_L
Soon_L

高产,厉害

回复
2022-5-30 19:58:47
Hello_Kun
Hello_Kun

6666

回复
2022-5-31 09:22:36
longlong899
longlong899

简直是保姆级的教程啊!

回复
2022-5-31 10:23:32
牧南牧南
牧南牧南

内容赞👍

回复
2022-6-6 18:53:32
回复
    相关推荐