Quand le Rover envoie des datas, en retour, c'est souvent sur demande mais il sait aussi le faire en cas de sécurité.
Soit je lui demande des paramètres, il me renvoie un tableau de valeurs.
Soit je ne lui demande rien mais il doit avertir d'un soucis (en fonction de ses capteurs) pour prévenir l'opérateur du problème rencontré.
Exemple, je lui demande de faire 5 mètres devant lui.
À 2 mètres il rencontre un obstacle qu'il juge ne pas pouvoir franchir et s'arrête en attente d'ordre. Il envoie alors un message impliquant le capteur de proximité indiquant le message suivant : Ordre 5 mètres. Parcouru 2 mètre. Capteur US 10cm. Impossible à franchir.
Comme ce message peut intervenir à n'importe quel moment, il faut bien l'affiché dès réception.
C'est peut être pas clair
En attendant de coder le reste, j'ai ajouter la déconnexion
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145 # -- IMPORTATIONS import tkinter as tk import serial # -- CLASSE Interface graphique class IHM(tk.Frame): #Initialisation def __init__(self, parent): #Variables self.parent = parent self.connexion = COM(parent) #Les frames tk.Frame.__init__(self, self.parent) self.boutons = tk.LabelFrame(self, text="Contoles", padx=20, pady=20) self.logs = tk.LabelFrame(self, text="Logs", padx=20, pady=20) #Images self.myImgAV = tk.PhotoImage(file="ressources/icones/av.gif") self.myImgCO = tk.PhotoImage(file="ressources/icones/co.gif") self.myImgDECO = tk.PhotoImage(file="ressources/icones/deco.gif") #Boutons self.btAV = tk.Button(self.boutons, image=self.myImgAV, bg = "grey") self.btCO = tk.Button(self.boutons, image=self.myImgCO, bg = "green", command=self.callback_connexion) self.btDECO = tk.Button(self.boutons, image=self.myImgDECO, bg = "green", command=self.callback_deconnexion) #Textes self.textLogs = tk.Text(self.logs, width=50, height=20, wrap=tk.WORD) #Position des boutons self.boutons.grid(column=0, row=0, sticky='NS') self.btCO.grid(column=0, row=0) self.btDECO.grid(column=1, row=0) self.btAV.grid(column=2, row=1) #Position du log self.logs.grid(column=0, row=1, sticky='NS') self.textLogs.grid(column=0, row=0) #Afficher des informations def setLog(self, informations): self.textLogs.insert(0.0, informations) #Callback : Connexion def callback_connexion(self): self.connexion.serialConnexion() self.setLog(self.connexion.getEtatConnexion()) self.setLog("\n" + self.connexion.getInformationsUser()) self.connexion.resetInformation() #Callback : Déconnexion def callback_deconnexion(self): self.connexion.serialDeconnexion() self.setLog(self.connexion.getEtatConnexion()) self.setLog("\n" + self.connexion.getInformationsUser()) self.connexion.resetInformation() # --CLASSE rover class ROVER(): #Initialisation def __init__(self, parent): #Variables self.parent = parent """ Ici on place toutes les fonctions que feront le rover -> Admet des infos de l'IHM <- Retourne des datas à envoyer sur le port série """ # -- CLASSE Communication class COM(): #Initialisation def __init__(self, parent): #Variables self.parent = parent self.locations=['/dev/ttyUSB0', '/dev/ttyUSB1', '/dev/ttyUSB2', '/dev/ttyUSB3', '/dev/ttyS0', '/dev/ttyS1', '/dev/ttyS2', '/dev/ttyS3'] self.ser = '' self.is_connected = False self.information = "" #Connexion Serie def serialConnexion(self): #Tentative de connexion au XBee Usb for device in self.locations: try: self.information += "Tentative de connexion sur le port" + device + "...\n" self.ser = serial.Serial(device, 9600) self.information += "Connexion sur sur le port" + device + " [Ok]\n" self.is_connected = True break except: self.information += "Connexion échoué sur " + device + "! [Fail]\n" self.is_connected = False #Deconnexion série def serialDeconnexion(self): #Test si le port à été ouvert if self.is_connected: #Ferme le port self.ser.close() self.is_connected = False self.information += "Deconnexion [Ok]\n" else: self.information += "La connexion n'a jamais été faite !\n" #Reset de message def resetInformation(self): self.information = "" #Etat de la connexion def getEtatConnexion(self): return self.is_connected #Informations utilisateur def getInformationsUser(self): return self.information # -- MAIN root = tk.Tk() ihm = IHM(root) ihm.grid(column=0, row=0, sticky='NS') #rover = ROVER(root) #com = COM(root) root.title('POSL Rover') #Titre de l'application root.mainloop() #Boucler
Salut,
Sur le port série vous allez lire byte après byte.
Comment allez vous savoir que vous avez lu tout le message à lire pour par exemple extraire les valeurs du tableau?
Ajoutez une bricole comme:
- W
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 import sys def dump_serial(port): while True: c = port.read(1) sys.stdout.write(c) root = tk.Tk() ihm = IHM(root) port = ihm.connexion.ser task = threading.Thread(target=dump_serial, args=(port,)) task.daemon = True task.start() ...
Oh, c'est exact... J'avais totalement oublier de parler du protocole que je vais mettre en place ! Désolé. Oui, faut que je test cet exercice que je voie ce qu'il en est.
Le protocaole sera tou le temps : "*,truc,!"
On as un début de trame avec "*"
On a des séparateur ","
Remplaçons truc par chose,valeur-chose,truc,valeur-truc
Et on termine la trame avec "!"
Donc on saura à terme si on a bien fini notre trame et quand envoyer.
Du coup, avant de m'attaquer à ton exemple, j'ai coder un petit truc pour la fermeture de l'application:
Donc, avant de quitter l'application, on pourra tuer le thread
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 # -------------------------------------------------------------------------------------------------------------- # -- FONCTIONS #Fonction qui fermera l'application et qui va killer les threads def fermetureApplication(): if tk.messagebox.askokcancel("Fermeture du programme", "Voulez-vous réelement fermer le programme POSL Rover ?"): root.destroy() # -- MAIN root = tk.Tk() ihm = IHM(root) ihm.grid(column=0, row=0, sticky='NS') #rover = ROVER(root) #com = COM(root) root.protocol("WM_DELETE_WINDOW", fermetureApplication) root.title('POSL Rover') #Titre de l'application root.mainloop() #Boucler
M'en doutais un peu que ça fonctionnerais mais que l'intégration serais délicate.
Logique pusique on cherche à établir une connexion qui n'aura lieu qu'à ma demande !Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python3.2/threading.py", line 740, in _bootstrap_inner
self.run()
File "/usr/lib/python3.2/threading.py", line 693, in run
self._target(*self._args, **self._kwargs)
File "/home/alexandre/Documents/Programmations/Python/POSL-Rover/POSL-Rover.py", line 148, in dump_serial
c = port.read(1)
AttributeError: 'str' object has no attribute 'read'
Je me propose donc une solution plus adéquate adaptant le code déjà mis.
Enfin, je propose cette solution qu'en pensez-vous ?// Si on a bien la connexion (voir serialDeconnexion.getEtatConnexion() car True / False)
//Lancer le thread
//Sinon, ne rien faire
Merci.
Salut,
Ah, oui pardon.
En fait, je ne comprends pas trop l'intérêt de "serialConnexion". Cà il se contente d'ouvrir le premier port USB qu'il trouve. Comme il n'y a pas encore d'échanges, on ne sait pas si çà va fonctionner. Ca permet peut être juste d'allouer le port (histoire de vérifier qu'il n'est pas déjà utilisé par un autre process ou d'éviter qu'il puisse être utilisé par...).
Vous pourriez vous connecter au port USB au lancement du programme et vous déconnecter (éventuellement) en sortie.
Fonctionnellement, çà ne changerait pas grand chose.
De plus cela permettrait de simplifier grandement le code à écrire côté threads dans ce cas.
Pour l'instant, le thread devrait se terminer avec le programme grâce à la fonctionnalité .daemon = True.
Si vous vouliez le terminer "proprement" sans cela, il faudrait hacker un peu ou effectuer des lectures avec timeout pour pouvoir tester régulièrement un "flag" qui signale la demande de sortie du thread.
Ce qui me gène ici, c'est que vous me parlez des trames expédiées alors que je vous demande à quoi ressemblent les trames à recevoir/lire... Peut être ont-elles le même format? mais çà serait mieux de le dire.
- W
Comme je travaille sur plusieurs cartes à la fois. Cela me permet de déconnecté tout en gardant le soft ouvert et tester d'autres bidouilles. Je sais, le même soft pour tout faire ? Non ! C'est juste que c'est plus commode pour moi.
L'intérêt est non seulement de contrôler réellement à la main, mais aussi de jouer avec les accesseurs. Mes boutons de commandes sont inactifs tant que la connexion n'est pas assurée.
Au démarrage de mon programme que se passerait-il si j'oublie de connecter le XBee sur l'USB ? Certes "joli message", mais ça resterait en auto donc obliger de relancer mon programme !! Bof, je n'aime pas !
Oui pour la simplification. Mais non, comme j'ai mis au-dessus c'est volontaire.
C'est ce que j'avais compris. Sauf que justement j'aimerais gérer mon tread depuis le callback prévus à cet effet. Idem pour le bouton quit qui pourra tuer le thread avant de fermer la fenêtre et de détruire root.
D'apparence, c'est le même format. Mais cela peut beaucoup varier. Exemple, une équipe autre part dans le monde développe un autre équipement. Sa trame est différente. Moi, j'autorise toute trame tant que mes trames aient au moins un caractère de départ et de fin différent, que les séparateurs sont des virgules et que le machin au milieu soit des caractères ascii.
Si je pilote un bras robotique à distance. Je vais envoyer des choses comme "*,3,5,100,!" et sa réponse peut très bien être "*,position,100,Ok,!" ou encore "*,ok,!"... Etc... Si je demande l'état de mes capteurs je peux avoir en retour "*,us,10.9,gauche,true,droite,false,!"
On peut aussi avoir un tableau de valeur en retour. On est bien d'accord que dans un premier temps je ne cherche pas à striper les données inutiles tel que les "," ni les caractères de trames. Je cherche juste à coder propre la base avant de faire toute la partie usante de tkinter.
Enfin, en dernier lieu, et ce bien malgré moi, je remarque quelques difficultés à gérer python2 et python3 dans le même projet. Personnellement, j'aimerais rester sous python 3. J'ai de la demande en python2.. grrr ! Bref, on avance en python3 et les autres se débrouillerons pour passer en python2 !
Pour l'heure, mon programme avance lentement vers ceci :
J'ai pour le moment laisser tel que ce que nous avions fait. J'espère demain et ce week-end passer à la suite et pourquoi pas finir cette partie récup de base.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 # -- IMPORTATIONS import sys import serial import threading #En fonction de la version python installé if sys.version_info[0] == 2: import Tkinter as tk else: import tkinter as tk # -- CLASSE Interface graphique class IHM(tk.Frame): #Initialisation def __init__(self, parent): #Variables self.parent = parent self.connexion = COM(parent) #Les frames tk.Frame.__init__(self, self.parent) self.boutons = tk.LabelFrame(self, text="Contoles", padx=20, pady=20) self.logs = tk.LabelFrame(self, text="Logs", padx=20, pady=20) #Images self.myImgAV = tk.PhotoImage(file="ressources/icones/av.gif") self.myImgCO = tk.PhotoImage(file="ressources/icones/co.gif") self.myImgDECO = tk.PhotoImage(file="ressources/icones/deco.gif") #Boutons self.btAV = tk.Button(self.boutons, image=self.myImgAV, bg = "grey") self.btCO = tk.Button(self.boutons, image=self.myImgCO, bg = "green", command=self.callback_connexion) self.btDECO = tk.Button(self.boutons, image=self.myImgDECO, bg = "green", command=self.callback_deconnexion) #Textes self.textLogs = tk.Text(self.logs, width=50, height=20, wrap=tk.WORD) #Position des boutons self.boutons.grid(column=0, row=0, sticky='NS') self.btCO.grid(column=0, row=0) self.btDECO.grid(column=1, row=0) self.btAV.grid(column=2, row=1) #Position du log self.logs.grid(column=0, row=1, sticky='NS') self.textLogs.grid(column=0, row=0) #Afficher des informations def setLog(self, informations): self.textLogs.insert(0.0, informations) #Callback : Connexion def callback_connexion(self): self.connexion.serialConnexion() self.setLog(self.connexion.getEtatConnexion()) self.setLog("\n" + self.connexion.getInformationsUser()) self.connexion.resetInformation() #Callback : Deconnexion def callback_deconnexion(self): self.connexion.serialDeconnexion() self.setLog(self.connexion.getEtatConnexion()) self.setLog("\n" + self.connexion.getInformationsUser()) self.connexion.resetInformation() # --CLASSE rover class ROVER(): #Initialisation def __init__(self, parent): #Variables self.parent = parent """ Ici on place toutes les fonctions que feront le rover -> Admet des infos de l'IHM <- Retourne des datas à envoyer sur le port série """ # -- CLASSE Communication class COM(): #Initialisation def __init__(self, parent): #Variables self.parent = parent self.locations=['/dev/ttyUSB0', '/dev/ttyUSB1', '/dev/ttyUSB2', '/dev/ttyUSB3', '/dev/ttyS0', '/dev/ttyS1', '/dev/ttyS2', '/dev/ttyS3'] self.ser = '' self.is_connected = False self.information = "" #Connexion Serie def serialConnexion(self): #Tentative de connexion au XBee Usb for device in self.locations: try: self.information += "Tentative de connexion sur le port" + device + "...\n" self.ser = serial.Serial(device, 9600) self.information += "Connexion sur sur le port" + device + " [Ok]\n" self.is_connected = True break except: self.information += "Connexion échoué sur " + device + "! [Fail]\n" self.is_connected = False #Deconnexion série def serialDeconnexion(self): #Test si le port à été ouvert if self.is_connected: #Ferme le port self.ser.close() self.is_connected = False self.information += "Deconnexion [Ok]\n" else: self.information += "La connexion n'a jamais été faite !\n" #Reset le message def resetInformation(self): self.information = "" #Etat de la connexion def getEtatConnexion(self): return self.is_connected #Informations utilisateur def getInformationsUser(self): return self.information # -------------------------------------------------------------------------------------------------------------- # -- FONCTIONS #Fonction qui fermera l'application et qui va killer les threads def fermetureApplication(): if tk.messagebox.askokcancel("Fermeture du programme", "Voulez-vous réelement fermer le programme POSL Rover ?"): root.destroy() #Fonction qui va scruter le port série def dump_serial(port): while True: c = port.read(1) sys.stdout.write(c) # -- MAIN root = tk.Tk() ihm = IHM(root) ihm.grid(column=0, row=0, sticky='NS') port = ihm.connexion.ser task = threading.Thread(target=dump_serial, args=(port,)) task.deamon = True task.start() root.protocol("WM_DELETE_WINDOW", fermetureApplication) root.title('POSL Rover') #Titre de l'application root.mainloop() #Boucler
Dès que c'est Ok, je lance une première sauvegarde de cette mouture avant de rajouter tous les contrôles. Et il y en as un certain nombre si tu as eu l'occasion de voir ce qui avait été fait dans mon lien donné plus haut.
Petite info. C'est purement prototype ce que j'ai fait dans ce projet. On a le droit de tester, refaire, modifier. C'est même le but ! Alors n'hésitons pas codons proprement et pas à pas afin de faire quelque-chose de solide et de très Python attitude
Après de mûres réflexions, j'ai décidé de faire le portage en C++ et de laisser de côté Python pour le moment.
Quoi qu'il en est, c'est fort agréable de se mesurer à ce type de programmation. On peut y faire déjà pas mal de choses.
Je ne ferme pas totalement l'idée du python. Ce qui a déjà été développé reste sur le git.
Merci beaucoup.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager