View  Edit  Attributes  History  Attach  Print  Search

ACCUEIL | ARDUINO > S'INSTALLER > DEBUTER > APPROFONDIR | PROCESSING | MECATRONIQUE | MATERIEL | OUTILS | TESTS | Plus...|
Python > Shell > ATELIERS Python + Qt > PyQt apps > PyQt+Arduino | Mes Robots | RepRap | Mes lib'Arduino | Mes shields Arduino | Mes distros | Les Mini-PC |
ATELIERS ARDUINO| VIDEOS | COMPRENDRE | REFERENCES | CODER | TECHNIQUE | GNU/LINUX | LIENS | Rien à voir |

Principe de déploiement d'une connexion entre 2 cartes Arduino via 2 PC en réseau wifi

Par X. HINAULT. Le 06 Avril 2011.

Intro

  • Pour mettre en place la chaîne des 4 programmes nécessaires à la mise en place de cette connexion par réseau wifi, il faut procéder par étape et avec un minimum de rigueur. Pour autant, çà n'est pas très compliqué.
  • Je vous propose ici une démarche pas à pas qui part de la façon habituelle d'utiliser Arduino pour l'étendre sur le réseau wifi. A chaque étape, je proposerai une façon de tester le bon fonctionnement de ce qui aura été mis en place, bien que toute la chaine de communication ne soit pas installée.
  • On commencera donc du programme Arduino serveur qui correspond à l'équivalent de la carte Arduino que l'on programme habituellement avec son PC.
  • Un exemple type d'utilisation de la chaîne de communication décrite ici, est l'utilisation d'un eeePC embarqué avec une carte Arduino de contrôle des moteurs sur un robot que l'on contrôle depuis le pc fixe, la carte Arduino fixe permettant l'utilisation d'un joystick par exemple pour contrôler le robot. Le PC fixe permettra également d'avoir le retour webcam du robot ainsi que la télémétrie des capteurs du robot : ni plus ni moins ! J'ai testé tout cela et çà marche bien : suivez le guide !
  • Comme on va le voir, un programme Arduino utilisant la communication série avec le PC en local va pouvoir être porté sur le réseau distant tel quel !! Toute la gestion de la communication via le réseau est assurée par 2 interfaces Processing Serveur/Client : ces interfaces Processing utilisées pour réaliser le "pont" vers le réseau se comporteront de façon transparentes et on recevra sur le PC distant ce que l'on aurait normalement reçu via le port série sur le PC en local !
  • On voit ici tout l'intérêt de cette façon de faire en terme de gain de temps : un programme Arduino mis au point en local pourra être utilisé sur le réseau immédiatement sans être modifié !!

Etapes préalables à la mise en place du réseau wifi entre les 2 cartes Arduino.

La mise en place du réseau wifi entre les 2 PC nécessite :

Ici, nous utilisons le port 5905.

Une connaissance minimale en structure de réseau est nécessaire ici :

  • savoir ce qu'est une adresse ip, un sous-masque réseau, un réseau
  • savoir ce qu'est un port
  • savoir ce qu'est un routeur, ce qu'est l'attribution des adresses ip en DHCP.

Rien d'inaccessible cependant !

Le schéma fonctionnel de la chaîne de connexion à réaliser

  • Voici le schéma fonctionnel de la chaine globale de programmes utilisée :

Détail des relations au sein de la chaîne de programmes utilisée

  • Toute la puissance l'interface Processing apparaît ici une nouvelle fois : les possibilités sont énormes si on considère par exemple la librairie Minim pour la gestion des fichiers sons, la librairie OpenCV pour la reconnaissance visuelle, les fonctions propres de Processing pour le traitement d'image et le graphisme, la librairie controlP5 pour la réalisation d'interface GUI et donc les librairies Serial pour la communication Série et Network pour les communications réseau.
  • En bref, grâce à Processing et Arduino utilisés ensembles, j'ai réussi à faire en une année ce que j'essayais de faire depuis 10 ans, et même à faire des choses que je n'aurai jamais imaginée être à ma portée un jour (suivi d'objet par exemple...). Cette page est d'ailleurs un bel exemple de la puissance du couplage Arduino / Processing. Que du libre et opensource et que du bon, et même du très bon !
  • J'ai tenté de rassembler sur ce schéma l'articulation entre les programmes au niveau du code lui-même :

Ce que nous allons faire ici...

  • On va faire ici quelque chose de simple (enfin presque...!) :
    • on va faire transiter une chaîne de caractères de la carte Arduino "client" vers la carte Arduino "serveur"
      • la carte Arduino "client" va émettre à intervalle régulier une chaine de caractères vers le "client" Processing via le port Série côté client.
      • le "client" Processing va envoyer la chaine reçue vers l'interface Processing "serveur" via le réseau wifi.
      • l'interface Processing "serveur" va envoyer la chaine reçue vers la carte Arduino "serveur" via le port série côté "serveur".
    • on va ensuite faire transiter une chaine de caractère de réponse de la carte Arduino "serveur" jusqu'à l'interface Processing "client" :
      • la carte Arduino "serveur" va émettre en réponse à la chaine reçue une chaine de caractère vers le "serveur" Processing via le port série côté "serveur".
      • le "serveur" Processing va envoyer la chaine reçue vers l'interface Processing "client" via le réseau wifi.
  • A chaque étape, les consoles des interfaces Processing aaficheront des messages attestant du parcours de la chaine de caractère entre les 4 programmes.
  • On rappelle qu'il faut :
  • Prêt ? Allez, c'est parti !

Détail des étapes de communication de la chaine série <-> wifi <-> série

  • La chaine de communication utilisée comporte 12 étapes distinctes, 6 dans chaque sens. J'ai numéroté ces étapes de la façon suivante :
  • Cette numérotation est celle qui sera utilisée par les messages des interfaces Processing de test que je présente ici. Les 2 interfaces Processing que je vous propose permettent "d'injecter" une chaine de caractères dans séquence de communication à différents point d'entrée comme cela est schématisé. Ceci permettra de vérifier simplement que tout fonctionne bien.

