Programme de Commande

Fermé
Frutichaos Messages postés 1 Date d'inscription mercredi 30 mars 2011 Statut Membre Dernière intervention 30 mars 2011 - Modifié par Frutichaos le 30/03/2011 à 14:33
Bonjour,





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 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 :

/*  
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 :



/*  
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  
    }  

}


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

</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.