Comment traiter données issues d'un capteur

Python est le langage de prédilection du Raspberry Pi

Modérateurs : Francois, Manfraid

Bud Spencer
Raspinaute
Messages : 940
Enregistré le : lun. 15 août 2016 21:38

Re: Comment traiter données issues d'un capteur

Message par Bud Spencer » lun. 9 mars 2020 16:24

redscreen a écrit :
dim. 8 mars 2020 20:47
... j'aimerais bien t'avoir dans mon équipe pour notre projet :D :lol:
:lol:
redscreen a écrit :
dim. 8 mars 2020 20:47
Je vais donc étudier la suite ! (ah oui, au passage, il n'y a pas la version .zip pour fainéant ? :? ;) )
J’ai ajouté un zip dans le tuto. Je me suis permis d’ajouter quelques options qui peuvent servir à d’autres qui veulent faire un peu d’udp.

redscreen a écrit :
dim. 8 mars 2020 20:47
J'en suis convaincu, donc je vais étudier ça en parallèle et voir si j'avance plus efficacement !
Et tu es encore très loin d'imaginer à quel point ...


Ps : pas la peine de modifier le code pour enlever le prefix, il suffit juste de passer une chaine vide en paramètre ("") ;)
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

redscreen
Messages : 26
Enregistré le : ven. 28 févr. 2020 17:05

Re: Comment traiter données issues d'un capteur

Message par redscreen » ven. 13 mars 2020 00:20

de retour après quelques essais, mes connaissances javascript étant assez faible...
j'essaie déjà de ranger le flux de données udp entrant dans un tableau
le flux arrive sous cette forme:

time=12.0137445525423\r\n
airspeed=34.5486679077148\r\n
altitude=520.117614746094\r\n
vario=16.6474590301514\r\n
et ainsi de suite... (29 données à ranger)

j'essaye donc de retranscrire le code python qui fonctionne (range chaque donnée dans un tableau en ométtant "valeur=") :

import socket
import re
port = 55278
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("", port))
print("waiting on port:", port)
while 1:
data, addr = s.recvfrom(1024)
x=re.findall(r"\d+\.\d+", data.decode(), re.MULTILINE) # j'essaye donc de retranscrire cette ligne
print("time="+x[0]+" airspeed="+x[1]) # et ainsi de suite...chaque donnée est bien rangée dans le tableau



voici mon test en js, mais je ne parviens pas à avoir le même comportement :

'use strict';
var myserver = require("./myserver.js");

var srvudp = new myserver.UDP("");
var Data = [];
const regexp = /\d+\.\d+/igm;

srvudp.Open("0.0.0.0", 55278);

srvudp.Events.on("server", function (data) {
console.log(data);
});

srvudp.Events.on("data", function (data) {
// initialisation des données Data[]
Data[0] = data.match(regexp);
// ou:
let match = null;
do {
match = regexp.exec(data);
if(match) {
Data.push(match[0]);
}
} while (match);

});

setInterval(function () {
console.log(Data);
}, 1000);

Bud Spencer
Raspinaute
Messages : 940
Enregistré le : lun. 15 août 2016 21:38

Re: Comment traiter données issues d'un capteur

Message par Bud Spencer » ven. 13 mars 2020 14:28

Soyons pragmatique et analysons la complexité du problème (si problème complexe il y a :mrgreen: ) :

Pour tester avec ton modèle de données, j’ai mis ça dans le send client :

Code : Tout sélectionner

//envois des donnés au serveur toutes les secondes
setInterval(function () {
	let d ="time = 12.0137445525423\r\nairspeed = 34.5486679077148\r\naltitude = 520.117614746094\r\nvario = 16.6474590301514\r\n"
 	cltudp.Send(d, 'localhost', 5000)
}, 1000);
objectif : convertir la chaine d’entrée data en un tableau Data [ [‘nom’,valeur], [‘nom’,valeur], …]
ou nom est une string et valeur un nombre décimale

1 - Supprimer les éventuels espaces et saut de ligne de part et d’autre de la chaine data :
data = data.trim();
=>data = "time = 12.0137445525423\r\nairspeed = 34.5486679077148\r\naltitude = 520.117614746094\r\nvario = 16.6474590301514"

2 - Convertir data en un tableau en splittant sur les ‘rn’ :
data = data.split("\r\n");
=>data = [" 'nom ' , ' valeur ' " , " 'nom ' , ' valeur ' " , ... ]

