Brújula digital con Arduino. Grupo 15

Explicación del proyecto
Dentro del ámbito del diseño de sistemas empotrados, la integración de sensores capaces de proporcionar una información fiable acerca del entorno es importante para garantizar un buen funcionamiento de dispositivos móviles o inteligentes. Entre ellos, hemos visto la brújula digital como un componente clave para la orientación de un sistema respecto al campo magnético terrestre.
Ese ha sido el motivo por el que nos hemos decantado en elegir este proyecto. El uso de la brújula digital resulta especialmente relevante en distintas aplicaciones hoy en día y en donde el rumbo y la orientación espacial es básica en el rendimiento global de dispositivos como robots, sistemas de navegación o drones, por enumerar algunos casos.
Los objetivos principales del proyecto son:
- Analizar el funcionamiento de una brújula digital.
- Diseño e implementación de un sistema empotrado que muestre el rumbo del dispositivo.
- Integrar el sensor con un microcontrolador y desarrollar el software necesario para lectura y tratamiento.
Reparto de tareas
El reparto de tareas ha sido de manera equitativa conjunta. El tiempo empleado en el proyecto supera las 30 horas debido a los problemas que nos hemos encontrado.
En primer lugar, nos reunimos y hablamos sobre los materiales y herramientas necesarias para construir la brújula digital. Después comenzamos a quedar varios días donde vimos primero la parte hardware y luego todo el software del proyecto. La mayor parte del tiempo de la reunión fue dedicado a la parte hardware. Nos reunimos en nueve ocasiones en una sala de la biblioteca de la URJC.
En líneas generales, el proyecto se ha dividido en 2 tareas:
- Montaje del hardware (montaje del circuito)
- El desarrollo del software (código Arduino)
Materiales y coste
A continuación, se muestran la relación de los materiales principales (figuras 1 a 4) empleados en el proyecto con su foto, nombre y modelo. Posteriormente establecemos un presupuesto con el coste de todos los materiales empleados.




Adicionalmente, hemos necesitado un botón con el fin de cambiar los diferentes datos que aparecen en pantalla. El botón ha sido proporcionado por un alumno del grupo. Además, hemos usado una cubierta de cartón para colocar y ensamblar todos los componentes del circuito.
Presupuesto
A continuación, se muestra en la tabla 1 una recopilación del coste en € de todos los materiales empleados en el proyecto. Aquellos materiales cuyo coste es 0€ han sido proporcionados por la Universidad Rey Juan Carlos mediante un kit laboratorio y otros componentes han sido proporcionados por un alumno de grupo. El total del coste de los materiales ha sido de 16,56€. Los materiales con coste se han comprado por internet.
| Material | Cantidad | Coste total (€) |
| Arduino UNO | 1 | 0 (proporcionado por la universidad) |
| HMC5883L | 4 | 12,21 (3,05€/ud) |
| Pantalla TFT | 1 | 2,93 |
| MPU6500 | 1 | 1,42 |
| Botón | 1 | 0 (proporcionado por un alumno del grupo) |
| Cables | 40 | 0 (proporcionado por la universidad) |
| Carcasa cartón | 1 | 0 (proporcionado por alumno del grupo) |
| Total | 16,56€ |
Herramientas utilizadas
En cuanto a las herramientas utilizadas, aparecen descritas en la tabla 2. Hemos utilizado un soldador para soldar las patas del componente HMC5883L y varias bridas para sujetar los cables del circuito. Por último, una Powerbank para dar corriente de manera rápida y efectiva a la brújula ha sido proporcionada por un alumno del grupo.
| Herramientas | Uso |
| Soldador | Soldar patas HMC5883L |
| Bridas | Sujetar cables del circuito |
| PowerBank | Dar corriente al sistema empotrado |
Implementación del proyecto
Durante los primeros días empezamos a ver cómo se usaba la pantalla TFT, ya que era algo nuevo para nosotros. Seguidamente, nos pusimos con el primer sensor o magnetómetro HMC5883L, aprendiendo cómo se utilizaba, su calibrado y su conexión a la pantalla TFT. Este sensor mide la fuerza del campo magnético de la Tierra.
Tras la conexión del HMC5883L con la pantalla, implementamos en el circuito el acelerómetro MPU6050, sensor que mide la inclinación (pitch y roll) de la brújula. Después, probamos su funcionamiento y recogida de datos. Por último, unificamos los dos sensores para que la brújula digital funcione correctamente. Finalmente ensamblamos el circuito en la carcasa o caja de cartón.
En las figura 5 vemos el circuito de Arduino con la placa y sus componentes. En la figura 6 vemos una imagen del circuito usando el programa Wokwi.com
Y por último vemos en la figura 7 la brújula digital dentro de la cubierta de cartón.



