Overview
The GY-273 is a compact digital compass: a Honeywell HMC5883L 3-axis magnetometer on a breakout board that measures magnetic field strength along X, Y, and Z and hands you the readings over plain I2C at address 0x1E. Point the board's X axis where your robot is heading, do one atan2() on the X and Y readings, and you have a compass heading in degrees — the classic recipe behind rovers that drive straight, drones that hold orientation, and weather stations that know which way the vane points.
The sensor resolves fields down to a couple of milligauss across a configurable ±1.3 to ±8.1 gauss range (Earth's field is roughly 0.25-0.65 gauss, so the default ±1.3 Ga range is right for compassing), with a 12-bit ADC and up to 75 Hz continuous output. The breakout adds a 3.3V regulator and I2C pull-ups, so the module accepts 3.3V or 5V power and wires directly to Arduino, ESP32, Raspberry Pi, and Pico with no level shifting. A DRDY pin flags when fresh data is ready, though most projects simply poll.
Two practical realities are worth knowing up front. First, magnetometers measure every magnetic field, not just Earth's — nearby speakers, motors, screws, and USB cables all bend the reading, so calibration and sensible mounting matter more than raw specs. Second, many boards sold as GY-273 actually carry the QMC5883L, a licensed variant with a different I2C address (0x0D) and register map — an I2C scan tells you which chip you have in ten seconds, and the FAQ below covers both cases.
At a Glance
Specifications
| Parameter | Value |
| Sensor IC | Honeywell HMC5883L (3-axis magnetoresistive) |
| Measurement Range | ±1.3 to ±8.1 gauss (8 selectable gains, default ±1.3 Ga) |
| Resolution | 12-bit ADC, ~0.92 mGa/LSB at default gain |
| Heading Accuracy | 1° - 2° achievable with calibration |
| Output Rate | 0.75 - 75 Hz continuous (160 Hz single-shot) |
| Interface | I2C, address 0x1E (fixed), up to 400 kHz |
| DRDY Pin | Data-ready interrupt output (optional) |
| Module Supply | 3.3V - 5V (onboard 3.3V regulator + I2C pull-ups) |
| Current Draw | ~100 µA idle, ~640 µA measuring |
| Board Size | ~14 x 13 mm with axis markings on silkscreen |
| Common Clone | QMC5883L variant answers at 0x0D with a different register map |
Pinout Diagram
Four pins do the work: VCC (3.3V or 5V), GND, and the I2C pair SCL and SDA. DRDY is optional — it pulses when a new measurement is ready, useful for interrupt-driven sampling but safely left unconnected otherwise. The silkscreen axis arrows show which way X, Y, and Z point; when using the module as a compass, mount it flat and note which axis faces your "forward" direction, because the heading math is built on exactly that.
Wiring Guide
Arduino Wiring
The onboard regulator and pull-ups make this a four-wire hookup on the Uno's standard I2C pins.
| GY-273 Pin | Arduino Pin | Details |
|---|---|---|
| VCC | 5V | Onboard regulator handles it |
| GND | GND | |
| SCL | A5 (SCL) | |
| SDA | A4 (SDA) | |
| DRDY | Not connected | Optional data-ready output |
ESP32 Wiring
Direct connection on the ESP32's default I2C pins.
| GY-273 Pin | ESP32 Pin | Details |
|---|---|---|
| VCC | 3V3 | |
| GND | GND | |
| SCL | GPIO 22 | Default I2C SCL |
| SDA | GPIO 21 | Default I2C SDA |
| DRDY | Not connected | Optional |
Raspberry Pi Wiring
Standard I2C1 hookup. Enable I2C first with sudo raspi-config (Interface Options > I2C).
| GY-273 Pin | Raspberry Pi Pin | Details |
|---|---|---|
| VCC | Pin 1 (3.3V) | |
| GND | Pin 6 (GND) | |
| SCL | Pin 5 (GPIO 3, SCL1) | |
| SDA | Pin 3 (GPIO 2, SDA1) | |
| DRDY | Not connected | Optional |
Raspberry Pi Pico Wiring
This table uses I2C0 on GP0/GP1 to match the MicroPython example.
| GY-273 Pin | Pico Pin | Details |
|---|---|---|
| VCC | 3V3(OUT) (pin 36) | |
| GND | GND (pin 38) | |
| SCL | GP1 (pin 2) | I2C0 SCL |
| SDA | GP0 (pin 1) | I2C0 SDA |
| DRDY | Not connected | Optional |
Code Examples
The Arduino and ESP32 examples use the Adafruit HMC5883 Unified library; the Raspberry Pi and Pico examples talk to the registers directly, so nothing needs installing on those platforms. Every example prints raw axis values plus a compass heading. For a true bearing, add your local magnetic declination to the heading (look it up for your city — it ranges from -15° to +15° across the US).
Arduino
Install "Adafruit HMC5883 Unified" (plus the Adafruit Unified Sensor dependency) from the Library Manager.
// HMC5883L (GY-273) Compass - Arduino Example
// SDA -> A4, SCL -> A5, VCC -> 5V, GND -> GND
// Library: "Adafruit HMC5883 Unified" (+ Adafruit Unified Sensor)
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_HMC5883_U.h>
Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345);
void setup() {
Serial.begin(9600);
if (!mag.begin()) {
Serial.println("HMC5883L not found at 0x1E - check wiring.");
Serial.println("(If an I2C scan shows 0x0D, you have a QMC5883L.)");
while (1);
}
Serial.println("Compass ready - rotate the board slowly.");
}
void loop() {
sensors_event_t event;
mag.getEvent(&event);
// Heading from the horizontal components (board held flat)
float heading = atan2(event.magnetic.y, event.magnetic.x);
// Add your local magnetic declination here (radians)
// Example: +3 degrees = 0.052 rad
// heading += 0.052;
if (heading < 0) heading += 2 * PI;
float degrees = heading * 180 / PI;
Serial.print("X: ");
Serial.print(event.magnetic.x);
Serial.print(" uT Y: ");
Serial.print(event.magnetic.y);
Serial.print(" uT | Heading: ");
Serial.print(degrees, 1);
Serial.println(" deg");
delay(500);
}
ESP32 (Arduino IDE)
// HMC5883L (GY-273) Compass - ESP32 Example
// SDA -> GPIO 21, SCL -> GPIO 22, VCC -> 3V3, GND -> GND
// Library: "Adafruit HMC5883 Unified" (+ Adafruit Unified Sensor)
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_HMC5883_U.h>
Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345);
void setup() {
Serial.begin(115200);
Wire.begin(21, 22); // SDA, SCL
if (!mag.begin()) {
Serial.println("HMC5883L not found at 0x1E - check wiring.");
while (1) delay(10);
}
Serial.println("Compass ready - rotate the board slowly.");
}
void loop() {
sensors_event_t event;
mag.getEvent(&event);
float heading = atan2(event.magnetic.y, event.magnetic.x);
if (heading < 0) heading += 2 * PI;
Serial.printf("X: %.1f uT Y: %.1f uT | Heading: %.1f deg\n",
event.magnetic.x, event.magnetic.y,
heading * 180 / PI);
delay(500);
}
Raspberry Pi (Python)
No driver package needed — this reads the registers directly with smbus2 (pip3 install smbus2).
#!/usr/bin/env python3
# HMC5883L (GY-273) Compass - Raspberry Pi Example
# SDA -> GPIO 2 (pin 3), SCL -> GPIO 3 (pin 5), VCC -> 3.3V (pin 1)
# Setup: enable I2C in raspi-config, then: pip3 install smbus2
import math
import time
from smbus2 import SMBus
ADDR = 0x1E # HMC5883L (0x0D would be a QMC5883L - different chip!)
bus = SMBus(1)
# Config A: 8 samples averaged, 15 Hz output -> 0x70
bus.write_byte_data(ADDR, 0x00, 0x70)
# Config B: gain +/-1.3 gauss (default) -> 0x20
bus.write_byte_data(ADDR, 0x01, 0x20)
# Mode: continuous measurement -> 0x00
bus.write_byte_data(ADDR, 0x02, 0x00)
time.sleep(0.1)
def read_axes():
# Data registers start at 0x03, order is X, Z, Y (big endian)
data = bus.read_i2c_block_data(ADDR, 0x03, 6)
def s16(hi, lo):
v = (hi << 8) | lo
return v - 65536 if v > 32767 else v
x = s16(data[0], data[1])
z = s16(data[2], data[3])
y = s16(data[4], data[5])
return x, y, z
print("Compass ready - rotate the board slowly (Ctrl+C to stop)")
try:
while True:
x, y, z = read_axes()
heading = math.atan2(y, x)
# Add your local magnetic declination here (radians)
if heading < 0:
heading += 2 * math.pi
print("X: {:6d} Y: {:6d} Z: {:6d} | Heading: {:5.1f} deg".format(
x, y, z, math.degrees(heading)))
time.sleep(0.5)
except KeyboardInterrupt:
print("Stopped by user")
finally:
bus.close()
Raspberry Pi Pico (MicroPython)
# HMC5883L (GY-273) Compass - Pico MicroPython Example
# SDA -> GP0, SCL -> GP1 (I2C0), VCC -> 3V3(OUT), GND -> GND
# No library needed - reads the registers directly.
from machine import Pin, I2C
import math
import time
ADDR = 0x1E # HMC5883L (0x0D would be a QMC5883L - different chip!)
i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
if ADDR not in i2c.scan():
raise RuntimeError("HMC5883L not found at 0x1E - check wiring "
"(0x0D in the scan means QMC5883L)")
# Config A: 8 samples averaged, 15 Hz | Config B: +/-1.3 Ga | Mode: continuous
i2c.writeto_mem(ADDR, 0x00, b'\x70')
i2c.writeto_mem(ADDR, 0x01, b'\x20')
i2c.writeto_mem(ADDR, 0x02, b'\x00')
time.sleep_ms(100)
def s16(hi, lo):
v = (hi << 8) | lo
return v - 65536 if v > 32767 else v
print("Compass ready - rotate the board slowly")
while True:
# Data registers start at 0x03, order is X, Z, Y (big endian)
d = i2c.readfrom_mem(ADDR, 0x03, 6)
x = s16(d[0], d[1])
z = s16(d[2], d[3])
y = s16(d[4], d[5])
heading = math.atan2(y, x)
if heading < 0:
heading += 2 * math.pi
print("X:", x, " Y:", y, " Z:", z,
" | Heading: {:.1f} deg".format(math.degrees(heading)))
time.sleep(0.5)