#DAYU200体验官#HelloKun开源鸿蒙车机系统OHCar

Posted 开源基础软件社区官方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#DAYU200体验官#HelloKun开源鸿蒙车机系统OHCar相关的知识,希望对你有一定的参考价值。

@toc

0. OHCar ?

想象一下,现在你正忙完一天的工作准备下班回家,担心车辆能源不足?天气太热或太冷?于是在走到楼下停车位上的Dream Car前,拿出鸿蒙手机打开车辆专属的管家APP,提前检测剩余能量百分比,打开车载空调。到达车前的你不愿意掏出钥匙,顺手用手机碰一碰车门,只需点击弹出窗口中的解锁按钮即可进入车中。

坐进驾驶舱,OHCar又一次为你开启贴心服务。加载页面中红黑经典表盘与激情澎湃背景视频,短暂而又丝滑的过度只为让你忘却一天的疲惫。进入系统后,手指轻轻一戳,一键唤醒你的DreamCar。

出发前,你打算先来一首音乐,或者刷一段冰冰的甜美笑容,又或者看一段Jay的最新MV,这些,OHCar都能给你。

当然,安全出行第一步。嫌弃屏幕太暗?打开设置,亮度一步到位。终于,你已经释放掉50%的疲惫感,准备一脚油门回到家中。别急,马路拥挤,实时导航能不能有? 当然,OHCar一直为你保驾护航。

下班回家的路上,一切操作丝般顺滑,你享受着空调,听着Jay的音乐,踩着油门一路向北!

便捷而又炫酷的智慧生活极致体验,由OpenHarmony为你打造。再想象一下,通过OHCar,对话家里的MRobot,为你开启下一段贴心服务!

1. OHCar项目简介

1.1 项目说明

  • Dayu200体验官活动之初决定做车载中控,设想是在汽车模型中实现车辆信息监测、无钥匙解锁、车辆控制能力、导航地图以及影音娱乐等功能,并配备移动端车辆管家。OHCar便是该设想的落地,基于现有开源鸿蒙的系统能力,基本实现了上述功能,只需手机碰一碰解锁车辆,还可在APP中控制车载空调、查看剩余电量、获取车辆位置等信息,进入车辆后,可在dayu200上操控车辆,仪表区、车载APP、系统设置一应俱全。
  • 从技术角度而言,车机中使用ArkUI框架中的ets语言开发,结合条件渲染,让Video、Web等组件实现同框显示,自定义数据类实现动画;智能车控硬件方面,dayu200做车辆中控,再使用两个hi3861 iot核心板、一个Arduino Nano协同实现车辆控制,电源测量模块获取电量,GPS模块测量位置信息,笔记本风扇模拟车载空调,为实现影音功能,使用音频解码与放大板实现音响。总的来说,OHCar软硬件均属鸿蒙生态,展示出开源鸿蒙在车载系统中极具潜力。本文从OHCar的功能角度分解说明项目,并在其中讲解使用到的关键技术,更多技术细节移步Gitee仓库。demo视频OHCar视频
  • 注:
    dayu200: OH系统版本:OpenHarmony3.1Release ;IDE: 3.0.0.900 ; APP:ArkUI -ets
    hi3861: OpenHarmony 1.0.1 Release ,C语言
    车管家(手机端): HarmonyOS API 6 ,JS语言

    1.2 OHCar软硬件简介

    OHCar项目框架组成如下图,dayu200作为上层的控制终端,提供车辆仪表信息显示、影音娱乐等服务,使用TCP传输驾驶员的操控指令;②号hi3861接收到数据后进行预处理(如获取车辆温湿度,车内烟雾监测),非本地指令则通过uart转给车辆底层的mcu;①号hi3861则提供无钥匙解锁、电量、定位的信息获取、车载空调操控等功能。底层mcu直接负责车辆的操控,如电机控制,实时性强,同时也方便实现软硬件隔离。各模块分工明确但又紧密配合。所有各模块(除dayu200外)均安装于经典2003款 Ferrari Enzo 模型中,只为直观展示上述功能。

