Documentation

HMC5883L GY-273 3-Axis Magnetometer Compass Module for Arduino, Raspberry Pi & ESP32 | ShillehTek Product Manual
Documentation / HMC5883L GY-273 3-Axis Magnetometer Compass Module for Arduino, Raspberry Pi & ESP32 | ShillehTek Product Manual

HMC5883L GY-273 3-Axis Magnetometer Compass Module for Arduino, Raspberry Pi & ESP32 | ShillehTek Product Manual

manualshillehtek

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

Sensor
HMC5883L 3-axis magnetometer
Interface
I2C @ 0x1E, up to 400 kHz
Field Range
±1.3 to ±8.1 gauss
Resolution
12-bit, down to ~2 mGa
Supply Voltage
3.3V - 5V (onboard regulator)
Pins
VCC, GND, SCL, SDA, DRDY

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.

HMC5883L GY-273 3-axis magnetometer compass module pinout diagram showing VCC, GND, SCL, SDA, and DRDY pins

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
Note: The module's I2C lines are held at 3.3V by its onboard pull-ups, which the Uno reads as valid logic HIGH — this pairing is standard practice and safe in both directions.
Tip: Keep the module a few centimeters away from motors, speakers, and the Arduino's own USB cable. Local magnetic fields are the number one cause of "my compass is wrong" — not the sensor.

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
Tip: Run i2c.scan() (or an I2C scanner sketch) after wiring: 0x1E confirms an HMC5883L, while 0x0D means your board carries the QMC5883L variant — use a QMC library in that case (see FAQ).

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
Tip: After wiring, run sudo i2cdetect -y 1. An entry at 0x1e confirms the HMC5883L; 0x0d indicates the QMC5883L variant.

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_arduino.ino
// 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_esp32.ino
// 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).

hmc5883l_rpi.py
#!/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_pico.py
# 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)

Frequently Asked Questions

My board answers at 0x0D instead of 0x1E. Is it broken?
Not broken — it is a QMC5883L, a licensed variant that many GY-273-style boards ship with. It measures the same thing but uses a different I2C address and register map, so HMC libraries report "not found." Use a QMC library instead (the Arduino "QMC5883LCompass" library is the usual choice) and everything else in this manual — wiring, heading math, calibration — applies unchanged.
How do I calibrate the compass?
Slowly rotate the module through full circles (and figure-8s in the air) while recording the minimum and maximum values on each axis. The midpoint of each axis's min/max is its hard-iron offset — subtract it from every reading before computing the heading. This one-time step corrects for magnetized components near the sensor and typically improves heading accuracy from "vaguely right" to within a couple of degrees.
Why is my heading off by a consistent amount everywhere?
That is magnetic declination: the difference between magnetic north (what the sensor sees) and true north (what maps use). It depends on where you live and can exceed 10 degrees. Look up your local declination and add it to the computed heading — the code examples mark exactly where.
Why does the reading go crazy near my motors or speaker?
Magnetometers measure every field, and a motor or magnet centimeters away is thousands of times stronger than Earth's field. Mount the module as far as practical from motors, speakers, relays, steel screws, and power wiring — on robots, a small mast above the chassis is the classic fix. If nearby steel is unavoidable but fixed in place, calibration absorbs much of its effect.
Do I need the DRDY pin?
Only for interrupt-driven designs. DRDY pulses each time a new measurement lands in the data registers, which lets a microcontroller sleep between samples instead of polling. For a compass updated a few times per second, leaving DRDY unconnected and polling over I2C — as all the examples do — is perfectly fine.
Does tilt affect the heading?
Yes — the simple atan2(Y, X) formula assumes the board is level. Tip the module and the heading skews, which is why phone compasses ask you to hold flat. For a tilt-compensated compass, pair the magnetometer with an accelerometer (MPU6050 or the MPU9250, which includes its own magnetometer) and rotate the readings into the horizontal plane before computing the heading.
Can I power it from 5V?
Yes. The GY-273 breakout includes a 3.3V regulator and holds its I2C lines at 3.3V through onboard pull-ups, so both a 5V Arduino and 3.3V boards connect directly. Only the bare HMC5883L chip is 3.3V-only — the breakout exists precisely to handle that for you.

Related Tutorials