1. 程式人生 > >WIFI小車之旅(二)手機控制端

WIFI小車之旅(二)手機控制端

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">手機端的上機位比較的簡單…共兩個介面…一個介面用於設定IP和使用者名稱和密碼…另一個是主要的控制介面…用於給路由器傳遞控制指令並接受從路由器傳遞回來的資料顯示在手機螢幕上…介面如下……</span>


登入介面比較的簡單,就四個編輯框和兩個按鈕,一個登入一個退出,通訊方面使用的是較為簡單的socket,原始碼如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fff6f6f6" >

    <LinearLayout
        android:id="@+id/input_mainxml"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:orientation="vertical" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal" >

            <TextView
                android:layout_width="70dp"
                android:layout_height="match_parent"
                android:gravity="center_vertical"
                android:text="IP:"
                android:textSize="25sp" />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/background_style_black" >

                <EditText
                    android:id="@+id/edi_input_ip"
                    android:layout_width="220dp"
                    android:layout_height="wrap_content"
                    android:layout_margin="1dp"
                    android:background="@drawable/background_style_white"
                    android:maxLength="15"
                    android:textSize="25sp" />
            </LinearLayout>
        </LinearLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:orientation="horizontal" >

            <TextView
                android:layout_width="70dp"
                android:layout_height="match_parent"
                android:gravity="center_vertical"
                android:text="埠:"
                android:textSize="18sp" />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/background_style_black" >

                <EditText
                    android:id="@+id/edi_input_port"
                    android:layout_width="220dp"
                    android:layout_height="wrap_content"
                    android:layout_margin="1dp"
                    android:background="@drawable/background_style_white"
                    android:inputType="number"
                    android:maxLength="5"
                    android:textSize="25sp" />
            </LinearLayout>
        </LinearLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:orientation="horizontal" >

            <TextView
                android:layout_width="70dp"
                android:layout_height="match_parent"
                android:gravity="center_vertical"
                android:text="使用者:"
                android:textSize="18sp" />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/background_style_black" >

                <EditText
                    android:id="@+id/edi_input_user"
                    android:layout_width="220dp"
                    android:layout_height="wrap_content"
                    android:layout_margin="1dp"
                    android:background="@drawable/background_style_white"
                    android:maxLength="20"
                    android:textSize="25sp" />
            </LinearLayout>
        </LinearLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:orientation="horizontal" >

            <TextView
                android:layout_width="70dp"
                android:layout_height="match_parent"
                android:gravity="center_vertical"
                android:text="密碼:"
                android:textSize="18sp" />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/background_style_black" >

                <EditText
                    android:id="@+id/edi_input_password"
                    android:layout_width="220dp"
                    android:layout_height="wrap_content"
                    android:layout_margin="1dp"
                    android:background="@drawable/background_style_white"
                    android:inputType="textPassword"
                    android:maxLength="20"
                    android:textSize="25sp" />
            </LinearLayout>
        </LinearLayout>
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/input_mainxml"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:orientation="horizontal" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/background_style_black" >

            <Button
                android:id="@+id/bnt_login"
                android:layout_width="120dp"
                android:layout_height="35dp"
                android:layout_margin="1dp"
                android:background="@drawable/background_style_green"
                android:text="登入"
                android:textSize="25sp" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:background="@drawable/background_style_black" >

            <Button
                android:id="@+id/bnt_exit"
                android:layout_width="120dp"
                android:layout_height="35dp"
                android:layout_margin="1dp"
                android:background="@drawable/background_style_white"
                android:text="退出"
                android:textSize="25sp" />
        </LinearLayout>
    </LinearLayout>

