Pages: [1] 2 3 4   Go Down
Author Topic: aide communication série entre Arduino et visual c#  (Read 4344 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour,

je suis un étudiant en Ingénieur électronique, et dans le cadre de mon stage il m'est demandé de programmer une presse.

Mon maitre de stage désire que cette presse puisse :

- choisir la vitesse de descente
- choisir le déplacement
- avoir les données de pression de cellule de force

Ma question est la suivante,

je réussi a avoir les données de la cellule de force et d'en faire un graph en temps réel sur visual c#.

Mais... comment pouvoir envoyer vers Arduino la valeur de la vitesse et du déplacement rentré par l'utilisateur sur visual c# ?

Pour obtenir ce que l'arduino lit sur son entrée analogique, je lui dit que quand il a 4 sur le port il m'écrit sur le port la valeur de l'entrée analogique.
Mais comment lui dire d'écrire par exemple 4 et la valeur de la vitesse et le déplacement ?

Je possède une carte Arduino UNO et un moteur pas à pas

Merci
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour,

J'ai trouvé quelque chose qui peut t'intéresser : http://csharp.simpleserial.com/

Logged

Ile-de-France (92 sud), France
Offline Offline
Edison Member
*
Karma: 24
Posts: 2055
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Pour obtenir ce que l'arduino lit sur son entrée analogique, je lui dit que quand il a 4 sur le port il m'écrit sur le port la valeur de l'entrée analogique.
Mais comment lui dire d'écrire par exemple 4 et la valeur de la vitesse et le déplacement ?

Hum.
Précise déjà ce que tu as comme connexion.
Tu dis que tu réussi à transférer la valeur du port analogique. Précise comment.

En fait on ne sait pas exactement où tu en es, ce qui marche, ce qui ne marche pas.
Logged

Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour, désolé de ne pas avoir répondu plus tôt

Donc je vous post mon code Arduino qui fonctionne pour la lecture de l'entrée analogique et le code visual c# associé

