I'm using an Android phone as a remote control for a robot using an Arduino micro-controller. The app works as expected and sends x and y axis data from the accelerometer to the Arduino robot. Communication only needs to be one way from the phone to the microcontroller.
The problem is that the app will freeze after a couple minutes. The x and y axis data that is being sent to the robot is also displayed on the screen of the Android phone, and I can see that the x and y axis data does not change when the app freezes.
The app is modified from something that I found on a tutorial.
I have been told to look at the sendMotor method, because a socket doesn't get closed, but I have spent hours reading tutorials and documentation and looking at examples, and I can't see where it differs from other examples. Any help would be appreciated.
The problem is that the app will freeze after a couple minutes. The x and y axis data that is being sent to the robot is also displayed on the screen of the Android phone, and I can see that the x and y axis data does not change when the app freezes.
The app is modified from something that I found on a tutorial.
Code:
package com.example.shiel.sonicartrc;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.util.UUID;
public class SendData extends AppCompatActivity implements SensorEventListener {
Button btnOn, btnOff, btnDis;
float x, y;
String address = null;
private ProgressDialog progress;
BluetoothAdapter myBluetooth = null;
BluetoothSocket btSocket = null;
private boolean isBtConnected = false;
static final UUID myUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
//MOTION STARTS
//private static final String TAG = ledControl.class.getSimpleName();
private SensorManager mSensorManager;
private Sensor mAccelerometer;
TextView tv, tv1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent newint = getIntent();
address = newint.getStringExtra(BTdevices.EXTRA_ADDRESS);
//receive the address of the bluetooth device
//view of the ledControl
setContentView(R.layout.activity_send_data);
//call the widgets
btnOn = (Button) findViewById(R.id.button2);
btnOff = (Button) findViewById(R.id.button3);
btnDis = (Button) findViewById(R.id.button4);
//MOTION START
//get the sensor service
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
//get the accelerometer sensor
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
//get layout
tv = (TextView) findViewById(R.id.xval);
tv1 = (TextView) findViewById(R.id.yval);
Log.d("TAG", "My debug-message4");
//MOTION END
new ConnectBT().execute(); //Call the class to connect
//commands to be sent to bluetooth
btnOn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
turnOnLed(); //method to turn on
}
});
btnOff.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
turnOffLed(); //method to turn off
}
});
btnDis.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Disconnect(); //close connection
}
});
}
private void Disconnect() {
if (btSocket != null) {
//If the btSocket is busy
try {
btSocket.close(); //close connection
} catch (IOException e) {
msg("Error");
}
}
finish(); //return to the first layout
}
private void turnOffLed() {
if (btSocket != null) {
try {
btSocket.getOutputStream().write("<a>".getBytes());
} catch (IOException e) {
msg("Error");
}
}
}
private void turnOnLed() {
if (btSocket != null) {
try {
btSocket.getOutputStream().write("<b>".getBytes());
} catch (IOException e) {
msg("Error");
}
}
}
private void sendMotor(String cmdSendLR) {
if (btSocket != null) {
try {
btSocket.getOutputStream().write(cmdSendLR.getBytes());
} catch (IOException e) {
msg("Error");
}
}
}
// fast way to call Toast
private void msg(String s) {
Toast.makeText(getApplicationContext(), s, Toast.LENGTH_LONG).show();
}
private class ConnectBT extends AsyncTask<Void, Void, Void> {
// UI thread
private boolean ConnectSuccess = true; //if it's here, it's almost connected
@Override
protected void onPreExecute() {
progress = ProgressDialog.show(SendData.this, "Connecting", "Please wait"); //show a progress dialog
}
@Override
protected Void doInBackground(Void... devices) {
//while the progress dialog is shown, the connection is done in background
try {
if (btSocket == null || !isBtConnected) {
myBluetooth = BluetoothAdapter.getDefaultAdapter();
//get the mobile bluetooth device
BluetoothDevice dispositive = myBluetooth.getRemoteDevice(address);
//connects to the device's address and checks if it's available
btSocket = dispositive.createInsecureRfcommSocketToServiceRecord(myUUID);
//create a RFCOMM (SPP) connection
BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
btSocket.connect();//start connection
}
} catch (IOException e) {
ConnectSuccess = false;//if the try failed, you can check the exception here
}
return null;
}
@Override
protected void onPostExecute(Void result) {
//after the doInBackground, it checks if everything went fine
super.onPostExecute(result);
if (!ConnectSuccess) {
msg("Connection Failed");
finish();
} else {
msg("Connected");
isBtConnected = true;
}
progress.dismiss();
}
}
//MOTION STARTS
@Override
public final void onAccuracyChanged(Sensor sensor, int accuracy) {
// Do something here if sensor accuracy changes.
}
@Override
public final void onSensorChanged(SensorEvent event) {
WindowManager windowMgr = (WindowManager) this.getSystemService(WINDOW_SERVICE);
int rotationIndex = windowMgr.getDefaultDisplay().getRotation();
if (rotationIndex == 1 || rotationIndex == 3) {
// detect 90 or 270 degree rotation
x = -event.values[1];
y = event.values[0];
} else {
x = event.values[0]; //Force x axis in m s-2
y = event.values[1]; //Force y axis in m s-2
}
sendEventValues();
}
public void sendEventValues() {
tv.setText("X axis" + "\t\t" + x);
tv1.setText("Y axis" + "\t\t" + y);
if (isBtConnected) {
int xx = Math.round(x);
int yy = Math.round(y);
sendMotor("<" + xx + "," + yy + ">");
try {
Thread.sleep(50);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
//MOTION ENDS
}
I have been told to look at the sendMotor method, because a socket doesn't get closed, but I have spent hours reading tutorials and documentation and looking at examples, and I can't see where it differs from other examples. Any help would be appreciated.