2. OHCar车载系统实现

以APP形式模拟OHCar车载系统,APP基于ArkUI框架中的est语言开发,运行在dayu200之上,APP包括系统启动页、操控UI页、系统设置页、本地视频播放页。启动页是模拟车载系统开机;操控UI页面包含系统展示窗、车载APP(音乐、地图、Blibili)、仪表盘、车辆操控。系统设置页目前支持屏幕亮度调节功能;本地视频播放页用于播放视频文件,提高影音娱乐功能。
车载系统模拟APP架构总结如下图:

打开DevEco Studio 3.0.0.900, 新建一个基于ets的工程,API为8。详情见环境搭建。下面对OHCar项目中的关键功能模块的实现进行说明。

2.1 系统启动页面

系统启动页模拟车机开机启动画面,使用到Video组件展示加载视频,Canvas绘制表盘,结合定时器实现指针摆动,最后使用Stack容器实现覆盖效果。关键代码如下,具体实现可参考这篇帖子首页aito视频&Canvas绘制仪表盘

Stack()
     
          Video(
            src: this.srcs,
            previewUri: this.previewUris,
            currentProgressRate: this.currentProgressRates,
            controller: this.controller
          ).width(100%).height(100%)
            .objectFit(ImageFit.Cover)
            .autoPlay(true)
            .controls(this.controlsss)
            .onFinish(() => 
              console.error(onFinish);
             router.push(url:pages/gauge)
            )
          // 仪表盘
          Row( space: 0 ) 
          //油门表
          MyGauge()
         Column() 
              Canvas(this.car_gauge)
                .width(45%)
                .height(20%)
                .backgroundColor(#000000)
                .onReady(() => 
                  //表环-车速
                 this.car_gauge.clearRect(-100, -100, 600, 600);
                 this.car_gauge.beginPath()
                 this.car_gauge.translate(0, 0)
                 this.car_gauge.shadowBlur = 30
                 this.car_gauge.shadowColor = this.car_gauge_col
                 this.car_gauge.arc(this.gauge_speed_x, this.gauge_speed_y, 100, 0, 6.28)
                 this.car_gauge.fillStyle = black
                 this.car_gauge.fill()
                 this.car_gauge.closePath()
                  //数字环、指针 操作类似,略过
                //车速
             Text(this.car_velocity+" KM/H")
                .fontSize(40).height(40).fontStyle(FontStyle.Italic).textAlign(TextAlign.Center)
                .backgroundColor(black).fontColor(white)
            
         //电量表
            Gauge( value: this.fuel_value, min: 0, max: 120 )
              .startAngle(240)
              .endAngle((this.fuel_value))
              .colors([[0x5BA854, 0.5],[0xCFB53B, 0.5],[0xF01020, 0.5] ])
              .strokeWidth(30)
              .width(120)
              .height(120)
              .margin(top:30)
            
        
    

2.2 操控页面——系统展示窗

操控UI页面的系统展示窗模拟车辆的中控屏,用于显示车辆状态、内置app。使用条件渲染将自定义component(音乐、地图、Blibili)展示出来。内置车载APP用web组件模拟(dayu200 联网后可实现网页加载。)
关键实现代码如下:

Column( space:0 ) 
            if(this.display_flag==1) 
              Video(
                src: this.srcs,
                currentProgressRate: this.currentProgressRates,
                controller: this.controller
              )
                .width(100%)
                .height(80%)
                .objectFit(ImageFit.Fill)
                .autoPlay(this.autoPlays)
                .controls(this.controlsss)
                .onStart(() => 
                  console.error(onStart);
                )
            
            else if(this.display_flag==2)
            
              Column()
              
                qqmusic()
              .height(80%).alignItems(HorizontalAlign.Center)
            
            else if(this.display_flag==3)
            
                Column()
                
                  amap()
                .height(80%).alignItems(HorizontalAlign.Center)
            
            else if(this.display_flag==4)
            
                Column()
                
                  Bilibili()
                .height(80%).alignItems(HorizontalAlign.Center)

           
//web实现如下:
@Component
struct Bilibili 
  @State message: string = Hello World
  controller: WebController = new WebController();
  build() 
      Column()
      
        Web( src: https://www.bilibili.com/, controller: this.controller )
      
      .width(100%)
      .height(100%)
    .backgroundColor(black)
  

2.3 操控页面——仪表盘


车辆仪表区用于模拟车机的仪表盘,从左到右依次用于展示能源余量、时速、油门大小。其中时速表盘、油门大小可随操控按钮(2.4节介绍)动态加载。时速表盘使用Canvas画布实现,油门表使用Gauge组件实现。具体实现可参考这篇帖子首页aito视频&Canvas绘制仪表盘

2.4 操控页面——车辆控制

车辆控制区用于模拟车辆实际操控,如一键启动、驾驶(油门、方向、刹车)、开门、灯光、甚至是升降Dream Car的尾翼。UI使用Buttom、Image基础组件布局,实现比较简单。控件触发事件后,调用Socket接口,将控制量发送到目标ip中(hi3861中),下面代码举例说明如何将一键启动触发后将消息通过socket接口发送出去,关于Socket tcp通信实现可参考该文档Socket连接

  tcpSend() 
    tcp.getState().then((data) => 
      if (data.isConnected) 
        //发送消息
        tcp.send(
           data: this.message_send, 
        ).then(() => 
          prompt.showToast(message:"send message successful")
        ).catch((error) => 
          prompt.showToast(message:"send failed")
        )
       else 
        prompt.showToast(message:"tcp not connect")
      
    )
  
 //一键启动
          Button( type: ButtonType.Circle, stateEffect: true ) 
            Image($r(app.media.engine)).objectFit(ImageFit.Contain)
          
          .width(90)
          .height(90)
          .margin( top: 1, left: 80 )
          .backgroundColor(this.engine_btn_col)
          .onClick(() => 
            this.car_gauge_col = white
            this.srcs = $r(app.media.ferrari_start)
            this.controller.start()
            this.click_times += 1
            this.tcpConnect()
            if (this.click_times % 2 != 0) 
              this.engine_btn_col = 0x32c5ef
              this.update_canvas();
            
            else
            
              this.engine_btn_col = 0xCBD3D0
              this.click_times = 0;
            
            prompt.showToast(
              message: "Start Engine:" + this.car_velocity,
            )
          )

2.5 系统设置与视频播放

系统设置功能页面主要使用brightness接口调节屏幕亮度。另外,还使用class自定义车辆信息类,为动态展示车辆提供参考。视频播放使用Video组件实现,音频的输出经过车载的音频放大器播放,关键代码如下:

import brightness from @ohos.brightness;
 Row()
        
          Text(亮度).fontColor(blue).fontSize(35).width(10%).borderRadius(30).margin(top:10,left:30)

          Slider(
            value: this.brightness,
            min: 100,
            max: 255,
            step: 1,
            style: SliderStyle.OutSet
          )
            .width(80%).height(100%) .blockColor(blue).trackColor(Color.Black)    
            .onChange((value: number, mode: SliderChangeMode) => 
              this.brightness = value
              brightness.setValue(this.brightness);
              console.info(value: + value + mode: + mode.toString())
            ).width(75%)
          Text(this.brightness.toFixed(0)).fontSize(30).width(15%).fontColor(blue)
        .height(10%).backgroundColor(white)

3. OHCar车辆管家介绍

智能时代,车载系统不应该仅仅是独立的系统,基于OpenHarmony的OHCar可为用户提供优质全面的服务。车辆管家运行于HarmonyOS 2.0 的移动端,依托NFC短距通信协议,通过碰一碰的交互方式,将手机和OHCar连接起来。然后通过手机端的原子化服务能力,快速完成配网、连接OHCar,提供无钥匙开门、监测车辆信息的服务。 类似的开发案例可参考本人这篇教程 碰一碰系列分享总贴

3.1 UI开发

UI布局使用js开发,具体方式参考该文档 JS开发APP。车辆管家UI直观,展示信息如下图,电量、位置信息的获取来自于hi3861端,空调、车门控制消息也发送至hi3861端。

3.2 碰一碰与数据传输

车辆管家的技术核心是调用JS接口完成设备配网、消息发送。获取设备ID、发送消息接口核心代码如下(可参考本贴JS通信接口):

//需引入 import getApp from ../../common.js;  
 sendMessage()
    
        var message = this.app_msg;
        let commonInfo = 
            sessionId: getApp(this).ConfigParams.deviceInfo.sessionId
        ;
        getApp(this).NetConfig.sendMessage(commonInfo, message,(result)=>
            if(result.code ==0)   prompt.showToast(message:发送成功)
            elseprompt.showToast(message:发送失败)
            );
    ,

4. OHCar南向开发

南向开发分为三部分,分别对应车载系统UI南向开发、车辆管家APP南向开发、车辆硬件实时控制系统实现(电机、灯光等)

4.1 车载系统协同

车载系统协同依靠dayu200与hi3861之间的TCP通信,南向开发也主要是针对该通信数据进行处理,hi3861端作为TCP服务器,接收dayu200发送的操作指令。hi3861也可采集车辆温湿度、烟雾信息,有需求可上报至dayu200端。如何建立二者之间的TCP连接可参考本人这篇教程 #DAYU200#体验官Hi3861与dayu200通信 。下图是南向功能框架。

下面给出将dayu200数据发送值车载mcu、将温湿度烟雾发送至dayu200的关键代码:

while (1)
        
            AHT20_Calibrate();
            AHT20_StartMeasure();
            AHT20_GetMeasureResult(&EnvData.temp_val, &EnvData.humi_val);
            EnvData.ppm_val = Get_MQ2_PPM();
            if ((ret = recv(new_fd, recvbuf, sizeof(recvbuf), 0)) == -1)
            
                printf("recv error \\r\\n");
            
            printf("recv :%s\\r\\n", recvbuf);
            const unsigned char msg_cmd = recvbuf[0];
            //hi_uart_write(1, &msg_cmd, 1);
            UartWrite(1, &msg_cmd, 1);
            if (msg_cmd == x)
            
                GpiosetOutputVal(WIFI_IOT_IO_NAME_GPIO_14, 0);
                hi_udelay(80000);
                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_14, 1);
            
            if (msg_cmd == y)
            
                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_8, 0);
                hi_udelay(80000);
                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_8, 1);
            
            Float2String(buf, EnvData.humi_val, 2);
            if ((ret = send(new_fd, buf, strlen(buf) + 1, 0)) == -1)
            
                perror("send : ");
            
            Float2String(buf, EnvData.ppm_val, 2);
            if ((ret = send(new_fd, buf, strlen(buf) + 1, 0)) == -1)
            
                perror("send : ");
            
            Float2String(buf, EnvData.ppm_val, 2);
            if ((ret = send(new_fd, buf, strlen(buf) + 1, 0)) == -1)
            
                perror("send : ");
            
            GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_14, 0);
            GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_8, 0);
            sleep(1);
        

