Pilotage d'une alimentation ELC - Centrad AL991S

Cette alimentation est décrite sur ce site ici.

Elle est livrée avec un logiciel de pilotage sous Windows. Les utilisateurs de Linux ayant été oubliés, on a réalisé un logiciel de communication dont voici l'interface utilisateur :

Elc_Centrad_Al991S_Linux_r.png

Le logiciel permet de visualiser simultanément la tension disponible sur chacune des sorties de l'alimentation.

On peut régler individuellement chacune des tensions de sortie en cliquant sur le bouton "Valider" correspondant. On peut ainsi prérégler une valeur de tension et ne l'appliquer qu'au moment opportun. (Exemple : appliquer un échelon de tension).

Le logiciel ne bloque pas les réglages sur l'alimentation : un changement de tension réalisé directement sur l'alimentation sera répercuté sur l'afficheur du logiciel.

Le logiciel accepte les ports série standards de même que les convertisseurs USB-Série indispensables sur les ordinateurs portables actuels.

Dépendance :

Pour fonctionner, le logiciel nécessite l'installation d'un module python de communication série (python-serial) : dans le Gestionnaire de paquets, vérifier sa présence ; l'installer si nécessaire (ici c'est la version 2.5-2.1 qui est installée) :

python-serial.png

status_unknown.png  Attention : Linux étant un système sécurisé, vous n'avez peut-être pas les droits pour accéder en tant qu'utlisateur aux ports série.

Ouvrir un Terminal et entrer la commande :

ls -l /dev/ttyS*

Voici un exemple de retour :

droits_tty.png

Pour des convertisseurs USB-série, taper la commande :

ls -l /dev/ttyU* 

Voici un retour pour deux câbles USB-série (le grand luxe !) :

droits_ttyUsb.png

On voit qu'il faut appartenir au groupe "dialout" pour accéder en tant qu'utilisateur à ces différents ports série.

Pour savoir à quels groupes on appartient, entrer dans un terminal la commande :

groups

Un exemple de retour (réalisé sur une distribution Debian toute neuve dans une VirtualBox) :

groups.png

On voit que l'utilisateur "vincent" n'appartient pas au group "dialout"

 

Appartenir au groupe "dialout" :

Pour que cet utilisateur "vincent" puisse appartenir au groupe "dialout", entrer les commandes suivantes dans un Terminal :

su     ( il faudra ensuite entrer son mot de passe administrateur)

usermod -a -G dialout vincent  (remplacer bien sûr l'utilisateur "vincent" par le vôtre !)


(Rque : sur une distribution SuSE Linux, la commande à entrer est légèrement différente :

usermode -A dialout vincent           )...

Voici l'ensemble de la séquence (à remarquer : la commande groups réitérée après usermod ne montre pas l'appartenance de l'utilisateur "vincent" au groupe "dialout". Il faudra faire un redémarrage pour que cela soit pris en compte :

usermod_avant_redemarage.png

Après redémarrage :

usermod_apres_reem.png

 

Remarque : l'ensemble des groupes disponibles se trouve dans le fichier etc/group. On aurait pu le lire avec gedit par exemple, voire même le modifier directement (en mode superutilisateur ... mais attention à ne pas faire d'erreurs !) :

 dialout0.png

Installation :

1- Télécharger l'archive. Deux versions sont proposées :

    - l'une écrite pour GTK2 (cette version ne sera plus maintenue) : AL991S_GTK2.zip

    - l'autre pour GTK3 (c'est la version décrite sur ces pages) : AL991S.zip

2- Copier puis extraire l'archive téléchargée dans le dossier de son choix. On trouvera les fichiers suivants :

fichiers.png

Le fichier AL991S.glade contient la description de l'interface utilisateur. Il est appelé par le fichier AL991S.py. Celui-ci contient toute la logique de fonctionnement du programme. L'icône reload.png provient de la série d'icônes Crystal-Clear.

