Skip to content

Commit da04777

Browse files
Kaan OzenKaan Ozen
authored andcommitted
feat(lis2mdl): Add OLED digital compass example.
1 parent 5086533 commit da04777

2 files changed

Lines changed: 138 additions & 0 deletions

File tree

lib/lis2mdl/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ print("Register dump:", regs)
213213
| `power_on()` / `power_off()` | Power management |
214214
| `soft_reset()` / `reboot()` | Sensor reset functions |
215215

216+
216217
---
217218

218219
## Examples
@@ -229,6 +230,7 @@ print("Register dump:", regs)
229230
| low_power_one_shot.py | Energy-efficient sampling example. Uses `power_off()` between readings and `read_one_shot()` every 10 seconds, then prints values and free memory. |
230231
| magnet_compass.py | Flat compass example that computes heading and cardinal direction from the LIS2MDL magnetic field. Useful for basic orientation demos. |
231232
| magnet_fieldForce.py | Magnetic field magnitude example that shows total field strength in microtesla. Useful for observing magnetic disturbances and relative field changes. |
233+
| compass_display.py | Graphical compass with OLED display |
232234

233235
---
234236

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
"""Digital compass example using LIS2MDL and SSD1327 OLED.
2+
3+
Reads the magnetic heading using the built-in flat heading method,
4+
and draws a dynamic compass needle on the display using lines.
5+
Includes a preliminary calibration step.
6+
"""
7+
8+
from math import cos, pi, sin
9+
from time import sleep_ms
10+
11+
import ssd1327
12+
from lis2mdl import LIS2MDL
13+
from machine import I2C, SPI, Pin
14+
15+
# Layout Constants for Round Screen
16+
CENTER_X = 64
17+
CENTER_Y = 54
18+
COMPASS_RADIUS = 42 # Radius for the outer border of the compass
19+
NEEDLE_LENGTH = 35
20+
21+
TEXT_HEAD_X = 36
22+
TEXT_HEAD_Y = 100
23+
TEXT_DIR_X = 36
24+
TEXT_DIR_Y = 112
25+
26+
CARD_N_X = 60
27+
CARD_N_Y = 16
28+
CARD_S_X = 60
29+
CARD_S_Y = 84
30+
CARD_E_X = 96
31+
CARD_E_Y = 50
32+
CARD_W_X = 24
33+
CARD_W_Y = 50
34+
35+
CALIB_MSG1_X = 12
36+
CALIB_MSG1_Y = 50
37+
CALIB_MSG2_X = 4
38+
CALIB_MSG2_Y = 70
39+
40+
def draw_circle(fbuf, x0, y0, r, c):
41+
"""Draw a circle using the integer midpoint circle algorithm."""
42+
f = 1 - r
43+
ddf_x = 1
44+
ddf_y = -2 * r
45+
x = 0
46+
y = r
47+
48+
fbuf.pixel(x0, y0 + r, c)
49+
fbuf.pixel(x0, y0 - r, c)
50+
fbuf.pixel(x0 + r, y0, c)
51+
fbuf.pixel(x0 - r, y0, c)
52+
53+
while x < y:
54+
if f >= 0:
55+
y -= 1
56+
ddf_y += 2
57+
f += ddf_y
58+
x += 1
59+
ddf_x += 2
60+
f += ddf_x
61+
62+
fbuf.pixel(x0 + x, y0 + y, c)
63+
fbuf.pixel(x0 - x, y0 + y, c)
64+
fbuf.pixel(x0 + x, y0 - y, c)
65+
fbuf.pixel(x0 - x, y0 - y, c)
66+
fbuf.pixel(x0 + y, y0 + x, c)
67+
fbuf.pixel(x0 - y, y0 + x, c)
68+
fbuf.pixel(x0 + y, y0 - x, c)
69+
fbuf.pixel(x0 - y, y0 - x, c)
70+
71+
# Hardware Initialization
72+
i2c = I2C(1)
73+
mag = LIS2MDL(i2c)
74+
75+
spi = SPI(1)
76+
dc = Pin("DATA_COMMAND_DISPLAY")
77+
res = Pin("RST_DISPLAY")
78+
cs = Pin("CS_DISPLAY")
79+
display = ssd1327.WS_OLED_128X128_SPI(spi, dc, res, cs)
80+
81+
try:
82+
# Calibration Phase
83+
display.fill(0)
84+
display.text("Calibrating...", CALIB_MSG1_X, CALIB_MSG1_Y, 15)
85+
display.text("Move in 8-shape", CALIB_MSG2_X, CALIB_MSG2_Y, 15)
86+
display.show()
87+
sleep_ms(100)
88+
89+
print("Calibrate the magnetometer by moving it in a figure-eight pattern.")
90+
mag.calibrate_minmax_3d()
91+
print("Calibration complete.")
92+
93+
# Main Compass Loop
94+
while True:
95+
heading_deg = mag.heading_flat_only()
96+
direction = mag.direction_label(heading_deg)
97+
98+
# Convert to radians for the trigonometric functions
99+
# 0 degrees is North (Up), 90 is East (Right)
100+
heading_rad = heading_deg * pi / 180.0
101+
102+
# Calculate the end coordinates of the compass needle
103+
end_x = CENTER_X + int(NEEDLE_LENGTH * sin(heading_rad))
104+
end_y = CENTER_Y - int(NEEDLE_LENGTH * cos(heading_rad))
105+
106+
# Drawing Phase
107+
display.fill(0)
108+
109+
# Draw the compass outer border (circle)
110+
draw_circle(display.framebuf, CENTER_X, CENTER_Y, COMPASS_RADIUS, 15)
111+
112+
# Draw Cardinal Points (N, E, S, W)
113+
display.text("N", CARD_N_X, CARD_N_Y, 15)
114+
display.text("S", CARD_S_X, CARD_S_Y, 15)
115+
display.text("E", CARD_E_X, CARD_E_Y, 15)
116+
display.text("W", CARD_W_X, CARD_W_Y, 15)
117+
118+
# Draw the center dot and the needle
119+
display.framebuf.fill_rect(CENTER_X - 1, CENTER_Y - 1, 3, 3, 15)
120+
display.framebuf.line(CENTER_X, CENTER_Y, end_x, end_y, 15)
121+
122+
# Display the heading text and direction label at the bottom
123+
display.text("{} deg".format(int(heading_deg)), TEXT_HEAD_X, TEXT_HEAD_Y, 15)
124+
display.text("Dir: {}".format(direction), TEXT_DIR_X, TEXT_DIR_Y, 15)
125+
126+
display.show()
127+
sleep_ms(50)
128+
129+
except KeyboardInterrupt:
130+
pass
131+
finally:
132+
# Clean up and power off display on exit
133+
display.fill(0)
134+
display.show()
135+
sleep_ms(100)
136+
display.power_off()

0 commit comments

Comments
 (0)