lcdnumber signal and slot - pyqt4

I have put together (with lots of researching questions from this site, thank you) some code which will, in part, display raspberry pi input pin voltages on qlcdnumber widgets in my qt creator gui. The code runs perfectly, the gui pops up, and the pin voltage prints to the terminal (temporary) and the buttons are functional in the gui, turning other pins high and low. I don't get any errors, but the issue is that the signal won't display on the gui lcd. I have researched all I can to no success and I feel as though I'm guessing at it now. I would appreciate any input and instruction. I've learned a lot but still have far to go so any help would be great. I am using Raspbian and Qt4/Qt Creator 3.2.1
Here is the entire code and once again thank you for any instruction:
import sys
import RPi.GPIO as GPIO
import time
import re
from PyQt4 import QtGui, uic, QtCore
import spidev
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
o2zero = 26
o2span = 19
cozero = 13
cospan = 6
co2zero = 5
co2span = 21
status = "nil"
o2_channel = 0
o2_temp_channel = 1
spi = spidev.SpiDev()
spi.open(0,0)
class MyWindow(QtGui.QMainWindow):
def __init__(self):
super(MyWindow, self).__init__()
uic.loadUi('mainwindow.ui', self)
self.o2_zero_up.clicked.connect(self.o2zeroup)
self.o2_zero_down.clicked.connect(self.o2zerodown)
self.o2_span_up.clicked.connect(self.o2spanup)
self.o2_span_down.clicked.connect(self.o2spandown)
self.co_zero_up.clicked.connect(self.cozeroup)
self.co_zero_down.clicked.connect(self.cozerodown)
self.co_span_up.clicked.connect(self.cospanup)
self.co_span_down.clicked.connect(self.cospandown)
self.co2_zero_up.clicked.connect(self.co2zeroup)
self.co2_zero_down.clicked.connect( self.co2zerodown)
self.co2_span_up.clicked.connect(self.co2spanup)
self.co2_span_down.clicked.connect(self.co2spandown)
self.close_button.clicked.connect(self.gpiocleanup)
self.thread = O2_Channel()
self.thread.o2_concentration.connect(self.onChangeValue)
self.thread.start()
self.show()
def onChangeValue(self, values):
o2_volts = values
def o2zeroup(self):
GPIO.setup(o2zero, GPIO.OUT)
GPIO.output(o2zero, 1)
def o2zerodown(self):
GPIO.setup(o2zero, GPIO.OUT)
GPIO.output(o2zero, 0)
def o2spanup(self):
GPIO.setup(o2span, GPIO.OUT)
GPIO.output(o2span, 1)
def o2spandown(self):
GPIO.setup(o2span, GPIO.OUT)
GPIO.output(o2span, 0)
def cozeroup(self):
GPIO.setup(cozero, GPIO.OUT)
GPIO.output(cozero, 1)
def cozerodown(self):
GPIO.setup(cozero, GPIO.OUT)
GPIO.output(cozero, 0)
def cospanup(self):
GPIO.setup(cospan, GPIO.OUT)
GPIO.output(cospan, 1)
def cospandown(self):
GPIO.setup(cospan, GPIO.OUT)
GPIO.output(cospan, 0)
def co2zeroup(self):
GPIO.setup(co2zero, GPIO.OUT)
GPIO.output(co2zero, 1)
def co2zerodown(self):
GPIO.setup(co2zero, GPIO.OUT)
GPIO.output(co2zero, 0)
def co2spanup(self):
GPIO.setup(co2span, GPIO.OUT)
GPIO.output(co2span, 1)
def co2spandown(self):
GPIO.setup(co2span, GPIO.OUT)
GPIO.output(co2span, 0)
def gpiocleanup(self):
GPIO.cleanup()
def closeEvent(self, event):
self.thread.stop()
self.thread.quit()
self.thread.wait()
self.thread.deleteLater()
print ("GPIO CleanUP")
GPIO.cleanup()
event.accept()
def ReadChannel(channel):
adc = spi.xfer2([1,(8+channel)<<4,0])
data = ((adc[1]&3) << 8) + adc[2]
return data
def ConvertVolts(data, places):
volts = (data * 3.3) / float(1023)
volts = round(volts,places)
return volts
class O2_Channel(QtCore.QThread):
o2_concentration = QtCore.pyqtSignal(int)
def __init__(self):
QtCore.QThread.__init__(self)
self.mRunning = True
def run(self):
while self.mRunning:
o2_level = ReadChannel(o2_channel)
o2_volts = ConvertVolts(o2_level,2)
print("{}".format(o2_volts))
self.o2_concentration.emit(o2_volts)
delay = .2
time.sleep(delay)
def stop(self):
self.mRunning = False
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = MyWindow()
sys.exit(app.exec_())

In a different post, eyllanesc set me up with the signal and slot I needed to display the signal to my gui lcd but I didn't understand it well enough to know just what he did. I've spent the last few days reading about this and finally see just what he did. Everything works and works just like I want it to.
For anyone who might have the same confusion I had, here was my main problem:
def onChangeValue(self, values):
o2_volts = values
I am so new at this that I didn't realize I needed to actually put my specified value in place of the word "values" in the above code. A little embarrassing but part of learning I guess. The other problem was here:
o2_concentration = QtCore.pyqtSignal(int)
I didn't realize it but after I fixed the "values", the lcd was working but was reading 0 and I assumed it wasn't working. Using a photocell to get voltage, I was getting .25 when printing to the terminal but 0 to the lcd. Again being new I didn't think about (int) not being correct for what I wanted. Changing it to (float) fixed the problem. Everything works great.
The my script has grown since the original post but if anyone would like to see it I would be happy to post it.
This is a wonderful site. Thank for everything.

Related

Python Serial "ClearCommError failed (OSError(9, 'The handle is invalid.', None, 6))

I am new to python and multiprocessing (Electronics background). I am writing an GUI application to communicate with micro controller over serial port. The interaction with user is through some buttons on the GUI, which sends some command on serial port to the MCU and displays data received from MCU in the same GUI(there can be data from MCU without any command being sent). I am using PyQt5 module and QT designer to design the UI. I converted the UI to py code using uic.compileUi. I am then calling this python file in my main code.
After reading through several documents and stack overflow posts I decided to use to QThreads for the application.
I am however facing issue with serial communication when being used inside thread (It works fine if used in a single main loop without threads).
My code is:
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication,QWidget,QMainWindow #
from PyQt5.QtCore import QCoreApplication, QObject, pyqtSignal, pyqtSlot, QThread
import serial
from GUI import Ui_MainGUIWindow
import sys
serialString = ""
def ClosePort():
serialPort.close()
# print("port closed")
def OpenPort():
serialPort.open()
#print("port open")
def sendFV():
serialPort.write('fv\r'.encode())
def configSerial(port,baudRate):
global serialPort
serialPort=serial.Serial(port = port, baudrate=baudRate, bytesize=8, timeout=None, stopbits=serial.STOPBITS_ONE)
if not serialPort.isOpen():
serialPort.open()
class Worker(QObject):
finished = pyqtSignal()
dataReady = pyqtSignal(['QString'])#[int], ['Qstring']
print("workerinit")
def run(self):
print ("worker run")
while(1):
if(serialPort.in_waiting > 0):
serialString = serialPort.read()
self.dataReady.emit(str(serialString))
self.finished.emit()
class GUI(QWidget):
def __init__(self):
self.obj = Worker()
self.thread = QThread()
self.obj.dataReady.connect(self.onDataReady)
self.obj.moveToThread(self.thread)
self.obj.finished.connect(self.thread.quit)
self.thread.started.connect(self.obj.run)
self.thread.finished.connect(app.exit)
self.thread.start()
self.initUI()
def initUI(self):
#Form, Window = uic.loadUiType("TestGUI.ui")
#print(Form,Window)
#self.window = Window()
#self.form=Form()
self.window = QMainWindow()
self.form = Ui_MainGUIWindow()
self.form.setupUi(self.window)
self.form.FVButton.clicked.connect(sendFV)
print("guiinit")
self.window.show()
def onDataReady(self, serialString):
print("here")
print(serialString.decode('Ascii'))
self.form.plainTextOutput.insertPlainText((serialString.decode('Ascii')))
self.form.plainTextOutput.ensureCursorVisible()
if __name__ == '__main__':
configSerial("COM20",9600)
"""
app = QCoreApplication.instance()
if app is None:
app = QCoreApplication(sys.argv)
"""
app = QApplication(sys.argv)
form=GUI()
app.exec_()
sys.exit(ClosePort())
I get following error on line if(serialPort.in_waiting > 0):
File "C:\Users\...\Anaconda3\lib\site-packages\serial\serialwin32.py", line 259, in in_waiting
raise SerialException("ClearCommError failed ({!r})".format(ctypes.WinError()))
SerialException: ClearCommError failed (OSError(9, 'The handle is invalid.', None, 6))
I found this post talking about similar issue, but do know how exactly to implement the suggested solution in my code.
Also I get "kernel died" error multiple times when I run the code on spyder IDE. I added a check if I am creating multiple instances of QT application but that did not help.Running the code from anaconda command prompt works fine.

