基于DragonBoard 410c的遥控炮台五之远程交互(下)

一.背景

在实现了android手机对Dragonboard 410c系统的远程舵机控制后,我们再回头来优化android客户端的界面控制效果。

二.虚拟摇杆

1.android虚拟摇杆

上一节我们在android的客户端是通过手动输入数值的方式来控制舵机,虽然这也能实现远程控制,但是相对于人的操作方式相当不方便,这里我们考虑使用虚拟的摇杆来优化这个控制方式。


图1 虚拟摇杆效果

2.摇杆实现代码

2.1.RockerView.java

package com.boss.xiao.streerocker;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnPreDrawListener;

public class RockerView extends View {

	//固定摇杆背景圆形的X,Y坐标以及半径
	private float mRockerBg_X;
	private float mRockerBg_Y;
	private float mRockerBg_R;
	//摇杆的X,Y坐标以及摇杆的半径
	private float mRockerBtn_X;
	private float mRockerBtn_Y;
	private float mRockerBtn_R;
	private Bitmap mBmpRockerBg;
	private Bitmap mBmpRockerBtn;
	
	private PointF mCenterPoint;
	
	public RockerView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		// 获取bitmap
		mBmpRockerBg = BitmapFactory.decodeResource(context.getResources(), R.drawable.rocker_bg);
		mBmpRockerBtn = BitmapFactory.decodeResource(context.getResources(), R.drawable.rocker_btn);
		
		getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
			
