• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Bluetooth send accelerometer data

dan1107669

Newbie
Oct 25, 2017
11
0
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.

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.
 
When you say running for a few minutes, what's it doing? I mean the code you showed doesn't appear to have much functionality, other than displaying a few buttons and sending some data to the socket.
You're also catching exceptions, do any of those blocks get triggered?
Is there anything in particular which triggers the freeze? When you click one of the buttons?
Have you tried running your app in debug mode, and setting breakpoints in the button click handlers? This would verify they are working correctly.
 
Upvote 0
When I say running for a few minutes I mean, the app connects to the arduino bluetooth and acts as a remote control to move a robot. I tilt the phone on the x and y axis and the app sends the accelerometer data to the arduino bluetooth. It connects ok, sends data, and the arduino receives data and moves the robot for a few minutes then the app freezes. The accelerometer data being sent to the arduino bluetooth is also displayed on the phone screen. The buttons work ok and just send commands to the arduino. I don't really use that function, but I have tested them turning on and off LED's. The buttons do not correspond with the app freezing. When I say freezing, I don't mean that the app crashed, I mean that the data displayed on the screen stops changing to correspond with the tilting of the phone. And the robot will continue in whatever direction it was going just before the app froze. It could also be an accelerometer problem and not a bluetooth problem. I don't know. Edit: Exceptions do not get triggered.
 
Last edited:
Upvote 0
You might want to put some Log statements in your onSensorChanged() and sendMotor() methods.
I would normally recommend setting breakpoints, but due to the large number of events from the accelerometer, I don't think this would be a practical way of debugging.
What I'd be looking to do is pin down exactly where the code is getting stuck.
 
Upvote 0
I changed the error message in sendMotor() method so it was unique to that method. That error does come up when the app freezes. Does that narrow it down at all?

Code:
    private void sendMotor(String cmdSendLR) {
        if (btSocket != null) {
            try {
                btSocket.getOutputStream().write(cmdSendLR.getBytes());
            } catch (IOException e) {
                msg("E-motorSend");
            }
        }
    }
 
Upvote 0
Something else interesting....this afternoon Android Studio updated to version 3.0. Now I have a few warnings in this activity where there were none before. One that stands out refers to this class:
Code:
private class ConnectBT extends AsyncTask<Void, Void, Void>  // UI thread
The warning says: "this AsyncTask class should be static or leaks might occur"

also I ran this in debugging mode and this was in the debugger console

