在Android可穿戴设备上持续感知加速度计和陀螺仪数据

3

我正在开发一款应用,该应用将在可穿戴设备(Sony Smart Watch 3)和手持设备(Samsung S5)上运行。

我想要连续感知手表的加速度计和陀螺仪数据,并将数据发送并保存到手持设备上。

我想知道实现这一目标的最佳方法是什么。目前,我正在使用DataApi

由于加速度计和陀螺仪数据采样率足够高,并且可穿戴设备上的应用程序不断向手机发送数据,它会分配过多的内存,然后被操作系统杀死。

以下是手表上的活动:

public class MyActivity extends Activity implements SensorEventListener{

    private TextView mTextView;
    private TextView textViewGyro;
    private SensorManager mSensorManager;
    private GoogleApiClient mGoogleApiClient;
    private String mNode;
    private float x,y,z;
    private float gx,gy,gz;
    private final String TAG = MyActivity.class.getName();
    private final float GAIN = 0.9f;
    public static final float EPSILON = 0.000000001f;
    String WEARABLE_DATA_PATH = "/wearable_data";
    //String WEARABLE_GYROSCOPE_PATH = "/wearable_gyroscope";


    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
        stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
            @Override
            public void onLayoutInflated(WatchViewStub stub) {
                mTextView = (TextView) stub.findViewById(R.id.text);
                textViewGyro= (TextView) stub.findViewById(R.id.textgyro);
            }
        });

        mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Wearable.API)
                .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
                    @Override
                    public void onConnected(Bundle bundle) {
                        Log.d(TAG, "onConnected");
                        Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>() {
                            @Override
                            public void onResult(NodeApi.GetConnectedNodesResult nodes) {                               
                                if (nodes.getNodes().size() > 0) {
                                    mNode = nodes.getNodes().get(0).getId();
                                    Log.e("Wearable","Device found");
                                    Log.e("Wearable",mNode);
                                }
                            }
                        });
                    }

                    @Override
                    public void onConnectionSuspended(int i) {
                        Log.d(TAG, "onConnectionSuspended");

                    }
                })
                .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
                    @Override
                    public void onConnectionFailed(ConnectionResult connectionResult) {
                        Log.d(TAG, "onConnectionFailed : " + connectionResult.toString());
                    }
                })
                .build();
    }

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

        Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

        mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);

        Sensor sensor1 = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
        mSensorManager.registerListener(this, sensor1, SensorManager.SENSOR_DELAY_NORMAL);

        mGoogleApiClient.connect();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mSensorManager.unregisterListener(this);
        mGoogleApiClient.disconnect();
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            x = (x * GAIN + event.values[0] * (1 - GAIN));
            y = (y * GAIN + event.values[1] * (1 - GAIN));
            z = (z * GAIN + event.values[2] * (1 - GAIN));

            if (mTextView != null) mTextView.setText(String.format("\n" + "Accelerometer Data: \nX : %f\nY : %f\nZ : %f\n",x, y, z));

            DataMap dataMap = new DataMap();
            dataMap.putLong("timestamp", new Date().getTime());
            dataMap.putFloat("ax",x);
            dataMap.putFloat("ay",y);
            dataMap.putFloat("az",z);

            new SendToDataLayerThread(WEARABLE_DATA_PATH, dataMap).start();

        }

        if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
            gx = event.values[0];
            gy = event.values[1];
            gz = event.values[2];

            float omegaMagnitude = (float)java.lang.Math.sqrt(gx*gx + gy*gy + gz*gz);

            // Normalize the rotation vector if it's big enough to get the axis
            // (that is, EPSILON should represent your maximum allowable margin of error)
            if (omegaMagnitude > EPSILON) {
                gx /= omegaMagnitude;
                gy /= omegaMagnitude;
                gz /= omegaMagnitude;
            }

            if (textViewGyro != null)
                textViewGyro.setText(String.format("\nGyroscope Data: \nX : %f\nY : %f\nZ : %f\n", gx, gy, gz));

            DataMap dataMap = new DataMap();
            dataMap.putLong("timestamp", new Date().getTime());
            dataMap.putFloat("gx",gx);
            dataMap.putFloat("gy",gy);
            dataMap.putFloat("gz",gz);

            new SendToDataLayerThread(WEARABLE_DATA_PATH, dataMap).start();
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    class SendToDataLayerThread extends Thread {
        String path;
        DataMap dataMap;

        // Constructor for sending data objects to the data layer
        SendToDataLayerThread(String p, DataMap data) {
            path = p;
            dataMap = data;
        }

        public void run() {
            NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();
            for (Node node : nodes.getNodes()) {

                // Construct a DataRequest and send over the data layer
                PutDataMapRequest putDMR = PutDataMapRequest.create(path);
                putDMR.getDataMap().putAll(dataMap);
                PutDataRequest request = putDMR.asPutDataRequest();
                DataApi.DataItemResult result = Wearable.DataApi.putDataItem(mGoogleApiClient,request).await();
                if (result.getStatus().isSuccess()) {
                    Log.e("myTag", "DataMap: " + dataMap + " sent to: " + node.getDisplayName());
                } else {
                    // Log an error
                    Log.e("myTag", "ERROR: failed to send DataMap");
                }
            }
        }
    }
}