Etape 1 : le programme Arduino "serveur" (sur la carte Arduino distante)

Ce que fait ce programme

  • Cette étape est la plus simple : un programme Arduino classique reçoit une chaine de caractères sur le port série et envoi une réponse sur le port série.

Principe du code

Exemple de code

// --- Programme Arduino ---
// Trame de code générée par le générateur de code Arduino
// du site www.mon-club-elec.fr

// Auteur du Programme : X. HINAULT - Tous droits réservés
// Programme écrit le : 31/3/2011.

// ------- Licence du code de ce programme -----
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License,
//  or any later version.
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

// ////////////////////  PRESENTATION DU PROGRAMME ////////////////////

// -------- Que fait ce programme ? ---------
 /* Ce programme reçoit une chaine sur le port Série et renvoie la chaine reçue pour attester que la chaine est bien reçue.  */

// --- Fonctionnalités utilisées ---

// Utilise la connexion série matérielle vers le PC
// Utilise / fonctionne avec une interface Processing coté PC

// -------- Circuit à réaliser ---------

// La connexion série matérielle vers le PC utilise les broches 0 et 1 (via le câble USB)


// /////////////////////////////// 1. Entête déclarative ///////////////////////
// A ce niveau sont déclarées les librairies incluses, les constantes, les variables, les objets utiles...

// --- Déclaration des constantes ---

// --- Inclusion des librairies ---

// --- Déclaration des constantes utiles ---

// --- Déclaration des constantes des broches E/S numériques ---


// --- Déclaration des constantes des broches analogiques ---


// --- Déclaration des variables globales ---

int octetReception=0; // variable de stockage des valeurs reçues sur le port Série
String chaineReception=""; // déclare un objet String vide pour reception chaine



// --- Déclaration des objets utiles pour les fonctionnalités utilisées ---


// ////////////////////////// 2. FONCTION SETUP = Code d'initialisation //////////////////////////
// La fonction setup() est exécutée en premier et 1 seule fois, au démarrage du programme

void setup()   { // debut de la fonction setup()

// --- ici instructions à exécuter 1 seule fois au démarrage du programme ---

// ------- Initialisation fonctionnalités utilisées -------  

Serial.begin(115200); // initialise connexion série matérielle à 115200 bauds
// IMPORTANT : régler le terminal côté PC avec la même valeur de transmission


// ------- Broches en sorties numériques -------  

// ------- Broches en entrées numériques -------  

// ------- Activation si besoin du rappel au + (pullup) des broches en entrées numériques -------  

// ------- Initialisation des variables utilisées -------  

// ------- Codes d'initialisation utile -------  

} // fin de la fonction setup()
// ********************************************************************************

////////////////////////////////// 3. FONCTION LOOP = Boucle sans fin = coeur du programme //////////////////
// la fonction loop() s'exécute sans fin en boucle aussi longtemps que l'Arduino est sous tension

void loop(){ // debut de la fonction loop()


// --- ici instructions à exécuter par le programme principal ---

//---- code type réception valeur sur le port série ---

if (Serial.available()>0) { // si un octet en réception


//---- code type réception chaine sur le port série ---
while (Serial.available()>0) { // tant qu'un octet en réception

        octetReception=Serial.read(); // Lit le 1er octet reçu et le met dans la variable

        if (octetReception==10) { // si Octet reçu est le saut de ligne
                Serial.println (chaineReception); // affiche la chaine recue
                //chaineReception=""; //RAZ le String de réception
                break; // sort de la boucle while
        }
        else { // si le caractère reçu n'est pas un saut de ligne
                chaineReception=chaineReception+char(octetReception); // ajoute le caratère au String
        }

} // fin tant que  octet réception

} // --- fin Serial available

//----- une fois que le saut de ligne est reçu, on sort du While et on se positionne ici


chaineReception=""; //RAZ le String de réception

//while(1); // stop loop

} // fin de la fonction loop() - le programme recommence au début de la fonction loop sans fin
// ********************************************************************************


// ////////////////////////// FONCTIONS DE GESTION DES INTERRUPTIONS ////////////////////


// ////////////////////////// AUTRES FONCTIONS DU PROGRAMME ////////////////////



// ////////////////////////// Fin du programme ////////////////////

Tester ce programme

Préparation du Terminal côté PC dans le logiciel Arduino

  • Côté PC, il faut ouvrir la fenêtre terminal de l'IDE Arduino : pour ce faire, un simple clic sur le bouton « Sérial Monitor ».
  • La fenêtre « Terminal » s'ouvre alors :
  • Il faut alors régler le débit de communication sur la même valeur que celle utilisée par le programme avec lequel nous allons programmer la carte Arduino :

Point important, il faut également activer l'option "newline" qui active l'envoi du caractère '\n' (ascii 10) lorsque l'on saisi quelque chose dans le champ du Terminal suivi d'un <send>

  • Saisir une chaîne dans le champ texte du Terminal suivi de envoi : la réponse avec la chaîne recue s'affiche dans la fenêtre :
  • Bien, jusque là, rien de très compliqué... On continue..

Etape 2 : le programme Processing "serveur" (sur le PC distant)

Ce que fait ce programme

  • Ce code fournit la communication entre le réseau et la carte Arduino côté "serveur".
  • Deux champs texte permettent d'envoyer une chaine de caractère de test vers le serveur Arduino via le port série ou vers le client Processing via le réseau.

Principe du code

Exemple de code


// Programme processing
// généré avec le générateur de code Processing
// www.mon-club-elec.fr
// par X. HINAULT - Avril 2011 - tous droits réservés

