Partage
  • Partager sur Facebook
  • Partager sur Twitter

Communication Arduino vers Python

    14 octobre 2021 à 16:35:06

    oui effectivement je n'avais pas pensé au fait que ça créerait une erreur en déclarant une nouvelle variable pour mes boutons.

    • Oui le code Arduino ne sert que de lecture de données pour la carte électronique qui sont ensuite à envoyer en python
    • Oui pour les envoyer sur le serveur et les charger ensuite
    • Oui avec les conditions établis sur le serveur et les valeurs chargées des différents fichiers json on vérifie si elles sont vraies ou fausses
    • Le logiciel relié en OPC UA au serveur se nomme Visual Components. C'est un logiciel de visualistion 3D et à l'aide d'une partie connectivité je peux connecter des signaux à mes variables où sinon des variables logiciels à mon serveur pour les modifier ainsi dedans avec une action tel que le mouvement d'un joystick. Les signaux étant comme des booléens à l'appui d'un bouton il change par exemple de faux à vrai et ainsi peut par exemple en fonction du signal avoir une vitesse rapide ou lente ou encore normale. Cela est possible dû fait que sur ce logiciel l'utilisation du Python (particulière et spécifique au logiciel) est possible mais seulement en version 2.7 et c'est pour cela qu'une utilisation externe d'un code est nécessaire pour la création du serveur.

    Le système voulu consiste donc à communiquer au logiciel Visual Components l'état par exemple des boutons pour action ou non des différents signaux définis par rapport à chaque bouton. Il peut s'agir sinon du sélecteur qui actionne des niveaux de vitesse d'un convoyeur en fonction de si c'est 1 ou 2 ou 3. La carte doit agir comme une manette au final on pourrait dire. Seulement elle doit juste communiquer des informations tels que des états de boutons au logiciel par le biais du serveur connecté à celui-ci, le niveau de sélecteur choisit où les mouvements sur joysticks exécutés.

    Bonne idée d'un unique script pour se connecter à Visual. J'ai donc modifier mes scripts et voici le résultat.

    import time
    import json
    import serial
    from opcua import ua, Server
    
    if __name__ == "__main__":
        # setup server
        server = Server()
        server.set_endpoint("opc.tcp://localhost:4841")
        ser = serial.Serial('COM3', 115200)
        ser.timeout = 0.5  # valeur en secondes
        ser.reset_input_buffer()  # flushInput est dépréciée depuis PySerial 3.0
        ser.reset_output_buffer()  # idem pour flushOutput
    
        '''
        server.set_security_policy([
          ua.SecurityPolicyType.NoSecurity,
          ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,
          ua.SecurityPolicyType.Basic256Sha256_Sign
        ])
        '''
    
        # setup our own namespace, not really necessary but should as spec
        uri = "http://localhost"
        idx = server.register_namespace(uri)
    
        # get Objects node, this is where we should put our nodes
        objects = server.get_objects_node()
        print(objects)
    
        # populating our address space
        MyObjects = objects.add_object(idx, "MyObjects")
        bouton3 = MyObjects.add_variable(idx, "bouton3", False)
        bouton4 = MyObjects.add_variable(idx, "bouton4", False)
        joystick = MyObjects.add_variable(idx, "joystick", int(512))
        selecteur = MyObjects.add_variable(idx, "selecteur", int(0))
    
        # starting!
        server.start()
        etape = 0
    
        while True:
            try:
                msg_recu = ser.readline().decode('utf8').rstrip().lower()  # réception puis décodage puis retrait des '\r\n' (avec rstrip()) puis mise en minuscule)
            except serial.SerialTimeoutException:
                print("Erreur: Sortie par Timeout de lecture")
                print(f"Pas de message reçu dans l'intervalle de temps indiqué ({ser.timeout}s)")
                break
            except serial.SerialException:
                print("Erreur: Erreur d'E/S du port série")
            else:
                #print((msg_recu))
    
                if msg_recu.startswith("bouton3"):
                    etape = 1
                elif etape == 1:
                    # on passe ici si on a eu le message "boutons poussoirs" et que l'on a reçu le 1er message suivant
                    bouton3 = msg_recu
                    ButtonSignal = bool(int(msg_recu))
                    bouton3.set_writable()
    
                if msg_recu.startswith("bouton4"):
                    etape = 2
                elif etape == 2:
                    bouton4 = bool(int((msg_recu)))
    
                    if bouton4 == True:
                        for i in range(1, 4):
                            if i == 1:
                                SlowSpeed = True
                                FastSpeed = False
                                StartStopSpeed = False
                                bouton4.set_writable()
                            elif i == 2:
                                SlowSpeed = False
                                StartStopSpeed = False
                                FastSpeed = True
                                bouton4.set_writable()
                            elif i == 3:
                                FastSpeed = False
                                SlowSpeed = False
                                StartStopSpeed = True
                                bouton4.set_writable()
    
                    elif bouton4 == False:
                        SlowSpeed = False
                        FastSpeed = False
                        StartStopSpeed = False
                        bouton4.set_writable()
    
                elif msg_recu.startswith("selecteur"):
                    etape = 10
                elif etape == 10:
                    # on passe ici si on a eu le message "sélecteur" et une des valeurs
                    selecteur = int(msg_recu)
    
                    if selecteur == 1:
                        Vitesse_lente = True
                        selecteur.set_writable()
    
                    if selecteur == 2:
                        Vitesse_normale = True
                        selecteur.set_writable()
    
                    if selecteur == 3:
                        Vitesse_rapide = True
                        selecteur.set_writable()
    
                elif msg_recu.startswith("joystick") and selecteur == 1:
                    etape = 20
                elif etape == 20:
                    # on passe ici si on a eu le message "joystick" et une des valeurs
                    joystick = float(msg_recu)
                    if joystick >= 0 and joystick < 512:
                        joystick.set_writable()
                        low_vitesse = 399 - 10
                    if joystick == 512:
                        joystick.set_writable()
                        low_vitesse = 399
                    elif joystick > 512:
                        joystick.set_writable()
                        low_vitesse = 200 + 10
    
                elif msg_recu.startswith("joystick") and selecteur == 2:
                    etape = 20
                elif etape == 20:
                    # on passe ici si on a eu le message "joystick" et une des valeurs
                    joystick = float(msg_recu)
                    if joystick >= 0 and joystick < 512:
                        joystick.set_writable()
                        normal_vitesse = 599 - 10
                    elif joystick == 512:
                        joystick.set_writable()
                        normal_vitesse = 599
                    elif joystick > 512:
                        joystick.set_writable()
                        normal_vitesse = 400 + 10
    
                elif msg_recu.startswith("joystick") and selecteur == 3:
                    etape = 20
                elif etape == 20:
                    # on passe ici si on a eu le message "joystick" et une des valeurs
                    joystick = float(msg_recu)
                    if joystick >= 0 and joystick < 512:
                        joystick.set_writable()
                        fast_vitesse = 799 - 10
                    elif joystick == 512:
                        joystick.set_writable()
                        fast_vitesse = 799
                    elif joystick > 512:
                        joystick.set_writable()
                        fast_vitesse = 600 + 10
    
            # Set MyVariable to be writable by clients
    
            print(server.get_namespace_array())
    
            try:
                # count = 0
                # while True:
                #     time.sleep(1)
                #     count += 0.1
                #     myvar.set_value(count)
                input("Press Enter to shutdown server...\n")
            finally:
                # close connection, remove subcsriptions, etc
                ser.close()
                server.stop()
    



    -
    Edité par Aistos 15 octobre 2021 à 12:26:55

    • Partager sur Facebook
    • Partager sur Twitter
      14 octobre 2021 à 18:27:24

      c'est à mon avis mal organisé, et tu redéfinis les variables; par exemple:

      • ligne 33, bouton3 est MyObjects.add_variable(idx, "button3", False)
      • ligne 58, bouton3 devient un booléen
      • ligne 62 et 66, il faudrait que bouton3 soit du type de départ mais c'est un booléen à ce moment, et comme un booléen n'a pas de méthode set_writable(), il y a génération d'une erreur

      Vu que l'on se passe de fichier, il n'y a pas forcément besoin de remettre en boolén ou en entier, on peut comparer directement la chaine reçu. et on peut simplifier ici les lignes 60 à 66 (on affecte directement la valeur lue (convertit en booléen) à ButtonSignal, pas besoin de test)

      ButtonSignal= bool(int(msg_recu))
      bouton3.set_writable()
          

      Quel intérêt de la boucle des lignes 74 à 88, on aura passer dans chacun des tests à la fin de la boucle (on sera Slow puis Fast puis Stop)

      J'ai aussi du mal à voir si c'est normal que Vitesse_lente, Vitesse_normale et Vitesse_rapide peuvent être soit True/False (dans la partie selecteur), soit un entier (dans la partie joystick+selecteur) (et il y a moyen de simplifier cette partie)

      Edit1: Je n'avais pas fait ces remarques avant, parce que je n'avais pas beaucoup analysé le code du serveur avant, j'admets

      Edit2: j'ai aussi un doute sur ce que tu veux faire quand tu fais bouton3.set_writable()

      Edit3: tes variables joy2_x et joy2_y ligne 110 ne sont pas définies, donc encore une erreur

      -
      Edité par umfred 14 octobre 2021 à 18:50:38

      • Partager sur Facebook
      • Partager sur Twitter
        15 octobre 2021 à 12:24:54

        • La ligne 33, bouton3 est MyObjects.add_variable(idx, "button3", False) pour la création d'un objet variable sur Visual.
        • J'ai modifié les lignes 58 et 62 à 66.
        bouton3 = msg_recu
        ButtonSignal = bool(int(msg_recu))
        bouton3.set_writable()

        Au début je voulais créer une boucle qui après chaque appui change d'erreur mais au final après avoir réalisé ce code je me suis dit que vu que le but est de créer des erreurs dans mon logiciel alors changer de vitesse lente, à rapide puis à stop ensuite serait au final une bonne erreur vu que cela dérègle complètement le convoyeur et donc la ligne de production.

        J'ai changé le nom de mes variables sur le logiciel et donc sur Python aussi comme vous pouvez le voir ci-dessous.

                    elif msg_recu.startswith("joystick") and selecteur == 1:
                        etape = 20
                    elif etape == 20:
                        # on passe ici si on a eu le message "joystick" et une des valeurs
                        joystick = float(msg_recu)
                        if joystick >= 0 and joystick < 512:
                            joystick.set_writable()
                            low_vitesse = 399 - 10
                        if joystick == 512:
                            joystick.set_writable()
                            low_vitesse = 399
                        elif joystick > 512:
                            joystick.set_writable()
                            low_vitesse = 200 + 10
        
                    elif msg_recu.startswith("joystick") and selecteur == 2:
                        etape = 20
                    elif etape == 20:
                        # on passe ici si on a eu le message "joystick" et une des valeurs
                        joystick = float(msg_recu)
                        if joystick >= 0 and joystick < 512:
                            joystick.set_writable()
                            normal_vitesse = 599 - 10
                        elif joystick == 512:
                            joystick.set_writable()
                            normal_vitesse = 599
                        elif joystick > 512:
                            joystick.set_writable()
                            normal_vitesse = 400 + 10
        
                    elif msg_recu.startswith("joystick") and selecteur == 3:
                        etape = 20
                    elif etape == 20:
                        # on passe ici si on a eu le message "joystick" et une des valeurs
                        joystick = float(msg_recu)
                        if joystick >= 0 and joystick < 512:
                            joystick.set_writable()
                            fast_vitesse = 799 - 10
                        elif joystick == 512:
                            joystick.set_writable()
                            fast_vitesse = 799
                        elif joystick > 512:
                            joystick.set_writable()
                            fast_vitesse = 600 + 10

        Je n'ai pas encore regardé comment simplifier ce code car j'ai d'abord corrigé les erreurs que vous m'avez indiqué et les coquilles que j'ai faites aussi en écrivant. Ce n'est pas un problème toutes remarques sont bonnes à prendre et cela me permet ainsi de gagner en compétence sur un aspect serveur où je ne m'étais jamais aventuré auparavant. 

        Avec bouton3.set_writable() je veux écrire la valeur du bouton sur Visual Components et si c'est True alors le signal Visual choisi le devient aussi et s'active.

        Si vous souhaitez y voir plus clair j'ai joint ci-dessus une catpure de mon interface connexion sur Visual Components. 

        Edit : J'ai corrigé mon code dans le message précédent

        -
        Edité par Aistos 15 octobre 2021 à 12:25:39

        • Partager sur Facebook
        • Partager sur Twitter
          15 octobre 2021 à 13:16:23

          pour écrire une variable c'est bouton3.set_valeur(valeur) ; set_writable() rend la variable modifiable (écrivable?) par le logiciel
          • Partager sur Facebook
          • Partager sur Twitter
            15 octobre 2021 à 16:28:50

            Oui c'est cela je viens de voir mais du coup cela me semble peu approprié j'imagine vu que tout mon code agit sur la simulation et non l'inverse.

            J'ai par ailleurs codé un autre script serveur avec les scripts json et cela me semble plus correct.

            import time
            import json
            from opcua import ua, Server
            
            
            if __name__ == "__main__":
                # setup server
                server = Server()
                server.set_endpoint("opc.tcp://localhost:4841")
            
                '''
                server.set_security_policy([
                  ua.SecurityPolicyType.NoSecurity,
                  ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt,
                  ua.SecurityPolicyType.Basic256Sha256_Sign
                ])
                '''
                OFFSET_JOYSTICK = 50
            
                # setup our own namespace, not really necessary but should as spec
                uri = "http://localhost"
                idx = server.register_namespace(uri)
            
                # get Objects node, this is where we should put our nodes
                objects = server.get_objects_node()
                print(objects)
            
                # populating our address space
                MyObjects = objects.add_object(idx, "MyObjects")
                button3 = MyObjects.add_variable(idx,"button3",int())
                button4 = MyObjects.add_variable(idx,"button4",int())
                joyst = MyObjects.add_variable(idx,"joyst",int())
                select = MyObjects.add_variable(idx, "selector", int())
            
                # starting!
                server.start()
            
                while True:
            
                    with open ("bouton3.json") as k:
                        bouton3 = json.load(k)
                        print(bouton3)
                        print(bouton3['bouton3'])
            
                    if bouton3 == 1:
                        ButtonSignal = True
                        button3.set_value(1)
                    else:
                        ButtonSignal = False
                        button3.set_value(0)
            
                    with open("bouton4.json") as p:
                        bouton4 = json.load(p)
                        print(bouton4)
                        print(bouton4['bouton4'])
            
                    if bouton4 == 1:
                        for i in range(1,4):
                            if i == 1:
                                SlowSpeed = True
                                FastSpeed = False
                                StartStopSpeed = False
                                button4.set_value(1)
                            if i == 2:
                                SlowSpeed = False
                                StartStopSpeed = False
                                FastSpeed = True
                                button4.set_value(1)
                            if i == 3:
                                FastSpeed = False
                                SlowSpeed = False
                                StartStopSpeed = True
                                button4.set_value(1)
            
                    if bouton4 == 0:
                        SlowSpeed = False
                        FastSpeed = False
                        StartStopSpeed = False
                        button4.set_value(0)
            
                    with open("selecteur.json") as f:
                        selecteur = json.load(f)
                        print(selecteur)
                        print(selecteur['selecteur'])
            
                    if selecteur == 1:
                        Vitesse_lente = True
                        select.set_value(1)
                        with open("joystick.json") as o:
                            joystick =json.load(o)
                            print(joystick)
                            print(joystick['joystick'])
            
                        if joystick >= 0 and joystick < 512:
                            joyst.set_value(joystick)
                            low_vitesse = 399 - 10
                        if joystick == 512:
                            joyst.set_value(joystick)
                            low_vitesse = 399
                        elif joystick > 512:
                            joyst.set_value(joystick)
                            low_vitesse = 200 + 10
            
                    if selecteur == 2:
                        Vitesse_normale = True
                        select.set_value(2)
                        with open("joystick.json") as l:
                            joystick = json.load(l)
                            print(joystick)
                            print(joystick['joystick'])
            
                        if joystick >= 0 and joystick < 512:
                            joyst.set_value(joystick)
                            normal_vitesse = 599 - 10
                        elif joystick == 512:
                            joyst.set_value(joystick)
                            normal_vitesse = 599
                        elif joystick > 512:
                            joyst.set_value(joystick)
                            normal_vitesse = 400 + 10
            
                    if selecteur == 3:
                        Vitesse_rapide = True
                        select.set_value(3)
                        with open("joystick.json") as r:
                            joystick = json.load(r)
                            print(joystick)
                            print(joystick['joystick'])
            
                        if joystick >= 0 and joystick < 512:
                            joyst.set_value(joystick)
                            fast_vitesse = 799 - 10
                        elif joystick == 512:
                            joyst.set_value(joystick)
                            fast_vitesse = 799
                        elif joystick > 512:
                            joyst.set_value(joystick)
                            fast_vitesse = 600 + 10
            
                    # Set MyVariable to be writable by clients
            
                    print(server.get_namespace_array())
            
                    try:
                        # count = 0
                        # while True:
                        #     time.sleep(1)
                        #     count += 0.1
                        #     myvar.set_value(count)
                        input("Press Enter to shutdown server...\n")
                    finally:
                        # close connection, remove subcsriptions, etc
                        server.stop()
            



            Malheureusement je me retrouve de nouveau avec cette erreur.

            AttributeError: 'dict' object has no attribute 'set_valeur'

            Je vais donc voir pour contourner le problème par un autre moyen.


            -
            Edité par Aistos 21 octobre 2021 à 12:44:45

            • Partager sur Facebook
            • Partager sur Twitter
              15 octobre 2021 à 16:38:02

              c'est encore le problème de redéfinition de la variable pour selecteur et joystick entre les lignes 32/33 et au moment des json.load. Tu utilises encore le même nom pour stocker 2 choses différentes.
              • Partager sur Facebook
              • Partager sur Twitter
                21 octobre 2021 à 12:46:56

                Effectivement je viens de voir le problème et vous avez raison. J'ai donc modifié mon code ci-dessus avec les différentes corrections apportées. 

                En changeant set_valeur par set_value je n'ai plus l'erreur d'attribut en sortie.

                Cependant, je me demande s'il n'y a pas quelque chose qui cloche car les valeurs ne se modifient pas sur mon logiciel au contact pour effectuer une action.

                • Partager sur Facebook
                • Partager sur Twitter
                  21 octobre 2021 à 14:35:52

                  arf désolé pour le set_valeur au lieu de set_value (j'ai du me mélanger entre anglais et français en écrivant, pensant écrire la bonne version):o

                  Si je regarde attentivement ta capture de ton logiciel de simulation, tu as une zone variables simulation vers server et une zone variables server vers simulation, et dans cette section, tu n'as rien de défini (je ne sais pas si c'est ça le problème)

                  Je remarque aussi que pour plusieurs variables simulation tu as la même variable server associée (sauf erreur de ma part), donc quand tu modifies par exemple bouton4 côté server, tu modifies (à mon avis) Conveyor #.SlowSpeed, Conveyor #2.FastSpeed et Conveyor #2.Start/StopSpeed

                  Tu peux essayer de suivre le tuto proposé sur le site de visual components https://academy.visualcomponents.com/courses/basics-of-python-scripting/ 

                  ou consulter/explorer leur forum https://forum.visualcomponents.com/t/controlling-with-external-python-script/2116/2 par exemple

                  Donc un faire un bout de code qui te permette de tester la modification (et lecture) d'une variable/d'un état/d'un actionneur/.... "manuellement" dans visual components sans liaison avec la carte arduino 

                  • Partager sur Facebook
                  • Partager sur Twitter
                    22 octobre 2021 à 12:08:35

                    Pas de soucis, il n'y a pas de mal :) .

                    Justement depuis j'ai changé et mis toutes mes variables côté serveur vers simulation. Cependant lorsque la connexion se fait, elles sont définies en fonction de ces instructions différentes. 

                    button3 = MyObjects.add_variable(idx,"button3",int())
                    button4 = MyObjects.add_variable(idx,"button4",int())
                    joyst = MyObjects.add_variable(idx,"joyst",int())
                    select = MyObjects.add_variable(idx, "selector", int())

                    J'essaye de faire en sorte de changer leurs valeurs, mais rien n'y fait.

                    Oui, ai-je tort de donner le même nom au variables serveurs et simulation ? Cependant je me posais la question par rapport à ces variables, ne devrais-je pas utiliser la méthode set_writable pour que la simulation mette à jour les valeurs de signaux ?

                    J'ai bien suivit le tuto de Visual mais le logiciel utilise des librairies propres au logiciel. 

                    Je vais essayer alors de continuer à chercher du côté du forum de Visual pour voir si cela peut m'aider.

                    Très bien merci pour ces conseils.

                    -
                    Edité par Aistos 22 octobre 2021 à 12:19:18

                    • Partager sur Facebook
                    • Partager sur Twitter
                      22 octobre 2021 à 16:31:49

                      le même nom, non mais il semble y avoir une variable d'un côté associée à 3 ou 4 autres de l'autre côté (un non sens selon moi)

                      Conveyor #.SlowSpeed <-> bouton4

                      Conveyor #2.FastSpeed <-> bouton4

                      Conveyor #2.Start/StopSpeed <-> bouton4

                      donc forcément si tu modifies bouton4, tu modifies les 3 en même temps (si l'association se fait et sauf erreur de ma part)

                      • Partager sur Facebook
                      • Partager sur Twitter

                      Communication Arduino vers Python

                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                      • Editeur
                      • Markdown