Difficulty using data processors

I am trying to stream around 100 x,y,z data from the accelerometer prior and after a switch trigger. I am trying to use this code for this purpose:
final byte sampleSize= 100;
final String streamKeyX= "x_axis_event_data";
final String streamKeyY= "y_axis_event_data";
final String streamKeyZ= "z_axis_event_data";

accelCtrllr.routeData().fromXAxis()
.process(new Sample(sampleSize))
.process(streamKeyX, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
.stream(streamKeyX)
.commit().onComplete(new AsyncOperation.CompletionHandler<RouteManager>() {
@Override
public void success(RouteManager result) {
result.subscribe(streamKeyX, new RouteManager.MessageHandler() {
@Override
public void process(Message message) {
Log.i("X Axis", "" + message.getData(Float.class));
}
});
}
});

accelCtrllr.routeData().fromYAxis()
.process(new Sample(sampleSize))
.process(streamKeyY, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
.stream(streamKeyY)
.commit().onComplete(new AsyncOperation.CompletionHandler<RouteManager>() {
@Override
public void success(RouteManager result) {
result.subscribe(streamKeyY, new RouteManager.MessageHandler() {
@Override
public void process(Message msg) {
Log.i("Y Axis", "" + msg.getData(Float.class));
}
});
}
});

accelCtrllr.routeData().fromZAxis()
.process(new Sample(sampleSize))
.process(streamKeyZ, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
.stream(streamKeyZ)
.commit().onComplete(new AsyncOperation.CompletionHandler<RouteManager>() {
@Override
public void success(RouteManager result) {
result.subscribe(streamKeyZ, new RouteManager.MessageHandler() {
@Override
public void process(Message msg) {
Log.i("Z Axis", "" + msg.getData(Float.class));
}
});
}
});

switchModule.routeData().fromSensor().monitor(new DataSignal.ActivityHandler() {
@Override
public void onSignalActive(Map<String, DataProcessor> processors, DataSignal.DataToken token) {
processors.get(streamKeyX).setState(new Passthrough.State((short) (sampleSize * 2)));
processors.get(streamKeyY).setState(new Passthrough.State((short) (sampleSize * 2)));
processors.get(streamKeyZ).setState(new Passthrough.State((short) (sampleSize * 2)));
}
}).commit();
I am not able to get any data from any axis when I try this. On the other hand, if I use only 1 axis, I am able to get the data. I don't think this would be a problem with the output rate because I am using just 25 for that. Can you suggest what I should do to resolve this issue?

Comments

  • Extra info:
    I have tried using this app in Android Kitkat, Lollipop, Marshmallow. None of them worked.

    I am using the RG board with firmware version 1.0.4.
  • 300 total samples is pretty excessive.  Does a lower number work like 48 (16 per axis x 3 axes) ?
  • Hi Eric -
    Can we use some math functions (sum, avg, etc.) to lower the number? Basically, we are trying to save/stream 1 sec prior and 1 sec after an event (100Hz freq). If this is not possible with current setup, is there something we can do (custom firmware for example) to achieve this?

    Thanks,
    Vinod.
  • Attach a time processor to the acceleration data.
  • Hey Eric,

    I have been trying out various stuff and it looked like I cannot even log X axis, y axis and z axis separately. So, I am trying to do something like this
    accelCtrllr.routeData().fromAxes()
    .process(new Sample((byte) sampleSize))
    .process(streamKeyX, new Time(Time.OutputMode.ABSOLUTE,30000000))
    .split()
    .branch()
    .monitor(new DataSignal.ActivityHandler() {
    @Override
    public void onSignalActive(Map<String, DataProcessor> map, DataSignal.DataToken dataToken) {
    map.get(streamKeyX).modifyConfiguration(new Time(Time.OutputMode.ABSOLUTE,30000000));
    }
    })
    .branch()
    .log(streamKeyY)
    .end()
    .commit().onComplete(new AsyncOperation.CompletionHandler<RouteManager>() {
    @Override
    public void success(RouteManager result) {
    result.setLogMessageHandler(streamKeyY, new RouteManager.MessageHandler() {
    @Override
    public void process(Message message) {
    Log.i("XYZ", message.getData(CartesianFloat.class).toString());
    }
    });
    }
    });

    switchModule.routeData().fromSensor()
    .monitor(new DataSignal.ActivityHandler() {
    @Override
    public void onSignalActive(Map<String, DataProcessor> map, DataSignal.DataToken dataToken) {
    map.get(streamKeyX).modifyConfiguration(new Time(Time.OutputMode.ABSOLUTE, 1000));
    }
    }).commit();
    Since the Passthrough process cannot be used with the Axes data, I am trying to add a time filter that will allow the data to be logged 1 second after the button click. But I am getting a Null Pointer Exception saying:

    java.lang.NullPointerException: Attempt to invoke interface method 'void com.mbientlab.metawear.module.DataProcessor.modifyConfiguration(com.mbientlab.metawear.DataSignal$ProcessorConfig)' on a null object reference

    Can you help me resolve this issue?
  • I also tried using this but failed to get any data from the board.
    accelCtrllr.routeData().fromXAxis()
    .process(new Sample(sampleSize))
    .process(streamKeyX, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
    .log(streamKeyX)
    .commit().onComplete(new AsyncOperation.CompletionHandler<RouteManager>() {
    @Override
    public void success(RouteManager result) {
    result.subscribe(streamKeyX, new RouteManager.MessageHandler() {
    @Override
    public void process(Message message) {
    Log.i("X Axis", "" + message.getData(Float.class));
    }
    });
    }
    });

    accelCtrllr.routeData().fromYAxis()
    .process(new Sample(sampleSize))
    .process(streamKeyY, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
    .log(streamKeyY)
    .commit().onComplete(new AsyncOperation.CompletionHandler<RouteManager>() {
    @Override
    public void success(RouteManager result) {
    result.subscribe(streamKeyY, new RouteManager.MessageHandler() {
    @Override
    public void process(Message msg) {
    Log.i("Y Axis", "" + msg.getData(Float.class));
    }
    });
    }
    });

    accelCtrllr.routeData().fromZAxis()
    .process(new Sample(sampleSize))
    .process(streamKeyZ, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
    .log(streamKeyZ)
    .commit().onComplete(new AsyncOperation.CompletionHandler<RouteManager>() {
    @Override
    public void success(RouteManager result) {
    result.subscribe(streamKeyZ, new RouteManager.MessageHandler() {
    @Override
    public void process(Message msg) {
    Log.i("Z Axis", "" + msg.getData(Float.class));
    }
    });
    }
    });

    switchModule.routeData().fromSensor().monitor(new DataSignal.ActivityHandler() {
    @Override
    public void onSignalActive(Map<String, DataProcessor> processors, DataSignal.DataToken token) {
    processors.get(streamKeyX).setState(new Passthrough.State((short) (sampleSize * 2)));
    processors.get(streamKeyY).setState(new Passthrough.State((short) (sampleSize * 2)));
    processors.get(streamKeyZ).setState(new Passthrough.State((short) (sampleSize * 2)));
    }
    }).commit();
  • edited May 2016
    Override the CompletionHandler.failure function and see if any errors are being passed back.
  • When I logged out the error, I got this message : Cannot attach sample filter to data longer than 4 bytes.
  • So there's your issue. You can't use the sample filter without compacting the acceleration data or split it into its xyz components.
  • Oh! Thanks for the clarification. The documentation you have for sample shows that we can use sample filter with routeData().fromAxes(). 

    Can you tell me if there is any other filter that can hold 200 odd xyz data prior to the trigger? Or atleast break down the xyz data within the routeData().fromAxes() method?
  • Sorry about the bad example; I have corrected the example.

    No, like I said earlier, 200 is excessive and you should try with a smaller amount first to see if everything is working before increasing the sample size.

    You need to create separate routes like you did in your second post.  Again, override  CompletionHandler.failure to see if any errors are returned.
  • I tried that too but after so much trying, I am still stuck. I used the code in my second comment and tried tweaking it a bit. Finally I ended up with this :
    final String streamKeyX= "x_axis_event_data";
    final String streamKeyY= "y_axis_event_data";
    final String streamKeyZ= "z_axis_event_data";
    final String streamKeyXPassthrough= "x_axis_event_data_passthrough";
    final String streamKeyYPassthrough= "y_axis_event_data_passthrough";
    final String streamKeyZPassthrough= "z_axis_event_data_passthrough";
    final byte sampleSize=(byte) 100;

    accelCtrllr.routeData().fromXAxis()
    .process(new Sample(sampleSize))
    .process(streamKeyXPassthrough, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
    .log(streamKeyX).commit();

    accelCtrllr.routeData().fromYAxis()
    .process(new Sample(sampleSize))
    .process(streamKeyYPassthrough, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
    .log(streamKeyY).commit();

    accelCtrllr.routeData().fromZAxis()
    .process(new Sample(sampleSize))
    .process(streamKeyZPassthrough, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
    .log(streamKeyZ)
    .commit().onComplete(new AsyncOperation.CompletionHandler<RouteManager>() {
    @Override
    public void success(RouteManager result) {
    result.setLogMessageHandler(streamKeyZ, new RouteManager.MessageHandler() {
    @Override
    public void process(Message msg) {
    Log.i("Z Axis", "" + msg.getData(Float.class));
    }
    });
    result.setLogMessageHandler(streamKeyX, new RouteManager.MessageHandler() {
    @Override
    public void process(Message message) {
    Log.i("X Axis", "" + message.getData(Float.class));
    }
    });
    result.setLogMessageHandler(streamKeyY, new RouteManager.MessageHandler() {
    @Override
    public void process(Message message) {
    Log.i("Y Axis", "" + message.getData(Float.class));
    }
    });
    }

    @Override
    public void failure(Throwable error) {
    Log.i("Failure", error.getMessage());
    }
    });

    switchModule.routeData().fromSensor().monitor(new DataSignal.ActivityHandler() {
    @Override
    public void onSignalActive(Map<String, DataProcessor> processors, DataSignal.DataToken token) {
    processors.get(streamKeyXPassthrough).setState(new Passthrough.State((short) (sampleSize * 2)));
    processors.get(streamKeyYPassthrough).setState(new Passthrough.State((short) (sampleSize * 2)));
    processors.get(streamKeyZPassthrough).setState(new Passthrough.State((short) (sampleSize * 2)));
    }
    }).commit();
  • Whenever I try to run this code, I get a message saying "I/Failure﹕ Processor configuration key 'z_axis_event_data_passthrough' already present" but the app doesn't crash. Instead, it continues to scan.

    Later on when I stop the scanning, after a couple of seconds, the board automatically disconnects from the app and then gives out this error before re-connecting itself :

    ExampleActivity﹕ Error connecting
        java.lang.RuntimeException: onConnectionStateChanged reported non-zero status: 8
                at com.mbientlab.metawear.MetaWearBleService$2$2.run(MetaWearBleService.java:909)
                at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
                at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
                at java.lang.Thread.run(Thread.java:818)

    1. Route managers can only manipulate their respective routes.  You need to move the subscribe functions into their respective route CompletionHandler.
    2. I don't see any call to start the accelerometer.
    3. I would move the switch route code into the CompletionHandler of the Z axis route.

    accelCtrllr.routeData().fromXAxis()
    .process(new Sample(sampleSize))
    .process(streamKeyXPassthrough, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
    .stream(streamKeyX).commit().onComplete(new AsyncOperation.CompletionHandler() {
    @Override
    public void success(RouteManager result) {
    result.subscribe(streamKeyX, new RouteManager.MessageHandler() {
    @Override
    public void process(Message msg) {
    Log.i("test", "X -> " + msg.getData(Float.class));
    }
    });
    }
    });
    accelCtrllr.routeData().fromYAxis()
    .process(new Sample(sampleSize))
    .process(streamKeyYPassthrough, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
    .stream(streamKeyY).commit().onComplete(new AsyncOperation.CompletionHandler() {
    @Override
    public void success(RouteManager result) {
    result.subscribe(streamKeyY, new RouteManager.MessageHandler() {
    @Override
    public void process(Message msg) {
    Log.i("test", "Y -> " + msg.getData(Float.class));
    }
    });
    }
    });
    accelCtrllr.routeData().fromZAxis()
    .process(new Sample(sampleSize))
    .process(streamKeyZPassthrough, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
    .stream(streamKeyZ).commit().onComplete(new AsyncOperation.CompletionHandler() {
    @Override
    public void success(RouteManager result) {
    result.subscribe(streamKeyZ, new RouteManager.MessageHandler() {
    @Override
    public void process(Message msg) {
    Log.i("test", "Z -> " + msg.getData(Float.class));
    }
    });

    switchModule.routeData().fromSensor().monitor(new DataSignal.ActivityHandler() {
    @Override
    public void onSignalActive(Map processors, DataSignal.DataToken token) {
    processors.get(streamKeyXPassthrough).setState(new Passthrough.State((short) (sampleSize * 2)));
    processors.get(streamKeyYPassthrough).setState(new Passthrough.State((short) (sampleSize * 2)));
    processors.get(streamKeyZPassthrough).setState(new Passthrough.State((short) (sampleSize * 2)));
    }
    }).commit().onComplete(new CompletionHandler() {
    @Override
    public void success(RouteManager result) {
    accelCtrllr.start();
    }
    });
    }
    });
  • I tried to do what you said but still got some issues. The code I have is :
    accelCtrllr.routeData().fromXAxis()
    .process(new Sample(sampleSize))
    .process(streamKeyXPassthrough, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
    .stream(streamKeyX).commit().onComplete(new AsyncOperation.CompletionHandler<RouteManager>() {
    @Override
    public void success(RouteManager result) {
    result.subscribe(streamKeyX, new RouteManager.MessageHandler() {
    @Override
    public void process(Message msg) {
    Log.i("test", "X -> " + msg.getData(Float.class));
    }
    });
    }

    @Override
    public void failure(Throwable error){
    Log.i("Error X", error.getMessage());
    }
    });
    accelCtrllr.routeData().fromYAxis()
    .process(new Sample(sampleSize))
    .process(streamKeyYPassthrough, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
    .stream(streamKeyY).commit().onComplete(new AsyncOperation.CompletionHandler<RouteManager>() {
    @Override
    public void success(RouteManager result) {
    result.subscribe(streamKeyY, new RouteManager.MessageHandler() {
    @Override
    public void process(Message msg) {
    Log.i("test", "Y -> " + msg.getData(Float.class));
    }
    });
    }
    @Override
    public void failure(Throwable error){
    Log.i("Error Y", error.getMessage());
    }
    });

    contd..
  • contd..

    accelCtrllr.routeData().fromZAxis()
    .process(new Sample(sampleSize))
    .process(streamKeyZPassthrough, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
    .stream(streamKeyZ).commit().onComplete(new AsyncOperation.CompletionHandler<RouteManager>() {
    @Override
    public void success(RouteManager result) {
    result.subscribe(streamKeyZ, new RouteManager.MessageHandler() {
    @Override
    public void process(Message msg) {
    Log.i("test", "Z -> " + msg.getData(Float.class));
    }
    });

    switchModule.routeData().fromSensor().monitor(new DataSignal.ActivityHandler() {
    @Override
    public void onSignalActive(Map<String, DataProcessor> map, DataSignal.DataToken dataToken) {
    map.get(streamKeyXPassthrough).setState(new Passthrough.State((short) (sampleSize * 2)));
    map.get(streamKeyYPassthrough).setState(new Passthrough.State((short) (sampleSize * 2)));
    map.get(streamKeyZPassthrough).setState(new Passthrough.State((short) (sampleSize * 2)));
    }
    }).commit().onComplete(new AsyncOperation.CompletionHandler<RouteManager>() {
    @Override
    public void success(RouteManager result) {
    Log.i("Switch Module", "Ready");
    }
    });

    }
    @Override
    public void failure(Throwable error){
    Log.i("Error Z", error.getMessage());
    }
    });



    I am having the call to start the accelerometer in another button which I am calling only after I see a "Switch Module : Ready" Log I am getting when the switchModule's monitor is added successfully(the place where you are calling the accelerometer.start method)

    The issue is that after I click on start, I get the following message:
    Error X﹕ Processor configuration key 'x_axis_event_data_passthrough' already present
    Error Y﹕ Processor configuration key 'y_axis_event_data_passthrough' already present
    Error Z﹕ Processor configuration key 'z_axis_event_data_passthrough' already present
  • edited May 2016
    The only way that error message is if you are adding multiple processors with the same ID string.  Double check that you aren't creating the same route multiple times.

    At this point, I am out of ideas.  My suggestions are to use a low frequency accelerometer stream and start with only 1 axis.  Get those working first before you tack on more axes and use higher frequencies.


    accelCtrllr.setOutputDataRate(12.5f);
    accelCtrllr.routeData().fromXAxis()
    .process(new Sample(sampleSize))
    .process(streamKeyXPassthrough, new Passthrough(Passthrough.Mode.COUNT, (short) 0))
    .stream(streamKeyX).commit().onComplete(new AsyncOperation.CompletionHandler() {
    @Override
    public void success(RouteManager result) {
    result.subscribe(streamKeyX, new RouteManager.MessageHandler() {
    @Override
    public void process(Message msg) {
    Log.i("test", "X -> " + msg.getData(Float.class));
    }
    });

    switchModule.routeData().fromSensor().monitor(new DataSignal.ActivityHandler() {
    @Override
    public void onSignalActive(Map processors, DataSignal.DataToken token) {
    processors.get(streamKeyXPassthrough).setState(new Passthrough.State((short) (sampleSize * 2)));
    }
    }).commit().onComplete(new CompletionHandler() {
    @Override
    public void success(RouteManager result) {
    accelCtrllr.start();
    }
    });
    }
    });
  • Is there any way to get the details of this error message? "java.lang.RuntimeException: onConnectionStateChanged reported non-zero status: 8"

    After starting the scanning and waiting for around 20 seconds, the board is automatically disconnecting and giving me this output.
  • I was able
    to get 3 axes working with sample size of 50. Next, in our
    application we need both gyro and accel data with the same spec. Is there any customization of
    the board that we can do to achieve that? I am assuming that the current board supports only upto a limited number of data entries in the sample filter due to which we are having this error(maybe the memory issues of the queue). Is it possible to customize the board to increase the capacity of this? Or is there any other way to solve this?
  • There is no public documentation about those status codes that I am aware of.  You can look up the #define macros in the Android C code to get a cursory understanding of what could be wrong.


    We do provide customized firmware and hardware tailored for specific use cases, as opposed to being a general purpose solution.  You can contact us at "hello at mbientlab dot com" for inquiries.
This discussion has been closed.