Ensuite je vous posterai (dans un autre post pour eviter toutes confusion ce que j'ai essayé de faire pour commander le moteur mais qui ne marche pas smiley

Donc voici mon code Arduino :

Code:
void setup()  
{                

  Serial.begin(19254 );  
}

void loop()                    
{
  if(Serial.available())
  {
    int c = Serial.read();
    
    if (c == '4')
    {
    Serial.println(analogRead(A1));
    }  
  }
}

et le code visual c#

Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.IO;
using Microsoft.Office.Core;
using Excel = Microsoft.Office.Interop.Excel;
using System.Windows.Forms.DataVisualization.Charting;
using Microsoft.Office.Interop.Excel;
using ApplicationForm = System.Windows.Forms.Application;
using System.Globalization;

namespace Acqu_donnee
{
    public partial class Form1 : Form
    {
        SerialPort Port1; //ouverture du port série

        public Form1()
        {
            InitializeComponent();
            for (int i = 1; i <= 50; i++)
            {
                try
                {
                    Port1 = new SerialPort("COM" + i, 19254); //Port1 trouve le port COM du PC
                    Port1.Open(); //Port1 est ouvert
                    Port1.ReadTimeout = 1000; //Delais pour l'écriture
                    Port1.WriteTimeout = 1000; //Délais pour la lecture

                    Port1.Write("4"); //Ecrit 4 sur le port 1

                    byte[] lus = new byte[8];
                    int nblu = Port1.Read(lus, 0, 8);
                    if (nblu > 0)
                    {
                        return; // port trouvé
                    }
                }
                catch (Exception)
                {
                    Port1.Dispose();
                }

            }
        }

        public void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (Port1.IsOpen) Port1.Close(); //Ferme le port1 à la fermeture du programme
        }

        public void timer1_Tick(object sender, EventArgs e) //Evenement à chaque tick du Timer1
        {
            string r = ""; //défini r comme un string vide
            double x = 0; //défini x comme un double vide
            double value = 0; //Défini vélue comme un double vide
            if (Lect_mes.Checked) //Si Lect_mes est cochée
            {
                Port1.Write("4"); //on écrit 4 sur le port1
            }
            
            r = Port1.ReadLine(); //r = ce qu'il lit sur le port1
            try
            {
                x = Convert.ToDouble(r); //converti un Char en Double
                value = Math.Round((x / 1024 * 5 * 2 * 196.2), 2); //On calcul la pression
                //1024 = 0...1023 échantillons (valeur renvoyée par le port1)
                //5 car on est sur la plage 0...5V
                //196.2 convertion Kg en Newton
                //2, on arrondis à 2 décimales
            }
            catch
            {
                if (listBox1.Items.Count == 0)
                {
                    value = 0;
                }
                else
                {
                    value = double.Parse( listBox1.Items[listBox1.Items.Count - 1].ToString());
                }
            }
            listBox1.Items.Add(value); //Ajoute les valeurs de value dans la ListBox
            listBox1.SelectedIndex = listBox1.Items.Count - 1; //AutoScroll de la ListBox

            double xVal = listBox1.Items.Count * 0.02; //Valeur axe des x
            chart1.Series[0].Points.AddXY(xVal, value); //Ecriture des points sur le graph
            chart1.ChartAreas[0].AxisX.Maximum = xVal; // Maximum de l'axe des x est la dernière valeur de XVal
            if (chart1.Series[0].Points.Count > 250) // Permet d'afficher que 5 secondes sur l'axe des x
            {
                chart1.Series[0].Points.RemoveAt(0);
            }
            
           chart1.ChartAreas[0].AxisX.Minimum = chart1.Series[0].Points[0].XValue;
              
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            string r = ""; //défini r comme un string vide
            double x = 0; //défini x comme un double vide
            double value = 0; //Défini vélue comme un double vide
            if (Lect_mes.Checked) //Si Lect_mes est cochée
            {
                Port1.Write("4"); //on écrit 4 sur le port1
            }

            r = Port1.ReadLine();
            try
            {
                x = Convert.ToDouble(r); //converti un Char en Double
                value = Math.Round((x / 1023 * 5 * 2 * 196.2), 2); //On calcul la pression
                //1024 = 0...1023 échantillons (valeur renvoyée par le port1)
                //5 car on est sur la plage 0...5V
                //196.2 convertion Kg en Newton
                //2, on arrondis à 2 décimales
            }
            catch
            {
                value = 0;
            }
            textBox1.Text = value.ToString() +' ' + 'N'; // Rajoute N après la mesure dans la TextBox
        }

        public void Lect_mes_CheckedChanged(object sender, EventArgs e) //Evenement quand Lect_mes change d'état
        {
            if (Lect_mes.Checked) //Si Lect-mes est coché on écrit 4 sur le Port1
            {                     //et on actionne les Timers
                Port1.Write("4");
                timer1.Enabled = true;
                timer2.Enabled = true;
            }
            else
            {
                timer1.Enabled = false; //Sinon on coupe les Timers
                timer2.Enabled = false;
            }
        }

        public void Del_ListBox_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear(); //Clear la ListBox
            chart1.Series[0].Points.Clear(); //Clear le Graph
            textBox1.Clear(); //Clear la TextBox
        }

        private void toExcel_Click(object sender, EventArgs e)
        {
            Excel.Application oXL;    //Définition d'une nouvelle application Excel
            Excel.Workbook oWB;       //Définition d'un classeur
            Excel.Worksheet oSheet;   //Définition d'une feuille

            object misValue = System.Reflection.Missing.Value;

            // initialisation feuille excel
            try
            {
                oXL = new Excel.Application(); //myExcelApp est créee par Excel.Application
                oXL.Visible = true;            //Ouvre Excel automatiquement après l'export
                FileInfo fi = new FileInfo(ApplicationForm.ExecutablePath);

                oWB = (Excel.Workbook)(oXL.Workbooks.Open(Path.Combine(fi.DirectoryName, "Acquisition.xls"))); //Ouvre le fichier Acquisition.xls
                oSheet = (Excel.Worksheet)oWB.ActiveSheet;

                Excel.Range oRange = (Excel.Range)oSheet.get_Range("A3", "B30000"); //Ecrit les données de la cellule A3 a B30000
                oRange.Clear();


                //écriture dans feuille excel
                for (int i = 0; i < Math.Min(listBox1.Items.Count - 1, 27997); i++)
                {
                    oXL.Cells[i + 3, 2] = listBox1.Items[i].ToString(); //On inscrit toutes les valeurs de la ListBox les une en dessous des autres à partir de B3
                    if (i == 0)
                    {
                        oXL.Cells[3, 1] = 0; //Permet d'écrire le temps dans A3
                    }
                    else
                    {
                        oXL.Cells[i + 3, 1] = i * 0.02; //Permet d'écrire le temps dans A4 jusque autant de mesure par pas de 0,02 (50hz)
                    }
                }
            }
            catch
            {
                MessageBox.Show("L'exportation n'a pas été effectuée"); //Si exportation Excel plante, message d'erreur
            }
        }
    }
}



NB : y a deux timer dans le code car j'ai une acquisition à 50hz dans une listbox et une a 10hz dans une textbox smiley-wink
Voila, ceci fonctionne très bien pour lire l'entrée analogique A1
« Last Edit: April 16, 2012, 01:14:26 am by HadesDT » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Et voila ce que je voulais faire pour commander le moteur :

Code:
#include <Stepper.h>

const int steps = 20;  // change this to fit the number of steps per revolution
                                     // for your motor
Stepper myStepper(steps, 4,5,7,8);

void setup() 
{               

  Serial.begin(19254); 
}

void loop()                   
{
  if(Serial.available())
  {
    int c = Serial.read();
    int Speed = 0;
    int Distance = 0;
    if (c == '0')
    {
      Speed = Serial.read(); 
    }
    else
    {
      Speed = Speed;
    }
    if (c == '1')
    {
      Distance = Serial.read();
    }
    else
    {
      Distance = Distance;
    }
 
    if (c == '4')
    {
    Serial.println(analogRead(A1));
    myStepper.setSpeed(Speed);
    double Deplacement = Distance / 0.005;
    myStepper.step(Deplacement);
    myStepper.step(-Deplacement);
    } 
  }
}

et visual c# (je rajoute ceci)

Code:
        private void Speed_button_Click(object sender, EventArgs e)
        {
            Port1.Write("0");
            string Speed;
            Speed = Speed_TextBox.Text;
            Port1.Write(Speed);
        }

        private void Depl_button_Click(object sender, EventArgs e)
        {
            Port1.Write("1");
            string Deplacement;
            Deplacement = Depl_TextBox.Text;
            Port1.Write(Deplacement);
        }

A votre avis qu'est ce qu'il faudrait que je fasse ?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Pas grand chose ne fonctionne à part l'acquisition sur l'entrée analogique

Mais... Cette acquisition fonctionne si je retire toute la commande du moteur, donc la je sèche vraiment ... Comment faire?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Personne pour m'aider ?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Vais essayé d'etre un peu plus clair smiley

Si je met le code du début à savoir :

Code:
void setup() 
{               

  Serial.begin(19254 ); 
}

void loop()                   
{
  if(Serial.available())
  {
    int c = Serial.read();
   
    if (c == '4')
    {
    Serial.println(analogRead(A1));
    } 
  }
}

L'acquisition de l'entrée analogique fonctionne très bien, mon graph se fait en temps réel etc sur visual c#

Si je rajoute un peu de code pour la commande du moteur :

Code:
#include <Stepper.h>

const int steps = 20; 
Stepper myStepper(steps, 4,5,7,8);
int EnA=3;
int EnB=6;

void setup() 
{               
  Serial.begin(19254);
  pinMode(EnA, OUTPUT);
  pinMode(EnB, OUTPUT);
}

void loop()                   
{
  if(Serial.available())
  {
    int c = Serial.read();
     
    if (c == '4')
    {
    digitalWrite(EnA,HIGH);
    digitalWrite(EnB,HIGH);
    Serial.println(analogRead(A1));
    }
motor();
  }
}

void motor()
{
  myStepper.setSpeed(60);
  myStepper.step(steps);
  myStepper.step(-steps);
}

Maintenant avec ce code :

J'ai 1 ou 2 acquisitions sur visual c# (au lieu de 50 par secondes) puis il me dit qu'il a pas sur lire le port et que l'opération has timeout.
Ce qui me parait logique car la boucle loop s'éffectue tout le temps, donc il va ecrire sur le portsérie l'entrée analogique et après il lance le moteur, mais celui ci prend un certain temps à faire son cycle.

Donc ma question est :
Comment arriver à dire a la carte tu fais le cycle du moteur ET tu envoies en continu les info sur le port série de l'entrée analogique ?

Merci de m'aider car je suis totalement bloqué et je trouve rien sur internet smiley-sad
Logged

Ile-de-France (92 sud), France
Offline Offline
Edison Member
*
Karma: 24
Posts: 2055
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Je ne sais pas ce que fais ce code "Stepper" mais de toute évidence c'est lui qui te faire perdre ton temps.

Déjà tu peut probablement découper le code de motor() en 3 phases

Code:
int motor_state = 0;
motor()
{
  switch( motor_state )
  {
  case 1:
    myStepper.setSpeed(60);
    ++motor_state;
    break;
  case 2:
    myStepper.step(steps);
    ++motor_state;
    break;
  case 3:
    myStepper.step(-steps);
    motor_state = 0;
    break;
  }
}

Sur Arduino tu n'as pas de multi-tâche.
Il faut donc découper chaque tâche en sous-tâche élémentaire de durée très courte de façon a pouvoir entremêler les sous tâches. Une machine d'état pour chaque tâche est souvent utile.

Si çà ne marche pas mieux c'est que l'appel à mySTepper.step(xxx) prend trop de temps. N'est-il pas possible de scinder en plusieurs appels plus petits ?

Logged

Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

oui j'ai remarqué que Stepper.step me prennait beaucoup de temps,

j'ai fait quelque recherche et j'ai trouvé qu'il était plus facile de commander un pas a pas avec Arduino + L297 + L298 + pont de diode en HH + moteur.

Le l297 permet de faire la sequence mystepper (enfin si on peut dire) et il y a que 3 I/O digital de l'arduino qui sont utilisée

une qui permet de choisir le sens de rotation, 1 ou 0
une qui permet de choisir le step, sur celle ci faut mettre une clock, je sais pas encore trop comment la faire, si tu as une idée smiley
une qui permet de dire si c'est un pas entier ou demi, 1 ou 0

Donc cette méthode devrait me permettre de plus perdre de temps, t'en penses quoi ?

J'ai fais un essai avec un servo pour savoir si en mettant des 1 ou 0 etc si ca réagissait, et la je ne perd plus de temps, j'ai la lecture de l'analogique sur c# et le servo qui est controler, donc si je suis cette logique je devrait arriver a ce que je veux smiley

Edit, voila le schéma utilisé



Les bornes 3,4,5 de l'arduino sont connectées aux bornes 17,18,19 du L297
la borne 15 est connectée à un potentiometre (cela permet de définir le max dans le L297)
la borne 10 est mise aux 5V, car pas besoin de pouvoir jouer dessus
La borne reset est connectée avec celle de l'arduino

13 et 14 à la masse et 1 et 15 du l298 aussi car pas besoin de pouvoir mesuré le courant