10/26 17:16:32: Launching app
$ adb shell am start -n "com.example.shiel.sonicartrc/com.example.shiel.sonicartrc.BTdevices" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -D
Waiting for application to come online: com.example.shiel.sonicartrc.test | com.example.shiel.sonicartrc
Waiting for application to come online: com.example.shiel.sonicartrc.test | com.example.shiel.sonicartrc
Waiting for application to come online: com.example.shiel.sonicartrc.test | com.example.shiel.sonicartrc
Connecting to com.example.shiel.sonicartrc
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
W/ActivityThread: Application com.example.shiel.sonicartrc is waiting for the debugger on port 8100...
I/System.out: Sending WAIT chunk
I/art: Debugger is active
I/System.out: Debugger has connected
I/System.out: waiting for debugger to settle...
I/System.out: waiting for debugger to settle...
I/System.out: waiting for debugger to settle...
I/System.out: waiting for debugger to settle...
I/System.out: waiting for debugger to settle...
Connected to the target VM, address: 'localhost:8600', transport: 'socket'
I/System.out: waiting for debugger to settle...
I/System.out: waiting for debugger to settle...
I/System.out: waiting for debugger to settle...
I/System.out: waiting for debugger to settle...
I/System.out: waiting for debugger to settle...
I/System.out: waiting for debugger to settle...
I/System.out: waiting for debugger to settle...
I/System.out: debugger has settled (1486)
W/System: ClassLoader referenced unknown path: /data/app/com.example.shiel.sonicartrc-2/lib/arm64
I/InstantRun: starting instant run server: is main process
W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
I/Adreno: QUALCOMM build : b6da14b, I47548ba842
Build Date : 11/14/16
OpenGL ES Shader Compiler Version: XE031.09.00.03
Local Branch :
Remote Branch : quic/LA.BF64.1.2.3_rb1.6
Remote Branch : NONE
Reconstruct Branch : NOTHING
I/OpenGLRenderer: Initialized EGL, version 1.4
D/OpenGLRenderer: Swap behavior 1
D/TAG: My debug-message4
W/BluetoothAdapter: getBluetoothService() called with no BluetoothManagerCallback
I/art: Do partial code cache collection, code=23KB, data=29KB
I/art: After code cache collection, code=23KB, data=29KB
I/art: Increasing code cache capacity to 128KB
I/art: Compiler allocated 7MB to compile void android.widget.TextView.<init>(android.content.Context, android.util.AttributeSet, int, int)
I/art: Do partial code cache collection, code=61KB, data=58KB
I/art: After code cache collection, code=61KB, data=58KB
I/art: Increasing code cache capacity to 256KB
D/OpenGLRenderer: endAllActiveAnimators on 0x721ccaf400 (ListView) with handle 0x721cbfe9a0
I/art: Compiler allocated 6MB to compile void android.view.ViewRootImpl.performTraversals()
I/art: Do full code cache collection, code=120KB, data=121KB
I/art: After code cache collection, code=98KB, data=72KB
I/art: Do partial code cache collection, code=125KB, data=113KB
I/art: After code cache collection, code=125KB, data=113KB
I/art: Increasing code cache capacity to 512KB
I/art: Compiler allocated 6MB to compile void android.view.ViewRootImpl.performTraversals()
I/Choreographer: Skipped 2969 frames! The application may be doing too much work on its main thread.
I/art: Do full code cache collection, code=236KB, data=217KB
I/art: After code cache collection, code=212KB, data=190KB
I/art: Do partial code cache collection, code=250KB, data=227KB
I/art: After code cache collection, code=250KB, data=227KB
I/art: Increasing code cache capacity to 1024KB
I/Choreographer: Skipped 2740 frames! The application may be doing too much work on its main thread.
I/Choreographer: Skipped 54 frames! The application may be doing too much work on its main thread.
I/art: Do full code cache collection, code=504KB, data=405KB
I/art: After code cache collection, code=472KB, data=381KB
I/Choreographer: Skipped 912 frames! The application may be doing too much work on its main thread.
I/Choreographer: Skipped 921 frames! The application may be doing too much work on its main thread.
I/Choreographer: Skipped 913 frames! The application may be doing too much work on its main thread.
I/art: Do partial code cache collection, code=504KB, data=411KB
I/art: After code cache collection, code=504KB, data=411KB
I/art: Increasing code cache capacity to 2MB
I/Choreographer: Skipped 914 frames! The application may be doing too much work on its main thread.
 
Upvote 0
unfortunately debugging is primitive with arduino and the arduino ide than with android studio.

One thing I have noticed is that the communication can remain open between the arduino and android as long as the motors aren't on. Possibly they are creating electro magnetic interference to the arduino microcontroller itself or the bluetooth module on the arduino, and that causes the broken pipe. It doesn't appear that the connection ever breaks. If that is the case would that cause the x and y and y data displayed on the phone screen to freeze?

On the arduino bluetooth side, I have tried the whole range of baud rates without success. Maybe I could try a non-blocking delay of the rate at which the arduino receives and processes the incoming serial data.

Attached is a screenshot of what the app looks like when connected to the arduino bluetooth.
 

Attachments

  • device-2017-10-26-191438.png
    device-2017-10-26-191438.png
    234.7 KB · Views: 173
Upvote 0

BEST TECH IN 2023

We've been tracking upcoming products and ranking the best tech since 2007. Thanks for trusting our opinion: we get rewarded through affiliate links that earn us a commission and we invite you to learn more about us.

Smartphones