You are reading a single comment by @HughB and its replies. Click here to read the full conversation.
  • Yes, that Hackaday link is basically all the info I have on the Q3 at the moment, and you can build Espruino (although I'm not doing automatic builds at the moment). Basically what we're missing is the heart rate sensor right now (since I have to reverse engineer it all). I'm hoping to get them in the shop 'soon' - hopefully within the next month - but they're still very much beta as I have to decide exactly what to do about making existing apps compatible (the screen/buttons are different).

    GPS is a pain though - it doesn't seem to be quite as good as the Bangle's, and as you say it's a completely different command set too.

    Is there a way to simulate this in javascript first,

    Yes - it's not a very difficult algorithm (there is no machine learning), so this is probably what I should have actually done at the start. Try:

    // values for debug plotting
    var lastAccel = 120;      // BLUE
    var lastAccelFilt = 120;  // YELLOW
    var lastThresh = 120;     // RED
    
    var filter_taps = new Int8Array([ -2, 4, 4, 1, -1, 0, 2, -3, -12, -13, 2, 24, 29, 6, -25, -33, -13, 10, 11, -1, 3, 29, 41, 4, -62, -89, -34, 62, 110, 62, -34, -89, -62, 4, 41, 29, 3, -1, 11, 10, -13, -33, -25, 6, 29, 24, 2, -13, -12, -3, 2, 0, -1, 1, 4, 4, -2 ]);
    var history = new Int8Array(filter_taps.length);
    const stepCounterThresholdMin = 1500;
    const stepCounterAvr = 1;
    
    /// Theshold in filtered acceleration for detecting a step
    var stepCounterThreshold = stepCounterThresholdMin;
    /// has filtered acceleration passed stepCounterThresholdLow?
    var stepWasLow = false;
    
    function onAccel(a) {
      // scale to fit and clip
      var v = ((a.mag-1)*8192)>>5;
      // save
      history.set(new Int8Array(history.buffer,1));
      history[history.length-1] = E.clip(v, -128, 127);
      // do filtering
      var accFiltered = E.convolve(filter_taps, history, 0) >> 2;
    
      /*
      // Simple average-based threshold
      if (stepCounterAvr) {
        var a = accFiltered;
        if (a<0) a=-a;
        stepCounterThreshold = (stepCounterThreshold*(32-stepCounterAvr) + a*stepCounterAvr) >> 5;
        if (stepCounterThreshold < stepCounterThresholdMin)
          stepCounterThreshold = stepCounterThresholdMin;
      }*/
      
      // Set threshold based on the 'middle' history item - the one making the big spikes.
      // Try and scale it appropriately
      var a = history[32] * 55; 
      if (a<0) a=-a;
      if (a > stepCounterThreshold) 
        stepCounterThreshold = a;//(stepCounterThreshold+a) >> 1;
      stepCounterThreshold -= 48;
      if (stepCounterThreshold < stepCounterThresholdMin)
        stepCounterThreshold = stepCounterThresholdMin;  
      
      // check for steps
      var hadStep = false;
      if (accFiltered < -stepCounterThreshold) 
        stepWasLow = true;
      else if ((accFiltered > stepCounterThreshold) && stepWasLow) {
        stepWasLow = false;
        hadStep = true;
      }
    
      // output data
      g.scroll(0,1);
      var n;
      
      if (accFiltered < -stepCounterThreshold)
        g.setColor("#0ff").fillRect(0,0,8,0);
      if (accFiltered > stepCounterThreshold)
        g.setColor("#0ff").fillRect(232,0,240,0);
      
      n = 120+v;
      g.setColor("#00f").fillRect(lastAccel,0,n,0);
      lastAccel = n;
      n = 120+(accFiltered>>6);
      g.setColor("#ff0").fillRect(lastAccelFilt,0,n,0);
      lastAccelFilt = n;
      n = 120+(stepCounterThreshold>>6);
      g.setColor("#f00").fillRect(lastThresh,0,n,0);
      lastThresh = n;
    
      if (hadStep) {
        g.setColor(-1).drawString("STEP",60,0);
      }
    }
    Bangle.on('accel',onAccel);
    Bangle.setLCDTimeout(0);
    
    

    On the graph that's displayed, blue is the actual accelerometer data, yellow is the filtered data, and red is the threshold.

    The issue is really the filter...

    • It's good in that repeated inputs within the frequency range get amplified, so are easy to detect
    • However a single big acceleration input will 'ring' - it generates oscillations in the desired frequency.

    So if using the filter actually turns out to be a good idea, we basically need a way of only passing through steps when the filter is producing values that are all the same (ish) amplitude, and not passing through the outliers.

  • but they're still very much beta as I have to decide exactly what to do about making existing apps compatible (the screen/buttons are different).

    I've been thinking about this. I think the best way would be to say, the screen is different size, its got one button, its a different watch but same API, you will have to port your App. Hopefully the original authors of the Apps would do the porting. The thing with a one button watch is that the whole way of interacting with an App will be totally changed. With it being a full touch screen I would expect use of Up, Down, Left, Right swipe would provide a lot more options for navigating round things.

    I'm definitely up for having a go at the low power GPS again. It was a lot of work but worth it. There were a few comments made about me stepping outside the house a lot to get a signal :)

About

Avatar for HughB @HughB started