Puck.js IMU data logging

Posted on
  • Hello,

    I would like to log some IMU data using my Puck.js v.2.

    I have set up a SD card reader (w/ SPI HW set to 8Mbps) on it so I can log the data. I can log the data at maximum 160Hz in average which is quite low for what I would like to do. I guess there are a lot of "wasted" time when converting the JSON object to string, and then when writing the data to the file. Note, I am using "Stream File IO".

    I am far from being an expert, but maybe some on this forum could help me to know how much I can expect from the device. If I were to write my own C code to log the data from the IMU directly to the SD card, what would be the possible maximum sampling rate for instance?

    (My messy code below)

    function onInit(){
      // Wire up up MOSI, MISO, SCK and CS pins (along with 3.3v and GND)
    SPI1.setup({mosi:D30, miso:D28, sck:D29, baud: 8000000});
    // console.log(E);
    E.connectSDCard(SPI1, D31 /*CS*/);
    // see what's on the device
      try {
        console.log(require("fs").readdirSync());
      } catch(error){
        console.log(error);
      }
    }
    
    var data = [];
    var i = 0;
    // Store data into filesystem
    function storeMyData(fID, start, a) {  
      if (i>100) {
        i = 0;
        var t = new Date.now();
        fID.write(data);
        console.log((new Date.now()) - t);
        data = [];
      } else {
        data += (Date.now()-start) + "," + 
                a.acc.x + "," +
                a.acc.y + "," +
                a.acc.z + "," +
                a.gyro.x + "," +
                a.gyro.y + "," +
                a.gyro.z + "\n"; 
      } 
      i++;
    }
    
    function openFile(){
      var start = Date.now();
      var fID = E.openFile("data"+start+".csv", "w");
      fID.write("Time (ms), "+
                "acc X, "+
                "acc Y, "+
                "acc Z, "+
                "gyro X, "+
                "gyro Y, "+
                "gyro Z \n");
      return {fID: fID, start: start};
    }
    
    onInit();
    var res = openFile();
    var fID = res.fID;
    const start = res.start;
    
    function onButton(e){
      d = e.time - e.lastTime;
      if (d>0.5) {
        digitalPulse(LED2, 1, [100, 100, 100]);
        Puck.accelOn(208);
        Puck.on('accel', function(a) {
          storeMyData(fID, start, a);      
        });
      } else {    
        try {
          Puck.accelOff();
          fID.close();
          console.log("stopped!");
          digitalPulse(LED1, 1, [100, 100, 100]);
        } catch(error) {
          console.log(error);
        }    
      }
    }
    

    Thanks in advance,

    Greetings

  • That looks pretty good.

    I'm not sure what the fastest speed you can get is with C code, but I bet the vast majority of time in your code right now is spent in fID.write(data);, which is all C code.

    SD card IO is a bit tricky because it often has to load up a 512 byte sector before it can write it, but you're off to a pretty good start by batching samples in RAM and writing them out in one chunk.

    Some things that would help you though:

    • Try Puck.on('accel', storeMyData.bind(null,fID, start)); instead of what you have - it'll call the function directly rather than having the function inbetween
    • Turn on minification in the IDE
    • Try writing in smaller batches (20?)

    Also worth noting that the way storeMyData is, it'll lose 1 in 100 readings (the one where you write the file).

    I think one issue you might be hitting is that the data is read direct from the accelerometer data registers, but only in the idle loop. It means that if your code is spending a long time doing something (like writing to an SD card!) then you'll end up missing accelerometer data.

    Puck.js wasn't really designed for this kind of high speed data acquisition so it wasn't implemented, but the LSM6DS3TR-C actually contains a pretty big FIFO, which means it could be configured pretty easily such that it doesn't lose data.

    Either that'd require some firmware changes, or potentially it would be possible to access the LSM6DS3TR-C directly from JS and read the data out that way. If you just grabbed the binary data and wrote it straight to the file (without turning it into CSV) then you should be able to get a pretty decent data rate out of it.

  • Hi @Gordon, thanks for your quick and comprehensive reply!

    I will give a try to the FIFO buffer!

  • Hi again,

    I was able to activate and configure the FIFO buffers directly with JS. Because I do not have much time at the moment, one of my colleagues (much more skilled as well) is currently doing the implementation.

    We are thinking about sharing the code with the community, do you have any requirements for its implementation to maximize its chances to be merged with the upstream repository?

    For now, Puck.accelOnFifo(samplerate) was created and is very similar to Puck.accelOn(samplerate) but uses the FIFO buffer and returns binary data (so it is not converted into a JS object). At the moment, the implementation was done in jswrap_puck.c but you may want it to be done in a separate module?

    EDIT: Sorry, I found the answer to my question https://github.com/espruino/Espruino/blob/master/CONTRIBUTING.md

    /CN

  • That's great - thanks! As long as you're happy with contributing the code under the MPLv2 license it should be fine.

    It may be that when I see it I'll want to tweak it in such a way that the FIFO can be used for the standard Puck.on('accel',..) so all existing code gets the benefit - but having your code as a starting point would be hugely appreciated.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Puck.js IMU data logging

Posted by Avatar for christian-nils @christian-nils

Actions