4.2 车辆管家协同

车载系统协同依靠移动端NFC短距通信,碰一碰车门上的NFC标签后,启动原子化服务后与hi3861通信,hi3861将GPS模块采集位置信息、电压采集模块采集汽车电量传输至车辆管家APP端;同时也可接收开门指令,实现无钥匙解锁。该部分南向工程架构如下(详细见附件):

NAN配网关键接口如下,具体参考本人这篇教程设备配网

include:
│   ├── netcfg.h   // 无感配网注册相关接口
│   ├── network_config_service.h //无感配网相关头文件。
libs:
├── libs
│   ├── libhilinkadapter_3861.a // 无感配网相关库文件。
│   └── libnetcfgdevicesdk.a // 无感配网相关库文件。
src:
    ├── netcfg.c // NAN相关操作和联网动作
const char *g_ssid = "OHCar     ";
const char *g_pinCode = "11111111";
const char *g_productId = "1";
const char *g_sn = "0123/.,.,4567890123450123456789012345";
···
devInfo[0].key = "productId";
devInfo[1].key = "sn";
devInfo[0].value = g_productId;
devInfo[1].value = g_sn;
ret = StartNetCfg(devInfo, DEVICE_INFO_NUM, NETCFG_SOFTAP_NAN); //SoftAP and NAN模式 

