Souhaitez-vous participer à la création d'un jeu vidéo inspiré de Stardew Valley, ou le tester lorsque la version bêta sera disponible ? Remplissez notre sondage ou inscrivez-vous à notre lettre d'information (en bas de page)
1

acquisition en temps réel Arduino + transmission bluetooth

le 18-07-2017 à 19:14 #
Bonjour,
N'hésitez pas à poser des questions, ce programme est assez didactique niveau de programmation moyen .

Ici j'ai écrit un programme qui lit un encodeur quadratique linéaire 5 microns par pas d'une longueur de 15cm
cet encodeur se trouve dans un outil en rotation maximum 500RPM

le signal de cet encodeur doit être envoyé en utilisant bluetooth
hors de question de perdre un pas bien sur
la routine de lecture doit être courte
certaines instructions d'arduino sont très longue en temps d'execution Serial.print par exemple
Par contre Serial.write(byte) est beaucoup plus rapide.

String(encoder0Pos, HEX) me permettrait de convertir mon nombre en une string hexadecimal (l'hexadecimal permet economie d'un caractère)
malheureusement cette instruction est aussi très lente nous ferons donc la conversion dans le programme
de plus nous pourrons visiter le port pendant la fabrication de la chaine de caractère ce qui permet de travailler à une fréquence plus rapide.

Dans le cas présent oubliez les interruptions vous n'avez simplement pas assez de temps pour les traiter lorsque vous faites une interruption vous devez sauver les registres les pointeur et empiler ce n'est pas gratuit en temps, ici nous avons un signal qui doit être traité en 100 microsecondes idéalement le signal max théorique étant 10KHZ


la réécriture des instructions de lecture du port est justifié par l'économie des 4 cycles nécessaires bien que très faible puisque nous avons de la memoire mais pas de temps bouffons de la mémoire et ne perdons pas de temps

la programmation pour le temps réel est un mélange de super court et d'idiotement répétitif
je presenterai le programme de décodage

nous avons un encodeur avec les signaux en quadrature A et B une masse et 5V connectés aux pin 14 portC0 et 15 portC1 habituellement port entrée analogique mais utilisé ici en input our travailler sans avoir à faire de décalage
la routine de lecture est donc
Old = NewTest; //on sauve l'état du port
NewTest =(PINC&3);//on prend la valeur du port
encoder0Pos+=direction [Old * 4 + NewTest];//on ne fait pas de test mais on modifie l'état du compteur toutes ces variables étant inferieur à 255 elles sont définies en char donc 1 octet

la table const char direction [16] = { 0 ,-1,. 1 ,. 2 ,. 1 ,. 0 , 2 , -1 , -1 , 2 , 0 , 1 ,. 2 ,. 1 , -1 ,0};
---------------------------------------------------00-01-02-03-04-05-06-07-08-09-10-11-12-13-14-15
donne les variations de direction et les valeurs possible 2 est une valeur impossible
00,01,11,10,00 soit décimal 0,1,3,2,0 pour sens horaire
00,10,11,01,00 soit décimal 0,2,3,1,0 pour sens anti horaire


faisons fonctionner le programme
Prenons la séquence de test 01,11,11,10,10,10,11,11,00,10

ancienne valeur old = newtest=10 (par exemple) donc 2
NewTest =(PINC&3) donc newtest = 01 donc 1 le masque &3 permet de ne considérer que les bits 0 et1
encoder0Pos+=direction [Old * 4 + NewTest]; donc 2*4+1 =direction [9] soit -1 encoder0Pos est décrementé 32767+-1=32766
ancienne valeur old = newtest=01
NewTest =(PINC&3) donc newtest = 11 donc 3
encoder0Pos+=direction [Old * 4 + NewTest]; donc 1*4+3 =direction [7] soit -1 encoder0Pos est décrementé 32766+-1=32765
ancienne valeur old = newtest=11
NewTest =(PINC&3) donc newtest = 11 donc 3
encoder0Pos+=direction [Old * 4 + NewTest]; donc 3*4+3 =direction [15] soit -0 encoder0Pos est décrementé 32765+0=32765
ancienne valeur old = newtest=11
NewTest =(PINC&3) donc newtest = 10 donc 2
encoder0Pos+=direction [Old * 4 + NewTest]; donc 3*4+2 =direction [14] soit -1 encoder0Pos est décrementé 32765+-1=32764
ancienne valeur old = newtest=10
NewTest =(PINC&3) donc newtest = 10 donc 2
encoder0Pos+=direction [Old * 4 + NewTest]; donc 2*4+2 =direction [10] soit 0 encoder0Pos est décrementé 32764+0=32764

