Support Forum

Share your projects and post your questions

Register   or   Sign In
The Forum

Errno24 too many open files

2576 Views - Created 05/04/2019

05/04/2019

Posted by:
supernono

supernono Avatar

hello

i'm trying to convert un old fish tank controler program that run on Pcduino (but this one death recently) for running now on raspberry pi 3b+ with expander pi board and library

i use QT Designer 4.8.7 for made the gui and the program is in PyQt4 / Python 2.7 and Geany 1.29

a small part of the program is for logging 5 analog value (1 sample per minutes /1440 samples for a day) and plot it with pyqtgraph

the program read the 5 analog each minutes and refresh the graph

after about 1012 loop i get this error :


Traceback (most recent call last):
  
  File "graphMain.py", line 127, in refreshPlot

  File "/usr/local/lib/python2.7/dist-packages/ExpanderPi/ExpanderPi.py", line 107, in __init__

IOError: [Errno 24] Too many open files


the program :


#!/usr/bin/python
# -*- coding: utf-8 -*-

# par A. VILLOIN - nov 2012 - Tous droits réservés


# modules a importer 
from PyQt4.QtGui import *
from PyQt4.QtCore import *  # inclut QTimer..
import os,sys,time,ConfigParser

import numpy as np
import pyqtgraph as pg

#from pyduino_pcduino import *
import ExpanderPi

from graph import * # fichier obtenu à partir QtDesigner et pyuic4



# +/- variables et objets globaux 