Le reste comme c'est mit
« Last Edit: April 17, 2012, 12:22:03 pm by HadesDT » Logged

Ile-de-France (92 sud), France
Offline Offline
Edison Member
*
Karma: 24
Posts: 2055
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Je n'ai pas d'expérience avec les moteurs pas à pas mais je comprend le principe.
A la fin même si tu fais ce nouveau montage, tu devras donner sur CLOCK un nombre d'impulsion égal au nombre de pas.
On peut peut-être arriver à faire générer à l'Arduino un nombre précis d'impulsions via timer et interruptions...Je vais y réfléchir

Mais ne peux-tu pas commencer par faire moins de pas dans chaque appel à step() ?
Logged

Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

Ile-de-France (92 sud), France
Offline Offline
Edison Member
*
Karma: 24
Posts: 2055
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Question subsidiaire : Pourquoi choisir un baudrate non standard de 19254 ?
La valeur standard la plus proche est 19200.

Les valeurs les plus courantes sont :
75, 120, 240, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 256000
Et 31250 pour le MIDI

Certains drivers sur PC, à une lointaine époque smiley, ne savaient pas générer d'autres valeurs.

Logged

Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

car je fais en sorte que le pc trouve le port COM de la carte automatiquement, donc je les ai mit a un débit non standard comme ca un périf extérieur du pc ne peux pas venir perturber la détection de la carte smiley
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 30
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Je n'ai pas d'expérience avec les moteurs pas à pas mais je comprend le principe.
A la fin même si tu fais ce nouveau montage, tu devras donner sur CLOCK un nombre d'impulsion égal au nombre de pas.
On peut peut-être arriver à faire générer à l'Arduino un nombre précis d'impulsions via timer et interruptions...Je vais y réfléchir

Mais ne peux-tu pas commencer par faire moins de pas dans chaque appel à step() ?


oui, mais peut être que ca lui fera perdre moins de temps de faire 1 ou 0 très rapidement sur une seule I/O digital ? Mais comment arriver a faire cette clock ?

et pour faire moins de pas dans chaque appel de step je ne sais pas trop comment faire (je n'ai jamais touché au moteur PaP smiley-sad)
Logged

Ile-de-France (92 sud), France
Offline Offline
Edison Member
*
Karma: 24
Posts: 2055
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

car je fais en sorte que le pc trouve le port COM de la carte automatiquement, donc je les ai mit a un débit non standard comme ca un périf extérieur du pc ne peux pas venir perturber la détection de la carte smiley

Ca n'a pas de sens ce que tu dis.
Le baudrate c'est toi qui le règle dans l'objet SerialPort, membre baudrate.

Revenons aux moteurs pas à pas.
De ton code je déduit :
- Ton moteur à besoin de 20 pas pour faire un tour complet (cf le constructeur de Serial)
- Tu le règle à la vitesse de 60 tours par minute, donc 1 tour par seconde
- Quand tu appelles myStepper.step(20) tu lui fait faire un tour, en 1 seconde.

Donc tu ne peux revenir sur ton code de liaison série qu'une fois par seconde.

Il faut donc réduire le nombre de pas dans myStepper.step(), en faire moins (1 par 1 par exemple) à chaque tour de loop() jusqu'à atteindre 20.

Essaye quelque chose comme :

1) Déplace le setSpeed(60) dans setup(). Rien a faire dans loop.

2) Change motor() comme çà :

Code:
int motor_count = 0;
int motor_dir = 1;
void motor()
{
  myStepper( motor_dir );
  if ( ++motor_count >= step )
  {
    motor_dir = - motor_dir;// on change de sens
    motor_count = 0;
  }
}

Le temps d'exécution d'un step passe de 1 seconde à 1/20ème.

Pour aller plus loin, si c'est nécessaire, il va falloir être plus malin. Probablement se passer de la classe Stepper et refaire à la main le séquencement des pas.
Logged

Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

Pages: [1] 2 3 4   Go Up
Jump to: