SocketAPP WiShield

Salut tout le monde :slight_smile:

Je rencontre des difficultés avec mon WiShield (Copperhead pour être exact) donc je viens faire appel à votre savoir :grin: Je voudrais envoyer une information en WiFi à ma carte Arduino UNO R2 quand j'appui sur une touche de mon clavier. Pour le moment je fais simple, j'ai fais un petit programme en Python qui envoi succesivement les valeurs 1, 2, 3, ..., 6 et un autre programme sur la Arduino qui interprète ces valeurs. La Arduino recoit bien les données puisque dans le "Serial Monitor" je vois les messages mais on dirait qu'elle n'arrive pas à commander les PIN quand le Wishield est branché :astonished:

J'ai beau chercher, je ne comprends pas mon erreur :relaxed:

Voici les codes :

Serveur Python :

#!/usr/bin/python

import socket
import time

HOST = '192.168.0.100'     # The remote host
PORT = 1000               # The same port as used by the server

def sendValue(value):
   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   s.connect((HOST, PORT))
   s.send(str(value) + '\n')
   s.close()

sendValue(1)
time.sleep(1)
sendValue("1")

sendValue(2)
time.sleep(1)
sendValue("2")

sendValue(3)
time.sleep(1)
sendValue("3")

sendValue(4)
time.sleep(1)
sendValue("4")

sendValue(5)
time.sleep(1)
sendValue("5")

sendValue(6)
time.sleep(1)
sendValue("6")

Programme Arduino "Socket.pde":

/*
* Socket App
 *
 * A simple socket application example using the WiShield 1.0
 */

#include <WiShield.h>

//Wireless configuration defines ----------------------------------------
#define WIRELESS_MODE_INFRA   1
#define WIRELESS_MODE_ADHOC   2

//Wireless configuration parameters ----------------------------------------
unsigned char local_ip[]       = {
  192,168,0,100};  // IP address of WiShield
unsigned char gateway_ip[]     = {
  192,168,0,47};     // router or gateway IP address
unsigned char subnet_mask[]    = {
  255,255,255,0}; // subnet mask for the local network
const prog_char ssid[] PROGMEM = {
  "JPPW"};    // max 32 bytes
unsigned char security_type    = 2;               // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2
// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {
  "****************"};   // max 64 characters
// WEP 128-bit keys
prog_uchar wep_keys[] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Key 0
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Key 1
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Key 2
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // Key 3
// setup the wireless mode
// infrastructure - connect to AP
// adhoc - connect to another WiFi device
unsigned char wireless_mode = WIRELESS_MODE_INFRA;
unsigned char ssid_len;
unsigned char security_passphrase_len;
// End of wireless configuration parameters ----------------------------------------

char recvChar;

void setup()
{
  //set up serial communications
  Serial.begin(9600);
  pinMode(4, OUTPUT);

  //set up global recvChar to indicate nothing received
  recvChar = NULL;
  WiFi.init();
}

void loop()
{
  if(NULL != recvChar) {
    Serial.print("Received: ");
    Serial.print(recvChar);
    Serial.print(" [");

    switch(recvChar) {
    case '1':
      Serial.println("forward]");
      //your control code goes here...
      digitalWrite(4, HIGH);
      Serial.println("Commande envoyée");
      delay(300);
      break;
    case '2':
      Serial.println("backward]");
      //your control code goes here...
      break;
    case '3':
      Serial.println("turn right]");
      //your control code goes here...
      break;
    case '4':
      Serial.println("turn left]");
      //your control code goes here...
      break;
    case '5':
      Serial.println("stop]");
      //your control code goes here...
      break;
    default:
      Serial.println("unexpected value received]");
      //your control code goes here...
      break;
    }

    //we have handled the last data receive so clear recvChar so that we don't handle the same data again.
    recvChar = NULL;
  }

  WiFi.run();
}

Programme Arduino "Socket.c"

/******************************************************************************

  Filename:      socketapp.c
  Description:   Simple socket programming example for the WiShield 1.0

******************************************************************************

  TCP/IP stack and driver for the WiShield 1.0 wireless devices

  Copyright(c) 2009 Async Labs Inc. All rights reserved.

  This program is free software; you can redistribute it and/or modify it
  under the terms of version 2 of the GNU General Public License as
  published by the Free Software Foundation.

  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, write to the Free Software Foundation, Inc., 59
  Temple Place - Suite 330, Boston, MA  02111-1307, USA.

  Contact Information:
  <asynclabs@asynclabs.com>

   Author               Date        Comment
  ---------------------------------------------------------------
   AsyncLabs         06/06/2009   Initial version

*****************************************************************************/

