0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

為鴻蒙小車做一個(gè)遙控器

OpenHarmony技術(shù)社區(qū) ? 來源:OST開源開發(fā)者 ? 2022-12-26 09:56 ? 次閱讀

HarmonyOS 3.0 和 OpenHarmony 3.2 的支持下,TCP-socket 通信 API 已經(jīng)穩(wěn)定可控,今天我們做一個(gè)控制應(yīng)用來控制小車。

效果演示:

b0d57e74-8468-11ed-bfe3-dac502259ad0.gif

設(shè)計(jì)思路

運(yùn)行環(huán)境:HarmonyOS 3.0,OpenHarmony 3.2

b12540a8-8468-11ed-bfe3-dac502259ad0.png

①按鍵說明

如下:

轉(zhuǎn)向控制:左右滑動(dòng)搖桿,實(shí)現(xiàn)轉(zhuǎn)向,上下滑動(dòng)搖桿,實(shí)現(xiàn)速度控制

動(dòng)力控制:上下滑動(dòng)搖桿,實(shí)現(xiàn)前進(jìn)后退

本機(jī) IP 地址展示

對(duì)端 IP 地址輸入

鏈接,斷開按鍵,主動(dòng)進(jìn)行 TCP 連接請(qǐng)求與斷開

②控制指令

本遙控器以狀態(tài)指令為驅(qū)動(dòng),每觸發(fā)一種狀態(tài)僅發(fā)送一次指令,對(duì)端在未接收到新指令的情況下一直保持當(dāng)前指令狀態(tài)。

前進(jìn)狀態(tài):“1”

后退狀態(tài):“2”

左轉(zhuǎn)狀態(tài):“3”

右轉(zhuǎn)狀態(tài):“4”

停止?fàn)顟B(tài):“0”

頁面設(shè)計(jì)

在搖桿的拖動(dòng)設(shè)計(jì)中,主要運(yùn)用 ontouchmove,ontouchend,ontouchstart 實(shí)現(xiàn)。 通過手指坐標(biāo)來確定搖桿組件的 top 和 left 值,通過設(shè)定方向閾值來判斷是否開始發(fā)送指令,通過打印回調(diào)數(shù)據(jù)來設(shè)置參數(shù)。

hml:



{{local_ip}} 鏈接 斷開

CSS:

.container{
display:flex;
flex-direction:column;
justify-content:center;
align-items:center;
left:0px;
top:0px;
width:100%;
height:100%;
}

.title{
font-size:40px;
text-align:center;
width:100%;
height:40%;
margin:10px;
}


.yaogan{
position:absolute;
top:100px;
left:50px;
width:200px;
height:200px;
background-image:url("./common/RadialJoy_Area.png");
background-size:100%;
background-repeat:no-repeat;
z-index:-1;


}
.controller{
width:100px;
height:100px;
top:150px;
left:100px;
background-image:url("./common/RadialJoy_Area.png");
background-size:100%;
background-repeat:no-repeat;
position:absolute;
z-index:1;
}
.forward{
position:absolute;
left:550px;
width:100px;
height:100px;
background-size:100%;
z-index:-1;
}
.ip_input{
font-size:18px;
left:30px;
width:200px;
height:50px;
margin-top:25px;
background-color:#ff2c7a87;
/*background-imagenone*/
/*background-size:100%;*/
/*background-repeat:no-repeat;*/
}
.btn{
width:100px;
height:30px;
left:30px;
margin-top:5px;
background-color:#ff93f0fd;
/*background-imagenone*/
/*background-size:150%;*/
/*background-repeat:no-repeat;*/
}
.ip_local{
font-size:20px;
width:200px;
height:50px;
left:30px;
color:#ff3850ef;
margin-top:20px;
background-image:url("./common/images/bg2.png");
background-size:100%;
background-repeat:no-repeat;
}

業(yè)務(wù)邏輯

①參數(shù)調(diào)試

我們前面為搖桿組件設(shè)置了 ontouch 事件,那么如何設(shè)計(jì) Top 或者 left 值來判斷什么時(shí)候可以開始發(fā)送指令呢?

搖桿既不可太過靈敏也不可以太過遲鈍,我們可以通過打印觸摸事件返回的參數(shù)來進(jìn)行調(diào)參。