Códigos del proyecto
El código software para Arduino del proyecto es el que aparece a continuación. En él, podemos observar funciones para poder recolectar los datos de los sensores, funciones para dibujar los componentes estáticos de la pantalla, como el círculo de la brújula, puntos cardinales, etc. y una función para dibujar dinámicamente la flecha de la brújula considerando los datos de los sensores.
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <Wire.h>
#include <MPU6500_WE.h>
#include <Adafruit_QMC5883P.h>
//PINES
#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
#define BUTTON_PIN 7
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
#define BLACK ST77XX_BLACK
#define WHITE ST77XX_WHITE
#define RED ST77XX_RED
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 160
#define CENTER_X (SCREEN_WIDTH / 2)
#define CENTER_Y (SCREEN_HEIGHT / 2)
#define RADIUS 51
int displayMode = 0;
int buttonState = HIGH;
int lastButtonState = HIGH;
MPU6500_WE mpu = MPU6500_WE(0x69);
Adafruit_QMC5883P brujula;
float currentHeading = 0;
float previousHeading = -1;
float currentPitch = 0;
float currentRoll = 0;
//FUNCIONES PARA DIBUJAR LOS PTOS CARD.
void drawCardinalPoint(const char* text, int angle, int radius, uint16_t color){
float rad = (angle-90)*PI/180.0;
int textX = CENTER_X + (radius+5)*cos(rad);
int textY = CENTER_Y + (radius+5)*sin(rad);
int16_t x1,y1; uint16_t w,h;
tft.getTextBounds(text,0,0,&x1,&y1,&w,&h);
tft.setCursor(textX-w/2,textY-h/2);
tft.setTextColor(color);
tft.setTextSize(1);
tft.print(text);
}
void drawStaticCompass(){
tft.drawCircle(CENTER_X,CENTER_Y,RADIUS,WHITE);
drawCardinalPoint(«N»,0,RADIUS, RED);
drawCardinalPoint(«NE»,45,RADIUS+3, WHITE);
drawCardinalPoint(«E»,90,RADIUS+2, WHITE);
drawCardinalPoint(«SE»,135,RADIUS+5, WHITE);
drawCardinalPoint(«S»,180,RADIUS+2, WHITE);
drawCardinalPoint(«SO»,225,RADIUS+4, WHITE);
drawCardinalPoint(«O»,270,RADIUS, WHITE);
drawCardinalPoint(«NO»,315,RADIUS+2, WHITE);
}
//FLECHA y ACTUALIZACION
void drawArrow(float heading, int length, uint16_t color){
float rad = (heading-90)*PI/180.0;
int x2 = CENTER_X + length*cos(rad);
int y2 = CENTER_Y + length*sin(rad);
tft.drawLine(CENTER_X,CENTER_Y,x2,y2,color);
int offset_x = round(sin(rad));
int offset_y = round(cos(rad));
tft.drawLine(CENTER_X+offset_x,CENTER_Y-offset_y,x2+offset_x,y2-offset_y,color);
tft.drawLine(CENTER_X-offset_x,CENTER_Y+offset_y,x2-offset_x,y2+offset_y,color);
tft.fillCircle(CENTER_X,CENTER_Y,2,WHITE);
}
void updateCompassArrow(float heading){
if(abs(heading-previousHeading)>1 || previousHeading==-1){
if(previousHeading!=-1){
drawArrow(previousHeading,RADIUS-5,BLACK);
}
drawArrow(heading,RADIUS-5,RED);
previousHeading = heading;
}
}
//BOTON
void handleButton(){
buttonState = digitalRead(BUTTON_PIN);
if(lastButtonState == HIGH && buttonState == LOW){
displayMode = 1 – displayMode; // Cambia modo solo una vez por pulsación
}
lastButtonState = buttonState;
}
//
void updateDisplayData(float heading, float pitch, float roll, int mode){
tft.fillRect(0,0,SCREEN_WIDTH,20,BLACK);
tft.setTextColor(WHITE);
tft.setTextSize(1);
if(mode==0){
tft.setCursor(5,5);
tft.print(«RUMBO: «);
tft.print(heading,0);
tft.write((char)248);
}else{
tft.setCursor(5,5);
tft.print(«PITCH:»);
tft.print(pitch,0);
tft.write((char)248);
tft.setCursor(65,5);
tft.print(«ROLL:»);
tft.print(roll,0);
tft.write((char)248);
}
}
//MPU
void readMPUAngles(){
xyzFloat acc = mpu.getGValues();
currentRoll = atan2(acc.y, acc.z);
float acc_sq = sqrt(acc.y*acc.y + acc.z*acc.z);
currentPitch = atan2(-acc.x, acc_sq);
}
// CALCULO RUMBO
float getMagneticHeading(){
float mx, my, mz;
if(brujula.getGaussField(&mx,&my,&mz)){
float sinPitch = sin(currentPitch);
float cosPitch = cos(currentPitch);
float sinRoll = sin(currentRoll);
float cosRoll = cos(currentRoll);
float Xh = mx * cosPitch + mz * sinPitch;
float Yh = mx * sinRoll * sinPitch + my * cosRoll – mz * sinRoll * cosPitch;
float heading = atan2(Xh, -Yh) * 180.0/PI;
if(heading < 0) heading += 360;
return heading;
}
return previousHeading;
}
//SET UP Y LOOPEO
void setup(){
pinMode(BUTTON_PIN, INPUT_PULLUP);
tft.initR(INITR_BLACKTAB);
tft.setRotation(0);
tft.fillScreen(BLACK);
Wire.begin();
if(!brujula.begin()){
tft.setTextColor(RED);
tft.setCursor(0,5);
tft.print(«Error QMC5883P»);
while(1) delay(100);
}
brujula.setMode(QMC5883P_MODE_CONTINUOUS);
brujula.setODR(QMC5883P_ODR_50HZ);
brujula.setOSR(QMC5883P_OSR_4);
brujula.setDSR(QMC5883P_DSR_2);
brujula.setRange(QMC5883P_RANGE_8G);
brujula.setSetResetMode(QMC5883P_SETRESET_ON);
if(!mpu.init()){
tft.setTextColor(RED);
tft.setCursor(0,15);
tft.print(«Error MPU6500»);
while(1) delay(100);
}
drawStaticCompass();
}
void loop(){
handleButton();
readMPUAngles();
// La flecha de la brújula siempre se actualiza
currentHeading = getMagneticHeading();
updateCompassArrow(currentHeading);
// Datos numéricos según el modo
updateDisplayData(currentHeading,currentPitch*180/PI,currentRoll*180/PI,displayMode);
delay(50);
}
Casos de uso
Algunos de los casos de uso de una brújula digital en sistemas empotrados son los siguientes.
- PANTALLA: Muestra la brújula con sus puntos cardinales y los grados.
La pantalla del sistema se encarga de mostrar de forma visual la brújula digital, incluyendo los puntos cardinales y los grados correspondientes al rumbo actual. Gracias a esta visualización, el usuario puede conocer en todo momento la orientación del dispositivo de manera clara e intuitiva.
- BOTÓN: Cambia de modo de muestreo de rumbo con el pitch y roll.
El sistema también incorpora un botón que permite cambiar el modo de muestreo del rumbo, teniendo en cuenta los valores de pitch y roll. Esta funcionalidad es importante, ya que permite adaptar la medición de la orientación cuando el dispositivo se encuentra inclinado, mejorando la precisión de los datos mostrados.
- SENSOR HMC5883L: Mide los campos magnéticos en 3 ejes y determina el norte.
El sensor HMC5883L, mide los campos magnéticos en los tres ejes espaciales y permite determinar la dirección del norte magnético. Este sensor es fundamental para el funcionamiento de la brújula digital, ya que proporciona los datos básicos de orientación.
- SENSOR MPU6500: Mide la inclinación y gracias a este compensa los datos para que siga mostrando el norte.
El sensor MPU6500, es el encargado de medir la inclinación del dispositivo. Gracias a los datos de este sensor, es posible compensar las mediciones del campo magnético, asegurando que la brújula continúe mostrando correctamente el norte incluso cuando el sistema no se encuentra en posición horizontal
Problemas y soluciones encontradas
Para elaborar una brújula compacta con un diseño reducido y limpio nos hemos encontrado varios problemas.
-El primero de ellos fue la sensibilidad del sensor HMC5883L para detectar campos magnéticos, al ser el campo terrestre muy débil, cualquier interferencia (componentes electrónicos, imanes, otros dispositivos) cambiaba el funcionamiento de la brújula. Cubrimos la brújula con una caja de cartón para evitar interferencias electromagnéticas producidas por la corriente eléctrica de los cables de conexión.
-Pantalla sin brújula centrada. Se ajustó con funciones matemáticas (aparece en el código en las funciones de dibujo).
-El output del sensor HMC5883L no mostraba datos, el problema fue un sensor defectuoso, por lo que tuvimos que comprar varios sensores más y comprobamos su funcionamiento.
-Además, uno de los problemas principales al que nos hemos enfrentado es que, con cualquier mínimo movimiento en los cables y conexiones, la brújula dejaba de funcionar. Esto nos pasaba todas las veces que nos reuníamos. Lo hemos intentado solucionar añadiendo varias bridas a las conexiones del circuito.
Conclusión
El desarrollo de la brújula digital con Arduino ha permitido comprender de manera práctica la integración de sensores en sistemas empotrados, combinando hardware y software para obtener datos de orientación (rumbo, pitch y roll) de forma fiable. El proyecto ha servido para unir conceptos teóricos de electrónica, señales y sistemas en tiempo real.
Este proyecto demuestra que es posible implementar soluciones funcionales con un coste reducido (16,56 €), lo que refuerza la viabilidad económica y la utilidad de este tipo de dispositivos para aplicaciones en robótica, navegación y domótica. A pesar de los avances, se identificaron limitaciones y problemas importantes: alta sensibilidad del magnetómetro a interferencias, fragilidad en las conexiones de los sensores y necesidad de calibración precisa. Estas dificultades resaltan la importancia de un diseño robusto y técnicas de compensación en entornos y aplicaciones reales.
En definitiva, el proyecto no solo cumplió los objetivos planteados, sino que también nos proporcionó un aprendizaje (a base de errores cometidos y soluciones buscadas) sobre la interacción entre sensores y programación.