faites la suite vous même pour comprendre comment cela fonctionne


la transformation en hexa est enfantine mais il montre pour un débutant la potion d'octet de poids fort
le caractère null est indispensable pour que le décodeur lise une chaine complète
le programma qui fait le job débarrassé de ses lectures du port ne nécessite pas de commentaires supplémentaires

Serial.write (asciiTable[(encoderPos>>12)]); //the highest digit is at the end

Serial.write (asciiTable[(encoderPos>>8&15 )]);//choice of hexadecimal because more economical in conversion

Serial.write (asciiTable[(encoderPos>>4&15)]);//the Serial.write is much faster than Serial.Print

Serial.write (asciiTable[(encoderPos&15)]);

Serial.write (0);// write the char 0 so it become a string

Serial.write (13);//finalize with a line feed carriage return for test only

Serial.write (10);

//***********************************************************************************
// **
// **
// **
/*
real time reading encoder and transmit
name "C:\Users\lulu64\Documents\Arduino\georgequadraticwireless01

created 18 July 2017

by rokag3
no interupt because the save register is too time consuming
no call since there is no problems of space but a time problem only
no use of a function like stringOne = String(encoder0Pos, HEX);
the use of such function is too slow
the port is still scanned during the transmission to not give a single chance to miss a change of state
of the encoder
the limit with unsigned encoder is 32767 since the encoder can be extreme right when initialized
so the maximum lenght of the encoder is 16cm


*/
unsigned int encoderPos, encoder0Pos=32767;//initialize at the worst case
const char asciiTable[16] = {48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70}; //hexadecimal
const char direction [16] = {0,-1,1,2,1,0,2,-1,-1,2,0,1,2,1,-1,0}; //up or down table or unchanged
unsigned char Old, NewTest;
const long interval=26316;//1.e+6/nb of iterations per second
// 1.e+6 / interval = nb of iterations per seconde here 1000000/25000=40 iterations per seconds
// if I want 38 iterations per second 1000000/38=26315.79 so interval will be 26316
unsigned long time, timeElapsed;
const int in1 = 15;// 0; // broches lecture encoder portF4 (A3)
const int in2 = 14;// 1; // broches lecture encoder portF5 (A2)

void setup() {
pinMode(in1, INPUT);//A from the encoder to be divided
pinMode(in2, INPUT);//B from the encoder to be divided

pinMode(outA1 , OUTPUT);//A signal after division 2
pinMode(outB2 , OUTPUT);//B signal after division 3 // Open serial communications and wait for port to open:
Serial.begin(38400);
while (!Serial) {} ; // wait for serial port to connect. Needed for native USB port only

}