Rotary encoder value looking sticky after using tkinter function " root.after"

I am quite new to python and tkinter ,I am working on a project where i give demand to slave device through rotary encoder value and reading feedback value from slave devices through communication.
I face issue when i use root.after () function .
Any suggestion regarding proper use of root.after () function so that my interrupt routine not affected welcome heartly.
Thank you.
Here is my code.
import pigpio
import tkinter as tk
from PIL import ImageTk,Image
import time
from RPi import GPIO
import serial
i="*00T%"
j="*01T%"
s=serial.Serial(port='/dev/ttyS0',
baudrate=9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1)
class decoder: # class for decoding rotary encoder
def __init__(self, pi, gpioA, gpioB, callback):
----------
---------------
----------------
if __name__ == "__main__":
import RPi.GPIO as GPIO
import time
import pigpio
import tkinter as tk
import board
import busio
rpm=0
tor=0
pow=0
pi = pigpio.pi()
st=1
pos=0
def callback(way): # interrupt event sense on pin no 17,18
global pos
global st
if st ==1:
pos += way
if pos >= 9999:
pos=9999
if pos <= 0:
pos=0
var.set(pos)
print("pos={}".format(pos))
def rpm_update():
global rpm
s.write(str.encode(i))
print(i)
time.sleep(0.2)
if s.inWaiting():
rpm=s.readline(s.inWaiting())
rpm=rpm.decode('utf-8',errors='ignore')
rpm=rpm[5:-1]
print(rpm)
var2.set(rpm)
def tor_update():
global tor
s.write(str.encode(j))
print(j)
time.sleep(0.2)
if s.inWaiting():
tor=s.readline(s.inWaiting())
tor=tor.decode('utf-8',errors='ignore')
tor=tor[4:-1]
print(tor)
var3.set(tor)
def pow_update():
global rpm,tor,pow
try:
rpm=float(rpm)
tor=float(tor)
except ValueError:
pass
pow=int(rpm*tor/5252)
var4.set(pow)
def update():
rpm_update()
time.sleep(0.5)
tor_update()
time.sleep(0.5)
pow_update()
root.after(1000,update)
path="/home/pi/logo.png"
root=tk.Tk()
img=ImageTk.PhotoImage(Image.open(path))
panel=tk.Label(root,image=img)
panel.pack()
panel.place(x=195,y=10,height=50,width=80)
root.title("Dynalec")
root.geometry("500x600")
{
body of tkinter screen
}
decoder=decoder(pi, 17, 18, callback)
root.after(1000,update)
root.mainloop()
everything is working fine before root.after() function " root.after(1000,update)
but i need it because i have to read slave values in every sec and update in gui screen.
Adding as a answer because long for comments, will remove soon.
Try this out:
def update():
root.after(500,rpm_update)
root.after(500,tor_update)
root.after(500,pow_update)
root.after(1000,update)
Do let me know.

RaspberryPi Stopwatch (TKinter) with Trigger

