Utilisez le «module de capteur 9 axes MPU-9250 (numéro de pièce du fabricant: MPU-9250)» fabriqué par Strawberry Linux avec Rasberry pi 3.

Il s'agit d'un record de lutte pour l'utilisation du "module de capteur 9 axes MPU-9250 (numéro de pièce du fabricant: MPU-9250)" fabriqué par Strawberry Linux avec Raspberry pi 3. J'essaye avec Python2.

Je ne pense pas que j'aurai plus le temps après la fin de GW J'ai acheté un capteur à l'âge adulte, mais il était presque intact. Je me sens comme un élève du primaire le dernier jour des vacances d'été.

(C'est long parce que j'ai écrit le processus d'essais et d'erreurs tel qu'il est. Je veux le résumer un jour.)

2017-04-09 Téléchargé sur github. https://github.com/boyaki-machine/MPU-9250

Câblage physique

Souder la tête de broche au capteur qui est arrivé. Puis fil.

Capteur 1pin (VDD) -> Raspi pin 1 Capteur 2 broches (VDDIO) -> Raspi broche 1 Capteur 3 broches (SCL) -> Raspi 5ème broche Capteur 4 broches (SDA) -> Raspi pin 3 Capteur 5 broches (GND ou VDD) -> Raspi pin 6 (l'adresse I2C change en fonction de GND ou VDD) Capteur 6 broches (VDDIO) -> Raspi pin 1 Capteur 10 broches (GND) -> Raspi 6ème broche

C'est désordonné, mais ça ressemble à ça. MPU9250.png

Activer I2C avec Raspberry pi

Réglez dans le menu de configuration du système d'exploitation.

$ sudo raspi-config

Sélectionnez le menu dans l'ordre "9 Options avancées" -> "A7 I2C". Il vous sera demandé "Souhaitez-vous que l'interface ARM I2C soit activée?", Alors sélectionnez oui. On vous demandera "Souhaitez-vous que le module du noyau I2C soit chargé par défaut?", Alors sélectionnez oui.

Puis éditez /boot/config.txt.

$ sudo vi /boot/config.txt
...Ajout du contenu suivant
dtparam=i2c_arm=on

De plus, modifiez / etc / modules.

$ sudo vi /etc/modules
...Ajout du contenu suivant
snd-bcm2835
i2c-dev

Une fois les paramètres définis, redémarrez Raspy. Assurez-vous que le module du noyau est chargé après le redémarrage.

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

Installer des outils

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

Confirmation d'adresse

Vérifiez l'adresse du capteur.

$ sudo i2cdetect -y 1	(Lorsque la broche 5 est connectée à GND)
     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: -- -- -- -- -- -- -- --

Reconnu à l'adresse 0x68. Ce MPU-9250 possède un capteur magnétique intégré AK8963 fabriqué par Asahi Kasei Electronics. Dans l'état initial, AK8963 n'est pas accessible, mais il est accessible par I2C en manipulant certains registres. Définissez le registre avec le script python ci-dessous.

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

import smbus
import time

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

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

#Fonction capteur magnétique avec I2C(AK8963)Accéder à(BYPASS_EN=1)
bus.write_i2c_block_data(address, 0x37, [0x02])
time.sleep(0.1)

Vérifiez à nouveau l'adresse après avoir exécuté le script.

$ sudo i2cdetect -y 1	(Lorsque la broche 5 est connectée à VDD)
     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 L'adresse 0x0C pour l'accès est affichée.

Obtenez une accélération

Obtenez des données brutes

Ici J'ai été autorisé à faire référence.

Selon la pièce jointe de Strawberry Linux

Au départ, il est en mode veille et aucune détection n'est effectuée. Tout d'abord, écrivez 0x00 à l'adresse interne 0x6B du MPU-9250. De plus, 0x02 est écrit à l'adresse interne 0x37. Cela démarrera l'opération et activera la communication I2C avec le capteur magnétique. Dans cet état, les données d'accélération X, Y, Z du gyroscope X, Y, Z sont stockées dans 14 octets à partir du registre interne 0x3B. Chaque donnée est de 16 bits et les 8 bits supérieurs sont alignés en premier. L'accélération est facile car vous pouvez déplacer le capteur pour voir l'accélération gravitationnelle. Le gyroscope doit être tourné, ce qui peut être un problème.

Pourquoi est-ce 14 octets alors que c'est 16 bits et 6 axes? Je me demandais, mais en regardant la fiche technique, il semble que la température puisse également être mesurée, qui est de 2 octets.

Pour l'instant, l'accélération de 6 octets est acquise et affichée.

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

import smbus
import time

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

#Réinitialiser le registre
bus.write_i2c_block_data(address, 0x6B, [0x80])
time.sleep(0.1)		

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

#Obtenez des données brutes
while True:
	data 	= bus.read_i2c_block_data(address, 0x3B ,6)
	rawX 	= data[0] << 8 | data[1]	#Bit supérieur en premier
	rawY	= data[2] << 8 | data[3]	#Bit supérieur en premier
	rawZ	= data[4] << 8 | data[5]	#Bit supérieur en premier
	print "%+8.7f" % rawX + "	",
	print "%+8.7f" % rawY + "	",
	print "%+8.7f" % rawZ
	time.sleep(1)

Avec cela, nous avons pu confirmer que les données étaient sorties en continu.

Calculer g

Calculez l'accélération à partir des données brutes. Le réglage par défaut semble sortir dans la plage de ± 2g. Sur cette base, j'ai calculé comme suit. Cependant, la valeur affichée est étrange.

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

Selon diverses investigations, la valeur sortie par le capteur est de type non signé, il semble donc qu'il soit nécessaire de la convertir en type signé pour exprimer une valeur négative.

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

import smbus
import time

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

#Convertir non signé en signé(16 bits limité)
def u2s(unsigneddata):
    if unsigneddata & (0x01 << 15) : 
        return -1 * ((unsigneddata ^ 0xffff) + 1)
    return unsigneddata

#Réinitialiser le registre
bus.write_i2c_block_data(address, 0x6B, [0x80])
time.sleep(0.1)		

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

#Obtenez des données brutes
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)

Désormais, la direction de l'axe Z produit presque 1g.

Changer la plage de mesure

Lorsque vous faites pivoter le capteur, il atteint 2g de manière inattendue. Alors, changeons la plage de mesure. Selon la fiche technique, il semble que vous puissiez spécifier une plage de 2,4,8,16.

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

import smbus
import time

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

#Convertir non signé en signé(16 bits limité)
def u2s(unsigneddata):
    if unsigneddata & (0x01 << 15) : 
        return -1 * ((unsigneddata ^ 0xffff) + 1)
    return unsigneddata

#Réinitialiser le registre
bus.write_i2c_block_data(address, 0x6B, [0x80])
time.sleep(0.1)		

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

#Réglez la plage du capteur d'accélération sur ± 8g
bus.write_i2c_block_data(address, 0x1C, [0x08])

#Obtenez des données brutes
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, maintenant vous pouvez obtenir la valeur même si vous vous balancez beaucoup.

Calibrer l'accélération

Selon la pièce jointe de Strawberry Linux

Comme il y a des variations dans le capteur, la valeur observée ne devient pas 0 même si l'accélération = 0 g, le gyroscope = 0 ° sec et le magnétisme = 0 μT, et les valeurs sont légèrement différentes. La plage de décalage autorisée est indiquée sur la feuille de données, la plage est donc normale. Il sera nécessaire que le logiciel fasse des ajustements en soustrayant le décalage.

Il y a. Certes, même si le capteur est fixe, l'accélération sur les axes X et Y ne sera pas nulle. Selon la fiche technique, il semble que vous puissiez définir la valeur de décalage sur le registre, mais essayez d'abord l'étalonnage côté python.

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

import smbus
import time

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

#Convertir non signé en signé(16 bits limité)
def u2s(unsigneddata):
    if unsigneddata & (0x01 << 15) : 
        return -1 * ((unsigneddata ^ 0xffff) + 1)
    return unsigneddata

#Réinitialiser le registre
bus.write_i2c_block_data(address, 0x6B, [0x80])
time.sleep(0.1)		

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

#Réglez la plage du capteur d'accélération sur ± 8g
bus.write_i2c_block_data(address, 0x1C, [0x08])

#Calculer la valeur d'étalonnage
print "Accel calibration start"
_sum	= [0,0,0]

#Prenez un échantillon de données réelles
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])