3 - itération sur tout le contenu du tableau data
for (let i = 0; i < data.length; i++){ ...

4 - Convertir Data en un tableau 2d en splittant sur les ‘=’ de data
Data [ i ] = data[ i ].split("=");
=>Data = [ [' nom ', ' valeur '], [' nom ', ' valeur '], …]

5 - On suppriment les éventuels espaces autour du nom
Data [ i ][0] = Data [ i ][0].trim();
=>Data = [ ['nom', ' valeur '], ['nom', ' valeur '], …]

5 - On converti la valeur en un nombre décimale
Data [ i ][1] = parseFloat(Data [ i ][1]);
=>Data = [ ['nom', valeur.décimale], ['nom', valeur.décimale ], …]

6 - fin d'iteration
...}

fini :P

en code, ca donne ca (avec en dessous différentes façon de se balader dans Data). bon j'aurrais bien transformé Data en un objet mais ... non, j'déconne :lol:
dataudp.png
dataudp.png (48.94 Kio) Vu 1022 fois
Modifié en dernier par Bud Spencer le sam. 14 mars 2020 09:26, modifié 10 fois.
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Bud Spencer
Raspinaute
Messages : 940
Enregistré le : lun. 15 août 2016 21:38

Re: Comment traiter données issues d'un capteur

Message par Bud Spencer » ven. 13 mars 2020 14:30

Et le résulat :
dataudpres.png
dataudpres.png (28.45 Kio) Vu 1023 fois
To be a coder or not to be (William Shakespeare … s'il avait possédé un computer du futur … :mrgreen: :lol: ;) )
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

redscreen
Messages : 26
Enregistré le : ven. 28 févr. 2020 17:05

Re: Comment traiter données issues d'un capteur

Message par redscreen » sam. 21 mars 2020 13:29

de retour une semaine plus tard, covid-19 & téléexam ne m'ayant pas laissé de temps libre pour apprendre NodeJs

efficacité ! :)
je te remercie beaucoup pour les explications bien détaillées
avec les bonnes méthode ça va mieux :D
je n'avais jamais réellement créé de tableau 2d -> efficace 8-)

les données Udp sont donc maintenant bien "rangées", prêtes à êtres utilisées ! yes: you are a coder :D ;) !

je m'informe donc sur https://serialport.io pour récupérer les données de la centrale inertielle via le port série
j'ai repensé à ton idée qui était de se passer de Arduino Uno, et retranscrire le code C sur Raspberry :
ce serait effectivement mieux, mais le module CAN que j'ai (ads1115): https://www.adafruit.com/product/1085 ne possède que 4 entrées Analogique,et ma centrale inertielle en utilise 5 sur UNO :(
je vais tenter une commande d'un autre module digital i2c/spi, mais je doute que je le recevrai à temps avec la situation actuelle...
pour info, si jamais je le reçois, concrètement, je dois m'orienter vers WiringPi pour faire ça ?

je regarde aussi https://www.npmjs.com/package/rpio pour le contrôle des 2 vérins en PWM,
la Rpi3B possède à ce que je lis 2 pin PWM "hardware" (pin 32 & 33), 2+2 pour d'autres, certain disent 1 seul, c'est flou, je retourne à mes recherches

Bud Spencer
Raspinaute
Messages : 940
Enregistré le : lun. 15 août 2016 21:38

Re: Comment traiter données issues d'un capteur

Message par Bud Spencer » dim. 22 mars 2020 11:34

Bien. La réception UDP, c’est fait. Il y a juste un petit détail auquel tu dois penser. Dans ton projet, il va y avoir des opérations qui vont prendre du temps. Je pense notamment au correction sur les vérins. Meme si cela va très vite, c’est quand meme des actions mécaniques qui prennent un peu de temps (quelques ms voir plus). Pendant ce temps tu vas continuer de recevoir des données qui finalement seront ignorées puisque remplacé par d’autres le temps que les vérins aient pris leurs positions. Il y aura donc une petite réflexion à avoir pour ne pas convertir systématiquement data en Data chaque réception de façon à ne pas gaspiller de temps uc en conversion inutiles.

Pour la suite, voilà ce que je conseillerais :

