Accelerometer Bosch - concurrent nomotion and acceleration modules usage; Bluetooth reconnect
Hi,
we are using MetaMotion R sensor, Model Number 5, firmware 1.4.4, hw rev. 0.3
We use BarometerBosch, AmbientLightLtr329 and AccelerometerBosch modules at the same time on the device. Sometimes it happens, that only barometer and ambientlight work, but AccelerometerBosch doesn't report anything for some reason.
I wonder if I'm using it in a correct way - I followed Mbientlab FreeFall example and other tutorials here - and if route on acceleration() can be used together with nomotion.
Here is how we use it:
module in following code is AccelerometerBosch, noMotion is it's nomotion
freeFallDuration - calculated and set to duration of freefall based on the height of fall
...
@Override
public void configure() {
module.configure().odr(50f).commit();
noMotion.configure()
.duration(noMotionTime * 1000)
.threshold(0.1f)
.commit();
}
@Override
public void start() {
module.acceleration().addRouteAsync(new RouteBuilder() {
private long enterTime;
@Override
public void configure(RouteComponent source) {
source.map(Function1.RSS)
.average((byte) 4)
.filter(ThresholdOutput.BINARY, 0.5f)
.multicast()
.to()
.filter(Comparison.EQ, -1)
.stream(new Subscriber() {
@Override
public void apply(Data data, Object... env) {
// FREEFALL ENTERED
enterTime = System.currentTimeMillis();
}
})
.to()
.filter(Comparison.EQ, 1)
.stream(new Subscriber() {
@Override
public void apply(Data data, Object... env) {
if ( ((System.currentTimeMillis() - enterTime) > freeFallDuration)) {
// CALL FREEFALL ACTION
}
// FREEFALL EXIT
}
})
.end();
}
}).continueWith(new Continuation<Route, Void>() {
@Override
public Void then(Task<Route> task) throws Exception {
if (task.isFaulted()) {
// SOMETIMES IT GETS HERE with java.util.concurrent.TimeoutException: Did not received timer id within 1000ms
}
noMotion.addRouteAsync(new RouteBuilder() {
@Override
public void configure(RouteComponent source) {
source.stream(new Subscriber() {
@Override
public void apply(Data data, Object... env) {
// CALL MANDOWN action here
}
});
}
}).continueWith(new Continuation<Route, Void>() {
@Override
public Void then(Task<Route> task) throws Exception {
module.acceleration().start();
noMotion.start();
module.start();
return null;
}
});
return null;
}
});
}
@Override
public void stop() {
module.acceleration().stop();
noMotion.stop();
module.stop();
}
....
Callbacks I have at places of "// CALL ..." in above code sometimes do not get called although I can see that
...
module.acceleration().start();
noMotion.start();
module.start();
...
sequence passed.
Sometimes I can see java.util.concurrent.TimeoutException: Did not received timer id within 1000ms in module.acceleration().addRouteAsync().continueWith(). How to avoid this / how to handle it properly?
I also have an issue that I'm sometimes not able to connect to board after turning bluetooth off and back on on phone. What is the correct order of calls when bluetooth gets disabled/enabled on the phone so that nothing leaks on the board or in SDK ... ?
Thanks a lot for any help.
Regards
Oldrich
Comments
Please wrap your code with 3 backticks (```).
Since you are already using motion detection, you should instead use the low/high g detector to watch for freefall events:
https://mbientlab.com/androiddocs/3/accelerometer_bosch.html#low-high-detection
It is not recommended to use both raw acceleration data with the on-board detection algorithms.
Odd, you shouldn't getting that error as I don't see any timer code in your snippets. Are you creating a timer elsewhere in your code?
What other MetaWear API calls are you making?
That is norma and happens from time to time. You need to implement some retry logic in your app.
@Eric
Hi Eric, thank you for you help.
For each of the modules I'm calling
mwBoard.getModule(moduleClass)
.For Light
module.configure() .gain(AmbientLightLtr329.Gain.LTR329_8X) .integrationTime(AmbientLightLtr329.IntegrationTime.LTR329_TIME_250MS) .measurementRate(AmbientLightLtr329.MeasurementRate.LTR329_RATE_2000MS) .commit();
module.illuminance().addRouteAsync(new RouteBuilder() { @Override public void configure(RouteComponent source) { source.stream(new Subscriber() { @Override public void apply(Data data, Object... env) { // HERE WE JUST READ DATA data.value(Float.class)); } }); } }).continueWith(new Continuation<Route, Void>() { @Override public Void then(Task<Route> task) throws Exception { module.illuminance().start(); return null; } });
and when stoping
module.illuminance().stop();
For Pressure I set it
module.configure() .filterCoeff(BarometerBosch.FilterCoeff.AVG_16) .pressureOversampling(BarometerBosch.OversamplingMode.ULTRA_HIGH) .standbyTime(500f) .commit();
and start(), stop() in similar manner as for light module.
For other SDK calls I do yet
mwBoard.tearDown()
when I connect to the board before setting my routes. Other calls -serviceBinder.getMetaWearBoard(btDevice), mwBoard.disconnectAsync().continueWith(... { ... serviceBinder.clearSerializedState(btDevice); serviceBinder.removeMetaWearBoard(btDevice); ... } )
and that's probably all.I will try to reimplement freefall using low/high as you suggest. What would be settings for this algorithm to have same results as in freefall above?
For reconnection I basicaly do following - on unexpected disconnects I do new connectAsync() and also when task is faulted I do reconnect until it passes. When bluetooth is disabled on the device I do stop modules, teardown, discnnnectAsync, etc. When it is enabled again I get new mwBoard instance, connectAsync, teardown, setup modules and start them.
When you refer to retry logics, do you mean it on level of SDK calls (connectAsync(), + reconnect calls until it passes ) or on android bluetooth service level? The problem is that sometimes I get to state when repeated connectAsync() calls never pass. When this happen, sometimes I'm not even able to connect to board with Metabase app.
Thanks for your help.
Oldrich
Please check that your posts are formated correctly on the forum and readable, and edit them appropriately. All of the above code snippets are displayed as one liners making it difficult to read.
These individually look fine. Are you properly chaining the routes together?
I don't see any timer code so I'm still not sure why you are getting a timer id error msg.
Looks fine.
The on-chip detection algorithm is different than the data processor version. You will have to experiment with different configurations to find what best suites your use case.
If Bluetooth is disabled none of those functions will do anything.
Yes
Could be an issue with your device's Bluetooth adapter. Maybe disabling then re-enabling the adapter will fix the problem.
Sorry for bad formatting.
Do you mean chaining of routes for different modules? I think I probably don't.
I do something like this (just pseudocode):
and then same for other modules
Should I be doing it like this instead?
Or could you, please, advice me some nice pattern for such chaining (I'm not very familiar with bolts yet)?
Ok, thanks, I will experiment with this.
ok, thanks, I thought it could be the case, but was not sure if it doesn't clear some state also on phone side.
I tried this before, but it didn't help. Also I do not want our app to break other apps which could be making use of bluetooth.
Thanks for your help.
Oldrich
Typically, you only start the sensors once all of the routes are successfully added. Since adding routes is an async task, Bolts provides the framework for consuming async results and task chaining.
Checkout the Bolts documentation for more details on their API.
In this case, what is the error returned when
connectAsync
fails?Hi Eric,
one of the scenarios which leads to unability to reconnect:
I disable bluetooth manualy on the phone (via android bluetooth disable/enable soft button) . Sometimes it leads to bluetooth stack crash and in the debugger I can see this or similar exception:
usually when this happens and I reanable bluetooth, then connectAsync task is repeatedly faulted with TimeoutException: Failed to connect and discover services within 10000ms
Although I redo init sequence in response to bluetooth availability:
Another exception after bluetooth disable, followed unability to connect again :
Yes. I tried and "Beacon scanner" app works with other device at the same time.
Sometimes yes - i.e. after few connection timeouts it reconnects, sometimes it doesn't help.
+/- yes. After several sequences of bluietooth disable/enable it usually happens.
We reproduce it on android 8.0 (Mi note 2), Google Pixel 2 XL (android 9), Nokia (Android 6.0) ,..
We have it reported fro our colleagues also, but I'm not sure what devices exactly they have.
Can you connect to the device with the "nRF Connect" app?
Does this happen on its own i.e. you are not touching the BT adapter?
Yes, In my application it timeouts repeated connectAsync(), but I'm able to connect to same sensor using nRF Connect app from the same phone. When I connect to it from nRF Connect, it resurrects and connectAsync() in my app completes successfully.
In the past I saw this inability to reconnect after leting it to run over night or so, but wasn't able to reproduce this in past two days. Given that I'd say it is related to adapter ON/OFF - at least it is very "reliable" way.
I have yet another question. I thought, that tearDown() should "clear" the device to some default state. I turned green LED from MEtawear sample app. When I connect from our app to the device I call tearDown() to remove old routes, etc. I expected it will also turn the LED off, but it stays ON. What do I need to call on successfull connection to the device to be 100% sure, that there are no routes, all modules are stoped, ...
Thanks
Oldrich
Hrm...it would be interesting to see if you can connect to the board in question with another MetaWear based app. From our end, it might be worth swapping out the BLE code with Nordic's BLE library given the good stability of the nRF Connect app.
Might be fixed if we use different BLE code, as mentioned above
tearDown
is explained in the documentation:https://mbientlab.com/androiddocs/3/metawearboard.html#tear-down
If you want a default, clean state, you can use the Debug module to reset the board.
Yes, I tried it and I'm able to connect with sample Metawear app as well. Connection in my app is reestablished then ,too. I have created a simple app which runs AmbientLight sensor and prints to debug console. It tries to reconnect on unexpected disconnects and on bluetooth off/on. I can send you the this project if you'd like to. I want to eliminate possibility that I'm doing something in a wrong way. Our problem is reproducible on this app.
I have read the documentation before and now again, but I still have some questions -
1) when I remove all data routes with tearDown(), does it also stop sensor module? Is there a way to find out module state? If it's running, if there are active Routes, etc ? Or should I call stop(); each time before configure(); addRoute(); start(); ?
2) Is there another way or just reset() ? I want to clean board on successfull connnectAsync() without droping connection. At least I want to make sure nothing runs on the device and consumes battery and if someone "played" with device (like he turned LEDs on, or some other modules) which are not needed in our app.
Thanks for your help,
Oldrich
Yes, post the project.
No
The simplest way is to reset the board.
No, reset the board to put it in a clean state. It's OK to drop the connection when it is expected to happen.
@Eric
Hi Eric,
attaching simple app where I'm able to reproduce the reconnection problem. It only prints illuminance to console and tries to keep permanent connection with metawear. Several times turning bluetooth off / on usually leads to described problem. In MainActivity, there is hardcoded MAC of metawear sensor
private final String macAddress =
which needs to be changed before using app. Reconnection and other calls is pretty much same as what I do in our application. Can you, please, see it and optionaly advice me some enhancements for stabilization to see if it helps to reconnection timeout issue?
Thanks.
Oldrich
Unfortunately I haven't had a chance to look over the project yet.
I will update this thread when I have new information.
After running your project, it appears that doing a BLE scan fixes the connection issues that occur from toggling the Bluetooth adapter. So for your project, you should get the
BluetoothDevice
object from a BLE scan rather than directly instantiating it from a MAC address.Thanks Eric,
I'll give it a try today / latest tomorrow and let you know how it went.
Regards,
Oldrich
@Eric
Hi Eric,
thank you very much for your help. I'm starting BLE scan when trying to connect and stoping it on sucessfull connection. Although we had a chance to test it only for several hours with toggling bluetooth state off/on, I think it realy solves our issue. As far as we were able to test it always connects now.
I have a different question now. We use nomotion accelerometer-Bosch module to detect no motion for let's say 5 mins. Sometimes it happens, that when we reconnect to the sensor after long period without connection, we start getting these events immediately. It seems to me, that mwboard has these events buffered and sends them then right away. Does it work this way?
Thank you!
Regards,
Oldrich
There's no buffering. It's possible the board was never reset and the Android object was never destroyed so it was already prepared to receive the events.