[PYTHON] Verwenden Sie das 9-Achsen-Sensormodul "MPU-9250 (Hersteller-Teilenummer: MPU-9250)" von Strawberry Linux mit Rasberry pi 3.

Es ist ein Kampfrekord für die Verwendung von "MPU-9250 9-Achsen-Sensormodul (Hersteller-Teilenummer: MPU-9250)", hergestellt von Strawberry Linux mit Raspberry pi 3. Ich versuche es mit Python2.

Da GW vorbei ist und ich keine Zeit mehr zu haben scheine, kann ich es tun ... Ich habe als Erwachsener einen Sensor gekauft, der aber fast unberührt blieb. Ich fühle mich wie ein Grundschüler am letzten Tag der Sommerferien.

(Es ist eine lange Zeit, weil ich den Prozess von Versuch und Irrtum so geschrieben habe, wie er ist. Ich möchte ihn eines Tages zusammenfassen.)

2017-04-09 Hochgeladen auf github. https://github.com/boyaki-machine/MPU-9250

Physikalische Verkabelung

Löten Sie den Stiftkopf an den Sensor, der angekommen ist. Dann verdrahten.

Sensor 1pin (VDD) -> Raspi Pin 1 Sensor 2pin (VDDIO) -> Raspi Pin 1 Sensor 3-polig (SCL) -> Raspi-5-polig Sensor 4pin (SDA) -> Raspi Pin 3 Sensor 5-polig (GND oder VDD) -> Raspi-Pin 6 (I2C-Adresse ändert sich je nach GND oder VDD) Sensor 6pin (VDDIO) -> Raspi Pin 1 Sensor 10pin (GND) -> Raspi 6. Pin

Es ist chaotisch, aber es sieht so aus. MPU9250.png

Aktivieren Sie I2C mit Raspberry pi

Im Konfigurationsmenü des Betriebssystems einstellen.

$ sudo raspi-config

Wählen Sie das Menü in der Reihenfolge "9 erweiterte Optionen" -> "A7 I2C". Sie werden gefragt, ob die ARM I2C-Schnittstelle aktiviert werden soll. Wählen Sie also Ja. Sie werden gefragt, ob das I2C-Kernelmodul standardmäßig geladen werden soll. Wählen Sie also Ja.

Bearbeiten Sie dann /boot/config.txt.

$ sudo vi /boot/config.txt
...Folgende Inhalte wurden hinzugefügt
dtparam=i2c_arm=on

Bearbeiten Sie außerdem / etc / modules.

$ sudo vi /etc/modules
...Folgende Inhalte wurden hinzugefügt
snd-bcm2835
i2c-dev

Starten Sie Raspy nach Abschluss der Einstellungen neu. Stellen Sie sicher, dass das Kernelmodul nach dem Neustart geladen ist.

$ lsmod
...
i2c_dev                 6709  0 
snd_bcm2835            21342  0 
...

Installieren Sie Werkzeuge

$ sudo apt-get install i2c-tools python-smbus

Adressbestätigung

Überprüfen Sie die Adresse des Sensors.

$ sudo i2cdetect -y 1	(Wenn Pin 5 mit GND verbunden ist)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

An der Adresse 0x68 erkannt. Diese MPU-9250 verfügt über einen eingebauten Magnetsensor AK8963 von Asahi Kasei Electronics. Im Ausgangszustand kann nicht auf AK8963 zugegriffen werden, aber I2C kann durch Manipulieren einiger Register darauf zugreifen. Stellen Sie das Register mit dem folgenden Python-Skript ein.

#!/usr/bin/python -u
# -*- coding: utf-8 -*-

import smbus
import time

address	= 0x68
channel = 1
bus		= smbus.SMBus(channel)

# PWR_MGMT_Löschen 1
bus.write_i2c_block_data(address, 0x6B, [0x00])
time.sleep(0.1)

#Magnetsensorfunktion mit I2C(AK8963)Machen Sie Zugriff auf(BYPASS_EN=1)
bus.write_i2c_block_data(address, 0x37, [0x02])
time.sleep(0.1)

Überprüfen Sie die Adresse erneut, nachdem Sie das Skript ausgeführt haben.

$ sudo i2cdetect -y 1	(Wenn Pin 5 mit VDD verbunden ist)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- 0c -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

AK8963 Die Adresse 0x0C für den Zugriff wird angezeigt.

Beschleunigung bekommen

Rohdaten abrufen

Hier Ich durfte mich beziehen.

Laut dem Anhang von Strawberry Linux

Anfangs befindet es sich im Schlafmodus und es erfolgt keine Erfassung. Schreiben Sie zunächst 0x00 in die interne Adresse 0x6B der MPU-9250. Außerdem wird 0x02 in die interne Adresse 0x37 geschrieben. Dies startet den Betrieb und ermöglicht die I2C-Kommunikation mit dem Magnetsensor. In diesem Zustand werden die Beschleunigungs-X-, Y-, Z-Kreisel-X-, Y-, Z-Daten in 14 Bytes aus dem internen Register 0x3B gespeichert. Jede Daten sind 16 Bit und die oberen 8 Bits werden zuerst ausgerichtet. Die Beschleunigung ist einfach, da Sie die Gravitationsbeschleunigung durch Bewegen des Sensors sehen können. Der Kreisel muss gedreht werden, was problematisch sein kann.

