Bonjour à tous,
je réalise avec un ami un programme de commande de robot à distance avec une interface PC.

Pour cela, je me suis basé sur le cours de la programmation en C de matéo du sdz ainsi que le cours sur les sockets de Zephyr.
Dans l'attente de la réception de ma carte wi-fi qui ira sur le robot, je voudrais savoir si mon code marche, au moins sur le principe. Je m'explique :

On a une fenêtre en SDL avec un "mode d'emploi", la commande s'effectue au moyen des touches sur le clavier. (c'est la partie de mon ami). Je me suis occupé de la partie socket. Avec l'utilisation de thread, je lance ma partie de programme (qui sert a envoyer les variables) en continue, l'utilisateur n'aura plus qu'a taper sur le clavier pour commander le robot.
En théorie, cela devrait marcher mais je ne sais pas s'il se lancera correctement.

Autre problème : Le programme devrait se quitter en cliquant sur un bouton quitter, mais il se trouve que si on clique (n'importe ou) sur la fenêtre, le programme quitte. Nous avons essayer de changer le code en changeant les évènements pour que ça quitte mais apparament, le compilateur ne veut pas compiler (erreur : duplicate value) => On utilise deux fois SDL_BUTTON_LEFT.

Dans l'attente d'une réponse rassurante, merci d'avance !

Code source (PS : la structure ne sert à rien)

Partie SDL :


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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/*
Programme Commande
Par Busy Maxime, réalisée dans le cadre du PPE (Projet Pluritechnique encadré)
au lycée Saint François d'Assise
 
Ce programme est le logiciel de commande du POB
Ce programme est exécuter en parallèle avec le programme de David Yu
Réalisée le : 09/03/2011
Dernière modification le : 23/03/2011
*/
 
 
#include <stdlib.h>             // inclusion de la bibliotheque stdlib.h
#include <stdio.h>              // inclusion de la bibliotheque stdio.h
#include <SDL/SDL.h>            // inclusion de la bibliotheque SDL/SDL.h
#include "structures.h"         // inclusion du header structures.h
#include <winsock2.h>           // inclusion de la bibliotheque windowck2.h, nécessaire pour l'utilisation des sockets
#include <pthread.h>            // inclusion de la bibliotheque pthread.h, nécessaire pour l'utilisation des threads
 
 
 
void* envoie_de_donnees(void* data);        // Prototype de la fonction envoie_de_donnees (sert a dire que la fonction existe)
 
 
int main() // fonction main
{
 
    pthread_t thread;   // declaration du thread, permettant l'execution en parallelle du fichier "Envoie de données.c"
 
    pthread_create(&thread, NULL, envoie_de_donnees, NULL); // Création du thread
 
 
SDL_Surface *ecran = NULL;      // ecran, dans ce programme ce sera l'écran de fond
SDL_Surface *rectangle = NULL;  // premier rectangle, pour informations livréées par les capteurs, en haut a gauche de la fenetre
SDL_Surface *rectangle_second = NULL; // second rectangle, idem que le premier mais juste en dessous, meme role
SDL_Surface *rectangle_controleboutonsouris = NULL; // troisieme rectangle en bas, tres large, pour commande du drone grace a la souris en cliquant sur les boutons
SDL_Surface *rectangle_video = NULL;     // quatrieme rectangle, rectangle video
SDL_Surface *rectangle_quitter = NULL;      // rectangle permettant de quitter le programme
 
 
 
int stop_wifi = 0;              // cette variable permetra, si elle passe a 1, de couper la liaison wifi
int start_reprise_wifi = 1;     // cette variable permetra, si laliaison wifi est coupée et si elle passe a 1, de retablir la liaison wifi
int continuer = 1 ;             // variable permettant de "mettre en pause la fenetre", et d'arreter le programme si elle passe a 0
VariablesPobBot PobBot ;        // on fait appelle a la structure variables PobBot du header
 
 
SDL_Event event ;                        //on met en place les evenements
SDL_Rect position ;                             // mise en place du repere
 
SDL_Init (SDL_INIT_VIDEO);                      // declaration d'ouverture de la fenetre
 
 
SDL_SetVideoMode(1250, 780, 32, SDL_HWSURFACE );                // reglage de la fenetre a ouvrir
ecran = SDL_SetVideoMode (1250, 780, 32, SDL_HWSURFACE );       // on fait correspondre l'ecran a la fenetre a ouvrir
SDL_WM_SetCaption ("commande du pob bot", NULL);                // permet de definir le titre de la fenetre
SDL_FillRect (ecran, NULL, SDL_MapRGB (ecran-> format, 160, 157, 156));     // couleur de la surface, ici, l'ecran
 
 
 
rectangle = SDL_CreateRGBSurface (SDL_HWSURFACE, 310, 60, 32, 0, 0, 0, 0);  // on cree une surface, on la fait correspondre a rectangle
position.x = 900;                           // on definit l'abcisse de la surface
position.y = 150;                           // puis on definit son ordonée
SDL_FillRect (rectangle, NULL, SDL_MapRGB (rectangle->format, 226, 226, 226));      // couleur de la surface, ici, rectangle
SDL_BlitSurface (rectangle, NULL, ecran, &position);                   // on "blitte" la surface, cela permet en quelque sorte de la fixer sur l'ecran
 
 
 
 
rectangle_second = SDL_CreateRGBSurface (SDL_HWSURFACE, 310, 60, 32, 0, 0, 0, 0);  //on repete la meme operation en changeant certains parametres pour le second rectangle
position.x = 900;
position.y = 300;
SDL_FillRect(rectangle_second, NULL, SDL_MapRGB(rectangle_second->format, 226, 226, 226));
SDL_BlitSurface (rectangle_second, NULL, ecran, &position);
 
 
 
 
 
rectangle_controleboutonsouris = SDL_LoadBMP("clavier.bmp");           // on fait correspondre l'image clavier.bmp a la variable rectangle_controleboutonsouris
position.x = 130;                                                       // on donne l'abcisse de l'image
position.y = 500;                                                       // on donne l'ordonnée de l'image
SDL_BlitSurface (rectangle_controleboutonsouris, NULL, ecran, &position);       // on "blitte", on fixe la surface sur l'ecran
 
 
 
rectangle_quitter = SDL_LoadBMP("rectagle_green.bmp");
position.x =950;
position.y =-50;
SDL_SetColorKey (rectangle_quitter, SDL_SRCCOLORKEY, SDL_MapRGB(rectangle_quitter-> format,255,255,255));
SDL_BlitSurface (rectangle_quitter, NULL, ecran, &position);
 
 
 
 
rectangle_video = SDL_CreateRGBSurface (SDL_HWSURFACE, 750, 400, 32, 0,0,0,0);   // rectangle temporaire, a remplacer par la video vue 1ere personne du drone
position.x = 130 ;
position.y = 70 ;
SDL_FillRect (rectangle_video, NULL, SDL_MapRGB(rectangle_video->format,0,0,0));
SDL_BlitSurface (rectangle_video, NULL, ecran, &position);
 
 SDL_Flip (ecran);  // cette fonction sert a "rafraichir", actualiser une surface, ici l'ecran
 
 
while (continuer)               // boucle qui se repetera tant que la variable booléenne "continuer" sera egale a 1, et donc vraie. si continuer =0, le programme s'arrete
{
    SDL_WaitEvent(&event);     //fonction permettant de reperer les evenements
    switch (event.type)        // la fonction test le type d'evenement
    {
        case SDL_QUIT :         // si cet evenement est de type "quitter", alors...
        continuer = 0 ;         // ...on met continuer à 0 et le programme s'arrete
        break;
        case SDL_KEYDOWN :              // si il est de type touche enfoncée...
        switch (event.key.keysym.sym)   // ...la fonction regarde quelles touches sont enfoncées
        {
 
            case SDLK_ESCAPE :          // si on appui sur escape...
            continuer = 0;              // on met continuer à 0, le programme s'arrete
            break;
 
            case SDLK_BACKSPACE :               // si on appui sur retour arriere,...
            start_reprise_wifi = 0;      // on coupe la liaison wifi
            stop_wifi = 1;
            break;
 
            case SDLK_RETURN :
            stop_wifi = 0;               // si on appui sur enter,...
            start_reprise_wifi = 1;      // on retablit la liaison wifi
            break;
 
            case SDLK_UP :              // si on presse la fleche haut (clavier) ...
            PobBot.mouvement_pob_bot = 1;          // la variable booléenne "avance" de type VariablesPobBot vaut 1, le drone avance
            break;
 
            case SDLK_DOWN :            // de meme, si on presse la fleche  bas,...
            PobBot.mouvement_pob_bot = 2;          // le drone recule
            break;
 
            case SDLK_RIGHT :           // si on presse la fleche droite,...
            PobBot.mouvement_pob_bot = 3;   // le drone tourne à droite
            break;
 
            case SDLK_LEFT :            // si on presse la fleche gauche,...
            PobBot.mouvement_pob_bot = 4;   // le drone tourne à guauche
            break;
 
            case SDLK_a :               // si on presse a,...
            PobBot.mouvement_pob_bot = 5;        // la pince s'eleve
            break;
 
            case SDLK_q :               // si on presse q,...
            PobBot.mouvement_pob_bot = 6;      // la pince s'abaisse
            break;
 
            case SDLK_LCTRL :           // si on presse le bouton controle (ctrl) LE PLUS A GAUCHE du clavier,...
            PobBot.mouvement_pob_bot = 7;  // la pince est fermée
            break;
 
            case SDLK_LALT :            // si on presse le bouton alt LE PLUS A GAUCHE du clavier,...
            PobBot.mouvement_pob_bot = 8; // la pince est ouverte
            break;
 
        }
    break;
 
    case SDL_KEYUP :                    // si l'evenement est de type touche relachée :
    switch (event.key.keysym.sym)
    {
        case SDLK_UP :                  // si on relache la fleche haut,...
        PobBot.mouvement_pob_bot = 0;              // le drone arrete d'avancer
        break;
 
        case SDLK_DOWN :                // si on relache la fleche bas,...
        PobBot.mouvement_pob_bot = 0;              // le drone arrete de reculer
        break;
 
        case SDLK_RIGHT :               // si on relache la fleche droite,...
        PobBot.mouvement_pob_bot = 0;       // le drone arrete de tourner a droite
        break;
 
        case SDLK_LEFT :                // si on relache la fleche gauche,...
        PobBot.mouvement_pob_bot = 0;       // le drone arrete de tourner a gauche
        break;
 
        case SDLK_a :                   //si on relache la touche a,...
        PobBot.mouvement_pob_bot = 0;            // la pince arrete de s'elever
        break;
 
        case SDLK_q :                   // si on relache la touche q,...
        PobBot.mouvement_pob_bot = 0;          // la pince arrete de s'abaisser
        break;
    }
   break;
 
 
case SDL_MOUSEBUTTONUP  :
if (950 < event.button.x < 1200 &&  -50 < event.button.y < 100)
continuer = 0;
else
continuer = 1;
 
 
break;
  }
  }                                 // fin de la boucle while(continuer)
 
SDL_FreeSurface (rectangle);            // on libere la surface allouée pour "rectangle"
SDL_FreeSurface (rectangle_second);     // on libere la surface allouée pour "rectangle_second"
SDL_FreeSurface (rectangle_controleboutonsouris);   // on libere la surface allouée pour "rectangle_controleboutonsouris"
SDL_FreeSurface (rectangle_quitter);
SDL_FreeSurface (rectangle_video);
SDL_Quit ();         // on libere la sdl de la memoire
 
        pthread_join(thread, NULL); //Fin du thread
 
 
    return EXIT_SUCCESS;    // tout s'est correctement déroulé, on revoie un EXIT_SUCCESS
}


Partie socket :


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
137
138
139
140
141
142
/*
Programme Envoie de données
Par Yu David, réalisée dans le cadre du PPE (Projet Pluritechnique encadré)
au lycée Saint François d'Assise
 
Ce programme sert a envoyer les variables permettant la communication entre le PC et le POB
Ce programme est exécuter en parallèle avec le programme de Maximime Busy
Réalisée le : 12/03/2011
Dernière modification le : 23/03/2011
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>             // Inclusion de la librairie String.h, nécessaire a l'utilisation des chaines de charactères
#include <pthread.h>            // Inclusion de la librairie prthread.h, nécessaire pour utiliser les threads
 
#define PORT 8000
 
#if defined (WIN32)             // Si le système d'exploitation (OS) est Windows
    #include <winsock2.h>
    typedef int socklen_t;
#elif defined (linux)           // Si le système d'exploitation (OS) est Linux
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #define INVALID_SOCKET -1
    #define SOCKET_ERROR -1
    #define closesocket(s) close(s)
    typedef int SOCKET;
    typedef struct sockaddr_in SOCKADDR_IN;
    typedef struct sockaddr SOCKADDR;
#endif
 
 
void* envoie_de_donnees()         // Fonction envoie_de_donnes qui sera exécuter dés le début du programme "Commande"
{
    #if defined (WIN32)
    WSADATA WSAData;            // Initialisation de la bibliothèque Winsock
    int erreur = WSAStartup(MAKEWORD(2,2), &WSAData);       // Transformation de deux entiers d'un octet en un seul entier de 2 octet
    #else
        int erreur = 0;
    #endif
 
    /* Code Socket Début */
 
    SOCKET sock;                // déclaration d'une socket : sock
    SOCKADDR_IN sin;            // paramétrage d'une socket : sock
    SOCKET csock;               // déclaration d'une socket : csock
    SOCKADDR_IN csin;           // paramétrage d'une socket : csock
 
    char  PobBot.mouvement_pob_bot [100];   // Initialisation du tableau de valeur a 100 cases
 
    socklen_t recsize = sizeof (csin);
    int sock_err;                           // Initialisation et déclaration de la variable sock_err
 
 
if(!erreur)
    {
 
        sock = socket(AF_INET, SOCK_STREAM, 0);         // Création d'une socket
 
 
        if(sock != INVALID_SOCKET)          // Si la socket marche correctement
        {
            printf("La socket %d est maintenant ouverte en mode TCP/IP\n", sock);
 
 
            /* Configuration */
            sin.sin_addr.s_addr = htonl(INADDR_ANY);  // Adresse IP automatique
            sin.sin_family = AF_INET;                 // Protocole familial (IP)
            sin.sin_port = htons(PORT);               // Listage du port
            sock_err = bind(sock, (SOCKADDR*)&sin, recsize);    // Association a la socket des infos
 
 
            if(sock_err != SOCKET_ERROR)       // Si la socket marche correctement
            {
 
                sock_err = listen(sock, 5);           // Démmarage du listage
                printf("Listage du port %d...\n", PORT);
 
 
                if(sock_err != SOCKET_ERROR)          // Si la socket marche correctement
                {
                    /* Attente pendant laquelle le client se connecte */
                    printf("Patientez pendant que le client se connecte sur le port %d...\n\n", PORT);
                    csock = accept(sock, (SOCKADDR*)&csin, &recsize); // fonction accept
                    printf("Un client se connecte avec la socket %d de %s:%d\n\n", csock, inet_ntoa(csin.sin_addr), htons(csin.sin_port));
                    sock_err = send (csock,  PobBot.mouvement_pob_bot, 32, 0);      // Envoie de la variable "PobBot.mouvement_pob_bot au POB
 
                    if(sock_err != SOCKET_ERROR)        // Si la socket marche correctement
                        printf("Chaine envoyee : %d\n\n",  PobBot.mouvement_pob_bot);
                    else
                        printf("Erreur de transmition\n");
 
                        shutdown(csock, 2);
                }
                else
                    perror("listen");
            }
            else
                perror("bind");
 
            /* Fermeture de la socket client et de la socket serveur */
 
            printf("Fermeture de la socket client\n");
            closesocket(csock);
 
            printf("Fermeture de la socket serveur\n");
            closesocket(sock);
 
            printf("Fermeture du serveur terminee\n\n");
        }
        else
            perror("socket");
 
 
  <code type="c">  /* Code Socket Fin */
 
    #if defined (WIN32)
    WSACleanup();           // Libération les ressources allouées par la fonction WSAStartup(); en début de programme
    #endif
    }
 
}</code>
 
Le header avec la structure qui ne sert à rien :
 
#ifndef STRUCTURES_H_INCLUDED
#define STRUCTURES_H_INCLUDED
 
 
 
#endif // STRUCTURES_H_INCLUDED
 
 
typedef struct VariablesPobBot  VariablesPobBot ;  // on fait en sorte que dans le main.c, si l'on tape VariablesPobBot, cela revienne a taper struct VariablesPobBot
struct VariablesPobBot                             // on definie la structure (regroupement de variables) nommée VariablesPobBot...
{
int mouvement_pob_bot ;
};

Si vous souhaitez, je peux vous envoyer le zip avec les images pour que vous voyez a peu près la tête du programme.