/*
* This is a short example of how to write uIP applications using
* protosockets.
*/

/*
* We define the application state (struct socket_app_state) in the
* socketapp.h file, so we need to include it here. We also include
* uip.h (since this cannot be included in socketapp.h) and
* <string.h>, since we use the memcpy() function in the code.
*/
#include "socketapp.h"
#include "uip.h"
#include <string.h>

extern char recvChar;

/*
* Declaration of the protosocket function that handles the connection
* (defined at the end of the code).
*/
static int handle_connection(struct socket_app_state *s);
/*---------------------------------------------------------------------------*/
/*
* The initialization function. We must explicitly call this function
* from the system initialization code, some time after uip_init() is
* called.
*/
void socket_app_init(void)
{
   /* We start to listen for connections on TCP port 1000. */
   uip_listen(HTONS(1000));
}
/*---------------------------------------------------------------------------*/
/*
* In socketapp.h we have defined the UIP_APPCALL macro to
* socket_app_appcall so that this function is uIP's application
* function. This function is called whenever an uIP event occurs
* (e.g. when a new connection is established, new data arrives, sent
* data is acknowledged, data needs to be retransmitted, etc.).
*/
void socket_app_appcall(void)
{
   /*
    * The uip_conn structure has a field called "appstate" that holds
    * the application state of the connection. We make a pointer to
    * this to access it easier.
    */
   struct socket_app_state *s = &(uip_conn->appstate);

   /*
    * If a new connection was just established, we should initialize
    * the protosocket in our applications' state structure.
    */
   if(uip_connected()) {
      PSOCK_INIT(&s->p, s->inputbuffer, sizeof(s->inputbuffer));
   }

   /*
    * Finally, we run the protosocket function that actually handles
   * the communication. We pass it a pointer to the application state
   * of the current connection.
   */
   handle_connection(s);
}
/*---------------------------------------------------------------------------*/
/*
* This is the protosocket function that handles the communication. A
* protosocket function must always return an int, but must never
* explicitly return - all return statements are hidden in the PSOCK
* macros.
*/
static int handle_connection(struct socket_app_state *s)
{
   if(uip_newdata()) {
      PSOCK_BEGIN(&s->p);
      PSOCK_READTO(&s->p, '\n');
      recvChar = s->inputbuffer[0];
      PSOCK_CLOSE(&s->p);
      PSOCK_END(&s->p);
   }
   else {
      //if no new data is received set our global into to 0 to indicate no new data
      recvChar = NULL;
   }
}
/*---------------------------------------------------------------------------*/

Merci d'avance :slight_smile:

bonjour, je n'ai pas compris ton erreur.. tu reçois bien tes valeurs mais.. la je bloque .. " mais on dirait qu'elle n'arrive pas à commander les PIN quand le Wishield est branché "..? sa doit réagir et ça marche pas c'est ça??

Skizo !

ClarKenT:
Salut tout le monde :slight_smile:

Je rencontre des difficultés avec mon WiShield (Copperhead pour être exact) donc je viens faire appel à votre savoir :grin: Je voudrais envoyer une information en WiFi à ma carte Arduino UNO R2 quand j'appui sur une touche de mon clavier. Pour le moment je fais simple, j'ai fais un petit programme en Python qui envoi succesivement les valeurs 1, 2, 3, ..., 6 et un autre programme sur la Arduino qui interprète ces valeurs. La Arduino recoit bien les données puisque dans le "Serial Monitor" je vois les messages mais on dirait qu'elle n'arrive pas à commander les PIN quand le Wishield est branché :astonished:

J'ai beau chercher, je ne comprends pas mon erreur :relaxed:

