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.

Port série sous Linux

 

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.pngAttention : 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 !) :

c67ab3ba9b56073038c451f57b61c6c3_f812.png

 

 

 

Installation

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 :

d6930b4269892cb2427e287fbe2ef45f_f797.png

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

lancement.png

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

 

Utilisation

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

Un exemple d'utilisation :

Elc_Centrad_Al991S_Linux_r.png

Le code source

#!/usr/bin/python
#-*- coding: iso-8859-15 -*-
from __future__ import division
from gi.repository import Gtk, GObject
import os, sys
import serial
import string
from time import sleep
import glob

class AL991S:
	def __init__(self):

		self.builder = Gtk.Builder()
		self.builder.add_from_file("AL991S.glade")

		#recuperation des widgets utilises par le programme :
		self.lbA = self.builder.get_object("lbA")
		self.sbA = self.builder.get_object("sbA")
		self.btA = self.builder.get_object("btA")
		self.lbB = self.builder.get_object("lbB")
		self.sbB = self.builder.get_object("sbB")
		self.btB = self.builder.get_object("btB")
		self.lbC = self.builder.get_object("lbC")
		self.sbC = self.builder.get_object("sbC")
		self.btC = self.builder.get_object("btC")
		self.btOuvrir = self.builder.get_object("btOuvrir")
		self.btFermer = self.builder.get_object("btFermer")
		self.btQuitter = self.builder.get_object("btQuitter")
		self.btRafraichir = self.builder.get_object("btRafraichir")
		self.comboPort = self.builder.get_object("comboPort")
		self.textAide = self.builder.get_object("textAide")
		self.textAPropos = self.builder.get_object("textAPropos")

		self.buffer_aide = self.textAide.get_buffer()
		fichier_aide = open("Aide.txt", "r")
		if fichier_aide:
			texte_aide = fichier_aide.read()
			fichier_aide.close()
			self.buffer_aide.set_text(texte_aide)

		self.buffer_apropos = self.textAPropos.get_buffer()
		fichier_apropos = open("A_propos.txt", "r")
		if fichier_apropos:
			texte_apropos = fichier_apropos.read()
			fichier_apropos.close()
			self.buffer_apropos.set_text(texte_apropos)


		self.lb_etat = self.builder.get_object("lb_etat")
		self.lb_etat.set_text("Connexion non établie")
		self.builder.connect_signals(self)




		window = self.builder.get_object('window')
		window.show_all()

		self.lister_ports()

		#initialisations :
		self.sortie =""
		self.port_serie = " "
		self.port_choisi = " "
		self.data_format = " "
		self.debit = 9600
		self.parite = ""

		adjA = Gtk.Adjustment(0, 0, 15, 0.1, 0.1, 0)
		self.sbA.configure(adjA, 1,1)
		adjB = Gtk.Adjustment(2, 2, 5.5, 0.1, 0.1,0 )
		self.sbB.configure(adjB, 1,1)
		adjC = Gtk.Adjustment(0, -15, 15, 0.1, 0.1,0)
		self.sbC.configure(adjC, 1,1)

		self.btA.set_sensitive(False)
		self.btB.set_sensitive(False)
		self.btC.set_sensitive(False)
		self.btFermer.set_sensitive(False)
		self.btQuitter.set_sensitive(False)

	def lister_ports(self) :
		  list_port =  glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyS*')
		  i = 0
		  while i < len(list_port):
			self.comboPort.append_text(list_port[i])
			i=i+1

	def lecture(self) :
		sleep(0.2)
		chaine = ""
		data = []
		n_data = self.port_serie.inWaiting()
		if n_data > 0 :
			for i in range (n_data) :
				data.append(ord(self.port_serie.read(1)))
				chaine += chr(data[i])
			index = chaine.find('\r\n>')
			if index == -1 :
				self.lecture_voies()
			else :
				self.sortie = chaine[index - 3] + str(int(chaine[index -2 : index],16)/10)
		return self.sortie

	def lecture_voies(self) :
		try :
			#lecture de chacune des 3 voies et affichage :
			self.port_serie.write('A?' + '\r' )
			self.lecture()
			self.lbA.set_text(self.sortie)

			self.port_serie.write('B?' + '\r' )
			self.lecture()
			self.lbB.set_text(self.sortie)

			self.port_serie.write('C?' + '\r' )
			self.lecture()
			self.lbC.set_text(self.sortie)
			return True
		except :
			self.lbA.set_text('xx.x')
			self.lbB.set_text('xx.x')
			self.lbC.set_text('xx.x')
			return False
		sleep(0.2)
		self.lecture_voies()

	def on_btA_clicked(self,widget):

		chaine = str(hex(int(str(self.sbA.get_value()).replace('.',''))).replace('0x','')).zfill(2)
		self.port_serie.write('A+' + chaine + '\r' )
		self.lecture_voies()

	def on_btB_clicked(self,widget):

		chaine = str(hex(int(str(self.sbB.get_value()).replace('.',''))).replace('0x','')).zfill(2)
		self.port_serie.write('B+' + chaine + '\r' )
		self.lecture_voies()

	def on_btC_clicked(self,widget):
		reglage = int(10*self.sbC.get_value())

		if reglage < 0 :
			chaine = str(hex(int(str(self.sbC.get_value()).replace('.',''))).replace('0x','')).zfill(3)
			self.port_serie.write('C' + chaine + '\r' )
		else :
			chaine = str(hex(int(str(self.sbC.get_value()).replace('.',''))).replace('0x','')).zfill(2)
			self.port_serie.write('C+' + chaine + '\r' )
		self.lecture_voies()

	def on_btRafraichir_clicked(self,widget):
		#Rafraichir la liste des ports série disponibles
		self.comboPort.remove_all()
		self.lister_ports()

	def on_btOuvrir_clicked(self,widget):
		#ouverture du port série choisi:
		# recuperation des parametres choisis :
		self.port_choisi = self.comboPort.get_active_text()
		debit = 9600
		data_format = serial.EIGHTBITS
		stop = serial.STOPBITS_ONE
		parite = serial.PARITY_NONE

		try:
			# desactivation de widgets (ceux qui ne doivent pas
			# etre modifies une fois le port serie ouvert) :
			self.comboPort.set_sensitive(False)
			self.btRafraichir.set_sensitive(False)
			self.btQuitter.set_sensitive(True)

			#ouverture du port serie :
			self.port_serie = serial.Serial(
				port=self.port_choisi,
				baudrate = debit,
				bytesize = data_format,
				parity = parite,
				stopbits = stop,
				timeout=2
			)

			#activation/desactivation de widgets :
			self.btFermer.set_sensitive(True)
			self.btOuvrir.set_sensitive(False)
			self.btA.set_sensitive(True)
			self.btB.set_sensitive(True)
			self.btC.set_sensitive(True)

			#vidage du port et tentative de contact avec l'alim :
			self.port_serie.flushInput()
			self.port_serie.write('R?' + '\r' )
			#petit délai avant de lire le retour :
			sleep(0.2)
			data = []
			char_ascii = []
			n_data = 0
			n_data = self.port_serie.inWaiting()
			if n_data > 0 :
				chaine = ""
				for i in range (n_data) :
					data.append(ord(self.port_serie.read(1)))

					chaine += chr(data[i])
				index = chaine.find('AL991', 0,len(chaine))
				self.lb_etat.set_text("Etat : connecté sur " + chaine[index : index + 10])
				GObject.timeout_add(1000, self.lecture_voies)
			else:
				self.lb_etat.set_text("L'alimentation est-elle allumée ?")

		except :
			self.comboPort.set_sensitive(True)
			self.btOuvrir.set_sensitive(True)
			self.btRafraichir.set_sensitive(True)

			#self.bt_fermer.set_sensitive(False)
			self.ouvert = False
			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"
			dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msg)
			# Montre le dialog
			dialog.run()
			# Destruction du dialog
			dialog.destroy()

	def on_btFermer_clicked(self,widget):
		#fermeture du port série ouvert
		try :
			if self.port_serie.isOpen() == True:
				self.port_serie.close()
				self.comboPort.set_sensitive(True)
				self.btOuvrir.set_sensitive(True)
				self.btRafraichir.set_sensitive(True)
				self.btFermer.set_sensitive(False)
				self.btA.set_sensitive(False)
				self.btB.set_sensitive(False)
				self.btC.set_sensitive(False)
				self.lb_etat.set_text("Etat : déconnecté")
				self.lbA.set_text('xx.x')
				self.lbB.set_text('xx.x')
				self.lbC.set_text('xx.x')

		except :
			msgFermer = "Erreur lors de la fermeture du port série !"
			dlgFermer = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msgFermer)
			dlgFermer.run()
			dlgFermer.destroy()

	def on_btQuitter_clicked(self,widget):
		Gtk.main_quit()

	def destroy(window, self):
		Gtk.main_quit()

def main():
	app = AL991S()
	Gtk.main()

if __name__ == "__main__":
	sys.exit(main())

 katuberling.png Sur cette page :

- un logiciel libre écrit en Python (avec le listing source fourni) : AL991S.zip

- Connaissances Linux apportées :

  •  commandes : ls, groups, usermod
  •  fichier : etc/group 
  •     communication série (python-serial)