本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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)