1. 項(xiàng)目背景
“軟件定義汽車”,目前汽車的智能化主要體現(xiàn)在自動(dòng)駕駛、智能座艙、AI等方面。而人機(jī)交互技術(shù)則主要應(yīng)用在智能座艙上,所謂智能座艙,指的是通過(guò)對(duì)汽車內(nèi)部的乘坐空間進(jìn)行改造,汽車和人能夠進(jìn)行語(yǔ)音等多模態(tài)交互,實(shí)現(xiàn)汽車和人的自然交流。
無(wú)論完全自動(dòng)駕駛何時(shí)到來(lái),人與汽車都將面臨長(zhǎng)期共駕的未來(lái)。目前,智能座艙正處于蓬勃發(fā)展的時(shí)期。據(jù)ICVTank預(yù)測(cè),中國(guó)智能座艙市場(chǎng)將在2025年達(dá)到1030億元規(guī)模。在全球汽車市場(chǎng)進(jìn)入下行通道與存量競(jìng)爭(zhēng)時(shí)代的大背景下,對(duì)座艙智能化需求的滿足將會(huì)成為車企競(jìng)相爭(zhēng)奪的下一個(gè)差異化重點(diǎn)。
為了更好地理解智能座艙,今天通過(guò)DAYU200體驗(yàn)官活動(dòng),來(lái)模擬智能座艙的實(shí)現(xiàn)。通過(guò)汽車模型的方式,來(lái)實(shí)現(xiàn)車輛控制、信息監(jiān)測(cè)、電子車鑰匙、碰一碰、以及影音娛樂(lè)等功能的Demo演示。并模擬演示手機(jī)應(yīng)用層面的車輛管家程序。OHCar的實(shí)現(xiàn)是通過(guò)基于OpenHarmony 3.1的能力來(lái)實(shí)現(xiàn)了上述一些模塊功能的。
從技術(shù)實(shí)現(xiàn)來(lái)看,項(xiàng)目用ArkUI框架中ets語(yǔ)言來(lái)進(jìn)行開(kāi)發(fā)。讓Video、Web等交互組件通過(guò)條件渲染的方式在同框進(jìn)行顯示。南向方面,中控是通過(guò)DAYU200支持的,同時(shí),我們還用到了hi3861 iot核心板、Arduino Nano協(xié)同支持對(duì)模擬跑車的控制、電源和位置數(shù)據(jù)的測(cè)量,模擬車內(nèi)空調(diào)系統(tǒng)的調(diào)節(jié),以及模擬車內(nèi)音響的播放功能。
2. 系統(tǒng)架構(gòu)述本項(xiàng)目的架構(gòu)圖如下:DAYU200作為上層車載系統(tǒng)的控制端,通過(guò)②號(hào)hi3861來(lái)獲取環(huán)境監(jiān)測(cè)數(shù)據(jù),比如:溫濕度信息、煙霧監(jiān)測(cè)信息等。然后通過(guò)車輛儀表信息顯示界面進(jìn)行呈現(xiàn)。DAYU200和②號(hào)hi3861通過(guò)TCP傳輸?shù)姆绞竭M(jìn)行通信。②號(hào)hi3861還會(huì)把監(jiān)控到的環(huán)境信息,以及車載系統(tǒng)下達(dá)的一些指令,通過(guò)Uart接口傳遞給車輛底層孔子單元MCU。①號(hào)hi3861模擬智能車鑰匙,所以關(guān)于車鑰匙的一些信號(hào),比如開(kāi)鎖人身份信息,開(kāi)鎖位置信息等,同樣通過(guò)Uart接口傳遞給車輛底層控制MCU單元。底層mcu會(huì)操控整體車的狀態(tài),來(lái)實(shí)現(xiàn)車門打開(kāi)關(guān)閉,發(fā)動(dòng)機(jī)啟動(dòng)、車內(nèi)的燈光、音響、座椅等等設(shè)備動(dòng)作。兩塊Hi3861都安裝在小車模型中。3. 車載系統(tǒng)界面實(shí)現(xiàn)
小車的車載部分,通過(guò)DAYU200上的液晶屏幕進(jìn)行模擬顯示。開(kāi)發(fā)通過(guò)ArkUI框架中的est語(yǔ)言。車載系統(tǒng)的界面分為如下幾個(gè)關(guān)鍵部分:系統(tǒng)啟動(dòng)、UI操控、系統(tǒng)設(shè)置、影音播放。通過(guò)系統(tǒng)啟動(dòng),來(lái)模擬車載系統(tǒng)的開(kāi)機(jī);通過(guò)UI操控來(lái)模擬車載系統(tǒng)的數(shù)字儀表盤,音樂(lè)播放、地圖導(dǎo)航等界面顯示區(qū)。通過(guò)系統(tǒng)設(shè)置來(lái)模擬調(diào)節(jié)屏幕亮度。通過(guò)影音播放頁(yè)來(lái)模擬播放音視頻文件,實(shí)現(xiàn)影音娛樂(lè)功能。
車載系統(tǒng)界面框架如下圖所示:
下面對(duì)OHCar項(xiàng)目中的關(guān)鍵功能模塊的實(shí)現(xiàn)進(jìn)行說(shuō)明。
3.1系統(tǒng)啟動(dòng)頁(yè)面
系統(tǒng)啟動(dòng)頁(yè)模擬車機(jī)開(kāi)機(jī)啟動(dòng)畫面,使用到Video組件展示加載視頻,Canvas繪制表盤,結(jié)合定時(shí)器實(shí)現(xiàn)指針擺動(dòng),最后使用Stack容器實(shí)現(xiàn)覆蓋效果。關(guān)鍵代碼如下:
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(() => {
//表環(huán)-車速
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()
//數(shù)字環(huán)、指針 操作類似,略過(guò)
//車速
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})
}
}
}
3.2操控頁(yè)面——系統(tǒng)展示窗
操控UI頁(yè)面的系統(tǒng)展示窗模擬車輛的中控屏,用于顯示車輛狀態(tài)、內(nèi)置app。使用條件渲染將自定義component(音樂(lè)、地圖、Blibili)展示出來(lái)。內(nèi)置車載APP用web組件模擬(DAYU200 聯(lián)網(wǎng)后可實(shí)現(xiàn)網(wǎng)頁(yè)加載。)
關(guān)鍵實(shí)現(xiàn)代碼如下:
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實(shí)現(xiàn)如下:
struct Bilibili {
'Hello World'
message: string = controller: WebController = new WebController();
build() {
Column()
{
Web({ src: 'https://www.bilibili.com/', controller: this.controller })
}
.width('100%')
.height('100%')
.backgroundColor('black')
}
}
3.3 操控頁(yè)面——儀表盤
車輛儀表區(qū)用于模擬車機(jī)的儀表盤,從左到右依次用于展示能源余量、時(shí)速、油門大小。其中時(shí)速表盤、油門大小可隨操控按鈕(2.4節(jié)介紹)動(dòng)態(tài)加載。時(shí)速表盤使用Canvas畫布實(shí)現(xiàn),油門表使用Gauge組件實(shí)現(xiàn)。
3.4 操控頁(yè)面——車輛控制
車輛控制區(qū)用于模擬車輛實(shí)際操控,如一鍵啟動(dòng)、駕駛(油門、方向、剎車)、開(kāi)門、燈光、甚至是升降Dream Car的尾翼。UI使用Buttom、Image基礎(chǔ)組件布局,實(shí)現(xiàn)比較簡(jiǎn)單??丶|發(fā)事件后,調(diào)用Socket接口,將控制量發(fā)送到目標(biāo)ip中(hi3861中),下面代碼舉例說(shuō)明如何將一鍵啟動(dòng)觸發(fā)后將消息通過(guò)socket接口發(fā)送出去:
tcpSend() {
tcp.getState().then((data) => {
if (data.isConnected) {
//發(fā)送消息
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"})
}
})
}
//一鍵啟動(dòng)
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,
})
})
3.5 系統(tǒng)設(shè)置與視頻播放系統(tǒng)設(shè)置功能頁(yè)面主要使用brightness接口調(diào)節(jié)屏幕亮度。另外,還使用class自定義車輛信息類,為動(dòng)態(tài)展示車輛提供參考。視頻播放使用Video組件實(shí)現(xiàn),音頻的輸出經(jīng)過(guò)車載的音頻放大器播放,關(guān)鍵代碼如下:
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')
4.6 碰一碰與數(shù)據(jù)傳輸車輛管家的技術(shù)核心是調(diào)用JS接口完成設(shè)備配網(wǎng)、消息發(fā)送。獲取設(shè)備ID、發(fā)送消息接口核心代碼如下:
//需引入 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:'發(fā)送成功'})}
else{prompt.showToast({message:'發(fā)送失敗'})}
});
},
5.OHCar南向開(kāi)發(fā)南向開(kāi)發(fā)分為三部分,分別對(duì)應(yīng)車載系統(tǒng)UI南向開(kāi)發(fā)、車輛管家APP南向開(kāi)發(fā)、車輛硬件實(shí)時(shí)控制系統(tǒng)實(shí)現(xiàn)(電機(jī)、燈光等)。
4.1 車載系統(tǒng)協(xié)同
車載系統(tǒng)協(xié)同依靠dayu200與hi3861之間的TCP通信,南向開(kāi)發(fā)也主要是針對(duì)該通信數(shù)據(jù)進(jìn)行處理,hi3861端作為TCP服務(wù)器,接收dayu200發(fā)送的操作指令。hi3861也可采集車輛溫濕度、煙霧信息,有需求可上報(bào)至dayu200端。下圖是南向功能框架。
下面給出將dayu200數(shù)據(jù)發(fā)送值車載mcu、將溫濕度煙霧發(fā)送至dayu200的關(guān)鍵代碼:
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
");
}
printf("recv :%s
", 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 車載系統(tǒng)協(xié)同
車載系統(tǒng)協(xié)同依靠移動(dòng)端NFC短距通信,碰一碰車門上的NFC標(biāo)簽后,啟動(dòng)原子化服務(wù)后與hi3861通信,hi3861將GPS模塊采集位置信息、電壓采集模塊采集汽車電量傳輸至車輛管家APP端;同時(shí)也可接收開(kāi)門指令,實(shí)現(xiàn)無(wú)鑰匙解鎖。該部分南向工程架構(gòu)如下:
NAN配網(wǎng)關(guān)鍵接口如下:
include:
│ ├── netcfg.h // 無(wú)感配網(wǎng)注冊(cè)相關(guān)接口
│ ├── network_config_service.h //無(wú)感配網(wǎng)相關(guān)頭文件。
libs:
├── libs
│ ├── libhilinkadapter_3861.a // 無(wú)感配網(wǎng)相關(guān)庫(kù)文件。
│ └── libnetcfgdevicesdk.a // 無(wú)感配網(wǎng)相關(guān)庫(kù)文件。
src:
├── netcfg.c // NAN相關(guān)操作和聯(lián)網(wǎng)動(dòng)作
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模式
//上報(bào)電量、位置信息、控制模擬空調(diào)
if (strcmp(app_msg, "turn off air") == 0)
{
IoTGpioSetOutputVal(FAN_IO1, IOT_GPIO_VALUE0);
IoTPwmStart(1, 0, 80000);
printf("turn off air
");
app_msg[0] = '9';
return;
}
if (strcmp(app_msg, "car location") == 0)
{
// Bluetooth_read(location2app, 18) //室內(nèi)GPS信號(hào)弱
strncpy(location2app, "N:110.20 E:19.220 addr", 18);
SendRawData(&location2app); // 將消息發(fā)到FA
printf("car location
");
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); // 將消息發(fā)到FA
printf("get car fuel
");
app_msg[0] = '9';
return;
}
4.3 車輛控制
車輛電機(jī)、車門、尾翼以及燈光控制使用另一塊io接口多一些的mcu實(shí)現(xiàn)(5組燈光、6個(gè)舵機(jī)),mcu實(shí)時(shí)接收兩塊hi3861的控制指令,完成最底層的控制。從車載系統(tǒng)到車輛管家,再到hi3861,最終到mcu,遵循的報(bào)文如下,有助于了解項(xiàng)目:
typedef enum MSG_CMD {
MOVE_GO = 'a',
MOVE_BACK,
MOVE_LEFT,
MOVE_RIGHT, //移動(dòng)
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
};
5. 項(xiàng)目實(shí)現(xiàn)效果想象一下,現(xiàn)在你正忙完一天的工作準(zhǔn)備下班回家,擔(dān)心車輛能源不足?天氣太熱或太冷?于是在走到樓下停車位上的Dream Car前,拿出手機(jī)打開(kāi)車輛專屬的管家APP,提前檢測(cè)剩余能量百分比,打開(kāi)車載空調(diào)。到達(dá)車前的你不愿意掏出鑰匙,順手用手機(jī)碰一碰車門,只需點(diǎn)擊彈出窗口中的解鎖按鈕即可進(jìn)入車中。
坐進(jìn)駕駛艙,OHCar又一次為你開(kāi)啟貼心服務(wù)。加載頁(yè)面中紅黑經(jīng)典表盤與激情澎湃背景視頻,短暫而又絲滑的過(guò)度只為讓你忘卻一天的疲憊。進(jìn)入系統(tǒng)后,手指輕輕一戳,一鍵喚醒你的DreamCar。
出發(fā)前,你打算先來(lái)一首音樂(lè),或者刷一段冰冰的甜美笑容,又或者看一段Jay的最新MV,這些,OHCar都能給你。
當(dāng)然,安全出行第一步。嫌棄屏幕太暗?打開(kāi)設(shè)置,亮度一步到位。終于,你已經(jīng)釋放掉50%的疲憊感,準(zhǔn)備一腳油門回到家中。別急,馬路擁擠,實(shí)時(shí)導(dǎo)航能不能有?當(dāng)然,OHCar一直為你保駕護(hù)航。
下班回家的路上,一切操作絲般順滑,你享受著空調(diào),聽(tīng)著Jay的音樂(lè),踩著油門一路向北!
便捷而又炫酷的智慧生活極致體驗(yàn),由OpenHarmony為你打造。再想象一下,通過(guò)OHCar,對(duì)話家里的MRobot,為你開(kāi)啟下一段貼心服務(wù)!
整個(gè)演示視頻如下:
6. 項(xiàng)目總結(jié)
從技術(shù)上講,實(shí)際的車載系統(tǒng)比文中說(shuō)的要復(fù)雜、嚴(yán)苛很多。不過(guò)OpenHarmony作為萬(wàn)物互聯(lián)時(shí)代下的產(chǎn)物,未來(lái)用于車載系統(tǒng)還是值得期待的。借此項(xiàng)目可了解OpenHarmony以及在DAYU200上的開(kāi)發(fā)方式,學(xué)習(xí)ARkUI框架、est語(yǔ)言。
都說(shuō)田家少閑月,五月人倍忙,自從疫情之后很多事被打亂,一到窗口期就是“5月",不知不覺(jué)DAYU200體驗(yàn)官活動(dòng)也接近尾聲,感謝平臺(tái)的支持與各位老師的直播分享,讓我天馬行空想法得以實(shí)現(xiàn)。
本文完寫在最后我們最近正帶著大家玩嗨OpenHarmony。如果你有好玩的東東,歡迎投稿,讓我們一起嗨起來(lái)!有點(diǎn)子,有想法,有Demo,立刻聯(lián)系我們:合作郵箱:zzliang@atomsource.org
原文標(biāo)題:玩嗨OpenHarmony:基于OpenHarmony的車機(jī)系統(tǒng)OHCar
文章出處:【微信公眾號(hào):開(kāi)源技術(shù)服務(wù)中心】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
-
開(kāi)源技術(shù)
+關(guān)注
關(guān)注
0文章
389瀏覽量
7955 -
OpenHarmony
+關(guān)注
關(guān)注
25文章
3727瀏覽量
16379
原文標(biāo)題:玩嗨OpenHarmony:基于OpenHarmony的車機(jī)系統(tǒng)OHCar
文章出處:【微信號(hào):開(kāi)源技術(shù)服務(wù)中心,微信公眾號(hào):共熵服務(wù)中心】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論