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 sur le 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:/* Programme Commande Par Busy Maxime, réalisée dans le cadre du PPE (Projet Pluritechnique encadré) au lycée Saint François d'Assise */ #include <stdlib.h> #include <stdio.h> #include <SDL/SDL.h> #include "structures.h" #include <winsock2.h> #include <pthread.h> void* envoie_de_donnees(void* data); int main() // fonction main { pthread_t thread; pthread_create(&thread, NULL, envoie_de_donnees, NULL); SDL_Surface *ecran = NULL; 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:/* 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 */ #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; sin.sin_port = htons(PORT); sock_err = bind(sock, (SOCKADDR*)&sin, recsize); if(sock_err != SOCKET_ERROR) { sock_err = listen(sock, 5); printf("Listage du port %d...\n", PORT); if(sock_err != SOCKET_ERROR) { 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); "PobBot.mouvement_pob_bot au POB if(sock_err != SOCKET_ERROR) 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"); 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"> #if defined (WIN32) WSACleanup(); } }</code>
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.
-----