//上报电量、位置信息、控制模拟空调
    if (strcmp(app_msg, "turn off air") == 0)
    
        IoTGpioSetOutputVal(FAN_IO1, IOT_GPIO_VALUE0);
        IoTPwmStart(1, 0, 80000);
        printf("turn off air \\r\\n");
        app_msg[0] = 9;
        return;
    

    if (strcmp(app_msg, "car location") == 0)
    
        // Bluetooth_read(location2app, 18)   //室内GPS信号弱
        strncpy(location2app, "N:110.20  E:19.220 addr", 18);
        SendRawData(&location2app); // 将消息发到FA
        printf("car location\\r\\n");
        app_msg[0] = 9;
        return;
    

    if (strcmp(app_msg, "car fuel") == 0)
    
        fuel_val = GetVoltage();
        float percent_vol = 1000 * fuel_val / FULL_FUEL;
        Float2String(percent_vol, &temp_str, 2);
        strncpy(fuel2app, temp_str, 5);
        SendRawData(&fuel2app); // 将消息发到FA
        printf("get car fuel \\r\\n");
        app_msg[0] = 9;
        return;
    

4.3 车辆控制


车辆电机、车门、尾翼以及灯光控制使用另一块io接口多一些的mcu实现(5组灯光、6个舵机),mcu实时接收两块hi3861的控制指令,完成最底层的控制。从车载系统到车辆管家,再到hi3861,最终到mcu,遵循的报文如下,有助于了解项目:

