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

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
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
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.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
#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
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
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;
}
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
#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.