i would like to build a stopwatch for my carrera track which i built a little bit bigger.
So I have bought a Raspberry Pi 3 with an additional 7 "touch screen and the individual modules for triggering.
Everything works fine individually.
Now I found a great stopwatch on the net which I also used. Works really great.
In another script, that I've written by myself, the triggering with the gpios works also fantastic.
Now I want to combine both and fail.
Does anyone have an idea or suggested solution where my mistake is?
Here is my code
#!/usr/bin/python
import tkinter as tk
import RPi.GPIO as GPIO
import time
GPIO_TRIGGER_PIN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_TRIGGER_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setwarnings(False)
def update_timeText():
if (state):
global timer
timer[2] += 1
if (timer[2] >= 100):
timer[2] = 0
timer[1] += 1
if (timer[1] >= 60):
timer[0] += 1
timer[1] = 0
timeString = pattern.format(timer[0], timer[1], timer[2])
timeText.configure(text=timeString)
root.after(10, update_timeText)
def start():
global state
state = True
print('Pressed Start')
def stop():
global state
state = False
print('Pressed Stop')
def reset():
global timer
timer = [0, 0, 0]
timeText.configure(text='00:00:00')
print('Pressed Reset')
while GPIO.input(GPIO_TRIGGER_PIN) == True:
if GPIO.input(GPIO_TRIGGER_PIN):
print('CAR DETECTED')
time.sleep(0.1)
state = False
# BULDING TKinter GUI
root = tk.Tk()
root.wm_title('Stopwatch')
timer = [0, 0, 0]
pattern = '{0:02d}:{1:02d}:{2:02d}'
timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 150))
timeText.pack()
startButton = tk.Button(root, text='Start', command=start)
startButton.pack()
stopButton = tk.Button(root, text='Stop', command=stop)
stopButton.pack()
resetButton = tk.Button(root, text='Reset', command=reset)
resetButton.pack()
update_timeText()
root.mainloop()
Currently I get the trigger in the console as output "CAR DETECTED". However, I do not get the TKinter panel.
If I remove
while GPIO.input(GPIO_TRIGGER_PIN) == True:
if GPIO.input(GPIO_TRIGGER_PIN):
print('CAR DETECTED')
time.sleep(0.1)
then the display appears and works. Without triggering.
If I put it all down, I get also the panel but it also triggers nothing more.
Any ideas ?
Thanks for help
Not really my area of expertise, but since nobody else answered, I'll give it a shot.
I think you want to use GPIO.add_event_callback()* to add a callback that gets called when an event happens.
# Callback function
def on_trigger(channel_number):
# Just update the flag
global state
state = False
# Set the callback
GPIO.add_event_callback(GPIO_TRIGGER_PIN , callback=on_trigger)
Then, delete the while loop.
*According to the docs, you need the darksidesync library to use this function. Instead of the callback, you could also create a separate thread. Personally, I would prefer the callback.
from threading import Thread
def thread_function(arg):
global state
# Listen for state change
while GPIO.input(GPIO_TRIGGER_PIN) == True:
if GPIO.input(GPIO_TRIGGER_PIN):
# Update var
state = False
print('CAR DETECTED')
time.sleep(0.1)
thread = Thread(target = thread_function)
thread.start()
Hope this helps.

Updating progress bar in Tkinter simultaneously while recording audio Python3