Warum sind es 14 Bytes, wenn es 16 Bits und 6 Achsen sind? Ich habe mich gefragt, aber beim Betrachten des Datenblattes scheint es, dass auch die Temperatur gemessen werden kann, die 2 Bytes beträgt.

Derzeit wird die Beschleunigung von 6 Bytes erfasst und angezeigt.

#!/usr/bin/python -u
# -*- coding: utf-8 -*-

import smbus
import time

address	= 0x68
bus		= smbus.SMBus(channel)

#Setzen Sie das Register zurück
bus.write_i2c_block_data(address, 0x6B, [0x80])
time.sleep(0.1)		

# PWR_MGMT_Löschen 1
bus.write_i2c_block_data(address, 0x6B, [0x00])
time.sleep(0.1)

#Rohdaten abrufen
while True:
	data 	= bus.read_i2c_block_data(address, 0x3B ,6)
	rawX 	= data[0] << 8 | data[1]	#Höheres Bit zuerst
	rawY	= data[2] << 8 | data[3]	#Höheres Bit zuerst
	rawZ	= data[4] << 8 | data[5]	#Höheres Bit zuerst
	print "%+8.7f" % rawX + "	",
	print "%+8.7f" % rawY + "	",
	print "%+8.7f" % rawZ
	time.sleep(1)

Damit konnten wir bestätigen, dass die Daten kontinuierlich ausgegeben wurden.

Berechnen Sie g

Berechnen Sie die Beschleunigung aus Rohdaten. Die Standardeinstellung scheint im Bereich von ± 2 g auszugeben. Basierend darauf habe ich wie folgt berechnet. Der angezeigte Wert ist jedoch seltsam.

rawX 	= (2.0 / float(0x8000)) * (data[0] << 8 | data[1])
rawY	= (2.0 / float(0x8000)) * (data[2] << 8 | data[3])
rawZ	= (2.0 / float(0x8000)) * (data[4] << 8 | data[5])
print "%+8.7f" % rawX + "	",
print "%+8.7f" % rawY + "	",
print "%+8.7f" % rawZ

Nach verschiedenen Untersuchungen handelt es sich bei dem vom Sensor ausgegebenen Wert um einen vorzeichenlosen Typ. Daher scheint es erforderlich zu sein, ihn in einen vorzeichenbehafteten Typ umzuwandeln, um einen negativen Wert auszudrücken.

#!/usr/bin/python -u
# -*- coding: utf-8 -*-

import smbus
import time

address	= 0x68
bus		= smbus.SMBus(channel)

#Nicht signiert in signiert konvertieren(16-Bit begrenzt)
def u2s(unsigneddata):
    if unsigneddata & (0x01 << 15) : 
        return -1 * ((unsigneddata ^ 0xffff) + 1)
    return unsigneddata

#Setzen Sie das Register zurück
bus.write_i2c_block_data(address, 0x6B, [0x80])
time.sleep(0.1)		

# PWR_MGMT_Löschen 1
bus.write_i2c_block_data(address, 0x6B, [0x00])
time.sleep(0.1)

#Rohdaten abrufen
while True:
	data 	= bus.read_i2c_block_data(address, 0x3B ,6)
	rawX 	= (2.0 / float(0x8000)) * u2s(data[0] << 8 | data[1])
	rawY	= (2.0 / float(0x8000)) * u2s(data[2] << 8 | data[3])
	rawZ	= (2.0 / float(0x8000)) * u2s(data[4] << 8 | data[5])
	print "%+8.7f" % rawX + "	",
	print "%+8.7f" % rawY + "	",
	print "%+8.7f" % rawZ
	time.sleep(1)

Jetzt gibt die Richtung der Z-Achse fast 1 g aus.

Ändern Sie den Messbereich

Wenn Sie den Sensor herumschwenken, erreicht er unerwartet 2 g. Ändern wir also den Messbereich. Laut Datenblatt können Sie anscheinend einen Bereich von 2,4,8,16 angeben.

#!/usr/bin/python -u
# -*- coding: utf-8 -*-

import smbus
import time

address	= 0x68
bus		= smbus.SMBus(channel)

#Nicht signiert in signiert konvertieren(16-Bit begrenzt)
def u2s(unsigneddata):
    if unsigneddata & (0x01 << 15) : 
        return -1 * ((unsigneddata ^ 0xffff) + 1)
    return unsigneddata

#Setzen Sie das Register zurück
bus.write_i2c_block_data(address, 0x6B, [0x80])
time.sleep(0.1)		

# PWR_MGMT_Löschen 1
bus.write_i2c_block_data(address, 0x6B, [0x00])
time.sleep(0.1)

#Stellen Sie den Bereich des Beschleunigungssensors auf ± 8 g ein
bus.write_i2c_block_data(address, 0x1C, [0x08])