</RelativeLayout>
LoginActivity.java
package com.control.tank.activity;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Serializable;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.control.tank.R;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class LoginActivity extends Activity implements OnClickListener{

	EditText ipAddressEdi,portEdi,userEdi,passwordEdi;
	String ipAddress,port,user,password;

	Button loginBnt,exitBnt;
	
	Socket clientSocket;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_login);

		ipAddressEdi=(EditText)findViewById(R.id.edi_input_ip);
		portEdi=(EditText)findViewById(R.id.edi_input_port);
		userEdi=(EditText)findViewById(R.id.edi_input_user);
		passwordEdi=(EditText)findViewById(R.id.edi_input_port);

		loginBnt=(Button)findViewById(R.id.bnt_login);
		exitBnt=(Button)findViewById(R.id.bnt_exit);

		loginBnt.setOnClickListener(this);
		exitBnt.setOnClickListener(this);

	}

	@Override
	public void onClick(View id) {
		switch(id.getId()){
		case R.id.bnt_login:

			ipAddress=ipAddressEdi.getText().toString();
			if(ipAddress.equals("")){
				Toast.makeText(this,"IP地址不能為空",Toast.LENGTH_SHORT).show();
				return;
			}

			//檢驗IP地址是否正確,如果需要對映域名,需要新增判斷
			Pattern pattern = Pattern.compile("\\b((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\.((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\b");
			Matcher matcher = pattern.matcher(ipAddress);
			if(!matcher.matches()){
				Toast.makeText(this,"IP地址錯誤",Toast.LENGTH_SHORT).show();
				return;
			}

			port=portEdi.getText().toString();
			if(port.equals("")){
				Toast.makeText(this,"埠不能為空",Toast.LENGTH_SHORT).show();
				return;
			}else if(Integer.parseInt(port)<0&&Integer.parseInt(port)>65536){
				Toast.makeText(this,"埠範圍異常",Toast.LENGTH_SHORT).show();
				return;
			}

			user=userEdi.getText().toString();
			if(user.equals("")){
				Toast.makeText(this,"使用者名稱不能為空",Toast.LENGTH_SHORT).show();
				return;
			}else{

			}

			password=passwordEdi.getText().toString();
			if(password.equals("")){
				Toast.makeText(this,"密碼不能為空",Toast.LENGTH_SHORT).show();
				return;
			}else{

			}

			if(checkLogin(user,password)){
				Toast.makeText(this,"登入成功",Toast.LENGTH_SHORT).show();
				Intent intent=new Intent(this,MainActivity.class);
				Bundle bundle=new Bundle();
				bundle.putSerializable("socket",(Serializable)clientSocket);
				intent.putExtras(bundle);
				startActivity(intent);
			}else{
				Toast.makeText(this,"使用者名稱或密碼不正確",Toast.LENGTH_SHORT).show();
			}
			
			break;
		case R.id.bnt_exit:
			finish();
			break;
		}
	}

	//使用socket進行使用者名稱和密碼的校驗
	boolean checkLogin(String username,String password){
		try {
			Socket socket=new Socket(ipAddress,Integer.parseInt(port));

			PrintWriter os=new PrintWriter(socket.getOutputStream());

			BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));

			os.println(username);
			os.flush();
			
			os.println(password);
			os.flush();
			
			String checkResult=is.readLine();
			
			is.close();
			os.close();
		
			
			if(checkResult.equals("loginright")){
				clientSocket=socket;
				return true;
			}else if(checkResult.equals("loginwrong")){
				socket.close();
				return false;
			}

		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

}

登入成功後進入主介面,請無視那個用於測試的藍芽列表:

介面如下:


攝像頭監控使用webview載入openwrt路由器上的網頁來顯示監視的影象,地圖用的是百度的地圖,控制小車方向使用的是虛擬搖桿,廢話不多說,直接上程式碼:

MainActivity.java

package com.control.tank.activity;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.MapView;
import com.control.tank.R;
import com.control.tank.view.MySurfaceView;
import com.control.tank.view.RadarView;
import com.control.tank.view.VerticalSeekBar;

public class MainActivity extends Activity implements OnClickListener{

