Interfacer le capteur de particules SPS30

Interfacer le capteur de particules SPS30

Sensirion vient de sortir le SPS30, un capteur de particules qui offre une interface série et une interface I2C. Alors évidement, il n'a pas fallu longtemps avant qu'on nous demande s'il était possible de l'interfacer avec des modules Yoctopuce.





Le compteur de Particule SPS30 de Sensirion se présente sous la forme d'une petite boîte verte d'environ 4x4x1cm. Sa finalité est de compter les particules de poussière en suspension dans l'air en fonction de leur taille. Il est capable de mesurer les particules PM1, PM2.5, PM4 et PM10, ce qui correspond respectivement aux particules dont la taille est inférieure à 1, 2.5, 4.0 et 10.0µm.

Le capteur SPS30 de Sensirion
Le capteur SPS30 de Sensirion



En théorie, pour interfacer ce capteur, il suffit d'utiliser un des modules d'interface électrique qui correspondent, à savoir un Yocto-Serial ou un Yocto-I2C. Etudions ces options d'un peu plus près, voulez-vous?

Utilisation avec un Yocto-Serial

Le SPS30 peut être interfacé avec un lien série TTL, ce qui peut être réalisé avec un Yocto-Serial. Pour cela le capteur doit être alimenté en 5V, la communication doit se faire à 115200 bauds avec un niveau de signal à 3.3 ou 5.5V.

Branchement entre le Yocto-Serial et le SPS30
Branchement entre le Yocto-Serial et le SPS30


Configuration du Yocto-Serial pour communiquer avec le SPS30
Configuration du Yocto-Serial pour communiquer avec le SPS30


Le protocole est le suivant:

  • Lancer les mesures en envoyant la trame 7E0000020103F97E
  • Interroger périodiquement le capteur avec la trame 7E000300FC7E
  • Le capteur répond alors avec une trame qui a une structure un peu particulière

    • Un byte = 0x7E;
    • L'adresse du capteur sur un byte (toujours 0)
    • La commande (0x03)
    • Longueur des données (normalement 40)
    • Les données
    • Checksum sur 1 byte
    • Byte final = 0x7E;


Les données sont une série de 10 nombres encodés au format cbig-endian float IEEE754, soit 4 bytes par float. Cette série correspond respectivement aux valeurs PM1.0, PM2.5, PM4.0, PM10 (en µg/m3) PM0.5, PM1.0, PM2.5, PM4.0 et PM10 (en nombre/ m3) et Taille typique (en µm). Par contre, avant d'envoyer ces données, le capteur a potentiellement effectué un certain nombre de substitutions qu'il faudra inverser avant de décoder les données.

  • 0x7E a été remplacé par 0x7D, 0x5E
  • 0x7D a été remplacé par 0x7D, 0x5D
  • 0x11 a été remplacé par 0x7D, 0x31
  • 0x13 a été remplacé par 0x7D, 0x33

Voici un bout de code Python qui configure un Yocto-Serial, interroge le SPS30 et affiche la réponse.

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, sys
from struct import *
from yocto_api import *
from yocto_serialport import *
from yocto_poweroutput import *

def decodeBlob(blob):
  # revert Sensirion's Byte-Stuffing
  blob =  blob.replace("7D5E","7E")
  blob =  blob.replace("7D31","11")
  blob =  blob.replace("7D33","13")
  blob =  blob.replace("7D5D","7D")
  # consistency checks
  if (len(blob) <16): return print("Frame  too short")
  if (blob[:2] != "7E"):return  print("First byte is not 7E")
  if (blob[-2:] != "7E"):return print("Last byte is not 7E")
  size=  int(blob[8:10],16)
  if len(blob) != 2*(7 + size):return  print("invalid frame size")
  if (size!=40):return  print("suspicious data size")
  # at this point, blob data contains 10 hex-encoded floats
  # starting at character #10. note : 1 float = 4 bytes = 8 characters
  keys = ['MassPM1','MassPM2.5', 'MassPM4', 'MassPM10', 'CountPM0.5',
        'CountPM1', 'CountPM2.5' ,'CountPM4', 'CountPM10','TypSize']
  # lets use some python black magic to convert data into a dictionnary
  values = unpack('!ffffffffff', bytes.fromhex(blob[10:90]))
  return dict(zip(keys, values))

errmsg = YRefParam()
# connects through the virtualhub, so one can use it
# monitor communications
if YAPI.RegisterHub("127.0.0.1", errmsg) != YAPI.SUCCESS:
    sys.exit("init error" + errmsg.value)

## assumes there is only one Yoctopuce serial port available
## otherwise one has to use logical names.
serial = YSerialPort.FirstSerialPort()
if serial is None :
     sys.exit("No Serial Port found")

# configure serial port an power supply
serial.set_protocol("Frame:10ms")
serial.set_serialMode("115200,8N1")
serial.reset()
power = YPowerOutput.FindPowerOutput(serial.get_module().get_serialNumber()+".powerOutput");
power.set_voltage(YPowerOutput.VOLTAGE_OUT5V)
serial.set_voltageLevel( YSerialPort.VOLTAGELEVEL_TTL3V)

serial.queryHex("7E0000020103F97E", 100) # start automatic  measurement
while True:
  YAPI.Sleep(1000,errmsg) # each measure takes ~ 1 sec
  blob = serial.queryHex("7E000300FC7E", 100) # ask or result
  data = decodeBlob(blob)  # decode result
  print(data) # tadaaa !


A propos des jobs

Sensirion a choisi d'utiliser des bytes spéciaux pour délimiter les trames du protocole, ce qui les a ensuite obligés à effectuer des substitutions pour éviter que ces caractères spéciaux ne se retrouve au beau milieu des trames. Cette particularité nous empêche d'écrire un job autonome qui tournerait dans le Yocto-Serial, parce que le système de jobs ne permet pas de définir ces substitutions. Modifier le firmware du Yocto-Serial pour qu'il puisse le faire ne fait pas beaucoup de sens: c'est un cas un peu trop particulier.

Utilisation avec un Yocto-I2C

Le SPS30 peut aussi être interfacé avec un lien I2C, ce qui relève des compétences du Yocto-I2C. Pour cela, le capteur doit être alimenté en 5V, la communication doit être se faire à 100kps. Les signaux peuvent être en 3.3V ou 5.5V. Attention le module ne supporte apparemment pas la condition "Restart".

Branchement entre le Yocto-I2C et le SPS30
Branchement entre le Yocto-I2C et le SPS30


Configuration du Yocto-I2C pour communiquer avec le SPS30
Configuration du Yocto-I2C pour communiquer avec le SPS30



Pour lancer les mesures, il suffit d'envoyer la séquence

{S}D200100300AC{P}


Ensuite, pour lire les mesures il suffit d'envoyer la séquence suivante à intervalles réguliers.

{S}D20300{P}


Le capteur répond par une séries de 10 nombres en virgule flottante simple précision, et qui par conséquent, sont censés tenir sur 4 bytes chacun. Malheureusement, ici aussi Sensirion a un peu innové: chacun de ces nombres est encodé sous la forme de deux bytes, un CRC, encore deux bytes et encore un CRC. Chaque float prend donc 6 bytes, dont un byte de CRC en plein milieu. Depuis bientôt dix ans qu'on travaille avec des capteurs Sensirion, on avait bien remarqué qu'ils adoraient mettre des CRC un peu partout, mais là, franchement, ça frise le ridicule.

Quoi qu'il en soit, on a modifié le firmware du Yocto-I2C (version 42159) pour qu'il soit capable de lire ces floats Sensirion encodés sur 6 bytes, qu'on a appeléé "FLOAT32S". Ce qui permet d'écrire un job autonome pour lire automatiquement le capteur. Le job est constitué de deux tâches:

  • Une tâche d'initialisation (lancée une fois)

    • assert ! isset($started)
    • writeLine {S}D200100300AC{P}
    • expect 69:{A}{A}{A}{A}{A}{A}
    • wait 2000
    • compute $started=1

  • Une tâche de lecture (lancée une fois / seconde)

    • assert isset($started)
    • assert $started==1
    • writeLine {S}D20300{P}
    • expect 69:{A}{A}{A}
    • writeLine {S}D3xx{A}xx{A}xx{A}xx{A}xx{A}xx{A}xx{A}xx{A}xx{A}xx{A}xx{A}xx{N}{P}
    • expect 69:{A}($1:FLOAT32S)($2:FLOAT32S))


Histoire de rester un peu lisible, la tâche de lecture ci-dessus ne mappe que les 2 premières valeurs PM1.0, PM2.5 (en µg/m3) sur les "generic sensors" 1 et 2, mais rien ne vous empêche de lire le reste. Voici par exemple un fichier job qui lit et mappe les 9 premières valeurs.

Conclusion

On peut aussi bien utiliser un Yocto-Serial qu'un Yocto-I2C pour interfacer un SPS30. Cependant des choix de protocole un peu malheureux de la part de Sensirion imposent quelques limitations avec le Yocto-Serial. C'est pourquoi on recommande plutôt d'utiliser un Yocto-I2C qui vous permettra d'utiliser le SPS30 sans écrire une ligne de code et aussi d'afficher directement les données dans Yocto-Visualization.

Si vous utilisez un Yocto-I2C, vous pourrez voir les données dans Yocto-Visualization
Si vous utilisez un Yocto-I2C, vous pourrez voir les données dans Yocto-Visualization


Commenter aucun commentaire Retour au blog












Yoctopuce, get your stuff connected.