/////////////// Description du programme ////////////
// Utilise un/des objets String (chaîne de caractère)
// Utilise le port Serie
// Utilise un Serveur réseau

// Utilise la librairie GUI controlP5
// Utilise un/des bouton(s) simple(s) (Button)
// Utilise un/des champ(s) texte (Textfield)
// Ajoute un bouton et un champ pour chemin fichier

/*
Envoie vers Arduino une chaîne saisie dans un champ texte.
Reçoit la chaine renvoyée par Arduino et l'affiche dans la console.
Déclare également un serveur réseau
*/


// XXXXXXXXXXXXXXXXXXXXXX ENTETE DECLARATIVE XXXXXXXXXXXXXXXXXXXXXX

// inclusion des librairies utilisées

import processing.serial.*; // importe la librairie série processing

import processing.net.*; // importe la librairie pour connexion réseau Client/Serveur

import controlP5.*; // importe la librairie GUI controlP5
// cette librairie doit être présente dans le répertoire /libraries du répertoire Processing
// voir ici : http://www.sojamo.de/libraries/controlP5/

// déclaration objets

String str1 = "machaine"; // déclare un objet String (chaine de caractère)
String chaineEnvoiSerie = ""; // déclare un objet String (chaine de caractère)
String chaineEnvoiNetwork = ""; // déclare un objet String (chaine de caractère)

// --- port Série ---
Serial serialServerBoard; // Création objet désignant le port série de la carte Arduino "serveur"
String inStringFromServerBoard; // pour réception chaine en provenance carte Arduino "serveur"

// --- objet Client Réseau ---
Client clientNetwork; // déclaration d'un objet client réseau (pour réception données depuis client réseau)

// --- objet Serveur Réseau ---
Server serverNetwork; // déclaration d'un objet Serveur réseau = cet ordinateur
String inStringFromClientNetwork; // pour réception chaine en provenance Client réseau


//--------- librairie GUI controlP5 -----------
ControlP5 controlP5; // déclare un objet principal de la librairie GUI controlP5


Button serialButton; // déclare objet Button  
Button networkButton; // déclare objet Button  

Textfield serialText; // déclare des objets Textfield
Textfield networkText; // déclare des objets Textfield

// déclaration variables globales

//------ déclaration des variables de couleur utiles ----
int jaune=color(255,255,0);
int vert=color(0,255,0);
int rouge=color(255,0,0);
int bleu=color(0,0,255);
int noir=color(0,0,0);
int blanc=color(255,255,255);
int bleuclair=color(0,255,255);
int violet=color(255,0,255);

//---- variables utiles réseau ----
boolean clientConnected=false; // variable témoin connexion client active

String ipClient="192.168.0.3"; // ip du client (pas du serveur!) sur réseau wifi local
//String ipClient="127.0.0.1"; // ip du client sur boucle locale

int portNetwork=5905; // pour reseau wifi
//int portNetwork=12345; // port sur boucle locale

// XXXXXXXXXXXXXXXXXXXXXX  Fonction SETUP XXXXXXXXXXXXXXXXXXXXXX

void setup(){ // fonction d'initialisation exécutée 1 fois au démarrage

        // ---- initialisation paramètres graphiques utilisés
        colorMode(RGB, 255,255,255); // fixe format couleur R G B pour fill, stroke, etc...
        fill(0,0,255); // couleur remplissage RGB
        stroke (0,0,0); // couleur pourtour RGB
        rectMode(CORNER); // origine rectangle : CORNER = coin sup gauche | CENTER : centre
        imageMode(CORNER); // origine image : CORNER = coin sup gauche | CENTER : centre
        //strokeWeight(0); // largeur pourtour
        frameRate(30);// Images par seconde

        // --- initialisation fenêtre de base ---
        size(400, 130); // ouvre une fenêtre xpixels  x ypixels
        background(jaune); // couleur fond fenetre

// --- initialisation des objets et fonctionnalités utilisées ---

        //------------- initialisation port série ----
        println(Serial.list()); // affiche dans la console la liste des ports séries
        // Vérifier que le numéro du port série utilisé est le meme que celui utilisé avec  Serial.list()[index]
        //serialServerBoard = new Serial(this, Serial.list()[1], 115200); // Initialise une nouvelle instance du port Série - utilisé par la carte Arduino "serveur"
        serialServerBoard = new Serial(this, "/dev/ttyUSB0", 115200); // Initialise une nouvelle instance du port Série - utilisé par la carte Arduino "serveur"
        serialServerBoard.bufferUntil('\n'); // attendre arrivée d'un saut de ligne pour générer évènement série

        //======== Initialisation Objets GUI ControlP5 =========

        controlP5 = new ControlP5(this); // initialise l'objet principal de la librairie GUI controlP5

        // typeObjet nomObjet=controlP5.addObjet(paramètres); // pour info : déclaration / initialisation possible en 1 ligne
        // Textfield field = controlP5.addTextfield("myWindowTextfield",70,130,100,20); // exemple

        //======== Initialisation Objets Button =========

        //---- le bouton envoi chaine vers serveur Arduino port série
        serialButton=controlP5.addButton("serialButton",0,110,35,200,24); // initialise et ajoute un Button au ControlP5
        serialButton.setLabelVisible(true); // affichage des labels
        serialButton.setLabel("==> ENVOI serie vers serveur Arduino"); // fixe label du bouton
        serialButton.setColorActive(color(255,0,0)); // fixe la couleur active
        serialButton.setColorForeground(color(0,255,255)); // fixe couleur avant

        //---- le bouton envoi chaine vers client réseau Processing
        networkButton=controlP5.addButton("networkButton",0,110,35+60,200,24); // initialise et ajoute un Button au ControlP5
        networkButton.setLabelVisible(true); // affichage des labels
        networkButton.setLabel("==> ENVOI reseau vers client Processing"); // fixe label du bouton
        networkButton.setColorActive(color(255,0,0)); // fixe la couleur active
        networkButton.setColorForeground(color(0,255,255)); // fixe couleur avant

        //======== Initialisation Objets Textfield =========

        //---- champ texte saisie chaine
        serialText=controlP5.addTextfield("serialText",10,10,300,20); // initialise et ajoute un Textfield au ControlP5
        serialText.setAutoClear(false); // autoeffacement après return
        serialText.setValue(chaineEnvoiSerie); // initialise Texte du champ
        serialText.setLabelVisible(true); // affichage des labels
        serialText.setLabel("Saisir chaine"); // fixe label
        serialText.setColorLabel(bleu); // fixe la couleur label
        serialText.setColorActive(color(255,0,0)); // fixe la couleur active
        serialText.setColorForeground(color(0,255,255)); // fixe couleur avant

        //---- champ texte saisie chaine
        networkText=controlP5.addTextfield("networkText",10,10+60,300,20); // initialise et ajoute un Textfield au ControlP5
        networkText.setAutoClear(false); // autoeffacement après return
        networkText.setValue(chaineEnvoiNetwork); // initialise Texte du champ
        networkText.setLabelVisible(true); // affichage des labels
        networkText.setLabel("Saisir chaine"); // fixe label
        networkText.setColorLabel(bleu); // fixe la couleur label
        networkText.setColorActive(color(255,0,0)); // fixe la couleur active
        networkText.setColorForeground(color(0,255,255)); // fixe couleur avant

//------------- initialisation objet Serveur réseau ----
  serverNetwork = new Server(this, portNetwork); // Ouvre un simple Serveur sur port
  //serverNetwork = new Server(this, 5905); // Ouvre un simple Serveur sur port 5905

  // info : le port utilisé doit être ouvert sur le PC client et le PC serveur ainsi que sur le routeur du réseau
  // info : l'adresse du serveur devra être utilisé par le client

  println("Serveur : Serveur réseau actif !");


} // fin fonction Setup

