Crear un detector de metales con un magnetómetro o brújula digital.

Vamos a usar un magnetómetro o brújula digital como detector de metales. Para ello vamos a convertir un problema en una ventaja. Cualquier metal magnético cerca del magnetómetro mete ruido en las lecturas, mucho ruido tanto que puede imposibilitar leer los resultados. Usaremos ese ruido para detectar que estamos cerca de un metal magnético o un imán.

En mi caso usaré el magnetómetro del Arduino Nano 33 BLE Sense (ya vimos como leerlo) aunque la ideas sirve cualquier otro magnetómetro, habrá que adaptar el código y los valores empleados.

Realmente es muy sencillo crear un detector de metales. Basta con detectar el ruido y es un ruido tan grande que deja ridículas las lecturas del campo magnético terrestre. Para ello mediremos la intensidad del campo magnético. Lo hacemos elevando al cuadrado el valor de cada eje de magnetómetro, sumándolas y calculando su raíz cuadrada. El del Arduino Nano Sense tiene tres ejes por lo que el calculo lo haremos con el siguiente código.

 IMU.readMagneticField(x, y, z);
 float field = sqrt((x*x) + (y*y) + (z*z))

Ese valor lo podemos comparar con distintos umbrales calculados a base de prueba y error para saber lo cerca que estamos de un metal. En este caso usaremos cuatro niveles, cada uno asociado a un color del LED RGB. Desde «no se detecta nada» a «estas encima de un metal». Lo colores de menos a más son: blanco, verde, amarillo, rojo.

Para evitar verse influido por las condiciones del entorno (por ejemplo que haya metal cerca que hace que siempre se active nuestro detector) puede ser necesario calcular un «offset inicial» cuando se activa el microcontrolador. Este offset es una lectura inicial (la situaremos en la función setup) que se usará para ajustar el valor del campo en el resto de las lecturas. Para decidir si se realiza esta lectura o no se se realiza a través de una constante CALCULATE_OFFSET

if(CALCULATE_OFFSET){
  while(!IMU.magneticFieldAvailable()){    
  }
  IMU.readMagneticField(x, y, z);
  offset = sqrt((x*x) + (y*y) + (z*z));
}

Para corregir el valor del campo respecto de este offset basta con restarlo:

float field = sqrt((x*x) + (y*y) + (z*z))-offset; 

Vamos a juntar todo esto en un ejemplo:

#include <Arduino_LSM9DS1.h>

const bool CALCULATE_OFFSET = true;
float offset = 50; //valor por defecto
float x, y, z;

void setup() {
  Serial.begin(9600);  

  if (!IMU.begin()) {
    Serial.println("Error al inicializar IMU!");
    while (1);
  }
  if(CALCULATE_OFFSET){
    while(!IMU.magneticFieldAvailable()){    
    }
    IMU.readMagneticField(x, y, z);
    offset = sqrt((x*x) + (y*y) + (z*z));
  }

  // activar todos los pins del led RGB
  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);

}

float oldX, oldY, oldZ;

void loop() {

  float difX, difY, difZ;

  if (IMU.magneticFieldAvailable()) {
    IMU.readMagneticField(x, y, z);
    float field = sqrt((x*x) + (y*y) + (z*z))-offset; 
    if(field > 450){
      Serial.print(field);
      Serial.println(" metal");
      //rojo
      digitalWrite(LEDR, LOW);
      digitalWrite(LEDG, HIGH);
      digitalWrite(LEDB, HIGH);
    } else if(field > 150){
      Serial.print(field);
      Serial.println(" metal");
      //amarillo
      digitalWrite(LEDR, LOW);
      digitalWrite(LEDG, LOW);
      digitalWrite(LEDB, HIGH);
    } else if(field > 20){
      Serial.print(field);
      Serial.println(" metal");
      //verde
      digitalWrite(LEDR, HIGH);
      digitalWrite(LEDG, LOW);
      digitalWrite(LEDB, HIGH);
    } else {
      Serial.println(field);
      digitalWrite(LEDR, HIGH);
      digitalWrite(LEDG, HIGH);
      digitalWrite(LEDB, HIGH);
    }    
  }
}

Un ultimo detalle, si usas una placa de Arduino como detector de metales, cuida con los pines. Si entran en contacto con el metal pueden producirse un cortocircuito.