#Rohdaten abrufen
while True:
	data 	= bus.read_i2c_block_data(address, 0x3B ,6)
	rawX 	= (8.0 / float(0x8000)) * u2s(data[0] << 8 | data[1])
	rawY	= (8.0 / float(0x8000)) * u2s(data[2] << 8 | data[3])
	rawZ	= (8.0 / float(0x8000)) * u2s(data[4] << 8 | data[5])
	print "%+8.7f" % rawX + "	",
	print "%+8.7f" % rawY + "	",
	print "%+8.7f" % rawZ
	time.sleep(1)

Hmmm, jetzt können Sie den Wert auch dann erhalten, wenn Sie viel herumschwingen.

Beschleunigung kalibrieren

Laut dem Anhang von Strawberry Linux

Da es Abweichungen im Sensor gibt, wird der beobachtete Wert nicht zu 0, selbst wenn die Beschleunigung = 0 g, der Kreisel = 0 ° s und der Magnetismus = 0 μT sind und die Werte geringfügig abweichen. Der zulässige Versatzbereich wird im Datenblatt angezeigt, sodass der Bereich normal ist. Die Software muss Anpassungen vornehmen, indem sie den Versatz abzieht.

Es gibt. Selbst wenn der Sensor fest sitzt, ist die Beschleunigung auf der X- und Y-Achse nicht Null. Laut Datenblatt können Sie den Offset-Wert im Register einstellen, versuchen Sie jedoch zuerst die Kalibrierung auf der Python-Seite.

#!/usr/bin/python -u
# -*- coding: utf-8 -*-

import smbus
import time

address	= 0x68
bus		= smbus.SMBus(channel)

#Nicht signiert in signiert konvertieren(16-Bit begrenzt)
def u2s(unsigneddata):
    if unsigneddata & (0x01 << 15) : 
        return -1 * ((unsigneddata ^ 0xffff) + 1)
    return unsigneddata

#Setzen Sie das Register zurück
bus.write_i2c_block_data(address, 0x6B, [0x80])
time.sleep(0.1)		

# PWR_MGMT_Löschen 1
bus.write_i2c_block_data(address, 0x6B, [0x00])
time.sleep(0.1)

#Stellen Sie den Bereich des Beschleunigungssensors auf ± 8 g ein
bus.write_i2c_block_data(address, 0x1C, [0x08])

#Berechnen Sie den Kalibrierungswert
print "Accel calibration start"
_sum	= [0,0,0]

#Nehmen Sie eine Stichprobe realer Daten
for _i in range(1000):
	data 	= bus.read_i2c_block_data(address, 0x3B ,6)
	_sum[0] += (8.0 / float(0x8000)) * u2s(data[0] << 8 | data[1])
	_sum[1] += (8.0 / float(0x8000)) * u2s(data[2] << 8 | data[3])
	_sum[2] += (8.0 / float(0x8000)) * u2s(data[4] << 8 | data[5])

#Versetzen Sie den Durchschnittswert
offsetAccelX 	= -1.0 * _sum[0] / 1000
offsetAccelY 	= -1.0 * _sum[1] / 1000
#Die Z-Achse subtrahiert die Schwerkraft, wirklich 1.0 ist verdächtig
offsetAccelZ 	= -1.0 * ((_sum[2] / 1000 ) - 1.0)
print "Accel calibration complete"

#Rohdaten abrufen
while True:
	data 	= bus.read_i2c_block_data(address, 0x3B ,6)
	rawX 	= (8.0 / float(0x8000)) * u2s(data[0] << 8 | data[1]) + offsetAccelX
	rawY	= (8.0 / float(0x8000)) * u2s(data[2] << 8 | data[3]) + offsetAccelY
	rawZ	= (8.0 / float(0x8000)) * u2s(data[4] << 8 | data[5]) + offsetAccelZ
	print "%+8.7f" % rawX + "	",
	print "%+8.7f" % rawY + "	",
	print "%+8.7f" % rawZ
	time.sleep(1)

Hmmm, es ist nicht genau 0, aber es ist besser als am Anfang. Ich weiß nicht, ob Sie den Durchschnittswert für den Offset verwenden können.

Andere

Selbst nach der Kalibrierung schwankt der Wert leicht weiter, wenn der Sensor fest sitzt und eine kontinuierliche Erfassung durchgeführt wird. Erkennen Sie eine unbekannte Welle? Es ist beängstigend. .. .. Möglicherweise ist der Sensor zu empfindlich, um elektrische Störungen aufzunehmen. In der Registerliste des Datenblattes befand sich die Einstellung "Beschleunigungsmesser-Tiefpassfilter". Wenn Sie also damit spielen, erhalten Sie möglicherweise einen stabileren Wert. Ich habe es diesmal nicht angefasst, weil die Zeit abgelaufen war.

Holen Sie sich die Temperatur

Es scheint, dass die Temperatur mit großem Aufwand gemessen werden kann, also habe ich es versucht.

#!/usr/bin/python -u
# -*- coding: utf-8 -*-

import smbus
import time

address	= 0x68
bus		= smbus.SMBus(channel)

#Setzen Sie das Register zurück
bus.write_i2c_block_data(address, 0x6B, [0x80])
time.sleep(0.1)		

# PWR_MGMT_Löschen 1
bus.write_i2c_block_data(address, 0x6B, [0x00])
time.sleep(0.1)