#Décalage de la valeur moyenne
offsetAccelX 	= -1.0 * _sum[0] / 1000
offsetAccelY 	= -1.0 * _sum[1] / 1000
#L'axe Z soustrait la gravité, vraiment 1.0 est suspect
offsetAccelZ 	= -1.0 * ((_sum[2] / 1000 ) - 1.0)
print "Accel calibration complete"

#Obtenez des données brutes
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, ce n'est pas exactement 0, mais c'est mieux qu'au début. Je ne sais pas si vous pouvez utiliser la valeur moyenne pour le décalage.

Autre

Même après l'étalonnage, si le capteur est fixe et qu'une détection continue est effectuée, la valeur continue de fluctuer légèrement. Détectez-vous une onde inconnue!? C'est effrayant. .. .. Peut-être que le capteur est trop sensible pour capter le bruit électrique. Il y avait "Réglage du filtre passe-bas de l'accéléromètre" dans la liste des registres de la fiche technique, donc si vous jouez avec cela, vous pouvez obtenir une valeur plus stable. Je n'y ai pas touché cette fois car le temps était écoulé.

Obtenez la température

Il semble que la température puisse être prise avec beaucoup d'efforts, alors je l'ai essayé.

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

import smbus
import time

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

#Réinitialiser le registre
bus.write_i2c_block_data(address, 0x6B, [0x80])
time.sleep(0.1)		

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