// XXXXXXXXXXXXXXXXXXXXXX Fonction Draw XXXXXXXXXXXXXXXXXXXX

void  draw() { // fonction exécutée en boucle

//------------- Code pour Serveur Réseau ----

  clientNetwork = serverNetwork.available(); // l'objet client est un client connecté au serveur si il existe - renvoie null sinon
  // available() différent de null seulement si client existe ET caractères disponibles

  if (clientNetwork != null) { // si myClient existe

    //------------- réception de la chaine émise par le client réseau -----------
    inStringFromClientNetwork = clientNetwork.readString(); // lit la chaine envoyée par le Client
    print ("4. Réception serveur Processing <== client Processing : "+inStringFromClientNetwork); // affiche la chaine reçue
    //inStringClient = inStringClient.substring(0, inStringClient.indexOf("\n")); // Garde uniquement ce qui est avant le saut de ligne

    //--------- renvoi de la chaine sur le port Série de la carte Arduino serveur --------
    serialServerBoard.write(inStringFromClientNetwork); // envoie la chaine suivi saut ligne sur le port Série
    print ("5. Envoi Serveur Processing ==> serveur Arduino : "+inStringFromClientNetwork); // affiche la chaine envoyée

  } // fin si client existe


} // fin de la fonction draw()

// XXXXXXXXXXXXXXXXXXXXXX Autres Fonctions XXXXXXXXXXXXXXXXXXXXXX

//--------------- Fonction de gestion Evènement Serveur = survient lorsque client se connecte ------------

// Doc : The code inside serverEvent() is run when a new client connects to a server that has been created within the program.

void serverEvent(Server someServer, Client clientEntrant) { // la fonction reçoit l'objet serveur et un objet client de réception

  if (clientEntrant != null) { // toujours le cas ici normalement car l'évènement survient quand un client se connecte
    println("Serveur : Un client s'est connecté avec l'adresse : " + clientEntrant.ip());
  }

  if (match(clientEntrant.ip(),ipClient)!=null)  { // si l'adresse ip du client est celle attendue
    println("Serveur : Le client connecté est le client attendu (ip= " + clientEntrant.ip()+") !");
    clientConnected=true; // mémorise connexion active
  }
  else {
    println("Serveur : Le client connecté n'est pas le client attendu !");
  }

} //--- fin gestion évènement serveur ----

//------------ fonction de gestion de l'évènement Client = lorsque des caractères sont disponibles

// Doc : This function is called when a server sends a byte to an existing Client object.

void clientEvent(Client someClient) { // ne fonctionne que coté client ?


} // --- fin de fonction de gestion de l'évènement client

//--------------- fonction de gestion de l'évènement déconnexion ----------------
void disconnectEvent(Client someClient) {

   println("Serveur : Un client s'est déconnecté depuis l'adresse : " + someClient.ip());

  if (match(someClient.ip(),ipClient)!=null)  { // si l'adresse ip du client est celle attendue
    println("Serveur : Le client déconnecté est le client attendu (ip= " + someClient.ip()+") !");
    clientConnected=false; // mémorise connexion inactive
  }


} // ------------- fin fonction de gestion de l'évènement  déconnexion