void loop()
{

Old = NewTest; //save the actual value of the port
NewTest =(PINC&3);//get the value of the encoder
encoder0Pos+=direction [Old * 4 + NewTest];//get the sign of displacement that can be only -1,0 or 1

if (micros()>timeElapsed) //in regard of the value of interval we send the value of the counter to the serial part
//************************************************
{
Old = NewTest;
NewTest =(PINC&3);
encoder0Pos+=direction [Old * 4 + NewTest];
timeElapsed=micros()+interval; //reinitialisation of the interval
Old = NewTest;
NewTest =(PINC&3);
encoder0Pos+=direction [Old * 4 + NewTest];
encoderPos=encoder0Pos; // encoderPos is the position of the counter at the moment we transmit
Old = NewTest;
NewTest =(PINC&3);
encoder0Pos+=direction [Old * 4 + NewTest];
Serial.write (asciiTable[(encoderPos>>12)]); //the highest digit is at the end
Old = NewTest; // in order to go faster no loop just rewriting of the all routine only 3 lines
NewTest =(PINC&3);
encoder0Pos+=direction [Old * 4 + NewTest];
Serial.write (asciiTable[(encoderPos>>8&15 )]);//choice of hexadecimal because more economical in conversion
Old = NewTest;
NewTest =(PINC&3);
encoder0Pos+=direction [Old * 4 + NewTest];
Serial.write (asciiTable[(encoderPos>>4&15)]);//the Serial.write is much faster than Serial.Print
Old = NewTest;
NewTest =(PINC&3);
encoder0Pos+=direction [Old * 4 + NewTest];
Serial.write (asciiTable[(encoderPos&15)]);
Old = NewTest;
NewTest =(PINC&3);
encoder0Pos+=direction [Old * 4 + NewTest];
Serial.write (0);// write the char 0 so it become a string
Old = NewTest;
NewTest =(PINC&3);
encoder0Pos+=direction [Old * 4 + NewTest];
Serial.write (13);//finalize with a line feed carriage return for test only
Old = NewTest;
NewTest =(PINC&3);
encoder0Pos+=direction [Old * 4 + NewTest];
Serial.write (10);
}
Old = NewTest;
NewTest =(PINC&3);
encoder0Pos+=direction [Old * 4 + NewTest];
}





(Modifié par rokag3 le 18-07-2017 à 21:08)
Re: acquisition en temps réel Arduino + transmission bluetooth
le 20-07-2017 à 06:08 #
La partie récepteur non commenté
testé cela fonctionne
ce programme n'est pas encore nettoyé il n'a pas besoin d'être optimisé


//
// encoder generator between 2 limits
// write a signal for a DRO using A+ B+ only due to the short connection it is useless to write a differential
//now just programm the blue tooth and job done

#include <stdlib.h>
const byte numChars = 5;
char receivedChars[numChars]; // an array to store the received data
//long strtol (const char *__nptr, char **__endptr, int __base)
boolean newData = false;
byte numberOfCarReceived = 0;
char endMarker = '\n';
char receiveChar;
int ledA = 8; //PD0 signal A
int ledB = 9; //PD1 signal B
int ledEnd = 4;//PD4 not transmitting when TRUE
int accel =1; // the value that will be used to send the signal roughly number of frame to send / 40(if 40 value per sec)
int valA, valB; //general purpose for test
const byte quadratureEncoderAB [4] = {2,3,1,0};//10,11,01,00 the sequence of a quadrature encodeer
int actualPositionOfVirtualEncoder =3;//state of the actual output A and B

unsigned int lastEncoderPosTransmittedToUser =0;//position received from the emitter
long int encoder0Pos =1;//actual position
int sign = 0;
int nbOfIteration = 0;
unsigned long time, timeElapsed;
const unsigned long MaxDelay=1000 ;//(interval/vmax)
// vmax is the max speed calculated with 3meters/min with an encoder 5 microns in number of steps
// 3 millions of microns/5 =600000steps/min or 10000 steps/sec or 100 microsecons/steps
const long interval=100000;//1/10th of a sec


//-----------------------------------------
void setup() {
// initialize the digital pin as an output.
pinMode(ledA, OUTPUT);
pinMode(ledB, OUTPUT);
pinMode(ledEnd, OUTPUT);
Serial.begin(38400);
Serial.setTimeout(2); //2 miliseconds
timeElapsed= micros();
Serial.println("<Arduino pret>");
// if (Serial.available())encoder0Pos = Serial.parseInt();

}

