3

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

 2 years ago
source link: https://blog.51cto.com/harmonyos/5363438
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

推荐 原创

#基于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
#基于DAYU200开发一个好玩的图传智能小车--demo样例#_socket_02

三、代码介绍

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样例#_http_03

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

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

3、模拟倒车雷达功能

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

4、实现控制小车行驶

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

附件链接: https://ost.51cto.com/resource/2006

 想了解更多关于开源的内容,请访问:

 51CTO 开源基础软件社区

 https://ost.51cto.com/#bkwz

  • 打赏
  • 1
  • 1收藏
  • 1评论
  • 分享
  • 举报

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK