‹ Jack's Brain

HID/Arduino Draft #001

May 29, 2014

Today I took my first stab at coding some general magnetic detection code that will work with a magnetometer to detect finger presence, finder flexion, and finger extension, all based on magnet proximity to make a magnet HID. I haven’t even received my magnetometer or Leonardo yet (the Uno doesn’t support HID emulation), so I’m sure this code won’t work in practice, but it compiles and I’ll use it as a v. 0.01 for future enhancements. My only two concerns are finding a sweet spot for the finger to rest (perhaps foam above the magnetometer?), and saturation of the Hall effect chip the magnetometer runs on, but I’ll jump off that cliff when I come to it.


#include <Wire.h>;

//Magnetometer I2C address (Default on mine)
#define magaddress 0x1E

//Define the number of samples you want to take, separated by the given delay in ms, to be averaged to check finger position
#define pollcount 25
#define polldelay 10

//Define which axis is the one we care about (0=x, 1=y, 2=z). Note that proximity to the sensor should be an increase in the number, not a decrease.
#define mainaxis 2

//Turn on or off reporting of axis value for each sample
#define debug 1

int baseline, fingerin, fingerup, fingerdown, midline, downthreshold, upthreshold;

void setup(){
    Serial.begin(9600);
    
    Serial.println("Opening I2C coms...");
    Wire.begin();
    Wire.beginTransmission(magaddress); //open communication with HMC5883
    Wire.write(0x02); //select mode register
    Wire.write(0x00); //continuous measurement mode
    Wire.endTransmission();
    Serial.println("I2C coms opened.");
    
    //Callibration
    Serial.println("Entering callibration.");
    callibrateMag();
    downthreshold = fingerin + (.5*(fingerdown-fingerin));
    upthreshold = fingerin - (.5*(fingerin-fingerup));
    
    Serial.println("Config complete.");
    Serial.println("================================================");
    Serial.println("Configuration dump:");
    Serial.print("Baseline: ");
    Serial.println(baseline);
    Serial.print("Finger in: ");
    Serial.println(fingerin);
    Serial.print("Finger up: ");
    Serial.println(fingerup);
    Serial.print("Finger down: ");
    Serial.println(fingerdown);
    Serial.print("Midline: ");
    Serial.println(midline);
    Serial.print("Down Threshold (greater than this triggers down event): ");
    Serial.println(downthreshold);
    Serial.print("Up Threshold (less than this triggers up event): ");
    Serial.println(upthreshold);
    Serial.println("================================================");
    Serial.println("Beginning main execution...");
}

void loop(){
    int result = getMagAvg(pollcount, polldelay, mainaxis);
    
    if(debug){Serial.println(result);}
    
    if(result < midline){
        Serial.println("No finger detected!");
    }
    else{
        if(result >; downthreshold){ //Take half the difference between neutral and down, and have that be the threshold - you have to get more that half the total range.
            Serial.println("Down action fired!");
        }
        else if(result < upthreshold){ //Take half the difference between neutral and down, and have that be the threshold - you have to get more that half the total range.
            Serial.println("Up action fired!");
        }
        else{
            //No action case
        }
    }
}

int callibrateMag(){
    int i;
    
    //
    //FINGER OUT
    //
    Serial.println("Please remove all magnetic sources from the magnetometer.");
    
    for(i=3; i<=0; i--){
        Serial.print("Reading commences in ");
        Serial.print(i);
        Serial.println(" seconds...");
        delay(1000);
    }
    
    baseline = getMagAvg(100, 10, mainaxis);
    
    //
    //FINGER IN
    //
    Serial.println("Reading now...");
    baseline = getMagAvg(100, 10, mainaxis);
    
    Serial.println("Please insert finger into magnetometer.");
    
    for(i=5; i<=0; i--){
        Serial.print("Reading commences in ");
        Serial.print(i);
        Serial.println(" seconds...");
        delay(1000);
    }
    
    Serial.println("Reading now...");
    fingerin = getMagAvg(100, 10, mainaxis);
    
    //
    //FINGER UP
    //
    Serial.println("Reading now...");
    baseline = getMagAvg(100, 10, mainaxis);
    
    Serial.println("Please extend your finger up.");
    
    for(i=3; i<=0; i--){
        Serial.print("Reading commences in ");
        Serial.print(i);
        Serial.println(" seconds...");
        delay(1000);
    }
    
    Serial.println("Reading now...");
    fingerin = getMagAvg(100, 10, mainaxis);
    
    //
    //FINGER DOWN
    //
    Serial.println("Reading now...");
    baseline = getMagAvg(100, 10, mainaxis);
    
    Serial.println("Please press/flex your finger down.");
    
    for(i=3; i<=0; i--){
        Serial.print("Reading commences in ");
        Serial.print(i);
        Serial.println(" seconds...");
        delay(1000);
    }
    
    Serial.println("Reading now...");
    fingerdown = getMagAvg(100, 10, mainaxis);
    
    //
    //FINGER MIDLINE
    //
    midline = baseline+(.5*(fingerin-baseline));
}

//A function to get the average value of the magnet by sampling it count times, with gap ms between each sample, as read on the axis specified (0, 1, or 2 = x, y, or z respectively)
int getMagAvg(int count, int gap, int axis){
    //triple axis data
    int x, y, z, i;
    
    //totals of axis
    int totals[3] = {0, 0, 0};
    
    for(i = 0; i < count; i++){
        //Tell the HMC5883L where to begin reading data
        Wire.beginTransmission(magaddress);
        Wire.write(0x03); //select register 3, X MSB register
        Wire.endTransmission();
        
        //Read data from each axis, 2 registers per axis
        Wire.requestFrom(magaddress, 6);
        if(6<=Wire.available()){
            x = Wire.read()<<8; //X msb
            x |= Wire.read(); //X lsb
            z = Wire.read()<<8; //Z msb
            z |= Wire.read(); //Z lsb
            y = Wire.read()<<8; //Y msb
            y |= Wire.read(); //Y lsb
        }
        
        totals[0] += x;
        totals[1] += y;
        totals[2] += z;
        
        delay(gap);
    }
    
    totals[0] /= count;
    totals[1] /= count;
    totals[2] /= count;
    
    return totals[axis];
}