exportdefault{
touchstartfunc(msg){
console.info(`ontouchstart,pointis:${msg.touches[0].globalX}`);
console.info(`ontouchstart,pointis:${msg.touches[0].globalY}`);
console.info(`ontouchstart,datais:${msg.target.dataSet.a}`);
}
}
②觸摸控制 根據(jù)前文提到的狀態(tài)控制機(jī)制,我們應(yīng)該在 ontouchmove 中進(jìn)行判斷,當(dāng)上滑到某一閾值的時(shí)候開始發(fā)送前進(jìn)指令,當(dāng)松手時(shí)即 ontouchend 時(shí)我們應(yīng)該立即發(fā)送停止指令。 即滑動(dòng)中判斷并發(fā)送指令,停止則立馬發(fā)送停止信息。具體的閾值參數(shù)根據(jù)個(gè)人考慮進(jìn)行調(diào)試設(shè)置。
importpromptfrom'@ohos.prompt';
importwififrom'@ohos.wifi';
importsocketfrom'@ohos.net.socket';
importdisplayfrom'@ohos.display';
varpromise;
exportdefault{
data:{
title:"",
x:150,
y:100,
forward_x:150,
msg:"forward",
forward_image:"Button_normal",
TGA:"YZJ",
command:"1",
local_ip:"",
remote_ip:"",
speed_mode:1,
speed:10,
tcp:socket.constructTCPSocketInstance(),
pre_cmd:'0',
cur_cmd:'0'
},
onInit(){
this.title=this.$t('strings.world');
this.getIpAddress();
this.creatScoket();


},
send_cmd(cmd){
if(cmd!=this.cur_cmd){
this.cur_cmd=cmd;
this.sendMessage(cmd);
}
},
onMoveStart(e){
console.info("開始移動(dòng)"+JSON.stringify(e));
},
toSpeed_mode(){
if(this.speed_mode==0)
this.speed_mode=1;
elseif(this.speed_mode==1)
this.speed_mode=0;

},
onMove(e){
//圓心是(100,250)
if(this.speed_mode==0){
console.info(JSON.stringify(e))
letnx=e.touches[0].globalY-50;
this.x=nx;
}
elseif(this.speed_mode==1){
console.info(JSON.stringify(e))
letny=e.touches[0].globalX-50;
this.y=ny;
if(ny>=110){
this.msg="trun_right"
console.info("YZJ:正在向右轉(zhuǎn)")
this.command="4";
this.send_cmd(this.command);

}
elseif(ny<=90){
????????????????this.msg="trun_left"
????????????????console.info("YZJ:正在向做左轉(zhuǎn)")
????????????????this.command="3";
????????????????this.send_cmd(this.command);

????????????}

????????}

????},
????onMoveEnd(){
????????this.x=150;
????????this.y=100;
????????this.msg="stop"
????????this.command='0';
????????this.send_cmd(this.command);

????},
????onForwardstart(e){
????????this.forward_image="Button_active";
????????this.forward_x=e.touches[0].globalY-50
????},
????onForward(e){
????????if(?e.touches[0].globalY-50<=140){
????????????console.info("正在前進(jìn)")
????????????this.msg="forward"
????????????this.command="1"
????????????this.send_cmd(this.command);

????????????if(e.touches[0].globalY-50<100){
????????????????this.forward_x=100
????????????}
????????????else
????????????this.forward_x=e.touches[0].globalY-50
????????}
????????else?if(e.touches[0].globalY-50>165){
console.info("正在后退")
this.msg="backoff"
this.command="2"
this.send_cmd(this.command);

if(e.touches[0].globalY-50>200){
this.forward_x=200
}
else
this.forward_x=e.touches[0].globalY-50

}
},
onForwardend(){
this.forward_x=150;
console.info("停止前進(jìn)")
this.msg="stop"
this.forward_image="Button_normal"
this.command="0"
this.send_cmd(this.command);

},
//創(chuàng)建udpSocket默認(rèn)端口10006
creatScoket:asyncfunction(){

this.tcp.bind({address:this.local_ip,port:8888,family:1},err=>{
if(err){
console.log('YZJ---bindfail');
return;
}
console.log('YZJ---bindsuccess');
})

//監(jiān)聽收到的信息打印到屏幕上
this.tcp.on('message',value=>{
letbuffer=value.message;
letdataView=newDataView(buffer);
letstr="";
for(leti=0;i{
console.log('YZJ---sendsuccess');
}).catch(err=>{
console.log('YZJ---sendfail');
});


},
onConnect:asyncfunction(){
promise=this.tcp.connect({address:{address:"192.168.1.1",port:8888,family:1},timeout:6000});
promise.then(()=>{
prompt.showToast({
message:"連接成功!"
})
console.log('YZJ---connectsuccess');
this.tcp.setExtraOptions({
keepAlive:true,
OOBInline:true,
TCPNoDelay:true,
socketLinger:{on:true,linger:10},
receiveBufferSize:1000,
sendBufferSize:1000,
reuseAddress:true,
socketTimeout:3000,
},err=>{
if(err){
console.log('YZJ---setExtraOptionsfail');
return;
}
console.log('YZJ---setExtraOptionssuccess');
});
}).catch(err=>{
console.log('YZJ---connectfail');
prompt.showToast({
message:"連接失?。?
})
});
},
onDisconnect(){
this.tcp.close()
prompt.showToast({
message:"斷開鏈接!"
})
},
onDestroy(){
this.tcp.close()
prompt.showToast({
message:"斷開鏈接!"
})
},
//獲取本機(jī)ip地址
getIpAddress(){
letip=wifi.getIpInfo().ipAddress;
this.local_ip=(ip>>24&0xFF)+"."+((ip>>16)&0xFF)+"."+((ip>>8)&0xFF)+"."+(ip&0xFF);
},
get_remote_ip(e){
this.remote_ip=e.value
}
}
③TCP 通過輸入框獲取對(duì)端 IP 地址,點(diǎn)擊鏈接按鍵時(shí)觸發(fā) connect 方法請(qǐng)求連接,連接成功彈出對(duì)話框"連接成功"。 展示本機(jī) IP 地址。 應(yīng)用或者頁面銷毀時(shí)應(yīng)關(guān)閉連接,否則會(huì)占據(jù)對(duì)端該端口,導(dǎo)致下次連接失敗。 根據(jù)狀態(tài)驅(qū)動(dòng)指令控制,由于 ontouchmove 是一直在觸發(fā)的,也就是判斷是一直在進(jìn)行的,當(dāng)我們保持搖桿前進(jìn)狀態(tài)的時(shí)候,注意要判斷指令狀態(tài)是否更新了?如果指令未變,那么就不再發(fā)送指令。只有指令變化的時(shí)候才會(huì)發(fā)送一次指令。 只有連接成功后,才能夠發(fā)送信息。 b13bb496-8468-11ed-bfe3-dac502259ad0.png

tcp 設(shè)置參數(shù):

|參數(shù)|描述|
|-|-|
|keepAlive|是否保持連接。默認(rèn)為false。|
|OOBInline|是否為OOB內(nèi)聯(lián)。默認(rèn)為false。|
|TCPNoDelay|TCPSocket連接是否無時(shí)延。默認(rèn)為false。|
|receiveBufferSize|接收緩沖區(qū)大?。▎挝唬築yte)|
|sendBufferSize|發(fā)送緩沖區(qū)大小(單位:Byte)|
|reuseAddress|是否重用地址。默認(rèn)為false|
|socketTimeout|套接字超時(shí)時(shí)間,單位毫秒(ms)|
建議開啟 HarmonyOS 工程,開發(fā)完畢后可同步安裝到 OpenHarmony 設(shè)備,反之則會(huì)變得麻煩一些。

④申請(qǐng)權(quán)限

"reqPermissions":[

{
"name":"ohos.permission.GET_WIFI_INFO"
},
{
"name":"ohos.permission.GET_NETWORK_INFO"
},
{
"name":"ohos.permission.INTERNET"
},
{
"name":"ohos.permission.SET_NETWORK_INFO"
},
{
"name":"ohos.permission.ACCELEROMETER"
}
]

結(jié)語

本次分享的應(yīng)用需要南北向開發(fā)配合食用,同時(shí)需要 HarmonyOS 3.0 設(shè)備或者 OpenHarmony 3.2 設(shè)備。 HarmonyOS 2.0 設(shè)備可考慮采用 JS/JAVA 混合開發(fā),JAVA 側(cè)實(shí)現(xiàn) Socket 通信,可參考我往期博客。 下一期,我將會(huì)分享如何配置 HarmonyOS 3.0 設(shè)備的碰一碰拉起應(yīng)用配置。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴

原文標(biāo)題:為鴻蒙小車做一個(gè)遙控器

文章出處:【微信號(hào):gh_834c4b3d87fe,微信公眾號(hào):OpenHarmony技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    玩具車 wifi遙控器

    現(xiàn)在有輛玩具小車,可以用安卓手機(jī)或蘋果連接(wifi)來進(jìn)行控制,我想做一個(gè)玩具車遙控器來控制,有沒有可以實(shí)現(xiàn)的,有償!
    發(fā)表于 05-22 22:50

    【NanoPi2申請(qǐng)】基于Linux or 安卓的遙控小車

    申請(qǐng)理由:其實(shí)我是想用它來學(xué)opencv的些東西,或許那樣寫不是個(gè)好的選擇,做一個(gè)遙控小車
    發(fā)表于 12-02 16:10

    做一個(gè)用單片機(jī)控制的遙控器

    本人菜鳥,想要做一個(gè)用單片機(jī)來控制的遙控器,但不知道需要什么部件和工具,求大神指導(dǎo)。
    發(fā)表于 10-07 14:06

    最近做了個(gè)遙控小車 前進(jìn)后退都沒有問題 但是有時(shí)候不按遙控器后 車子自己會(huì)轉(zhuǎn) 怎么破?

    最近做了個(gè)遙控小車 前進(jìn)后退都沒有問題 但是有時(shí)候不按遙控器后 車子自己會(huì)轉(zhuǎn) 怎么破
    發(fā)表于 05-10 22:19

    遙控器單片機(jī)是51的,小車芯片是飛思卡爾的,請(qǐng)問如何修好這個(gè)遙控器 急急急

    接手前人的活,用搖桿控制小車運(yùn)動(dòng) 無線模塊是zigbee,現(xiàn)在遙控器壞了 沒有原來的電路圖 遙控器單片機(jī)是51的,小車芯片是飛思卡爾的,請(qǐng)問如何修好這個(gè)
    發(fā)表于 05-05 20:03

    遙控器通信原理簡(jiǎn)介

    目錄. 遙控器通信原理簡(jiǎn)介二. SBUS信號(hào)解析1. SBUS信號(hào)簡(jiǎn)介2. STM32F7解析SBUS信號(hào)三. 通信任務(wù)實(shí)現(xiàn). 遙控器通信原理簡(jiǎn)介要實(shí)現(xiàn)
    發(fā)表于 08-19 08:53

    如何做一個(gè)無線遙控小車?

    如何做一個(gè)無線遙控小車?
    發(fā)表于 12-17 06:58

    如何做一個(gè)遙控器控制的計(jì)算

    基于arduino uno r3/ Mega2560,做一個(gè)遙控器控制的計(jì)算。。。。。目錄. 實(shí)驗(yàn)材料:(? ?_?)?...
    發(fā)表于 02-15 07:42

    如何做一個(gè)相機(jī)紅外遙控器

    如何做一個(gè)相機(jī)紅外遙控器?
    發(fā)表于 02-15 07:04

    如何設(shè)計(jì)個(gè)智能遙控器的電路?

      智能遙控器種可以通過紅外線或藍(lán)牙等無線技術(shù)來控制家電的設(shè)備,以下是設(shè)計(jì)智能遙控器的電路需要考慮的些方面:  電源管理:智能遙控器
    發(fā)表于 04-21 11:03

    請(qǐng)問能用單片機(jī)加上紅外做一個(gè)空調(diào)遙控器嗎?

    能用單片機(jī)加上紅外做一個(gè)空調(diào)遙控器嗎?該怎么實(shí)現(xiàn)?
    發(fā)表于 11-07 06:28

    空調(diào)遙控器維修資料下載

    空調(diào)遙控器壞了怎么辦?空調(diào)遙控器哪里修?空調(diào)遙控器哪里買?空調(diào)遙控器多少錢個(gè)
    發(fā)表于 05-13 10:13 ?18次下載
    空調(diào)<b class='flag-5'>遙控器</b>維修資料下載

    文弄懂無線遙控器

    相信大家對(duì)于無線遙控器都有著自己的認(rèn)知,認(rèn)為無線遙控器就是我們家用的電視啊、空調(diào)啊的遙控器嗎?是的,這些當(dāng)然是無線遙控種,它們屬于紅外
    發(fā)表于 11-14 09:18 ?9145次閱讀

    如何構(gòu)建個(gè)簡(jiǎn)單的基于紅外的車門遙控器

    在這篇文章中,我們將學(xué)習(xí)如何構(gòu)建個(gè)簡(jiǎn)單但萬無失的基于紅外的遙控器,該遙控器可用于通過個(gè)人遙控
    的頭像 發(fā)表于 04-02 10:37 ?1314次閱讀
    如何構(gòu)建<b class='flag-5'>一</b><b class='flag-5'>個(gè)</b>簡(jiǎn)單的基于紅外的車門<b class='flag-5'>遙控器</b>

    使用紅外發(fā)射模塊自制空調(diào)遙控器

    我們家里的空調(diào)、電視等,它們的遙控器都是通過紅外信號(hào)來控制的。其實(shí),我們可以自己用紅外發(fā)射模塊來做一個(gè)遙控器。
    的頭像 發(fā)表于 05-23 15:43 ?3730次閱讀
    使用紅外發(fā)射模塊自制空調(diào)<b class='flag-5'>遙控器</b>