#Rohdaten abrufen
while True:
	data 	= bus.read_i2c_block_data(address, 0x65 ,2)
	raw 	= data[0] << 8 | data[1]
	#Die Formel zur Berechnung der Temperatur lautet wie folgt aus dem Datenblatt
	# ((TEMP_OUT – RoomTemp_Offset)/Temp_Sensitivity) + 21degC
	temp 	= (raw / 333.87) + 21 
	print str(temp)

Damit wurde der Wert erhalten, der Raumtemperatur zu sein scheint. Die Formel zur Berechnung der Temperatur aus Rohdaten ist im Datenblatt angegeben, die wesentlichen Werte von RoomTemp_Offset und Temp_Sensitivity sind jedoch nicht aufgeführt. Daher hier. 23 / Himbeerstück% E3% 81% A8mpu-9250% E3% 81% AE% E6% B8% A9% E5% BA% A6% E3% 82% BB% E3% 83% B3% E3% 82% B5 /) Ich habe auf den Artikel verwiesen. Es scheint, dass die Verfolgbarkeit nicht so gut ist und sich der Wert nicht leicht ändert, selbst wenn Sie ihn mit der Hand halten.

Holen Sie sich Winkelgeschwindigkeit

Daten bekommen

Die Methode ist die gleiche wie für die Beschleunigung. Außerdem werden dps-Werte aus Rohdaten berechnet, der Messbereich korrigiert und Kalibrierungswerte berechnet.

#!/usr/bin/python -u
# -*- coding: utf-8 -*-

import smbus
import time

address	= 0x68
bus		= smbus.SMBus(1)

#Setzen Sie das Register zurück
bus.write_i2c_block_data(address, 0x6B, [0x80])
time.sleep(0.1)		

# PWR_MGMT_Löschen 1
bus.write_i2c_block_data(address, 0x6B, [0x00])
time.sleep(0.1)

#Korrigieren Sie den Messbereich auf 1000 dps
bus.write_i2c_block_data(address, 0x1B, [0x10])

#Faktor zur Berechnung von dps
gyroCoefficient	= 1000 / float(0x8000)

#Berechnen Sie den Kalibrierungswert
print "Gyro calibration start"
_sum	= [0,0,0]

#Nehmen Sie eine Stichprobe realer Daten
for _i in range(1000):
	data 	= bus.read_i2c_block_data(address, 0x43 ,6)
	_sum[0] += gyroCoefficient * u2s(data[0] << 8 | data[1])
	_sum[1] += gyroCoefficient * u2s(data[2] << 8 | data[3])
	_sum[2] += gyroCoefficient * u2s(data[4] << 8 | data[5])

#Versetzen Sie den Durchschnittswert
offsetGyroX 	= -1.0 * _sum[0] / 1000
offsetGyroY 	= -1.0 * _sum[1] / 1000
offsetGyroZ 	= -1.0 * _sum[2] / 1000
print "Gyro calibration complete"

#Daten bekommen
while True:
	data 	= bus.read_i2c_block_data(address, 0x43 ,6)
	rawX 	= gyroCoefficient * u2s(data[0] << 8 | data[1]) + offsetGyroX
	rawY	= gyroCoefficient * u2s(data[2] << 8 | data[3]) + offsetGyroY
	rawZ	= gyroCoefficient * u2s(data[4] << 8 | data[5]) + offsetGyroZ

	print "%+8.7f" % rawX + "	",
	print "%+8.7f" % rawY + "	",
	print "%+8.7f" % rawZ + "	"
	time.sleep(1)

Andere

Wie beim Beschleunigungssensor schwankt der dps-Wert auch dann, wenn der Sensor fest sitzt. Es ist nur ein Fehler, wenn es aus dem Messbereich betrachtet wird, aber es beruhigt sich nicht. .. .. Ich hoffe, dass dies auch durch Setzen von DLPF_CFG im 0x1A-Register verbessert werden kann, aber ich konnte es diesmal nicht versuchen.

Erfassung des Magnetsensors

Der Magnetsensor ist AK8963, hergestellt von Asahi Kasei Electronics. Ich schätze das japanische Datenblatt sehr. .. ..

Es ist eine Schande, aber ich dachte, dass der Sensor der einzige japanische Hersteller ist, aber selbst wenn ich das an raspi angeschlossene Probenmodul überprüfe, wurde er nur in Übersee hergestellt. Ich möchte, dass japanische Hersteller ihr Bestes geben.

Mit dem AK8963 ist es also einfach, die Daten nur einmal zu erfassen, aber beim Versuch, eine kontinuierliche Erfassung durchzuführen, waren verschiedene Verfahren problematisch. Ich meine, es ist ein verrücktes Design, oder Sie können seltsam detaillierte Einstellungen vornehmen. .. ..