My goal for this simple program is to be able to show a progress bar of time the mic has been recording(range from 0 - 30 seconds). I am using the Tkinter library, Python 3.6, and PyAudio to record.
I finished writing the code for the individual parts(recording + updating progress bar) but I don't know how to change the code so that they happen at the same time(not one after the other). Also, I've realized that while I am recording, the GUI freezes(I can't click or resize buttons), I am also wondering about how to fix this issue. After doing some more research, I have a feeling that the answer lies with multi-threading or root.update() but I am not sure.
I am looking for a code example of recording audio while I simultaneously update the progress bar.
Here is an example:
from tkinter import *
from tkinter import ttk
import tkinter as tk
import pyaudio
import numpy as np
np.random.seed(123) # for reproducibility
import matplotlib
matplotlib.use('Agg') # No pictures displayed
class Test_GUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
root = self
label_title = Label(root, text="Progress Bar Recording Sample")
label_title.pack(fil="x")
topFrame = Frame(root)
topFrame.pack(side=TOP)
self.recordButton = Button(topFrame, text="Record", command=self.start)
self.recordButton.pack(side=LEFT)
self.progress = ttk.Progressbar(topFrame, orient="horizontal",
length=200, mode="determinate")
self.min = 0
self.maxMin = 0
self.progress.pack(side=RIGHT)
# recording attributes.
self.CHUNK = 1024
self.FORMAT = pyaudio.paInt16
self.CHANNELS = 2
self.RATE = 44100
self.RECORD_SECONDS = 15
self.WAVE_OUTPUT_FILENAME = "/Users/Sree/Desktop/PythonPrograms/audio_output_test.wav"
def start(self):
print("here")
self.progress["value"] = 0
self.maxMin = 30
self.progress["maximum"] = 30
'''
I need the following 2 lines to happen at the same time
the progress bar needs to update from 1-30 seconds(which is the time I am recording)
'''
self.record()
self.update_progress() #The progress bar is from 0 sec to 30 sec indicating what percentage of the time the mic has been recording for.
def update_progress(self):
self.min += 0.1
self.progress["value"] = self.min
if self.min < self.maxMin:
# update after 100 ms
self.after(100, self.update_progress)
def record(self):
p = pyaudio.PyAudio()
stream = p.open(format=self.FORMAT,
channels=self.CHANNELS,
rate=self.RATE,
input=True,
frames_per_buffer=self.CHUNK)
print("* recording")
frames = []
for i in range(0, int(self.RATE / self.CHUNK * self.RECORD_SECONDS)):
data = stream.read(self.CHUNK)
frames.append(data)
print("* done recording")
stream.stop_stream()
stream.close()
p.terminate()
wf = wave.open(self.WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(self.CHANNELS)
wf.setsampwidth(p.get_sample_size(self.FORMAT))
wf.setframerate(self.RATE)
wf.writeframes(b''.join(frames))
wf.close()
app = Test_GUI()
app.mainloop()
To prevent the GUI from freezing while recording, you need to launch the recording in a separate thread. To do so, you can use the threading module for instance and replace self.record() in your start method by:
record_thread = threading.Thread(target=self.record, daemon=True)
record_thread.start()

Python 3.6; PyQt5; arch linux; interrupted by signal 6: SIGABRT

Intro
I encountered a problem while trying to learn PyQt5.
So far in my search for an answer and understanding to the problem i have come up mostly empty handed. A lot of links and posts i find does not apply to python or even Qt5 at all, which is not strange because SIGABRT applies to several fronts of memory allocation etc. (Correct me if I'm wrong).
I'm fairly certain that the error stems from the lines such as and similar to
buttonEnv.clicked.connect(lambda: self.btnClicked(buttonEnv))
But have not been able to locate or figure out what it is. Probably because of my lack of knowledge coming to python.
System
-OS: Arch linux (Manjaro) 4.9.27-1-MANJARO
-IDE: Pycharm 2017.1
-Python version: 3.6
-Using: PyQt5
Error I'm getting
/usr/bin/python3.6 /opt/pycharm-community/helpers/pydev/pydevd.py
--multiproc --qt-support --client 127.0.0.1 --port 42749 --file /home/alpeace/Documents/git_reps/project-tardis/main.py pydev debugger:
process 22588 is connecting
Connected to pydev debugger (build 171.4249.47)
Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
My code
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication, QGridLayout,\
QBoxLayout, QPushButton, QWidget, QSizePolicy
from PyQt5.QtGui import QIcon
class HomeScreen(QWidget):
clickedBtn = ''
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.clickedBtn = ''
homeBtnLayout = QGridLayout()
self.setLayout(homeBtnLayout)
buttonEnv = QPushButton('Environment')
buttonEnv.clicked.connect(lambda: self.btnClicked(buttonEnv))
buttonEnv.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred)
buttonMedia = QPushButton('Media')
buttonMedia.clicked.connect(lambda: self.btnClicked(buttonMedia))
buttonMedia.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred)
buttonInv = QPushButton('Inventory')
buttonInv.clicked.connect(lambda: self.btnClicked(buttonInv))
buttonInv.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred)
buttonSched = QPushButton('Schedual')
buttonSched.clicked.connect(lambda: self.btnClicked(buttonSched))
buttonSched.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred)
homeBtnLayout.addWidget(buttonEnv, 0, 0)
homeBtnLayout.addWidget(buttonMedia, 0, 1)
homeBtnLayout.addWidget(buttonInv, 1, 0)
homeBtnLayout.addWidget(buttonSched, 1, 1)
self.move(300, 150)
self.show()
def btnClicked(self, btnName):
self.clickedBtn = btnName.text()
btnName.disconnect()
def getClickedBtn(self):
return self.clickedBtn
class MainWindow(QMainWindow):
screenHome = HomeScreen()
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 250)
self.setWindowTitle('Home')
self.screenHome = HomeScreen()
self.setCentralWidget(self.screenHome)
self.show()
def changeWindow(self):
newWindow = self.screenHome.getClickedBtn()
if newWindow == 'Environment':
print(newWindow)
elif newWindow == 'Media':
print(newWindow)
elif newWindow == 'Inventory':
print(newWindow)
elif newWindow == 'Schedual':
print(newWindow)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainWindow()
sys.exit(app.exec_())
Anyways, thanks for reading and i hope someone might be able to help me with this. If more information is needed i will gladly provide it, but as far as I know this should be sufficient.
The problem is you're doing this on class level:
class MainWindow(QMainWindow):
screenHome = HomeScreen()
This means you're trying to create a HomeScreen at the very beginning, even before your main-block is running.
Since you're assigning self.screenHome properly later anyways:
def initUI(self):
# [...]
self.screenHome = HomeScreen()
you can simply get rid of the class level one.
By the way, the faulthandler module is useful in tracking things like this down - when putting an import faulthandler; faulthandler.enable() at the top, Python tells you on what line something happened - in this case it pointed to HomeScreen.__init__ so I've only had to figure out where a HomeScreen object is created before QApplication.

Resources