IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VB.NET Discussion :

Problème réception Port Série Arduino


Sujet :

VB.NET

  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2016
    Messages : 9
    Points : 2
    Points
    2
    Par défaut Problème réception Port Série Arduino
    Salut tout le monde,

    Je développe un actuellement un projet mélangeant un Arduino Zero et une application en VB .net.
    L'Arduino doit envoyer par USB un peu prés 8000 bytes par secondes par paquet de 6 bytes. (6 bytes, delay de 500µs, 6 bytes, delay de 500 µs, etc..).

    Le problème, c'est que j'ai des octets qui sautent de temps de en temps...

    Voici ma fonction Arduino, j'utilise oui le port série, pas de soucis la dessus, il travaille bien en 115200 8N1. :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SerialUSB.write(Buffer_Gypro, 6);
    Et ma fonction de reception VB.net, c'est ici que j'observe un décalage au bout de 200 lectures à peu près: IncomingBytes(4) contient la valeur de IncomingBytes(5)..:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    SerialPort1.Read(IncomingBytes, 0, 6)
          Byte0 = IncomingBytes(0)
          Byte1 = IncomingBytes(1)
          Byte2 = IncomingBytes(2)
          Byte3 = IncomingBytes(3)
          Byte4 = IncomingBytes(4)
          Byte5 = IncomingBytes(5)
    J'utilise read comme je souhaite travailler en byte et non en chaine de caractères pour optimiser mes traitements de données.

    Je n'ai pas de soucis avec la fonction ReadByte, toutefois celle ci fait ralentir le transfert de données et n'arrive pas à supporter un débit supérieure à 4000 bytes/sec (les octets s'accumulent dans le buffer du port jusqu'à leurs traitements...)

    J'observe également le même problème lorsque j'augmente l'intervalle entre chaque paquet (en changent 500µs a 100ms).
    Le problème vient bien de l'appli, je n'ai aucun soucis de pertes de données avec mes 3 hyperterminal (putty, termite et celui de l'IDE d'Arduino).

    Y-a t'il un moyen pour rendre solide et sans pertes cette communication ?

    Voilà comment est configuré mon port série dans l'appli, je pense pas avoir fait d'erreur ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    With SerialPort1
         .PortName = COM_Port_Detected
         .BaudRate = 115200 
         .Encoding = System.Text.Encoding.Default
         .RtsEnable = True
         .DtrEnable = True
         .Parity = Parity.None
         .StopBits = StopBits.One
         .Open() 
    End With


    Merci pour votre aide,

    Bonne journée

  2. #2
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    ce n'est pas comme ca que s'opère une réception, surtout sur un port sans correction d'erreur

    le principe est de récupérer tout ce que tu peux, et de traiter quand tu as tout ce qu'il te faut (donc pas de readbyte déjà, qui comme tu le dis ralenti sensiblement)
    ensuite il faut pouvoir détecter une erreur de dialogue, le port série est sensible aux interférences, et contrairement au tcp/ip par exemple, les données peuvent être corrompues (manque, ajout ou altération de bits ou d'octets)

    c'est pour ca qu'en général on se créé une norme de dialogue, le plus couramment il y a un caractère de début, un caractère de fin ou une longueur encodée en début de trame, et un checksum permettant de voir s'il y a eut erreur
    la réception d'une trame complète peut se faire en plusieurs fois (le mieux est d'utiliser l'event qui te dis que tu as reçu quelque chose et de lire tout le tampon, concaténé dans un buffer locale en attendant une trame complète)
    si une trame pose problème tu la jette ; tu reposes la question si la trame était une réponse, ou tu attends la prochaine trame si c'est une trame automatique avec une périodicité

    et vu que c'est toi qui code l'arduino, tu peux intégrer ça, et choisir techniquement comment l'appliquer
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  3. #3
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2016
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    Merci de ta réponse Pol,

    Peut être que je me trompe, mais je pense pas pouvoir imposer un caractère de début, ni de fin de ma trame. Les valeurs de mes bytes peuvent prendre n'importe quoi (0 à 255) et donc peut être égales à ces caractères de début ou de fin.
    Je ne peux de plus rater aucune trame, je peux pas me permettre de jeter un paquet de bytes possédant une erreur.
    Je me trompe sûrement, mais je ne vois pas comment utiliser l’événement de réception de données, ma fonction read(buf, offset, count) se trouve à l'intérieur d'un backgroundworker puisque je lis, traite les données et affiche les résultats en temps réels sur un chart.

  4. #4
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    l'event tu peux t'en passer si tu as un thread oui, mais la lecture globale ca serait dommage de s'en passer
    il faut décomposer la lecture et les données = lire 6 octets par 6 octets n'est pas une bonne idée

    après tu dis que tu ne peux pas faire ce que je dis, mais le mieux serait que tu nous dises ce que sont ces 6 octets et à quoi équivaut la trame complète, là je pourrais surement t'expliquer comment gérer ça
    et que tu ne puisses pas ignorer quelque chose va à l'encontre du matériel, le matériel ne peut te garantir que ce que tu envoies sera reçu, et à l'identique ... donc il faut prendre cette contrainte en considération (même si ce n'est pas forcément courant je te l'accorde, enfin plus le débit augmente et plus le cable est long plus ca peut arriver)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  5. #5
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2016
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    D'accord je comprend un peu mieux. Les 6 octets une fois traités (concaténation + bitmask) donnent 3 valeurs d'un accéléromètre 3 axes (accélération X, Y et Z) communiquant avec l'arduino par SPI.
    Je souhaite pouvoir faire 2000 mesures par secondes de ce capteur (qui est son max). J'ai besoin de tout les points de mesure pour pouvoir traiter correctement derrière (filtrage, intégrateur, calibration, etc...)

  6. #6
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    déjà si ton arduino émet en continu, comment être sur qu'au moment où tu le branches ta tombe pile entre 2 envois ? (/ je ne suis pas expert sur le matériel il n'est pas exclu que je dise une connerie quand même)
    parce que si le 1er octet est parti dans le vent, tu auras un décalage à vie dans ta lecture
    donc il faut bien un début
    200k *6o < 115200 bauds, donc tu peux te permettre de rajouter un peu d'octets sans perdre le débit

    genre x fois telle valeur (la moins probable) de suite = caractère de début
    ce caractère de début est à renouveler genre une fois par seconde (à toi de voir, une fois tous les tant de valeur ca permet de simplifier le code .net, une fois tous les tant de temps ca permet de vérifier la vitesse du flux)
    ensuite tu envoies tes 6 octets + 1 octet de checksum
    puis 6 autres octets + 1 chk
    ...
    puis donc de temps en temps une chaine d'octets de synchro

    comme ca peu importe quand tu branches en moins d'une seconde tu es sur te pouvoir te recaller sur le flux

    le chk te permettra de détecter qu'une série de 6 octets est fausse (tu verras donc si ca arrive jamais ou pas)

    115200bauds, si c'est réellement les bits utiles (hors bit de stop ou autre) ca te fait 14,4 ko
    7 octets par truc = 14ko donc il te reste un peu de marge pour mettre le signal de synchro

    après il reste à voir ce qui se passe si tu n'arrives pas à lire assez vite, ou si tu as plus de choses à envoyer que ce que le débit le permet réellement
    ca par contre je vois pas trop comment le détecter, il faudrait déjà voir si c'est l'arduino qui bloque pour buffer plein ou pas
    parce que si tu affiches des infos qui en fait datent, et que la dérive augmente ca n'ira pas


    concernant la lecture côté .net, le but c'est de lire tous les octets que tu peux quand il y en a dans le buffer de réception
    tu les ajoutes à une collection
    parallèlement (ou pas) dans cette collection tu cherches la trame de synchro, si tu la trouves, tu peux alors découper des morceaux de 7 octets s'il y en a plusieurs dans le buffer, vérifier le chk et utiliser ta valeur
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  7. #7
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2016
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    L'Arduino commence à émettre seulement après avoir reçu une commande émise par le PC (dans mon cas il s'agit d'un bouton VB). Il envoie ensuite un paquet de 6 octets, il attend un petit peu pour bien avoir une attente de 1/2000 seconde, il envoie à nouveau 6 octets, attends 0.5ms, 6 octets etc... pendant un nombre de secondes que je définie. Par exemple pour 10 secondes, il me renvoie 10 * 2000 * 6 octets très bien synchronisés sur 10 secondes.

    Effectivement, je peux me permettre d'ajouter des octets qui vérifient que la trame est bien placée (exemple un ".", "CR" et un "LF", ca fait jolie dans une console en plus). Sans ces octets de contrôle, j'arrive à à monter à 3500*6 octets par seconde dans un hyperterminal, ça doit passer sans problème

    Toutefois, une fois une erreur détectée, qu'est ce que je peux faire ?
    Un octet de perdu reste un octet de perdu, non ?

    Merci beaucoup de ton aide; mais peut être que je me suis mal exprimé mais ma question était plutôt comment "solidifier" la communication pour n'avoir aucun octets de perdu même sur très longues durées (de l'ordre de l'heure) plutôt que de savoir comment détecter une erreur et de jeter un paquet de 6 octets et me resynchroniser avec ceux d'après...
    Genre est-ce que je dois utiliser une autre fonction que read(buf, offset, count), mon port série est-il mal configuré, etc..?

  8. #8
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    entre temps j'avais relu le post de départ, et j'avais compris que tu te demandais surtout pourquoi tu avais un problème en vb et pas sur la console
    là je n'ai pas spécialement de réponse, donc j'ai brodé sur le reste ^^

    après si tu veux pas perdre d'infos, il suffit de sécuriser le dialogue
    là aussi dans le domaine il y a des réponses à ça sur bon nombre de protocoles de liaison non fiable, comme les acquittements
    dans le principe, il faudrait que l'arduino envoie 7 octets (chk inclus), le pc vérifie le chk, s'il est bon alors il envoie un ack (= acknowledgment) (octet au choix de ta part)
    s'il n'est pas bon alors il faudrait envoyer un autre octet
    en théorie l'arduino là devrait en cas d'erreur renvoyer la trame précédente
    le problème c'est qu'un ack seul ne sert pas à grand chose, vu qu'on a pas de preuve lui non plus qu'il est arrivé

    récemment en étudiant une doc de dialogue avec une freebox j'avais vu un protocole avec un numéro de trame dedans (ca devait etre le rudp, surcouche sécurisée de l'udp qui par défaut ne garanti ni l'arrivée ni l'ordre des paquets émis)
    ce qui permet de faire un truc du genre l'arduino envoi un numéro puis les 6 octets et le chk
    le pc renvoi le même numéro avec l'acquitement
    en cas d'ack d'erreur l'arduino renvoi la même trame
    en cas d'ack ok RAS
    en cas de non réponse l'arduino renvoi la même trame
    puis l'arduino augmente son numéro de 1
    sur un octet ca doit pouvoir suffire (avec retour à 0)
    l'avantage ici c'est que l'arduino sait de quelle trame on parle

    côté arduino ca va te compliquer le code, car il faudra en plus que tu gardes les infos des trames non encore validée pour pouvoir les renvoyer
    tout en continuant d'acquérir des valeurs à intervalle régulier (et à stocker donc)

    là déjà tu seras sûr d'avoir toutes les infos
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  9. #9
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2016
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    Pas de problèmes
    C'est assez intéressant ce protocole de communication, mais je doute que communiquer dans les 2 sens 2000 fois par seconde soit possible avec un simple Arduino, je dois déjà laisser une tempo de 10 ms entre le moment où je lui envoie la commande d'envoie de données et le moment où je commence à lire ce que je reçois...

  10. #10
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    en informatique plutôt que de rester sur une théorie ou un à priori je pense qu'il faut plutôt tester
    un arduino ca a en général quelques MHz donc je ne vois pas pourquoi ca ne fonctionnerait pas
    l'ack ne serait que 2 octets, à 14,4ko/s 2 octets devraient mettre 0.14s à arriver de l'autre côté
    si tu fais des mesures toutes les demie secondes ca a des chances de passer ^^

    Pour apprendre voir les cours et tutoriels Arduino : https://arduino.developpez.com/cours/
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  11. #11
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2016
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    Le port USB de l'Arduino que j'utilise est un peu spécial (SerialUSB et non Serial pour les connaisseurs), il est configuré en CDC et on ne peut changer ses paramètres à moins de toucher aux librairies internes de l'IDE, sinon je l'aurait mit à 2 megabaud et hop ça aurait été réglé comme sur l'autre port ^^

    Toutefois le problème vient bien de la fonction read(buf,offset,count) où en faite la fonction n'attends pas forcément d'avoir "count" octets dans le "buf" pour passer à l'instruction suivante. Elle retourne d'ailleurs le nombre d'octets qu'elle lit, et lorsque je l'affiche dans la console de VS, j'ai des valeurs différentes de 6..

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Dim numBytes As Integer = SerialPort1.Read(IncomingBytes, 0, IncomingBytes.Length)
    Console.WriteLine(numBytes)
    Console :
    6
    5
    1
    5
    1
    6
    5
    1

  12. #12
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    c'est pour ca qu'il est préconisé de tout lire sans se poser de question, d'y stocker
    et en parallèle de regarder si dans ce qu'on a reçu on a ce qu'il faut ; dans ton cas 6 octets, dans d'autre on attend d'avoir un début et une fin dans la collection pour en extraire ce morceau pour le traiter, en y laissant ce qui est en trop (car il peut y en avoir plus aussi)

    après que la fonction read sort même si elle n'a pas eut autant d'octet que le count, ce n'est pas un problème, c'est son fonctionnement tel qu'indiqué dans l'aide de la fonction
    sur le tableau d'octet qu'on lui fournit les octets après réception restent inchangés (restent à 0 si suite à une initialisation)

    il y a BytesToRead, donc tu peux attendre d'en avoir au moins 6
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  13. #13
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2016
    Messages : 9
    Points : 2
    Points
    2
    Par défaut
    Ca doit marcher aussi avec BytesToRead, j'essayerai ce soir.
    J'ai réussi d'une autre manière à avoir tout mes octets en jouant avec l'offset :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    For numBytes As Integer = 0 To 5
    SerialPort1.Read(IncomingBytes, numBytes, 1)
    Next numBytes
    Mais ça doit être plus optimiser avec BytesToRead..

Discussions similaires

  1. problème réception port série.
    Par hppp01 dans le forum Débuter
    Réponses: 1
    Dernier message: 09/03/2012, 17h45
  2. [Débutant] c# problème réception port série windows ce 6
    Par kliel dans le forum C#
    Réponses: 2
    Dernier message: 06/03/2012, 16h39
  3. Réception port série (API javax.comm)
    Par trifly dans le forum Entrée/Sortie
    Réponses: 4
    Dernier message: 10/06/2009, 09h13
  4. Problème de ports série sous linux
    Par Imaging dans le forum Matériel
    Réponses: 0
    Dernier message: 15/05/2009, 19h24
  5. Problème avec port Série sur Win XP
    Par alexorel dans le forum MFC
    Réponses: 9
    Dernier message: 27/10/2005, 15h32

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo