Lire les informations du contrôleur T’REX

Protocole de communication avec le T’REX

Le bus I²C nous permet d’échanger une série d’octet entre 2 cartes, mais ne propose pas de protocole de communication à proprement parler. Le code d’exemple du T’REX propose un protocole pour la réception d’informations :

Le T’REX peut transmettre 24 octets qui contient :

  • Un indicateur d’erreur
  • La tension de la batterie
  • L’intensité des moteurs
  • Le compteur des encodeurs (non installés par défaut sur le Wild Thumper)
  • Les informations brutes de l’accéléromètre
  • Une détection d’impact

Certaines de ces informations sont contenues sur 16 bits. Nous devons combiner deux octets pour récupérer la valeur.

Octet Nom Position Description
1 Start byte Cet octet doit être 0x0F (15 décimal)
2 Error flag 0x00 indique qu’il n’y a pas d’erreur. Sinon, il faut regarder le/les bits qui sont à 1 :

  • BIT 0: Start byte not received or incorrect data packet size
  • BIT 1: PWM frequency was not 1-7
  • BIT 2: Left or right motor speed was not -255 to +255
  • BIT 3: One or more servo positions was not -2400 to +2400
  • BIT 4: Impact sensitivity not 0-1023
  • BIT 5: Low battery was not 550 to 3000 (5.5V to 30V)
  • BIT 6: I²C slave address was not 0-127
  • BIT 7: I²C speed not 0 or 1 (100kHz or 400kHz)
3 Battery voltage High byte Un entier qui correspond à la tension de la batterie x 100, en volt. Par exemple, une valeur de 1527 correspond à 15,27V
4 Low byte
5 Left motor current High byte Intensité utilisée par les moteurs gauche, en mA
6 Low byte
7 Left encoder count High byte Valeur de l’encodeur du côté gauche (D6). En activant le frein gauche avec la vitesse gauche à 0, cette valeur se réinitialise
8 Low byte
9 Right motor current High byte Intensité utilisée par les moteurs droit, en mA
10 Low byte
11 Right encoder count High byte Valeur de l’encodeur du côté droit (D5). En activant le frein droit avec la vitesse droite à 0, cette valeur se réinitialise
12 Low byte
13 Accelerometer X-axis High byte Données brutes de l’accéléromètre qui peut être utilisée pour déterminer l’angle et l’accélération du robot
14 Low byte
15 Accelerometer Y-axis High byte
16 Low byte
17 Accelerometer Z-axis High byte
18 Low byte
19 Impact X-axis High byte La carte lit les valeurs de l’accéléromètre toutes les 2 ms pour déterminer s’il y a un changement significatif de valeur. Si un impact est détecté, l’octet correspondant à l’axe concerné change de valeur.
20 Low byte
21 Impact Y-axis High byte
22 Low byte
23 Impact Z-axis High byte
24 Low byte

Communication avec Python

Dans cet article je fais souvent référence au protocole I²C, mais l’implémentation que l’on rencontre sur les systèmes monocartes sous Linux (Raspberry Pi, BeagleBone Black, etc.) est plutôt un dérivé de ce protocole nommée SMBus. Les différences essentielles sont des limitations dans les tensions autorisées (3.3V max) ou les fréquences de communication (10 à 100 kHz seulement).

Pigpio

Il existe une bibliothèque Python (python-smbus) permettant d’utiliser directement le protocole dans un script Python. Mais avec cette bibliothèque, je n’ai pas réussi à récupérer les 24 octets de statut. J’ai contourné ce problème en utilisant la bibliothèque pigpio

Pour l’installer, il faut installer les paquets suivants :

sudo apt-get update
sudo apt-get install pigpio python-pigpio python3-pigpio

Pour vérifier qu’il s’est bien installé, on vérifie la version :

pigpiod -v

Il faut que le daemon pigpiod soit démarré pour pouvoir l’utiliser. On peut soit la démarrer manuellement avec

sudo pigpiod

ou le lancer au démarrage du système avec

sudo systemctl enable pigpiod
Source :

http://abyz.me.uk/rpi/pigpio/download.html

Le code

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

from __future__ import division # Pour division float
import pigpio

# Cablage
TREX_ADDRESS = 0x07
SDA=2 # Pin no 3
SCL=3 # Pin no 5

# Connexion de pigpiod
pigpio = pigpio.pi() # Connect to Pi.

def __trex_status():
    '''
    Envoi une requête de statut au T'REX
    Retourne une liste d'octet
    '''
    
    # Vérification de la connexion de pigpiod
    if not pigpio.connected:
        exit(0)
    
    # Préparation de la requête Bit Bang
    pigpio.bb_i2c_open(SDA, SCL, baud=100000)
    
    # 4, TREX_ADDRESS : Set I2C adress to TREX_ADDRESS
    # 2 : Start condition
    # 6, 24 : Read 24 bytes of data
    # 3 : Stop condition
    # 0 No more commands
    (count, data) = pigpio.bb_i2c_zip(SDA, [4, TREX_ADDRESS, 2, 6, 24, 3, 0])
    
    # Fin de la requête Bit Bang    
    pigpio.bb_i2c_close(SDA)

    # Déconnexion de pigpiod
    pigpio.stop()
    
    if not data:
        print("Impossible de communiquer avec le T'REX")
        exit(0)
        
    return data

def __hight_low_int(hight_byte, low_byte):
    '''
    Convertit deux octets (high et low) en entier
    '''
    result = (hight_byte << 8) + low_byte # Gestion des entiers signés if result > 32768 :
        result -= 65536
    
    return result

def trex_status():
    '''
    Envoi une requête de statut au T'REX
    
    Return tuple: battery_voltage, left_motor_current, left_motor_encoder, right_motor_current, right_motor_encoder, accelerometer_x, accelerometer_y, accelerometer_z, impact_x, impact_y, impact_z
    '''
    b = __trex_status()
    # pprint(b)
    battery_voltage =  (__hight_low_int(b[2], b[3])/100)
    left_motor_current =  __hight_low_int(b[4], b[5])
    left_motor_encoder =  __hight_low_int(b[6], b[7])
    right_motor_current =  __hight_low_int(b[8], b[9])
    right_motor_encoder =  __hight_low_int(b[10], b[11])
    accelerometer_x =  __hight_low_int(b[12], b[13])
    accelerometer_y =  __hight_low_int(b[14], b[15])
    accelerometer_z =  __hight_low_int(b[16], b[17])
    impact_x =  __hight_low_int(b[18], b[19])
    impact_y =  __hight_low_int(b[20], b[21])
    impact_z =  __hight_low_int(b[22], b[23])
    return battery_voltage, left_motor_current, left_motor_encoder, right_motor_current, right_motor_encoder, accelerometer_x, accelerometer_y, accelerometer_z, impact_x, impact_y, impact_z

    
if __name__ == '__main__':
    battery_voltage, left_motor_current, left_motor_encoder, right_motor_current, right_motor_encoder, accelerometer_x, accelerometer_y, accelerometer_z, impact_x, impact_y, impact_z = trex_status()
    print("Battery voltage: " + str(battery_voltage) + " V")
    print("Left motor current: " + str(left_motor_current) + " mA")
    print("Left motor encoder: " + str(left_motor_encoder))
    print("Right motor current: " + str(right_motor_current) + " mA")
    print("Right motor encoder: " + str(right_motor_encoder))
    print("Accelerometer X-axis: " + str(accelerometer_x))
    print("Accelerometer Y-axis : " + str(accelerometer_y))
    print("Accelerometer Z-axis : " + str(accelerometer_z))
    print("Impact X-axis: " + str(impact_x))
    print("Impact Y-axis: " + str(impact_y))
    print("Impact Z-axis: " + str(impact_z))

Source :

GNU Linux magazine HS n°75
https://www.raspberrypi.org/forums/viewtopic.php?t=129678
Documentation de pigpio

Troubleshooting

Can’t connect to pigpio at localhost(8888)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Can't connect to pigpio at localhost(8888)

Did you start the pigpio daemon? E.g. sudo pigpiod

Did you specify the correct Pi host/port in the environment
variables PIGPIO_ADDR/PIGPIO_PORT?
E.g. export PIGPIO_ADDR=soft, export PIGPIO_PORT=8888

Did you specify the correct Pi host/port in the
pigpio.pi() function? E.g. pigpio.pi('soft', 8888)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Le daemon n’est pas démarré. Démarrez le avec sudo pigpiod ou au démarrage du système avec sudo systemctl enable pigpiod

pigpio.error: ‘GPIO already in use’

Il n’y a pas eu de bb_i2c_close(SDA)
Il faut kill le daemon avec sudo killall pigpiod, puis le relancer avec sudo pigpiod

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *