最简单DIY基于Android系统的万能蓝牙设备智能遥控器
51单片机物联网智能小车系列文章目录
第一篇:最简单DIY的51蓝牙遥控小车设计方案
第二篇:最简单DIY串口蓝牙硬件实现方案
第三篇:最简单DIY蓝牙PS2遥控器控制蓝牙智能小车
第四篇:最简单DIY基于51单片机的舵机控制器
第五篇:最简单DIY基于蓝牙、51单片机和舵机的钢铁爱国者机关枪控制器
第六篇:最简单DIY基于Android系统的万能蓝牙设备智能遥控器
文章目录
- 51单片机物联网智能小车系列文章目录
- 前言
- 一、最简单DIY基于Android系统的万能蓝牙设备智能遥控器是什么?
- 二、软件制作过程
- 1.设计软件逻辑
- 2.分析代码
- 三、仿真与调试
- 1.操控舵机云台:准备好硬件,上电,运行app。
- 2. 操控智能小车
- 总结
前言
daodanjishui物联网核心原创技术之最简单DIY基于Android系统的万能蓝牙设备智能遥控器。
市面上有各种开源智能手机舵机控制器app,但是有复杂的有简单的,如果想快速入门安卓app开发蓝牙设备万能遥控器,这个方案会给你一个快捷高效的方案。
一、最简单DIY基于Android系统的万能蓝牙设备智能遥控器是什么?
在第五篇完成了51单片机多个舵机控制的设计的遥杆,读者好奇当时为什么不写控制多个舵机的PWM波的手机APP呢?那是因为学习是一个循序渐进的过程,掌握基本的技能才能去举一反三。到现在来看是为我第六篇博文是第五篇博文的升级版,可以手机app替代ESP32蓝牙遥杆控制舵机,并且互相不受影响。安卓手机app的java代码相当精妙,纯粹是自己的原创代码,如果不好好专研深入思考,是不可能写出这样的代码的,物联网技术就需要万物互联,那能不能写一个安卓app来替代单片机组成的硬件蓝牙遥控器,就是使用一个app能控制智能小车( 第一篇)又能控制钢铁爱国者机关枪( 第五篇)?答案是肯定的,这也是鸿蒙系统想要做到的思想。
虽然市面上也有不少开源的蓝牙调试助手,但是跟硬件结合的代码却很少,特别是能遥控多个蓝牙设备的app更是少见,这个app还能实现在线调试硬件设备,能遥控我设计的智能小车和智能舵机云台,全方位开源原创,现在用文字的形式记录下来,这个代码蓝牙通信代码的改造,除了基本代码之外都是我原创的!这次源码进行了大幅度的升级,代码写得非常精简和奇妙,现在用文字的形式记录下来,对自己童年时代深刻地回忆和对未来技术的展望。“闭门造app”虽然有点痛苦,但是当你看到自己亲手做的app在手机上安装通过自制的遥控器遥控多个设备动起来的时候,你会发现一切的付出都是值得的!全家福如下图所示:
万能遥控器控制智能小车优酷视频地址:https://v.youku.com/v_show/id_XNDk2MDkyMjI0OA==.html?spm=a2hbt.13141534.app.55!25!2555!255!25!25!255!27A
直接看视频
51智能蓝牙小车控制
万能遥控器控制舵机云台优酷视频地址:https://v.youku.com/v_show/id_XNDk2MDkyMDUwOA==.html?firsttime=0
直接看视频
钢铁爱国者机关枪控制
功能描述:手机app发送指令控制智能小车或者智能云台,硬件将控制信息通过蓝牙返回给手机app显示,单片机解析控制指令,最后控制二自由度舵机转动或者小车运动,可玩性相当高,其实该app除了可以用蓝牙调试助手按键控制之外,也可以手机自带的重力传感器控制云台或者小车。
二、软件制作过程
1.设计软件逻辑
1.1明确小车控制协议:
(1)FFF\r\n是前进
(2)BBB\r\n是后退
(3)LLL\r\n是左转
(4)RRR\r\n是右转
(5)SSS\r\n是停止
1.2明确舵机控制协议:
(1)FFF\r\n是仰头
(2)BBB\r\n是低头
(3)LLL\r\n是左转
(4)RRR\r\n是右转
(5)SSS\r\n是切换机关开关
1.3准备一份蓝牙串口调试助手的app源码
首先强调一下这个app使用eclipse搭建的Android开发环境编写的Android4.3版本的app,如果想要定制高版本的app或者Android studio版本的源码请联系我。
部分源码如下:
package daodanjishui.Bluetooth;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
@SuppressLint("NewApi")
public class BluetoothService {
// Debugging
private static final String TAG = "BluetoothChatService";
private static final boolean D = true;
// Name for the SDP record when creating server socket
private static final String NAME_SECURE = "蓝牙搜索";
// Unique UUID for this application
private static final UUID MY_UUID = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB");
// Member fields
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private AcceptThread mSecureAcceptThread;
private AcceptThread mInsecureAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
// Constants that indicate the current connection state
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_LISTEN = 1; // now listening for incoming
// connections
public static final int STATE_CONNECTING = 2; // now initiating an outgoing
// connection
public static final int STATE_CONNECTED = 3; // now connected to a remote
// device
/**
* Constructor. Prepares a new BluetoothChat session.
*
* @param context
* The UI Activity Context
* @param handler
* A Handler to send messages back to the UI Activity
*/
@SuppressLint("NewApi")
public BluetoothService(Context context, Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
}
/**
* Set the current state of the chat connection
*
* @param state
* An integer defining the current connection state
*/
private synchronized void setState(int state) {
if (D)
Log.d(TAG, "setState() " + mState + " -> " + state);
mState = state;
// Give the new state to the Handler so the UI Activity can update
mHandler.obtainMessage(BTconnect.MESSAGE_STATE_CHANGE, state, -1)
.sendToTarget();
}
/**
* Return the current connection state.
*/
public synchronized int getState() {
return mState;
}
/**
* Start the chat service. Specifically start AcceptThread to begin a
* session in listening (server) mode. Called by the Activity onResume()
*/
public synchronized void start() {
if (D)
Log.d(TAG, "start");
// Cancel any thread attempting to make a connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
setState(STATE_LISTEN);
// Start the thread to listen on a BluetoothServerSocket
if (mSecureAcceptThread == null) {
mSecureAcceptThread = new AcceptThread(true);
mSecureAcceptThread.start();
}
if (mInsecureAcceptThread == null) {
mInsecureAcceptThread = new AcceptThread(false);
mInsecureAcceptThread.start();
}
}
/**
* Start the ConnectThread to initiate a connection to a remote device.
*
* @param device
* The BluetoothDevice to connect
* @param secure
* Socket Security type - Secure (true) , Insecure (false)
*/
public synchronized void connect(BluetoothDevice device, boolean secure) {
if (D)
Log.d(TAG, "connect to: " + device);
// Cancel any thread attempting to make a connection
if (mState == STATE_CONNECTING) {
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Start the thread to connect with the given device
mConnectThread = new ConnectThread(device, secure);//开启一个线程去连接远程蓝牙设备
mConnectThread.start();
setState(STATE_CONNECTING);
}
/**
* Start the ConnectedThread to begin managing a Bluetooth connection
*
* @param socket
* The BluetoothSocket on which the connection was made
* @param device
* The BluetoothDevice that has been connected
*/
@SuppressLint({ "NewApi", "NewApi" })
public synchronized void connected(BluetoothSocket socket,
BluetoothDevice device, final String socketType) {
if (D)
Log.d(TAG, "connected, Socket Type:" + socketType);
// Cancel the thread that completed the connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Cancel the accept thread because we only want to connect to one
// device
if (mSecureAcceptThread != null) {
mSecureAcceptThread.cancel();
mSecureAcceptThread = null;
}
if (mInsecureAcceptThread != null) {
mInsecureAcceptThread.cancel();
mInsecureAcceptThread = null;
}
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(socket, socketType);
mConnectedThread.start();
// Send the name of the connected device back to the UI Activity
Message msg = mHandler.obtainMessage(BTconnect.MESSAGE_DEVICE_NAME);//开启连接蓝牙设备的线程之后,还要返回设备的名字给主线程
Bundle bundle = new Bundle();
bundle.putString(BTconnect.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
/**
* Stop all threads
*/
public synchronized void stop() {
if (D)
Log.d(TAG, "stop");
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if (mSecureAcceptThread != null) {
mSecureAcceptThread.cancel();
mSecureAcceptThread = null;
}
if (mInsecureAcceptThread != null) {
mInsecureAcceptThread.cancel();
mInsecureAcceptThread = null;
}
setState(STATE_NONE);
}
/**
* Write to the ConnectedThread in an unsynchronized manner
*
* @param out
* The bytes to write
* @see ConnectedThread#write(byte[])
*/
public void write(byte[] out) {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mState != STATE_CONNECTED)
return;
r = mConnectedThread;
}
// Perform the write unsynchronized
r.write(out);
}
/**
* Indicate that the connection attempt failed and notify the UI Activity.
*/
private void connectionFailed() {
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(BTconnect.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BTconnect.TOAST, "Unable to connect device");
msg.setData(bundle);
mHandler.sendMessage(msg);
// Start the service over to restart listening mode
BluetoothService.this.start();
}
/**
* Indicate that the connection was lost and notify the UI Activity.
*/
private void connectionLost() {
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(BTconnect.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BTconnect.TOAST, "Device connection was lost");
msg.setData(bundle);
mHandler.sendMessage(msg);
// Start the service over to restart listening mode
BluetoothService.this.start();
}
/**
* This thread runs while listening for incoming connections. It behaves
* like a server-side client. It runs until a connection is accepted (or
* until cancelled).
*/
@SuppressLint("NewApi")
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
private String mSocketType;
@SuppressLint({ "NewApi", "NewApi" })
public AcceptThread(boolean secure) {
BluetoothServerSocket tmp = null;
// Create a new listening server socket
try {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,
MY_UUID);
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed", e);
}
mmServerSocket = tmp;
}
@SuppressLint({ "NewApi", "NewApi", "NewApi", "NewApi", "NewApi" })
public void run() {
if (D)
Log.d(TAG, "Socket Type: " + mSocketType
+ "BEGIN mAcceptThread" + this);
setName("AcceptThread" + mSocketType);
BluetoothSocket socket = null;
// Listen to the server socket if we're not connected
while (mState != STATE_CONNECTED) {
try {
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType
+ "accept() failed", e);
break;
}
// If a connection was accepted
if (socket != null) {
synchronized (BluetoothService.this) {
switch (mState) {
case STATE_LISTEN:
case STATE_CONNECTING:
// Situation normal. Start the connected thread.
connected(socket, socket.getRemoteDevice(),
mSocketType);
break;
case STATE_NONE:
case STATE_CONNECTED:
// Either not ready or already connected. Terminate
// new socket.
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close unwanted socket", e);
}
break;
}
}
}
}
if (D)
Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType);
}
public void cancel() {
if (D)
Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this);
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "Socket Type" + mSocketType
+ "close() of server failed", e);
}
}
}
/**
* This thread runs while attempting to make an outgoing connection with a
* device. It runs straight through; the connection either succeeds or
* fails.
*/
@SuppressLint({ "NewApi", "NewApi" })
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
private String mSocketType;
@SuppressLint({ "NewApi", "NewApi", "NewApi" })
public ConnectThread(BluetoothDevice device, boolean secure) {
mmDevice = device;
BluetoothSocket tmp = null;
mSocketType = secure ? "Secure" : "Insecure";
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
if (secure) {
tmp = device
.createRfcommSocketToServiceRecord(MY_UUID);
} else {
tmp = device
.createInsecureRfcommSocketToServiceRecord(MY_UUID);
}
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
}
mmSocket = tmp;
}
@SuppressLint({ "NewApi", "NewApi", "NewApi" })
public void run() {
Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
setName("ConnectThread" + mSocketType);
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() " + mSocketType
+ " socket during connection failure", e2);
}
connectionFailed();
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothService.this) {
mConnectThread = null;
}
// Start the connected thread
connected(mmSocket, mmDevice, mSocketType);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect " + mSocketType
+ " socket failed", e);
}
}
}
/**
* This thread runs during a connection with a remote device. It handles all
* incoming and outgoing transmissions.
*/
@SuppressLint("NewApi")
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
@SuppressLint("NewApi")
private final OutputStream mmOutStream;
private ByteArrayOutputStream out = new ByteArrayOutputStream();
public ConnectedThread(BluetoothSocket socket, String socketType) {//蓝牙连接线程
Log.d(TAG, "create ConnectedThread: " + socketType);
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
/*
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);//从输入流读取字节到字节数组buffer,如果读取的数组过长,那么返回的信息就会断断续续
// Send the obtained bytes to the UI Activity
//mHandler.obtainMessage(BTconnect.MESSAGE_READ, bytes,-1, buffer).sendToTarget();//发消息到主线程
ByteArrayOutputStream out = new ByteArrayOutputStream();
// 根据读取的长度写入到os对象中
out.write(buffer, 0, bytes);
out.flush();//强制输出到控制台
//返回消息到主线程
Message msg=new Message();
msg.what=BTconnect.MESSAGE_READ;
String result=new String(out.toByteArray());
msg.obj = result;
mHandler.sendMessage(msg);//将消息发回手机主线程查看
out.reset();//清空缓冲区
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
*/
while (true) {
try {
// Read from the InputStream
if( (bytes = mmInStream.read(buffer)) > 0 )
{
byte[] buf_data = new byte[bytes];
for(int i=0; i<bytes; i++)
{
buf_data[i] = buffer[i];
}
String s = new String(buf_data);
Message msg = new Message();
msg.obj = s;
//msg.what = 1;
msg.what=BTconnect.MESSAGE_READ;
//LinkDetectedHandler.sendMessage(msg);
mHandler.sendMessage(msg);//将消息发回手机主线程查看
}
} catch (IOException e) {
try {
mmInStream.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
break;
}
}
}
/**
* Write to the connected OutStream.
*
* @param buffer
* The bytes to write
*/
@SuppressLint("NewApi")
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);//直接写给蓝牙模块
System.out.println("----发送指令到蓝牙模块--------"+new String(buffer));
//ByteArrayOutputStream out = new ByteArrayOutputStream();
// 根据读取的长度写入到os对象中
//out.write(buffer, 0, buffer.length);
//out.flush();//强制输出到控制台
//返回消息到主线程
Message msg=new Message();
msg.what=BTconnect.MESSAGE_WRITE;
// String result=new String(out.toByteArray());
msg.obj = new String(buffer);//存入消息
mHandler.sendMessage(msg);//将消息发回BTconnect主线程查看
// out.reset();//清空缓冲区
// Share the sent message back to the UI Activity
//mHandler.obtainMessage(BTconnect.MESSAGE_WRITE, -1, -1,buffer.toString()).sendToTarget();//在返回写出的信息到主线程。
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
}
1.4准备一份重力传感器的app源码
部分代码如下:
package daodanjishui.Bluetooth;
import java.util.Enumeration;
import org.join.wfs.R;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.Camera.Size;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.view.SurfaceHolder.Callback;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
/**
* This is the main Activity that displays the current chat session.
*/
@SuppressLint("HandlerLeak")
public class BTconnect extends Activity {
//下面是重力传感器添加
//ToggleButton transButton;
Button button3,button4,button5,button6,button7,button8;
SensorManager sensorManager;// 管理器对象
private Sensor gyroSensor;// 陀螺 传感器对象
private Sensor acceSensor;// 加速度
private Sensor quatSensor;// 旋转矢量
private TextView tv_X;
private TextView tv_Y;
private TextView tv_Z;
boolean transFlag = false;//重力传感器开关
// Debugging
private static final String TAG = "BTconnect";
private static final boolean D = true;
// Message types sent from the BluetoothChatService Handler
public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_READ = 2;
public static final int MESSAGE_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;
// Key names received from the BluetoothChatService Handler
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
private static final int REQUEST_ENABLE_BT = 3;
// Layout Views
private TextView mTitle;
TextView textView0,textView1,textView2;
// Name of the connected device
private String mConnectedDeviceName = null;
// String buffer for outgoing messages
private static StringBuffer mOutStringBuffer;
// Local Bluetooth adapter
private BluetoothAdapter mBluetoothAdapter = null;
// Member object for the chat services
private static BluetoothService mChatService = null;
int cout = 0;
private Button button=null;
private Button button2=null;
private EditText editText=null;
private boolean Bluetooth_connect_flag=false;
public void projectinit() {
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
gyroSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
acceSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
quatSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
if (gyroSensor == null) {
Toast.makeText(BTconnect.this, "您的设备不支持陀螺仪~~~", Toast.LENGTH_SHORT).show();
} else {
/**
* 注册监听器
*/
sensorManager.registerListener(sensoreventlistener, gyroSensor,
SensorManager.SENSOR_DELAY_GAME);
sensorManager.registerListener(sensoreventlistener, acceSensor,
SensorManager.SENSOR_DELAY_GAME);
sensorManager.registerListener(sensoreventlistener, quatSensor,
SensorManager.SENSOR_DELAY_GAME);
}
}
private SensorEventListener sensoreventlistener = new SensorEventListener() {
private long acceTime;
private float[] acce = { 0, 0, 0, };
byte command;
int value = 0x00;
private int count1 = 0;
@SuppressWarnings("deprecation")
@Override
public void onSensorChanged(SensorEvent event) {
float[] values = event.values;
if (event.sensor == acceSensor) {//加速度
acce[0] = values[0];
acce[1] = values[1];
acce[2] = values[2];
this.acceTime = event.timestamp;
}
tv_X.setText("X-acce:" + Float.toString(acce[0]));//手机左右加速度,x
tv_Y.setText("Y-acce:" + Float.toString(acce[1]));//手机前后加速度,y
tv_Z.setText("Z-acce:" + Float.toString(acce[2]));//手机上下加速度,平放静止手机这个值是9.8,z
if (count1 >= 10) {//延时采集数据
textView2.setText("重力手势的状态是:"+transFlag);
if (transFlag){
//sendCmd(command, value);//如果手势开关打开了,就发送手势参数给蓝牙模块
//sendMessage(value+"");//
//在这里写逻辑
if(acce[0]<-5&&acce[1]<-2&&acce[2]>0){//右转,acce[0]=x,acce[1]=y,acce[2]=z
sendMessage("RRR"+"\r\n");
}else if(acce[0]>5&&acce[1]<-2&&acce[2]>0){//左转
sendMessage("LLL"+"\r\n");
}else if(acce[0]<1&&acce[0]>-1&&acce[1]<-3&&acce[2]>0){//前进
sendMessage("FFF"+"\r\n");
}else if(acce[0]<1&&acce[0]>-1&&acce[1]>3&&acce[2]>0){//后退
sendMessage("BBB"+"\r\n");
}else if(acce[0]<1&&acce[0]>-1&&acce[1]>-1&&acce[1]<1&&acce[2]>0){//停止
sendMessage("SSS"+"\r\n");
}else
sendMessage("SSS"+"\r\n");//停止
}
count1=0;
}
count1++;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
};
@SuppressLint("NewApi")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (D)
Log.e(TAG, "+++ ON CREATE +++");
// Set up the window layout
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.bluetooth);
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.custom_title);
tv_X = (TextView) findViewById(R.id.tvX);
tv_Y = (TextView) findViewById(R.id.tvY);
tv_Z = (TextView) findViewById(R.id.tvZ);
button3 = (Button) findViewById(R.id.button3);
button3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if(transFlag==false)
transFlag=true;
else
transFlag=false;
Toast.makeText(BTconnect.this, "transFlag="+transFlag,Toast.LENGTH_SHORT).show(); //显示消息提示
}
});
button4 = (Button) findViewById(R.id.button4);//前进
button4.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if(Bluetooth_connect_flag){
BTconnect.sendMessage("FFF"+"\r\n");//加入\r\n的字符串才能触发stm32串口1中断
}else{
Toast.makeText(BTconnect.this, "蓝牙还有没有连接上",Toast.LENGTH_SHORT).show(); // 显示消息提示
}
}
});
button5 = (Button) findViewById(R.id.button5);//向左
button5.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if(Bluetooth_connect_flag){
BTconnect.sendMessage("LLL"+"\r\n");//加入\r\n的字符串才能触发stm32串口1中断
}else{
Toast.makeText(BTconnect.this, "蓝牙还有没有连接上",Toast.LENGTH_SHORT).show(); // 显示消息提示
}
}
});
button6 = (Button) findViewById(R.id.button6);//向右
button6.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if(Bluetooth_connect_flag){
BTconnect.sendMessage("RRR"+"\r\n");//加入\r\n的字符串才能触发stm32串口1中断
}else{
Toast.makeText(BTconnect.this, "蓝牙还有没有连接上",Toast.LENGTH_SHORT).show(); // 显示消息提示
}
}
});
button7 = (Button) findViewById(R.id.button7);//向后
button7.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if(Bluetooth_connect_flag){
BTconnect.sendMessage("BBB"+"\r\n");//加入\r\n的字符串才能触发stm32串口1中断
}else{
Toast.makeText(BTconnect.this, "蓝牙还有没有连接上",Toast.LENGTH_SHORT).show(); // 显示消息提示
}
}
});
button8 = (Button) findViewById(R.id.button8);//停止
button8.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if(Bluetooth_connect_flag){
BTconnect.sendMessage("SSS"+"\r\n");//加入\r\n的字符串才能触发stm32串口1中断
}else{
Toast.makeText(BTconnect.this, "蓝牙还有没有连接上",Toast.LENGTH_SHORT).show(); // 显示消息提示
}
}
});
projectinit(); // 初始化传感器监听
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // 保持屏幕常亮
textView0= (TextView) findViewById(R.id.textView0);
textView1= (TextView) findViewById(R.id.textView1);
textView2= (TextView) findViewById(R.id.textView2);
textView1.setText("等待机器人的回应");
textView2.setText("手势开关的状态是:"+transFlag);
editText=(EditText)findViewById(R.id.editText1);
button=(Button)findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if(Bluetooth_connect_flag){
Toast.makeText(BTconnect.this, "提交蓝牙指令是:"+editText.getText().toString(),Toast.LENGTH_SHORT).show(); // 显示消息提示
//ipname=editText.getText().toString();
BTconnect.sendMessage(editText.getText().toString()+"\r\n");//加入\r\n的字符串才能触发stm32串口1中断
editText.setText("");
}else{
Toast.makeText(BTconnect.this, "蓝牙还有没有连接上",Toast.LENGTH_SHORT).show(); // 显示消息提示
}
}
});
button2=(Button)findViewById(R.id.button2);
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Intent serverIntent = null;
// Launch the DeviceListActivity to see devices and do scan
serverIntent = new Intent(BTconnect.this, DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);//注意有返回值
}
});
// Set up the custom title
mTitle = (TextView) findViewById(R.id.title_left_text);
mTitle.setText(R.string.app_name);
mTitle = (TextView) findViewById(R.id.title_right_text);
//mTitle.setText(getIpAddress());
// Get local Bluetooth adapter
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// If the adapter is null, then Bluetooth is not supported
if (mBluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth is not available",
Toast.LENGTH_LONG).show();
finish();
return;
}
}
@SuppressLint("NewApi")
@Override
public void onStart() {
super.onStart();
if (D)
Log.e(TAG, "++ ON START ++");
// If BT is not on, request that it be enabled.
// setupChat() will then be called during onActivityResult
if (!mBluetoothAdapter.isEnabled()) {
/*Intent enableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);*/
//历史蓝牙连接上之后自动跳转到 主窗口
// Otherwise, setup the chat session
} else {
if (mChatService == null)
setupChat();
}
}
@Override
public synchronized void onResume() {
super.onResume();
if (D)
Log.e(TAG, "+ ON RESUME +");
// Performing this check in onResume() covers the case in which BT was
// not enabled during onStart(), so we were paused to enable it...
// onResume() will be called when ACTION_REQUEST_ENABLE activity
// returns.
if (mChatService != null) {
// Only if the state is STATE_NONE, do we know that we haven't
// started already
if (mChatService.getState() == BluetoothService.STATE_NONE) {
// Start the Bluetooth chat services
mChatService.start();
}
}
}
@SuppressLint("NewApi")
private void setupChat() {
Log.d(TAG, "setupChat()");
// Initialize the BluetoothChatService to perform bluetooth connections
mChatService = new BluetoothService(this, mHandler);
// Initialize the buffer for outgoing messages
mOutStringBuffer = new StringBuffer("");
}
@Override
public synchronized void onPause() {
super.onPause();
if (D)
Log.e(TAG, "- ON PAUSE -");
}
@Override
public void onStop() {
super.onStop();
if (D)
Log.e(TAG, "-- ON STOP --");
}
@Override
public void onDestroy() {
super.onDestroy();
// Stop the Bluetooth chat services
if (mChatService != null)
mChatService.stop();
if (D)
Log.e(TAG, "--- ON DESTROY ---");
}
@SuppressLint("NewApi")
private void ensureDiscoverable() {
if (D)
Log.d(TAG, "ensure discoverable");
if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {//打开蓝牙
Intent discoverableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(
BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
}
public static void sendMessage(String message) {
// Check that we're actually connected before trying anything
if (mChatService.getState() != BluetoothService.STATE_CONNECTED) {
// Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT)
// .show();
return;
}
// Check that there's actually something to send
if (message.length() > 0) {
// Get the message bytes and tell the BluetoothChatService to write
byte[] send = message.getBytes();
mChatService.write(send);
// Reset out string buffer to zero and clear the edit text field
mOutStringBuffer.setLength(0);
}
}
// The Handler that gets information back from the BluetoothChatService
private final Handler mHandler = new Handler() {//接收BluetoothChatService发回来的消息并且解析这些消息,提取数据,如果是获取蓝牙设备返回的消息,需要用这个
//但是如果是单纯发送数据到蓝牙设备的话,直接用sendMessage(String message)就可以了
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_STATE_CHANGE:
if (D)
Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
switch (msg.arg1) {
case BluetoothService.STATE_CONNECTED://连接成功了就可以跳转到监控界面了
mTitle.setText(R.string.title_connected_to);
mTitle.append(mConnectedDeviceName);
Bluetooth_connect_flag=true;
//startActivity(new Intent (BTconnect.this, CameraTest.class) );//连接成功了就可以跳转到监控界面了
break;
case BluetoothService.STATE_CONNECTING:
mTitle.setText(R.string.title_connecting);
break;
case BluetoothService.STATE_LISTEN:
case BluetoothService.STATE_NONE:
mTitle.setText(R.string.title_not_connected);
break;
}
break;
case MESSAGE_DEVICE_NAME:
// save the connected device's name
mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);//BTconnect.DEVICE_NAME
Toast.makeText(getApplicationContext(),
"Connected to " + mConnectedDeviceName,
Toast.LENGTH_SHORT).show();//显示连接到的是哪个蓝牙设备
break;
case MESSAGE_TOAST:
Toast.makeText(getApplicationContext(),
msg.getData().getString(TOAST), Toast.LENGTH_SHORT)
.show();
break;
case MESSAGE_READ:
//Toast.makeText(getApplicationContext(),msg.getData().toString(), Toast.LENGTH_SHORT).show();
//System.out.println("收到的蓝牙消息是"+msg.getData().toString());
Object result1 = msg.obj;
System.out.println("收到蓝牙模块的消息是:"+result1);
//Toast.makeText(getApplicationContext(),"recive from BT:"+result1, Toast.LENGTH_SHORT).show();
textView1.setText("recive from BT:"+result1);
break;
case MESSAGE_WRITE:
Object result = msg.obj;
//result=msg.getData().getString("result");
System.out.println("send to BT:"+result);
//Toast.makeText(getApplicationContext(),"send to BT:"+result, Toast.LENGTH_SHORT).show();
//Toast.makeText(getApplicationContext(),"send to BT:"+msg.getData().toString(), Toast.LENGTH_SHORT).show();
break;
}
}
};
public void onActivityResult(int requestCode, int resultCode, Intent data) {//接收DeviceListActivity界面返回的结果
if (D)
Log.d(TAG, "onActivityResult " + resultCode);
switch (requestCode) {//请求码
case REQUEST_CONNECT_DEVICE_SECURE://请求连接设备,startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);//注意有返回值
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {//请求成功了
connectDevice(data, true);
}
break;
case REQUEST_CONNECT_DEVICE_INSECURE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
connectDevice(data, false);
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
// Bluetooth is now enabled, so set up a chat session
setupChat();
} else {
// User did not enable Bluetooth or an error occured
Log.d(TAG, "BT not enabled");
Toast.makeText(this, R.string.bt_not_enabled_leaving,
Toast.LENGTH_SHORT).show();
finish();
}
}
}
@SuppressLint({ "NewApi", "NewApi" })
private void connectDevice(Intent data, boolean secure) {
// Get the device MAC address
String address = data.getExtras().getString(
DeviceListActivity.EXTRA_DEVICE_ADDRESS);//获取意图返回的设备地址
// Get the BLuetoothDevice object
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);//去连接蓝牙设备
// Attempt to connect to the device
mChatService.connect(device, secure);//去连接蓝牙设备
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.option_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {//链接蓝牙的第一步
Intent serverIntent = null;
switch (item.getItemId()) {
case R.id.secure_connect_scan:
// Launch the DeviceListActivity to see devices and do scan
serverIntent = new Intent(this, DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);//注意有返回值
return true;
}
return false;
}
}
1.5组合代码。缺省代码说明:整个安卓工程一个三个文件,非常简洁,很适合二次开发或者学习,目前给出了两个最重要的文件,还剩下一个蓝牙设备列表的文件,如果耐心够的读者慢慢看两个代码也能收获很多,说不定还能再现我这个app出来,毕竟代码关键的地方都写了注释,这个代码我编写了一周,如果感兴趣的读者想要我全部的源码,麻烦到我指定的地方下载工程吧,尊重原创,尊重劳动成果,我能保证的是我的app绝对是靠谱的,能控制所指定的硬件。
2.分析代码
首先强调一下这个app使用eclipse搭建的Android开发环境编写的Android4.3版本的app,如果想要定制高版本的app或者Android studio版本的源码请联系我,其实用什么软件开发程序都是次要的,关键是你设计产品的逻辑。记得我的老师说过,其实开发语言只是工具而已,关键还是你自己心中是否有完整的运行逻辑机制。
其实给出的源码我写上了完整的注释了,就说说读者能学到什么内容吧?这份源码可以学习的地方很多的,比如handler,蓝牙的调用和使用,主界面更新UI,activity参数传递,回调函数的使用,IO流控制,字节传输,重力传感器的调用和使用,私人通信协议的定制和解析判断,蓝牙通信反馈设计等等,如果要实现安卓手机app来控制蓝牙设备,那么我这个源码绝对物超所值!
三、仿真与调试
1.操控舵机云台:准备好硬件,上电,运行app。
1.1刚开始运行app可以看到正下方显示了三个方向的手机重力加速度和重力手势开关状态和蓝牙连接状态
1.2然后启动智能小车或者是钢铁爱国者机关枪,再打开手机蓝牙,再点击“设置蓝牙”,出现
1.3上面的图会看到我历史上连接好的设备,如果记性好是可以直接连上正在通电的HC-05蓝牙设备了,新安装软件如下显示,再也没有历史信息了。
1.4那么我们需要点击“搜索设备”,这个功能还是很人性化的,可以帮助用户搜寻需要连接的蓝牙设备,比如我这里有智能小车和爱国者机关枪,那它们名字是一样的,但是mac地址不一样,也是可以区分开来的。搜索结果如下所示
1.5最后点击搜索出来的蓝牙信息,点击输入密码1234,不行就输入0000,即可连上,出现下图所示,已连接。
1.6连上之后 ,就可以开始控制蓝牙设备了,这个万能遥控器可以使用三种模式控制:第一种是指令发送;第二种是方向按键控制;第三种是重力传感器控制。非常人性化,也方便用户调试,另外蓝牙设备反馈可以在手机app显示出来,这是很多app没有的功能。
剩下的事情就交给视频来说明了。
2. 操控智能小车
这里就交给视频说明吧。类似上面操控智能舵机云台一样的道理。
总结
说了那么多,无非就是想强调这份源码可以学习的地方很多的,比如handler,蓝牙的调用和使用,主界面更新UI,activity参数传递,回调函数的使用,IO流控制,字节传输,重力传感器的调用和使用,私人通信协议的定制和解析判断,蓝牙通信反馈设计等等,如果要实现安卓手机app来控制蓝牙设备,那么我这个源码绝对物超所值!
现代生活中蓝牙设备原来越多,所以手机智能蓝牙控制app的开发永不停止,除了蓝牙之外WIFI的应用也很广泛,那么下一期我将推出万能wifi app控制器,并且使用该控制器控制WiFi设备,敬请期待。
代码工程下载链接:https://gf.bilibili.com/item/detail/1107736114
点我直接跳转
花5个积分apk安装包试用链接
daodanjishui: 文章后面有下载地址。
Rocket_YQL: 串口1和串口2的代码有吗谢谢了
好家伙VCC: 喜欢博主的文章,我当时是一个小白,一步一步踩坑过来,我后面回顾学习路线,做了PID-控制-遥控-避障-跟随循迹的项目,大家可以一起学习交流一下:这是文章:https://blog.csdn.net/qq_46187594/article/details/138110155?spm=1001.2014.3001.5502
daodanjishui: 下载地址更新了,欢迎大家到我哔哩哔哩工坊下载源码。
普通网友: 你的博客内容深入浅出,总是让我不再感到学习的困难,每一篇博文都是我学习的宝库。【我也写了一些相关领域的文章,希望能够得到博主的指导,共同进步!】