#Obtenez des données brutes
while True:
	data 	= bus.read_i2c_block_data(address, 0x65 ,2)
	raw 	= data[0] << 8 | data[1]
	#La formule de calcul de la température est la suivante à partir de la fiche technique
	# ((TEMP_OUT – RoomTemp_Offset)/Temp_Sensitivity) + 21degC
	temp 	= (raw / 333.87) + 21 
	print str(temp)

Avec cela, la valeur qui semble être la température ambiante a été obtenue. La formule de calcul de la température à partir des données brutes est écrite dans la fiche technique, mais les valeurs essentielles de RoomTemp_Offset et Temp_Sensitivity ne sont pas répertoriées, donc [ici](https://ryusakura.wordpress.com/2015/04/ 23 / raspberrypie% E3% 81% A8mpu-9250% E3% 81% AE% E6% B8% A9% E5% BA% A6% E3% 82% BB% E3% 83% B3% E3% 82% B5 /) J'ai fait référence à l'article. Il semble que le suivi ne soit pas très bon et que la valeur ne change pas facilement même si vous la tenez avec votre main.

Obtenez une vitesse angulaire

Obtenez des données

La méthode est la même que pour l'accélération. Il calcule également les valeurs dps à partir des données brutes, corrige la plage de mesure et calcule les valeurs d'étalonnage.

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

import smbus
import time

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

#Réinitialiser le registre
bus.write_i2c_block_data(address, 0x6B, [0x80])
time.sleep(0.1)		

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

#Corrigez la plage de mesure à 1000 dps
bus.write_i2c_block_data(address, 0x1B, [0x10])

#Facteur pour calculer les dps
gyroCoefficient	= 1000 / float(0x8000)

#Calculer la valeur d'étalonnage
print "Gyro calibration start"
_sum	= [0,0,0]

#Prenez un échantillon de données réelles
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])

#Décalage de la valeur moyenne
offsetGyroX 	= -1.0 * _sum[0] / 1000
offsetGyroY 	= -1.0 * _sum[1] / 1000
offsetGyroZ 	= -1.0 * _sum[2] / 1000
print "Gyro calibration complete"

#Obtenez des données
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)

Autre

Comme pour le capteur d'accélération, la valeur dps fluctue même si le capteur est fixe. C'est juste une erreur vue à partir de la plage de mesure, mais cela ne semble pas s'installer. .. .. J'espère que cela pourra également être amélioré en définissant DLPF_CFG dans le registre 0x1A, mais je n'ai pas pu l'essayer cette fois.

Acquisition de capteur magnétique

Le capteur magnétique est AK8963 fabriqué par Asahi Kasei Electronics. J'apprécie vraiment la fiche technique japonaise. .. ..

C'est dommage, mais je pensais que le capteur était le seul fabricant japonais, mais même si j'ai vérifié le module d'échantillonnage connecté à raspi, il n'a été fabriqué qu'à l'étranger. Je veux que les fabricants japonais fassent de leur mieux.

