安卓端APP遥控树莓派小车
一、基本原理
? ? 在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í)例
最后,連上安卓實(shí)體機(jī),打開(kāi)樹(shù)莓派服務(wù)端,運(yùn)行
附上源代碼
總結(jié)
以上是生活随笔為你收集整理的安卓端APP遥控树莓派小车的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Java】数组对象转实体对象
- 下一篇: masm32开发com组件