Surement le probleme connu (mais tout le monde c'est fait avoir aun moins au debut )
de l'edition de apps-conf.h

essaie de replacer cette section en decommentant seulement le APP_SOCKAPP
comme dessous

// ----------------------------------------------------------------------------
// -- Begin uIP/WiShield stack configuration settings

//
// Application type defines; uncomment to enable APP_TYPES
//   APP_UDPAPP is used for UDP only apps as well as DNS and DHCP apps; if your app will use
//   DNS and/or DHCP then your APP_TYPE (e.g. APP_WISERVER) AND APP_UDPAPP must be defined 
//   (uncommented). Currently only APP_UDPAPP may be defined at the same time as any other APP_TYPE
//
//#define APP_WEBSERVER
//#define APP_WEBCLIENT
#define APP_SOCKAPP
//#define APP_UDPAPP
//define APP_WISERVER

@Artouste Je m'étais deja fais avoir par le app-conf mais non pas cette fois :stuck_out_tongue: Je suis bien en SocketAPP.
@Skizo En fait,dans le Serial Monitor les messages "Received : 1 [Forward]", ... s'affichent donc je reçois bien les infos. Mon problème, c'est que je ne peux pas commander les PIN. Par exemple, j'avais voulu mettre digitalWrite(13, HIGH) (la LED sur la Arduino) quand je recevais la valeur 1 mais impossible de l'allumer :expressionless:

Une idée ? :~

J'ai trouvé :grin: Tout ça était lié à un problème d'alim, pas assez de puissance pour faire le test. Par contre, j'ai un gros doute ... Sachant que je possède un WiShield (Copperhead) et une carte de puissance (DFRobot) comment je peux savoir quel PIN sont encore inutilisés ? Il m'en faudrait 6 de libres :cold_sweat:

Pour le WiShield, tout est sur le Wiki : http://asynclabs.com/wiki/index.php?title=WiShield_2.0

Pour ta carte DFrobot, tu devrais aussi trouvé l'info sur le site http://www.dfrobot.com/. Quelle carte ?

C'est la DFROBOT L298P 2A et aussi est-ce que si je n'utilise pas tous les PIN pour un module ils seront considérés comme libres ? Par exemple, je sais que la carte de puissance utilise les PIN 6 et 7 pour commander le moteur 2 sauf que je n'ai qu'1 seul moteur donc est-ce que je pourrais utiliser ces PIN pour autre chose ? :relaxed:

y'a le schéma sur le site, alors RTFS :wink:

Et sur le lien "manuel" tu as un wiki aussi avec une section "pin Allocation"

Merci pour les liens :slight_smile: Mais par exemple, j'ai vu que la carte de puissance utilise les PIN 6 et 7 pour commander le moteur 2 sauf que je n'ai qu'1 seul moteur donc est-ce que je pourrais utiliser ces PIN pour autre chose ? :relaxed:

De toute façon, on peut très bien utiliser les 6 sorties analogiques (A0, A2, ..., A5) comme des sorties digitales ? :smiley:

ClarKenT:
j'ai vu que la carte de puissance utilise les PIN 6 et 7 pour commander le moteur 2 sauf que je n'ai qu'1 seul moteur donc est-ce que je pourrais utiliser ces PIN pour autre chose ? :relaxed:

Oui, il ne faut pas mettre de cavalier alors pour les broches DIRB et PWMB (voir schéma).

De toute façon, on peut très bien utiliser les 6 sorties analogiques (A0, A2, ..., A5) comme des sorties digitales ?

Of course

Ok merci ! :grin: Juste une dernière petite précision, est-ce que c'est possible de moduler le signal analogique pour envoyer du 1V par exemple ? Je m'explique, j'ai un Pont en H et je dois envoyer des signals de commandes aux transistors mais si ce signal est trop fort, je sature alors les transistors et je court-circuit tout le pont :roll_eyes: En voici le schéma :

Désolé si tu as lu la première version de ma réponse. J'ai mélangé 2 topics :wink:

Tout d'abord correction sur ma réponse précédante :

De toute façon, on peut très bien utiliser les 6 sorties analogiques (A0, A2, ..., A5) comme des sorties digitales ?

Tu veux sans doute parler des ENTREES ANALOGIQUES ?
Oui, on peut les utiliser en entrées ou sorties numériques.

Il n'y a pas de sortie analogique sur l'Arduino.

Sinon, si tu compte attaquer ton pont en H directement par les sorties de l'Arduino : pas bon.
On n'attaque pas la base d'un transistor en direct par un signal numérique : tu ne vas réussir qu'à cramer ton chip ATmega.

Rappel 1: Un transistor est piloté en courant. Le courant de pilotage qui rentre dans la base (soit Ib) commande le courant de sortie qui traverse le transistor du collecteur à l'emetteur (soit Ic) suivant la formule : Ic = Hfe.Ib ou Hfe est le gain du transistor (noté aussi souvent avec le symbole grec beta).
Au de la d'un certain courant, le transistor ne fonctionne plus en linéaire mais en saturé. C'est ce mode ci qu'on utilise pour piloter de la puissance.
Donc il faut que tu fournisse à ton transistor un courant de base de quelques milliampères.

Rappel 2 : un transistor NPN peut de manière simpliste être vu comme 2 diodes : (C)----|<|----(B)---|>|----(E)
Donc quand tu polarise ton transistor il apparait que la liaison B-E est similaire à une diode passante.
la tension BE est donc de l'ordre de celle qu'on trouve sur une diode (forward voltage) soit environ 0,7V.
D'où on déduit la valeur de la résistance que tu doit mettre entre la sortie de l'Arduino et la base de ton transistor :
R = (VCC - 0,7) / Ib
Avec Ib de l'ordre de 5 à 10 mA soit environ 470ohms à 1kohms.

Pour un PNP c'est la même chose dans l'autre sens (E)----|>|----(B)----|<|----(C)
Et on arrive au même résultat sauf que Ib est négatif dans ce cas puisque le courant sort de la base au lieu d'y entrer.

J'espère que ta charge (moteur ?) ne consomme vraiment pas trop parce que 2N2222 et 2N2907, pour moi c'est plutôt des transistors petits signaux/faibles puissance même si la datasheet dit 800mA, la puissance max totale dissipée c'est 500mW donc sous 5V çà limite à 100mA.
Si c'est pour un moteur, du plus costaud genre TIP120 (et le TIP125 pour le PNP) me semble plus appropriés.

Sinon, un circuit intégré comme le TB6612 ou le L298 sont très pratique à utiliser pour ce genre d'application. Ils intègrent les diodes de roue-libre aussi.
Pas besoin non plus de résistances.

Ou alors une combinaison ULN2803A (darlington NPN) et UDN2981A (darlington PNP) qui fournissent 8 darlingtons par boitier DIP18.

Ok ! Merci beaucoup pour ton aide :grin:

Par contre, tu m'inquiete un peu par rapport aux transistors que j'ai choisi :~

En fait, la charge n'est pas un moteur mais un electro-aimant (voir image ci-dessous, au bout à droite de la voiture). Je dois lui envoyer soit 8-9V pour braquer les roues soit à droite soit à gauche, tout dépend de la position du + et du -. C'est pour ça que j'ai le pont en H, pour inverser le sens du courant. Ensuite, ce n'est pas du 0V que je lui envoie mais du 3-4V pour braquer les roues au milieu. Tu pense que les transistors ne sont pas assez costauds pour faire cela ? La seule chose qui m’inquiète c'est le pic d'intensité qu'il risque d'y avoir lors de l'inversion du sens du courant. La bobine risque bien de créer un pic d'intensité non ? Et ça risque de griller les transistors mais j'ai quand même mis 2 diodes en parallèles à chaque transistor pour éviter tout "retour" dans le circuit :wink:

Sinon, pour le courant de base, j'avais déjà mis entre la Arduino et les transistors une résistance de 120 Ohms mais à priori, d'après tes calculs, ce n'est pas assez élevée :frowning:

Sympa la buggy
Tu fera un film après ?

Je dois lui envoyer soit 8-9V pour braquer les roues soit à droite soit à gauche, tout dépend de la position du + et du -. C'est pour ça que j'ai le pont en H, pour inverser le sens du courant. Ensuite, ce n'est pas du 0V que je lui envoie mais du 3-4V pour braquer les roues au milieu.

Un truc que je ne suis pas sur de comprendre : pourquoi parles tu de 8-9V puis de 3-4V ?
Le pont en H est normalement utilisé en saturé/bloqué donc il n'y a que 4 positions :

  • a fond dans un sens : (+)---[LOAD]---(-)
  • a fond dans l'autre sens : (-)---[LOAD]---(+)
  • roue libre --[LOAD]-- (les broches en l'air, dans le cas d'un moteur il tourne sans frein)
  • frein c--[LOAD]--c (les 2 broches en court-circuit, dans le cas d'un moteur çà le freine)

Dans ton cas, seules les 3 premières positions ont un intérrêt.
Donc il faut que les roues reviennent au milieu toutes seuls. Ressort de rappel ?

N'oublie pas aussi que tu vas perdre 2 x Vce-sat dans l'affaire. D'après les datasheets

  • 2N2222 à Ic=150mA (Ib=15mA) : Vcesat = 0,6V à 1,2V
  • 2N2907 à Ic=150mA (Ib=15mA) : Vcesat = 0,4V
    Donc au total tu vas perdre entre 1V et 1,8V sur le pont.
    D'ailleurs, la datasheet conseille un courant plus important que ce que je proposait (15mA) donc plutot une résistance de 270ohms.
    120ohms çà fait trop peu. N'oublie pas que la broche de l'ATmega ne donne pas plus que 20mA et ca la met plutot à genoux.

Pour ce qui est de la puissance des transistors, je ne sais pas combien consomme ton électro-aimant.
Essaye de déterminer le courant qu'il a besoin.
Et regarde les datasheet des transistors.
les paramètres importants sont :

  • Vceo : tension maximale qu'il peut accepter en bloqué entre collecteur et émetteur (non passant, donc la tension d'alimentation de ton pont)
  • Vcesat : tension entre collecteur et émetteur quand le transistor est saturé (passant). La datasheet indique généralement le courant de base nécessaire en fonction de ton courant Ic
  • Icmax : courant maxi dans le collecteur
  • Puissance maximale dissipée

Donc par exemple avec un 2N2222 alimenté en 9V, avec 800mW maxi de puissance dissipée, il ne faut pas dépasser 88mA.

Mais sincèrement a moins que tu préfère bricoler un truc à partir de transistors que tu as sous la main, je te conseille de regarder le L298 ou le TB6612.
D'un point de vue efficacité et encombrement c'est bien plus simple que de se taper le pont en H en discret à la main.
J'utilise le TB6612 breakout de Sparkfun. C'est tout petit et ca passe sans encombre jusqu'à 1A. Juste besoin de 2 ou 3 broches de l'Arduino pour commander une charge inductive.
Le TB6612 est basé sur une techno MOS-FET alors que le L298 est basé sur du transistor bipolaire. Le TB6612 est donc plus "moderne" et dissipe moins que le L198 pour la même utilisation.

Wow ! :astonished:

J'avais jamais réalisé mais tu es entrain de me dire qu'il suffit que je branche mon electro-aimant sur ma carte de puissance(DFROBOT L298P) et HOP le tour est joué !? :open_mouth: Je le branche sur les PIN du Moteur 2 et il me suffit d'envoyer tout le voltage dans un sens et dans l'autre pour tourner et d'en envoyer juste assez pour remettre les roues droite ! XD

Si c'est ça, tu es un génie ! Et moi un idiot ! :grin:

PS : Si j'arrive à le faire fonctionner, je vous ferai une vidéo :wink:

Ben oui, un L298 c'est un pont en H. C'est ce que je te dis depuis quelques messages....

Merci pour tout ! :wink: Je vais tenter ta solution alors :stuck_out_tongue:

C'est bon tout fonctionne ! :grin: J'ai juste un petit bug de temps en temps sur mon Serveur. Je pense qu'il est très mal optimisé et en plus, je voudrais mettre une tempo pour éviter de surcharger la Arduino d'information.

Voici le code en Python :

#!/usr/bin/python
# -*- coding: cp1252 -*-

import socket
import time
import pythoncom, pyHook

HOST = '192.168.0.100'     # IP du WiShield
PORT = 1000                # Port du serveur ET du WiShield utilisé
delay = 1                 # Délai d'attente pour la Arduino
key = ""

print("Mise en place des définitions ...")

def sendValue(value):
   print("En attente de création du socket ...")
   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   print("Socket créé avec succés")
   print("En attente de connexion ...")
   s.connect((HOST, PORT))
   print("Serveur connecté au WiShield [" + str(HOST) + "] et écoute le port : " + str(PORT))
   s.send(value + '\n')
   s.close()

print("sendValue : OK")

def OnKeyboardEvent(event):
   key = event.GetKey()
   print("En attente d'envoi du message ...") 
   sendValue(key)
   print("Message envoyé : " + key + " !")

print("OnKeyboardEvent : OK")

def key() :
   # create a hook manager
   hm = pyHook.HookManager()
   # watch for all keyboard events
   hm.KeyDown = OnKeyboardEvent
   # set the hook
   hm.HookKeyboard()
   # wait forever
   pythoncom.PumpMessages()

print("key : OK")

while 1:
   print("Mise en route de l'essai ...")
   print("Saisie des touches opérationnel !")
   key()

Vous en pensez quoi ? :relaxed:

PS : Je contrôle bien le tout (Electro-aimant + moteur) avec le L298 ! :wink:

ClarKenT:
Voici le code en Python :

Là je passe la main. C'est du charabia pour moi....