Puck.js onAccel callback speed is slow

Posted on
  • Hello,

    I was trying to use a Puck.js v2.1 to broadcast accelerometer and gyro data to a mobile phone app at around 1kHz, but I can only get 50Hz. I am trying to double-integrate acceleration to get the world-frame to pose (position and orientation). I tried setting this function to 6600Puck.accelOn(6600); which matched one of the data rates supported by the accelerometer, but it still was around 45-50Hz which is not desired. How can I either increase the data rate through Javascript OR modify the existing firmware C code and reflash the Puck.js? If I want to modify the existing firmware what are the steps to do this? I believe the code base is here? https://github.com/espruino/Espruino. How would building binaries/installing the code work?

  • Sorry I forgot to attach my code for reference. Please find below.

    var accelOn = false;
    var batteryLevel = Puck.getBatteryPercentage();
      
    NRF.nfcURL("Puck.js 9e03");
    
    setWatch(function() {
      if (accelOn) {
        Puck.accelOff();
        accelOn = false;
        NRF.nfcRaw(new Uint8Array([193, 1, 0, 0, 0, 13, 85, 3, 80, 117, 99, 107, 46, 106, 115, 32, 57, 101, 48, 51]));
        batteryLevel = Puck.getBatteryPercentage();
      } else {
        Puck.accelOn(1660);
        accelOn = true;
      }
    }, BTN, {edge:"rising", repeat:1, debounce:20});
    
    
    NRF.setServices({
      0x2713: {
        "e482a929-e02a-4e8a-8296-cca819ebe0c6": {
          value: String(Puck.getTemperature()),
          maxLen: 20,
          broadcast: true, // optional, default is false
          readable: true,   // optional, default is false
          writable: false,   // optional, default is false
          notify: true,   // optional, default is false
          indicate: true,   // optional, default is false
          description: "Accelerometer X",  // optional, default is null,
        },
        "cad35f0b-8a1a-442c-b249-4698e582fcf4": {
          value: String(Puck.getTemperature()),
          maxLen: 20,
          broadcast: true, // optional, default is false
          readable: true,   // optional, default is false
          writable: false,   // optional, default is false
          notify: true,   // optional, default is false
          indicate: true,   // optional, default is false
          description: "Accelerometer Y",  // optional, default is null,
        }, 
        "4249a4c7-9a03-428d-818a-24a7c5aefb4a": {
          value: String(Puck.getTemperature()),
          maxLen: 20,
          broadcast: true, // optional, default is false
          readable: true,   // optional, default is false
          writable: false,   // optional, default is false
          notify: true,   // optional, default is false
          indicate: true,   // optional, default is false
          description: "Accelerometer Z",  // optional, default is null,
        },
        "54e832b7-714e-4aa5-ada9-e21dd2006844": {
          value: String(Puck.getTemperature()),
          maxLen: 20,
          broadcast: true, // optional, default is false
          readable: true,   // optional, default is false
          writable: false,   // optional, default is false
          notify: true,   // optional, default is false
          indicate: true,   // optional, default is false
          description: "Gyroscope X",  // optional, default is null,
        },
        "cbbb698d-878e-473a-9625-fbe0243ac8e1": {
          value: String(Puck.getTemperature()),
          maxLen: 20,
          broadcast: true, // optional, default is false
          readable: true,   // optional, default is false
          writable: false,   // optional, default is false
          notify: true,   // optional, default is false
          indicate: true,   // optional, default is false
          description: "Gyroscope Y",  // optional, default is null,
        }, 
        "6db27825-05fa-4984-9fed-568edd9f1fe8": {
          value: String(Puck.getTemperature()),
          maxLen: 20,
          broadcast: true, // optional, default is false
          readable: true,   // optional, default is false
          writable: false,   // optional, default is false
          notify: true,   // optional, default is false
          indicate: true,   // optional, default is false
          description: "Gyroscope Z",  // optional, default is null,
        },
        "1bdf76b4-006a-4e20-8a09-fb87b8f4b29d": {
          value: String(batteryLevel),
          maxLen: 20,
          broadcast: true, // optional, default is false
          readable: true,   // optional, default is false
          writable: false,   // optional, default is false
          notify: true,   // optional, default is false
          indicate: true,   // optional, default is false
          description: "Battery Level",  // optional, default is null,
        }
      }
    });
    
    NRF.setAdvertising({
      0x2713: undefined
    });
    
    Puck.on('accel', function(a) {
      NRF.updateServices({
        0x2713: {
          "e482a929-e02a-4e8a-8296-cca819ebe0c6": {
            value: String(a.acc.x),
            notify: true,
            readable: true
          },
          "cad35f0b-8a1a-442c-b249-4698e582fcf4": {
            value: String(a.acc.y),
            notify: true,
            readable: true
          },
          "4249a4c7-9a03-428d-818a-24a7c5aefb4a": {
            value: String(a.acc.z),
            notify: true,
            readable: true
          },
          "54e832b7-714e-4aa5-ada9-e21dd2006844": {
            value: String(a.gyro.x),
            notify: true,
            readable: true
          },
          "cbbb698d-878e-473a-9625-fbe0243ac8e1": {
            value: String(a.gyro.y),
            notify: true,
            readable: true
          },
          "6db27825-05fa-4984-9fed-568edd9f1fe8": {
            value: String(a.gyro.z),
            notify: true,
            readable: true
          },
          "1bdf76b4-006a-4e20-8a09-fb87b8f4b29d": {
            value: String(batteryLevel),
            notify: true,
            readable: true
          }
        }
      });
    });
    
  • Hi - I noticed you already posted this as an 'issue' on GitHub and I saw that first, so see the answer on there: https://github.com/espruino/Espruino/iss­ues/2349

    But for anyone else looking at this: Bluetooth LE itself can't send data that fast (the fastest 'connection interval' supported is 7.5ms) so you'll instead have to batch up multiple samples into one transmission.

    Once that is done you should be ok to go a lot faster - but 1kHz may still be quite optimistic.

    Some friends have a company doing VR hand controllers and they're finding that 200Hz works more than well enough for them at the moment.

  • Apart from batching maybe it would also help to not to have so many characteristics with string values but have one with e.g. 16 or 32bit binary triplet for xyz (3x16 or 3x32 bits). Not sure how many notifications/packets your single NRF.updateServices call generates. Also I'd reduce maxlen to 6 or 12 then.

    Typical BLE packet without MTU increase can have 20 bytes so your string values won't fit into single one making it much slower to send (and receive).

    EDIT:
    oh, after writing this I checked github issue, everything was already said there :-)

  • Hi Gordon, thanks a lot for your reply. I will try it out. Much appreciated

  • Thanks for your input! Yes, I think I may try Bluetooth.write thru UART and not use NRF.updateServices as well as combining all the values into one packet which should give me a lot more than what I am getting currently.

  • Also for others who may stumble upon this...I found out after reading the datasheets of the accelerometer and digging into the Espruino code for acceleration on the puck and it seems to be that the Puck's accelerometer is being put into low-power consumption mode which has a max polling rate of only 52Hz, but by doing the following two lines after Puck.accelOn(interval):

        Puck.accelOn(1660);
        Puck.accelWr('0x15', '0x00');
        Puck.accelWr('0x16', '0x00');
    

    It should put the accelerometer chip into "high-performance operating mode enabled" which can allow up to 6.66kHz, but the max the puck can handle (based on documentation) is 1.66Hz. Note that battery consumption will be more, however.

    I believe this happens here in the Espruino code: https://github.com/espruino/Espruino/blo­b/3fbcd63bc327de67c88bf19efd9e4776249ebd­3e/libs/puckjs/jswrap_puck.c#L528-L542

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

Puck.js onAccel callback speed is slow

Posted by Avatar for mc9311 @mc9311

Actions