A minimalistic MicroPython driver for the AS5600 12-bit magnetic rotary position sensor, designed for low-latency angle reading for my test bench composed of sensors, Raspberry Pi Pico 2, wires and other stuff.
- Low-latency design - Uses RAW_ANGLE register (~486 μs total latency)
- 12-bit angular position (4096 steps per revolution, ~0.088° resolution)
- Sensor health monitoring (magnet detection, field strength)
- Diagnostic telemetry with grep-friendly output
- PID-friendly angle wrapping across 0/360° boundary
See decision/LATENCY_PRECISION_TRADEOFF.md for design rationale.
- AS5600 magnetic encoder module (e.g., Adafruit)
- 3.3V operation (library constraint - 5V mode not supported)
- Diametrically magnetized magnet positioned above sensor
- I2C connection (default address: 0x36)
Copy driver/as5600.py to your MicroPython device.
from machine import I2C, Pin
from as5600 import AS5600, to_degrees
# Initialize I2C and encoder
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400_000)
encoder = AS5600(i2c)
# Read raw angle (0-4095 steps)
raw = encoder.read_raw_angle()
# Convert to degrees relative to mechanical center
AXIS_CENTER = 422 # Calibrate for your setup
angle_deg = to_degrees(raw, AXIS_CENTER)
# Check if magnet is detected (via diagnostic output)
diag = encoder.diagnose()
print(diag)
# Generate diagnostic telemetry
print(encoder.diagnose(axis_center=AXIS_CENTER))Initialize the driver.
i2c: MicroPython I2C instanceaddress: I2C address (default 0x36)
Returns raw angle in steps (0-4095).
Returns grep-friendly diagnostic telemetry string. See Diagnostic Output section.
Converts raw steps to degrees relative to axis center, with proper 0/360° wrap handling.
Normalizes angular error to [-2048, +2047] range for PID control loops.
Reads the CONF register (0x07-0x08) and returns the 16-bit configuration value.
Writes a 16-bit value to the CONF register. Changes take effect immediately but are not persistent across power cycles.
Configures the sensor for low-latency flight control applications with optimal settings:
- SF=11: Fastest filter (0.286ms settling)
- FTH=001: Fast filter threshold at 6 LSB
- PM=00: Always-on power mode
See decision/LATENCY_PRECISION_TRADEOFF.md for detailed rationale.
The diagnose() method returns a single-line, pipe-delimited string for easy parsing:
AS5600|TS=123456|MAGNET=true|WEAK=false|STRONG=false|AGC=85|AGC_PCT=66|MAG=1847|RAW=422|DEG=0.0
| Field | Description |
|---|---|
| TS | Timestamp in milliseconds since boot |
| MAGNET | Magnet detected (true/false) |
| WEAK | Magnet too weak flag |
| STRONG | Magnet too strong flag |
| AGC | Raw AGC value (0-128) |
| AGC_PCT | AGC as percentage (0-100) |
| MAG | CORDIC magnitude value |
| RAW | Raw angle in steps (0-4095) |
| DEG | Relative angle in degrees (if axis_center provided) |
# Filter for AGC readings
cat telemetry.log | grep "AS5600" | grep "AGC_PCT"
# Extract specific field
cat telemetry.log | grep "AS5600" | cut -d'|' -f6The AGC (Automatic Gain Control) value indicates magnetic field strength and is key for optimal sensor performance.
| AGC % | Status | Meaning | Recommended Action |
|---|---|---|---|
| 0-20% | low |
Magnet too strong | Increase air gap between magnet and sensor |
| 20-40% | acceptable | Strong but usable | Consider increasing gap slightly |
| 40-60% | optimal |
Ideal range | Best noise performance |
| 60-80% | acceptable | Weak but usable | Consider reducing gap slightly |
| 80-100% | high |
Magnet too weak | Reduce air gap or use stronger magnet |
- Position magnet above sensor (typical air gap: 0.5-3mm)
- Run diagnostic:
print(encoder.diagnose()) - Check
AGC_PCTvalue - Adjust air gap until AGC is in 40-60% range
- Verify
MAGNET=trueandWEAK=falseandSTRONG=false
Test date: 2026-01-31
Test script: tests/test_noise_levels.py
Samples: 200 per SF setting, magnet stationary
| SF | Settling Time | Expected RMS | Measured RMS | Measured P-P |
|---|---|---|---|---|
| 0 | 2.2 ms | 0.015° | 0.000° | 0.000° |
| 1 | 1.1 ms | 0.021° | 0.000° | 0.000° |
| 2 | 0.55 ms | 0.030° | 0.011° | 0.088° |
| 3 | 0.286 ms | 0.043° | 0.006° | 0.088° |
Observations:
- All measured values are better than datasheet specifications
- SF=0 and SF=1 show zero noise (below 12-bit resolution of 0.088°/step)
- SF=3 (low-latency config) shows only 1-step occasional jitter
- SF=3 is the minimum filtering available (2x averaging); filters cannot be fully disabled
Conclusion: The low-latency configuration (SF=3) provides excellent noise performance in practice, validating its use for flight control applications.
- Verify magnet is positioned above sensor
- Check magnet is diametrically magnetized (not axially)
- Reduce air gap
- Verify I2C connection
- Reduce air gap between magnet and sensor
- Use stronger magnet (recommended: 30-90 mT field strength)
- Check for magnetic interference from nearby components
- Increase air gap
- Use weaker magnet or add non-magnetic spacer
- Check AGC is in optimal range (40-60%)
- Verify magnet is centered over sensor
- Check for mechanical vibration or magnet wobble
- See Filter Configuration for tuning options
- Run noise characterization:
tests/test_noise_levels.py
The axis_center parameter defines the mechanical zero position:
- Move mechanism to desired center/neutral position
- Read raw angle:
center = encoder.read_raw_angle() - Use this value as
axis_centerin your application - Re-calibrate after mechanical changes (reassembly, etc.)
# Calibration
print(f"Center position: {encoder.read_raw_angle()}")
# Note this value and use it as AXIS_CENTER constantGPL-3.0