class myApp(QWidget, Ui_Form): # la classe reçoit le Qwidget principal ET la classe définie dans test.py obtenu avec pyuic4
	def __init__(self, parent=None):
		QWidget.__init__(self) # initialise le Qwidget principal 
		self.setupUi(parent) # Obligatoire 
		
		
		# --- Variables de classe
		self.points=None # déclaration initiale
		self.compt=0 # variable comptage
		self.nombreValeurs=1440
		#self.framerate=10 # nombre d'image par secondes (rafraîchissement de l'affichage)
		
		# --- Code actif initial  --- 
		
		#-- initialise le graphique pyqtgraph -- 
		# l'objet self.graph correspond au plotWidget créé dans QtDesigner
		
		# aspect fond /axes
		#self.graph.hideAxis('left') # masque axes - ‘left’, ‘bottom’, ‘right’, or ‘top’                
		self.graph.setBackgroundBrush(QBrush(QColor(191,191,191))) # la classe PlotWidget est un GraphicsWidget qui est un QGraphics View
		self.graph.showGrid(x=True, y=True)  # affiche la grille 
		self.graph.getAxis('bottom').setPen(pg.mkPen(0,0,255)) # couleur de l'axe + grille 
		self.graph.getAxis('left').setPen(pg.mkPen(255,0,0)) # couleur de l'axe + grille 
		self.graph.getAxis('right').setPen(pg.mkPen(255,0,0)) # couleur de l'axe + grille 
		
		# légende des axes 
		labelStyle = {'color': '#00F', 'font-size': '10pt'} # propriétés CSS à utiliser pour le label
		self.graph.getAxis('bottom').setLabel('Temps', units='minutes', **labelStyle) # label de l'axe
		#self.graph.getAxis('left').setLabel('Temperature  Ph', units='C ', **labelStyle) # label de l'axe
		#self.graph.getAxis('right').setLabel('Conductivite Redox', units='units', **labelStyle) # label de l'axe
		
		# adaptation échelle axes
		# axe X et Y sont autoscale par défaut
		self.graph.enableAutoRange(axis=pg.ViewBox.XAxis, enable=False) # fonction plotItem : désactive autoscale X 
		self.graph.enableAutoRange(axis=pg.ViewBox.YAxis, enable=False) # fonction plotItem : désactive autoscale Y 
		
		
		self.minX=-5
		self.maxX=1450 #self.nombreValeurs
		self.graph.setXRange(self.minX,self.maxX,0,update=True) # fonction plotItem : fixe échelle des X
		
		self.minY=-5
		self.maxY=1000
		self.graph.setYRange(self.minY,self.maxY) # fonction plotItem : fixe échelle des Y
		
		
		# interactivité
		#self.graph.setInteractive(True) # fonction QGraphics View : pour inactiver interaction souris
		self.graph.getViewBox().setMouseMode(pg.ViewBox.RectMode)  # fonction ViewBox pas accessible depuis PlotWidget : fixe selection par zone
		self.graph.setMouseEnabled(x=False, y=False) # désactive interactivité axe X
		
		#-- initialise données -- 
		#-- définition des x 
		self.x = np.arange(0.0, self.nombreValeurs+1, 1.0) # crée un vecteur de n valeurs à intervalle régulier pour les x
		#print (self.x) # debug - affiche les valeurs x
		
		#-- calcul des y : 
		#-- courbe 1 y=f(x)
		self.y1=np.zeros(self.nombreValeurs+1)# crée un tableau de valeur y basé sur x - courbe y=sin(x)
		#print (self.y1) # debug - affiche les valeurs y
		#-- affichage de la courbe -- 
		self.courbe1=self.graph.plot(self.x,self.y1, pen=(255,0,0)) # avec couleur
		
		#-- courbe 2 y=f(x)
		self.y2=np.zeros(self.nombreValeurs+1)# crée un tableau de valeur y basé sur x - courbe y=sin(x)
		#print (self.y2) # debug - affiche les valeurs y
		#-- affichage de la courbe -- 
		self.courbe2=self.graph.plot(self.x,self.y2, pen=(179,2,255)) # avec couleur
		
		#-- courbe 3 y=f(x)
		self.y3=np.zeros(self.nombreValeurs+1)# crée un tableau de valeur y basé sur x - courbe y=sin(x)
		#print (self.y3) # debug - affiche les valeurs y
		#-- affichage de la courbe -- 
		self.courbe3=self.graph.plot(self.x,self.y3, pen=(0,0,255)) # avec couleur
		
		#-- courbe 4 y=f(x)
		self.y4=np.zeros(self.nombreValeurs+1)# crée un tableau de valeur y basé sur x - courbe y=sin(x)
		#print (self.y4) # debug - affiche les valeurs y
		#-- affichage de la courbe -- 
		self.courbe4=self.graph.plot(self.x,self.y4, pen=(0,255,0)) # avec couleur
		
		#-- courbe 5 y=f(x)
		self.y5=np.zeros(self.nombreValeurs+1)# crée un tableau de valeur y basé sur x - courbe y=sin(x)
		#print (self.y4) # debug - affiche les valeurs y
		#-- affichage de la courbe -- 
		self.courbe5=self.graph.plot(self.x,self.y5, pen=(255,255,0)) # avec couleur
		
		
		adc = ExpanderPi.ADC() 
		adc.set_adc_refvoltage(4.096)
		
		 # -- Activation d'un Timer pour MAJ graphique - fixe le fps d'affichage en fait --
		self.timerRefreshPlot=QTimer() # déclare un timer Qt
		self.connect(self.timerRefreshPlot, SIGNAL("timeout()"), self.refreshPlot) # connecte le signal timeOut de l'objet timer à l'appel de la fonction voulue 
		#self.timerRefreshPlot.start(int(1000/self.framerate)) # lance le timer - mettre délai assez court pour fps élevé
		self.timerRefreshPlot.start(int(50)) # in normal run 60000 for 1 read per minutes h24/7
		
		#----- fonction de gestion du signal timeout du QTimer
	def refreshPlot(self): # fonction appelée lors de la survenue d'un évènement Timer - nom fonction indiférrent 
		
		print ("")
		print ("MAJ graph : \n"), # debug 
		
		adc = ExpanderPi.ADC() 
		
		value1=(adc.read_adc_raw(1, 0))
		value2=(adc.read_adc_raw(2, 0))
		value3=(adc.read_adc_raw(3, 0))
		value4=(adc.read_adc_raw(4, 0))
		value5=(adc.read_adc_raw(5, 0))
		
		print self.compt
		print value1
		print value2 
		print value3 
		print value4 
		print value5
		
		if self.compt==0: # premier passage 
			self.points= np.array([[self.compt,value1,value2,value3,value4,value5]]) # tableau à 2 dimensions - ici 1er points
			self.x =self.points[:,0] # colonne 1 = x
			self.y1=self.points[:,1] # colonne 2 = y1
			self.y2=self.points[:,2] # colonne 3 = y2
			self.y3=self.points[:,3] # colonne 4 = y3
			self.y4=self.points[:,4] # colonne 5 = y4
			self.y5=self.points[:,5] # colonne 6 = y5
			self.compt=self.compt+1 # incrémente compt
			
		elif self.compt<=self.nombreValeurs: # on remplit le tableau de point une première fois
			newY1=value1
			newY2=value2
			newY3=value3
			newY4=value4
			newY5=value5
			
			self.points=np.append(self.points,[[self.compt,newY1,newY2,newY3,newY4,newY5]],axis=0)# ajouter un point au tableau 
			self.x =self.points[:,0] # colonne 1 = x
			self.y1=self.points[:,1] # colonne 2 = y1
			self.y2=self.points[:,2] # colonne 3 = y2
			self.y3=self.points[:,3] # colonne 4 = y3
			self.y4=self.points[:,4] # colonne 5 = y4
			self.y5=self.points[:,5] # colonne 6 = y5
			self.compt=self.compt+1 # incrémente compt
		else:
			self.y1=np.roll(self.y1,-1) # décale les éléments y1 de 1 - fonction numpy - les x ne bougent pas.. 
			self.y2=np.roll(self.y2,-1) # décale les éléments y2 de 1 - fonction numpy - les x ne bougent pas..  
			self.y3=np.roll(self.y3,-1) # décale les éléments y3 de 1 - fonction numpy - les x ne bougent pas..  
			self.y4=np.roll(self.y4,-1) # décale les éléments y4 de 1 - fonction numpy - les x ne bougent pas..  
			self.y5=np.roll(self.y5,-1) # décale les éléments y5 de 1 - fonction numpy - les x ne bougent pas.. 
			
			self.y1[self.nombreValeurs]=value1 # nouvelle valeur en dernière position
			self.y2[self.nombreValeurs]=value2 # nouvelle valeur en dernière position
			self.y3[self.nombreValeurs]=value3 # nouvelle valeur en dernière position
			self.y4[self.nombreValeurs]=value4 # nouvelle valeur en dernière position
			self.y5[self.nombreValeurs]=value5 # nouvelle valeur en dernière position
			
		self.courbe1.setData(self.x,self.y1) # initialisation valeurs courbe 1
		self.courbe2.setData(self.x,self.y2) # initialisation valeurs courbe 2
		self.courbe3.setData(self.x,self.y3) # initialisation valeurs courbe 3
		self.courbe4.setData(self.x,self.y4) # initialisation valeurs courbe 4
		self.courbe5.setData(self.x,self.y5) # initialisation valeurs courbe 5
		
		
