Frutichaos
Messages postés1Date d'inscriptionmercredi 30 mars 2011StatutMembreDernière intervention30 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
}
}
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.