上次成功实现了通过笔记本电脑蓝牙来控制智能小车机器人的运动,但是通过电脑控制毕竟不方便,于是乎~本人打算将控制程序移植到手机上。
目前主流的手机操作系统有塞班、安卓(Android)、Windows Mobile,对比了一下,首先,塞班是用C++写的,这么多门语言我唯独看到C++就头大···,放弃了···,Windows Moblie 其实和之前发的电脑端程序基本是一样的,也就没什么意思了,最后决定选择目前正火的Android手机作为控制平台。
Android是个开源的应用,使用Java语言对其编程。
于是这次的开发我选用Eclipse作为开发工具,用Java语言开发手机端的控制程序,由于之前对Android的蓝牙通信这块涉及不多,一开始感觉有点小茫然,而网上也少有这方面的例程,有少数人做出了类似的东西,但是只传了个视频装X!雪特····经过几天的研究,最终确定了手机蓝牙通信其实就是Socket编程,再经过一番编写和调试,昨晚终于大功告成!这是视频:下面开始介绍Android手机端控制程序的编写:首先打开Eclipse,当然之前的Java开发环境和安卓开发工具自己得先配置好,这里就不多说了,网上教程一大摞。
然后新建一个Android项目,修改布局文件main.xml,代码如下:<?xml version="1.0" encoding="utf-8"?><AbsoluteLayoutandroid:id="@+id/widget0"android:layout_width="fill_parent"android:layout_height="fill_parent"xmlns:android="/apk/res/android"><Buttonandroid:id="@+id/btnF"android:layout_width="100px"android:layout_height="60px"android:text="前进"android:layout_x="130px"android:layout_y="62px"></Button><Buttonandroid:id="@+id/btnL"android:layout_width="100px"android:layout_height="60px"android:text="左转"android:layout_x="20px"android:layout_y="152px"></Button><Buttonandroid:id="@+id/btnR"android:layout_width="100px"android:layout_height="60px"android:text="右转"android:layout_x="240px"android:layout_y="152px"></Button><Buttonandroid:id="@+id/btnB"android:layout_width="100px"android:layout_height="60px"android:text="后退"android:layout_x="130px"android:layout_y="242px"></Button><Buttonandroid:id="@+id/btnS"android:layout_width="100px"android:layout_height="60px"android:text="停止"android:layout_x="130px"android:layout_y="152px"></Button></AbsoluteLayout>这个布局文件的效果就是如视频中所示的手机操作界面。
然后是权限声明,这一步不能少,否则将无法使用安卓手机的蓝牙功能。
权限声明如下:打开AndroidManifest.xml文件,修改代码如下:<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="/apk/res/android"package="com.ThinBTClient.www"android:versionCode="1"android:versionName="1.0"><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /><uses-permission android:name="android.permission.BLUETOOTH" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".ThinBTClient"android:label="@string/app_name"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="UNCHER" /> </intent-filter></activity></application></manifest>其中红色、加粗部分就是要添加的权限声明。
然后编写Activity中的执行代码,这些代码的作用就是发送指令,控制小车的运动。
代码如下:package com.ThinBTClient.www;import android.app.Activity;import android.os.Bundle;import java.io.IOException;import java.io.OutputStream;import java.util.UUID;import android.app.Activity;import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice;import android.bluetooth.BluetoothSocket;import android.content.DialogInterface;import android.content.DialogInterface.OnClickListener;import android.os.Bundle;import monDataKinds.Event;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.widget.Button;import android.widget.Toast;public class ThinBTClient extends Activity {private static final String TAG = "THINBTCLIENT";private static final boolean D = true;private BluetoothAdapter mBluetoothAdapter = null;private BluetoothSocket btSocket = null;private OutputStream outStream = null;Button mButtonF;Button mButtonB;Button mButtonL;Button mButtonR;Button mButtonS;private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");private static String address = "00:11:03:21:00:43"; // <==要连接的蓝牙设备MAC 地址/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.main);//前进mButtonF=(Button)findViewById(R.id.btnF);mButtonF.setOnTouchListener(new Button.OnTouchListener(){ @Overridepublic boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubString message;byte[] msgBuffer;int action = event.getAction();switch(action){case MotionEvent.ACTION_DOWN:try {outStream = btSocket.getOutputStream();} catch (IOException e) {Log.e(TAG, "ON RESUME: Output stream creation failed.", e);}message = "1";msgBuffer = message.getBytes();try {outStream.write(msgBuffer);} catch (IOException e) {Log.e(TAG, "ON RESUME: Exception during write.", e);}break;case MotionEvent.ACTION_UP:try {outStream = btSocket.getOutputStream();} catch (IOException e) {Log.e(TAG, "ON RESUME: Output stream creation failed.", e);}message = "0";msgBuffer = message.getBytes();try {outStream.write(msgBuffer);} catch (IOException e) {Log.e(TAG, "ON RESUME: Exception during write.", e);}break;}return false;}});//后退mButtonB=(Button)findViewById(R.id.btnB);mButtonB.setOnTouchListener(new Button.OnTouchListener(){ @Overridepublic boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubString message;byte[] msgBuffer;int action = event.getAction();switch(action){case MotionEvent.ACTION_DOWN:try {outStream = btSocket.getOutputStream();} catch (IOException e) {Log.e(TAG, "ON RESUME: Output stream creation failed.", e);}message = "3";msgBuffer = message.getBytes();try {outStream.write(msgBuffer);} catch (IOException e) {Log.e(TAG, "ON RESUME: Exception during write.", e);}break;case MotionEvent.ACTION_UP:try {outStream = btSocket.getOutputStream();} catch (IOException e) {Log.e(TAG, "ON RESUME: Output stream creation failed.", e);}message = "0";msgBuffer = message.getBytes();try {outStream.write(msgBuffer);} catch (IOException e) {Log.e(TAG, "ON RESUME: Exception during write.", e);}break;}return false;}});//左转mButtonL=(Button)findViewById(R.id.btnL);mButtonL.setOnTouchListener(new Button.OnTouchListener(){@Overridepublic boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubString message;byte[] msgBuffer;int action = event.getAction();switch(action){case MotionEvent.ACTION_DOWN:try {outStream = btSocket.getOutputStream();} catch (IOException e) {Log.e(TAG, "ON RESUME: Output stream creation failed.", e);}message = "2";msgBuffer = message.getBytes();try {outStream.write(msgBuffer);} catch (IOException e) {Log.e(TAG, "ON RESUME: Exception during write.", e);}break;case MotionEvent.ACTION_UP:try {outStream = btSocket.getOutputStream();} catch (IOException e) {Log.e(TAG, "ON RESUME: Output stream creation failed.", e);}message = "0";msgBuffer = message.getBytes();try {outStream.write(msgBuffer);} catch (IOException e) {Log.e(TAG, "ON RESUME: Exception during write.", e);}break;}return false;}});//右转mButtonR=(Button)findViewById(R.id.btnR);mButtonR.setOnTouchListener(new Button.OnTouchListener(){ @Overridepublic boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubString message;byte[] msgBuffer;int action = event.getAction();switch(action){case MotionEvent.ACTION_DOWN:try {outStream = btSocket.getOutputStream();} catch (IOException e) {Log.e(TAG, "ON RESUME: Output stream creation failed.", e);}message = "4";msgBuffer = message.getBytes();try {outStream.write(msgBuffer);} catch (IOException e) {Log.e(TAG, "ON RESUME: Exception during write.", e);}break;case MotionEvent.ACTION_UP:try {outStream = btSocket.getOutputStream();} catch (IOException e) {Log.e(TAG, "ON RESUME: Output stream creation failed.", e);}message = "0";msgBuffer = message.getBytes();try {outStream.write(msgBuffer);} catch (IOException e) {Log.e(TAG, "ON RESUME: Exception during write.", e);}break;}return false;}});//停止mButtonS=(Button)findViewById(R.id.btnS);mButtonS.setOnTouchListener(new Button.OnTouchListener(){ @Overridepublic boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubif(event.getAction()==MotionEvent.ACTION_DOWN)try {outStream = btSocket.getOutputStream();} catch (IOException e) {Log.e(TAG, "ON RESUME: Output stream creation failed.", e);}String message = "0";byte[] msgBuffer = message.getBytes();try {outStream.write(msgBuffer);} catch (IOException e) {Log.e(TAG, "ON RESUME: Exception during write.", e);}return false;}});if (D)Log.e(TAG, "+++ ON CREATE +++");mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();if (mBluetoothAdapter == null) {Toast.makeText(this, "Bluetooth is not available.", Toast.LENGTH_LONG).show();finish();return;}if (!mBluetoothAdapter.isEnabled()) {Toast.makeText(this, "Please enable your Bluetooth and re-runthis program.", Toast.LENGTH_LONG).show();finish();return;}if (D)Log.e(TAG, "+++ DONE IN ON CREATE, GOT LOCAL BT ADAPTER +++");}@Overridepublic void onStart() {super.onStart();if (D) Log.e(TAG, "++ ON START ++");}@Overridepublic void onResume() {super.onResume();if (D) {Log.e(TAG, "+ ON RESUME +");Log.e(TAG, "+ ABOUT TO ATTEMPT CLIENT CONNECT +");}BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);try {btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);} catch (IOException e) {Log.e(TAG, "ON RESUME: Socket creation failed.", e);}mBluetoothAdapter.cancelDiscovery();try {btSocket.connect();Log.e(TAG, "ON RESUME: BT connection established, data transfer link open.");} catch (IOException e) {try {btSocket.close();} catch (IOException e2) {Log .e(TAG,"ON RESUME: Unable to close socket during connection failure", e2);}}// Create a data stream so we can talk to server.if (D)Log.e(TAG, "+ ABOUT TO SAY SOMETHING TO SERVER +");/* try {outStream = btSocket.getOutputStream();} catch (IOException e) {Log.e(TAG, "ON RESUME: Output stream creation failed.", e);}String message = "1";byte[] msgBuffer = message.getBytes();try {outStream.write(msgBuffer);} catch (IOException e) {Log.e(TAG, "ON RESUME: Exception during write.", e);}*/}@Overridepublic void onPause() {super.onPause();if (D)Log.e(TAG, "- ON PAUSE -");if (outStream != null) {try {outStream.flush();} catch (IOException e) {Log.e(TAG, "ON PAUSE: Couldn't flush output stream.", e);}}try {btSocket.close();} catch (IOException e2) {Log.e(TAG, "ON PAUSE: Unable to close socket.", e2);}}@Overridepublic void onStop() {super.onStop();if (D)Log.e(TAG, "-- ON STOP --");}@Overridepublic void onDestroy() {super.onDestroy();if (D) Log.e(TAG, "--- ON DESTROY ---");}}可以看到,在这个程序中我直接把小车蓝牙模块的MAC地址给写进去了,其实更合理一点应该让程序运行后搜索周围蓝牙设备,然后选择需要连接的设备,获取它的MAC地址再连接,但是我为了图省事,就直接把我的小车的蓝牙MAC给定死了(反正也没那么多小车让我遥控~~~),这样一打开程序,手机将自动连接智能小车。