日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

安卓端APP遥控树莓派小车

發(fā)布時(shí)間:2024/3/26 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 安卓端APP遥控树莓派小车 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、基本原理

? ? 在android端寫一個(gè)小小的控制器來(lái)通過(guò)局域網(wǎng)來(lái)控制樹(shù)莓派小車的行駛,基本思路是在樹(shù)莓派上寫一個(gè)socket服務(wù)器,android端寫一個(gè)socket客戶機(jī),兩邊約定好命令的指令(例如可以簡(jiǎn)單的把停止約定為“0”,把前進(jìn)約定為“1”),android負(fù)責(zé)發(fā)送,樹(shù)莓派負(fù)責(zé)接受并執(zhí)行。用這種方法理論上是可以遠(yuǎn)程控制的,前提是得要知道樹(shù)莓派被分配的公網(wǎng)IP。

二、知識(shí)學(xué)習(xí)? ?

? ??【android】Socket簡(jiǎn)單用法

? ? Android自定義View的三種實(shí)現(xiàn)方式

三、代碼結(jié)構(gòu)

首先看一下最終結(jié)果截圖:


布局很簡(jiǎn)單,就布置了幾個(gè)控件,兩個(gè)文本輸入框,一個(gè)按鈕,以及一個(gè)搖桿。

Android官方?jīng)]有搖桿控件,為了方便,直接找了網(wǎng)上別人的開(kāi)源項(xiàng)目。


這是由GcsSloop開(kāi)發(fā)的自定義View。

GcsSloop兩個(gè)開(kāi)源項(xiàng)目快速導(dǎo)航:

View輔助工具包,幫助你快速優(yōu)雅的完成自定義View

https://github.com/GcsSloop/ViewSupport

一個(gè)安卓虛擬搖桿程序,可作為游戲控制器或者小車遙控器。

https://github.com/GcsSloop/Rocker


將這兩個(gè)項(xiàng)目下載下來(lái),后面會(huì)用到。

我將遙控器稍微改造了下,添加了能夠與樹(shù)莓派連接并發(fā)送數(shù)據(jù)的功能。

?


代碼結(jié)構(gòu):



View目錄下的類是GcsSloop開(kāi)發(fā)的輔助工具類

RockerView是GcsSloop使用自己的工具類開(kāi)發(fā)的一個(gè)搖桿控件

RockerSocketView是我寫的繼承自RockerView的搖桿控件

MainActivity為控件測(cè)試




四、編寫過(guò)程

AS創(chuàng)建一個(gè)新項(xiàng)目

? \Rocker-master\library\src\main\java\com\gcssloop\wid目錄下的RockerView.java、

? \ViewSupport-master\ViewSupport-master\Library\src\main\java\com\gcssloop下的view文件夾

復(fù)制到app\src\main\java\cn\luosh\rockertest目錄下

導(dǎo)入后會(huì)有一些路徑錯(cuò)誤,根據(jù)自身情況修改











將Rocker-master\library\src\main\res\values\attrs.xml復(fù)制到values下

此時(shí)項(xiàng)目應(yīng)該已經(jīng)沒(méi)有錯(cuò)誤了

將Rocker-master\Sample\src\main\res\drawable下的圖片資源也復(fù)制到我們的drawable目錄下(這是搖桿的底盤和按鈕圖片,自 己可以用其他圖片 ? ? 替換)






接下來(lái)就我們自己敲代碼啦

新建類RockerSocketView

package cn.luosh.rockertest;import android.content.Context; import android.os.AsyncTask; import android.util.AttributeSet; import android.util.Log; import android.widget.Toast;import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.net.Socket;/*** Created by luo76 on 2017/5/6.*/public class RockerSocketView extends RockerView{//樹(shù)莓派ip地址private String carIp;//端口private int carPort;//是否連接標(biāo)志private boolean isConnect = false;private Context context;Socket socket = null;BufferedReader reader = null;BufferedWriter writer = null;private int rockerEvent = 0;private int oldrockerEvent = -1;//定義搖桿事件狀態(tài)public static final int Movestop = 0;public static final int Moveforward = 1;public static final int Movebackward = 2;public static final int Turnleft = 3;public static final int Turnright = 4;//重新定義了構(gòu)造方法,目的是為了得到使用該控件的Activity的contextpublic RockerSocketView(Context context) {this(context, null);}public RockerSocketView(Context context, AttributeSet attrs) {super(context, attrs, 0);this.context = context;}//初始化函數(shù),由使用該控件的Activity調(diào)用public void init(String carIp,int carPort){this.carIp = carIp;this.carPort = carPort;connectAsyncTask();//添加搖桿事件監(jiān)聽(tīng)this.setListener(new RockerView.RockerListener() {@Overridepublic void callback(int eventType, int currentAngle, float currentDistance) {switch (eventType) {case RockerView.EVENT_ACTION:// 觸摸事件回調(diào)Log.e("EVENT_ACTION-------->", "angle="+currentAngle+" - distance"+currentDistance);rockerEvent = judgeEvent(currentAngle);send();break;case RockerView.EVENT_CLOCK:// 定時(shí)回調(diào)Log.e("EVENT_CLOCK", "angle="+currentAngle+" - distance"+currentDistance);rockerEvent = judgeEvent(currentAngle);send();break;}}});}//根據(jù)角度判斷搖桿方向public int judgeEvent(int currentAngle){if (currentAngle == -1){return Movestop;}else if (currentAngle > 45 && currentAngle <= 135){return Moveforward;}else if (currentAngle > 135 && currentAngle <= 225){return Turnleft;}else if (currentAngle > 225 && currentAngle <= 315){return Movebackward;}else{return Turnright;}}public void Destroy(){isConnect = false;}//使用異步任務(wù)建立socket連接public void connectAsyncTask(){AsyncTaskconnect =new AsyncTask() {@Overrideprotected Void doInBackground(Void... params) {try {socket = new Socket(carIp,carPort);writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));publishProgress("連接成功\n");isConnect = true;}catch (UnsupportedEncodingException e) {Toast.makeText(context,"無(wú)法建立連接",Toast.LENGTH_SHORT).show();e.printStackTrace();}catch (IOException e) {e.printStackTrace();Toast.makeText(context,"無(wú)法建立連接",Toast.LENGTH_SHORT).show();}String Line;try {while ((Line = reader.readLine()) != null){publishProgress(Line);}} catch (IOException e) {e.printStackTrace();}return null;}protected void onProgressUpdate(String...values){if(values[0].equals("連接成功\n")){Toast.makeText(context,"連接成功",Toast.LENGTH_SHORT).show();}else{System.out.println(values[0]);}super.onProgressUpdate(values[0]);}};connect.execute();}//不使用線程,事件變化時(shí)再發(fā)送狀態(tài)public void send(){//先判斷是否成功建立socket連接再向樹(shù)莓派發(fā)送數(shù)據(jù),避免出現(xiàn)錯(cuò)誤if(isConnect){if(rockerEvent != oldrockerEvent){oldrockerEvent = rockerEvent;try {//將要發(fā)送的int數(shù)據(jù)轉(zhuǎn)換成String再發(fā)送writer.write(String.valueOf(rockerEvent));writer.flush();Log.e("EVENT_ACTION-------->", "rockerEvent=" + rockerEvent);} catch (IOException e) {e.printStackTrace();}}}} }



給個(gè)如何調(diào)用的實(shí)例


package cn.luosh.rockertest;import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.EditText;public class MainActivity extends AppCompatActivity {private RockerSocketView rockersocket;private EditText carip,carport;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);rockersocket = (RockerSocketView) findViewById(R.id.rockersocket);carip = (EditText) findViewById(R.id.carip);carport = (EditText) findViewById(R.id.carport);findViewById(R.id.btn_car_connect).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {rockersocket.init(carip.getText().toString(),Integer.parseInt(carport.getText().toString()));}});}@Overrideprotected void onDestroy() {super.onDestroy();rockersocket.Destroy();rockersocket = null;} }