//------------- Fonction de gestion des évènements série ----
  void serialEvent (Serial serialServerBoard) { // fonction appelée lors de la survenue d'un évènement série


        // ******** Gestion de la valeur reçue sur le port série : **********

        String inStringFromServerBoard = serialServerBoard.readStringUntil('\n'); // chaine stockant la chaîne reçue sur le port Série
        // saut de ligne en marque de fin

        if (inStringFromServerBoard != null) { // si la chaine recue n'est pas vide

                inStringFromServerBoard = trim(inStringFromServerBoard); // enlève espace blancs de la chaine recue

                //--- si on a une réponse c'est que le serveur Arduino a bien reçu puis émis la chaine
                println("6. Réception serveur Arduino <== Serveur Processing : "+ inStringFromServerBoard); // affiche la chaine dans la console
                println("7. Envoi serveur Arduino ==> Serveur Processing : "+ inStringFromServerBoard); // affiche la chaine dans la console

                // --- réception réelle ---
                println("8. Réception serveur Processing <== serveur Arduino : "+ inStringFromServerBoard); // affiche la chaine dans la console

                 //------------ renvoi de la chaine vers Client réseau Processing seulement si le client existe ! ----

                if (clientConnected==true) { // si le client voulu est connecté
                       serverNetwork.write(inStringFromServerBoard); // envoi la chaine au client processing
                       println("9. Envoi serveur Processing ==> client Processing : "+ inStringFromServerBoard); // affiche la chaine dans la console

                } // fin si client connecté
                else {

                  println("9. Le client n'est pas connecté !"); // message dans la console

                }
        } // fin condition chaine recue pas vide



} // fin de la fonction de gestion des évènements Série

// Gestion des évènements des objets GUI controlP5 ----

//------ fonction gestion globale des évènements GUI controlP5
public void controlEvent(ControlEvent theEvent) {
        //println(theEvent.controller().name());// affiche le nom de l'évènement
}

//---- evenement bouton envoi chaine serie

void serialButton(int theValue) { // fonction évènement Button de meme nom - reçoit la valeur

        println("Serveur : Evènement serialButton");

        serialServerBoard.write(serialText.getText()+"\n"); // envoie la chaine suivi saut ligne sur le port Série
        print("5. Envoi Serveur Processing ==> serveur Arduino : ");
        print(serialText.getText()+"\n");
        serialText.setValue(""); // vide le champ texte


} // fin evènement bouton envoi

//---- evenement bouton envoi chaine reseau


void networkButton(int theValue) { // fonction évènement Button de meme nom - reçoit la valeur

        println("Serveur : Evènement networkButton");


        if (clientConnected==true) { // si le client voulu est connecté
             serverNetwork.write(networkText.getText()+"\n"); // envoi la chaine au client processing
             println("9. Envoi serveur Processing ==> client Processing : "+ networkText.getText()); // affiche la chaine dans la console

         } // fin si client connecté
         else {

             println("9. Le client n'est pas connecté !"); // message dans la console

         }

        networkText.setValue(""); // vide le champ texte


} // fin evènement bouton envoi

// ------ gestion évènement Textfield ------

//---- evenement champ texte serie

public void serialText(String theText) { // fonction évènement Textfield de meme nom - déclenché par return - reçoit la chaine

        //println("Evènement CheminText avec valeur = "+theText);

        chaineEnvoiSerie=theText; // mémorise le contenu du champ

        //println("Le chemin est :"+chaineEnvoi);

} // fin evènement champ texte chemin fichier

//---- evenement champ texte serie

public void networkText(String theText) { // fonction évènement Textfield de meme nom - déclenché par return - reçoit la chaine

        //println("Evènement CheminText avec valeur = "+theText);

        chaineEnvoiNetwork=theText; // mémorise le contenu du champ

        //println("Le chemin est :"+chaineEnvoi);

} // fin evènement champ texte chemin fichier

//XXXXXXXXXXXXXXXXXX Fin du programme XXXXXXXXXXXXXXXXX
 

Test du programme

  • Lancer ce programme Processing dans l'interface Processing côté serveur. On obtient la fenêtre suivante et le message dans la console sur le PC "serveur" :
  • On peut tester "l'injection" d'une chaine vers le client Processing : comme celui-ci n'est pas encore connecté à ce stade, on a un message nous indiquant que l'étape 9 n'est pas possible :
  • Si on teste "l'injection" d'une chaine vers le serveur Arduino, on obtient la liste des étapes réalisées :
  • On a donc une communication série opérationnelle entre le serveur Processing et le serveur Arduino, et la preuve que le serveur Arduino renvoie bien la chaine reçue. Jusque-là, rien de bien sorcier... Maintenant, l'étape de vérité : la communication entre le serveur Processing et le client Processing par le réseau wifi !

Etape 3 : le programme Arduino "client" (sur la carte Arduino locale)

Ce que fait ce programme

  • A noter que l'on peut très bien laisser la carte Arduino "cliente" muette en la programmant simplement avec le programme d'exemple "blink" qui fait clignoter la LED de la broche 13 et c'est tout. La carte sera ainsi juste présente sur le "réseau" mais sans action particulière. Dans une première approche, c'est ce qu'on peut faire.
  • Sinon, on pourra utiliser le programme suivant qui assure l'envoi d'une chaine de caractères à intervalles régulier. A noter que ce programme ne gère pas la réception d'une chaine en provenance du port série, car ceci n'a pas grand intérêt la plupart du temps. Au besoin, on peut toujours l'ajouter.

Principe du code

Exemple de code

  • Ce programme est à programmer dans la carte Arduino "client" :

// --- Programme Arduino ---
// Trame de code générée par le générateur de code Arduino
// du site www.mon-club-elec.fr

// Auteur du Programme : X. HINAULT - Tous droits réservés
// Programme écrit le : 8/4/2011.

// ------- Licence du code de ce programme -----
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License,
//  or any later version.
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

// ////////////////////  PRESENTATION DU PROGRAMME ////////////////////

// -------- Que fait ce programme ? ---------
 /* Ce programme émet une chaine de caractères sur le port série à intervalles régulier.  */

// --- Fonctionnalités utilisées ---

// Utilise la connexion série matérielle vers le PC

// -------- Circuit à réaliser ---------

// La connexion série matérielle vers le PC utilise les broches 0 et 1 (via le câble USB)


// /////////////////////////////// 1. Entête déclarative ///////////////////////
// A ce niveau sont déclarées les librairies incluses, les constantes, les variables, les objets utiles...

// --- Déclaration des constantes ---

// --- Inclusion des librairies ---