Comme vous avez déjà un module d’acquisition validé qui vous retourne des données filtrées sur un port série (c’est l’arduino) autant profiter dans un premier temps de l’existant. Donc je créerais un objet récepteur port série qui fonctionnerais exactement de la meme façon que pour l’udp et qui viendrait alimenter un autre tableau de donnée (tu pourrais par exemple avoir DataUDP [] et DataSerial []). Le npm SerialPort semble parfaitement adapté pour ça bien que je ne l’ai jamais essayé (Si tu me donne un exemple de ce que vous recevez sur le port serie, je peux voir pour faire une simulation). Une fois fait, auriez toutes les données pour programmer les pwm d’asservissement des vérins (avec le npm rpio et apparemment 4 gpio pwm sur les pi 40 broches (12,32,33,35) mais jamais essayé).

Optionnellement, vous pourriez ensuite envisager d’utiliser le meme programme pour faire l’acquisition des données analogique et de vous passer de l’arduino. Vous gagneriez énormément en vitesse d’acquisition et en traitement des données (filtrage kalman entre autre). Pour ça, pas d’hésitation à avoir sur le circuit adc à utiliser. Un MCP3208 (en ci seul si vous disposez d’une breadbord ou en petit module tout fait) dispose de 8 entrées analogiques 12 bits. Il est beaucoup plus rapide que l’ADS115 ou les adc de l’arduino et peut aller jusqu’à 100Ksps. Il utilise une liaison spi et J’ai déjà très largement détaillé la façon de l’utiliser avec NodeJS et le npm rpio à la page 8 du tuto pour le projet 'datalogger'.

Resterait le filtrage. Pour ça, il ni a aucun probleme si vous voulez utiliser le code c++ du filtre kalman que tu as cité. Il peut sans probleme etre compilé sur le PI (je viens de le faire) en tant que librairie partagée et utilisable par votre programme NodeJS ou meme en faire un module JS à part entière. Il y a aussi la possibilité de coder ce type de filtre directement en javascript (pas sûr que ce soit la meilleure solution, mais pourquoi pas)
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Bud Spencer
Raspinaute
Messages : 940
Enregistré le : lun. 15 août 2016 21:38

Re: Comment traiter données issues d'un capteur

Message par Bud Spencer » lun. 23 mars 2020 13:40

Exemple d'ajout d'un serveur port serie dans le tuto NodeJS ;)
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

redscreen
Messages : 26
Enregistré le : ven. 28 févr. 2020 17:05

Re: Comment traiter données issues d'un capteur

Message par redscreen » lun. 23 mars 2020 18:38

Super pour l'exemple :P , je fonce voir ça

Ce qui arrive sur le port série est défini dans le "sketch arduino":
Serial.print(xAngle,15); Serial.print("\t");
Serial.print(yAngle,15); Serial.print("\tEquivalent degrès:\t");
Serial.print(xAngle*RAD_TO_DEG); Serial.print("\t"); // conversion des radians en degrés (plus parlant)
Serial.print(yAngle*RAD_TO_DEG); Serial.print("\t");
Serial.print("\n");
delay(10);

Soit pour exemple (toutes les 10ms, d'ailleurs en relisant je pourrais mettre 100ms ce serait suffisant et adapté à l'UDP envoyé toutes les 100ms) :
-0.220764899253845 0.132013773918151 Equivalent degrès: -12.65 7.56
(je peux supprimer "équivalent degrès", je l'avais juste rajouté pour tester le bon fonctionnement)


La première chose que j'ai fait quand le programme UDP fonctionnait est de connecter un instrument de bord pour tester (en me basant sur le tuto4) -> YES ça fonctionne :D !
et comme j'ai créé un petit site http avec 5 pages, je les sers avec "programme.js"
-> du coup j'ai 2 petites questions :
- est ce ce mieux (niveau ressources rpi3b) de laisser "programme.js" servir les pages (et du coup désactiver apache), ou bien laisser apache faire le job comme j'avais fait auparavant... ou peu importe ?...
- en servant mes pages avec NodeJs, si je dois définir une variable dans un formulaire (type range), en l’occurrence le pourcentage de gain PID (Kp), je n'ai plus besoin de PHP du coup ? (comme j'avais appris)


je résume pour la suite
-> Optimisation, si besoin...pour gagner des ressources uc
-> Si jamais je reçois le MCP3208 -> page 8 du tuto ! et passer la centrale inertielle sur Rpi -> adapter les entrées analogiques et compiler, ça devrait aller -> gcc/g++ ?, mais "librairie partagée utilisable par le programme NodeJS" c'est là que je me repose des questions sur la manière... bref ce n'est pas le plus important aujourd'hui, j'ai déjà l'impression d'avancer et c'est très motivant, merci pour tout ! ;)