Ainsi, avec l'AK8963, il est facile de prendre les données une seule fois, mais lorsque vous essayez d'effectuer une détection continue, diverses procédures sont gênantes. Je veux dire, c'est un design maniaque, ou vous pouvez faire des réglages étrangement détaillés. .. ..

Il existe quatre modes de mesure: simple coup, continu 1 (8 Hz), continu 2 (100 Hz) et déclenchement externe. De plus, le nombre de bits pour sortir la valeur mesurée peut être sélectionné en 16 bits / 14 bits. En mode de prise de vue unique, une fois la détection effectuée, il passera à la mise hors tension, vous devez donc redéfinir le mode de prise de vue unique. En particulier dans le mode de détection continue, les dernières (nouvelles) données sont supprimées jusqu'à ce que les données précédentes soient récupérées. Les données récupérées doivent être vérifiées à chaque fois pour détecter tout débordement. Il semble que la valeur correcte ne sortira pas si elle déborde.

De plus, j'étais accro au fait que les bits inférieurs peuvent être acquis en premier lors de la lecture des données du registre. Veuillez noter que le bit supérieur vient en premier pour l'accélération et la vitesse angulaire.

Avec ce sentiment, j'ai pensé essayer d'extraire uniquement la partie du capteur magnétique et de l'écrire, mais c'est assez difficile, alors veuillez lire l'opération classifiée.

Il est difficile de juger si le capteur magnétique est correct même si la valeur est obtenue. Selon wiki Il semble que "la force du géomagnétisme à 50 degrés de longitude: 58 μT", donc je ne pense pas que ce soit une valeur très différente.

Aussi, je voulais calculer l'orientation de chaque axe μT, mais je ne pouvais pas non plus le gérer. Est-ce la prochaine tâche?

Faites un cours ensemble

Classez les résultats jusqu'à présent ensemble.

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

import smbus
import time

