I want to send data from one pi to another with UART communication. The first Raspberry model is Raspberry Pi 4, and the second one Raspberry Pi 3. To do this communication Im connecting both Raspberry pins in this way:
Pi 4 -> Pi 3
Tx -> Rx
Rx -> Tx
Ground -> Ground
I have already activated both Pis serial connection on the raspberry configuration following the steps of this link: https://iot4beginners.com/raspberry-pi-configuration-settings/. In order to write and send the data I have created the next python program:
import time
import serial
ser = serial.Serial(
port='/dev/ttyS0', #Replace ttyS0 with ttyAM0 for Pi1,Pi2,Pi0
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.SEVENBITS)
counter=0
while True:
ser.write(str.encode(str(counter)))
time.sleep(1)
counter += 1
To read and print the data received I have created the next program:
import time
import serial
ser = serial.Serial(
port='/dev/ttySO', #Replace ttyS0 with ttyAM0 for Pi1,Pi2,Pi0
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.SEVENBITS
)
counter=0
while 1:
x = ser.readline()
print(x)
Finally when I run the reading program I get the next error:
Traceback (most recent call last):
File "serial_read.py", line 14, in <module>
x = ser.readline()
File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 501, 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?)
I'm new to Raspberry communication and I will be thankful for any suggestion.
Python 2.7 is officially dead, so I would recommend using Python3 - especially for new projects such as yours.
So, rather than run your script with:
python3 YourScript.py
you could put a proper shebang at the start so it automatically uses the correct Python version you intended:
#!/usr/bin/env python3
import ...
Then make the script executable with:
chmod +x YourScript.py
Now you can run it with:
./YourScript.py
and be happy it will use Python3, and also even if someone else uses it.
The actual issue, I think, is that the readline() on the receiving end is looking for a newline that you didn't send. So I would try adding one:
ser.write(str.encode(str(counter) + '\n'))
Personally, I find f-strings to be much easier than the older % and .format() stuff, so maybe try:
ser.write(str.encode(f'{counter}\n'))
Related
In windows 10 I am trying to read the output of an attached serial device.
Using hterm I am able to see the data on serial port COM5. So the serial port works fine.
Now using WSL2 (Ubuntu 20.04.3) I am running the following python script
import serial
ser = serial.Serial("COM5", baudrate=115200)
which fails with the error
Traceback (most recent call last):
File "test1.py", line 6, in <module>
ser = serial.Serial("COM5", baudrate=115200)
File "/usr/lib/python3/dist-packages/serial/serialutil.py", line 240, in __init__
self.open()
File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 268, in open
raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg))
serial.serialutil.SerialException: [Errno 2] could not open port COM5: [Errno 2] No such file or directory: 'COM5'
I also tried to use the suggestions posted in this article at attach the USB port on which the serial device is connected to, to WSL.
The command usbipd wsl list in a windows powershell shows then
8-3 0403:6001 USB Serial Converter Attached - Ubuntu-20.04
But when then running the same python code in WSL2 gives the same error.
So how to fix this problem so I am able to just read all data from the serial port with python?
You could try using the following script.
import serial
ser = serial.Serial("COM5", baudrate=115200, timeout=1)`
while True:
data = ser.readline()
print(data)
[EDIT] Code updated and tested as per locking remarks[/EDIT]
I generally use a solution where I just identify the port name from USB VID:PID data.
This allows me to not hard code any com port name.
You must begin searching for the port name corresponding to your USB device (see find_device() below).
You should also use locks on your serial port while reading so you don't get multiple concurrent accesses, which especially on Windows will create permission errors. See with LOCK context manager for locking the serial reads.
Code has been tested from Python 2.7 to 3.11 on both Windows and Linux.
Of course you can adapt the serial port settings and perhaps the size of read bytes and/or timeout.
import serial.tools.list_ports
import serial
from threading import Lock
# Your USB SERIAL DEVICE identification
USB_VID = "0x0403"
USB_PID = "0x6001"
SERIAL_SETTINGS = {
"baudrate": 115200,
"bytesize": 8,
"parity": "N",
"stopbits": 1,
}
LOCK = Lock()
def find_devices():
# type: () -> List[str]
"""
Find all COM ports corresponding to your USB device
"""
_device_ports = []
for port in serial.tools.list_ports.comports():
if port.vid == int(USB_VID, 16) and port.pid == int(USB_PID, 16):
_device_ports.append(port.device)
return _device_ports
def read_device(device) -> str:
# type: (str) -> str
try:
with LOCK:
with serial.Serial(device_port, timeout=1, **SERIAL_SETTINGS) as ser:
result = ser.read(size=64).decode('utf-8')
if len(result) == 0:
return None
else:
return result.strip("\r\n")
return result
except serial.SerialException as exc:
error_message = "Cannot read serial port {}: {}".format(device_port, exc)
print(error_message) # or log it
raise OSerror(error_message)
for port in find_devices():
data = read_device(port)
print(data)
Hope this helps.
More examples of serial reading can be found in a library I wrote for reading USB temperature sensors, see this
I personally would get this to work in Ubuntu 20.04.3 first.
Just download a Virtual Machine of Ubuntu, install it (in a VM environment (or real machine if you have one spare) ) and test.
WSLx is really good but it still has some teething problems.
If you know it passes in a real (or VM) Ubuntu install then you are most of the way there.
I always do this as WSLx can have some weird quirks I have found. It shouldn't for note but it does, especially when it comes down to external hardware.
Since you are using Ubuntu, you can't use the Port-Names used by Windows. In Ubuntu Port names usually are in the format of dev/ttyUSB followed by the number of the port (dev/ttyUSB0).
I have an Arduino microcontroller (Adafruit feather M0), and if I have it plugged into my windows PC and open the serial monitor, I can type P 0 2 1 0 and then enter, the Arduino interprets this command and works as expected.
Now I want to plug in the same device into my raspberry pi, and have python do this instead.
I have done this in the past on a different microcontroller (sparkfun pro micro) and it worked great. I can't seem to get it to work and am not sure what I am missing.
python code:
import serial
import time
ser = serial.Serial('/dev/ttyACM0', 115200, timeout = None)
time.sleep(2)
returnKey = "\r\n"
ser.write(str.encode("P 2 1 0"))
ser.write(str.encode(returnKey)
The code finishes, but the Arduino simply does nothing, as if it discarded the command or didn't get it at all.
The serial speed is matching on the Arduino too (115200).
I also tried:
ser.write(b'P 2 1 0')
ser.write(returnKey.encode())
Any ideas what I am missing here?
Solved it.
Ended up using
import serial
import time
ser = serial.Serial('/dev/ttyACM0', 115200, timeout = None)
time.sleep(2)
ser.write(b'P 2 1 0 \r\n')
I'm having trouble with a python script running on an RPI0 reading serial input from an Arduino. I know the Arduino's code is correct as everything works as intended interacting with the Arduino over the built in serial monitor in the Arduino software(send code a10(code to drive a relay HIGH), Arduino sends back 11(basically asking for how long), send code b5, Arduino will hold pin HIGH for 5 seconds(b5)).
However when I attempt to read any serial input in python using the pyserial module, nothing happens. I know it does successfully send the code to the arduino as it will hold the pin HIGH for the specified seconds when I rewrite the python script with ser.write("a10b5").
The serial connection is NOT USB. I'm using jumper wires with a voltage shifter in between them using the Arduino's and Pi's GPIO TX and RX pins.
using python -V in the terminal it tells me I'm running version 3.8
I've tried multiple baud rates(300, 1200, 9600, 57600) with no change in behavior
I've also tried changing if x == 11: to if x == "11": in case for some reason it was receiving strings and not ints, also to no avail.
Here is the code:
import time
import serial
ser = serial.Serial(
port='/dev/ttyAMA0',
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=None
)
print("sending data over serial now")
ser.write("a10") #a10 is relay HIGH code
while True:
x = ser.read()
if x == 11: ##arduino code 11(asking for how long)
print("recieved code 11")
print("arduino recieved relay HIGH code and is waiting for time to hold relay for")
print("sending time now")
ser.write('a5') # 5 seconds
time.sleep(1)
if x == 13: #arduino code 13(water success)
print("recieved code 13")
print("arduino reports watering complete")
x = 0 ##this is to clear the variable every loop. Not sure if it's needed
And here is a simple serial reader I've pulled from online. Opening it up in a second terminal and running it at the same time with my own script it will actually read the codes from the arduino business as usual.
#!/usr/bin/env python
import time
import serial
ser = serial.Serial(
port='/dev/ttyAMA0',
baudrate = 57600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1
)
while True:
x=ser.readline()
print x
What gives?
Answering my own question. In the arduino code I used
Serial.println(whatevergoeshere)
instead of
Serial.print(whatevergoeshere)
So the arduino was sending out '\n' at the end of every serial line that was not being printed by either the arduino serial console and the python script. Updating my IF statements in python to
if x == "11\n":
Solves the issue and everything works as intended.
I am trying to receive GPS data from my HC-05 bluetooth module.
I can see complete data in any serial plotter program, however I need to use Python executable for my Raspberry PI.
I have tried below code that I found from internet;
"""
A simple Python script to receive messages from a client over
Bluetooth using PyBluez (with Python 2).
"""
import bluetooth
hostMACAddress = 'C8:09:A8:56:11:EC' # The MAC address of a Bluetooth adapter on the server. The server might have
# multiple Bluetooth adapters.
port = 9
backlog = 1
size = 1024
s = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
s.bind((hostMACAddress, port))
s.listen(backlog)
try:
client, clientInfo = s.accept()
while 1:
data = client.recv(size)
if data:
print(data)
client.send(data) # Echo back to client
except:
print("Closing socket")
client.close()
s.close()
However It gives me error below, for the line "s.bind((hostMACAddress, port))". I have run "ipconfig /all" in cmd window to see bluetooth adapter MAC Adress, and checked advanced settings in "bluetooth devices" of my computer to find corresponding port.
Other problem I suspect is that I am using Python 3.8 while in comment area it says written with Python 2. I am not sure if 3.xx is backward backward compatible with 2.xx.
C:\Users\aliul\PycharmProjects\pythonProject\venv\Scripts\python.exe C:/Users/aliul/PycharmProjects/pythonProject/main.py
Traceback (most recent call last):
File "C:/Users/aliul/PycharmProjects/pythonProject/main.py", line 14, in <module>
s.bind((hostMACAddress, port))
File "C:\Users\aliul\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\bluetooth\msbt.py", line 84, in bind
bt.bind (self._sockfd, addr, port)
OSError: G
I am new to python and any help would be highly appreciated!
Thanks.
I've figured out recieving data importing "serial" package instead of "bluetooth" of pybluez. Source code is below, all you need to do is to find the serial port adress of your socket and setting baudrate, timeout, parity and stopbits parameters according to the bluetooth module you have!
import serial
serialPort = serial.Serial(port='COM8', baudrate=9600, timeout=0, parity=serial.PARITY_EVEN, stopbits=1)
size = 1024
while 1:
data = serialPort.readline(size)
if data:
print(data)
I have a windows 7 os pc, using pyserial in python3.6 to talk to an embedded board with a debian Jessie os that is using pyserial python 3.6 to listen. The cable between the two is a USB to UART bridge controller from a microUSB port on the board to a USB port on the pc. These are my scripts:
PC:
import serial
ser = serial.Serial('COM5')
ser.baudrate = 115200
ser.bytesize = 8
ser.parity = 'N'
ser.stopbits = 1
data = bytearray(b'A')
No = ser.write(data)
ser.close()
BOARD:
import serial
ComPort = serial.Serial('dev/ttyS0')
ComPort.baudrate = 115200
ComPort.bytesize = 8
ComPort.parity = 'N'
ComPort.stopbits = 1
data = ComPort.read(1)
print(data)
ComPort.close()
THE PROBLEM:
I run the script on the board first, it will run and wait without incident until I run the script on the pc. Once I run the pc script, it takes a second or two for the error in the title to pop up on the board and stop the script. There are no errors on the pc side, and the script runs and finishes in less than a second.
I am connected to the board via putty ssh on the pc. I need to be able to send commands and files between these two via this serial connection. Any help or working examples would be a great help. Is there a problem with using pyserial on both the sender and receiver?