Avatar for user101436

user101436

Member since Jun 2019 • Last active Jul 2019
  • 1 conversations
  • 9 comments

Most recent activity

  • in Projects
    Avatar for user101436

    IT WORKS!

    To use:

    1. Upload code via webIDE
    2. Disconnect the IDE
    3. Calibrate the mag sensor by rotating puck in all directions until no red flashes (only green)
    4. Press button to stop calibrating
    5. Connect by BLE from a laptop or phone
    6. run music software
    7. rotate for volume
    8. press for pause/play
    9. Turn over and rotate for next/prev track

    Let me know your results.
    Current things to improve are next/prev un- pauses, the is no power saving mode, and tidy up my code and create some low level functions for calibrate and power management.

    Code:

    var Vec3 = require('Vec3');
    var vMin = new Vec3();
    var vMax = new Vec3();
    var vAve = new Vec3();
    var vZero = new Vec3(); 
    var calibrating = false;
    var calibrated = false;
    var count = 0;
    var h = 0;
    var oldh = 0;
    var r = 0;
    var controls = require("ble_hid_controls");
    var nrf = NRF.setServices(undefined, { hid : controls.report });
    
    /*
    // use this for power managment
    // call a function if button is held down for 4 seconds
    function b4Seconds(callback) {
      setWatch(function(e) {
        if (calibrating) {return;}
        console.log("Button down");
        t4s = setTimeout(function() {
          callback();
        },4000);
        setWatch(function(e) {
          clearTimeout(t4s);
          console.log("Button up");
        }, BTN, { repeat: false, edge: 'falling', debounce: 50 });
      }, BTN, { repeat: true, edge: 'rising', debounce: 50 });
    }
    */
    
    function calibrate () {
      if (calibrated) {
        //console.log('re-calibrating...');
      } else {
        //console.log('calibrating...');
      }
      calibrated = false;
      calibrating = true;
      var xyz = Puck.mag();
      var sMax = 0; 
      var sMin = 0;
      count = 0;
      vMin = new Vec3(xyz);
      vMax = new Vec3(xyz);
      Puck.magOn(10);
      Puck.on('mag', function(xyz) {
        if (calibrated) {return;}
        var vMag = new Vec3(xyz);
        vMin = vMin.min(vMag);
        vMax = vMax.max(vMag);
        if ((sMax !=  vMax.mag()) || (sMin != vMin.mag())) {
          sMin = vMin.mag();
          sMax = vMax.mag();
          count++;
          //console.log('new min or max: ',count);
          // flash the red LED when calibrating
          digitalPulse(LED1,1,100);
        } else { 
        // flash the green LED when not calibrating
        digitalPulse(LED2,1,10);
        }
      });
      //press the buton to stop calibrating
      setWatch(function(e) {
        Puck.magOn(5);
        calibrating = false;
        //console.log("calibarion completed");
        //console.log('max: ',vMax);
        //console.log('min: ',vMin);
        // calculate the average of vMin and vMax to get the nuteral position
        vAve = new Vec3((vMin.x + vMax.x)/2,(vMin.y + vMax.y)/2,(vMin.z + vMax.z)/2);
       // console.log('ave: ',vAve);
        // get the zero position when the end calibrate button was pressed
        vZero = new Vec3(Puck.mag()).sub(vAve);
       // console.log('zero:',vZero);
        calibrated = true;
      }, BTN, { repeat: false, edge: 'rising', debounce: 50 });
    }
    
    
    function calibratedMag() {
      var comQueue = [];
      var coms = false;
      // use the button for play/pause
      setWatch(function(e) {
        if(calibrating) {return;}
        comQueue.push('S');
        digitalPulse(LED1,1,10);
        digitalPulse(LED2,1,10);
        digitalPulse(LED3,1,10);
      }, BTN, { repeat: true, edge: 'rising', debounce: 50 });
      Puck.magOn(10);
      Puck.on('mag', function(xyz) {
        if(calibrating) {return;}
        if ((comQueue.length > 0) && (coms == false)){
          coms = true;
          //console.log(comQueue,coms);
          var comand = comQueue.pop();
          if (comand == 'U') {
            digitalPulse(LED1,1,3);
            try { 
              controls.volumeUp(function(){
                controls.volumeUp(function(){
                  coms = false;
                });});
            } catch (e) {coms = false;}
          }
          if (comand == 'D') {
            digitalPulse(LED3,1,3);
            try { 
              controls.volumeDown(function(){
                controls.volumeDown(function(){
                  coms = false;
                });});
            } catch (e) {coms = false;}
          }
          if (comand == 'N') {
            digitalPulse(LED2,1,3);
            try { 
              controls.next(function(){
                  coms = false;
              });
            } catch (e) {coms = false;}
          }
          if (comand == 'P') {
            digitalPulse(LED2,1,3);
            try { 
              controls.prev(function(){
                  coms = false;
              });
            } catch (e) {coms = false;}
          }
          if (comand == 'S') {
            try { 
              controls.playpause(function(){
                  coms = false;
              });
            } catch (e) {coms = false;}
          }
        }
        // correct mag reading using calibration data
        var vMag = new Vec3(xyz).sub(vAve);
        //console.log('mag: ',vMag);
        h = (Math.atan2(vMag.y, vMag.x) * 180) / Math.PI;
        if (h > 360) {
          h = h - 360; 
        }
        if (h < 0) {
          h = h + 360;
        }
        
        r = Math.round(h - oldh);
        if ((r > 300)) {r = r - 360;} 
        if ((r < -300)) {r = r + 360;} 
        
        if (Math.abs(r) >4) {
          if (vMag.z > 0) {
            if (r>0) {
              comQueue.push('U');
              //try { controls.volumeUp();} catch (e) { }
            } else {
              comQueue.push('D');
            }
          } else {
            if (r>0) {
              comQueue.push('P');
            } else {
              comQueue.push('N');
            }
          }
          //console.log('-------------');
          if (!calibrated) {console.log('uncalibrated!');}
            //console.log('heading: ',Math.round(h));
            //console.log('rotate: ',r);
          if (vMag.z > 0) {
            //console.log('upwards');
          } else {
            //console.log('downwards');
          }
        }
        oldh = h;
      });
    }
    
    
    //calibrate by holding button down for 4 seconds
    calibrate()
    calibratedMag();
    
    
    
    
    
    

    Reset to remove stop code

  • in Projects
    Avatar for user101436

    I will do some optimisation and tidying up then post the final code

  • in Projects
    Avatar for user101436

    I found the problem. I was still using console.log() while connected as a HID which caused the puckjs to hang. I need to work out how to re-direct console.log somewhere safe. I have volume up and down working well. I will do a bit more work and post an update.

  • in Projects
    Avatar for user101436

    I have added the HID media keys but only volume up is working.??? I am debugging

  • in Projects
    Avatar for user101436

    I have calculated the average of the min max and subtracted this from the raw. The calibration data now looks good. Now i can see when the puck is upside down as the z axis changes it sign. I am also calculating the heading and correcting for negative numbers .

    Can you test on your device and see if the puck now works as a digital compass.

    You will have to calibrate by holding down the button for 5 seconds then rotating the puck in all directions until the is only green flashes no blue. then press to go back to calibrated readings.

    var Vec3 = require('Vec3');
    var vMin = new Vec3();
    var vMax = new Vec3();
    var vAve = new Vec3();
    var vZero = new Vec3(); 
    var calibrating = false;
    var calibrated = false;
    var count = 0;
    var h = 0;
    var oldh = 0;
    
    
    // call a function if button is held down for 4 seconds
    function b4Seconds(callback) {
      setWatch(function(e) {
        if (calibrating) {return;}
        console.log("Button down");
        t4s = setTimeout(function() {
          callback();
        },4000);
        setWatch(function(e) {
          clearTimeout(t4s);
          console.log("Button up");
        }, BTN, { repeat: false, edge: 'falling', debounce: 50 });
      }, BTN, { repeat: true, edge: 'rising', debounce: 50 });
    }
    
    
    function calibrate () {
      if (calibrated) {
        console.log('re-calibrating...');
      } else {
        console.log('calibrating...');
      }
      calibrated = false;
      calibrating = true;
      var xyz = Puck.mag();
      var sMax = 0; 
      var sMin = 0;
      count = 0;
      vMin = new Vec3(xyz);
      vMax = new Vec3(xyz);
      Puck.magOn(10);
      Puck.on('mag', function(xyz) {
        if (calibrated) {return;}
        var vMag = new Vec3(xyz);
        vMin = vMin.min(vMag);
        vMax = vMax.max(vMag);
        if ((sMax !=  vMax.mag()) || (sMin != vMin.mag())) {
          sMin = vMin.mag();
          sMax = vMax.mag();
          count++;
          console.log('new min or max: ',count);
          // flash the blue LED when calibrating
          digitalWrite(LED3, count % 2 == 0);
        } else { 
        // flash the green LED when not calibrating
        digitalWrite(LED2, Math.random()>0.5);
        digitalWrite(LED3, false);
        }
      });
      //press the buton to stop calibrating
      setWatch(function(e) {
        Puck.magOn(5);
        calibrating = false;
        console.log("calibarion completed");
        console.log('max: ',vMax);
        console.log('min: ',vMin);
        digitalWrite(LED3, false);
        digitalWrite(LED2, false);
        // calculate the average of vMin and vMax to get the nuteral position
        vAve = new Vec3((vMin.x + vMax.x)/2,(vMin.y + vMax.y)/2,(vMin.z + vMax.z)/2);
        console.log('ave: ',vAve);
        // get the zero position when the end calibrate button was pressed
        vZero = new Vec3(Puck.mag()).sub(vAve);
        console.log('zero:',vZero);
        calibrated = true;
      }, BTN, { repeat: false, edge: 'rising', debounce: 50 });
    }
    
    
    function calibratedMag() {
      Puck.magOn();
      Puck.on('mag', function(xyz) {
        if(calibrating) {return;}
        var vMag = new Vec3(xyz).sub(vAve);
        //console.log('mag: ',vMag);
        h = (Math.atan2(vMag.y, vMag.x) * 180) / Math.PI;
        if (h > 360) {
          h = h - 360; 
        }
        if (h < 0) {
          h = h + 360;
        }
        if (Math.abs(Math.round(oldh) - Math.round(h)) >4) {
          console.log('--------------------');
          if (!calibrated) {console.log('uncalibrated!');}
          console.log('heading: ',Math.round(h));
          console.log('rotate: ', Math.round(oldh - h));
          if (vMag.z > 0) {
            console.log('upwards');
          } else {
            console.log('downwards');
          }
        }
        oldh = h;
      });
    }
    
    
    //calibrate by holding button down for 4 seconds
    b4Seconds(calibrate);
    calibratedMag();
    
    

    The out

    --------------------
    heading:  140
    rotate:  -20
    downwards
    --------------------
    heading:  209
    rotate:  -69
    downwards
    --------------------
    heading:  201
    rotate:  9
    upwards
    --------------------
    heading:  186
    rotate:  13
    upwards
    --------------------
    heading:  161
    rotate:  25
    upwards
    --------------------
    heading:  128
    rotate:  29
    upwards
    --------------------
    heading:  114
    rotate:  14
    upwards
    --------------------
    heading:  103
    rotate:  11
    upwards
    --------------------
    

    put after calibration

  • in Projects
    Avatar for user101436

    Thanks for your test. Your calibration numbers are both similar which is good but are also very different to my numbers.

    You are right I will need to add some sort of sleep mode where the puck reduces or stops its mag sensor scanning to save power.

    next step is to calculate the average of the min and max and use to re-base the sensor.

  • in Projects
    Avatar for user101436

    I have made some progress.

    The following code calculates the min and max value for the mag x,y,z axis using Vec3 module. Can you test and show what you get on your puck. The to do at the end of the code shows my next steps.

    To use hold down the button for 5 seconds then rotate the puck in all directions until you only see green flashes (no blue). Then press the button to end calibration. The min and max values are then logged on your debug screen.

    var Vec3 = require('Vec3');
    var vMin = new Vec3();
    var vMax = new Vec3();
    var calibrating = false;
    var count = 0;
    
    
    // call a function if button is held down for 4 seconds
    function b4Seconds(callback) {
      setWatch(function(e) {
        console.log("Button down");
        t4s = setTimeout(function() {
          callback();
        },4000);
        setWatch(function(e) {
          clearTimeout(t4s);
          console.log("Button up");
        }, BTN, { repeat: false, edge: 'falling', debounce: 50 });
      }, BTN, { repeat: true, edge: 'rising', debounce: 50 });
    }
    
    
    function calibrate () {
      console.log('calibrating...');
      calibrating = true;
      var xyz = Puck.mag();
      var sMax = 0; 
      var sMin = 0;
      count = 0;
      vMin = new Vec3(xyz);
      vMax = new Vec3(xyz);
      Puck.magOn(10);
      Puck.on('mag', function(xyz) {
        var vMag = new Vec3(xyz);
        vMin = vMin.min(vMag);
        vMax = vMax.max(vMag);
        if ((sMax !=  vMax.mag()) || (sMin != vMin.mag())) {
          sMin = vMin.mag();
          sMax = vMax.mag();
          count++;
          console.log('new min or max: ',count);
          // flash the blue LED when calibrating
          digitalWrite(LED3, count % 2 == 0);
        } else { 
        // flash the green LED when not calibrating
        digitalWrite(LED2, Math.random()>0.5);
        digitalWrite(LED3, false);
        }
      });
      //press the buton to stop calibrating
      setWatch(function(e) {
        Puck.magOff();
        calibrating = false;
        console.log("calibarion completed");
        console.log('max: ',vMax);
        console.log('min: ',vMin);
        digitalWrite(LED3, false);
        digitalWrite(LED2, false);
        // TO DO 
        // get the zero position when the end calibrate button was pressed
        // calculate the average of vMin and vMax to get the nuteral position
        // calculate the spread of vMin, vMax to scale future readings
        // use the above to find out if the puck is rotating clockwise or anti
        // use the above to find out if the puck is upside down
        // send BT HID key presses
      }, BTN, { repeat: false, edge: 'rising', debounce: 50 });
    }
    
    //calibrate by holding button down for 4 seconds
    b4Seconds(calibrate);
    
    
    

    | |_ ___ ___ _ ||___ ___
    | |_ -| . | _| | | | | . |
    |
    |_| || |_|||_|_|

         |_| espruino.com
    

    2v03 (c) 2018 G.Williams

    Button down
    calibrating...
    new min or max: 1
    new min or max: 2
    new min or max: 3
    new min or max: 4
    new min or max: 5
    new min or max: 6
    Button up
    new min or max: 7
    new min or max: 8
    new min or max: 9
    new min or max: 10
    new min or max: 11
    new min or max: 12
    new min or max: 13
    new min or max: 14
    new min or max: 15
    new min or max: 16
    new min or max: 17
    new min or max: 18
    new min or max: 19
    new min or max: 20
    new min or max: 21
    new min or max: 22
    new min or max: 23
    new min or max: 24
    new min or max: 25
    new min or max: 26
    new min or max: 27
    new min or max: 28
    new min or max: 29
    new min or max: 30
    new min or max: 31
    new min or max: 32
    new min or max: 33
    new min or max: 34
    new min or max: 35
    new min or max: 36
    new min or max: 37
    new min or max: 38
    Button down
    calibarion completed
    max: Vec3: { "x": 794, "y": 527, "z": 124 }
    min: Vec3: { "x": 104, "y": -179, "z": -857 }
    Button up

  • in Projects
    Avatar for user101436

    Thanks for all the good advice.

    I think I need to lean some vector math!

    my next steps are:

    Use Vec3.js to calibrate my mag sensor and surroundings.

    by adding a hold down the button for 4 seconds to calibrate feature:

    To calibrate rotate the puck in all directions while sampling the mag data at a high rate, save the min and max value of each x,y,z axis.

    Press button to exit calibrate

    Take the average of the min/max for x,y,z and store these as JSON to a file in flash mem.

    Sample at a lower rate and subtract the average x,y,z from each reading

    use vector maths to calculate which way up the puck is and any clockwise or anticlockwise rotation steps.

    Then I need to work out how to send HID command via BT

    I will post an update as soon as I have made progress or if I have more problems. With some debug output this time.

  • in Projects
    Avatar for user101436

    Hi, I have a few puckjs and am looking at how make them into useful household devices. I am currently trying to build a simple to use HID BLE media remote control

    Features

    1. Turn the puck clockwise to raise the volume
    2. Tune the puck anticlockwise to turn down the volume
    3. Tune the puck on its back (black side facing up) then turn to change the channel or track
    4. Click to pause and resume (or Mute /UnMute)


    console.log('Compass heading test');
    Puck.magOn();
    Puck.on('mag', function(c) {
      console.log('Raw mag data: ',c);
      var xGa = c.x * 0.48828125;
      var yGa = c.y * 0.48828125;
      var d = 0;
      if (xGa == 0) {
        if ( yGa <= 0) {
          d = 90;
        } else {
          d = 0;
        }
      } else {
        console.log('Corrected X,YL ',xGa,yGa);
        d = Math.atan(yGa/xGa)*(180/Math.PI);
      }
      if (d > 360) {
        d = d - 360; 
      }
      if (d < 0) {
        d = d + 360;
      }
      console.log('Direction: ', d);
    });
    

    My first attempt is to convert mag x, y, z reading to a compass heading to then take changes to measure left and right rotation. I have completely failed to get this to work any idea what I am doing wrong?

Actions