Sending Multiple Serial Bytes from Arduino to Python to Display Images - python

Essentially, I've been trying to write a program that when you push a specific button, a specific image appears. For example, if I push Button1, Image1 will be displayed. Next, if I push Button2, Image1 will disappear and Image2 will displayed. The problem I ran into is regarding button2. Eventually, I would like it so that many image files can be opened. Right now, I have serial data being sent from the arduino to a raspberry pi with python. The python program recognizes button1 being pressed and displays the image. However, when I press button2 (before or after pressing button1), the program stops and an error message appears.
Any help to resolve this issue would be great!
I have tried altering the bytes sent from the Arduino but it was to no avail. I am new to serial data processing so there could be something I have missed.
Arduino Code
int First=2;
int buttonState=0;
int Second=3;
int buttonState2=0;
void setup()
{
Serial.begin(9600);
pinMode(First, INPUT);
pinMode(Second, INPUT);
}
void loop()
{
int buttonState=digitalRead(First);
int buttonState2=digitalRead(Second);
if(buttonState==HIGH)
{
Serial.print(0x0);
delay(100);
}
if (buttonState==LOW)
{
//do nothing
}
//BUTTON STATE SECOND
if(buttonState2==HIGH)
{
Serial.print(0x1);
delay(100);
}
if (buttonState2==LOW)
{
//do nothing
}
}
Python Code(The formatting for two lines is off due to how the question is posted):
import numpy
import cv2, glob
import sys
import os
import serial
from subprocess import Popen
ser=serial.Serial('/dev/ttyUSB0',9600)
Title = cv2.imread('/home/pi/Desktop/Avengers/Title.jpg')
Zero = cv2.imread('/home/pi/Desktop/Avengers/000.jpg')
while True:
command = ser.read()
if command:
#flush serial for unprocessed data
ser.flushInput()
print("new command:", command)
if (int(command) == 0):
cv2.namedWindow("Title", cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty("Title",cv2.WND_PROP_FULLSCREEN,cv2.WINDOW_FULLSCREEN)
cv2.imshow('Title', Title)
cv2.waitKey(0)
cv2.destroyAllWindows()
if (int(command) == 1):
cv2.namedWindow("Zero", cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty("Zero",cv2.WND_PROP_FULLSCREEN,cv2.WINDOW_FULLSCREEN)
cv2.imshow('Zero', Zero)
cv2.waitKey(0)
cv2.destroyAllWindows()
I expect one image to displayed when I push a button, and another image to be displayed when I push the other button. The results of the code allow one button to display an image. However, when the other button is pushed, no image is displayed. In short, one button works and the other doesn't. An error message reads:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 490, in read
'device reports readiness to read but returned no data '
serial.serialutil.SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/pi/OpenJPG.py", line 14, in <module>
command = ser.read()
File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 497, in read
raise SerialException('read failed: {}'.format(e))
serial.serialutil.SerialException: read failed: device reports readiness to read but returned no data (device disconnected or multiple access on port?)

Related

How can I fix issue connecting Arduino with python?

I am trying to configure python on my arduino. Ive followed like 10 tutorials but none of them are working. Ive tried to connect via pyserial. When I use pyserial, I simply get no response, here is the code.
I am trying to process data and code in python, then send data to arduino to run. I already downloaded the Firmata libraries on both, no issues there. I have also uploaded the arduino standard firmata sketch, no issues there.
Code being run on my python ide:
import serial
import time
Arduino = serial.Serial('com5',115200)
time.sleep(5)
while True:
while (Arduino.inWaiting()==0):
print("ur dumb")
pass
dataPacket = Arduino.readline()
print(dataPacket)
Code being run on my Arduino IDE:
int count = 1;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.print(count);
delay(1000);
count = count+1;
}
Similary I've tried:
import pyfirmata
import time
board = pyfirmata.Arduino('/dev/ttyACM0')
it = pyfirmata.util.Iterator(board)
it.start()
digital_input = board.get_pin('d:10:i')
led = board.get_pin('d:13:o')
while True:
sw = digital_input.read()
if sw is True:
led.write(1)
else:
led.write(0)
time.sleep(0.1)
you can use a more accessible python program here to work:
import serial
import time
ArduinoUnoSerial = serial.Serial('com5',115200)
while 1:
print (ArduinoUnoSerial.readline())
this will work with your Arduino program
don't worry about the board no matter whether it is mega or uno or anything else ArduinoUnoSerial.readline() will work

Pyserial - COM disconnection and reconnection possible?

new to Python but it really makes fun to work with :-)
Using the pyserial lib and works fine so far. BUT...
...is there a way to ignore the following problem: During a serial communication I disconnect the COM-cable for a short time. I got the following errormessage then:
**Traceback (most recent call last):
File "C:\Users\greulich\PycharmProjects\arduino_serial\main.py", line 48, in <module>
functions.receiveWithStartMarkers()
File "C:\Users\greulich\PycharmProjects\arduino_serial\functions.py", line 30, in receiveWithStartMarkers
receivedChar = serialPort.read(1) # read 1 byte
File "C:\Users\greulich\PycharmProjects\arduino_serial\venv\lib\site-packages\serial\serialwin32.py", line 275, in read
raise SerialException("ClearCommError failed ({!r})".format(ctypes.WinError()))
serial.serialutil.SerialException: ClearCommError failed (PermissionError(13, 'Das Gerät erkennt den Befehl nicht.', None, 22))**
My code looks like that:
while serialPort.is_open is True and newData is False:
#try:
receivedChar = serialPort.read(1) # read 1 byte
print(str(date.time()) + ' >>> ' + 'I got the following byte: ' + str(receivedChar))
I opened up port initially in that module:
try:
serialPort = serial.Serial('COM12', 115200)
except:
print('COM-Port not available!')
print('Will exit not the Python program!')
exit() #quits the complete Python program
serialPort.timeout = 3
Is there a way to define kind of a timeout until this error will hit me where the user has the chance to reconnect the cable?
In a nutshell: I want to be able to disconnect the com cable for a short time and connect it again without an error showing :-)
Thanks,
Markus