3- Autoriser, par un clic droit, l'utilisation comme exécutable du fichier AL991S.py :

autorisation.png

4- Faire un double clic sur le fichier AL991S.py :

lancement.png

... et cliquer sur le bouton "Lancer".

Utilisation :

Au lancement du programme, on choisira le port série sur lequel est connectée l'alimentation. On pourra éventuellement utiliser le bouton "Rafraîchir" (par exemple lorsque l'on a lancé le logiciel avant de connecter un câble USB-RS232) :

choix_port.png

La ligne d'état située en bas indique l'état de connexion avec d'éventuelles erreurs, comme ci-dessous, l'alimentation qui n'est pas allumée :

defaut.png

Conception :

L'interface utilisateur a été réalisée avec le logiciel de conception d'interface Glade (version 3.12) :

glade_0.png

Pour les plus curieux, où ceux qui souhaiteraient améliorer à leur convenance ce logiciel, voici le code source en Python (version 2.7):

  1. #!/usr/bin/python
  2. #-*- coding: iso-8859-15 -*-
  3. from __future__ import division
  4. from gi.repository import Gtk, GObject
  5. import os, sys
  6. import serial
  7. import string
  8. from time import sleep
  9. import glob
  10.  
  11. class AL991S:
  12. def __init__(self):
  13.  
  14. self.builder = Gtk.Builder()
  15. self.builder.add_from_file("AL991S.glade")
  16.  
  17. #recuperation des widgets utilises par le programme :
  18. self.lbA = self.builder.get_object("lbA")
  19. self.sbA = self.builder.get_object("sbA")
  20. self.btA = self.builder.get_object("btA")
  21. self.lbB = self.builder.get_object("lbB")
  22. self.sbB = self.builder.get_object("sbB")
  23. self.btB = self.builder.get_object("btB")
  24. self.lbC = self.builder.get_object("lbC")
  25. self.sbC = self.builder.get_object("sbC")
  26. self.btC = self.builder.get_object("btC")
  27. self.btOuvrir = self.builder.get_object("btOuvrir")
  28. self.btFermer = self.builder.get_object("btFermer")
  29. self.btQuitter = self.builder.get_object("btQuitter")
  30. self.btRafraichir = self.builder.get_object("btRafraichir")
  31. self.comboPort = self.builder.get_object("comboPort")
  32. self.textAide = self.builder.get_object("textAide")
  33. self.textAPropos = self.builder.get_object("textAPropos")
  34.  
  35. self.buffer_aide = self.textAide.get_buffer()
  36. fichier_aide = open("Aide.txt", "r")
  37. if fichier_aide:
  38. texte_aide = fichier_aide.read()
  39. fichier_aide.close()
  40. self.buffer_aide.set_text(texte_aide)
  41.  
  42. self.buffer_apropos = self.textAPropos.get_buffer()
  43. fichier_apropos = open("A_propos.txt", "r")
  44. if fichier_apropos:
  45. texte_apropos = fichier_apropos.read()
  46. fichier_apropos.close()
  47. self.buffer_apropos.set_text(texte_apropos)
  48.  
  49.  
  50. self.lb_etat = self.builder.get_object("lb_etat")
  51. self.lb_etat.set_text("Connexion non établie")
  52. self.builder.connect_signals(self)
  53.  
  54.  
  55.  
  56.  
  57. window = self.builder.get_object('window')
  58. window.show_all()
  59.  
  60. self.lister_ports()
  61.  
  62. #initialisations :
  63. self.sortie =""
  64. self.port_serie = " "
  65. self.port_choisi = " "
  66. self.data_format = " "
  67. self.debit = 9600
  68. self.parite = ""
  69.  
  70. adjA = Gtk.Adjustment(0, 0, 15, 0.1, 0.1, 0)
  71. self.sbA.configure(adjA, 1,1)
  72. adjB = Gtk.Adjustment(2, 2, 5.5, 0.1, 0.1,0 )
  73. self.sbB.configure(adjB, 1,1)
  74. adjC = Gtk.Adjustment(0, -15, 15, 0.1, 0.1,0)
  75. self.sbC.configure(adjC, 1,1)
  76.  
  77. self.btA.set_sensitive(False)
  78. self.btB.set_sensitive(False)
  79. self.btC.set_sensitive(False)
  80. self.btFermer.set_sensitive(False)
  81. self.btQuitter.set_sensitive(False)
  82.  
  83. def lister_ports(self) :
  84. list_port = glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyS*')
  85. i = 0
  86. while i < len(list_port):
  87. self.comboPort.append_text(list_port[i])
  88. i=i+1
  89.  
  90. def lecture(self) :
  91. sleep(0.2)
  92. chaine = ""
  93. data = []
  94. n_data = self.port_serie.inWaiting()
  95. if n_data > 0 :
  96. for i in range (n_data) :
  97. data.append(ord(self.port_serie.read(1)))
  98. chaine += chr(data[i])
  99. index = chaine.find('\r\n>')
  100. if index == -1 :
  101. self.lecture_voies()
  102. else :
  103. self.sortie = chaine[index - 3] + str(int(chaine[index -2 : index],16)/10)
  104. return self.sortie
  105.  
  106. def lecture_voies(self) :
  107. try :
  108. #lecture de chacune des 3 voies et affichage :
  109. self.port_serie.write('A?' + '\r' )
  110. self.lecture()
  111. self.lbA.set_text(self.sortie)
  112.  
  113. self.port_serie.write('B?' + '\r' )
  114. self.lecture()
  115. self.lbB.set_text(self.sortie)
  116.  
  117. self.port_serie.write('C?' + '\r' )
  118. self.lecture()
  119. self.lbC.set_text(self.sortie)
  120. return True
  121. except :
  122. self.lbA.set_text('xx.x')
  123. self.lbB.set_text('xx.x')
  124. self.lbC.set_text('xx.x')
  125. return False
  126. sleep(0.2)
  127. self.lecture_voies()
  128.  
  129. def on_btA_clicked(self,widget):
  130.  
  131. chaine = str(hex(int(str(self.sbA.get_value()).replace('.',''))).replace('0x','')).zfill(2)
  132. self.port_serie.write('A+' + chaine + '\r' )
  133. self.lecture_voies()
  134.  
  135. def on_btB_clicked(self,widget):
  136.  
  137. chaine = str(hex(int(str(self.sbB.get_value()).replace('.',''))).replace('0x','')).zfill(2)
  138. self.port_serie.write('B+' + chaine + '\r' )
  139. self.lecture_voies()
  140.  
  141. def on_btC_clicked(self,widget):
  142. reglage = int(10*self.sbC.get_value())
  143.  
  144. if reglage < 0 :
  145. chaine = str(hex(int(str(self.sbC.get_value()).replace('.',''))).replace('0x','')).zfill(3)
  146. self.port_serie.write('C' + chaine + '\r' )
  147. else :
  148. chaine = str(hex(int(str(self.sbC.get_value()).replace('.',''))).replace('0x','')).zfill(2)
  149. self.port_serie.write('C+' + chaine + '\r' )
  150. self.lecture_voies()
  151.  
  152. def on_btRafraichir_clicked(self,widget):
  153. #Rafraichir la liste des ports série disponibles
  154. self.comboPort.remove_all()
  155. self.lister_ports()
  156.  
  157. def on_btOuvrir_clicked(self,widget):
  158. #ouverture du port série choisi:
  159. # recuperation des parametres choisis :
  160. self.port_choisi = self.comboPort.get_active_text()
  161. debit = 9600
  162. data_format = serial.EIGHTBITS
  163. stop = serial.STOPBITS_ONE
  164. parite = serial.PARITY_NONE
  165.  
  166. try:
  167. # desactivation de widgets (ceux qui ne doivent pas
  168. # etre modifies une fois le port serie ouvert) :
  169. self.comboPort.set_sensitive(False)
  170. self.btRafraichir.set_sensitive(False)
  171. self.btQuitter.set_sensitive(True)
  172.  
  173. #ouverture du port serie :
  174. self.port_serie = serial.Serial(
  175. port=self.port_choisi,
  176. baudrate = debit,
  177. bytesize = data_format,
  178. parity = parite,
  179. stopbits = stop,
  180. timeout=2
  181. )
  182.  
  183. #activation/desactivation de widgets :
  184. self.btFermer.set_sensitive(True)
  185. self.btOuvrir.set_sensitive(False)
  186. self.btA.set_sensitive(True)
  187. self.btB.set_sensitive(True)
  188. self.btC.set_sensitive(True)
  189.  
  190. #vidage du port et tentative de contact avec l'alim :
  191. self.port_serie.flushInput()
  192. self.port_serie.write('R?' + '\r' )
  193. #petit délai avant de lire le retour :
  194. sleep(0.2)
  195. data = []
  196. char_ascii = []
  197. n_data = 0
  198. n_data = self.port_serie.inWaiting()
  199. if n_data > 0 :
  200. chaine = ""
  201. for i in range (n_data) :
  202. data.append(ord(self.port_serie.read(1)))
  203.  
  204. chaine += chr(data[i])
  205. index = chaine.find('AL991', 0,len(chaine))
  206. self.lb_etat.set_text("Etat : connecté sur " + chaine[index : index + 10])
  207. GObject.timeout_add(1000, self.lecture_voies)
  208. else:
  209. self.lb_etat.set_text("L'alimentation est-elle allumée ?")
  210.  
  211. except :
  212. self.comboPort.set_sensitive(True)
  213. self.btOuvrir.set_sensitive(True)
  214. self.btRafraichir.set_sensitive(True)
  215.  
  216. #self.bt_fermer.set_sensitive(False)
  217. self.ouvert = False
  218. msg = "Erreur lors de l'ouverture du port série : ce port n'est peut-être pas valide, ou bien vous n'avez pas les droits pour accéder aux ports série"
  219. dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msg)
  220. # Montre le dialog
  221. dialog.run()
  222. # Destruction du dialog
  223. dialog.destroy()
  224.  
  225. def on_btFermer_clicked(self,widget):
  226. #fermeture du port série ouvert
  227. try :
  228. if self.port_serie.isOpen() == True:
  229. self.port_serie.close()
  230. self.comboPort.set_sensitive(True)
  231. self.btOuvrir.set_sensitive(True)
  232. self.btRafraichir.set_sensitive(True)
  233. self.btFermer.set_sensitive(False)
  234. self.btA.set_sensitive(False)
  235. self.btB.set_sensitive(False)
  236. self.btC.set_sensitive(False)
  237. self.lb_etat.set_text("Etat : déconnecté")
  238. self.lbA.set_text('xx.x')
  239. self.lbB.set_text('xx.x')
  240. self.lbC.set_text('xx.x')
  241.  
  242. except :
  243. msgFermer = "Erreur lors de la fermeture du port série !"
  244. dlgFermer = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msgFermer)
  245. dlgFermer.run()
  246. dlgFermer.destroy()
  247.  
  248. def on_btQuitter_clicked(self,widget):
  249. Gtk.main_quit()
  250.  
  251. def destroy(window, self):
  252. Gtk.main_quit()
  253.  
  254. def main():
  255. app = AL991S()
  256. Gtk.main()
  257.  
  258. if __name__ == "__main__":
  259. sys.exit(main())

La version GTK2 en action sur une distribution OpenSuSE (12.1) :

suse.png

This site uses cookies. Some of the cookies we use are essential for parts of the site to operate and have already been set. You may delete and block all cookies from this site, but parts of the site will not work.