Closed mihir-chauhan closed 1 year ago
I seriously doubt you can get 1khz through Bluetooth, especially using only service advertising. You could perhaps try to send it through the uart, streaming the data over Bluetooth as fast as possible.
You could have a look at this example code, it used the Bangle but should work with the Puck as well: https://www.espruino.com/Bangle.js+Data+Streaming
Hi - I don't believe the problem is with the Puck.js accelerometer speed - it's just that Bluetooth LE isn't capable of sending the data that fast the way you are attempting to do it
Bluetooth works on a connection interval, and the fastest this can be is 7.5ms (130Hz) according to the spec. While you can trigger more than one notification per connection interval I think the max might be around 5, and since you're updating multiple characteristics that will really eat into it.
What I'd suggest is:
As @mariusGundersen says, the best way to do all the above is really just to use the built-in UART since Espruino will automatically batch updates into the minimum amount of packets required.
Something along the lines of:
Puck.on('accel', function(a) {
Bluetooth.write((new Int16Array([a.acc.x,a.acc.y,a.acc.z,a.gyro.x,a.gyro.y,a.gyro.z])).buffer);
});
is probably all you need. I wouldn't send the battery level 1000 times a second as you're just wasting time and bandwidth again (you could keep doing that with a characteristic as you were, but update it once a minute)
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
Yes - there are some READMEs in the repo about how to build it, as well as some tutorials on the website about adding functionality. But as above it's not really an issue with Espruino at this point, it's to do with what you're trying to do with Bluetooth.
Just to add, in the example I send the data as 16 bit values, but if you were able to do with just 8 bits (losing a bit of precision) that would halve the amount of data you needed to send and so would make life a lot easier.
Thank you @mariusGundersen and @gfwilliams for your input. I will try these out and let you know! Appreciate your help. Edit: closing issue for now
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 (setting accel/gyro to low power) happens here in the Espruino code: https://github.com/espruino/Espruino/blob/3fbcd63bc327de67c88bf19efd9e4776249ebd3e/libs/puckjs/jswrap_puck.c#L528-L542
Ok, thanks! So we should ideally not set those low power mode flags above 52Hz? I could make a change for that...
Yes that would be great because in low power mode, as per the accelerometer/gyro datasheet it will only go up to 50Hz, which was what I was originally receiving even if I did Puck.accelOn(1660);
. Thanks
I did have a quick try and:
n=0;
Puck.on("accel", ()=>{"jit" n++});
setInterval(function() {
console.log(n);
n=0;
},1000);
Puck.accelOn(208)
With firmware 2v17 it does give you 208Hz as expected, but for me any higher and it tops out at ~350Hz even at very high sample rates. Setting the register values as you have done had no effect for me.
Looking again at Table 52. Accelerometer ODR register setting
and the one for Gyro it's actually fine as it was. It's saying that actually with that low power flag set it'll automatically set the correct operation mode depending on what frequency is requested.
Digging into it further, with it topping out at ~350Hz, around 80% of the time is spent in the accel_read
routine which literally does nothing except read the data via I2C from the accelerometer, so about the only way to actually make it go faster would be to switch to using hardware I2C (currently we use software)
I've had a quick play around and have swapped it to hardware I2C, and that gets us to ~740Hz with only about 25% of the time spent on I2C, so it's definitely an improvement, but it's still not 1kHz - and I'm not sure if it's worth putting that code in as some users will be upset that the only available hardware I2C device disappears if they use the accelerometer. I've pushed it as a PUCKJS_HW_I2C_ACCEL branch though.
Potentially it could be added conditionally - if the poll rate is above 50Hz it starts using hardware I2C or something like that...
The 740Hz is a great improvement, I will try out the hardware I2C. One question I had is if I was storing n amount of the data in a list and then sending all the data through Bluetooth when it was full, would the Bluetooth send function be "blocking" in the sense that I won't be able to handle any of the new data during the send time period and lose that data? Or would there be a way to still store the data while sending through Bluetooth. Thanks for your help
If you use Bluetooth.write
(with the UART) then the function only blocks when the output buffer is full, otherwise it returns right away. The output buffer is around 1kB I think so even if you just do Bluetooth.write
with the data as it comes in (without worrying about buffering) as I'd done in https://github.com/espruino/Espruino/issues/2349#issuecomment-1511030810 you should be fine.
Thanks. When I try to build on WSL (Windows Subsystem for Linux), I am able to get bootloader_espruino_2v17_puckjs.elf
and bootloader_espruino_2v17_puckjs.hex
. I am not sure what exactly to do in order to package these as it says to upload a ZIP for nRF52 boards. Also, what are all the parameters and respective values I need in the following command line action?: nrfutil pkg generate --application bootloader_espruino_2v17_puckjs.hex puckjs_bootloader.zip
, such as hardware version, etc?
Hi - you don't need to flash the bootloader firmware - I'm not sure quite how you ended up with only that built.
You could try DFU_UPDATE_BUILD=1 BOARD=PUCKJS RELEASE=1 make
and that will automatically spit out a DFU zip for the application that you can then use with the normal 'DFU' app on iOS/Android.
However, GitHub automatically builds the firmware if github actions is enabled (it is on the main repo). That used to be only for the 'master' branch, but I've just enabled it for all new branches, so you should now be able to download via:
https://github.com/espruino/Espruino/actions?query=branch%3APUCKJS_HW_I2C_ACCEL
For instance in https://github.com/espruino/Espruino/actions/runs/4784020729 scroll right down to Artefacts
and click PUCKJS
and you should get the DFU zip built for you.
Thanks for your help @gfwilliams, I was able to update the firmware through the iOS app (Web IDE and other Web Bluetooth Secure DFU had error at last step). Just FYI: I am able to get a max of 833Hz when there is just the counter, but when I do the Bluetooth.write((new Int16Array([a.acc.x,a.acc.y,a.acc.z,a.gyro.x,a.gyro.y,a.gyro.z])).buffer);
it drops down to 348Hz.
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 6600
Puck.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?Here is my JS code.