把a(bǔ)ctivity_main.xml和AndroidManifest.xml的內(nèi)容也放出來(lái)






最后,連上安卓實(shí)體機(jī),打開(kāi)樹(shù)莓派服務(wù)端,運(yùn)行



附上源代碼

總結(jié)

以上是生活随笔為你收集整理的安卓端APP遥控树莓派小车的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 牛牛精品视频 | 日韩中文字幕精品视频 | 午夜视频免费在线观看 | 欧美乱妇高清无乱码 | www.日本精品| 国产在线第二页 | 看片网址国产福利av中文字幕 | 日韩日日夜夜 | 五月天爱爱 | 五月激情开心网 | 在线午夜视频 | 免费成人在线观看视频 | 亚洲国产成人精品一区二区三区 | 性猛交xxxx乱大交孕妇2十 | a级片免费网站 | 最近中文字幕在线视频 | 天堂中文8 | 精品人伦一区二区三 | 超碰成人免费电影 | 精彩毛片| 天天夜夜久久 | 国产精品亚洲一区二区三区在线观看 | 高潮一区二区 | 激情综合一区二区三区 | 午夜视频1000 | 久草免费在线观看视频 | 不卡中文字幕av | 无码精品人妻一区二区三区湄公河 | 狠狠丁香| 国产手机在线播放 | 在线无码va中文字幕无码 | 欧美一区二区人人喊爽 | 亚洲精品中文字幕在线观看 | 久久网av| 中文字幕91在线 | 久久久噜噜噜 | 69久久精品无码一区二区 | 精品亚洲一区二区三区四区五区 | 天天射夜夜撸 | 久久国产美女 | 少妇精品无码一区二区三区 | 婷婷丁香六月 | 无码人妻精品一区二区三区夜夜嗨 | 一级黄色片国产 | 打屁股视频网站 | 丁香综合| 男操女视频在线观看 | 玖玖爱在线精品视频 | 俄罗斯av在线 | 91免费看 | 欧美激情视频一区 | 国产精品无码av无码 | 免费的毛片网站 | 国产视频在线观看一区二区 | 天天躁日日躁aaaaxxxx | 日韩av男人天堂 | 天天躁日日躁狠狠躁 | 日韩中文字幕一区 | 国产精品夜夜爽张柏芝 | 青青草激情 | 国产妞干网 | 手机在线观看免费av | 精品久久久无码中文字幕 | 一区在线免费观看 | 亚洲永久av | 一二三区精品视频 | 深夜av| 97欧美视频| www国产精品内射熟女 | 新版天堂资源中文8在线 | 三级成人在线 | 在线播放国产一区 | 成人看片黄a免费看视频 | 精品国产一区二区三区久久狼黑人 | 老色驴综合网 | 伊在线久久丫 | 在线日韩亚洲 | 咪咪色影院 | 亚洲国产精品va在线看黑人 | youjizzxxx69 | 中文亚洲av片在线观看 | 97人妻精品一区二区三区动漫 | 国产青草视频在线观看 | 被黑人猛躁10次高潮视频 | 在线观看91视频 | 黄色三级小说 | 亚洲成年人在线 | 一区二区三区视频免费在线观看 | 亚洲成人黄色影院 | 欧美伦理在线观看 | 神马久久精品 | 蜜桃一区二区三区 | aa亚洲 | 奇米四色网| 99热成人 | 日本少妇喂奶漫画 | 91精品国产麻豆国产自产在线 | 国产在线免费 | 在线免费观看中文字幕 |