How to structure my Python code? - python

I apologize in advance for this being a bit vague, but I'm trying to figure out what the best way is to write my program from a high-level perspective. Here's an overview of what I'm trying to accomplish:
RasPi takes input from altitude sensor on serial port at 115000 baud.
Does some hex -> dec math and updates state variables (pitch, roll, heading, etc)
Uses pygame library to do some image manipulation based on the state variables on a simulated heads up display
Outputs the image to a projector at 30 fps.
Note that there's no user input (for now).
The issue I'm running into is the framerate. The framerate MUST be constant. I'd rather skip a data packet than drop a frame.
There's two ways I could see structuring this:
Write one function that, when called, grabs data from the serial bus and spits out the state variables as the output. Then write a pygame loop that calls this function from inside it. My concern with this is that if the serial port starts being read at the end of an attitude message, it'll have to pause and wait for the message to start again (fractions of a second, but could result in a dropped frame)
Write two separate modules, both to be running simultaneously. One continuously reads data from the serial port and updates the state variables as fast as possible. The other just does the image manipulation, and grabs the latest state variables when it needs them. However, I'm not actually sure how to write a multithreaded program like this, and I don't know how well the RasPi will handle such a program.

I don't think that RasPi would work that well running multithreaded programs. Try the first method, though it would be interesting to see the results of a multithreaded program.

Related

Raspberry: Showing various images on display according to GPIO states

I would like to have some advice, what would be the best solution to my problem. I want to write a python program, that runs on Raspberry Pi. It runs in an infinite loop, and checks various stuff, like contents of some folders, and GPIO states.
A basic operation looks like this:
pictures arrive in a folder from a different source
the code notices, reads the images, does some processing
it starts to listen to GPIO input: in case of GPIO state change, the code displays the image.
if the GPIO state changes again, the code switches the picture to an another. And the loop resets, files are deleted, and the cycle starts again
I solved most of the problems, but I have difficulties with displaying the images.
I tried using opencv, I structured the code something like this, it's only a dummy:
state = "first_phase"
while True:
state = decide_state() #this part checks everything,
GPIO, folders, etc
if state = "first_phase":
cv2.imread(some_picture)
cv2.imshow(the picture)
cv2.waitKey(1500) #I had freezes with less delay, but this seems to work
state = "next_phase"
continue
elif state = "next_phase":
cv2.imread(some_other_picture)
cv2.imshow(the_picture)
cv2.waitKey(1500)
state = "first_phase"
continue
destroyAllWindows()
This is much much more complex in reality, with way more states and GPIO ports used, it really is a difficult application, but the idea is something like this, and it is working. 99% of the time...
1% of the time I get weird errors, like "GDK_IS_DEVICE" and Segmentation Faults. (I checked, resources are ok) I can't resolve them, and they come erratically, sometimes right away, sometimes after the 994th picture, and always at the point where the code tries to show the images.
I'm now convinced that it has to do with the highgui opencv uses, but - you can probably guess from my code - I have not enough experience to debug this. I cannot completely omit using opencv because I'll also do some operations on the images, but for displaying them I think I should use an another method. PILLOW is not okay, because I don't want to write out the results of the image manipulations, only draw them on the display. (also it is only possible to kill the display with subprocesses, and I don't feel comfortable doing that). I tried using tkinter but I'm lost how threading and communicating between my main loop and the tkinter loop would be possible and crash-free.
I can restart the code, but the last images will be lost, and it is important to show them again, if the code crashed. I could write a workaround, where I write the manipulated pictures on the disk, and after a successfull display it deletes them, so after starting up again, it sees that there are still images left to show, and shows them... but this only solves the symptoms, and also kills the sd card faster.
Is there any other solution to this? TL;DR: I want to draw pictures on the display in case of some events, while my code does it's thing in the background for eternity.

Python for sockets sensors gui system

I am new to socket programing and SW architecture.
My system must be : a GUI in my laptop using python. There are many embedded systems with same sensors ( GPS, Temperature, pressure ...). Each time you select an embedded system, my program needs to establish a connection with it , I need to show its GPS position and the real time feed of its sensors in the GUI ( For now the GUI is not the problem, I can do with Kivy or Tkinter).
This is how it must function :
In the GUI, there is a field to enter the ID of embedded system and a button to try to connect with it.
When the button is clicked, the program establishes connection and shows GPS, Temperature and pressure in real time continuously until connection is lost.
I was thinking of doing it with this architecture :
A thread to deal with the GUI
Each time a button is clicked and an embedded system is found, an object of a class I created is instantiated.
The class has as attributes :
list GPS ( to store GPS feed)
list temperature ( to store Temperature feed)
list pressure
a thread_socket ( the socket is created in a thread to be a client to the embedded system. So each time an object is instantiated of the class, a separate socket is create )
The class has as methods :
Get_Gps() : Each time this method is called the GPS list attribute is updated
Get_Temperature() / Pressure()
Stop() : When this method is called the embedded system needs to shutdown.
In the socket thread, I have methods such as send_message() and receive_message() to send through TCP/IP the request for getting GPS and sensor data or stopping the system.
On each embedded system I will put a server using python that is set up everytime the system starts.
This way the ID of the system is the ip of the server, And my laptop would be a client, searching for the ip adress when I select a system.
My questions are :
Does this architecture seem alright to you ?
Is it correct to receive real time feed in a list ? for example for the gps.
Each time I find a system I instanciate an object to keep things clean, is this a good way to do it?
Do you see any issues or improvements ?
Thank you in advance,
I think your approach in general is fine.
However, you should keep a few things in mind:
When designing your software, you should first identify the different tasks involved and define separate functional units for each task. This is the concept of separation of concerns.
I also suggest to read a bit on the Model-View-Controller (MVC) pattern: In your case, the model would be your class containing the data structure for the measurements and the business logic (e.g. polling data from a source for example every second until the connection is stopped). The view and the controller might both be located in the GUI (which is absolutely fine).
The GUI is not necessarily an explicit thread, but many frameworks rather work with an event-based concept that lets you define the application's behavior for a given user interaction.
Why do you actually need lists for the measurements? Is there a requirement to keep the history of measurements over a certain period of time? Is this a list that will keep growing and growing or rather a rolling list (e.g. for showing the last n seconds/minutes of measurements in the GUI)? There seems a bit of a contradiction to starting a new class instance with every new connection, because you would obviously loose the contents when you stop the connection and terminate the instance.
Hope this gives you some ideas of how to proceed from there.

Writing fast serial data to a file (csv or txt)

Is there a way to capture and write very fast serial data to a file?
I'm using a 32kSPS external ADC and a baud rate of 2000000 while printing in the following format: adc_value (32bits) \t millis()
This results in ~15 prints every 1 ms. Unfortunately every single soulution I have tried fails to capture and store real time data to a file. This includes: Processing sketches, TeraTerm, Serial Port Monitor, puTTY and some Python scripts. All of them are unable to log the data in real time.
Arduino Serial Monitor on the other hand is able to display real time serial data, but it's unable to log it in a file, as it lacks this function.
Here's a printscreen of the serial monitor in Arduino with the incoming data:
One problematic thing is probably that you try to do a write each time you receive a new record. That will waste a lot of time writing data.
Instead try to collect the data into buffers, and as a buffer is about to overflow write the whole buffer in a single and as low-level as possible write call.
And to not stop the receiving of the data to much, you could use threads and double-buffering: Receive data in one thread, write to a buffer. When the buffer is about to overflow signal a second thread and switch to a second buffer. The other thread takes the full buffer and writes it to disk, and waits for the next buffer to become full.
After trying more than 10 possible solutions for this problem including dedicated serial capture software, python scripts, Matlab scripts, and some C projects alternatives, the only one that kinda worked for me proved to be MegunoLink Pro.
It does not achieve the full 32kSPS potential of the ADC, rather around 12-15kSPS, but it is still much better than anything I've tried.
Not achieving the full 32kSPS might also be limited by the Serial.print() method that I'm using for printing values to the serial console. By the way, the platform I've been using is ESP32.
Later edit: don't forget to edit MegunoLinkPro.exe.config file in the MegunoLink Pro install directory in order to add further baud rates, like 1000000 or 2000000. By default it is limited to 500000.

How to implement triggers in Python script

I have a psychopy script for a psychophysical experiment in which participants see different shapes and have to react in a specific way. I would like to take physiological measures (ECG) on a different computer and implement event points in my measures. So whenever the participant is shown a stimulus, I would like this to show up on the ECG.
Basically, I would like to add commands for parallel port i/o.
I don't even know where to start, to be honest. I have read quite a bit about this, but I'm still lost.
Here is probably the shortest fully working code to show a shape and send a trigger:
from psychopy import visual, parallel, core
win = visual.Window()
shape = visual.ShapeStim(win)
# Show it
shape.draw()
win.flip()
# Immediately send trigger
parallel.setData(10) # Trigger code, here 10
core.wait(0.020) # Number of seconds to send this trigger code (enough for the hardware to send and the receiver to recognize it)
parallel.setData(0) # Stop sending trigger.
You could, of course, extend this by putting the stimulus presentation and trigger in a loop (running trials), and do various other things alongside it, e.g. collecting responses and saving data. This is just a minimal example of stimulus presentation and sending a trigger.
It is very much on purpose that the trigger code is located immediately after flipping the window. On most hardware, sending a trigger is very fast (voltage on the port changes within 1 ms of the line being run in the script) whereas the monitor only updates its image around every 16.7 ms. and win.flip() waits for the latter. I've made some examples of good and bad practices for timing triggers here.
For parallel port io, you should use pyparallel. Make continuous ECG measurements, store those and store the timestamp and whatever metadata you want per stimulus. Pseudo code to get you started:
while True:
store_ecg()
if time_to_show():
stimulus()
time.sleep(0.1) # 10 Hz

wxPython & Pyserial - Continuous communication

I am a newbie to python and I am learning new things day by day. I have a question regarding integrating wxpython and pyserial. I am writing a GUI application to control a microprocessor through pyserial.
I have a wxpython script written - displays good - with buttons and text fields.
I tested communication with my microprocessor using small commands from pyserial - everything is in good place.
Problem:
I will be having a button (say Button A) on my GUI, which after clicked - checks if the serial communication is made (by sending and receiving data ofcourse). Once the communication is good, I have to make sure the communication stays good as long as I am using my GUI. So I decided to write an external function which continuously sends and reads data (probably a for loop). Based on the functions return value I will know if my serial communication is active or not (this might be a bad idea - but thats the best I got)
Now the problem is I have a lot of other features on my GUI, buttons, text fields etc.. So for example when another button (say button B) is pressed I want to send a specific command to the microprocessor. This requires I interrupt the serial communication which was going on in my Step 1, send data from button B click, then re-start the Step 1 communication again (to keep checking my serial communication is active). I dont know how I can interrupt the communication. The Step 1 serial communication (for loop) is bound to the Button A click. Once the Button A is clicked, it goes to a for loop and serial communication is checked continuously.
I have so many buttons and text fields like this - which are going to read and write data to the Microprocessor. Whenever I want to do an event, I have to stop the serial communication in step 1 and restart it again.
On top of all this, I can only check the serial communication (mentioned in Step 1) every 100ms. I cannot just write a for loop. I have to do some modifications - like time.delay(100ms) or something.
I dont know how to frame it, but may be I just require a good algorithm idea or implement this somehow with help of import sched or import thread
I am trying majorly to avoid import thread - because my microprocessor has very minimal RAM. Also using threading with wxPython is pain in the neck (what I read online)
One of my colleagues suggested using "timer service" from my Operating system. I dont think python have a feature like that. I have no clue what he is talking about, at the least. His argument is that, if I can use this, I can run the continuous serial communication check every 100ms very easily.
Any help would be greatly appreciated. I am not looking for any complicated solutions, I appreciate if you attach a piece of code, use very basic programming. I have the wxPython GUI in a single class.

Categories