python cv2.imshow() is working for root, but not for other users on raspberry pi

On my raspberry pi cv2.imshow('text', frame) works fine when run from root. However, when run from another user (myname), I get the following error:
Unable to init server: Could not connect: Connection refused Traceback
(most recent call last): File "my_file.py", line 7, in
cv.imshow('text', frame) cv.error: OpenCV(4.5.1)
/tmp/pip-wheel-qd18ncao/opencv-python/opencv/modules/highgui/src/window_gtk.cpp:624: error: (-2:Unspecified error) Can't initialize GTK backend in function
'cvInitSystem'
my code:
import cv2
camera = cv2.VideoCapture(0)
success, frame = camera.read()
if not success:
stop('camera not connected')
cv2.imshow('text', frame)
cv2.waitKey(1000)
My group permission for the user (id -a) in case that helps:
uid=1001(myname) gid=1001(myname)
groups=1001(myname),27(sudo),29(audio),44(video)
As everything is working as expected for root (pi) I suspect that I don't have access or the right permissions to specific packages from user 'myname'? However, I don't know how to troubleshoot this.
As I said in the comments of the question, using this command:
echo $DISPLAY
It prints the current X server configured in the environment variables for the user. If this variable is different for "pi" and "myname" (for any reason), then you should change the value of "myname" to be equal to that of "pi". If they are the same, you can try this command:
xhost +si:localuser:myname
This will change the X server permissions for user "myname".

Start and check name of window on virtual X display

I'm writing a test on Ubuntu 18.04. I want to create a virtual display, start a window on it, and check the window name. In three separate shells I'm running:
Xvfb :4 -screen 0 1920x1080x24+32 -fbdir /var/tmp
then
DISPLAY=:4 xterm
then
DISPLAY=:4 xdotool getwindowfocus getwindowname
That last command returns
XGetInputFocus returned the focused window of 1. This is likely a bug in the X server.
X Error of failed request: BadWindow (invalid Window parameter)
Major opcode of failed request: 20 (X_GetProperty)
Resource id in failed request: 0x1
Serial number of failed request: 20
Current serial number in output stream: 20
That error seems to come from xdotool:
int xdo_get_focused_window(const xdo_t *xdo, Window *window_ret) {
int ret = 0;
int unused_revert_ret;
ret = XGetInputFocus(xdo->xdpy, window_ret, &unused_revert_ret);
/* Xvfb with no window manager and given otherwise no input, with
* a single client, will return the current focused window as '1'
* I think this is a bug, so let's alert the user. */
if (*window_ret == 1) {
fprintf(stderr,
"XGetInputFocus returned the focused window of %ld. "
"This is likely a bug in the X server.\n", *window_ret);
}
return _is_success("XGetInputFocus", ret == 0, xdo);
}
I just want to do the minimal thing to get a virtual display, start a window on it, and check the window name.
What should I do?

Segmentation fault occurs when a C++ program is reading a file while a separate python GUI script is writing to the same file