// --- Déclaration des constantes utiles ---

// --- Déclaration des constantes des broches E/S numériques ---


// --- Déclaration des constantes des broches analogiques ---


// --- Déclaration des variables globales ---




// --- Déclaration des objets utiles pour les fonctionnalités utilisées ---


// ////////////////////////// 2. FONCTION SETUP = Code d'initialisation //////////////////////////
// La fonction setup() est exécutée en premier et 1 seule fois, au démarrage du programme

void setup()   { // debut de la fonction setup()

// --- ici instructions à exécuter 1 seule fois au démarrage du programme ---

// ------- Initialisation fonctionnalités utilisées -------  

Serial.begin(115200); // initialise connexion série matérielle à 115200 bauds
// IMPORTANT : régler le terminal côté PC avec la même valeur de transmission


// ------- Broches en sorties numériques -------  

// ------- Broches en entrées numériques -------  

// ------- Activation si besoin du rappel au + (pullup) des broches en entrées numériques -------  

// ------- Initialisation des variables utilisées -------  

// ------- Codes d'initialisation utile -------  

} // fin de la fonction setup()
// ********************************************************************************

////////////////////////////////// 3. FONCTION LOOP = Boucle sans fin = coeur du programme //////////////////
// la fonction loop() s'exécute sans fin en boucle aussi longtemps que l'Arduino est sous tension

void loop(){ // debut de la fonction loop()


// --- ici instructions à exécuter par le programme principal ---

Serial.println("EnvoiParClientArduino"); // envoi chaine sur port série
delay(5000); // 5 secondes entre chaque envoi

} // fin de la fonction loop() - le programme recommence au début de la fonction loop sans fin
// ********************************************************************************


// ////////////////////////// FONCTIONS DE GESTION DES INTERRUPTIONS ////////////////////


// ////////////////////////// AUTRES FONCTIONS DU PROGRAMME ////////////////////


// ////////////////////////// Fin du programme ////////////////////
 

Test du programme

  • Ce programme est très facile à tester : il suffit d'ouvrir une fenêtre Terminal Arduino sur le PC client et on doit voir :

Etape 4 : le programme Processing "client" (sur le PC local)

  • Cette étape est "l'étape de vérité" qui va permettre de vérifier que la communication wifi fonctionne bien entre l'interface Processing serveur et l'interface Processing client.

Ce que fait ce programme

  • Ce programme Processing fournit la communication entre le réseau wifi et la carte Arduino Client.
  • Deux champs texte permettent d'envoyer une chaine de caractère de test vers le client Arduino via le port série ou vers le serveur Processing via le réseau.

Principe du code

Exemple de code

  • Ce code est à copier/coller dans une interface Processing sur le PC client. Il ne reste plus alors qu'à lancer le programme.

// Programme processing
// généré avec le générateur de code Processing
// www.mon-club-elec.fr
// par X. HINAULT - Avril 2011 - tous droits réservés

/////////////// Description du programme ////////////
// Utilise un/des objets String (chaîne de caractère)
// Utilise le port Serie
// Utilise un Client réseau : ce programme nécessite un serveur réseau accessible

// Utilise la librairie GUI controlP5
// Utilise un/des bouton(s) simple(s) (Button)
// Utilise un/des champ(s) texte (Textfield)
// Ajoute un bouton et un champ pour chemin fichier

/*
Envoie vers Arduino une chaîne saisie dans un champ texte.
Reçoit la chaine renvoyée par Arduino et l'affiche dans la console.
*/


// XXXXXXXXXXXXXXXXXXXXXX ENTETE DECLARATIVE XXXXXXXXXXXXXXXXXXXXXX

// inclusion des librairies utilisées

import processing.serial.*; // importe la librairie série processing

import processing.net.*; // importe la librairie pour connexion réseau Client/Serveur

import controlP5.*; // importe la librairie GUI controlP5
// cette librairie doit être présente dans le répertoire /libraries du répertoire Processing
// voir ici : http://www.sojamo.de/libraries/controlP5/

// déclaration objets

String str1 = "machaine"; // déclare un objet String (chaine de caractère)
String chaineEnvoiSerie = ""; // déclare un objet String (chaine de caractère)
String chaineEnvoiNetwork = ""; // déclare un objet String (chaine de caractère)

// --- port Série ---
Serial  serialClientBoard; // Création objet désignant le port série de la carte Arduino Client

// --- objet Client Réseau ---
Client clientNetwork; // déclaration d'un objet client réseau
String inStringFromServerNetwork; // pour réception chaine en provenance Serveur Réseau
String inStringFromClientBoard; // pour réception chaine en provenance carte Arduino Client

// --- police texte ---
//PFont fontA; // crée un objet de police texte

//---- librairie GUI controlP5 ----
ControlP5 controlP5; // déclare un objet principal de la librairie GUI controlP5

Button serialButton; // déclare objet Button  
Button networkButton; // déclare objet Button  

Textfield serialText; // déclare des objets Textfield
Textfield networkText; // déclare des objets Textfield

// déclaration variables globales

//------ déclaration des variables de couleur utiles ----
int jaune=color(255,255,0);
int vert=color(0,255,0);
int rouge=color(255,0,0);
int bleu=color(0,0,255);
int noir=color(0,0,0);
int blanc=color(255,255,255);
int bleuclair=color(0,255,255);
int violet=color(255,0,255);

String ipServeur="192.168.2.5"; // ip du serveur sur réseau wifi local
//String ipServeur="192.168.0.3"; // ip du serveur sur réseau wifi local
//String ipServeur="127.0.0.1"; // ip du serveur sur boucle locale

//int portNetwork=12345; // port pour boucle locale
int portNetwork=5905; // port pour réseau wifi

// XXXXXXXXXXXXXXXXXXXXXX  Fonction SETUP XXXXXXXXXXXXXXXXXXXXXX

