android之藍芽控制小四軸飛行器
阿新 • • 發佈:2019-01-29
本app基於匿名開源小四軸app( http://www.anotc.com/Product/Overview/8 )改編。匿名小四軸接上串列埠藍芽模組後,可直接使用本app控制。其它飛控修改通訊協議後方可使用。本app改編後可用於控制藍芽智慧小車,感興趣的小夥伴可以試試看。使用飛行器測試時,請千萬注意安全。
藍芽連線介面,需開啟手機藍芽才可進行下一步操作。上面文字框顯示當前藍芽連線狀況;中間大圖是我們的logo;左下藍芽圖示,單擊可選擇要連線的串列埠藍芽裝置;右下六邊形圖示,單擊可跳轉至下圖飛行器控制介面。
中上三個全錶盤飛機圖示,動畫實時顯示飛行器當前橫滾角、航向角和俯仰角;中間半錶盤指標圖示,顯示飛行器當前油門值;中下圖示,單擊可解鎖飛控,再次單擊可鎖定飛控,如此反覆;兩側文字框,實時顯示飛控的加速度計和陀螺儀數值;左側箭頭圖示,上下為油門加、減,左右控制橫滾角;右側箭頭圖示,上下控制俯仰角,左右控制航向角。
控制部分原始碼:
package com.example.seuxiaosi; import java.util.Timer; import java.util.TimerTask; import android.app.Activity; import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.Matrix; import android.graphics.Paint; importandroid.graphics.drawable.BitmapDrawable; import android.os.Bundle; import android.os.Handler; import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.view.WindowManager; import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; import android.annotation.SuppressLint; public class MyControl extends Activity { //用於影象旋轉的變數 privateImageView mImageView_yaw; privateImageView mImageView_rol; privateImageView mImageView_pit; privateImageView mImageView_thr; privateMatrix mMatrix = new Matrix(); privatefloat mAngle_thr = 0; BitmapmBitmap; Paintpaint = new Paint(); privateint thrTF = 0;// //自定義按鍵監聽事件類 mImageListentermImageButtonListener = new mImageListenter(); //設定油門, yaw,pit,rol的初始值 privateint VAL_THR = 1000; privateint VAL_YAW = 1500, VAL_ROL = 1500, VAL_PIT = 1500; //資料顯示 TextView acc_x_show , acc_y_show , acc_z_show , gyr_x_show , gyr_y_show , gyr_z_show ; //圖片按鈕變數 privateImageButton image; //飛控解鎖 LOCK=0——鎖定,LOCK=1——解鎖 privateint LOCK = 0; //時間管理器 Timersend_timer = new Timer(); privatefinal Handler myHandler = new Handler(); //handler可以分發Message物件和Runnable物件到主執行緒中 //handler中的執行時間過長會出錯!!!!!!!!!! privatefinal Runnable myRunable = new Runnable() { @Override publicvoid run() { //TODO Auto-generated method stub //0.1秒後呼叫此Runnable物件,用於控制資料的更新 myHandler.postDelayed(this,100); //控制介面資料的更新 acc_x_show.setText("X:" + MainActivity.VAL_ACC_X); acc_y_show.setText("Y:" + MainActivity.VAL_ACC_Y); acc_z_show.setText("Z:" + MainActivity.VAL_ACC_Z); gyr_x_show.setText("X:" + MainActivity.VAL_GYR_X); gyr_y_show.setText("Y:" + MainActivity.VAL_GYR_Y); gyr_z_show.setText("Z:" + MainActivity.VAL_GYR_Z); mRotate_yaw();//旋轉影象 mRotate_pit(); mRotate_rol(); if(LOCK== 1){ if(thrTF== 1) VAL_THR+= 2; elseif(thrTF == 2) VAL_THR-= 2; mRotate_thr_up(); } } }; @Override protectedvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //橫屏模式 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //保持螢幕長亮 getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.activity_my_control); ImageButtonmImageButton; acc_x_show = (TextView)findViewById(R.id.acc_x); acc_y_show = (TextView)findViewById(R.id.acc_y); acc_z_show = (TextView)findViewById(R.id.acc_z); gyr_x_show = (TextView)findViewById(R.id.gyr_x); gyr_y_show = (TextView)findViewById(R.id.gyr_y); gyr_z_show = (TextView)findViewById(R.id.gyr_z); //用於旋轉影象 mImageView_yaw = (ImageView)findViewById(R.id.yaw_image); mImageView_rol = (ImageView)findViewById(R.id.rol_image); mImageView_pit = (ImageView)findViewById(R.id.pit_image); mImageView_thr = (ImageView)findViewById(R.id.thr_image); DisplayMetrics dm =new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); //按鈕監聽器 mImageButton= (ImageButton) findViewById(R.id.thr_up); mImageButton.setOnTouchListener(mImageButtonListener); mImageButton= (ImageButton) findViewById(R.id.thr_down); mImageButton.setOnTouchListener(mImageButtonListener); mImageButton= (ImageButton) findViewById(R.id.rol_you); mImageButton.setOnTouchListener(mImageButtonListener); mImageButton= (ImageButton) findViewById(R.id.rol_zuo); mImageButton.setOnTouchListener(mImageButtonListener); mImageButton= (ImageButton) findViewById(R.id.pit_qian); mImageButton.setOnTouchListener(mImageButtonListener); mImageButton= (ImageButton) findViewById(R.id.pit_hou); mImageButton.setOnTouchListener(mImageButtonListener); mImageButton= (ImageButton) findViewById(R.id.yaw_zuo); mImageButton.setOnTouchListener(mImageButtonListener); mImageButton= (ImageButton) findViewById(R.id.yaw_you); mImageButton.setOnTouchListener(mImageButtonListener); mImageButton= (ImageButton) findViewById(R.id.suo); mImageButton.setOnClickListener(newView.OnClickListener(){ @Override publicvoid onClick(View v) { //TODO Auto-generated method stub image= (ImageButton) findViewById(R.id.suo); if(LOCK== 0){ LOCK= 1;//解鎖狀態置1 //傳送解鎖命令 MainActivity.Send_Command((byte)0xa1); image.setImageResource(R.drawable.jie); } else{ //傳送鎖定命令 MainActivity.Send_Command((byte)0xa0); image.setImageResource(R.drawable.suo); VAL_THR= 1000;//油門置0 mRotate_thr_up(); LOCK= 0;//解鎖狀態置0 } } }); //延遲1秒後執行任務send_task,然後經過0.05秒再次執行send_task,用於迴圈任務 send_timer.schedule(send_task,1000,50); //每0.1秒執行一次runnable myHandler.postDelayed(myRunable,100); } classmImageListenter implements OnTouchListener{ @Override publicboolean onTouch(View v, MotionEvent event) { //TODO Auto-generated method stub if(LOCK== 1){ //yaw按鈕 if(v.getId()== R.id.yaw_zuo){ if(event.getAction()== MotionEvent.ACTION_DOWN) VAL_YAW= 1200; if(event.getAction()== MotionEvent.ACTION_CANCEL) VAL_YAW= 1500; if(event.getAction()== MotionEvent.ACTION_UP) VAL_YAW= 1500; } if(v.getId()== R.id.yaw_you){ if(event.getAction()== MotionEvent.ACTION_DOWN) VAL_YAW= 1800; if(event.getAction()== MotionEvent.ACTION_CANCEL) VAL_YAW= 1500; if(event.getAction()== MotionEvent.ACTION_UP) VAL_YAW= 1500; } //pit按鈕 if(v.getId()== R.id.pit_qian){ if(event.getAction()== MotionEvent.ACTION_DOWN) VAL_PIT= 1650; if(event.getAction()== MotionEvent.ACTION_CANCEL) VAL_PIT= 1500; if(event.getAction() ==MotionEvent.ACTION_UP) VAL_PIT= 1500; } if(v.getId()== R.id.pit_hou){ if(event.getAction()== MotionEvent.ACTION_DOWN) VAL_PIT= 1350; if(event.getAction()== MotionEvent.ACTION_CANCEL) VAL_PIT= 1500; if(event.getAction()== MotionEvent.ACTION_UP) VAL_PIT= 1500; } //rol按鈕 if(v.getId()== R.id.rol_zuo){ if(event.getAction()== MotionEvent.ACTION_DOWN) VAL_ROL= 1200; if(event.getAction()== MotionEvent.ACTION_CANCEL) VAL_ROL= 1500; if(event.getAction()== MotionEvent.ACTION_UP) VAL_ROL= 1500; } if(v.getId()== R.id.rol_you){ if(event.getAction()== MotionEvent.ACTION_DOWN) VAL_ROL= 1800; if(event.getAction()== MotionEvent.ACTION_CANCEL) VAL_ROL= 1500; if(event.getAction()== MotionEvent.ACTION_UP) VAL_ROL= 1500; } //油門 if(v.getId()== R.id.thr_up){ if(VAL_THR >= 2000) {VAL_THR= 2000;}//執行空語句 else{ if(event.getAction()== MotionEvent.ACTION_DOWN) thrTF= 1; //{VAL_THR+= 15; mRotate_thr_up();} if(event.getAction()== MotionEvent.ACTION_CANCEL) thrTF= 0; if(event.getAction()== MotionEvent.ACTION_UP) thrTF= 0; } } if(v.getId()== R.id.thr_down){ if(VAL_THR<= 1000) {VAL_THR= 1000;} else{ if(event.getAction()== MotionEvent.ACTION_DOWN) thrTF= 2; if(event.getAction()== MotionEvent.ACTION_CANCEL) thrTF= 0; if(event.getAction() ==MotionEvent.ACTION_UP) thrTF= 0; } } } returnfalse; } } TimerTasksend_task = new TimerTask(){ //Timer是一種執行緒設施,用於安排以後在後臺執行緒中執行的任務。 //可安排任務執行一次,或者定期重複執行,可以看成一個定時器,可以排程TimerTask。 //TimerTask是一個抽象類,實現了Runnable介面,所以具備了多執行緒的能力。 byte[] bytes = new byte[25]; public void run () { byte sum=0; bytes[0] = (byte) 0xaa; bytes[1] = (byte) 0xaf; bytes[2] = (byte) 0x03; bytes[3] = (byte) 20; bytes[4] = (byte)(VAL_THR/0xff);//取商 油門 bytes[5] = (byte)(VAL_THR%0xff);//取餘數 bytes[6] = (byte)(VAL_YAW/0xff);//航向 bytes[7] = (byte) (VAL_YAW%0xff); bytes[8] = (byte)(VAL_ROL/0xff);//橫滾 bytes[9] = (byte) (VAL_ROL%0xff); bytes[10] = (byte)(VAL_PIT/0xff);//俯仰 bytes[11] = (byte) (VAL_PIT%0xff); bytes[12] = 1; bytes[13] = 2; bytes[14] = 3; bytes[15] = 4; bytes[16] = 0; bytes[17] = 0; bytes[18] = 0; bytes[19] = 0; bytes[20] = 0; bytes[21] = 0; bytes[22] = 0; bytes[23] = 0; for(int i=0;i<24;i++) sum +=bytes[i]; bytes[24] = sum; MainActivity.SendData_Byte(bytes);//傳送資料 } }; protected void onDestroy(){ if(send_timer != null) //登出定時器 { send_timer.cancel(); send_timer= null; } super.onDestroy(); } //自定義影象旋轉函式 private void mRotate_yaw(){ mBitmap = ((BitmapDrawable)(getResources().getDrawable(R.drawable.yaw2))).getBitmap(); mMatrix.setRotate(MainActivity.VAL_ANG_Z,mBitmap.getWidth() / 2, mBitmap.getHeight() / 2);//旋轉角度設定 paint= new Paint(); //設定抗鋸齒,防止過多的失真 paint.setAntiAlias(true); mBitmap= Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(),mMatrix, true); mImageView_yaw.setImageBitmap(mBitmap); } private void mRotate_rol(){ mBitmap =((BitmapDrawable)(getResources().getDrawable(R.drawable.rol2))).getBitmap(); mMatrix.setRotate(MainActivity.VAL_ANG_X, mBitmap.getWidth() / 2, mBitmap.getHeight() / 2);//旋轉角度設定 paint= new Paint(); //設定抗鋸齒,防止過多的失真 paint.setAntiAlias(true); mBitmap= Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(),mMatrix, true); mImageView_rol.setImageBitmap(mBitmap); } private void mRotate_pit(){ mBitmap= ((BitmapDrawable)(getResources().getDrawable(R.drawable.pit2))).getBitmap(); mMatrix.setRotate(-MainActivity.VAL_ANG_Y,mBitmap.getWidth() / 2, mBitmap.getHeight() / 2);//旋轉角度設定 paint= new Paint(); //設定抗鋸齒,防止過多的失真 paint.setAntiAlias(true); mBitmap= Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(),mMatrix, true); mImageView_pit.setImageBitmap(mBitmap); } private void mRotate_thr_up(){ if(LOCK== 1){ mBitmap= ((BitmapDrawable)(getResources().getDrawable(R.drawable.zhen))).getBitmap(); mAngle_thr = (float)(VAL_THR-1000)*180/1000; mMatrix.setRotate(mAngle_thr,mBitmap.getWidth() / 2, mBitmap.getHeight() / 2);//旋轉角度設定 paint= new Paint(); //設定抗鋸齒,防止過多的失真 paint.setAntiAlias(true); mBitmap= Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(),mMatrix, true); mImageView_thr.setImageBitmap(mBitmap); } } }
eclipse工程原始碼下載地址:
http://download.csdn.net/detail/qq_21478795/9538237