Es gibt vier Messmodi: Einzelaufnahme, kontinuierliche 1 (8 Hz), kontinuierliche 2 (100 Hz) und externer Trigger. Zusätzlich kann die Anzahl der Bits zur Ausgabe des Messwerts in 16 Bit / 14 Bit ausgewählt werden. Im Einzelbildmodus wird nach dem Erkennen auf Ausschalten umgeschaltet, sodass Sie den Einzelbildmodus erneut einstellen müssen. Insbesondere im kontinuierlichen Erfassungsmodus werden die späteren (neuen) Daten verworfen, bis die vorherigen Daten abgerufen werden. Die abgerufenen Daten sollten jedes Mal auf Überlauf überprüft werden. Es scheint, dass der richtige Wert nicht herauskommt, wenn er überläuft.

Ich war auch süchtig nach der Tatsache, dass die unteren Bits zuerst erfasst werden können, wenn Daten aus dem Register gelesen werden. Bitte beachten Sie, dass das obere Bit für Beschleunigung und Winkelgeschwindigkeit an erster Stelle steht.

Mit diesem Gefühl dachte ich, ich würde versuchen, nur den Magnetsensorteil zu extrahieren und zu schreiben, aber es ist ziemlich schwierig, also lesen Sie bitte die klassifizierte Operation.

Es ist schwierig zu beurteilen, ob der Magnetsensor korrekt ist, selbst wenn der Wert erhalten wird. Laut Wiki Es scheint, dass "die Stärke des Geomagnetismus bei 50 Grad Länge: 58 μT", also denke ich nicht, dass es ein ganz anderer Wert ist.

Außerdem wollte ich die Ausrichtung von jeder Achse μT berechnen, konnte sie aber auch nicht verarbeiten. Ist es die nächste Aufgabe?

Bilden Sie eine Klasse zusammen

Klassifizieren Sie die bisherigen Ergebnisse zusammen.

#!/usr/bin/python -u
# -*- coding: utf-8 -*-

import smbus
import time