void setup(){ // fonction d'initialisation exécutée 1 fois au démarrage

        // ---- initialisation paramètres graphiques utilisés
        colorMode(RGB, 255,255,255); // fixe format couleur R G B pour fill, stroke, etc...
        fill(0,0,255); // couleur remplissage RGB
        stroke (0,0,0); // couleur pourtour RGB
        rectMode(CORNER); // origine rectangle : CORNER = coin sup gauche | CENTER : centre
        imageMode(CORNER); // origine image : CORNER = coin sup gauche | CENTER : centre
        //strokeWeight(0); // largeur pourtour
        frameRate(30);// Images par seconde

        // --- initialisation fenêtre de base ---
        size(400, 130); // ouvre une fenêtre xpixels  x ypixels
        background(vert); // couleur fond fenetre

// --- initialisation des objets et fonctionnalités utilisées ---

        //------------- initialisation de la police texte - à mettre avant série ----
        //fontA = loadFont("Arial-Black-14.vlw"); // charge le fichier police dans l'objet police texte
        // ce fichier doit être présent dans un rép <data> dans le répertoire du programme
        // pour générer un fichier de police à partir des polices système aller dans Tools > create Fonts
        // voir également http://processing.org/learning/text/

        //textFont(fontA, 14); // Initialise la police et sa taille (en pixels)

        //text("Client Processing actif !", 10, 60);

        //------------- initialisation port série ----
        println(Serial.list()); // affiche dans la console la liste des ports séries
        // Vérifier que le numéro du port série utilisé est le meme que celui utilisé avec  Serial.list()[index]
        serialClientBoard = new Serial(this, Serial.list()[0], 115200); // Initialise une nouvelle instance du port Série carte Arduino Client
        //serialClientBoard = new Serial(this, "/dev/ttyUSB1", 115200); // Initialise une nouvelle instance du port Série carte Arduino Client
        serialClientBoard.bufferUntil('\n'); // attendre arrivée d'un saut de ligne pour générer évènement série

        //======== Initialisation Objets GUI ControlP5 =========

        controlP5 = new ControlP5(this); // initialise l'objet principal de la librairie GUI controlP5

        // typeObjet nomObjet=controlP5.addObjet(paramètres); // pour info : déclaration / initialisation possible en 1 ligne
        // Textfield field = controlP5.addTextfield("myWindowTextfield",70,130,100,20); // exemple

        //======== Initialisation Objets Button =========

        //---- le bouton envoi chaine vers serveur Arduino port série
        serialButton=controlP5.addButton("serialButton",0,110,35+60,200,24); // initialise et ajoute un Button au ControlP5
        serialButton.setLabelVisible(true); // affichage des labels
        serialButton.setLabel("==> ENVOI serie vers client Arduino"); // fixe label du bouton
        serialButton.setColorActive(color(255,0,0)); // fixe la couleur active
        serialButton.setColorForeground(color(0,255,255)); // fixe couleur avant

        //---- le bouton envoi chaine vers client réseau Processing
        networkButton=controlP5.addButton("networkButton",0,110,35,200,24); // initialise et ajoute un Button au ControlP5
        networkButton.setLabelVisible(true); // affichage des labels
        networkButton.setLabel("==> ENVOI reseau vers serveur Processing"); // fixe label du bouton
        networkButton.setColorActive(color(255,0,0)); // fixe la couleur active
        networkButton.setColorForeground(color(0,255,255)); // fixe couleur avant

        //======== Initialisation Objets Textfield =========

        //---- champ texte saisie chaine
        serialText=controlP5.addTextfield("serialText",10,10+60,300,20); // initialise et ajoute un Textfield au ControlP5
        serialText.setAutoClear(false); // autoeffacement après return
        serialText.setValue(chaineEnvoiSerie); // initialise Texte du champ
        serialText.setLabelVisible(true); // affichage des labels
        serialText.setLabel("Saisir chaine"); // fixe label
        serialText.setColorLabel(bleu); // fixe la couleur label
        serialText.setColorActive(color(255,0,0)); // fixe la couleur active
        serialText.setColorForeground(color(0,255,255)); // fixe couleur avant

        //---- champ texte saisie chaine
        networkText=controlP5.addTextfield("networkText",10,10,300,20); // initialise et ajoute un Textfield au ControlP5
        networkText.setAutoClear(false); // autoeffacement après return
        networkText.setValue(chaineEnvoiNetwork); // initialise Texte du champ
        networkText.setLabelVisible(true); // affichage des labels
        networkText.setLabel("Saisir chaine"); // fixe label
        networkText.setColorLabel(bleu); // fixe la couleur label
        networkText.setColorActive(color(255,0,0)); // fixe la couleur active
        networkText.setColorForeground(color(0,255,255)); // fixe couleur avant


//------------- initialisation objet Client réseau ----
  // Connexion du Client au serveur ayant l'adresse indiquée et sur le port indiqué
  // 127.0.0.1 pour connexion en local sur la machine
  //clientNetwork = new Client(this, ipServeur, portNetwork); // Remplacer avec l'adresse IP du serveur et le numéro de port utilisé
  clientNetwork = new Client(this, ipServeur, portNetwork); // pour réseau local sur port 5905
  // info : le port utilisé doit être ouvert sur le PC client et le PC serveur ainsi que sur le routeur du réseau

  println("Client : Connexion du client Processing.....");

} // fin fonction Setup

// XXXXXXXXXXXXXXXXXXXXXX Fonction Draw XXXXXXXXXXXXXXXXXXXX

void  draw() { // fonction exécutée en boucle

     if (clientNetwork.available() > 0) { // si des caractères sont disponibles en provenance du réseau
        inStringFromServerNetwork= clientNetwork.readString();
        println("10.Réception client Processing <== serveur Processing: " + inStringFromServerNetwork);
      }

} // fin de la fonction draw()