def main(args):
	a=QApplication(args) # crée l'objet application 
	f=QWidget() # crée le QWidget racine
	c=myApp(f) # appelle la classe contenant le code de l'application 
	f.show() # affiche la fenêtre QWidget
	r=a.exec_() # lance l'exécution de l'application 
	return r

if __name__=="__main__": # pour rendre le code exécutable 
	main(sys.argv) # appelle la fonction main


this part of program runned very well on Pcduino without error

i'm newbee on raspberry pi but the software used are the same (PyQt4 and Python 2.7)

i tried all the example in the expander pi library package and all work nice

i dont understand this error can you help me ?

regards

05/04/2019

Posted by:
andrew

andrew Avatar

Location:
United Kingdom

andrew Twitter  andrew Website  

Hello

The problem could be that you are creating a new instance of the ExpanderPi.ADC() object every time the refreshPlot function is called which would open a new connection to the SPI bus. After 1012 loops the Raspberry Pi would run out of available connections to the SPI bus which causes it to crash.

Try moving the adc object out of the functions and into the top of the class and then reference it from within the functions using self.adc. This will allow the code to run with only one SPI connection open on the Raspberry Pi and should stop it from crashing.

The code below contains the modifications that you should need to make to your program.


#!/usr/bin/python
# -*- coding: utf-8 -*-

# par A. VILLOIN - nov 2012 - Tous droits réservés


# modules a importer 
from PyQt4.QtGui import *
from PyQt4.QtCore import *  # inclut QTimer..
import os,sys,time,ConfigParser

import numpy as np
import pyqtgraph as pg

#from pyduino_pcduino import *
import ExpanderPi

from graph import * # fichier obtenu à partir QtDesigner et pyuic4



# +/- variables et objets globaux 