Bud Spencer
Raspinaute
Messages : 940
Enregistré le : lun. 15 août 2016 21:38

Re: Comment traiter données issues d'un capteur

Message par Bud Spencer » lun. 23 mars 2020 23:08

Vu que tu as la maitrise de ce que tu envoies sur le port série depuis l’arduino, tu pourrais faire un truc du genre :

Serial.print(xAngle,15); Serial.print("\t");
Serial.print(xAngle*RAD_TO_DEG); Serial.print("\t");
Serial.print(yAngle,15);
Serial.print(yAngle*RAD_TO_DEG); Serial.print("\t");
Serial.print("\n");

Et dans le programme nodejs, formater la var COMData de la facon suivante :
var COMData = [["xAngle", 0.0, 0.0], ["yAngle", 0.0, 0.0]];

et pour la convertion à la reception :, un truc du genre :

data = data.split(« /t ») ;
Data[0][1] = parseFloat(data[0]) ;
Data[0][2] = parseFloat(data[1]) ;
Data[1][1] = parseFloat(data[2]) ;
Data[1][2] = parseFloat(data[3]) ;

Et tu aurais ainsi un COMData qui ressemblerais à ça :
[["xAngle", angx.rad, angx.deg], ["yAngle", angy.rad, angy.deg]]

C’est juste une suggestion, mais cela te permetterais d’avoir une structure proche de ce que tu as avec l’udp qui en plus serait à la fois strict, clean, explicite et ordonnée.

Bien entendu, il fait augmenter la valeur de delay. Ce qui prime, c’est d’avoir toujours de nouvelle valeurs pour positionner tes vérins et il serait complétement illusoire de prétendre le faire 100 fois par seconde. Donc autant augmenter ces délais raisonnablement pour ne pas surcharger l’uc du pi inutilement.

Bien sûr, Apache, php sont de très bon outils, mais ils n’ont pas leur place dans ce genre d’application alors que NodeJS est parfaitement adapté à ce genre de cas et tout ça en une seule application.

Pour la suite, tu peux parfaitement acquérir les entrées analogiques en javascript avec nodeJs et rpio sans utiliser de c ou c++ (voir page 8,9 et 10 du tuto) et remplacer l'objet 'COM' par un objet l objet ‘ADC’. Il lirait périodiquement les données analogiques en utilisant une lisaison spi et les transférerais au programme principale exactement de la meme façon (aucune modif sur le code du programme principale). Seule petite divergence, cet objet devrait posséder son propre timer puisque que contrairement aux 2 autres, il ne peut recevoir des données que s’il en demande.

La seule chose qui manquerai, c’est le filtrage des données en provenance de l’adc. Avec ce type de capteur très sensible, c’est indispensable et pour ça, le filtrage kalman fait bien l’affaire. A ce niveau, il y a plusieurs solutions :

1 : Coder un filtre en javascript. Autant etre clair, javascript n’est pas l’idéal pour faire du calcul matriciel, mais ça pourrait être suffisant.
2 : Chercher si un npm de un filtre tout fait existe et essayer (google -> npm kalman )
3 : Utiliser le code c++ de celui que vous avez et le transformer en un add-on pour nodejs. Je n’ai jamais abordé ça dans le tuto mais cela se fait très bien. NodeJS dispose d’outils très pratique pour compiler et wrapper du code c et c++ (N-API,node-addon-api, NAN, node-gyp …). Je ferais peut etre un petit exemple là-dessus.
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Bud Spencer
Raspinaute
Messages : 940
Enregistré le : lun. 15 août 2016 21:38

Re: Comment traiter données issues d'un capteur

Message par Bud Spencer » mar. 24 mars 2020 11:33

Pour garder la forme en cette période de confinement j'ai fait mon petit jogging code du matin. Nouveau serveur 'adc' pour un mcp3208

Dans la foulé, je te confirme qu'il y a bien 4 pins pwm sur 2 canaux utilisables avec rpio sur un Pi3 (canal 0: 12,32 et canal 1: 33,35). En plus on parle bien de pwm hardware. Je viens de faire l'essais avec les 3 serveurs activés et bousculés toutes les 100 ms et les 4 pwm actifs et la charge cpu tourne entre 3 et 5%. Je confirme donc que l'intégralité de ton projet (y compris la distribution de pages web dynamique) est parfaitement à la porté du PI tout seul et en un seul programme NodeJS.
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Répondre

Retourner vers « Python »