// XXXXXXXXXXXXXXXXXXXXXX Autres Fonctions XXXXXXXXXXXXXXXXXXXXXX

        //------------- Fonction de gestion des évènements série ----
         void serialEvent (Serial serialClientBoard) { // fonction appelée lors de la survenue d'un évènement série

        // ******** Gestion de la valeur reçue sur le port série depuis la carte Arduino Client **********

        String inStringFromClientBoard = serialClientBoard.readStringUntil('\n'); // chaine stockant la chaîne reçue sur le port Série depuis la carte Arduino Client
        // saut de ligne en marque de fin

        if (inStringFromClientBoard != null) { // si la chaine recue n'est pas vide

                // print (inString); // affichage brut de la chaine recue
                inStringFromClientBoard = trim(inStringFromClientBoard); // enlève espace blancs de la chaine recue
                //int inByte_brut=int(inStringClientBoard); // conversion valeur reçue en valeur numérique entiere
                //float inByte = float(inStringClientBoard); // conversion valeur reçue en valeur numérique décimale

                //--- si une chaine est reçue, alors l'étape 1 a obligatoirement eu lieu...
                println("1. Envoi Client Arduino ==> client Processing : "+ inStringFromClientBoard); // affiche la chaine dans la console

                // réception effective de la chaine
                println("2. Réception Client Processing <== client Arduino : "+ inStringFromClientBoard); // affiche la chaine dans la console

                //----- renvoie la chaine reçue vers le Serveur Réseau ----
                clientNetwork.write(inStringFromClientBoard+"\n"); //--- envoie une chaine vers le Serveur  suivie d'un saut de ligne
                println("3. Envoi Client Processing ==> Serveur Processing : "+ inStringFromClientBoard); // affiche la chaine dans la console
                delay(1000); // entre deux envois


        } // fin condition chaine recue pas vide


} // fin de la fonction de gestion des évènements Série

// Gestion des évènements des objets GUI controlP5 ----

//------ fonction gestion globale des évènements GUI controlP5
public void controlEvent(ControlEvent theEvent) {
        //println(theEvent.controller().name());// affiche le nom de l'évènement
}

//---- evenement bouton envoi chaine

void networkButton(int theValue) { // fonction évènement Button de meme nom - reçoit la valeur

        println("Client : Evènement envoiButton");

        //----- envoie la chaine vers le Serveur Réseau ----
        clientNetwork.write(networkText.getText()+"\n"); //--- envoie une chaine vers le Serveur  suivie d'un saut de ligne
        print("3. Envoi Client Processing ==> Serveur Processing : ");
        print(networkText.getText()+"\n");
        delay(100); // entre deux envois

       networkText.setValue(""); // vide le champ texte


} // fin evènement bouton envoi

//---- evenement bouton envoi chaine serie

void serialButton(int theValue) { // fonction évènement Button de meme nom - reçoit la valeur

        println("Client : Evènement serialButton");

        serialClientBoard.write(serialText.getText()+"\n"); // envoie la chaine suivi saut ligne sur le port Série
        print("5. Envoi Client Processing ==> client Arduino : ");
        print(serialText.getText()+"\n");
        serialText.setValue(""); // vide le champ texte


} // fin evènement bouton envoi

// ------ gestion évènement Textfield ------

//---- evenement champ texte network

public void networkText(String theText) { // fonction évènement Textfield de meme nom - déclenché par return - reçoit la chaine

        //println("Evènement CheminText avec valeur = "+theText);

        chaineEnvoiNetwork=theText; // mémorise le contenu du champ

        //println("Le chemin est :"+chaineEnvoi);

} // fin evènement champ texte chemin fichier


//---- evenement champ texte serie

public void serialText(String theText) { // fonction évènement Textfield de meme nom - déclenché par return - reçoit la chaine

        //println("Evènement CheminText avec valeur = "+theText);

        chaineEnvoiSerie=theText; // mémorise le contenu du champ

        //println("Le chemin est :"+chaineEnvoi);

} // fin evènement champ texte chemin fichier

//XXXXXXXXXXXXXXXXXX Fin du programme XXXXXXXXXXXXXXXXX
 

Test du programme

  • Une fois que le programme est lancé (sur le poste client), on doit voir :
  • De son côté, le serveur indique qu'il a détecté une connexion d'un client et précise si l'adresse ip du client est la bonne :
  • Si vous obtenez bien ces messages, c'est que votre connexion wifi fonctionne bien entre les 2 PC !! Le simple fait que les 2 interfaces fonctionnent sans message d'erreur au lancement confirme que la connexion wifi est opérationnelle.
  • Si vous avez lancé l'accès au bureau distant du PC serveur sur le PC client, vous devez avoir les 2 fenêtres des interfaces Serveur (jaune) et Client(vert) visibles en même temps sur le PC client :
  • Moi, je ne m'en lasse pas de cet accès distant au bureau du PC serveur depuis le PC client : trop top ! La procédure à suivre est ici : Configurer un accès bureau distant entre 2 PC sous Ubuntu
  • Maintenant, on va pouvoir tester l'envoi d'un chaîne via le réseau wifi : saisir la chaine de votre choix dans le champ d'envoi réseau vers serveur processing dans l'interface client (le champ du haut) et vous devez obtenir le parcours réalisé par la chaine :
  • On obtient logiquement :
    • les messages des étapes 3. et 10. du côté client
    • et les messages des étapes 4., 5., 6., 7., 8., 9. du côté serveur.
  • La chaîne a donc fait le "tour", partant du client Processing pour revenir au client Processing !
  • Si votre carte Arduino client est programmée et émet une chaine, les étapes 1 à 10 ont lieu :
  • Voilà, votre connexion wifi fonctionne ! A vous de jouer, faire des tests d'envoi de chaine de différents endroit (du serveur, du client, etc...) Enjoy !