	BluetoothSocket blueToothSocket=null;
	Socket MainSocket=null;
	ArrayAdapter<String> boothAdapter;
	BluetoothAdapter adapter;
	TextView blueToothMessage;
	OutputStream out;

	MySurfaceView controlDirection;

	List<String> bluetoothList=new ArrayList<String>();
	String message="";

	VerticalSeekBar seekbar;

	private MapView mMapView;
	private BaiduMap mBaiduMap;

	Button led1,led2,led3,led4,aimBnt;

	View mapButtonLayout;
	Button bntMapBlowUp,bntMapBlowDown,bntMapCenter,bntMapHide;
	Button lightBnt,leftBnt,rightBnt,weaponLockBnt;

	Socket socket;
	String order;
	boolean stopOrRun=true;
	RadarView radarView;
	int radarCentimetre=7500;

	WebView webView;

	//==============================================================================================
	//藍芽掃描部分
	private BroadcastReceiver searchDevices = new BroadcastReceiver(){

		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();

			if (BluetoothDevice.ACTION_FOUND.equals(action)) {

				BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

				String str= device.getName()+"  MAC:"+device.getAddress();
				bluetoothList.add(device.getAddress());	
				boothAdapter.add(str);	
			}else if(BluetoothDevice.ACTION_FOUND.equals(action)){
				blueToothMessage.setText("�����������");
			}
		}

	};
	//藍芽掃描部分
	//==============================================================================================


	boolean led1On=false,led2On=false;
	boolean led3On=false,led4On=false;
	boolean weaponOnOff=false,lightOnOff=false,aimOnOff=false;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		requestWindowFeature(Window.FEATURE_NO_TITLE);

		setContentView(R.layout.activity_main);

		webView=(WebView)findViewById(R.id.webview);

		WebSettings settings = webView.getSettings(); 
		settings.setUseWideViewPort(true); 
		settings.setLoadWithOverviewMode(true); 
		webView.setWebViewClient(new WebViewClient(){       
			public boolean shouldOverrideUrlLoading(WebView view, String url) {       
				view.loadUrl(url);       
				return true;       
			}       
		});   
		
		//網址改為路由器上的攝像頭的地址
		webView.loadUrl("http://www.baidu.com");

		led1=(Button)findViewById(R.id.button1);
		led2=(Button)findViewById(R.id.button2);
		led3=(Button)findViewById(R.id.button3);
		led4=(Button)findViewById(R.id.button4);
		aimBnt=(Button)findViewById(R.id.aimBnt);

		led1.setOnClickListener(this);
		led2.setOnClickListener(this);
		led3.setOnClickListener(this);
		led4.setOnClickListener(this);
		aimBnt.setOnClickListener(this);

		lightBnt=(Button)findViewById(R.id.lightBnt);
		leftBnt=(Button)findViewById(R.id.leftBnt);
		rightBnt=(Button)findViewById(R.id.rightBnt);
		weaponLockBnt=(Button)findViewById(R.id.weaponBnt);

		lightBnt.setOnClickListener(this);
		leftBnt.setOnClickListener(this);
		rightBnt.setOnClickListener(this);
		weaponLockBnt.setOnClickListener(this);

		mMapView = (MapView) findViewById(R.id.bmapView);
		mBaiduMap = mMapView.getMap();

		mapButtonLayout=findViewById(R.id.layout_mapcontrol_button);

		bntMapBlowUp=(Button)findViewById(R.id.bnt_mapcontrol_blowup);
		bntMapBlowDown=(Button)findViewById(R.id.bnt_mapcontrol_blowdown);
		bntMapCenter=(Button)findViewById(R.id.bnt_mapcontrol_center);
		bntMapHide=(Button)findViewById(R.id.bnt_mapcontrol_hide);

		bntMapBlowUp.setOnClickListener(this);
		bntMapBlowDown.setOnClickListener(this);
		bntMapCenter.setOnClickListener(this);
		bntMapHide.setOnClickListener(this);

		startRadar();

		//搖桿控制器監聽器
		controlDirection=(MySurfaceView)findViewById(R.id.controlDirectionBnt);

		controlDirection.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View arg0, MotionEvent arg1) {
				controlDirection.getXDirection();
				controlDirection.getYDirection();
				//搖桿控制器返回值,以座標0,0為圓心
				float x=controlDirection.getXDirection();
				float y=controlDirection.getYDirection();
				
				return false;
			}
		});

		//舵機控制器,使用的是豎直滑動條
		seekbar=(VerticalSeekBar)findViewById(R.id.seekBar1);
		seekbar.setMax(33);
		seekbar.setProgress(16);
		seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

			public void onStopTrackingTouch(SeekBar arg0) {				
			}

			public void onStartTrackingTouch(SeekBar arg0) {				
			}

			public void onProgressChanged(SeekBar arg0, int progress, boolean arg2) {	

				String s=new String("KD0"+	String.valueOf(progress+14)+"0");	
				//和微控制器規定的字串命令格式,六位字串,K開頭,D表明是舵機,三位角度值,最後一位補零

				try {
					out.write(s.getBytes());
					out.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}

			}
		});

		//===============================================================================
		//藍芽連線部分
		Button blueToothSearch=(Button)findViewById(R.id.blueToothSearch);
		final ListView blueToothList=(ListView)findViewById(R.id.boothlist);
		blueToothMessage=(TextView)findViewById(R.id.blueToothMessage);

		blueToothList.setOnItemClickListener(new OnItemClickListener() {

			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				blueTeethChoice(position);
			}

		});

		boothAdapter=new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item);
		blueToothList.setAdapter(boothAdapter);

		IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
		registerReceiver(searchDevices, filter);
		filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
		registerReceiver(searchDevices, filter);

		blueToothSearch.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

				try {
					blueTeeth();
				} catch (IOException e1) {
					e1.printStackTrace();
				}

			}
		});
	}
	void blueTeeth() throws IOException{
		adapter=BluetoothAdapter.getDefaultAdapter(); 
		if (!adapter.isEnabled()) {              
			blueToothMessage.setText("���ȿ�������");
		}else{
			adapter.startDiscovery();
			blueToothMessage.setText("����������");
		}
	}

	void blueTeethChoice(int position){

		adapter.cancelDiscovery();
		final BluetoothDevice bluetoothDevice=adapter.getRemoteDevice(bluetoothList.get(position));

		String uuid="00001101-0000-1000-8000-00805F9B34FB";
		try {
			blueToothSocket=bluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
			new Thread(new Runnable(){
				@Override
				public void run() {
					message=bluetoothDevice.getName()+"������";
					blueToothMessage.post(new Runnable() {							
						@Override
						public void run() {
							blueToothMessage.setText(message);
						}
					});
					boolean connected=false;
					int connectTime=0;
					while(!connected&&connectTime<20)
					{
						try {
							blueToothSocket.connect();
							connected=true;
						} catch (IOException e) {
							connectTime++;
							e.printStackTrace();
						}	
					}
					if(connected){

						message=bluetoothDevice.getName()+"������";
						blueToothMessage.post(new Runnable() {							
							@Override
							public void run() {
								blueToothMessage.setText(message);
							}
						});
						try {
							out=blueToothSocket.getOutputStream();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}else{
						message=bluetoothDevice.getName()+"����ʧ��";
					}
					blueToothMessage.post(new Runnable() {							
						@Override
						public void run() {
							blueToothMessage.setText(message);
						}
					});
				}		

			}).start();		

		} catch (IOException e) {
			e.printStackTrace();
		}

	}
	//藍芽連線部分
	//===============================================================================
	
	//啟動雷達掃描
	void startRadar(){
		radarView=(RadarView)findViewById(R.id.radarView);

		new Thread(new Runnable() {

			@Override
			public void run() {
				while(true){
					try {
						Thread.sleep(30);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}	

					radarView.point[radarView.angle]=radarCentimetre*radarView.radius/(10*1000);

					if(radarView.angle==359){
						radarView.angle=0;
					}
					radarView.angle++;
					radarView.postInvalidate();
				}
			}
		}).start();

		//網路連線socket,用於傳送命令和接收路由器回傳的狀態資訊
		/*		
		Intent intent=getIntent();
		socket=(Socket)intent.getSerializableExtra("socket");

		new Thread(new Runnable() {

			@Override
			public void run() {

				try {
					PrintWriter os = new PrintWriter(socket.getOutputStream());
					BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));

					while(stopOrRun){
						try {
							Thread.sleep(500);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						os.println(order);
						os.flush();
					}

					os.close();
					is.close();

					socket.close();

				} catch (IOException e) {
					e.printStackTrace();
				}

			}
		}).start();
	}*/
	}

	//地圖顯示模式轉換
	public void setMapMode(View view) {
		/*	boolean checked = ((RadioButton) view).isChecked();*/
		/*switch (view.getId()) {
		case R.id.normal:
			if (checked)
				mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
			break;
		case R.id.statellite:
			if (checked)
				mBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
			break;
		}*/
	}

	public void setTraffic(View view) {
		mBaiduMap.setTrafficEnabled(((CheckBox) view).isChecked());
	}

	public void setBaiduHeatMap(View view) {
		mBaiduMap.setBaiduHeatMapEnabled(((CheckBox) view).isChecked());
	}

	@Override
	protected void onPause() {
		mMapView.onPause();
		super.onPause();
	}

	@Override
	protected void onResume() {
		mMapView.onResume();
		super.onResume();
	}

	//退出介面後關閉socket,並關閉地圖
	protected void onDestroy() {
		mMapView.onDestroy();
		super.onDestroy();

		try {
			if(MainSocket!=null)
			{
				MainSocket.close();	
			}
			if(blueToothSocket!=null)
			{
				blueToothSocket.close();	
			}
			if(out!=null)
			{
				out.close();	
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void onClick(View id) {

		switch(id.getId()){

		//按鈕,用於給路由器傳送指令
		case R.id.button1:
			if(!weaponOnOff){
				Toast.makeText(MainActivity.this,"請先開啟武器鎖",Toast.LENGTH_SHORT).show();
				return;
			}

			if(!led1On){
				led1.setBackgroundResource(R.drawable.missileslunch);	
				try {
					String s=new String("KL1100");	
					out.write(s.getBytes());
					out.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
				led1On=true;
			}else{
				led1.setBackgroundResource(R.drawable.missilestate);
				String s=new String("KL1000");
				try {
					out.write(s.getBytes());
					out.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
				led1On=false;
			}
			break;
		case R.id.button2:
			if(!weaponOnOff){
				Toast.makeText(MainActivity.this,"請先開啟武器鎖",Toast.LENGTH_SHORT).show();
				return;
			}

			if(!led2On){
				led2.setBackgroundResource(R.drawable.missileslunch);
				try {
					String s=new String("KL2100");	
					out.write(s.getBytes());
					out.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
				led2On=true;
			}else{
				led2.setBackgroundResource(R.drawable.missilestate);
				String s=new String("KL2000");	
				try {
					out.write(s.getBytes());
					out.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
				led2On=false;
			}
			break;
		case R.id.button3:
			if(!weaponOnOff){
				Toast.makeText(MainActivity.this,"請先開啟武器鎖",Toast.LENGTH_SHORT).show();
				return;
			}

			if(!led3On){
				led3.setBackgroundResource(R.drawable.missileslunch);
				try {
					String s=new String("KL3100");	
					out.write(s.getBytes());
					out.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
				led3On=true;
			}else{
				led3.setBackgroundResource(R.drawable.missilestate);
				String s=new String("KL3000");	
				try {
					out.write(s.getBytes());
					out.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
				led3On=false;
			}
			break;
		case R.id.button4:
			if(!weaponOnOff){
				Toast.makeText(MainActivity.this,"請先開啟武器鎖",Toast.LENGTH_SHORT).show();
				return;
			}


			if(!led4On){
				led4.setBackgroundResource(R.drawable.missileslunch);
				try {
					String s=new String("KL4100");	
					out.write(s.getBytes());
					out.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
				led4On=true;
			}else{
				led4.setBackgroundResource(R.drawable.missilestate);
				String s=new String("KL4000");	
				try {
					out.write(s.getBytes());
					out.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
				led4On=false;
			}
			break;

			//瞄準按鈕,啟動鐳射瞄準
		case R.id.aimBnt:
			if(!weaponOnOff){
				Toast.makeText(MainActivity.this,"請先開啟武器鎖",Toast.LENGTH_SHORT).show();
				return;
			}

			if(!aimOnOff){
				aimOnOff=true;
				aimBnt.setBackgroundResource(R.drawable.aimstate);
				try {
					String s=new String("KL0100");	
					out.write(s.getBytes());
					out.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}else{
				aimOnOff=false;
				aimBnt.setBackgroundResource(R.drawable.aimstateon);
				String s=new String("KL0000");	
				try {
					out.write(s.getBytes());
					out.flush();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			break;

			//開啟LED燈
		case R.id.lightBnt:
			if(lightOnOff){
				lightBnt.setBackgroundResource(R.drawable.lighton);	
				lightOnOff=false;
			}else{
				lightBnt.setBackgroundResource(R.drawable.lightoff);
				lightOnOff=true;
			}
			break;
			//步進電機左轉
		case R.id.leftBnt:
			break;
			//步進電機右轉
		case R.id.rightBnt:
			break;
			
			//武器加解鎖,防止誤觸按鈕
		case R.id.weaponBnt:
			if(!weaponOnOff){
				weaponLockBnt.setBackgroundResource(R.drawable.weaponoff);
				aimBnt.setBackgroundResource(R.drawable.aimstateon);
				led1.setBackgroundResource(R.drawable.missilestate);
				led2.setBackgroundResource(R.drawable.missilestate);
				led3.setBackgroundResource(R.drawable.missilestate);
				led4.setBackgroundResource(R.drawable.missilestate);
				weaponOnOff=true;
			}else{

				Log.e("wea",String.valueOf(aimOnOff));
				if(led1On||led2On||led3On||led4On||aimOnOff){
					Toast.makeText(MainActivity.this,"請關閉武器後加鎖",Toast.LENGTH_SHORT).show();
					return;
				}
				weaponLockBnt.setBackgroundResource(R.drawable.weaponon);
				aimBnt.setBackgroundResource(R.drawable.aimuuse);
				led1.setBackgroundResource(R.drawable.missilesuuse);
				led2.setBackgroundResource(R.drawable.missilesuuse);
				led3.setBackgroundResource(R.drawable.missilesuuse);
				led4.setBackgroundResource(R.drawable.missilesuuse);
				weaponOnOff=false;
			}
			break;

			//地圖控制按鈕
		case R.id.bnt_mapcontrol_blowup:
			break;
		case R.id.bnt_mapcontrol_blowdown:
			break;
		case R.id.bnt_mapcontrol_center:
			break;
		case R.id.bnt_mapcontrol_hide:
			if(mapButtonLayout.getVisibility()==View.GONE){
				mapButtonLayout.setVisibility(View.VISIBLE);
			}else{
				mapButtonLayout.setVisibility(View.GONE);
			}
			break;

		}

	}
}
虛擬部門的原始碼

MySurfaceView.java

package com.control.tank.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class MySurfaceView extends SurfaceView implements Callback, Runnable {
	private Thread th;
	private SurfaceHolder sfh;
	private Canvas canvas;
	private Paint paint;
	private boolean flag;	
	private int intWidth,intHeight;

	private int RockerCircleX =300;
	private int RockerCircleY =300;
	private int RockerCircleR =100;

	private float SmallRockerCircleX =300;
	private float SmallRockerCircleY =300;
	private float SmallRockerCircleR = 50;
	public MySurfaceView(Context context, AttributeSet attrs) {
		super(context,attrs);

		this.setKeepScreenOn(true);
		sfh = this.getHolder();
		sfh.addCallback(this);
		paint = new Paint();
		paint.setAntiAlias(true);
		setFocusable(true);
		setFocusableInTouchMode(true);
	}
	
	public float getXDirection(){
		return (SmallRockerCircleX-RockerCircleX);
	}
	
	public float getYDirection(){
		return (SmallRockerCircleY-RockerCircleY);
	}

	public void surfaceCreated(SurfaceHolder holder) {

		intWidth=this.getWidth();
		intHeight=this.getHeight();
		
		RockerCircleX =intWidth/2;
		RockerCircleY =intHeight/2;	
		RockerCircleR=intWidth/2-intWidth/4/2;
		
		SmallRockerCircleX =intWidth/2;
		SmallRockerCircleY=intHeight/2;
		SmallRockerCircleR=intWidth/4-intWidth/4/2;
		
		th = new Thread(this);
		flag = true;
		th.start();
		
	}

	public double getRad(float px1, float py1, float px2, float py2) {

		float x = px2 - px1;

		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);
		
		if (py2 < py1) {
			rad = -rad;
		}
		return rad;
	}

	public boolean onTouchEvent(MotionEvent event) {
		if (event.getAction() == MotionEvent.ACTION_DOWN ||event.getAction() == MotionEvent.ACTION_MOVE) {
	
			if (Math.sqrt(Math.pow((RockerCircleX - (int) event.getX()), 2)+ Math.pow((RockerCircleY - (int) event.getY()), 2)) >= RockerCircleR) {
		
				double tempRad = getRad(RockerCircleX, RockerCircleY, event.getX(), event.getY());
		
				getXY(RockerCircleX, RockerCircleY, RockerCircleR, tempRad);
			} else {
				SmallRockerCircleX = (int) event.getX();
				SmallRockerCircleY = (int) event.getY();
			}
		} else if (event.getAction() == MotionEvent.ACTION_UP) {
		
			SmallRockerCircleX =intWidth/2;
			SmallRockerCircleY =intHeight/2;
		}
		return true;
	}

	public void getXY(float centerX, float centerY, float R, double rad) {

		SmallRockerCircleX = (float) (R * Math.cos(rad)) + centerX;

		SmallRockerCircleY = (float) (R * Math.sin(rad)) + centerY;
	}
	
	public void draw() {
		try {
			canvas = sfh.lockCanvas();
			canvas.drawColor(Color.WHITE);
		
			paint.setColor(0x70000000);
		
			canvas.drawCircle(RockerCircleX, RockerCircleY, RockerCircleR, paint);
			paint.setColor(0x7000ff00);
		
			canvas.drawCircle(SmallRockerCircleX, SmallRockerCircleY, 
					SmallRockerCircleR, paint);
		} catch (Exception e) {

		} finally {
			try {
				if (canvas != null)
					sfh.unlockCanvasAndPost(canvas);
			} catch (Exception e2) {
			}
		}
	}
	
	public void run() {

		while (flag) {
			draw();
			try {
				Thread.sleep(50);
			} catch (Exception ex) {
			}
		}
	}
	
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
	}
	
	public void surfaceDestroyed(SurfaceHolder holder) {
		flag = false;

	}
}

雷達掃描控制元件

RadarView.java

package com.control.tank.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.view.View;

public class RadarView extends View {

	private int viewSizeBackground =2;
	private int viewSize = 500;
	private Paint mPaintLine;
	private Paint mPaintSector;
	private Paint mPaintPoint;
	public boolean isstart = false;
	public int angle=0;
	public int radius=0;
	private Matrix matrix;
	//360度上距離陣列
	public int[] point=new int[360];

	public RadarView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initPaint();
		setBackgroundColor(Color.TRANSPARENT);

	}

	private void initPaint() {
		mPaintLine = new Paint();
		mPaintLine.setStrokeWidth(2);
		mPaintLine.setAntiAlias(true);
		mPaintLine.setStyle(Style.STROKE);
		mPaintLine.setColor(0xff000000);

		mPaintSector = new Paint();
		mPaintSector.setColor(0x9D00ff00);
		mPaintSector.setAntiAlias(true);

		mPaintPoint=new Paint();
		mPaintPoint.setColor(Color.RED);
	}


	@Override
	protected void onDraw(Canvas canvas) {
		viewSize=getWidth();
		viewSizeBackground=viewSize/10/2;
		radius=(viewSize-viewSizeBackground*2)/2;
		canvas.drawLine(viewSize / 2,viewSizeBackground*2, viewSize / 2, viewSize-viewSizeBackground*2, mPaintLine);
		canvas.drawLine(viewSizeBackground*2, viewSize / 2, viewSize-viewSizeBackground*2, viewSize / 2, mPaintLine);
		mPaintLine.setStrokeWidth(1);
		for(int r=1;r<=10;r++){
			canvas.drawCircle(viewSize / 2,viewSize / 2,(viewSize/2-viewSizeBackground*2)/10*r, mPaintLine);
		}

		for(int h=0;h<point.length;h++){
			canvas.drawCircle((int)(point[h]*Math.sin(Math.PI/180*h))+ viewSize/2,viewSize/2-(int)(point[h]*Math.cos(Math.PI/180*h)),2, mPaintPoint);
		}

		Shader mShader = new SweepGradient(viewSize / 2, viewSize / 2,Color.TRANSPARENT, Color.GREEN);
		mPaintSector.setShader(mShader);
		matrix = new Matrix();
		matrix.postRotate(angle-90,viewSize / 2,viewSize / 2);
		canvas.concat(matrix);
		canvas.drawCircle(viewSize / 2, viewSize / 2,viewSize/2-viewSizeBackground*2, mPaintSector);
		super.onDraw(canvas);
	}

}
舵機控制控制元件,使用的是豎直滾動條

VerticalSeekBar.java

package com.control.tank.view; 

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.SeekBar;
  
public class VerticalSeekBar extends SeekBar {  
  
    public VerticalSeekBar(Context context) {  
        super(context);  
    }  
  
    public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {  
        super(context, attrs, defStyle);  
    }  
  
    public VerticalSeekBar(Context context, AttributeSet attrs) {  
        super(context, attrs);  
    }  
  
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
        super.onSizeChanged(h, w, oldh, oldw);  
    }  
   
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
        super.onMeasure(heightMeasureSpec, widthMeasureSpec);  
        setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());  
    }  
  
    protected void onDraw(Canvas c) {  

        c.rotate(-90);  

        c.translate(-getHeight(),0);  

        super.onDraw(c);  
    }  
  
    public boolean onTouchEvent(MotionEvent event) {  
    	
        if (!isEnabled()) {  
            return false;  
        }  
  
        switch (event.getAction()) {  
            case MotionEvent.ACTION_DOWN:  
            case MotionEvent.ACTION_MOVE:  
            case MotionEvent.ACTION_UP:  
                int i=0;  
       
                i=getMax() - (int) (getMax() * event.getY() / getHeight());  
     
                setProgress(i);  
              
                onSizeChanged(getWidth(), getHeight(), 0, 0);  

                break;  
  
            case MotionEvent.ACTION_CANCEL:  
                break;  
        }  
        return true;  
    }  
      
}  

使用藍芽連線了下51開發板,舵機可以正常運轉,其他的硬體還沒有買,等買了後再試試……