#MPU de Strawberry Linux-Classe pour obtenir des données de 9250 avec I2C(python 2)
# https://strawberry-linux.com/catalog/items?code=12250
#
# 2016-05-03 Boyaki Machine
class SL_MPU9250:
	#Déclaration constante
	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			#Arrêt du capteur magnétique
	MAG_MODE_SERIAL_1	= 1			#Capteur magnétique 8Hz mode de mesure continue
	MAG_MODE_SERIAL_2	= 2			#Capteur magnétique 100 Hz mode de mesure continue
	MAG_MODE_SINGLE		= 3			#Mode de mesure en un seul coup avec capteur magnétique
	MAG_MODE_EX_TRIGER	= 4			#Mode de mesure de déclenchement externe du capteur magnétique
	MAG_MODE_SELF_TEST	= 5			#Mode d'auto-test du capteur magnétique

	MAG_ACCESS			= False		#Accès au capteur magnétique
	MAG_MODE			= 0			#Mode capteur magnétique
	MAG_BIT				= 14		#Nombre de bits émis par le capteur magnétique

	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

	#constructeur
	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)	#Un coefficient qui convertit la valeur décimale détectée en dps
		self.accelCoefficient	= self.accelRange / float(0x8000)	#Un coefficient qui convertit la valeur décimale détectée en g
		self.magCoefficient16	= self.magRange   / 32760.0			#Un coefficient qui convertit la valeur décimale détectée en μT(À 16 bits)
		self.magCoefficient14	= self.magRange   / 8190.0			#Un coefficient qui convertit la valeur décimale détectée en μT(À 14 bits)

	#Réinitialise les registres à leurs paramètres par défaut.
	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)		

	#Rend le registre mesurable.
	def powerWakeUp(self):
		# PWR_MGMT_Effacer 1
		self.bus.write_i2c_block_data(self.address, self.REG_PWR_MGMT_1, [0x00])
		time.sleep(0.1)
		#Fonction capteur magnétique avec I2C(AK8963)Accéder à(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)

	#Réglez le registre du capteur magnétique
	def setMagRegister(self, _mode, _bit):		
		if self.MAG_ACCESS == False:
			#Soulevez une exception car l'accès au capteur magnétique n'est pas activé
			raise Exception('001 Access to a sensor is invalid.')

		_writeData	= 0x00
		#Réglage du mode de mesure
		if _mode=='8Hz':			#Mode de mesure continue 1
			_writeData 		= 0x02
			self.MAG_MODE 	= self.MAG_MODE_SERIAL_1
		elif _mode=='100Hz':		#Mode de mesure continue 2
			_writeData		= 0x06
			self.MAG_MODE 	= self.MAG_MODE_SERIAL_2
		elif _mode=='POWER_DOWN':	#Mode de mise hors tension
			_writeData		= 0x00
			self.MAG_MODE 	= self.MAG_MODE_POWERDOWN
		elif _mode=='EX_TRIGER':	#Mode de mesure de déclenchement externe
			_writeData		= 0x04
			self.MAG_MODE 	= self.MAG_MODE_EX_TRIGER
		elif _mode=='SELF_TEST':	#Mode d'auto-test
			_writeData		= 0x08
			self.MAG_MODE 	= self.MAG_MODE_SELF_TEST
		else:	# _mode='SINGLE'	#Mode de mesure unique
			_writeData 		= 0x01
			self.MAG_MODE 	= self.MAG_MODE_SINGLE
		
		#Nombre de bits à sortir
		if _bit=='14bit':			#Sortie 14 bits
			_writeData 		= _writeData | 0x00
			self.MAG_BIT	= 14
		else:	# _bit='16bit'		#Sortie 16 bits
			_writeData		= _writeData | 0x10
			self.MAG_BIT 	= 16

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

	#Définit la plage de mesure de l'accélération. La granulométrie de mesure devient grossière dans une large plage.
	# 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)

		#Réinitialiser la valeur de décalage(Pour empêcher l'héritage des valeurs de décalage passées)
		self.offsetAccelX 		= 0
		self.offsetAccelY 		= 0
		self.offsetAccelZ 		= 0

		#Je pense qu'il vaut mieux utiliser l'étalonnage, mais cela prend du temps.
		if _calibration == True:
			self.calibAccel(1000)
		return

	#Réglez la plage de mesure du gyroscope. La granulométrie de mesure devient grossière dans une large plage.
	# 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)

		#Réinitialiser la valeur de décalage(Pour empêcher l'héritage des valeurs de décalage passées)
		self.offsetGyroX 		= 0
		self.offsetGyroY 		= 0
		self.offsetGyroZ 		= 0

		#En fait, il est préférable d'utiliser l'étalonnage, mais cela prend du temps.
		if _calibration == True:
			self.calibGyro(1000)
		return

	#Réglez le filtre passe-bas du capteur d'accélération.
	# def setAccelLowPassFilter(self,val):		

	#Si vous essayez d'utiliser les données du capteur telles quelles, elles seront traitées comme non signées, elles seront donc converties en signées.(16 bits limité)
	def u2s(self,unsigneddata):
	    if unsigneddata & (0x01 << 15) : 
	        return -1 * ((unsigneddata ^ 0xffff) + 1)
	    return unsigneddata

	#Obtenez la valeur d'accélération
	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

	#Obtenez la valeur du gyroscope.
	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:
			#Le capteur magnétique n'est pas valide.
			raise Exception('002 Access to a sensor is invalid.')

		#Pré-traitement
		if self.MAG_MODE==self.MAG_MODE_SINGLE:
			#Le mode de mesure unique sera Power Down dès que la mesure est terminée, changez donc à nouveau de mode.
			if self.MAG_BIT==14:				#Sortie 14 bits
				_writeData 		= 0x01
			else:								#Sortie 16 bits
				_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:
				#Détecter à nouveau parce qu'il y a un dépassement de données
				self.bus.read_i2c_block_data(self.addrAK8963, 0x09 ,1)

		elif self.MAG_MODE==self.MAG_MODE_EX_TRIGER:
			#Non mis en œuvre
			return

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

		#Vérifiez le registre ST1 pour voir si les données peuvent être lues.
		status 	= self.bus.read_i2c_block_data(self.addrAK8963, 0x02 ,1)
		while (status[0] & 0x01) != 0x01:
			#Attendez que les données soient prêtes
			time.sleep(0.01)
			status 	= self.bus.read_i2c_block_data(self.addrAK8963, 0x02 ,1)

		#Lecture des données
		data 	= self.bus.read_i2c_block_data(self.addrAK8963, 0x03 ,7)
		rawX 	= self.u2s(data[1] << 8 | data[0])	#Bit inférieur en premier
		rawY	= self.u2s(data[3] << 8 | data[2])	#Bit inférieur en premier
		rawZ	= self.u2s(data[5] << 8 | data[4])	#Bit inférieur en premier
		st2		= data[6]

		#Contrôle de débordement
		if (st2 & 0x08) == 0x08:
			#La valeur correcte n'est pas obtenue en raison d'un débordement
			raise Exception('004 Mag sensor over flow')

		#Conversion en μT
		if self.MAG_BIT==16:	#En sortie 16 bits
			rawX 	= rawX * self.magCoefficient16
			rawY	= rawY * self.magCoefficient16
			rawZ	= rawZ * self.magCoefficient16
		else:					#Au moment de la sortie 14 bits
			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

	#Calibrer le capteur d'accélération
	#Je pense qu'il faut tenir compte de la latitude, de l'altitude, de la topographie, etc., mais c'est simple.
	#En supposant que la gravité est appliquée correctement dans la direction de l'axe z et qu'aucune accélération autre que la gravité n'est générée
	def calibAccel(self, _count=1000):
		print "Accel calibration start"
		_sum	= [0,0,0]

		#Prenez un échantillon de données réelles
		for _i in range(_count):
			_data 	= self.getAccel()
			_sum[0] += _data[0]
			_sum[1] += _data[1]
			_sum[2] += _data[2]

		#Décalage de la valeur moyenne
		self.offsetAccelX 	= -1.0 * _sum[0] / _count
		self.offsetAccelY 	= -1.0 * _sum[1] / _count
		self.offsetAccelZ 	= -1.0 * ((_sum[2] / _count ) - 1.0)	#Soustraire la gravité

		#Je veux enregistrer la valeur de décalage dans le registre, mais je ne connais pas l'opération, donc la mise en œuvre est suspendue

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

	#Calibrer le capteur gyroscopique
	#Hypothèse selon laquelle la rotation ne se produit pas dans chaque axe
	def calibGyro(self, _count=1000):
		print "Gyro calibration start"
		_sum	= [0,0,0]

		#Prenez un échantillon de données réelles
		for _i in range(_count):
			_data 	= self.getGyro()
			_sum[0] += _data[0]
			_sum[1] += _data[1]
			_sum[2] += _data[2]

		#Décalage de la valeur moyenne
		self.offsetGyroX 	= -1.0 * _sum[0] / _count
		self.offsetGyroY 	= -1.0 * _sum[1] / _count
		self.offsetGyroZ 	= -1.0 * _sum[2] / _count

		#Je veux enregistrer la valeur de décalage dans le registre, mais je ne connais pas l'opération, donc la mise en œuvre est suspendue

		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)