#"MPU" von Strawberry Linux-Klasse zum Abrufen von Daten von 9250 mit I2C(python 2)
# https://strawberry-linux.com/catalog/items?code=12250
#
# 2016-05-03 Boyaki Machine
class SL_MPU9250:
	#Ständige Erklärung
	REG_PWR_MGMT_1 		= 0x6B
	REG_INT_PIN_CFG 	= 0x37
	REG_GYRO_CONFIG		= 0x1B
	REG_ACCEL_CONFIG1 	= 0x1C
	REG_ACCEL_CONFIG2	= 0x1D

	MAG_MODE_POWERDOWN	= 0			#Magnetsensor ausschalten
	MAG_MODE_SERIAL_1	= 1			#Magnetsensor 8Hz kontinuierlicher Messmodus
	MAG_MODE_SERIAL_2	= 2			#Magnetsensor 100Hz kontinuierlicher Messmodus
	MAG_MODE_SINGLE		= 3			#Single-Shot-Messmodus für Magnetsensoren
	MAG_MODE_EX_TRIGER	= 4			#Messmodus für externen Trigger des Magnetsensors
	MAG_MODE_SELF_TEST	= 5			#Selbsttestmodus des Magnetsensors

	MAG_ACCESS			= False		#Zugang zum Magnetsensor
	MAG_MODE			= 0			#Magnetsensormodus
	MAG_BIT				= 14		#Anzahl der vom Magnetsensor ausgegebenen Bits

	offsetRoomTemp		= 0
	tempSensitivity		= 333.87
	gyroRange			= 250		# 'dps' 00:250, 01:500, 10:1000, 11:2000
	accelRange			= 2			# 'g' 00:±2, 01:±4, 10:±8, 11:±16
	magRange			= 4912		# 'μT'  

	offsetAccelX		= 0.0
	offsetAccelY		= 0.0
	offsetAccelZ		= 0.0
	offsetGyroX			= 0.0
	offsetGyroY			= 0.0
	offsetGyroZ			= 0.0

	#Konstrukteur
	def __init__(self, address, channel):
		self.address	= address
		self.channel	= channel
		self.bus		= smbus.SMBus(self.channel)
		self.addrAK8963	= 0x0C

		# Sensor initialization
		self.resetRegister()
		self.powerWakeUp()

		self.gyroCoefficient	= self.gyroRange  / float(0x8000)	#Ein Koeffizient, der den erfassten Dezimalwert in dps umwandelt
		self.accelCoefficient	= self.accelRange / float(0x8000)	#Ein Koeffizient, der den erfassten Dezimalwert in g umwandelt
		self.magCoefficient16	= self.magRange   / 32760.0			#Ein Koeffizient, der den erfassten Dezimalwert in μT umwandelt(Bei 16bit)
		self.magCoefficient14	= self.magRange   / 8190.0			#Ein Koeffizient, der den erfassten Dezimalwert in μT umwandelt(Bei 14bit)

	#Setzt die Register auf ihre Standardeinstellungen zurück.
	def resetRegister(self):
		if self.MAG_ACCESS == True:
			self.bus.write_i2c_block_data(self.addrAK8963, 0x0B, [0x01])	
		self.bus.write_i2c_block_data(self.address, 0x6B, [0x80])
		self.MAG_ACCESS	= False
		time.sleep(0.1)		

	#Macht das Register messbar.
	def powerWakeUp(self):
		# PWR_MGMT_Löschen 1
		self.bus.write_i2c_block_data(self.address, self.REG_PWR_MGMT_1, [0x00])
		time.sleep(0.1)
		#Magnetsensorfunktion mit I2C(AK8963)Machen Sie Zugriff auf(BYPASS_EN=1)
		self.bus.write_i2c_block_data(self.address, self.REG_INT_PIN_CFG, [0x02])
		self.MAG_ACCESS	= True
		time.sleep(0.1)

	#Stellen Sie das Register des Magnetsensors ein
	def setMagRegister(self, _mode, _bit):		
		if self.MAG_ACCESS == False:
			#Eine Ausnahme auslösen, da der Zugriff auf den Magnetsensor nicht aktiviert ist
			raise Exception('001 Access to a sensor is invalid.')

		_writeData	= 0x00
		#Einstellung des Messmodus
		if _mode=='8Hz':			#Kontinuierlicher Messmodus 1
			_writeData 		= 0x02
			self.MAG_MODE 	= self.MAG_MODE_SERIAL_1
		elif _mode=='100Hz':		#Kontinuierlicher Messmodus 2
			_writeData		= 0x06
			self.MAG_MODE 	= self.MAG_MODE_SERIAL_2
		elif _mode=='POWER_DOWN':	#Ausschaltmodus
			_writeData		= 0x00
			self.MAG_MODE 	= self.MAG_MODE_POWERDOWN
		elif _mode=='EX_TRIGER':	#Externer Trigger-Messmodus
			_writeData		= 0x04
			self.MAG_MODE 	= self.MAG_MODE_EX_TRIGER
		elif _mode=='SELF_TEST':	#Selbsttestmodus
			_writeData		= 0x08
			self.MAG_MODE 	= self.MAG_MODE_SELF_TEST
		else:	# _mode='SINGLE'	#Einzelmessmodus
			_writeData 		= 0x01
			self.MAG_MODE 	= self.MAG_MODE_SINGLE
		
		#Anzahl der auszugebenden Bits
		if _bit=='14bit':			#14bit Ausgang
			_writeData 		= _writeData | 0x00
			self.MAG_BIT	= 14
		else:	# _bit='16bit'		#16bit Ausgang
			_writeData		= _writeData | 0x10
			self.MAG_BIT 	= 16

		self.bus.write_i2c_block_data(self.addrAK8963, 0x0A, [_writeData])

	#Legt den Beschleunigungsmessbereich fest. Die Messkorngröße wird in einem weiten Bereich rau.
	# val = 16, 8, 4, 2(default)
	def setAccelRange(self, val, _calibration=False):
		# ±2g (00), ±4g (01), ±8g (10), ±16g (11)
		if val==16 :
			self.accelRange 	= 16
			_data 				= 0x18
		elif val==8 :
			self.accelRange 	= 8
			_data 				= 0x10
		elif val==4 :
			self.accelRange 	= 4
			_data 				= 0x08
		else:
			self.accelRange 	= 2
			_data 				= 0x00

		self.bus.write_i2c_block_data(self.address, self.REG_ACCEL_CONFIG1, [_data])
		self.accelCoefficient 	= self.accelRange / float(0x8000)
		time.sleep(0.1)

		#Versatzwert zurücksetzen(Um zu verhindern, dass vergangene Versatzwerte vererbt werden)
		self.offsetAccelX 		= 0
		self.offsetAccelY 		= 0
		self.offsetAccelZ 		= 0

		#Ich denke, es ist besser, Kalibrierung zu verwenden, aber es braucht Zeit.
		if _calibration == True:
			self.calibAccel(1000)
		return

	#Stellen Sie den Messbereich des Kreisels ein. Die Messkorngröße wird in einem weiten Bereich rau.
	# val= 2000, 1000, 500, 250(default)
	def setGyroRange(self, val, _calibration=False):
		if val==2000:
			self.gyroRange		= 2000
			_data 				= 0x18
		elif val==1000:
			self.gyroRange 		= 1000
			_data 				= 0x10
		elif val==500:
			self.gyroRange 		= 500
			_data 				= 0x08
		else:
			self.gyroRange 		= 250
			_data 				= 0x00

		self.bus.write_i2c_block_data(self.address, self.REG_GYRO_CONFIG, [_data])
		self.gyroCoefficient 	= self.gyroRange / float(0x8000)
		time.sleep(0.1)

		#Versatzwert zurücksetzen(Um zu verhindern, dass vergangene Versatzwerte vererbt werden)
		self.offsetGyroX 		= 0
		self.offsetGyroY 		= 0
		self.offsetGyroZ 		= 0

		#Eigentlich ist es besser, Calibration zu verwenden, aber es braucht Zeit.
		if _calibration == True:
			self.calibGyro(1000)
		return

	#Stellen Sie den LowPass-Filter des Beschleunigungssensors ein.
	# def setAccelLowPassFilter(self,val):		

	#Wenn Sie versuchen, die Daten vom Sensor so zu verwenden, wie sie sind, werden sie als nicht signiert behandelt und in signierte konvertiert.(16-Bit begrenzt)
	def u2s(self,unsigneddata):
	    if unsigneddata & (0x01 << 15) : 
	        return -1 * ((unsigneddata ^ 0xffff) + 1)
	    return unsigneddata

	#Beschleunigungswert abrufen
	def getAccel(self):
		data 	= self.bus.read_i2c_block_data(self.address, 0x3B ,6)
		rawX 	= self.accelCoefficient * self.u2s(data[0] << 8 | data[1]) + self.offsetAccelX
		rawY	= self.accelCoefficient * self.u2s(data[2] << 8 | data[3]) + self.offsetAccelY
		rawZ	= self.accelCoefficient * self.u2s(data[4] << 8 | data[5]) + self.offsetAccelZ
		return rawX, rawY, rawZ

	#Holen Sie sich den Kreiselwert.
	def getGyro(self):
		data 	= self.bus.read_i2c_block_data(self.address, 0x43 ,6)
		rawX 	= self.gyroCoefficient * self.u2s(data[0] << 8 | data[1]) + self.offsetGyroX
		rawY	= self.gyroCoefficient * self.u2s(data[2] << 8 | data[3]) + self.offsetGyroY
		rawZ	= self.gyroCoefficient * self.u2s(data[4] << 8 | data[5]) + self.offsetGyroZ
		return rawX, rawY, rawZ

	def getMag(self):
		if self.MAG_ACCESS == False:
			#Der Magnetsensor ist ungültig.
			raise Exception('002 Access to a sensor is invalid.')

		#Vorverarbeitung
		if self.MAG_MODE==self.MAG_MODE_SINGLE:
			#Der Einzelmessmodus wird ausgeschaltet, sobald die Messung abgeschlossen ist. Ändern Sie den Modus daher erneut.
			if self.MAG_BIT==14:				#14bit Ausgang
				_writeData 		= 0x01
			else:								#16bit Ausgang
				_writeData		= 0x11
			self.bus.write_i2c_block_data(self.addrAK8963, 0x0A, [_writeData])
			time.sleep(0.01)

		elif self.MAG_MODE==self.MAG_MODE_SERIAL_1 or self.MAG_MODE==self.MAG_MODE_SERIAL_2:
			status 	= self.bus.read_i2c_block_data(self.addrAK8963, 0x02 ,1)
			if (status[0] & 0x02) == 0x02:
				#Erneutes Erkennen, da ein Datenüberlauf vorliegt
				self.bus.read_i2c_block_data(self.addrAK8963, 0x09 ,1)

		elif self.MAG_MODE==self.MAG_MODE_EX_TRIGER:
			#Nicht implementiert
			return

		elif self.MAG_MODE==self.MAG_MODE_POWERDOWN:
			raise Exception('003 Mag sensor power down')

		#Überprüfen Sie das ST1-Register, um festzustellen, ob Daten gelesen werden können.
		status 	= self.bus.read_i2c_block_data(self.addrAK8963, 0x02 ,1)
		while (status[0] & 0x01) != 0x01:
			#Warten Sie, bis die Daten bereit sind
			time.sleep(0.01)
			status 	= self.bus.read_i2c_block_data(self.addrAK8963, 0x02 ,1)

		#Daten gelesen
		data 	= self.bus.read_i2c_block_data(self.addrAK8963, 0x03 ,7)
		rawX 	= self.u2s(data[1] << 8 | data[0])	#Bit zuerst absenken
		rawY	= self.u2s(data[3] << 8 | data[2])	#Bit zuerst absenken
		rawZ	= self.u2s(data[5] << 8 | data[4])	#Bit zuerst absenken
		st2		= data[6]

		#Überlaufprüfung
		if (st2 & 0x08) == 0x08:
			#Der richtige Wert wird aufgrund eines Überlaufs nicht erhalten
			raise Exception('004 Mag sensor over flow')

		#Umrechnung in μT
		if self.MAG_BIT==16:	#Bei 16bit Ausgang
			rawX 	= rawX * self.magCoefficient16
			rawY	= rawY * self.magCoefficient16
			rawZ	= rawZ * self.magCoefficient16
		else:					#Zum Zeitpunkt der 14bit Ausgabe
			rawX 	= rawX * self.magCoefficient14
			rawY	= rawY * self.magCoefficient14
			rawZ	= rawZ * self.magCoefficient14

		return rawX, rawY, rawZ

	def getTemp(self):
		data 	= self.bus.read_i2c_block_data(self.address, 0x65 ,2)
		raw 	= data[0] << 8 | data[1]
		return ((raw - self.offsetRoomTemp) / self.tempSensitivity) + 21

	def selfTestMag(self):
		print "start mag sensor self test"
		self.setMagRegister('SELF_TEST','16bit')
		self.bus.write_i2c_block_data(self.addrAK8963, 0x0C, [0x40])
		time.sleep(1.0)
		data = self.getMag()

		print data

		self.bus.write_i2c_block_data(self.addrAK8963, 0x0C, [0x00])
		self.setMagRegister('POWER_DOWN','16bit')
		time.sleep(1.0)
		print "end mag sensor self test"
		return

	#Kalibrieren Sie den Beschleunigungssensor
	#Ich denke, es ist notwendig, Breite, Höhe, Topographie usw. zu berücksichtigen, aber es ist einfach.
	#Angenommen, die Schwerkraft wird korrekt in Richtung der Z-Achse angewendet und es wird keine andere Beschleunigung als die Schwerkraft erzeugt
	def calibAccel(self, _count=1000):
		print "Accel calibration start"
		_sum	= [0,0,0]

		#Nehmen Sie eine Stichprobe realer Daten
		for _i in range(_count):
			_data 	= self.getAccel()
			_sum[0] += _data[0]
			_sum[1] += _data[1]
			_sum[2] += _data[2]

		#Versetzen Sie den Durchschnittswert
		self.offsetAccelX 	= -1.0 * _sum[0] / _count
		self.offsetAccelY 	= -1.0 * _sum[1] / _count
		self.offsetAccelZ 	= -1.0 * ((_sum[2] / _count ) - 1.0)	#Schwerkraft abziehen

		#Ich möchte den Versatzwert im Register registrieren, kenne die Operation jedoch nicht, sodass die Implementierung angehalten wird

		print "Accel calibration complete"
		return self.offsetAccelX, self.offsetAccelY, self.offsetAccelZ

	#Kalibrieren Sie den Kreiselsensor
	#Annahme, dass nicht in jeder Achse eine Drehung auftritt
	def calibGyro(self, _count=1000):
		print "Gyro calibration start"
		_sum	= [0,0,0]

		#Nehmen Sie eine Stichprobe realer Daten
		for _i in range(_count):
			_data 	= self.getGyro()
			_sum[0] += _data[0]
			_sum[1] += _data[1]
			_sum[2] += _data[2]

		#Versetzen Sie den Durchschnittswert
		self.offsetGyroX 	= -1.0 * _sum[0] / _count
		self.offsetGyroY 	= -1.0 * _sum[1] / _count
		self.offsetGyroZ 	= -1.0 * _sum[2] / _count

		#Ich möchte den Versatzwert im Register registrieren, kenne die Operation jedoch nicht, sodass die Implementierung angehalten wird

		print "Gyro calibration complete"
		return self.offsetGyroX, self.offsetGyroY, self.offsetGyroZ