我遇到以下异常和错误:
02-13 02:06:37.777  17349-17360/? E/DataBuffer? Internal data leak within a DataBuffer object detected!  Be sure to explicitly call release() on all DataBuffer extending objects when you are done with them. (su@357af50)

02-13 02:24:09.300      594-685/? D/WearableService? putData: exception during processing: PutDataRequest[dataSz=67, numAssets=0, uri=wear:/wearable_gyroscope]
    android.os.DeadObjectException

02-13 02:24:09.108      594-685/? D/WearableService? getConnectedNodes: exception during processing
    android.os.DeadObjectException

android.system.ErrnoException: read failed: EAGAIN (Try again)
            at libcore.io.Posix.readBytes(Native Method)
            at libcore.io.Posix.read(Posix.java:147)
            at libcore.io.BlockGuardOs.read(BlockGuardOs.java:230)
            at android.system.Os.read(Os.java:364)
            at com.android.server.am.NativeCrashListener.consumeNativeCrashData(NativeCrashListener.java:240)
            at com.android.server.am.NativeCrashListener.run(NativeCrashListener.java:138)
02-13 15:46:29.977      150-150/? E/DEBUG? AM write failure (32 / Broken pipe)
02-13 15:46:34.704  21570-21581/? E/DataBuffer? Internal data leak within a DataBuffer object detected!  Be sure to explicitly call release() on all DataBuffer extending objects when you are done with them. (su@35563df0)

02-13 11:14:44.482  12012-12012/? E/AndroidRuntime? FATAL EXCEPTION: main
    Process: com.example.fazlay.accelerometerwearable, PID: 12012
    java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
            at java.lang.Thread.nativeCreate(Native Method)
            at java.lang.Thread.start(Thread.java:1063)
            at com.example.fazlay.accelerometerwearable.MyActivity.onSensorChanged(MyActivity.java:168)
            at android.hardware.SystemSensorManager$SensorEventQueue.dispatchSensorEvent(SystemSensorManager.java:405)
            at android.os.MessageQueue.nativePollOnce(Native Method)
            at android.os.MessageQueue.next(MessageQueue.java:143)
            at android.os.Looper.loop(Looper.java:122)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

02-13 15:52:47.934      424-464/? E/ActivityManager? ANR in com.example.fazlay.accelerometerwearable (com.example.fazlay.accelerometerwearable/.MyActivity)
    PID: 0
    Reason: Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago.  Wait queue length: 6.  Wait queue head age: 13150.8ms.)


02-13 16:19:23.999  24797-24797/? E/AndroidRuntime? FATAL EXCEPTION: main
    Process: com.example.fazlay.accelerometerwearable, PID: 24797
    java.lang.IllegalStateException: await must not be called on the UI thread
            at com.google.android.gms.internal.jx.a(Unknown Source)
            at com.google.android.gms.common.api.BaseImplementation$AbstractPendingResult.await(Unknown Source)
            at com.example.fazlay.accelerometerwearable.MyActivity.onSensorChanged(MyActivity.java:171)
            at android.hardware.SystemSensorManager$SensorEventQueue.dispatchSensorEvent(SystemSensorManager.java:405)
            at android.os.MessageQueue.nativePollOnce(Native Method)
            at android.os.MessageQueue.next(MessageQueue.java:143)
            at android.os.Looper.loop(Looper.java:122)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

你从那里得到任何解决方案了吗? - Foreverniu
1个回答

1
看一下 Github 项目 SensorDashboard,他们接收所有传感器数据并通过 MessageAPI 传递到移动设备。我认为它运行得非常好。据我记得,他们使用了某种容量限制来限制发送的数据量。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接