void loop()
{

readBlueTooth();
newData = false;
timeElapsed= micros();
Serial.println(lastEncoderPosTransmittedToUser);

nbOfIteration=encoder0Pos - lastEncoderPosTransmittedToUser;
if(nbOfIteration)
{digitalWrite(ledEnd, LOW);
if(nbOfIteration>0)
{sign=1;
while (nbOfIteration--)
{actualPositionOfVirtualEncoder--;
if (actualPositionOfVirtualEncoder<0) actualPositionOfVirtualEncoder=3;
makeSignal();
}
}
else
{ sign=-1;
while (nbOfIteration++)
{actualPositionOfVirtualEncoder++;
if (actualPositionOfVirtualEncoder>3) actualPositionOfVirtualEncoder=0;
makeSignal();
}
}
}

digitalWrite(ledEnd, HIGH);
}
void makeSignal()
{
PORTB &= (quadratureEncoderAB [actualPositionOfVirtualEncoder]);
PORTB |= (quadratureEncoderAB [actualPositionOfVirtualEncoder]);
encoder0Pos += sign*-1;
valB=PINC;
delayMicroseconds(accel);

}

void readBlueTooth()
{while (Serial.available()&& newData == false )
{receiveChar = Serial.read();
if (receiveChar != endMarker)
{receivedChars[numberOfCarReceived++] = receiveChar;
// numberOfCarReceived++;
if (numberOfCarReceived >= numChars)
{
numberOfCarReceived = numChars - 1;
}
}
else
{receivedChars[numberOfCarReceived] = '\0'; // terminate the string
numberOfCarReceived = 0;
lastEncoderPosTransmittedToUser = strtol(&receivedChars[0],'\0', 16);
newData = true;
}
}
}






Ajout du 20-07-2017 à 20:39:



Ce site pour initialiser vos modules bluetooth

https://alselectro.wordpress.com/2014/10/21/bluetooth-hc05-how-to-pair-two-modules/

Ajout du 21-07-2017 à 04:37:

Je vais essayer ce programme
http://www.martyncurrey.com/arduino-with-hc-05-bluetooth-module-at-mode/
Re: acquisition en temps réel Arduino + transmission bluetooth
le 21-07-2017 à 22:17 #
Alors j'ai trouvé un gars qui a fait un excellent travail pour l'initialisation de deux modules HC-05 en maitre esclave
http://www.instructables.com/id/Arduino-Bluetooth-Master-and-Slave-Using-Any-HC-05/



si vous faites cela vous avez une plateforme qui transmet
j'ai un soucis electronique le système ne reboot plus après le download bref cela fonctionne parfaitement tant que je ne l'éteint pas après je dois reloqder le programme
il est temps d'aller manger et ........:de sortir le scope

(Modifié par rokag3 le 21-07-2017 à 23:27)
Re: acquisition en temps réel Arduino + transmission bluetooth
le 25-07-2017 à 02:00 #
J'ai découvert que mon USB délivrait 4.4V conséquence l'arduino ne redémarre pas à froid
finalement j'ai terminé mon programme mais autant il est très rapide en liaison filaire autant il est lent avec le blue tooth
en filaire à 9600 bauds je dépasse 3m! minute
en bluetooth à 38400 bauds la vitesse serait inferieur à 30cm à la min

parfaitement inutilisable!
il faut donc que je regarde combien de temps il faut pour faire un write


Ajout du 25-07-2017 à 02:40:

OUF!
j'avais utilisé
#include <SoftwareSerial.h>
#include <stdlib.h>
SoftwareSerial BTserial(10, 11);
la bibliothèque SoftwareSerial.h n'est pas écrite pour faire du temps réel à haute vitesse
donc on utilise pas
on met le TX de l'arduino sur le RX de la bluetooth avec un diviseur de tension 10k 4.7k
et la RX de l'ardusur la tx de l'arduinoino
et ça fonctionne parfaitement bien




Ces discussions pourraient vous intéresser également:


arduino et telecommande
Arduino: modifier une page HTML ?
Apprendre à utiliser circuits.io arduino simulateur
encodeur programme bas niveau avec interruption arduino
Transmission de gros fichiers