Detecting movement

Posted on
  • A few people have asked about having an accelerometer so they can detect movement - but it's not the only way.

    For a lot of things you can still use the magnetometer. The magnetic field changes a lot, not just with angle, but with what other items the Puck.js is near. It's almost impossible to move Puck.js without changing the magnetometer's reading at least a little.

    For instance try this code:

    var avr = Puck.mag();
    var magDiff;
    Puck.on('mag', function(xyz) {
      // work out difference in field
      var dx = xyz.x-avr.x;
      var dy = xyz.y-avr.y;
      var dz = xyz.z-avr.z;
      magDiff = Math.sqrt(dx*dx+dy*dy+dz*dz);
      // update average
      avr.x += dx/2;
      avr.y += dy/2;
      avr.z += dz/2;  
      LED.write(magDiff > 50);
    });
    Puck.magOn();
    

    It looks for changes in the magnetic field about once a second, and will light the red LED if it has changed more than a little. After a few seconds of no movement the LED will turn off.

    It's easy, low power, and seems to work pretty well.

  • I am trying to use this, but every now and then the magnet readings keep moving. Especially when I have a magnet close sometimes it doesn't come to a stop. The difference keeps reading at about 200-700.

    Anything you know I could do about this?

  • You could try just increasing the threshold value > 50 in the above code? Or how close is the magnet nearby? You could make the threshold value dependent on the strength of the magnetic field - since the noise in the reading may well be proportionate to the size of the field.

    Otherwise if the readings keep varying randomly you could try keeping a short term average of the readings and comparing that to work around noise? This isn't tested, but something like it should work:

    var avr = Puck.mag(); // long average
    var savr = Puck.mag(); // short average
    var magDiff;
    Puck.on('mag', function(xyz) {
      // update short average
      var dx = xyz.x-savr.x;
      var dy = xyz.y-savr.y;
      var dz = xyz.z-savr.z;
      savr.x += dx/2;
      savr.y += dy/2;
      savr.z += dz/2;  
      // work out difference in field
      var dx = savr.x-avr.x;
      var dy = savr.y-avr.y;
      var dz = savr.z-avr.z;
      magDiff = Math.sqrt(dx*dx+dy*dy+dz*dz);
      // update average
      var dx = xyz.x-avr.x;
      var dy = xyz.y-avr.y;
      var dz = xyz.z-avr.z;
      avr.x += dx/8;
      avr.y += dy/8;
      avr.z += dz/8;  
      LED.write(magDiff > 50); // this value might need lowering
    });
    Puck.magOn();
    

    You could also do a median filter, which is relatively easy to do with the built-in array.sort.

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

Detecting movement

Posted by Avatar for Gordon @Gordon

Actions