Logging Acceleration Offline (n00b question)

Hi,

I'm Java developer, beginner with Android Studio. I setup and run on a Nexus 5 the Metawear-SampleAndroidApp. I have a few n00b question:

1. Is there a very simple Android Project to run sample example like:

2. How to perform logging of acceleration offline ?

I would like to stick the board on an object. Then log (offline) motion of that object for 2 weeks. Then download the log and send it by mail.

- I understand I can run code on board (without mobile). The Android app is use to write the code.
- I understand the Android app can read later the data and send it by mail

Do someone have already a dead simple Android project to do that ?
(Something wrapping this blogpost ?)

- I assume I need a button connect/disconnect
- I assume I need a button to write code
- Will the device always run that code ? (On sample app I have to push a button to start)
- I assume I need a filter to log the "motion" with a threashold to limit data stored. 
- How to play with sensitivity ? In the sample app the 2G setting still require a strong motion. 
- I assume I need to clear the logs on board after downloading it ?
- On sample app time is relative to ??? "start" can I have a timestamp ? Or at least a timestamp stored in the board when it starts ?

Thanks !
Sorry for my n00b question :-/








«1

Comments

  • I answer to myself,

    First part of my question was stupid...

    I use the SOSTrigger to learn how it works and create a little getting started app. I don't like the way mixed Fragment GUI and code in class and innerClass but anyway it works.

    Next Step, I will start from Android Sample App to add my own Fragment 

    I'm still interested in Logging Acceleration Offline for motions of objects

  • edited July 2015
    At the moment, no, the gist code is on its own.  As for your individual questions:

    - I assume I need a button connect/disconnect
    - I assume I need a button to write code
    This is the easiest way to set things up.  

    - Will the device always run that code ? (On sample app I have to push a button to start)
    We do have a macro feature that lets you execute code on boot.  This does use the on board flash memory, which will reduce the amount of acceleroemeter data you can store.

    - I assume I need a filter to log the "motion" with a threashold to limit data stored. 
    No, you can directly add acclerometer data to the logger as outlined in the blog post

    - How to play with sensitivity ? In the sample app the 2G setting still require a strong motion. 
    Use the ThresholdConfig.  The 2G setting relates to the XYZ axis sampling data, not motion detection

    - I assume I need to clear the logs on board after downloading it ?
    No, once you have downloaded the logs, they are marked to be cleared and will be freed upon disconnect.

    - On sample app time is relative to ??? "start" can I have a timestamp ? Or at least a timestamp stored in the board when it starts ?
    Yes, the blog post and Gist explains how to retrieve the timestamp.

    FYI we do have an Android getting started guide (http://docs.mbientlab.com/?page_id=40) which you may find useful for future reference.
  • Thanks Eric

    Yes the Android getting started guide is great but I had to jump into a smaller exemple to understand. The SOSTriger helped me a lot.


    About the BlogPost and the Gist there is something I do not understand:

    The private Logging.Callbacks logCallbacks is never used I see in the Android Sample App I have to do something like mwMnger.getCurrentController().addModuleCallback(...)




  • So I added a new Fragment to Android Sample App with the following code:

    The "Log" button seems to work but the "Save" button seems to crash the board and need a Hard Reboot !

    I go into loggingController.readTotalEntryCount(); then the device is disconnected. I don't understand my code is really close to LoggingFragment I will try to debug

    About ThresholdConfig I didn't find exemple but I'll try to dig :-)

  • edited July 2015
    Next Step: Motion Detection

    How can I get Orientation in logs ?

    loggingController.addTrigger(LoggingTrigger.ACCELEROMETER_ORIENTATION);
    orientation = accelController.enableOrientationDetection();
    orientation.withSilentMode();
    ...
    oData.add(new double[] { offset, BytesInterpreter.logBytesToGs(entry.data(), (byte) 0) });

    The data contains the Gs maybe I can get the orientation ? It is displayed in Accelerometer Fragment Demo

    How can I improve the Motion Detection ? 

    threshold = accelController.enableMotionDetection(Accelerometer.Axis.values());
    threshold.withSilentMode(); // .withThreshold(0.5f)

    What should I set in withThreshold() ? I want to trigger a motion if an object is in motion but 2G is too hard. Is 0.5f would mean 0.5G ? Because nothing append.

    I assume it is because there is no trigger ? What Trigger should I use ?
  • When you download the logs, you use the log entry ID to sort through which entry is for what data source.  For the orientation entries, you can use BytesInterpreter.byteToOrientation to convert the byte values to an orientation enum.

    Yes, the value is in Gs.  I'd be streaming the values first to make sure you have the correct settings before you log the motion alerts.  You can use this trigger definition for motion detection

    new Trigger() {
        @Override public Register register() { return Accelerometer.Register.FREE_FALL_VALUE; }
        @Override public byte index() { return (byte) 0xff; }
        @Override public byte offset() { return 0; }
        @Override public byte length() { return 1; }
    }
  • >  you can use BytesInterpreter.byteToOrientation to convert the byte values to an orientation enum

    Thanks I missed that !

    > You can use this trigger definition for motion detection

    I set Accelerometer.Register.FREE_FALL_VALUE for Motions ? 

    >  I'd be streaming the values first to make sure you have the correct settings before you log the motion alerts.

    I missed something, I should stream to the mobile app the X,Y,Z to adjust the thresahold value according to my needs ?

    And then use the Trigger Free_Fall to activate the motion detection

    Ok I'll try, I need a very low value, in the AccelerometerFragment it do not trigger fast enought (I assume it is because I set 2G in the app)

    On the other board there is a Gyroscope. Does that mean the API will evolved to get this data ? And will it be available to detect motions ? It says "pre order" any ETA ?
  • I set Accelerometer.Register.FREE_FALL_VALUE for Motions ? 
    Yes, the chip on the MetaWearR (MMA8452Q) bundles free fall and motion detection together.  Either one or the other is enabled.

    I missed something, I should stream to the mobile app the X,Y,Z to adjust the thresahold value according to my needs ?
    Yes, streaming the data will give you immediate feedback.  

    Ok I'll try, I need a very low value, in the AccelerometerFragment it do not trigger fast enought (I assume it is because I set 2G in the app)
    The 2G data range setting is not related to motion detection.

    On the other board there is a Gyroscope. Does that mean the API will evolved to get this data ? And will it be available to detect motions ? It says "pre order" any ETA ?
    Yes, the API will be updated to retrieve gyro data and yes, the new accelerometer chip (BMI160) has motion detection.  At this time, we do not have an ETA.

  • Yes Orientation works ! Motion too ! Thanks !!!

    > The 2G data range setting is not related to motion detection.

    So what is a Motion ? It's a hardcoded firmware feature ?
    Can I change it to be more or less sensitive to acceleration ? Is there a threashold that ignore first moves (I see that in feet devices)

    In my use case I need it to be really sensitive to trigger when I move an object (but do not spam logs during the move)

  • Motion detection is a feature of the the accelerometer that detects if the board is moving.  For example, if you pick up the board and move it to another spot on a table, you will get alerts for the initial acceleration from rest, and some alerts from the final deceleration to rest.
  • Ok I'll do more test. It seems the board needs to have a strong acceleration to match a motion
  • edited July 2015
    Hello,

    Here is a new version of my code;

    I'd like to ask have few more questions:

    1. What data can I retrieve in processData() from LogEntry for Activity ?
    For my log I only write "1" is there an average Gs or something ?.
    if (entry.triggerId() == fallId) {
    record = String.format("\"date\" : \"%tY%<tm%<td-%<tH:%<tM:%<tS\", \"activity\" : \"%s\"", d, "1");
    }

    2. What Trigger should I add to log "Shake" action ?
    We did something like this for Activity but I don't see something similar for Shake:
    loggingController.addTrigger(new Logging.Trigger() {
    @Override public Register register() { return Accelerometer.Register.FREE_FALL_VALUE; }
    @Override public byte index() { return (byte) 0xff; }
    @Override public byte offset() { return 0; }
    @Override public byte length() { return 1; }
    });
    3. How can I calculate the data I can store in memory and for the battery ?
    I know it really relies to activity but do you think that kind of Logger can stand days ? weeks ? months ?

    4. Activity vs Doors? 
    I did some tests of activity on a Door but Activity is not triggered. I have to do a very strong acceleration on door to make it trigger.

    Orientation is cool and trigger very fast

    {"date" : "20150713-11:30:49", "orientation" : "FRONT_PORTRAIT_DOWN"},
    {"date" : "20150713-11:30:50", "orientation" : "FRONT_LANDSCAPE_RIGHT"},
    {"date" : "20150713-11:30:51", "orientation" : "FRONT_LANDSCAPE_RIGHT"},
    {"date" : "20150713-11:30:53", "switch" : "1"},
    {"date" : "20150713-11:30:53", "switch" : "0"},
    {"date" : "20150713-11:30:54", "orientation" : "FRONT_LANDSCAPE_RIGHT"},
    {"date" : "20150713-11:30:56", "activity" : "1"},
    {"date" : "20150713-11:30:56", "activity" : "1"},
    {"date" : "20150713-11:30:56", "orientation" : "BACK_LANDSCAPE_RIGHT"},
    {"date" : "20150713-11:30:57", "activity" : "1"},
    {"date" : "20150713-11:30:57", "activity" : "1"},
    {"date" : "20150713-11:30:58", "orientation" : "FRONT_LANDSCAPE_RIGHT"},
    {"date" : "20150713-11:30:58", "orientation" : "FRONT_LANDSCAPE_RIGHT"},
    {"date" : "20150713-11:31:00", "switch" : "1"},
    {"date" : "20150713-11:31:00", "switch" : "0"},
    {"date" : "20150713-11:31:00", "switch" : "1"},
    {"date" : "20150713-11:31:01", "switch" : "0"},
    {"date" : "20150713-11:31:01", "orientation" : "FRONT_LANDSCAPE_RIGHT"},
    {"date" : "20150713-11:31:04", "orientation" : "BACK_LANDSCAPE_RIGHT"},


  • 1. What data can I retrieve in processData() from LogEntry for Activity ? 
    There isn't much information available other than which axes were above the movement threshold and in what direction (positive or negative).  I will do a quick release later today to add the other accelerometer triggers.

    2. What Trigger should I add to log "Shake" action ? 
    new Logging.Trigger() {
        @Override public Register register() { return Accelerometer.Register.TRANSIENT_STATUS; }
        @Override public byte index()  { return (byte) 0xff; }
        @Override public byte offset() { return 0; }
        @Override public byte length() { return 1; }
    }
    3. How can I calculate the data I can store in memory and for the battery ? 
    The amount of available space for logging varies and is dependent on the size of the firmware image.  For firmware v1.0.3, I believe you can store ~16k log entries.  So, if you are logging data every 30 seconds, you will only have 2880 log entries in 1 day which should be good for a 5 day span.

    Battery level cannot be logged.  As of the current firmware, the onboard logger is for MetaWear sensor data, which the battery is not a part of.

    4. Activity vs Doors? 
    Hrm, perhaps lowering the threshold will help?  The specific accelerometer on MetaWearR (MMA8452q) can go as low as 0.063g.
  • edited July 2015
    Thanks ! 

    2. TRANSIENT_STATUS ? That's a strange name for shake  ?


    3. Ok so if the logging depends on user activity user willl have to "open the door" 16K times thats ok ? I do not want to log the battery only keep the MetaWear "alive" for few weeks to log these "up to" 16K door opening.


    4. How can I lower the Threshold of "activity" sensor ? I know on product like sen.se you can set the device for high, medium or low sensibility. In high sensitivity knocking the door raise the activity
  • 1) I made a release (v1.9.0) with the additions for tap, motion, and shake logging.

    2) The spec sheet for the MetaWearR accelerometer calls it "transient" so we have kept that naming convention.

    3) Battey life can be retrieved with the readBatteryLevel function.  The accelerometer will be constantly draining power doing all the motion detection but the MetaWear should be able to go a few days on a full charge.  You'll have to run some live tests to see what works best for you.

    4) You can configure thresholds using the withThreshold function.
  • Many Thanks Eric !

    3) Okkkkk so it's the accelerometer "job" that kills the battery I thought it would live month without motions like sen.se product. 

    I assume I'll have to set a polling frequency larger to get longer battery life ? Something like 100Hz or 500Hz. 

    How much "power" the coin cell of Metaware C will deliver compare to the 100mAh ? 10x ? 5x ?


    4) Ok understand so withThreshold will also work offline for activity trigger, great !! I'll give it a try with 0.1g ! So cool !



  • edited July 2015
    @Eric could you explain to me the sub layer of the API ?


    I create a trigger for activity (aka FreeFall):
    loggingController.addTrigger(new Logging.Trigger() { ... }


    Then I enable motion detection with a Threashold (for sensitivity) and with SilentMode to work offline
    accelController.enableMotionDetection(Accelerometer.Axis.values()).withThreshold(0.2f).withSilentMode();


    Then I start the component
    accelController.startComponents();


    So now, on the device, each motion will trigger a FreeFall event that will be stored as an activity in memory.

    The underlayer is the firmware that will poll the x,y,z every N milliseconds and compute something to detect if it is an activity  according to threashold if "yes" then it fire a trigger, etc ... ?

    Is it right ? How can I reduce the polling to save the battery ?

  • Yes, that is the correct code flow.

    Motion detection is handled by the accelerometer chip, not firmware.  You can experiment with sleep mode (enableAutoSleepMode) to reduce the power consumption during periods of inactivity.
  • I don't know what is a period of inactivity :-)

    My MetaWear is not put on a sport device and activated by mobile app when doing sport

    My MetaWear is put on a fridge door to log when there is some activity during past 2 weeks. I need to know that someone wake up at 4AM to take nap :-)
  • Periods of inactivity meaning the accelerometer has not detected any movement related events over some time.  If you're board is attached to a fridge, then at night, there will be long period of inactivity except for the odd case of some getting a late night snack.  In that case, you would want sleep mode to kick, and only wake up if some motion is detected.
  • edited July 2015
    Hi Eric,

    I tried :

      accelController.enableAutoSleepMode();
      accelController.startComponents();

    But I only log switch not the orientation / motion. Then I tried

      accelController.enableAutoSleepMode(Accelerometer.SleepModeRate.SMR_50_HZ, 60000);

    I assume the second parameter is in milliseconds ? 
    I get the orientation / motion but after 1 minute I no longer get accelerometer data only switch. It seems it do not wakeup with motion.
  • Hrm.. ok.  What you can do is use the I2C module to configure some acceleromter registers that were not directly exposed in the firmware.  Try running this code block with your current code.

    I2c i2cCtrllr= (I2C) mwBoard.getModuleController(Module.I2C);
    i2cCtrllr.writeData((byte) 0x1c, (byte) 0x2c, new byte[] { (byte) 0x78 });
  • edited July 2015
    Hello,
    Thanks Eric, I'll try that ASAP.

    Some feedbacks:

    Here is my latest "logging" code with "old Android Sample App"

    - I added an Android Persistant Storage of Trigger Ids because If I start logging, kill the app then a week later download the logs TriggersIds are lost

    - I'll have to think about a better way to manager hundred of MetaWare later :-)
    (A NodeJS / Windows / RPi API would be great)

    - I tested MetaWare on a Bottle of Water, It works very well !
    => I lost 1% battery / day so this is really really cool and means 100 days uptime !?
    => 1.1f Accelerometer threashold seems to be a good value

    This is what I get (very usefull for me)






  • Unfortunately, we don't have the man power to support other platforms besides iOS and Android at the moment.
  • Hi Eric,
    I have rewrite my code to be compatible with  v2.5.26 (many changes ! but better API)

    I'm in Firmware 1.0.3 and Hardware 0.2 I have an error when updating to 1.0.4


    So everything seems to work (no exception) but I have no messages stored in my ArrayList
    - I start Logging on board line 211 and migh be called line 91 ?
    - Do you confirm that .log() is done offline on the board (like old with withSilentMode()) ?
    - Sometimes download hangs forever and I have to reset the board
    - In my previous code I played with motion sensitivity how I do the .withThreshold(1.0f) ?
    - How/Can I use a Threshold differential filter and log only on temperature change ?
    - How work the Timestamp ? It's a delta between records ? but the first value is an absolute value stored ? Or should I record something in the app ?
    - Can we add proprietary data on iBeacon advertise string ? (like temperature or last motion time)

    (Sorry for all question I try to learn te new API)

  • edited August 2015
    • The key passed into setLogMessageHandler and the log method must match, same with subscribe/unsubscribe and stream.  In your code, you are using different keys.
    • Log sends data to the internal logger
    • What Android version are you using?
    • Call configureMotionDetection().setThreshold(1.f).commit()
    • Sample code using threshold and differential filters is in the example module.
    • Log timestamp is when the data was recorded by the logger
    • Yes, but I have not exposed that feature in the IBeacon module, only some data processors to create feedback loops. I assume for your case, you would like to change the major/minor numbers?
  • When log download crash, it crash the board and I have to reset it (I use 2 MetaWare, one without battery attach but it's not very convenient)

    I have a java.lang.RuntimeException: Cannot instantiate message class on  DefaultMetaWearBoard$Loggable.processLogMessage

    > What Android version are you using?
    I use the Sample 2.5.26 on latest Android on a Nexus 5. My board is 1.0.3 Hardware 0.2 DFU update do not work.

    > I assume for your case, you would like to change the major/minor numbers?
    I'll try with that, I'd like to make a quick POC with SARAH to post a vidéo and link to your KickStarter before it ends.

  • Ok following my previous commont I manage a more simple task:

    I try to log offline the switch:

    • If I Connect > Setup > Click > Stop > Download IT WORKS
    • If I Connect > Setup > Click > Disconnect > Click > Reconnect > Stop > Download IT WON'T WORK
    The onProgressUpdate is called "Progress 0 / 22" but nothing is downloaded

  • edited August 2015
    Ok so

    - I find why it do not log accelerometer I'm so stupid and forget the mma8452qModule.start();
    - I start to understand why after disconnect it lost logs
    https://gist.github.com/JpEncausse/a7d1e7067ca9117a8a06 1.

    1.On connect I create a Logger When I setup my loggers, I provide an ArrayList to an anonymous class and I store all Message inside

    2. On disconnect I set the Logger to null So when I disconnect/reconnect the new Logger Instance create a new ArrayList. (To debug I also create a Date)
    08-26 18:59:12.274   I/LOG stopLogger﹕ Wed Aug 26 18:59:12 GMT+02:00 2015
    08-26 18:59:13.427 I/LOG Orientation﹕ Wed Aug 26 18:58:39 GMT+02:00 2015
    08-26 18:59:13.427 I/LOG Orientation﹕ Wed Aug 26 18:58:39 GMT+02:00 2015
    08-26 18:59:13.773 I/onProgressUpdate﹕ Progress= 0 / 59
    08-26 18:59:13.788 I/startEmailIntent﹕ processing mail...
    08-26 18:59:13.810 I/LOG saveDataToFile﹕ Wed Aug 26 18:59:12 GMT+02:00 2015
    So Loggers use the closure to the Array/Date provided on setup ?! But but the Android may be garbage collected !? There is something I miss here ...

    How can I download data stored on the board 3 week later, I assume the Android App has reboot, phone shut down, etc ... The onComplete() store something that will disapear so I get a NullPointerException RouteManager$MessageHandler.process(Message)'

    Any best practices ?
This discussion has been closed.