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];
}