I am currently running this on Raspbian OS - Debian.
I have two separate programs running in unison. I have a c++ 'engine' and a python 'gui' interface. I know there is probably a much better practice, but at the moment they are communicating via flat files. Essentially the python GUI writes to a file, cmd.sf, with specific text and the engine then decodes that exact same file and executes whatever it needs to do.
The setup is quite simple:
C++ Engine:
The C++ program is constantly reading the cmd.sf file and stays in an infinite loop within the engine if the context of the file is -1. The moment the file changes the engine should parse what the Python GUI essentially wrote and upon successful execution of whatever the contents told the engine to do, it writes back to the file -1
Python GUI
On the GUI end, it's the same concept except it is reversed. GUI also constantly reads from the cmd.sf file and doesn't proceed with writing the same or different instruction until it knows the C++ engine is done with its previous instruction. So it essentially checks the file to make sure it is anything BUT -1
The problem lies where if I initially set cmd.sf to -1, the C++ engine does what it needs to do successfully, by constantly reading and checking the contents of the file. However, the moment I instruct the GUI to change the file's contents, the C++ engine hangs, spits out a seg fault, and aborts.
However, I have found something that does work and I can not for the life of me figure out why. If I was to open cmd.sf in a text-editor such as geany (I am Raspbian) and change the contents via the editor and save it, it does not cause a segfault error. In fact the C++ engine notices the change of the file contents, executes the instruction appropriately and write -1 back to the file. It seems to not like it when I programatically change the contents of the file.
Here is a snippet of my python code that changes the contents of the file, this is nested in a loop:
scan_cmd = AllCommands.start_scan
# generate the key cmd packet for engine to start listening to incoming switches
#
# with open("../data/switches_debug.sf") as sw_file:
# switch_ids = [i.split(",")[0] for i in sw_file.readlines()]
# #print(switch_ids)
packet = CommandPacket(0xFFFFFF, scan_cmd)
content = ""
can_edit_file = False
while not can_edit_file:
with open("../data/cmd.sf", "r") as cmd_file:
try:
content = int(cmd_file.readlines()[0])
except ValueError:
# means gui has already written to file and is in the form of x,x,x,...,x
# 12345,67,8
# The beginning of this function should just check to see if
# file content IS NOT -1 in order to prevent engine and gui
# writing to the file at the same time
#
# So if GUI has written to file and in the
# form of csv, it is obviously not -1
#
# assign content a value that is not -1
content = 0
if content == -1:
can_edit_file = True
msg = "Begin Listening... [%s]" % packet.hex()
print(msg)
content = ','.join(str(x) for x in packet.plist)
# open as 'w' to overrite content of file
with open("../data/cmd.sf", "w") as cmd_file:
cmd_file.write(content)
print("Wrote [%s] to ../data/cmd.sf" % packet.hex())
Similarly, this is the C++ code that reads and checks if the file has changed:
Scribe Cher("../data/cmd.sf");
for (;;) {
std::cout << std::flush;
// cpu_timer tmr;
// loop forever and read from cmd.sf for instructions
// if file contents is != -1 instruction from GUI is set; read and execute
// upon successful instruction execution write '-1' to file
// read contents of cmd.sf file
bool file_is_ready = false;
int u = 0;
do{
Cher.ReadFile(); // custome object that actually does the reading
cmd_file = std::stoi(Cher.FileContents); // Cher.FileContents is std::string
//debugging section
if(u % 10000 == 0){
std::cout << std::flush;
fmt::printf("File Contents: {%s}\n", Cher.FileContents);
}
if(cmd_file != -1){
file_is_ready = true;
}
u++;
}while(!file_is_ready);
}
The Cher instance is of object Scribe with is a helper class that controls reading/writing to files. Upon initialization, it sets one important member within the class and that is the path to file.. each "Scribe" is assigned to one file.
void Scribe::ReadFile(){
std::string file_contents;
std::vector<std::string> vstring;
this->File.close(); //in case the file is opened
if(!this->File.open(std::ios::in)){
throw std::ios::failure("Unable to open file.");
//std::cout << "Unable to Open" << std::endl;
}
this->File.clear();
this->File.seekg(0, std::ios_base::beg);
while(this->File >> file_contents){
std::cout << "infinite loop" << std::endl;
vstring.push_back(file_contents);
}
//for(auto &i: vstring){
// std::cout << i << std::endl;
//
this->FileContents = vstring[0];
this->File.close();
}
Here is an example stdout output from the terminal when I run this by initially setting the cmd.sf to -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
File Contents: -1
Segmentation Fault //this is when I use the python gui to change file contents

Categories