
• #2
Hi,
The red flash when the battery is inserted seems like a good sign...
but pressing the button doesn't give a green LED ... or any other response
You need to hold the button down while you insert the battery. Pressing the button after the battery is inserted will have no effect.
Could that be the problem?
the puck is not recognized by my webbluetoothcompatible computer.
The Pucks should be recognized out the box once the red LED has flashed. Do you have an Android phone/tablet or some other computer you could try? It's possible that there is some configuration issue on the PC you are using.
If there are still issues, please could you record a video or how you do the reset and also what happens on the PC when you go to connect?

• #3
Thanks very much for that quick response ... and pressing the button while putting the baattery back in DID give me a flash of all the leds and then, only once, continued with a flaash of the green LED three times.
I guess I missed or misunderstood the need to press the button AS the battery is being inserted.
The puck still isn't recognized by my chromebook's pairing but it is recognized by my samsung phone ... although the phone says I need an app to use the device ... and also by the espruino web ide.
Thanks!
Do you know if there's an espruino version of the madgwick ahrs protocol?
And the IDE says a new firmware is available. I have 2.09 and it's suggesting 2v16.Do you know the firmware upgrade method? I'll look in the docs as well.
Thanks again!

• #4
and pressing the button while putting the baattery back in DID give me a flash of all the leds and then, only once, continued with a flaash of the green LED three times.
Ok  so the green LED flash 3 times means it's started up into Espruino and hasn't loaded any code.
If you let go of the button as soon as any lights light up, you'll enter bootloader mode (green LED on solid). Which I think is what you need to do to solve the other issue you posted: https://forum.espruino.com/conversations/382940/#comment16827704
I guess I missed or misunderstood the need to press the button AS the battery is being inserted.
You need to hold the button down, then insert the battery with the button still held...
But to just use the Puck normally, holding the button isn't needed. Once the red LED flashes you should be ok to connect.
The puck still isn't recognized by my chromebook's pairing
No, it won't be. You need to go to espruino.com/ide and then connect from there  do not pair it from the OS bluetooth menu  and if you have done, you need to unpair it.
There is a tutorial on getting started at https://www.espruino.com/Quick+Start+BLE#puckjs and I think it'd be worth going through that step by step
Do you know if there's an espruino version of the madgwick ahrs protocol?
For do you mean https://github.com/arduinolibraries/MadgwickAHRS/blob/master/src/MadgwickAHRS.cpp ?
I'm not aware of an implementation but the code there looks quite straightforward (just a bunch of maths) so it would be almost copy/paste to get it running in Espruino (change
float
tovar
and removef
from the end of the numbers). 
• #5
I've just converted the Madgwick code:
// Based on https://github.com/arduinolibraries/MadgwickAHRS/blob/master/src/MadgwickAHRS.cpp const sampleFreqDef = 26.0; // sample frequency in Hz const betaDef = 0.1; // 2 * proportional gain //============================================================================================ // Functions function invSqrt(x) { return 1/Math.sqrt(x); } // // AHRS algorithm update class Madgwick { /* contains: roll, pitch, yaw (in radians) */ constructor() { this.beta = betaDef; this.q0 = 1.0; this.q1 = 0.0; this.q2 = 0.0; this.q3 = 0.0; this.invSampleFreq = 1.0 / sampleFreqDef; this.anglesComputed = 0; } update(gx, gy, gz, ax, ay, az, mx, my, mz) { var recipNorm; var s0, s1, s2, s3; var qDot1, qDot2, qDot3, qDot4; var hx, hy; var _2q0mx, _2q0my, _2q0mz, _2q1mx, _2bx, _2bz, _4bx, _4bz, _2q0, _2q1, _2q2, _2q3, _2q0q2, _2q2q3, q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3; // Use IMU algorithm if magnetometer measurement invalid (avoids NaN in magnetometer normalisation) if((mx == 0) && (my == 0) && (mz == 0)) { this.updateIMU(gx, gy, gz, ax, ay, az); return; } var q0 = this.q0, q1 = this.q1, q2 = this.q2, q3 = this.q3; // Convert gyroscope degrees/sec to radians/sec gx *= 0.0174533; gy *= 0.0174533; gz *= 0.0174533; // Rate of change of quaternion from gyroscope qDot1 = 0.5 * (q1 * gx  q2 * gy  q3 * gz); qDot2 = 0.5 * (q0 * gx + q2 * gz  q3 * gy); qDot3 = 0.5 * (q0 * gy  q1 * gz + q3 * gx); qDot4 = 0.5 * (q0 * gz + q1 * gy  q2 * gx); // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) if(!((ax == 0.0) && (ay == 0.0) && (az == 0.0))) { // Normalise accelerometer measurement recipNorm = invSqrt(ax * ax + ay * ay + az * az); ax *= recipNorm; ay *= recipNorm; az *= recipNorm; // Normalise magnetometer measurement recipNorm = invSqrt(mx * mx + my * my + mz * mz); mx *= recipNorm; my *= recipNorm; mz *= recipNorm; // Auxiliary variables to avoid repeated arithmetic _2q0mx = 2 * q0 * mx; _2q0my = 2 * q0 * my; _2q0mz = 2 * q0 * mz; _2q1mx = 2 * q1 * mx; _2q0 = 2 * q0; _2q1 = 2 * q1; _2q2 = 2 * q2; _2q3 = 2 * q3; _2q0q2 = 2 * q0 * q2; _2q2q3 = 2 * q2 * q3; q0q0 = q0 * q0; q0q1 = q0 * q1; q0q2 = q0 * q2; q0q3 = q0 * q3; q1q1 = q1 * q1; q1q2 = q1 * q2; q1q3 = q1 * q3; q2q2 = q2 * q2; q2q3 = q2 * q3; q3q3 = q3 * q3; // Reference direction of Earth's magnetic field hx = mx * q0q0  _2q0my * q3 + _2q0mz * q2 + mx * q1q1 + _2q1 * my * q2 + _2q1 * mz * q3  mx * q2q2  mx * q3q3; hy = _2q0mx * q3 + my * q0q0  _2q0mz * q1 + _2q1mx * q2  my * q1q1 + my * q2q2 + _2q2 * mz * q3  my * q3q3; _2bx = Math.sqrt(hx * hx + hy * hy); _2bz = _2q0mx * q2 + _2q0my * q1 + mz * q0q0 + _2q1mx * q3  mz * q1q1 + _2q2 * my * q3  mz * q2q2 + mz * q3q3; _4bx = 2 * _2bx; _4bz = 2 * _2bz; // Gradient decent algorithm corrective step s0 = _2q2 * (2 * q1q3  _2q0q2  ax) + _2q1 * (2 * q0q1 + _2q2q3  ay)  _2bz * q2 * (_2bx * (0.5  q2q2  q3q3) + _2bz * (q1q3  q0q2)  mx) + (_2bx * q3 + _2bz * q1) * (_2bx * (q1q2  q0q3) + _2bz * (q0q1 + q2q3)  my) + _2bx * q2 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5  q1q1  q2q2)  mz); s1 = _2q3 * (2 * q1q3  _2q0q2  ax) + _2q0 * (2 * q0q1 + _2q2q3  ay)  4 * q1 * (1  2 * q1q1  2 * q2q2  az) + _2bz * q3 * (_2bx * (0.5  q2q2  q3q3) + _2bz * (q1q3  q0q2)  mx) + (_2bx * q2 + _2bz * q0) * (_2bx * (q1q2  q0q3) + _2bz * (q0q1 + q2q3)  my) + (_2bx * q3  _4bz * q1) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5  q1q1  q2q2)  mz); s2 = _2q0 * (2 * q1q3  _2q0q2  ax) + _2q3 * (2 * q0q1 + _2q2q3  ay)  4 * q2 * (1  2 * q1q1  2 * q2q2  az) + (_4bx * q2  _2bz * q0) * (_2bx * (0.5  q2q2  q3q3) + _2bz * (q1q3  q0q2)  mx) + (_2bx * q1 + _2bz * q3) * (_2bx * (q1q2  q0q3) + _2bz * (q0q1 + q2q3)  my) + (_2bx * q0  _4bz * q2) * (_2bx * (q0q2 + q1q3) + _2bz * (0.5  q1q1  q2q2)  mz); s3 = _2q1 * (2 * q1q3  _2q0q2  ax) + _2q2 * (2 * q0q1 + _2q2q3  ay) + (_4bx * q3 + _2bz * q1) * (_2bx * (0.5  q2q2  q3q3) + _2bz * (q1q3  q0q2)  mx) + (_2bx * q0 + _2bz * q2) * (_2bx * (q1q2  q0q3) + _2bz * (q0q1 + q2q3)  my) + _2bx * q1 * (_2bx * (q0q2 + q1q3) + _2bz * (0.5  q1q1  q2q2)  mz); recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude s0 *= recipNorm; s1 *= recipNorm; s2 *= recipNorm; s3 *= recipNorm; // Apply feedback step qDot1 = this.beta * s0; qDot2 = this.beta * s1; qDot3 = this.beta * s2; qDot4 = this.beta * s3; } // Integrate rate of change of quaternion to yield quaternion q0 += qDot1 * this.invSampleFreq; q1 += qDot2 * this.invSampleFreq; q2 += qDot3 * this.invSampleFreq; q3 += qDot4 * this.invSampleFreq; // Normalise quaternion recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); this.q0 = q0 * recipNorm; this.q1 = q1 * recipNorm; this.q2 = q2 * recipNorm; this.q3 = q3 * recipNorm; anglesComputed = 0; } // // IMU algorithm update updateIMU(gx, gy, gz, ax, ay, az) { var recipNorm; var s0, s1, s2, s3; var qDot1, qDot2, qDot3, qDot4; var _2q0, _2q1, _2q2, _2q3, _4q0, _4q1, _4q2 ,_8q1, _8q2, q0q0, q1q1, q2q2, q3q3; var q0 = this.q0, q1 = this.q1, q2 = this.q2, q3 = this.q3; // Convert gyroscope degrees/sec to radians/sec gx *= 0.0174533; gy *= 0.0174533; gz *= 0.0174533; // Rate of change of quaternion from gyroscope qDot1 = 0.5 * (q1 * gx  q2 * gy  q3 * gz); qDot2 = 0.5 * (q0 * gx + q2 * gz  q3 * gy); qDot3 = 0.5 * (q0 * gy  q1 * gz + q3 * gx); qDot4 = 0.5 * (q0 * gz + q1 * gy  q2 * gx); // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) if(!((ax == 0) && (ay == 0) && (az == 0))) { // Normalise accelerometer measurement recipNorm = invSqrt(ax * ax + ay * ay + az * az); ax *= recipNorm; ay *= recipNorm; az *= recipNorm; // Auxiliary variables to avoid repeated arithmetic _2q0 = 2 * q0; _2q1 = 2 * q1; _2q2 = 2 * q2; _2q3 = 2 * q3; _4q0 = 4 * q0; _4q1 = 4 * q1; _4q2 = 4 * q2; _8q1 = 8 * q1; _8q2 = 8 * q2; q0q0 = q0 * q0; q1q1 = q1 * q1; q2q2 = q2 * q2; q3q3 = q3 * q3; // Gradient decent algorithm corrective step s0 = _4q0 * q2q2 + _2q2 * ax + _4q0 * q1q1  _2q1 * ay; s1 = _4q1 * q3q3  _2q3 * ax + 4 * q0q0 * q1  _2q0 * ay  _4q1 + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * az; s2 = 4 * q0q0 * q2 + _2q0 * ax + _4q2 * q3q3  _2q3 * ay  _4q2 + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * az; s3 = 4 * q1q1 * q3  _2q1 * ax + 4 * q2q2 * q3  _2q2 * ay; recipNorm = invSqrt(s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3); // normalise step magnitude s0 *= recipNorm; s1 *= recipNorm; s2 *= recipNorm; s3 *= recipNorm; // Apply feedback step qDot1 = this.beta * s0; qDot2 = this.beta * s1; qDot3 = this.beta * s2; qDot4 = this.beta * s3; } // Integrate rate of change of quaternion to yield quaternion q0 += qDot1 * this.invSampleFreq; q1 += qDot2 * this.invSampleFreq; q2 += qDot3 * this.invSampleFreq; q3 += qDot4 * this.invSampleFreq; // Normalise quaternion recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); this.q0 = q0 * recipNorm; this.q1 = q1 * recipNorm; this.q2 = q2 * recipNorm; this.q3 = q3 * recipNorm; anglesComputed = 0; } // // Fast inverse squareroot // See: http://en.wikipedia.org/wiki/Fast_inverse_square_root // computeAngles() { var q0 = this.q0, q1 = this.q1, q2 = this.q2, q3 = this.q3; this.roll = Math.atan2(q0*q1 + q2*q3, 0.5  q1*q1  q2*q2); this.pitch = Math.asin(2 * (q1*q3  q0*q2)); this.yaw = Math.atan2(q1*q2 + q0*q3, 0.5  q2*q2  q3*q3); this.anglesComputed = 1; } } var m = new Madgwick(); var mag = {x:0,y:0,z:0}; Puck.magOn(40); Puck.on('mag', function(xyz) { mag = xyz; }); Puck.on('accel', function(a) { m.update( a.gyro.x/134, a.gyro.y/134, a.gyro.z/134, a.acc.x/8192, a.acc.y/8192, a.acc.z/8192, mag.x, mag.y, mag.z ); m.computeAngles(); }); Puck.accelOn(sampleFreqDef); // Check m.roll, m.yaw, m.pitch (in radians)
If this works ok I'm very happy to turn it into a library.
It seems to work well here  if anything it's just a shame that there's no absolute position measurement built in here  but the actual roll/pitch/yaw looks like it works ok

• #6
WoW! Thanks So much for all of this great help! I'm working on getting the puck recognized in SensiML Data Capture Lab today.

• #7
Had stumbled upon this in the mean time. Seems to include a three.js visualizer and to use a serial interface. Haven't looked thur it. Just passing along the info. https://github.com/ZiCog/madgwick.js

• #8
It appears I need to do a custom device setup to interface with the SensiML Data Capture Lab. Looking into how to do that. So far, it seems I need to create a config file with BLE gatt info for the services to be monitored.
The red led flashes when the battery is inserted but pressing the button doesn't give a green LED ... or any other response ... and the puck is not recognized by my webbluetoothcompatible computer.
I ordered the two pucks in 11/2021 and this was their behavior when I first received them so I set them aside and abandoned the intended use.
I'd like to get back to that project ... but the recommended reset and hard reset methods have no effect.
The pucks recognize the battery ( properly inserted via the docs) and the red LED flashes ... but that's all I get.
Is there some different reset method ... a way to see if these aren't actually DOA?
Any help/response appreciated.