Je souhaite réaliser une petite station météo à base d'arduino reliée par USB au Raspberry pi (pour gérer la partie domotique).
J'utilise un Dust Sensor : DSM501A pour mesurer le niveau de poussières dans l'air ambiant.
J'ai trouvé un script qui me permet de le faire tourner sur l'arduino (nickel !) par contre dès que j'alimente l'arduino sur le raspberry (USB), mes valeurs calculées de concentration sont totalement faussées ...
Pour info:
Sur le raspberry j'ai un script en python qui lit la valeur reçue par port série et l'enregistre dans un fichier,
Le script ci-dessous utilise la fonction "millis()", je soupçonne que le problème vienne de là mais je n'ai pas trouvé la solution...
Le script en question :
int pin = 7;
unsigned long duration;
unsigned long starttime;
unsigned long sampletime_ms = 30000;
unsigned long lowpulseoccupancy = 0;
float ratio = 0;
float concentration = 0;
void setup() {
Serial.begin(9600);
pinMode(7,INPUT);
starttime = millis();
}
void loop() {
duration = pulseIn(pin, LOW);
lowpulseoccupancy = lowpulseoccupancy+duration;
if ((millis()-starttime) > sampletime_ms)
{
ratio = lowpulseoccupancy/(sampletime_ms*10.0); // Integer percentage 0=>100
concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve
Serial.print(lowpulseoccupancy);
Serial.print(",");
Serial.print(ratio);
Serial.print(",");
Serial.println(concentration);
lowpulseoccupancy = 0;
starttime = millis();
}
}
Une personne qui poste pour la première fois sur le forum en ouvrant un sujet dans la bonne section, avec une bonne présentation du sujet, la bonne utilisation des balises [code] et de surcroît dans un français agréable à lire, c'est tellement rare que cela mérite bien un coup de pouce
Je ne vois rien de louche dans ton usage de la fonction millis()
J'ai cru voir une erreur dans le calcul de ratio, avec la division par 10, mais non c'est logique car pulseIn et donc lowpulseoccupancy sont en microsecondes.
Aucun avis sur le calcul de la variable concentration, mais je suppose que ton problème est déjà visible dans la valeur de ratio.
Donc pour ma part r.a.s. avec ton code.
Je ne connais pas ton capteur. Si une différence d'alim entraîne une variation des résultats, c'est probablement dans les aspects électriques qu'il faut se plonger.
Quel est le câblage de ton montage (alim incluse) ?
Personnellement j'ai pour habitude de toujours transformer les types de variable de manière isolée, pour n'avoir que des formats homogènes dans les calculs. Cela évite toute mauvaise surprise liée aux conversions intermédiaires.
Ainsi par exemple, j'aurais codé
unsigned long ratio = lowpulseoccupancy/(sampletime_ms*10); //que des entiers y compris le 10
float ratiof = ratio;
float ratiof2 = ratiof * ratiof;
float ratiof3 = ratiof2 * ratiof;
float concentration = 1.1*ratiof3-3.8*ratiof2+520.0*ratiof+0.62; //que des float y compris le 520
En principe, le type float est de précision médiocre.
D'habitude on utilise plutôt le type double en C (ce que je fais toujours sans me poser de question), mais il me semble que c'est équivalent sur Arduino.
Vérifier en comparant sizeof(float) et sizeof(double).
Pas sûr du tout que cela change quoi que ce soit à ton problème, mais au moins ce sera plus propre
On utilise des doubles en C car les ordinateurs type PC Mac utilise un coprocesseur mathématique qui fait les calculs en double précision.
Sur l'arduino effectivement j'ai lu que les float et les doubles sont identiques.
Quand à la précision des float médiocre, il ne faut pas exagérer il y a environ 7 chiffres significatifs ce qui est largement suffisant dans la plupart des cas et en particulier ici.
Je ne pense pas que le calcul soit en cause, moi je pense plutot à la mesure des impulsions. Est ce qu'on ne peut pas rater des impulsions?
Pour les float je reformule : la précision théorique offerte est rarement compatible avec le besoin.
Pour stocker une température, ça va, mais pas beaucoup plus.
Ici on a un pourcentage (2 chiffres) élevé au cube (6 chiffres) multiplié par 1.1 : le besoin est donc de gérer des nombres avec une précision de 7 chiffres => perso je passerais tout en double comme d'hab sans me poser de question.
Oui pour les impulsions, d'autant qu'à part quelques print chaque 30 secondes, la fonction loop ne fait qu'enchaîner en rafale des pulseIn().
A corréler avec l'info qui me semble la plus significative :
...par contre dès que j'alimente l'arduino sur le raspberry (USB), mes valeurs calculées de concentration sont totalement faussées
Je ne suis pas du tout d'accord. Tous les calculs sont fait avec une précision de 6 chiffres (approximativement). Tu n'as pas besoin d'avoir 7 chiffres, ton nombre élevé au cube aura toujours 6 chiffres de précision (la mantisse fait toujours 24 bits), c'est une des grosses différence avec les entiers.
J'émettais l'hypothèse qu'on pouvait rater les impulsions, car on ne connait pas la durée des impulsions et surtout l'intervalle entre chaque impulsion. Ce n'est pas la même chose si la durée entre chaque impulsion est 0.1ms ou 100ms.
Je sais bien que le format flottant n'est pas du binaire comme les entiers, mais regarde : dans le cas le plus défavorable où le pourcentage est à 99, le premier terme du calcul est 1,1 * 99^3 = 1067328,9
Cela fait déjà huit chiffres à mémoriser sans perte de précision.
Nb : j'ai un doute sur la taille de la mantisse en simple précision (24 bits ou 23 bits + 1 bit de signe?).
Bref pas sûr que ça passe, et si ça passe c'est vraiment limite il me semble
De toute façon c'est simple à vérifier, il suffit de faire les calculs en float et en double (sur un ordinateur qui gère effectivement la double précision) et on verra que les 6 premiers chiffres significatifs sont identiques.
Bon, tout ça, ça ne résout pas le problème de notre ami.
J'aurai tendance à penser comme kamill que le problème viendrait des impulsions ...
J'ai mesuré la tension et le courant dans mon circuit pour voir si j'avais bien la même chose avec le PC et le Raspberry : 4,7V / 192mA (avec les autres capteurs + afficheur LCD).
Il me semble qu'un port USB peut alimenter jusqu'à 500mA, je vais tester avec une autre alimentation du Raspberry au cas où ...