typedef enum MSG_CMD 
  MOVE_GO = a,
  MOVE_BACK,
  MOVE_LEFT,
  MOVE_RIGHT, //移动
  OPEN_LEFT_DOOR,
  CLOSE_LEFT_DOOR,
  OPEN_RIGHT_DOOR,
  CLOSE_RIGHT_DOOR,//车门
  SPOILER_UP,
  SPOILER_DOWN,  //尾翼
  MOVE_GO_LIGHT,
  MOVE_BACK_LIGHT,
  WARRING_LIGHT_ON,
  WARRING_LIGHT_OFF
;

总结

从技术上讲,实际的车载系统比文中说的要复杂、严苛很多。不过openHarmony作为万物互联时代下的产物,未来用于车载系统还是值得期待的。借此项目可了解openHarmony以及在dayu200上的开发方式,学习ARkUI框架、est语言。
都说田家少闲月,五月人倍忙,自从疫情之后很多事被打乱,一到窗口期就是“5月",不知不觉dayu200体验官活动也接近尾声,感谢平台的支持与各位老师的直播分享,让我天马行空想法得以实现。

源码分享:

下载地址:https://ost.51cto.com/resource/2161

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

51CTO 开源基础软件社区

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

以上是关于#DAYU200体验官#HelloKun开源鸿蒙车机系统OHCar的主要内容,如果未能解决你的问题,请参考以下文章

DAYU200升级最新的OpenHarmony系统,一起来玩开源鸿蒙呀!

DAYU200升级最新的OpenHarmony系统,一起来玩开源鸿蒙呀!

DAYU200升级最新的OpenHarmony系统,一起来玩开源鸿蒙呀!

#DAYU200体验官#MPPT光伏发电项目 DAYU200Hi3861华为云IotDA

#DAYU200体验官# OpenHarmony3.2的编译烧录

#DAYU200体验官# OpenHarmony标准系统运行docker软件