Pages: 1 [2]   Go Down
Author Topic: TIPE  (Read 1972 times)
0 Members and 1 Guest are viewing this topic.
Noum
Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Up, le code je l'ai posté plus haut... Je n'ai toujours pas de réponse pour les décimales (j'ai essayé le Float mais cela ne change rien)
D'autre part je me suis rendu compte que pour une entrée: Amplitude: 60
                                                                                 Pulsation: 1
j'obtient une valeur de tEch= 0,31, pourtant je devrait avoir 0,16 ??! Des idées?

merci
Logged

Bretagne
Offline Offline
Edison Member
*
Karma: 10
Posts: 1294
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Il ne m'a pas fallu bien longtemps pour voir cette ligne :
Code:
tEch= 3.1415/(10*pulsE);
Donc je te laisse calculer quand pulsE = 1...
Logged

Noum
Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Désolé pour le dernier post, j'étais trés fatigué et je me rend compte maintenant que ce n'était pas du tout ce que je voulais dire...J'avais un problême avec la fréquence d'échantillonage qui ne correspondait pas à celle que je souhaitais. Evidemment le calcul est juste mais c'est la formule qui ne convenait pas... Bref, j'ai reglé le problême avec un nouveau code (2.0 ^^) qui élimine ce problême (et bien d'autres...) Par contre j'ai toujours pas trouvé le moyen d'envoyer plus de deux décimales...

Code:
#include <Servo.h>
Servo servo;
int potpin;


float readCommand ();

void setup()
{
  potpin= 1;
  servo.attach(9);
  Serial.begin(9600);
 
  int numP=0;
  servo.write(90);
  float ampE=0, start=0, currentT=0;
  float pulsE= 0;
  float tEch= 0;
 
  Serial.println("Signal d'entree: ");
 
  Serial.print("Amplitude: ");
  ampE= readCommand();
  Serial.println(ampE);
 
  Serial.print("Pulsation: ");
  pulsE= readCommand();
  Serial.println(pulsE);
 
  Serial.print("Nombre de points: ");
  numP= readCommand();
  Serial.println(numP);
 
  float tableau[numP];
 
  start= millis();
 
  for(long i=0; i<numP; i++)
  {
    currentT= millis();
    while((millis()-currentT) <4*3.1415/(numP*pulsE)*1000)
    {
      servo.write(90+ampE*sin(i*4*3.1415/numP));
    }
    tableau[i]= analogRead(potpin);
  }
 
  for (long i=0; i<numP; i++)
  {
    tableau[i]= map(tableau[i], 0,1023 ,0,180);
    Serial.println(tableau[i]);
  }
 
  Serial.println("test");
}

void loop()
{
 
}

float readCommand ()
{
  float detec, nbrByte, actByte, nbr;
  nbr=0;
  detec=0;
  while(detec==0)
  {
    detec= Serial.available();
  }
  delay(5);
 
  nbrByte= Serial.available();
  for(long i=0; i<nbrByte; i++)
  {
    actByte= Serial.read();
    nbr= nbr*10 + actByte -48;
  }
  return nbr;
}
Logged

Bretagne
Offline Offline
Edison Member
*
Karma: 10
Posts: 1294
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

pour envoyer un float, peut-être devrais-tu envoyer un mot de 4 octets (la variable elle-même), puis la traduire sur le PC, car je crois que la fonction Serial.print() limite en interne le format envoyé sur le port série. Je n'ai pas vérifié, mais j'ai un prog qui envoie des données numériques par série à VB6 sur PC, et c'est dans le programme VB6 que je traite le format d'affichage à partir de la donnée numérique reçue (mais je ne joue qu'avec des word (entiers non signés 16 bits).
Logged

Made in Belgium
Offline Offline
God Member
*****
Karma: 0
Posts: 756
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Normalement c'est la seule façon de faire, envoyé et traité de l'autre côté.
En fait le port série n'envoie qu'un octet à la fois, que tu fasses print("toto"), println("toto"), print(156445645), print(12.56) la seule méthode à manipuler le port série est :
Code:
void HardwareSerial::write(uint8_t c)
Les méthodes print, println, write (char[]) (String) (float) (int) ... ne font que traité les donnée et appelé celle ci.

Edit:

Par contre j'ai toujours pas trouvé le moyen d'envoyer plus de deux décimales...

En relisant ton dernier message, ton problème c'est que tu n'arrive pas à atteindre un précision de plus de 2 décimale.
Le problème ne viendrait pas de là ?

Quote
Les variables float ont seulement 6 à 7 chiffres de précision. Ceci concerne le nombre total de chiffres, pas seulement le nombre à droite de la virgule. A la différence d'autres plateformes, où vous pouvez obtenir davantage de précision en utilisant une variable de type double ( c'est à dire avec plus de 15 chiffres), sur Arduino, les variables double sont de la même taille que les float.
« Last Edit: November 02, 2011, 10:35:33 am by osaka » Logged


Bretagne
Offline Offline
Edison Member
*
Karma: 10
Posts: 1294
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

A savoir que la méthode print(var) ou println(var) convertit var en chaîne de caractères, et dans le cas où var est un float, la chaine de caractères représentera un nombre à virgule, mais avec seulement deux décimales, c'est comme ça... Si tu envoies ta valeur avec write(), ce sont les 4 octets du float qui seront envoyés (et encore, il faut essayer car les fonctions arduino sur le port série sont bien trop orientées texte!), mais le terminal arduino les interprètera comme une chaîne de 4 caractères, donc illisible, tu auras l'impression qu'il te dit des gros mots...

La seule solution serait d'utiliser un processing qui traite les 4 octets reçus sous forme de float, ou se faire un terminal perso qui traite des octets et non pas des caractères (ça existe peut être, faudrait googliser la chose).

Je viens de regarder comment j'utilisais mon port série entre arduino et VB6 :

Code:
void Serial_write_16(word value){  // écrit un word sur le port série
  Serial.write(lowByte(value));  //poids faible
  Serial.write(highByte(value)); // poids fort
}

Effectivement, j'envoie deux octets et non pas une variable de 16 bits. Du coup, pour envoyer un float, peut-être faudrait faire un truc genre :

Code:
void Serial_write_32(float value){  // écrit un float sur le port série
  byte valToSend;
  for (byte i = 0; i <= 3; i++) {
    valToSend = mem[@value + i];                //          (1)
    Serial.write(valToSend);  //envoi un octet
  }
}
(1) : comprendre @ comme renvoyant l'adresse en mémoire de la variable value, mem[a] est emprunté ici au TurboPascal et renvoie la valeur à l'adresse a, désolé, je ne maîtrise pas du tout les pointeurs en C ou C++...

Ce code devrait envoyer les 4 octets composant la variable value...

Ensuite, il faut recevoir ces 4 octets comme un float...
« Last Edit: November 03, 2011, 02:54:19 am by Super_Cinci » Logged

Made in Belgium
Offline Offline
God Member
*****
Karma: 0
Posts: 756
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Tien j'ai vu que pour palier aux différent problème de précision et temps de calcul de l'arduino certains utilisaient des entiers qu'ils divisent par le nombre de décimal ensuite.

Code:
servo.write(90+ampE*sin(i*4*3.1415/numP));

par exemple ici tu multiplierai par 31415 au lieu de 3.1415 et du divisera le résultat par 10000 de l'autre côté.
Donc utilise un unsigned long (tu utiliseras pleinement les 4 octet) plutôt qu'un float. (quand tu initialises un float fais plutôt 0.0 au lieu de 0)
Logged


Noum
Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

mon dieu, je viens de retrouver ce topic...
Merci pour vos réponses, j'ai entre temps réussi à solutionner mon problême de transmission et je me suis contenté de la précision au 10e de degrés qui est déjà pas mal pour une chaîne de mesure amateur.
Merci pour vos réponses qui m'ont éclairée (paradoxalement) pour un autre topic que j'avais lancé sur la liaison série
Logged

Ile-de-France (92 sud), France
Offline Offline
Edison Member
*
Karma: 23
Posts: 2054
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Tien j'ai vu que pour palier aux différent problème de précision et temps de calcul de l'arduino certains utilisaient des entiers qu'ils divisent par le nombre de décimal ensuite.

Code:
servo.write(90+ampE*sin(i*4*3.1415/numP));

par exemple ici tu multiplierai par 31415 au lieu de 3.1415 et du divisera le résultat par 10000 de l'autre côté.
Donc utilise un unsigned long (tu utiliseras pleinement les 4 octet) plutôt qu'un float. (quand tu initialises un float fais plutôt 0.0 au lieu de 0)

Une division entière peut être plus rapide qu'une multiplication flottante. A vérifier car pas forcément évident car la division sur un processeur entier est une opération itérative.
Tout comme quand on pose la division à la main on divise 10 par 10 de manière itérative, le processeur va diviser bit par bit.
Donc sur un long ca fait 32 boucles de division binaire.
Ca coute très cher en temps CPU !

La meilleur solution est d'approximer par des fractions dont le numérateur est une puissance de 2.

PI = 3.1415 = 31515/1000 = 3217/1024
Donc le plus rapide est de multiplier par 3217 et de faire >>10 ce qui équivaut à une division par 1024 effectué en 1 seule instruction assembleur.
Imbattable.
Logged

Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

Pages: 1 [2]   Go Up
Jump to: