Integrating serial communication in wx GUI - user-interface

def updateV(self, event):
""""""
global v
v=random.uniform(1,10)
print('battery voltage =')
print(v)
if v>3:
self.labelOne.SetBackgroundColour('red')
self.labelOne.SetLabel('Battery Voltage : ' + str(v))
else:
self.labelOne.SetBackgroundColour('white')
self.labelOne.SetLabel('Battery Voltage : ' + str(v))
self.Refresh()
this is a function in my wxpython GUI which i use for generating random values.I have added this function in my panel class of the GUI. I have put a wx.Bind function that assigns a timer value to it and refreshes it regularly for value change regularly.
Now the GUI needs to have serial communication as I need to get sensor values and get them input in my GUI screen. So i found this code for serially inputing the value:
def updateV(self, event):
""""""
global v
v=ser.readline()
print v
if v>3:
self.labelOne.SetBackgroundColour('red')
self.labelOne.SetLabel('Battery Voltage : ' + str(v))
else:
self.labelOne.SetBackgroundColour('white')
self.labelOne.SetLabel('Battery Voltage : ' + str(v))
self.Refresh()
I then went it the init part of the panel class and added this code:
ser = serial.Serial('COM3', 9600, timeout=0)
On running the GUI, the value doesnt appear nor does it print it on the GUI. I know I am doing a big mistake here. Anyways the values right now come through an arduino uno connected to a XBEE shield which receives 1-20 values through another arduino conencted to a XBEE shield. By the way, random variables are generated properly and are printed in the GUI so there is'nt any proble with the function.
I need a way for python to read the value serially and assign it to a variable such that I can print the value I get in my GUI screen.
PS: I used the same serial code to properly get 0 1 2 3 4 5 6 7 8 9 10 value on the command screen of python module.
import serial
import time
ser = serial.Serial('COM3', 9600, timeout=0)
while 1:
v=ser.readline()
print v
time.sleep(1)
I am trying to get used to python, but these small things hinder my progress.. I am new to python, please bear with me!

Your problem is essentially that reading the serial interface in the while loop with ser.readline() as in your last example (EDIT1: and also when polling with a wx.Timer event) will block the GUI when it is waiting for data on the serial interface. Calling the app.MainLoop() will loop the wxPython event system. However, the only thing your GUI example will do is blocking at ser.readline(). As soon some data comes it will continue in the updateV method. But because the next timer event is waiting already, it will run to ser.readline() and block there again and preventing any GUI updates.
Did you try out the wxTerminal example in the pyserial package?
It shows how to spin of a thread which will do the reading and sending a user-defined SerialRxEvent so that everything is thread-safe.
You also should read LongRunningTasks in the wxPython wiki to get an idea how to use threads for long running/blocking tasks in wxPython and communicate back to the main GUI thread safely.

Related

Control brightness in Windows at software Level

It might be possible for a similar question to be already present on the site, but I have searched a lot and didn't find any relevant solution, so I'm posting it here.
I'm making a Night Light Application, which has two options-
Lessen the Brightness of the PC
Apply a Blue light filter mask over the screen.
I'm making this app cross platform, so I've already found a solution for Linux Systems, where I've been making use of xrandr utility to adjust the brightness and gamma at the software level, and my app works flawlessly.
The main problem is for Windows systems, where the brightness feature is only available for portable screens such as for a Laptop.
I cannot find any solution for this.
I made use of Qt5 for making a translucent app window which works good, but doesn't meet the requirement because the things displayed at kernel level are not masked like the cursor, taskbar, start menu, action center, and lots of other.
I searched a lot and lot, which included Microsoft Developer Network, where documentation included the Win32 API where brightness feature was present, but it didn't work for me, as I had a Desktop PC.
So my main problem is, How can I ajust the brightness of all Windows PC, including Laptops, Desktops n all others.
I'm working on Python with ctypes module.
I'm not that much familiar with VC+ and I cannot even afford to install it on my system as it is too much storage and resource intensive.
I primarily want to modify the output going to the physical monitor, that is to modify the Gamma values to get appropriate brightness and Yellow tincture.
I got something called gdi32.dll which deals with the outputs to screens, but I cannot find a way out as everything on the Internet is alongside C++.
Also, I cannot even provide my try code, as I'm not that much familiar to C type coding in Python.
Also, the thing I want to do, Intel Graphics Command Center already does it on my desktop.
If it can do it on at a software level, then I know its possible programmatically.
Can anyone tell is this possible what I'm thinking, and if yes, how can I achieve this?
I don't want the source code, I just want the way out for that.
Maybe GammaRamp from the Gdi32 API can be used, but I don't know how to begin.
This is a thread which actually asked this, but I didn't get my answer from here, and newbies are restricted from commenting, so I didn't have any choice than to post this question here.
I have found the way for the problem.
We can use GetDeviceGammaRamp and SetDeviceGammaRamp from the gdi32.dll library in Windows OS to set the brightness level.
To call these functions through Python, we can use ctypes module.
Below is the sample code that can set brightness of in Windows 10 via Python.
import ctypes
def displayGammaValues(lpRamp):
"""
Displays the GammaArray of 256 values of R,G,B individually
:param lpRamp: GammaArray
:return: None
"""
print("R values: ", end=' ')
for j in range(256):
print(lpRamp[0][j], end=' ')
print()
print("G values: ", end=' ')
for j in range(256):
print(lpRamp[0][j], end=' ')
print()
print("B values: ", end=' ')
for j in range(256):
print(lpRamp[0][j], end=' ')
print(), print()
def changeGammaValues(lpRamp, brightness):
"""
Modifies the Gamma Values array according to specified 'Brightness' value
To reset the gamma values to default, call this method with 'Brightness' as 128
:param lpRamp: GammaArray
:param brightness: Value of brightness between 0-255
:return: Modified GammaValue Array
"""
for i in range(256):
iValue = i * (brightness + 128)
if iValue > 65535: iValue = 65535
lpRamp[0][i] = lpRamp[1][i] = lpRamp[2][i] = iValue
return lpRamp
if __name__ == '__main__':
brightness = 100 # can be aby value in 0-255 (as per my system)
GetDC = ctypes.windll.user32.GetDC
ReleaseDC = ctypes.windll.user32.ReleaseDC
SetDeviceGammaRamp = ctypes.windll.gdi32.SetDeviceGammaRamp
GetDeviceGammaRamp = ctypes.windll.gdi32.GetDeviceGammaRamp
hdc = ctypes.wintypes.HDC(GetDC(None))
if hdc:
GammaArray = ((ctypes.wintypes.WORD * 256) * 3)()
if GetDeviceGammaRamp(hdc, ctypes.byref(GammaArray)):
print("Current Gamma Ramp Values are:")
displayGammaValues(GammaArray)
GammaArray = changeGammaValues(GammaArray, brightness)
print("New Current Gamma Ramp Values are:")
displayGammaValues(GammaArray)
if SetDeviceGammaRamp(hdc, ctypes.byref(GammaArray)): print("Values set successfully!")
else: print("Unable to set GammaRamp")
if ReleaseDC(hdc): print("HDC released")
else: print("HDC not found")
This sets the brightness value, that's between 0-255. Values may differ system-to-system, so preferable range for brightness is 0 - 128 where 128 is the default brightness.
FYI windows already has a monitor blue shade/color shift built in. Dimming external monitor outputs on a desktop is likely not possible.
You'll need to hook into the windows API somehow to control windows functions. There's some documentation about adjusting color temperature (making that warmer would essentially add a "blue light" filter to a screen on microsoft's website.
https://learn.microsoft.com/en-us/windows/win32/api/highlevelmonitorconfigurationapi/nf-highlevelmonitorconfigurationapi-setmonitorcolortemperature.
In terms of executing a small CPP script that actually can interface with windows, you can write a small CPP program, then compile it and execute from python using (slightly modified from this question)
import os
import subprocess
for filename in os.listdir(os.getcwd()):
proc = subprocess.Popen(["./prog", filename])
proc.wait()
However if you don't have the room to install visual studio compile tools, you won't be able to compile a small CPP script locally. There are a few online services that would be able to do that for you though.

How do I use the bluetooth module in conjunction with the multiprocessing module?

I am using python 3.5 and OSX 10.13.2.
I am attempting to gather EEG data from a bluetooth EEG recording device while a human is watching a pygame GUI. Because the bluetooth device sends data at about 512 Hz and the pygame GUI updates at about 25Hz, I'm thinking that including the gathering of the bluetooth data and the updating of the GUI in the same loop/process is not appropriate.
Therefore, I want to create two concurrent processes: one for the gathering of bluetooth input and one for displaying/updating the pygame GUI. I think I have figured out how to run a pygame window in a separate process, but creating a separate process using the multiprocessing module that connects to and reads input from my bluetooth device is not working out well.
When I run the code below, execution seems to stop on this line socket.connect(('B0:B4:48:F6:38:A1', 1)): nothing in the connect() method is printed. Is this a problem with Mac OSX, the bluetooth module, Python, or something else? Does anyone know how I can fix this? If not, does anyone have a different way I could approach my initial problem of gathering data from a bluetooth device and updating a GUI in parallel using python 3.5?
import multiprocessing, time, bluetooth
def connect():
socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
try:
socket.connect(('B0:B4:48:F6:38:A1', 1))
print("connected to device!!")
except Exception as e:
print("failed to connect :(")
def wait_and_do_nothing():
print("just sleeping over here in this process")
time.sleep(5)
process1 = multiprocessing.Process(target=connect, args=())
process2 = multiprocessing.Process(target=wait_and_do_nothing, args=())
process1.start()
process2.start()
process1.join()
process2.join()
print("finished")
The output of the above code is:
finished
I solved my problem. For one, I should have wrapped the multiprocessing code in an if statement like the one below. Two, I should have set the start method to 'spawn' instead of 'fork' like I do below:
if __name__ == '__main__':
multiprocessing.set_start_method('spawn', force=True)
process1 = multiprocessing.Process(target=connect, args=())
process2 = multiprocessing.Process(target=wait_and_do_nothing, args=())
process1.start()
process2.start()
process1.join()
process2.join()

Importing code as a module runs much slower than a single block of code in Python

I'm writing a code to stream images form raspberry-pi3 to my laptop.
I wrote two versions of code, one using module and other as single block of code.
I'm putting the code here (more details follow the code)
Code that runs fast:
import picamera
import socket
import struct
import time
import io
stream_client= socket.socket(socket.AF_INET,socket.SOCK_STREAM)
stream_client.connect(('192.168.43.34',9000))
print('connected')
camera = picamera.PiCamera()
camera.resolution=(320,240)
camera.color_effects=(128,128)
camera.framerate=18
time.sleep(2)
stream = io.BytesIO()
count=0
start=time.time()
try:
for i in camera.capture_continuous(stream,'jpeg',use_video_port=True):
count+=1
stream_client.sendall(struct.pack('<L',stream.tell()))
stream_client.sendall(struct.pack('<h',count))
stream_client.sendall(stream.getvalue())
stream.seek(0)
stream.truncate()
if(time.time()-start>10):
break
finally:
stream_client.sendall(struct.pack('<L',0))
stream_client.close()
camera.close()
print('connection closed')
The codes that runs slowly:
Module (contained in a different file "CameraStreamModule.py" in same folder):
'''
MODULE NAME: CAMERA STREAMING MODULE
OBJECTIVE: TO SEND IMAGE DATA FROM RASPBERRY-PI3 TO LAPTOP VIA TCP/IP STREAM
HARDWARE USED: RASPBERRY PI 3, PI CAMERA REV 1.3
PYTHON VERSION: 3.5.3
DATE WRITTEN: 8-1-2018
'''
'''************************************************************** IMPORTING MODULES ***********************************************************************'''
import picamera # PI CAMERA MODULE
import socket # MODULE TO HANDLE TCP/IP CONNECTION AND TRANSFER
import struct # MODULE TO CONVERT DATA TO BYTE-LIKE OBJECTS (REQUIRED BY SOCKET METHODS)
import time # MODULE FOR TIME RELATED FUNCTIONS
import io # MODULE USED TO CREATE IN-MEMORY DATA STREAMS
'''************************************************************ MODULE IMPORTS END HERE *******************************************************************'''
'''*********************************************************** DECLARING GLOBAL VARIABLES *****************************************************************'''
LIMITED_STREAM = False # Stream only for short time when true
LIMIT_TIME= 10 # Seconds
stream = io.BytesIO()
stream_client= socket.socket(socket.AF_INET,socket.SOCK_STREAM)
camera = picamera.PiCamera()
count=0
'''*********************************************************** GLOBAL VARIABLES END HERE ******************************************************************'''
'''************************************************************** METHOD DEFINITIONS ***********************************************************************'''
def Client_init (Server_ip,Server_port): # (str,int) expected as parameter
global stream_client,start,LIMITED_STREAM
stream_client.connect((Server_ip,Server_port))
if LIMITED_STREAM :
start=time.time()
print('connected')
def Camera_init (Resolution_tuple,Colour_tuple,Frame_rate): # (int_tuple,int_tuple,int) expected as parameter
global camera
camera.resolution= Resolution_tuple
camera.color_effects=Colour_tuple
camera.framerate= Frame_rate
time.sleep(2)
'''
THIS METHOD IS INTENDED TO BE CALLED INSIDE "for i in camera.capture_continuous(stream,'jpeg',use_video_port=True):" CONTINUOUSLY. ALSO .close() FOR SOCKET
AND CAMERA MUST BE CALLED SEPERATELY.
'''
def Send_frame ():
global count,stream_client,stream,LIMITED_STREAM
count+=1
stream_client.sendall(struct.pack('<L',stream.tell()))
stream_client.sendall(struct.pack('<h',count))
stream_client.sendall(stream.getvalue())
stream.seek(0)
stream.truncate()
if LIMITED_STREAM:
if(time.time()-start>LIMIT_TIME):
raise Exception('Time Finished')
'''********************************************************* METHOD DEFINITIONS END HERE ******************************************************************'''
The calling code:
import importlib
Camera_module= importlib.import_module('CameraStreamModule')
Camera_module.LIMITED_STREAM= True
Camera_module.Client_init('192.168.1.102',9000)
Camera_module.Camera_init((320,240),(128,128),18)
try:
for i in Camera_module.camera.capture_continuous(Camera_module.stream,'jpeg',use_video_port=True):
Camera_module.Send_frame()
finally:
Camera_module.camera.close()
Camera_module.stream_client.sendall(struct.pack('<L',0))
Camera_module.stream_client.close()
print('connection closed')
The first code streams about 179 images in 10 seconds and the second version does about 133 images which is a drastic reduction. I just wanted to create a module to make code more manageable and readable.
I have started coding in Python quite recently and I know that my method of coding may look ridiculous to more experienced coders (trust me, I'm trying to improve). Can anyone tell me what could be the reason of this slowdown?
I have observed that even changing the WiFi connection has an effect on the amount of data transferred in a given amount of time, so I have kept the WiFi connection the same for both versions of code.
I think that this slowdown occurrs because I'm passing a lot of data back and forth between modules ?
In any case, any advice/help regarding the code is welcome.
P.S: If you feel that my way of asking questions on this platform is not up to the mark and I need to give more or reduce the details, please let me know.
OK I found out the problem. Actually in the reciever code that I created , I had written a lot of print() statements for debugging purpose. which were causing the delay and due to this I was loosing some data since the socket transmission was asynchronous (and i did not handle the problem of data loss in the code). Along with this and probably the delay in passing large array data, back and forth between the modules caused this problem
Leaving this answer here just in case someone finds it useful.

Addressing multiple B200 devices through the UHD API

I have 2 B210 radios on USB3 on a Windows 10 system using the UHD USRP C API latest release and Python 3.6 as the programming environment. I can "sort of" run them simultaneously in separate processes but would like to know if it is possible to run them in a single thread? How?
1 Happy to move to Linux if it makes things easier, I'm just more familiar with Windows.
2 "sort of" = I sometimes get errors which might be the two processes colliding somewhere down the stack.
The code below illustrates the race condition, sometimes one or both processes fail with error code 40 (UHD_ERROR_ASSERTION) or occasionally code 11 ( UHD_ERROR_KEY )
from ctypes import (windll, byref, c_void_p, c_char_p)
from multiprocessing import Process, current_process
def pread(argstring):
# get handle for device
usrp = c_void_p(0)
uhdapi = windll.uhd
p_str=c_char_p(argstring.encode("UTF8"))
errNo = uhdapi.uhd_usrp_make(byref(usrp),p_str)
if errNo != 0:
print("\r*****************************************************************")
print("ERROR: ",errNo," IN: ", current_process())
print("=================================================================")
if usrp.value != 0:
uhdapi.uhd_usrp_free(byref(usrp))
return
if __name__ == '__main__':
while True:
p2 = Process(target=pread, args=("",))
p1 = Process(target=pread, args=("",))
p1.start()
p2.start()
p1.join()
p2.join()
print("end")
Yes, you can have multiple multi_usrp handles.
By the way, note that UHD is natively C++, and the C API is just a wrapper around that. It's designed for generating scripting interfaces like the Python thing you're using (don't know which interface between Python and the C API you're using – something self-written?).
While it's possible, there's no good reason to call the recv and send functions from the same thread – most modern machines are multi-threaded, and you should make use of that. Real-time SDR is a CPU-intensive task and you should use all the CPU resources available to get data to and from the driver, as to avoid overflowing buffers.

Arduino serial sometimes gives random values

I am using a MMA7361 accelerometer from sparkfun that is connected to my arduino uno and it is in turn connected to my pc.
I am simply reading the values from each axis(x,y,z) and sending them straight through the serial port to my pc with a series of Serial.print and Serial.write. From there I have set up a program to read and display the info with myPort.readString();
Now it works fine 80% of the time and it gives the right results and all, but sometimes I get some random value sent through the serial port and it messes up the receiving program making me unable to use the signal properly.
I am pretty sure its not the sensor itself sending the disturbing signal because I have tried to save 10 different readings and then sending an average to minimize the effect with no luck. The receiving pc still got the weird value spikes around 0-200 (from what I saw as output).
I tried with pulling out the cable that connects from the sensor to the analog in port and weirdly it gave out some random value instead of the expected 0, I'm not sure but for me it seems like that has something to do about my problem.
I have read about some kind of pull down resistor but that only works for buttons, right?
I just got my arduino and I'm trying to learn how to use sensors and what you can do with them and what can go wrong so I'd appreciate if someone could help me with this :)
Heres an example of the random value messing up the output:
252:236:218
251:202:215
2 <-- this is where it begins
59:231:245
28
4:144:142 <-- messing up the order of the values
251:19
2:187
246:235
:244
240:190:
238
250:202:2
32
248:243:224
245:227:240
251:228:244
253:223:241
If you want I got the code for sending and recieving too:
Serial.print(analogRead(xpin));
Serial.write(":");
Serial.print(analogRead(ypin));
Serial.write(":");
Serial.println(analogRead(zpin));
I'd really like the sending to be just one line of code but I haven't been able to join all numbers and strings to a one line string on the arduino.
Recieving:
if ( myPort.available() > 0) {
result = myPort.readString();
println(result);
}
Looking at your output, it seems that the values are all received, but somehow a CR and/or LF character is added to the output. And that comes from the println statement:
if ( myPort.available() > 0) {
result = myPort.readString();
println(result);
}
What happens is that the receiving end gets some characters (not necessarily all), it prints them, adding a linefeed character then exits the function.
Then it enters the if statement again and prints the available characters in the buffer. And so it goes.
If you wish to ensure a consistent output you have to either
1. build a packet of the data or
2. Count the received bytes and print them when all are received.
As to 1. it would be my preferred method, add a start- and end-character to the data. The receiving end will then know that all data between the start- and end-character is the data to be printed.
I seem to have fixed this by using readChar and checking if the current character inputted is the delimiter. It is a bit slower but it works.

Resources