if __name__ == "__main__":
	sensor 	= SL_MPU9250(0x68,1)
	sensor.resetRegister()
	sensor.powerWakeUp()
	sensor.setAccelRange(8,True)
	sensor.setGyroRange(1000,True)
	sensor.setMagRegister('100Hz','16bit')
	# sensor.selfTestMag()

	while True:
		now		= time.time()
		acc 	= sensor.getAccel()
		gyr 	= sensor.getGyro()
		mag 	= sensor.getMag()
		print "%+8.7f" % acc[0] + "	",
		print "%+8.7f" % acc[1] + "	",
		print "%+8.7f" % acc[2] + "	",
		print "	|	",
		print "%+8.7f" % gyr[0] + "	",
		print "%+8.7f" % gyr[1] + "	",
		print "%+8.7f" % gyr[2] + "	",
		print "	|	",
		print "%+8.7f" % mag[0] + "	",
		print "%+8.7f" % mag[1] + "	",
		print "%+8.7f" % mag[2]

		sleepTime 		= 0.1 - (time.time() - now)
		if sleepTime < 0.0:
			continue
		time.sleep(sleepTime)

Probleme

Wenn Sie die obige Klasse verwenden, können Sie die Daten vorerst kontinuierlich abrufen. Um jedoch eine genauere Erfassung zu realisieren, denke ich, dass es notwendig ist, den am Chip angebrachten Versatz und die Tiefpassfilterfunktion zu verwenden. Ich würde es gerne versuchen, wenn ich in Zukunft Zeit habe.

