Bonjour, je suis également stagiaire. On m'a confier la mission de créer un client afin de piloter un petit robot(wifibot) tout en obtenant des informations en temps réel sur son état grâce à des capteurs installés sur lui. Une grande partie de la programmation se fait en c++ et malheureusement, je ne connais ce langage que depuis peu. Je souhaiter réaliser des boucles d'envoi/réceptions périodiques tant que la connexion via socket est établi,. Pour ne pas bloquer mon programme, j'ai lu que si je voulais réaliser des autres actions en parallèle, il fallait que j'utilise des thread. J'ai utilisé des thread de la classe QThread dans ce but.
Le problème est que lorsque je compile mon programme, j'obtiens cette erreur
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0x8454b90), parent's thread is QThread(0x8454448), current thread is clientServeur(0x8454b88)
D'après ce que j'ai lu sur d'autres forum, L'enfant d'un QObject doit toujours être crée dans un thread où le parent a été crée, mais le problème est que je ne sais pas du tout comment corriger mon erreur vu que je malgré cette belle explication, je ne la situe pas du tout dans mon programme.
J'ai également lu qu'il fallait utiliser la fonction movetoThread() mais pareil je ne sais pas comment l'implémenter.
Je vous donne les liens de documentation que j'ai trouvé:
- http://qt.developpez.com/faq/?page=Thread
- http://qt.developpez.com/doc/3.3/qthread/
- http://qt-labs.developpez.com/thread...-movetothread/
Je serais très reconnaissant si vous pouviez me guider afin que je trouve la solution de mon problème et me dire comment le résoudre (à l'exception de la classe consigne qui n'est pas importante).
Je vous donne le code que j'ai produit pour l'instant:
clientServeur.h
clientServeur.cpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 #ifndef CLIENTSERVEUR_H #define CLIENTSERVEUR_H #include <iostream> #include <string> #include <QtNetwork/QTcpSocket> #include <QMutex> #include <QThread> #include "consigne.h" using namespace std; class clientServeur : public QThread { Q_OBJECT private: QTcpSocket socket; //Socket utilisé pour communiquer avec le robot QString ipaddr; //adresse IP du robot const static int LOOPTIME=500000; // Temps en uS avant deux cycles de lecture/écriture au robot const static int DEFAULT_PORT=15000;//port TCP de base utilisé pour se connecter au robot int port; //port tcp QMutex mutex; //Mutex utilisé pour bloquer l'accès aux variables sbuf et rbuf (Thread) char rbuf[7]; //variable temporaire de lecture/réception quint8 sbuf[2];//variable temporaire d'écriture/envoi bool quit; //On arrête le thread si le booleen "quit" est vrai int connect(); //Ouvre la connection avec le robot. Cette méthode privée doit être appellé uniquement //par la méthode run() pour débuter la communication avec le serveur robot //protected: public: //Les constructeurs et destructeur clientServeur() ;//Initialise avec ip=192.168.1.106 et port 15020 void run(); void lancement_boucle(); clientServeur(string ip); //port 15020 clientServeur(string ip, int ipport); //Initialise avec ip=192.168.1.106 et port 15020 clientServeur(int port); ~clientServeur(); void appliquer(Consigne cons); //Applique la commande en fonction de la consigne //Vérifie d'abord la consigne est valide, puis l'applique. void getData(char* data); //obtient des informations du serveur }; #endif // CLIENTSERVEUR_H
Robot.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 #include "clientServeur.h" //Les constructeurs et destructeur clientServeur::clientServeur() : port(DEFAULT_PORT), ipaddr("127.0.0.1"), quit(false), QThread() { start(); } clientServeur::clientServeur(string ip, int ipport) : ipaddr(QString(ip.c_str())) , port(ipport), quit(false), QThread() { start(); } clientServeur::clientServeur(string ip): ipaddr(QString(ip.c_str())) , port(DEFAULT_PORT), quit(false), QThread() { start(); } clientServeur::clientServeur(int nport) : ipaddr("127.0.0.1") , port(nport), quit(false), QThread() { start(); } clientServeur::~clientServeur() { mutex.lock(); quit = true; mutex.unlock(); if (!socket.isOpen()) { socket.close(); } } int clientServeur::connect() //Connecte le robot { if (!socket.isOpen()) { socket.connectToHost(ipaddr,DEFAULT_PORT,QIODevice::ReadWrite); if (!socket.waitForConnected(-1)) { cout<< "ERREUR:"<<socket.errorString().toStdString()<<endl; return -1; } cout<< "SOCKET CONNECTEE" <<endl; } } void clientServeur::appliquer(Consigne cons) //Aplique la commande, la méthode run() va l'envoyer dans la boucle du thread { //c'est pourquoi mutex est fermé! // si la consigne est valide if (cons.estValide()) { int vG = cons.getVitG(); int vD = cons.getVitD(); int ctrlV = int(cons.getSpeedControl()); //Moteur Gauche: Avance ou recule; est égale à 1 si ça avance, égale à 0 si ça recule int avanceG; if ( vG > 0) avanceG = 1; else avanceG = 0; //Moteur Droit: Avance ou recule; est égale à 1 si ça avance, égale à 0 si ça recule int avanceD; if ( vD > 0) avanceD = 1; else avanceD = 0; cout<<"vG= "<< vG <<" et vD="<< vD <<endl; mutex.lock(); // ferme le mutex sbuf[0] = quint8(128*ctrlV + 64 * avanceG + abs(vG)); //Moteur gauche sbuf[1] = quint8(128*ctrlV + 64 * avanceD + abs(vD)); //Moteur droit mutex.unlock(); //Dévérouille le mutex cout << "commande appliquer exécutée" << endl; } } void clientServeur::getData(char* data) //Copie le contenu de "rbuf" qui est provisoire(buffer) dans "data" { mutex.lock(); for (int i=0;i<7;i++) { data[i] = rbuf[i]; } cout << "data[1] vaut : " << data[1] << endl; mutex.unlock(); } void clientServeur::run() { lancement_boucle(); } void clientServeur::lancement_boucle() { if (connect()==-1) { mutex.lock(); quit = true; mutex.unlock(); } cout << "DEMARRAGE THREAD..." <<endl; while(!quit && socket.isOpen()) { // On ferme le mutex mutex.lock(); //cout << "début cycle" << endl; //Envoi Commande socket.waitForBytesWritten(300); bool nor0 = socket.putChar(sbuf[0]); bool nor1 = socket.putChar(sbuf[1]); int nb = int(nor0) + int(nor1); cout << "Envoie de " << nb << "octets" << endl; socket.flush(); //Lecture socket.waitForReadyRead(300); //cout<< "Octets a lire :"<< socket.bytesAvailable()<< endl; int nor = socket.read(rbuf,7); //Lit et dispose dans les rbuffer // cout<<"Nombre d'octets lus :"<< nor << endl; mutex.unlock(); cout << "fin cycle thread" << endl; usleep(LOOPTIME);//temps d'attente entre deux boucles envoi/réception } cout<<"ARRET THREAD"<<endl; }
robot.cpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 #ifndef ROBOT_H #define ROBOT_H #define PI 3.1415926536 #include <QtNetwork/QTcpSocket> #include <QMutex> #include <string> #include "consigne.h" #include "clientServeur.h" #include <iostream> using namespace std; class Robot { private: Consigne cons; quint8 vitG; quint8 vitD; quint8 batterie; quint8 distG; quint8 distD; clientServeur *client; const static float DIAMETRE = 0.125; public: //Constructeur Robot(); Robot(string ip); Robot(Consigne cons); ~Robot(); //Méthodes void modifier(Consigne cons); void modifier(float vitesse); //Donne une consigne de vitesse sans passer par la classe consigne, s'applique aux deux roues void accelerer(); void ralentir(); void stopper(); // void tourner(quint8 direction); quint8 getVitReelleG(); quint8 getVitReelleD(); quint8 getBatterie(); quint8 getDistanceG(); quint8 getDistanceD(); }; #endif // ROBOT_H
main.cpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 #include "Robot.h" Robot::Robot() :vitG(0) , vitD(0), batterie(0), distD(0), distG(0), cons(0,0) { client = new clientServeur(); } Robot::~Robot() { delete client; } //Méthodes void Robot::modifier(Consigne cons) { int vG = cons.getVitG(); int vD = cons.getVitD(); cons.modifier(vG, vD); //Modifie la consigne if (cons.estValide() == false) { cons.limiter(); client->appliquer(cons); } } void Robot::modifier(float vitesse) //Donne une consigne de vitesse , s'applique aux deux roues { cons.modifier(vitesse, vitesse); modifier(cons); } void Robot::accelerer() //Donne une consigne de vitesse, s'applique aux deux roues { cons.augmenter(5,5); if (cons.estValide() == false) { cons.limiter(); } } void Robot::ralentir() { cons.diminuer(5,5); if (cons.estValide() == false) { cons.limiter(); } } void Robot::stopper() { cons.modifier(0, 0); } /*void Robot::tourner(quint8 direction) { }*/ quint8 Robot::getVitReelleG() { char data[7]; quint8 vitGAvant; quint8 vitGArriere; client->getData(data); vitGAvant = (DIAMETRE*PI*quint8 (data[1]))/12; vitGArriere = (DIAMETRE*PI*quint8 (data[2]))/12; vitG = (vitGAvant + vitGArriere)/2; return vitG; } quint8 Robot::getVitReelleD() { char data[7]; quint8 vitDAvant; quint8 vitDArriere; client->getData(data); vitDAvant = (DIAMETRE*PI*quint8 (data[3]))/12; vitDArriere = (DIAMETRE*PI*quint8 (data[4]))/12; vitD = (vitDAvant + vitDArriere)/2; return vitD; } quint8 Robot::getBatterie() { char data[7]; client->getData(data); batterie = quint8 (data[0]); return batterie; } quint8 Robot::getDistanceG() { char data[7]; client->getData(data); distG = quint8 (data[5]); return distG; } quint8 Robot::getDistanceD() { char data[7]; client->getData(data); distD = quint8 (data[6]); return distD; }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 #include <QtCore/QCoreApplication> #include <QMutex> #include "clientServeur.h" #include "consigne.h" #include "Robot.h" #include <iostream> using namespace std; int main(int argc, char *argv[]) { cout << "début application" << endl; cout << "Création robot" << endl; Robot monrobot; cout << "Fin Création robot" << endl; cout << "début tempo" << endl; unsigned int i(0); while (i<10000000000) { } cout << "fin tempo" << endl; cout << "fin application" << endl; }
Je serai heureux si vous pouviez m'aider.![]()
Partager