HMC 5883L - 3-osiowy magnetometr

Moderator: bbiernat

Post Reply
User avatar
pancio
Administrator
Posts: 63
Joined: 18 September 2013, 23:02 - Wed
Location: SILESIA

HMC 5883L - 3-osiowy magnetometr

Post by pancio »

Wstęp
Dziś chciałbym przedstawić kolejny czujnik: HMC 5883L, który jest cyfrowym, o 12 bitowej rozdzielczości, 3-osiowym magnetometrem pozwalającym na pomiar w szerokim zakresie wielkości pola magnetycznego wynoszącego do ±8 gausa. Charakteryzuje się również bardzo niskim poborem prądu (100µA). HMC5883L komunikuje się ze światem za pomocą magistrali IIC.


Założenia:
- Cubietruck/Cubieboard/Raspberry Pi
- DVK570 (niewymagana, jednak jeśli nie masz kitu - musisz sam zadbać o odpowiednie parametry prądowe np dla diod LED)
- CTdebian 4.1 lub nowszy (do pobrania ze strony Igora Pecovnik-a lub z działu Wsady). W przypadku Raspberry Pi użyć można dystrybucji Raspian.
- Czujnik z układem HMC 5883L, ja wykorzystałem moduł firmy Geeetech:
Czujnik z magnetometrem opartym na układzie HMC5883L
Czujnik z magnetometrem opartym na układzie HMC5883L
Przestroga 1.
Wszystkie operacje wykonuję jako uprzywilejowany użytkownik root . Nie jest to dobra praktyka więc proponuję używać sudo i wykonywać wszystkie komendy z poziomu normalnego użytkownika...

Uwaga.
Dystrybucja, której używam to kompilacja ze źródeł CTDebian Igora Pecovnik-a. Możesz pobrać najnowszą wersję ze strony Igora lub skorzystać z mojej kompilacji.

Przestroga 2
Wszystko co robisz - robisz na własną odpowiedzialność. W trakcie tutoriala wykonywane są czynności, które mogą uszkodzić twoje urządzenie...

Zaczynamy
Do obsługi modułu z HMC5883L wymagane są tylko 2 linie sterujące SDA/SCL i zasilanie 3.3V do 5V. Ja korzystam z tego niższego napięcie 3V3, pamiętaj jednak, że chcąc skorzystać z wyższego napięcia zasilania musisz dopasować poziom linii SCL i SDA za pomocą odpowiedniego konwertera.

Wykrywanie HMC5883L:

Code: Select all

root@ctdev:~/HMC5883L# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- 1e -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --                         
root@ctdev:~/HMC5883L# 

Kod umożliwiający sprawdzenie czujnika (w zasadzie napisany dla Raspberry Pi ale bez dodatkowych przeróbek możliwy do wykonania na CB/CT:

Code: Select all

#!/usr/bin/env python
#vim: set fileencoding=UTF-8 :

# HMC5888L Magnetometer (Digital Compass) wrapper class
# Based on https://bitbucket.org/thinkbowl/i2clibraries/src/14683feb0f96,
# but uses smbus rather than quick2wire and sets some different init
# params.

import smbus
import math
import time
import sys

class hmc5883l:

    __scales = {
        0.88: [0, 0.73],
        1.30: [1, 0.92],
        1.90: [2, 1.22],
        2.50: [3, 1.52],
        4.00: [4, 2.27],
        4.70: [5, 2.56],
        5.60: [6, 3.03],
        8.10: [7, 4.35],
    }

    def __init__(self, port=1, address=0x1E, gauss=1.3, declination=(0,0)):
        self.bus = smbus.SMBus(port)
        self.address = address

        (degrees, minutes) = declination
        self.__declDegrees = degrees
        self.__declMinutes = minutes
        self.__declination = (degrees + minutes / 60) * math.pi / 180

        (reg, self.__scale) = self.__scales[gauss]
        self.bus.write_byte_data(self.address, 0x00, 0x70) # 8 Average, 15 Hz, normal measurement
        self.bus.write_byte_data(self.address, 0x01, reg << 5) # Scale
        self.bus.write_byte_data(self.address, 0x02, 0x00) # Continuous measurement

    def declination(self):
        return (self.__declDegrees, self.__declMinutes)

    def twos_complement(self, val, len):
        # Convert twos compliment to integer
        if (val & (1 << len - 1)):
            val = val - (1<<len)
        return val

    def __convert(self, data, offset):
        val = self.twos_complement(data[offset] << 8 | data[offset+1], 16)
        if val == -4096: return None
        return round(val * self.__scale, 4)

    def axes(self):
        data = self.bus.read_i2c_block_data(self.address, 0x00)
        #print map(hex, data)
        x = self.__convert(data, 3)
        y = self.__convert(data, 7)
        z = self.__convert(data, 5)
        return (x,y,z)

    def heading(self):
        (x, y, z) = self.axes()
        headingRad = math.atan2(y, x)
        headingRad += self.__declination

        # Correct for reversed heading
        if headingRad < 0:
            headingRad += 2 * math.pi

        # Check for wrap and compensate
        elif headingRad > 2 * math.pi:
            headingRad -= 2 * math.pi

        # Convert to degrees from radians
        headingDeg = headingRad * 180 / math.pi
        return headingDeg

    def degrees(self, headingDeg):
        degrees = math.floor(headingDeg)
        minutes = round((headingDeg - degrees) * 60)
        return (degrees, minutes)

    def __str__(self):
        (x, y, z) = self.axes()
        return "Axis X: " + str(x) + "\n" \
               "Axis Y: " + str(y) + "\n" \
               "Axis Z: " + str(z) + "\n" \
               "Declination: " + self.degrees(self.declination()) + "\n" \
               "Heading: " + self.degrees(self.heading()) + "\n"

if __name__ == "__main__":
    # http://magnetic-declination.com/Great%20Britain%20(UK)/Harrogate#
    compass = hmc5883l(gauss = 4.7, declination = (-2,5))
    while True:
        sys.stdout.write("\rHeading: " + str(compass.degrees(compass.heading())) + "     ")
        sys.stdout.flush()
        time.sleep(0.5)

Efekt działania :

Code: Select all

root@ctdev:~/HMC5883L# python hmc5883l.py 
Heading: (165.0, 12.0)     
Heading: (163.0, 58.0)     
Heading: (157.0, 42.0)     
Heading: (150.0, 46.0)     
Heading: (150.0, 3.0)     
Heading: (146.0, 11.0)     
Heading: (138.0, 25.0)     
Heading: (217.0, 8.0)      
Heading: (223.0, 50.0)     ^CTraceback (most recent call last):
  File "hmc5883l.py", line 99, in <module>
    time.sleep(0.5)
KeyboardInterrupt
root@ctdev:~/HMC5883L# 

W najbliższym czasie postaram się pokazać zastosowanie czujnika w sterowaniu serwomechanizmem...
Attachments
HMC5883L.pdf
(415.54 KiB) Downloaded 1367 times

Post Reply