关闭

android之蓝牙控制小四轴飞行器

标签: android蓝牙小四轴
1541人阅读 评论(1) 收藏 举报
分类:

         本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

      

 

 

1
0
查看评论

30分钟内使用手机控制四轴飞行器(ESP8266 + A7105 + Blynk App for iOS/Android)

很久以来,我就想做类似的项目了。但是手机集成工作的复杂性让我感到害怕。而且如果以后我有新的想法,也很难再重新利用这个项目。 现在,有了Blynk,这一切变得易如反掌:) 因此,我花了一个晚上,完成了这个项目。我希望大家会对这个项目感兴趣。 为了让这个项目正常工作,你需要: 1...
  • free0loop
  • free0loop
  • 2015-09-17 10:43
  • 6118

个人项目 小跟班——蓝牙小车控制(UI篇)

个人项目 :蓝牙控制小车(UI篇)
  • ZL_1205
  • ZL_1205
  • 2016-12-30 18:18
  • 675

四轴飞行器建模和控制(二)

上一章普及了一些基本的物理知识,下面我们开始具体分析四轴的建模和控制的具体问题 首先明确两个坐标系,世界坐标系和机体坐标系。世界坐标系是固定在地面或者特定位置不懂的,又称参考系或者惯性系。机体坐标系是随机体实时运转的,固连在飞机上的坐标系。惯性系我们用[a1,a2,a3][a_1,a_2,a_3]...
  • junshen1314
  • junshen1314
  • 2016-03-12 23:10
  • 1482

如何控制四轴飞行器四个方向飞行

四旋翼飞行器通过调节四个电机转速来改变旋翼转速,实现升力的变化,从而控制飞行器的姿态和位置。四旋翼飞行器是一种六自由度的垂直升降机,但只有四个输入力,同时却有六个状态输出,所以它又是一种欠驱动系统。 以四轴,X 形状为例: 1.飞行器保持悬停, 4个电机的转速保持一致,来使飞行器保持水平。 ...
  • weixin_35703797
  • weixin_35703797
  • 2016-07-30 12:22
  • 5059

安卓手机蓝牙控制智能小车 android程序设计

项目名称: 安卓手机控制智能小车本文主要介绍手机端程序设计源码托管在地址:github.com/cyang812/Bluetooth_Car 开发平台 :win10; 开发软件:Android Studio 2.1 在开发的过程中,软件版本有过几次更新,本文重点讲述更新逻辑及实现过程。一、...
  • u011303443
  • u011303443
  • 2016-06-10 19:21
  • 8238

android蓝牙控制继电器——手机客户端的实现

通过手机自身所带的蓝牙实现连接蓝牙模块,从而实现通过单片机控制继电器,实现弱点控制强电(这里只做掩饰的小Demo)。
  • u013470102
  • u013470102
  • 2014-11-04 16:11
  • 5791

HC-05蓝牙模块连接STC89C52单片机控制LED灯

**首先声明我用的是52单片机,板子型号为HC6800-ES V2.0;如果 非同类型,实现不了,概不认账。** 要实现这个玩法,首先得掌握串口通信的知识,不需要太多,只要知道如何接收/发送数据就行。 串行通信: 按照数据传送方向分为: *单...
  • W_K_L
  • W_K_L
  • 2017-05-21 13:00
  • 2513

Android蓝牙控制arduino机器人自走小车

一直以来,Android蓝牙控制arduino机器人自走小车这个项目困惑我好久了,以前把机器人小车的蓝牙地址写死了。现在随着android学习的深入,终于把这个项目全部完善完成了。从andrroid端APP的开发到机器人小车的设计全部统统搞定,现在我具体介绍一下我的项目: 1.机器人端 用到了L...
  • u014115577
  • u014115577
  • 2015-09-29 20:08
  • 2562

<转载>Android 通过蓝牙控制小车源代码+视频

《转载自http://hi.baidu.com/liuhuiviking/blog/item/503f2e1feb0e00e3e1fe0b74.html》 上次成功实现了通过笔记本电脑蓝牙来控制智能小车机器人的运动,但是通过电脑控制毕竟不方便,于是乎~本人打算将控制程序移植
  • caryee89
  • caryee89
  • 2011-10-14 20:30
  • 16388

一个简单实用的Android蓝牙程序实例

作者:   张奇        我将在这篇文章中介绍了的Android蓝牙程序。这个程序就是将实现把手机变做电脑PPT播放的遥控器:用音量加和音量减键来控制PPT页面的切换。 遥控器服务器端 首先,我们需要编写一个遥控器的服务器端(支持蓝牙的电...
  • pku_android
  • pku_android
  • 2012-04-06 09:12
  • 21415
    个人资料
    • 访问:18639次
    • 积分:518
    • 等级:
    • 排名:千里之外
    • 原创:34篇
    • 转载:1篇
    • 译文:0篇
    • 评论:1条
    文章分类
    文章存档
    最新评论