			// 调用该方法时可以获取view实际的宽getWidth()和高getHeight()
			@Override
			public boolean onPreDraw() {
				// TODO Auto-generated method stub
				getViewTreeObserver().removeOnPreDrawListener(this); 
				
				Log.e("RockerView", getWidth() + "/" +  getHeight());
				mCenterPoint = new PointF(getWidth() / 2, getHeight() / 2);
				mRockerBg_X = mCenterPoint.x;
				mRockerBg_Y = mCenterPoint.y;
				
				mRockerBtn_X = mCenterPoint.x;
				mRockerBtn_Y = mCenterPoint.y;
				
				float tmp_f = mBmpRockerBg.getWidth() / (float)(mBmpRockerBg.getWidth() + mBmpRockerBtn.getWidth());
				mRockerBg_R = tmp_f * getWidth() / 2;
				mRockerBtn_R = (1.0f - tmp_f)* getWidth() / 2;
				
				return true;
			}
		});
	
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				while(true){
					
					//系统调用onDraw方法刷新画面
					RockerView.this.postInvalidate();
					
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}).start();
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDraw(canvas);
		canvas.drawBitmap(mBmpRockerBg, null, 
				new Rect((int)(mRockerBg_X - mRockerBg_R), 
						(int)(mRockerBg_Y - mRockerBg_R), 
						(int)(mRockerBg_X + mRockerBg_R), 
						(int)(mRockerBg_Y + mRockerBg_R)), 
				null);
		canvas.drawBitmap(mBmpRockerBtn, null, 
				new Rect((int)(mRockerBtn_X - mRockerBtn_R), 
						(int)(mRockerBtn_Y - mRockerBtn_R), 
						(int)(mRockerBtn_X + mRockerBtn_R), 
						(int)(mRockerBtn_Y + mRockerBtn_R)), 
				null);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) {
			// 当触屏区域不在活动范围内
			if (Math.sqrt(Math.pow((mRockerBg_X - (int) event.getX()), 2) + Math.pow((mRockerBg_Y - (int) event.getY()), 2)) >= mRockerBg_R) {
				//得到摇杆与触屏点所形成的角度
				double tempRad = getRad(mRockerBg_X, mRockerBg_Y, event.getX(), event.getY());
				//保证内部小圆运动的长度限制
				getXY(mRockerBg_X, mRockerBg_Y, mRockerBg_R, tempRad);
			} else {//如果小球中心点小于活动区域则随着用户触屏点移动即可
				mRockerBtn_X = (int) event.getX();
				mRockerBtn_Y = (int) event.getY();
			}
			if(mRockerChangeListener != null) {
				mRockerChangeListener.report(mRockerBtn_X - mCenterPoint.x, mRockerBtn_Y - mCenterPoint.y);
			}
		} else if (event.getAction() == MotionEvent.ACTION_UP) {
			//当释放按键时摇杆要恢复摇杆的位置为初始位置
			mRockerBtn_X = mCenterPoint.x;
			mRockerBtn_Y = mCenterPoint.y;
			if(mRockerChangeListener != null) {
				mRockerChangeListener.report(0, 0);
			}
		}
		return true;
	}
	
	/***
	 * 得到两点之间的弧度
	 */
	public double getRad(float px1, float py1, float px2, float py2) {
		//得到两点X的距离
		float x = px2 - px1;
		//得到两点Y的距离
		float y = py1 - py2;
		//算出斜边长
		float xie = (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
		//得到这个角度的余弦值(通过三角函数中的定理 :邻边/斜边=角度余弦值)
		float cosAngle = x / xie;
		//通过反余弦定理获取到其角度的弧度
		float rad = (float) Math.acos(cosAngle);
		//注意:当触屏的位置Y坐标
   
   <摇杆的y坐标我们要取反值-0~-180 if (py2 < py1) { rad } return rad; ** * @param r 圆周运动的旋转点 centerx 旋转点x centery 旋转点y 旋转的弧度 public void getxy(float centerx, float centery, r, double rad) 获取圆周运动的x坐标 mrockerbtn_x="(float)" (r math.cos(rad)) + centerx; 获取圆周运动的y坐标 mrockerbtn_y="(float)" math.sin(rad)) centery; rockerchangelistener mrockerchangelistener="rockerChangeListener;" setrockerchangelistener(rockerchangelistener rockerchangelistener) interface report(float x, y); code>

2.2. activity_main.xml 


    
    

    
     
     
    
	
     
     


    
    

三.远程控制

1.核心控制代码:

MainActivity.java

package com.boss.xiao.streerocker;

import android.app.Activity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.content.Intent;
import android.os.Bundle;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ToggleButton;
import java.io.IOException;
import java.io.Serializable;

public class MainActivity extends Activity {

	private EditText edtTxt_Addr;
    private EditText edtTxt_Port;
    private ToggleButton tglBtn;
    private ToggleButton btn_fire;
    private Button btn_rocker;
    private String model="connector";
    Intent intent;
    private RockerView rockerView1;
	private RockerView rockerView2;
	private static String left_flag="LEFT";
	private static String right_flag="RIGHT";
	private static String rec_flag="Succee";
	private static String open_flag="OPEN";
	private static String close_flag="CLOSE";
	private static boolean flag_report=true;
	
   // private TextView tv_Msg;
   // private EditText edtTxt_Data;
   // private Button btn_Send;
	private static final String TAG = "MainActivity";
    private TcpClientConnector connector;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
        InitWidgets();
        connector = TcpClientConnector.getInstance();   //获取connector实例
        tglBtn.setOnCheckedChangeListener(new TglBtnCheckedChangeEvents());
        btn_fire.setOnCheckedChangeListener(new fireBtnCheckedChangeEvents());
        InitRocker();
    //    btn_rocker.setOnClickListener(new ButtonClickEvent());
        
	}
    /*初始化 摇杆**/
	private void InitRocker()
	{


		rockerView1 = (RockerView) findViewById(R.id.rockerView1);
		rockerView2 = (RockerView) findViewById(R.id.rockerView2);
		
		
		rockerView1.setRockerChangeListener(new RockerView.RockerChangeListener() {

					@Override
					public void report(float x, float y) {
						// TODO Auto-generated method stub
						 Log.e(x + "/" + y,TAG);
						// setLayout(rockerView2, (int)x, (int)y);
						//setLayout(rockerView2, (int)x, (int)y);
						//String data="1000000";
						 try{
							// connector.send(left_flag);
							// if(flag_report)
							  if(flag_report==true)
							  {	  
								  if(x<0)
								  {
									  connector.send(left_flag);
								  }
								  else if(x>=0)
								  {
									  connector.send(right_flag);
								  }
								  /*else
								  {
									  Log.d("everything is ok",TAG);
								  }*/
								  flag_report=false;
							  } 
							  else
							  {
								  Log.d("this cmd is not acesss",TAG);
							  }
			                    
			                }catch (IOException e){
			                    e.printStackTrace();
			                }
						
					}
				});

		rockerView2.setRockerChangeListener(new RockerView.RockerChangeListener() {

					@Override
					public void report(float x, float y) {
						// TODO Auto-generated method stub
						 Log.e(x + "/" + y,TAG);
						
					}
				});
	}
	
    /***
     * 控件初始化
     */
    private void InitWidgets(){
        edtTxt_Addr = (EditText) findViewById(R.id.edtTxt_Addr);
        edtTxt_Port = (EditText) findViewById(R.id.edtTxt_Port);
        tglBtn = (ToggleButton) findViewById(R.id.tglBtn);
        btn_fire= (ToggleButton) findViewById(R.id.btn_fire);
     //   btn_rocker = (Button) findViewById(R.id.btn_rocker);
      //  tv_Msg = (TextView) findViewById(R.id.tv_Msg);
      //  edtTxt_Data = (EditText) findViewById(R.id.edtTxt_Data);
     //   btn_Send = (Button) findViewById(R.id.btn_Send);
    }

    class TglBtnCheckedChangeEvents implements ToggleButton.OnCheckedChangeListener{

        @Override
        public void onCheckedChanged(CompoundButton btnView, boolean isChecked){
            if(btnView == tglBtn){
                if(isChecked == true){
                    //连接Tcp服务器端
                    connector.createConnect("172.27.35.16",8888);   //调试使用
                   // connector.createConnect(edtTxt_Addr.getText().toString(),Integer.parseInt(edtTxt_Port.getText().toString()));
                    connector.setOnConnectListener(new TcpClientConnector.ConnectListener() {
                        @Override
                        public void onReceiveData(String data) {
                            //Received Data,do somethings.
                           // tv_Msg.append("Server:"+ data + "\n");
                        	Log.d("data = "+data,TAG);
                        	if(data.equals(rec_flag))
                        	{
                        		flag_report=true;
                        		Log.d("I get report "+data,TAG);
                        	}
                        }
                    });
                }else{
                    try{   //断开与服务器的连接
                        connector.disconnect();
                    }catch(IOException e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    class fireBtnCheckedChangeEvents implements ToggleButton.OnCheckedChangeListener{

        @Override
        public void onCheckedChanged(CompoundButton btnView, boolean isChecked){
            if(btnView == btn_fire){
                if(isChecked == true){
                	try{
                		 connector.send(open_flag);
		                    
		                }catch (IOException e){
		                    e.printStackTrace();
		                }
                 
                }else{
                	try{
               		 	connector.send(close_flag);
		                    
		                }catch (IOException e){
		                    e.printStackTrace();
		                }
                }
            }
        }
    }

    /*class ButtonClickEvent implements View.OnClickListener{
       

		public void onClick(View v) {
            if (v == btn_rocker){

            	
              //  connector.send(edtTxt_Data.getText().toString());
              //  tv_Msg.append("Client:"+ edtTxt_Data.getText().toString() + "\n");
            }
        }
    }*/
}

四.实测效果


图2 android虚拟摇杆图


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值