I program an app witgh QT interface to read modbus data, I display data on GUI create with PyQT5.
When I launch program, it crash after few second, I haven't message error. I used debugger and nothing wrong thing, program just close.
This is a part of my code where is my problem, I'll explain after
def displayModbus(self):
modbusReturn = modbus.readModbus()
commStatus = modbusReturn[0]
if commStatus:
listRegValue = modbusReturn[1]
#Display data to ui
if str(listRegValue[1]) == "1": #HEATING_ST
self.ui.lnHeatingStatus.setText("On")
else:
self.ui.lnHeatingStatus.setText("Off")
# self.ui..setText(str(listRegValue[2])) #WAIT_TIME_CHG
# self.ui..setText(str(listRegValue[3])) #RUN_TIME_CHG
if str(listRegValue[4]) == "1": #ON_WAIT_TIME_P
self.ui.ledWaitTime.setStyleSheet("QPushButton {background-color:green;}")
else:
self.ui.ledWaitTime.setStyleSheet("QPushButton {background-color:red;}")
if str(listRegValue[5]) == "1": #RUN_CYCLE
self.ui.lnRunCycle.setText("On")
else:
self.ui.lnRunCycle.setText("Off")
# self.ui..setText(str(listRegValue[6])) #LEVEL_RESET
# self.ui..setText(str(listRegValue[7])) #CYL_MAN_CYCLE
# self.ui..setText(str(listRegValue[8])) #CYL_EMPTY
# self.ui..setText(str(listRegValue[9])) #CYL_EMPTY_END
# self.ui..setText(str(listRegValue[10])) #NORASYSTEM_MANUAL
# self.ui..setText(str(listRegValue[11])) #NORASYSTEM_ON
# self.ui..setText(str(listRegValue[12])) #HEATING_ALLOW
if str(listRegValue[13]) == "1": #LOW_AIRFLOW
self.ui.lnLowAirflow.setText("Low")
else:
self.ui.lnLowAirflow.setText("Normal")
# self.ui..setText(str(listRegValue[15])) #HUM_ALLOW
TC1 = listRegValue[16] / 100
self.ui.lnTC1.setText(str(TC1)+" °C") #TC1
TC2 = listRegValue[17] / 100
self.ui.lnTC2.setText(str(TC2)+" °C") #TC2
TC3 = listRegValue[18] / 100
self.ui.lnTC3.setText(str(TC3)+" °C") #TC3
TC4 = listRegValue[19] / 100
self.ui.lnTC4.setText(str(TC4)+" °C") #TC4
self.ui.lnH1.setText(str(listRegValue[20])+" %RH") #HUM1
waitTime = str(listRegValue[22] / 3600)
self.ui.lnWaitTime.setText(str(waitTime+" hr")) #WAIT_TIME_D
runTime = str(listRegValue[23] / 60)
self.ui.lnRunTime.setText(str(runTime+" min")) #RUN_TIME_D
timeRemainM = str(int(listRegValue[24] / 60))
timeRemainS = str(int(listRegValue[24] % 60))
self.ui.lnTimeRemain.setText(str(timeRemainM + " min "+timeRemainS + " sec")) #TIME_REMAIN_D
self.ui.lnLevel.setText(str(listRegValue[25])) #LEVEL_D
self.statusBar().showMessage("Modbus communication OK")
else:
self.statusBar().showMessage("Error modbus communication")
The problem come from this function after many try and error method. If I delete it program doesn't crash BUT if I modify it by print function (example: print(str(listRegValue[4]))) all is good so my problem doesn't come from mGUI assignation odbus module.
my function displayModbus is refresh every 5 second (using QtThreading).
If I keep just one variable to display my app doesn't crash.
I have another app to read and record modbus data using same displayModbus function (without QT5 display) and I haven't problem
I have this problem on 2 computers and I try it on 5 computers (4x windows 10 and 1x Linux)
Python 3.8.6
PyQT==5.15.1
PyQt5-sip==12.8.1
Any idea?
Thanks.
I built a robot and setup local networking by having it act as an access point. I then connect to the access point from a laptop and send commands over UDP using python.
I would like to do the same thing but over the internet and Im really lost on how to get started. I've seen some IoT services but they dont seem well suited for such an application. I know some basics of networking enough to get a local network running but I have no idea how to get started on sending data over the internet.
Here is how I sent data over my local network (I would love to be able to do the same over the internet). I understand the requirements are a little different as I can't have a static IP address. If you could even point me to resources, I would appreciate it.
Note: the non-networking stuff is irrelevant to my question but I included it in the code for the sake of completion.
import pygame
import socket
import time
import math
#UDP_IP = "192.168.4.1" # if using ESP32
UDP_IP = "10.42.0.1" # if using jetson nano AP
UDP_PORT = 8080
l1=127/2
l2=127/2
r1=127/2
r2=127/2
intake = 127/2
elevator = 127/2
base_line=127/2
joy_deadzone= 0.2
'''
Joystick setup
'''
pygame.joystick.init()
pygame.init()
joysticks = [pygame.joystick.Joystick(x) for x in range(pygame.joystick.get_count())]
counter = 0
for joy in joysticks:
joy_index = counter
counter+=1
joysticks[joy_index].init()
print("The number of joysticks: " + str(pygame.joystick.get_count()))
print("The name of joystick: " + joysticks[joy_index].get_name())
print("The number of axis: " + str(joysticks[joy_index].get_numaxes()))
hats = joysticks[joy_index].get_numhats()
print ("Number of hats: {}".format(hats) )
'''
end of joystick setup
'''
time.sleep(1)
keepRunning = True
def numToStringF(num):
# Make each pwm value 3 characters
num = int(num)
ans = str(num)
if len(ans) == 1:
return "00" + ans
elif len(ans) == 2:
return "0" + ans
else:
return ans
axisX = 0;
axisY = 0;
X = 25;
up_button_last = False
down_button_last = False
left_button_last = False
right_button_last = False
while keepRunning:
#for event in pygame.event.get():
#time.sleep(1)
if abs(round(joysticks[joy_index].get_axis(3), 1))>joy_deadzone:
axisY = (round(joysticks[joy_index].get_axis(3), 1)) * -base_line
else:
axisY=0
if abs(round(joysticks[joy_index].get_axis(0), 1))>joy_deadzone:
axisX = round(joysticks[joy_index].get_axis(0), 1) * base_line
else:
axisX=0
if abs(round(joysticks[joy_index].get_axis(2), 1))>joy_deadzone:
axisS = round(joysticks[joy_index].get_axis(2), 1) * -base_line
else:
axisS=0
print('Calculated:')
print("X: " + str(axisX))
print("S: " + str(axisS))
print("Y: " + str(axisY) + "\n\n")
print('-------')
print('joystick axis:')
print(round(joysticks[joy_index].get_axis(3), 1))
print(round(joysticks[joy_index].get_axis(1), 1))
print('-------')
l1 = int(base_line+axisY+axisX-axisS)
l2 = int(base_line+-axisY-axisX-axisS)
r1 = int(base_line+axisY-axisX+axisS)
r2 = int(base_line+-axisY+axisX+axisS)
if(l1>127):
l1=127
elif(l1<0):
l1=0
if(l2>127):
l2=127
elif(l2<0):
l2=0
if(r1>127):
r1=127
elif(r1<0):
r1=0
if(r2>127):
r2=127
elif(r2<0):
r2=0
intake = int(base_line+joysticks[joy_index].get_button(14)*30)
elevator = int(base_line+joysticks[joy_index].get_button(14)*30)
print('the motors in sequence (l1,l2,r1,r2) are:')
print((l1,l2,r1,r2))
pygame.time.delay(50)
pygame.event.pump()
#time.sleep(0.1)
MESSAGE = "d" + numToStringF(l1) + numToStringF(l2)+numToStringF(r1)+numToStringF(r2)+numToStringF(intake)+numToStringF(elevator)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
sock.sendto(MESSAGE.encode("utf-8"), (UDP_IP, UDP_PORT))
print('the message sent is')
print(MESSAGE)
print('-----')
I ended up using firebase which has a real-time database and seems suitable for data streaming. I still have to do some testing to make sure it's good enough for robot control.
As for interfacing firebase with python, you can use this library:
https://github.com/thisbejim/Pyrebase
This doesn't seem to be a topic with many resources on the internet. I hope more roboticists discuss it/post tutorials and resources if they do some IoT-like robotics.
Im trying to make a underground controlling program with visualisation (for fun of course ;D). I know there are many different loading bar libraries but I couldnt find anything wiht milestones if you know what I mean. Im using Python 3 on windows. I will be thankfull for any help
A loading bar with milestones can be achived with sys:
def updt(total, progress):
barLength, status = 25, ""
progress = float(progress) / float(total)
if progress >= 1.:
progress, status = 1, "\r\n"
block = int(round(barLength * progress))
text = "\r[{}] {:.0f}% {}".format(
"#" * block + "-" * (barLength - block), round(progress * 100, 0),
status)
sys.stdout.write(text)
sys.stdout.flush()
runs = 250
for run_num in range(runs):
time.sleep(.1)
updt(runs, run_num + 1)
time.sleep(1)
I've read another thread on SO regarding image rotation here:
PIL thumbnail is rotating my image?
and I've read another thread on SO about EXIF preservation here:
Preserve exif data of image with PIL when resize(create thumbnail)
Unfortunately, after implementing the suggestions above, it seems that I can only have either:
1) a saved rotated image without EXIF data
or
2) a non-rotated image with EXIF data
but it seems that I can't have both.
I'm hoping I can get some help to fix what I thought was a real simple problem, but has been turning into a scream-fest against my computer for the past few hours.
Here's the relevant parts of my code:
from PIL import Image, ExifTags
import piexif
currImage = Image.open(inFileName)
exif_dict = piexif.load(currImage.info["exif"])
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation]=='Orientation':
break
exif=dict(currImage._getexif().items())
if exif[orientation] == 3:
currImage=currImage.rotate(180, expand=True)
elif exif[orientation] == 6:
currImage=currImage.rotate(270, expand=True)
elif exif[orientation] == 8:
currImage=currImage.rotate(90, expand=True)
currWidth, currHeight = currImage.size
# Here is where I can only do one or the other. Don't know enough about how to get both
exif_bytes = piexif.dump(exif_dict)
#exif_bytes = piexif.dump(exif)
maxImageDimension = [1280, 640, 360, 160]
for imgDim in maxImageDimension:
thumbRatio = imgDim / max(currWidth, currHeight)
# note that because Python's round function is mathematically incorrect, I have to do the following workaround
newWidth = int(Decimal(str(thumbRatio * currWidth)).quantize(Decimal('0.'), rounding=ROUND_UP))
newHeight = int(Decimal(str(thumbRatio * currHeight)).quantize(Decimal('0.'), rounding=ROUND_UP))
# copy currImage object
newImage = currImage
# note that I have to do resize method because thumbnail method has same rounding problem
newImage = newImage.resize((newWidth, newHeight))
# save the thumbnail
if imgDim == 1280:
outFileName = destinationDir + '\\' + file[:len(file)-4] + '.jpg'
else:
outFileName = destinationDir + '\\' + file[:len(file)-4] + '-' + str(newWidth) + 'x' + str(newHeight) + '.jpg'
print('Writing: ' + outFileName)
# Here is where I have to choose between exif or exif_bytes when saving but I can only get one or the other desired result
newImage.save(outFileName, exif=exif_bytes)
print('\n')
currImage.close()
newImage.close()
Thanks in advance.
I try to extract each frame from GIF file.
I found two ways to deal with this problem.
1 Find an online tool to solve it.
https://ezgif.com/split
It is an excellent tool. It can redraw the details. Frames extracted from the GIF are in high quality.
2 Try to use python library to solve this problem.
I use PIL, but it comes with a knotty problem. The frame extracted lost many details with white edges.
So I want to ask what is the algorithm EZGif take, and how to implement it with python?
Got a useful reference of your problem.
import os
from PIL import Image
'''
I searched high and low for solutions to the "extract animated GIF frames in Python"
problem, and after much trial and error came up with the following solution based
on several partial examples around the web (mostly Stack Overflow).
There are two pitfalls that aren't often mentioned when dealing with animated GIFs -
firstly that some files feature per-frame local palettes while some have one global
palette for all frames, and secondly that some GIFs replace the entire image with
each new frame ('full' mode in the code below), and some only update a specific
region ('partial').
This code deals with both those cases by examining the palette and redraw
instructions of each frame. In the latter case this requires a preliminary (usually
partial) iteration of the frames before processing, since the redraw mode needs to
be consistently applied across all frames. I found a couple of examples of
partial-mode GIFs containing the occasional full-frame redraw, which would result
in bad renders of those frames if the mode assessment was only done on a
single-frame basis.
Nov 2012
'''
def analyseImage(path):
'''
Pre-process pass over the image to determine the mode (full or additive).
Necessary as assessing single frames isn't reliable. Need to know the mode
before processing all frames.
'''
im = Image.open(path)
results = {
'size': im.size,
'mode': 'full',
}
try:
while True:
if im.tile:
tile = im.tile[0]
update_region = tile[1]
update_region_dimensions = update_region[2:]
if update_region_dimensions != im.size:
results['mode'] = 'partial'
break
im.seek(im.tell() + 1)
except EOFError:
pass
return results
def processImage(path):
'''
Iterate the GIF, extracting each frame.
'''
mode = analyseImage(path)['mode']
im = Image.open(path)
i = 0
p = im.getpalette()
last_frame = im.convert('RGBA')
try:
while True:
print "saving %s (%s) frame %d, %s %s" % (path, mode, i, im.size, im.tile)
'''
If the GIF uses local colour tables, each frame will have its own palette.
If not, we need to apply the global palette to the new frame.
'''
if not im.getpalette():
im.putpalette(p)
new_frame = Image.new('RGBA', im.size)
'''
Is this file a "partial"-mode GIF where frames update a region of a different size to the entire image?
If so, we need to construct the new frame by pasting it on top of the preceding frames.
'''
if mode == 'partial':
new_frame.paste(last_frame)
new_frame.paste(im, (0,0), im.convert('RGBA'))
new_frame.save('%s-%d.png' % (''.join(os.path.basename(path).split('.')[:-1]), i), 'PNG')
i += 1
last_frame = new_frame
im.seek(im.tell() + 1)
except EOFError:
pass
def main():
processImage('foo.gif')
processImage('bar.gif')
if __name__ == "__main__":
main()
GIF transparency in PIL is broken. Not sure why it is that way, but it`s a fact.
You can try using my GIF library instead, for which I`ve just made a Python frontend:
from PIL import Image
def GIF_Load(file):
from platform import system
from ctypes import string_at, Structure, c_long as cl, c_ubyte, \
py_object, pointer, POINTER as PT, CFUNCTYPE, CDLL
class GIF_WHDR(Structure): _fields_ = \
[("xdim", cl), ("ydim", cl), ("clrs", cl), ("bkgd", cl),
("tran", cl), ("intr", cl), ("mode", cl), ("frxd", cl), ("fryd", cl),
("frxo", cl), ("fryo", cl), ("time", cl), ("ifrm", cl), ("nfrm", cl),
("bptr", PT(c_ubyte)), ("cpal", PT(c_ubyte))]
def intr(y, x, w, base, tran): base.paste(tran.crop((0, y, x, y + 1)), w)
def skew(i, r): return r >> ((7 - (i & 2)) >> (1 + (i & 1)))
def WriteFunc(d, w):
cpal = string_at(w[0].cpal, w[0].clrs * 3)
list = d.contents.value
if (len(list) == 0):
list.append(Image.new("RGBA", (w[0].xdim, w[0].ydim)))
tail = len(list) - 1
base = Image.frombytes("L", (w[0].frxd, w[0].fryd),
string_at(w[0].bptr, w[0].frxd * w[0].fryd))
if (w[0].intr != 0):
tran = base.copy()
[intr(skew(y, y) + (skew(y, w[0].fryd - 1) + 1, 0)[(y & 7) == 0],
w[0].frxd, (0, y), base, tran) for y in range(w[0].fryd)]
tran = Image.eval(base, lambda indx: (255, 0)[indx == w[0].tran])
base.putpalette(cpal)
list[tail].paste(base, (w[0].frxo, w[0].fryo), tran)
list[tail].info = {"delay" : w[0].time}
if (w[0].ifrm != (w[0].nfrm - 1)):
list.append(list[max(0, tail - int(w[0].mode == 3))].copy())
if (w[0].mode == 2):
base = Image.new("L", (w[0].frxd, w[0].fryd), w[0].bkgd)
base.putpalette(cpal)
list[tail + 1].paste(base, (w[0].frxo, w[0].fryo))
try: file = open(file, "rb")
except IOError: return []
file.seek(0, 2)
size = file.tell()
file.seek(0, 0)
list = []
CDLL(("%s.so", "%s.dll")[system() == "Windows"] % "gif_load"). \
GIF_Load(file.read(), size,
CFUNCTYPE(None, PT(py_object), PT(GIF_WHDR))(WriteFunc),
None, pointer(py_object(list)), 0)
file.close()
return list
def GIF_Save(file, fext):
list = GIF_Load("%s.gif" % file)
[pict.save("%s_f%d.%s" % (file, indx, fext))
for (indx, pict) in enumerate(list)]
GIF_Save("insert_gif_name_here_without_extension", "png")