Problèmes

Si vous utilisez la classe ci-dessus, vous pouvez obtenir les données en continu pour le moment. Cependant, afin de réaliser une détection plus précise, je pense qu'il est nécessaire d'utiliser le décalage attaché à la puce et la fonction de filtre passe-bas. J'aimerais l'essayer si j'ai le temps dans le futur.

Lorsque seules l'accélération et la vitesse angulaire étaient détectées en continu avec une source d'échantillon utilisant la classe ci-dessus, 100 Hz pouvait être atteint sans aucun problème, mais 200 Hz avaient tendance à être légèrement retardés. Je pense qu'il sera possible d'effectuer une détection avec une fréquence plus élevée en concevant également l'implémentation ici.

Vous ne vous souciez peut-être pas beaucoup de son utilisation avec raspi, mais si vous effectuez une détection avec une fréquence et une précision élevées, la consommation d'énergie augmentera, il est donc nécessaire de sélectionner un mode approprié en fonction de l'utilisation réelle. J'aimerais savoir quel mode consomme combien d'énergie .. Je me demande si cela prendra du temps alors ...

Si c'est utile, je suis heureux.

Recommended Posts

Utilisez le «module de capteur 9 axes MPU-9250 (numéro de pièce du fabricant: MPU-9250)» fabriqué par Strawberry Linux avec Rasberry pi 3.
Utilisez le «module de capteur d'éclairage TSL2561 (numéro de pièce du fabricant: TSL2561)» fabriqué par Strawberry Linux avec Rasberry pi 3 (résumé)
Utilisez "TSL2561 Illumination Sensor Module Manufacturer Part Number: TSL2561" fabriqué par Strawberry Linux avec Raspberry pi 3 (essai et erreur)
Utiliser le capteur de mouvement PIR avec Raspberry Pi