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
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.
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
...
$ sudo apt-get install i2c-tools python-smbus
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.
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.
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.
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.
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.
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é.
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.
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)
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.
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?
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)
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