class myApp(QWidget, Ui_Form): # la classe reçoit le Qwidget principal ET la classe définie dans test.py obtenu avec pyuic4

	adc = None

	def __init__(self, parent=None):
		QWidget.__init__(self) # initialise le Qwidget principal 
		self.setupUi(parent) # Obligatoire 
		
		
		# --- Variables de classe
		self.points=None # déclaration initiale
		self.compt=0 # variable comptage
		self.nombreValeurs=1440
		#self.framerate=10 # nombre d'image par secondes (rafraîchissement de l'affichage)
		
		# --- Code actif initial  --- 
		
		#-- initialise le graphique pyqtgraph -- 
		# l'objet self.graph correspond au plotWidget créé dans QtDesigner
		
		# aspect fond /axes
		#self.graph.hideAxis('left') # masque axes - ‘left’, ‘bottom’, ‘right’, or ‘top’                
		self.graph.setBackgroundBrush(QBrush(QColor(191,191,191))) # la classe PlotWidget est un GraphicsWidget qui est un QGraphics View
		self.graph.showGrid(x=True, y=True)  # affiche la grille 
		self.graph.getAxis('bottom').setPen(pg.mkPen(0,0,255)) # couleur de l'axe + grille 
		self.graph.getAxis('left').setPen(pg.mkPen(255,0,0)) # couleur de l'axe + grille 
		self.graph.getAxis('right').setPen(pg.mkPen(255,0,0)) # couleur de l'axe + grille 
		
		# légende des axes 
		labelStyle = {'color': '#00F', 'font-size': '10pt'} # propriétés CSS à utiliser pour le label
		self.graph.getAxis('bottom').setLabel('Temps', units='minutes', **labelStyle) # label de l'axe
		#self.graph.getAxis('left').setLabel('Temperature  Ph', units='C ', **labelStyle) # label de l'axe
		#self.graph.getAxis('right').setLabel('Conductivite Redox', units='units', **labelStyle) # label de l'axe
		
		# adaptation échelle axes
		# axe X et Y sont autoscale par défaut
		self.graph.enableAutoRange(axis=pg.ViewBox.XAxis, enable=False) # fonction plotItem : désactive autoscale X 
		self.graph.enableAutoRange(axis=pg.ViewBox.YAxis, enable=False) # fonction plotItem : désactive autoscale Y 
		
		
		self.minX=-5
		self.maxX=1450 #self.nombreValeurs
		self.graph.setXRange(self.minX,self.maxX,0,update=True) # fonction plotItem : fixe échelle des X
		
		self.minY=-5
		self.maxY=1000
		self.graph.setYRange(self.minY,self.maxY) # fonction plotItem : fixe échelle des Y
		
		
		# interactivité
		#self.graph.setInteractive(True) # fonction QGraphics View : pour inactiver interaction souris
		self.graph.getViewBox().setMouseMode(pg.ViewBox.RectMode)  # fonction ViewBox pas accessible depuis PlotWidget : fixe selection par zone
		self.graph.setMouseEnabled(x=False, y=False) # désactive interactivité axe X
		
		#-- initialise données -- 
		#-- définition des x 
		self.x = np.arange(0.0, self.nombreValeurs+1, 1.0) # crée un vecteur de n valeurs à intervalle régulier pour les x
		#print (self.x) # debug - affiche les valeurs x
		
		#-- calcul des y : 
		#-- courbe 1 y=f(x)
		self.y1=np.zeros(self.nombreValeurs+1)# crée un tableau de valeur y basé sur x - courbe y=sin(x)
		#print (self.y1) # debug - affiche les valeurs y
		#-- affichage de la courbe -- 
		self.courbe1=self.graph.plot(self.x,self.y1, pen=(255,0,0)) # avec couleur
		
		#-- courbe 2 y=f(x)
		self.y2=np.zeros(self.nombreValeurs+1)# crée un tableau de valeur y basé sur x - courbe y=sin(x)
		#print (self.y2) # debug - affiche les valeurs y
		#-- affichage de la courbe -- 
		self.courbe2=self.graph.plot(self.x,self.y2, pen=(179,2,255)) # avec couleur
		
		#-- courbe 3 y=f(x)
		self.y3=np.zeros(self.nombreValeurs+1)# crée un tableau de valeur y basé sur x - courbe y=sin(x)
		#print (self.y3) # debug - affiche les valeurs y
		#-- affichage de la courbe -- 
		self.courbe3=self.graph.plot(self.x,self.y3, pen=(0,0,255)) # avec couleur
		
		#-- courbe 4 y=f(x)
		self.y4=np.zeros(self.nombreValeurs+1)# crée un tableau de valeur y basé sur x - courbe y=sin(x)
		#print (self.y4) # debug - affiche les valeurs y
		#-- affichage de la courbe -- 
		self.courbe4=self.graph.plot(self.x,self.y4, pen=(0,255,0)) # avec couleur
		
		#-- courbe 5 y=f(x)
		self.y5=np.zeros(self.nombreValeurs+1)# crée un tableau de valeur y basé sur x - courbe y=sin(x)
		#print (self.y4) # debug - affiche les valeurs y
		#-- affichage de la courbe -- 
		self.courbe5=self.graph.plot(self.x,self.y5, pen=(255,255,0)) # avec couleur
		
		
		self.adc = ExpanderPi.ADC() 
		self.adc.set_adc_refvoltage(4.096)
		
		 # -- Activation d'un Timer pour MAJ graphique - fixe le fps d'affichage en fait --
		self.timerRefreshPlot=QTimer() # déclare un timer Qt
		self.connect(self.timerRefreshPlot, SIGNAL("timeout()"), self.refreshPlot) # connecte le signal timeOut de l'objet timer à l'appel de la fonction voulue 
		#self.timerRefreshPlot.start(int(1000/self.framerate)) # lance le timer - mettre délai assez court pour fps élevé
		self.timerRefreshPlot.start(int(50)) # in normal run 60000 for 1 read per minutes h24/7
		
		#----- fonction de gestion du signal timeout du QTimer
	def refreshPlot(self): # fonction appelée lors de la survenue d'un évènement Timer - nom fonction indiférrent 
		
		print ("")
		print ("MAJ graph : \n"), # debug 
		
		value1=(self.adc.read_adc_raw(1, 0))
		value2=(self.adc.read_adc_raw(2, 0))
		value3=(self.adc.read_adc_raw(3, 0))
		value4=(self.adc.read_adc_raw(4, 0))
		value5=(self.adc.read_adc_raw(5, 0))
		
		print self.compt
		print value1
		print value2 
		print value3 
		print value4 
		print value5
		
		if self.compt==0: # premier passage 
			self.points= np.array([[self.compt,value1,value2,value3,value4,value5]]) # tableau à 2 dimensions - ici 1er points
			self.x =self.points[:,0] # colonne 1 = x
			self.y1=self.points[:,1] # colonne 2 = y1
			self.y2=self.points[:,2] # colonne 3 = y2
			self.y3=self.points[:,3] # colonne 4 = y3
			self.y4=self.points[:,4] # colonne 5 = y4
			self.y5=self.points[:,5] # colonne 6 = y5
			self.compt=self.compt+1 # incrémente compt
			
		elif self.compt<=self.nombreValeurs: # on remplit le tableau de point une première fois
			newY1=value1
			newY2=value2
			newY3=value3
			newY4=value4
			newY5=value5
			
			self.points=np.append(self.points,[[self.compt,newY1,newY2,newY3,newY4,newY5]],axis=0)# ajouter un point au tableau 
			self.x =self.points[:,0] # colonne 1 = x
			self.y1=self.points[:,1] # colonne 2 = y1
			self.y2=self.points[:,2] # colonne 3 = y2
			self.y3=self.points[:,3] # colonne 4 = y3
			self.y4=self.points[:,4] # colonne 5 = y4
			self.y5=self.points[:,5] # colonne 6 = y5
			self.compt=self.compt+1 # incrémente compt
		else:
			self.y1=np.roll(self.y1,-1) # décale les éléments y1 de 1 - fonction numpy - les x ne bougent pas.. 
			self.y2=np.roll(self.y2,-1) # décale les éléments y2 de 1 - fonction numpy - les x ne bougent pas..  
			self.y3=np.roll(self.y3,-1) # décale les éléments y3 de 1 - fonction numpy - les x ne bougent pas..  
			self.y4=np.roll(self.y4,-1) # décale les éléments y4 de 1 - fonction numpy - les x ne bougent pas..  
			self.y5=np.roll(self.y5,-1) # décale les éléments y5 de 1 - fonction numpy - les x ne bougent pas.. 
			
			self.y1[self.nombreValeurs]=value1 # nouvelle valeur en dernière position
			self.y2[self.nombreValeurs]=value2 # nouvelle valeur en dernière position
			self.y3[self.nombreValeurs]=value3 # nouvelle valeur en dernière position
			self.y4[self.nombreValeurs]=value4 # nouvelle valeur en dernière position
			self.y5[self.nombreValeurs]=value5 # nouvelle valeur en dernière position
			
		self.courbe1.setData(self.x,self.y1) # initialisation valeurs courbe 1
		self.courbe2.setData(self.x,self.y2) # initialisation valeurs courbe 2
		self.courbe3.setData(self.x,self.y3) # initialisation valeurs courbe 3
		self.courbe4.setData(self.x,self.y4) # initialisation valeurs courbe 4
		self.courbe5.setData(self.x,self.y5) # initialisation valeurs courbe 5
		
		
def main(args):
	a=QApplication(args) # crée l'objet application 
	f=QWidget() # crée le QWidget racine
	c=myApp(f) # appelle la classe contenant le code de l'application 
	f.show() # affiche la fenêtre QWidget
	r=a.exec_() # lance l'exécution de l'application 
	return r

if __name__=="__main__": # pour rendre le code exécutable 
	main(sys.argv) # appelle la fonction main

05/04/2019

Posted by:
supernono

supernono Avatar

thank you very much andrew for your help

you "save" me

regards

Sign in to post your reply

Note: documents in Portable Document Format (PDF) require Adobe Acrobat Reader 5.0 or higher to view.
Download Adobe Acrobat Reader or other PDF reading software for your computer or mobile device.