Wenn nur Beschleunigung und Winkelgeschwindigkeit kontinuierlich mit einer Probenquelle unter Verwendung der obigen Klasse erfasst wurden, konnten 100 Hz ohne Probleme erreicht werden, aber es gab eine leichte Verzögerung bei 200 Hz. Ich denke, dass es möglich sein wird, eine Erfassung mit einer höheren Frequenz durchzuführen, indem auch hier die Implementierung entwickelt wird.

Es mag Ihnen nicht so wichtig sein, es mit Raspi zu verwenden. Wenn Sie jedoch mit hoher Frequenz und Genauigkeit messen, steigt der Stromverbrauch. Daher muss entsprechend der tatsächlichen Verwendung ein geeigneter Modus ausgewählt werden. Ich würde gerne wissen, welcher Modus wie viel Strom verbraucht. Ich frage mich, ob dies einige Zeit dauern wird.

Wenn es hilfreich ist, bin ich glücklich.

Recommended Posts

Verwenden Sie das 9-Achsen-Sensormodul "MPU-9250 (Hersteller-Teilenummer: MPU-9250)" von Strawberry Linux mit Rasberry pi 3.
Verwenden Sie "TSL2561 Beleuchtungssensormodul (Hersteller-Teilenummer: TSL2561)", hergestellt von Strawberry Linux mit Rasberry pi 3 (Zusammenfassung)
Verwenden Sie "TSL2561 Beleuchtungssensormodul Hersteller Teilenummer: TSL2561", hergestellt von Strawberry Linux mit Raspberry pi 3 (Versuch und Irrtum)
Verwenden Sie einen PIR-Bewegungssensor mit Himbeer-Pi