Unable to read data from serial port - python

I tried to read data from USB port on OSX using pyserial. When I tried to read it using CoolTerm, everything worked fine. This is the configuration:
Then I tried to write a short script which doesn't continuously output the data (it outputs the data only once and the even if I restart the script, nothing comes out):
import serial
import time
ser = serial.Serial("/dev/cu.SLAB_USBtoUART", 115200, timeout=5, bytesize=8, stopbits=serial.STOPBITS_ONE, parity=serial.PARITY_NONE)
def getTFminiData():
while True:
# time.sleep(0.1)
count = ser.in_waiting
if count > 8:
recv = ser.read(9)
ser.reset_input_buffer()
if recv[0] == 0x59 and recv[1] == 0x59: # python3
distance = recv[2] + recv[3] * 256
strength = recv[4] + recv[5] * 256
print('(', distance, ',', strength, ')')
ser.reset_input_buffer()
if __name__ == '__main__':
try:
if ser.is_open == False:
ser.open()
getTFminiData()
except KeyboardInterrupt: # Ctrl+C
if ser != None:
ser.close()
Does anyone know what is the right way to get the same data as CoolTerm in this case does?

Thanks to Joe's comment, I fuggered out how to modify the code. The working example is the following:
import serial
import time
ser = serial.Serial("/dev/cu.SLAB_USBtoUART", 115200, bytesize=8, stopbits=serial.STOPBITS_ONE, parity=serial.PARITY_NONE)
def getTFminiData():
bytes_read = 0
data = None
while True:
# time.sleep(0.1)
count = max(1, ser.in_waiting)
if count < 8:
if data is None:
data = ser.read(count)
else:
data.append(ser.read(count))
bytes_read += count
else:
recv = ser.read(9 - bytes_read)
bytes_read = 0
recv = data + recv
data = None
ser.reset_input_buffer()
if recv[0] == 0x59 and recv[1] == 0x59: # python3
distance = recv[2] + recv[3] * 256
strength = recv[4] + recv[5] * 256
print('(', distance, ',', strength, ')')
ser.reset_input_buffer()
if __name__ == '__main__':
try:
if ser.is_open == False:
ser.open()
getTFminiData()
except KeyboardInterrupt: # Ctrl+C
if ser != None:
ser.close()

Related

How do I combine these two python scripts?

Currently having problems combining two of my codes into one. Code 1 prints out GPS data continuously, but once I add Code 2 it only prints out once. I suspect the while-loop might be the problem but I don't know for sure.
Any help would be appreciated :)
Combined code:
import os
import sys
import time
import serial
import datetime
from gps import *
ser = serial.Serial(
port = '/dev/ttyS0',
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS,
timeout = 1
)
moment = time.strftime("%d-%m-%Y %H:%M",time.localtime())
try:
gpsd = gps(mode=WATCH_ENABLE)
except:
print('ERROR: Cannot set time')
sys.exit()
while True:
gpsd.next()
if gpsd.utc != None and gpsd.utc != '':
gpsutc = gpsd.utc[0:4] + gpsd.utc[5:7] + gpsd.utc[8:10] + ' ' + gpsd.utc[11:19]
os.system('sudo date -u --set="%s"' % gpsutc)
sys.exit()
if ser.in_waiting > 0:
x = ser.readline().decode('utf-8')
file = open('GPS ' + moment + '.txt', "a")
file.write(datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S.%f")[:-3] + " ")
file.write(str(x))
file.close()
print(datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S.%f ")[:-3])
print(x)
Code 1 (collects GPS data and stores to text files):
import time
import serial
import datetime
ser = serial.Serial(
port = '/dev/ttyS0',
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS,
timeout = 1
)
moment = time.strftime(%d-%m-%Y %H:%M", time.localtime())
while True:
if ser.in_waiting > 0:
x = ser.readline().decode('utf-8')
file = open('GPS ' + moment + '.txt', "a")
file.write(datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S.%f)[:-3] + " ")
file.write(str(x))
file.close()
Code 2 (Sets Raspberry Pi time to equal GPS time):
import os
import sys
import time
from gps import *
try:
gpsd = gps(mode=WATCH_ENABLE)
except:
print('ERROR: Cannot set time')
sys.exit()
while True:
gpsd.next()
if gpsd.utc != None and gpsd.utc != '':
gpsutc = gpsd.utc[0:4] + gpsd.utc[5:7] + gpsd.utc[8:10] + ' ' + gpsd.utc[11:19]
os.system('sudo date -u --set="%s"' % gpsutc)
sys.exit()
I don't own GPS hardware, so i cannot verify, but the second sys.exit() in the combined code stings my eye:
I assume the corresponding sys.exit() in code 2 just ends the script once the time could be read successfully - which makes sense.
But in the combined script, it will still end the whole script.
My first idea was to remove it, but then you will re-set the system time quite often which might cause further issues; maybe it is better keep two loops in the combined script, just replacing that one sys.exit() by break. Something like:
import os
import sys
import time
import serial
import datetime
from gps import *
ser = serial.Serial(
port = '/dev/ttyS0',
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS,
timeout = 1
)
moment = time.strftime("%d-%m-%Y %H:%M",time.localtime())
try:
gpsd = gps(mode=WATCH_ENABLE)
except:
print('ERROR: Cannot set time')
sys.exit()
while True:
gpsd.next()
if gpsd.utc != None and gpsd.utc != '':
gpsutc = gpsd.utc[0:4] + gpsd.utc[5:7] + gpsd.utc[8:10] + ' ' + gpsd.utc[11:19]
os.system('sudo date -u --set="%s"' % gpsutc)
break
while True:
if ser.in_waiting > 0:
x = ser.readline().decode('utf-8')
file = open('GPS ' + moment + '.txt', "a")
file.write(datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S.%f")[:-3] + " ")
file.write(str(x))
file.close()
print(datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S.%f ")[:-3])
print(x)

Is there a way to sync up live audio and live video using Python?

I am trying to write a bit of code to create a 2 person live chat application using Python 3. The code is working in the sense of having live audio and live video, (as tested by running the server and 2 clients on the same device), with the Client-Side code running most of the logic and running the camera and audio feeds to send through the server, (which also works as a form of handshake between the 2 clients with little logic aside from if a client sends video and/or audio to send it to the other client), to have the client-side code to get the audio and video to play.
fair warning, this code is a bit messy and is not optimized for fast performance
Client-Side Code:
import cv2
from socket import socket, AF_INET, SOCK_STREAM
from imutils.video import WebcamVideoStream
import pyaudio
from array import array
from threading import Thread
import numpy as np
import zlib
import struct
HOST = input("Enter Server IP\n")
PORT_VIDEO = 3000
PORT_AUDIO = 4000
BufferSize = 4096
CHUNK=1024
lnF = 640*480*3
FORMAT=pyaudio.paInt16
CHANNELS=2
RATE=44100
def SendAudio():
while True:
data = stream.read(CHUNK)
dataChunk = array('h', data)
vol = max(dataChunk)
clientAudioSocket.sendall(data)
def RecieveAudio():
while True:
data = recvallAudio(BufferSize)
stream.write(data)
def recvallAudio(size):
databytes = b''
while len(databytes) != size:
to_read = size - len(databytes)
if to_read > (4 * CHUNK):
databytes += clientAudioSocket.recv(4 * CHUNK)
else:
databytes += clientAudioSocket.recv(to_read)
return databytes
def SendFrame():
while True:
try:
frame = wvs.read()
cv2_im = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = cv2.resize(frame, (640, 480))
frame = np.array(frame, dtype = np.uint8).reshape(1, lnF)
jpg_as_text = bytearray(frame)
databytes = zlib.compress(jpg_as_text, 9)
length = struct.pack('!I', len(databytes))
bytesToBeSend = b''
clientVideoSocket.sendall(length)
while len(databytes) > 0:
if (5000 * CHUNK) <= len(databytes):
bytesToBeSend = databytes[:(5000 * CHUNK)]
databytes = databytes[(5000 * CHUNK):]
clientVideoSocket.sendall(bytesToBeSend)
else:
bytesToBeSend = databytes
clientVideoSocket.sendall(bytesToBeSend)
databytes = b''
# ~ print("##### Data Sent!! #####")
except:
continue
def RecieveFrame():
while True:
try:
lengthbuf = recvallVideo(4)
length, = struct.unpack('!I', lengthbuf)
databytes = recvallVideo(length)
img = zlib.decompress(databytes)
if len(databytes) == length:
# ~ print("Recieving Media..")
# ~ print("Image Frame Size:- {}".format(len(img)))
img = np.array(list(img))
img = np.array(img, dtype = np.uint8).reshape(480, 640, 3)
cv2.imshow("Stream", img)
if cv2.waitKey(1) == 27:
cv2.destroyAllWindows()
else:
print("Data CORRUPTED")
except:
continue
def recvallVideo(size):
databytes = b''
while len(databytes) != size:
to_read = size - len(databytes)
if to_read > (5000 * CHUNK):
databytes += clientVideoSocket.recv(5000 * CHUNK)
else:
databytes += clientVideoSocket.recv(to_read)
return databytes
clientVideoSocket = socket(family=AF_INET, type=SOCK_STREAM)
clientVideoSocket.connect((HOST, PORT_VIDEO))
wvs = WebcamVideoStream(0).start()
clientAudioSocket = socket(family=AF_INET, type=SOCK_STREAM)
clientAudioSocket.connect((HOST, PORT_AUDIO))
audio=pyaudio.PyAudio()
stream=audio.open(format=FORMAT,channels=CHANNELS, rate=RATE, input=True, output = True,frames_per_buffer=CHUNK)
initiation = clientVideoSocket.recv(5).decode()
if initiation == "start":
SendFrameThread = Thread(target=SendFrame).start()
SendAudioThread = Thread(target=SendAudio).start()
RecieveFrameThread = Thread(target=RecieveFrame).start()
RecieveAudioThread = Thread(target=RecieveAudio).start()
Server-Side Code:
from socket import socket, AF_INET, SOCK_STREAM
from threading import Thread
import struct
HOST = input("Enter Host IP\n")
PORT_VIDEO = 3000
PORT_AUDIO = 4000
lnF = 640*480*3
CHUNK = 1024
BufferSize = 4096
addressesAudio = {}
addresses = {}
threads = {}
def ConnectionsVideo():
while True:
try:
clientVideo, addr = serverVideo.accept()
print("{} is connected!!".format(addr))
addresses[clientVideo] = addr
if len(addresses) > 1:
for sockets in addresses:
if sockets not in threads:
threads[sockets] = True
sockets.send(("start").encode())
Thread(target=ClientConnectionVideo, args=(sockets, )).start()
else:
continue
except:
continue
def ConnectionsSound():
while True:
try:
clientAudio, addr = serverAudio.accept()
print("{} is connected!!".format(addr))
addressesAudio[clientAudio] = addr
Thread(target=ClientConnectionSound, args=(clientAudio, )).start()
except:
continue
def ClientConnectionVideo(clientVideo):
while True:
try:
lengthbuf = recvall(clientVideo, 4)
length, = struct.unpack('!I', lengthbuf)
recvall(clientVideo, length)
except:
continue
def ClientConnectionSound(clientAudio):
while True:
try:
data = clientAudio.recv(BufferSize)
broadcastSound(clientAudio, data)
except:
continue
def recvall(clientVideo, BufferSize):
databytes = b''
i = 0
while i != BufferSize:
to_read = BufferSize - i
if to_read > (1000 * CHUNK):
databytes = clientVideo.recv(1000 * CHUNK)
i += len(databytes)
broadcastVideo(clientVideo, databytes)
else:
if BufferSize == 4:
databytes += clientVideo.recv(to_read)
else:
databytes = clientVideo.recv(to_read)
i += len(databytes)
if BufferSize != 4:
broadcastVideo(clientVideo, databytes)
# ~ print("YES!!!!!!!!!" if i == BufferSize else "NO!!!!!!!!!!!!")
if BufferSize == 4:
broadcastVideo(clientVideo, databytes)
return databytes
def broadcastVideo(clientSocket, data_to_be_sent):
for clientVideo in addresses:
if clientVideo != clientSocket:
clientVideo.sendall(data_to_be_sent)
def broadcastSound(clientSocket, data_to_be_sent):
for clientAudio in addressesAudio:
if clientAudio != clientSocket:
clientAudio.sendall(data_to_be_sent)
serverVideo = socket(family=AF_INET, type=SOCK_STREAM)
try:
serverVideo.bind((HOST, PORT_VIDEO))
except OSError:
print("Server Busy")
serverAudio = socket(family=AF_INET, type=SOCK_STREAM)
try:
serverAudio.bind((HOST, PORT_AUDIO))
except OSError:
print("Server Busy")
serverAudio.listen(2)
print("Waiting for audio connection..")
AcceptThreadAudio = Thread(target=ConnectionsSound)
AcceptThreadAudio.start()
serverVideo.listen(2)
print("Waiting for video connection..")
AcceptThreadVideo = Thread(target=ConnectionsVideo)
AcceptThreadVideo.start()
AcceptThreadVideo.join()
serverVideo.close()
Both of these codes are what I have put together in a bit longer of time than I would have liked, but I noticed when doing a bit of testing with these codes that the audio and video were off by anywhere between 3 and 7 seconds. I tried a bit of troubleshooting but couldn't find any issues with the code, aside from the fact that it looks like a kid threw it all together. I am fine with importing a new Python package, but I would prefer to use the Python Packages that I already have in place. Keep in mind I am thinking about eventually converting both the codes into separate .exe files to allow for easy access to send the codes to individual people.

Serial Communication with any GPIO of Raspberry Pi

I need to connect a serial device to gpio pin of a raspberry pi. My UART port is already used. For that, I need a simple code which can convert any gpio like Tx and Rx pin. I wrote a code but it could not receive data properly at higher baudrate.
My simple code of myuart is:
import RPi.GPIO as GPIO
import time,threading
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
baudrate = OneBitDelay = timeout = Tx = Rx = timeout_exit = False
def begin(tx=2,rx=3,Baudrate=9600,Timeout=float('inf')):
global Tx,Rx,baudrate,OneBitDelay,timeout
Tx = tx
Rx = rx
baudtate = Baudrate
timeout = Timeout
GPIO.setup(Tx, GPIO.OUT, pull_up_down=GPIO.PUD_UP)
GPIO.setup(Rx, GPIO.IN, pull_up_down=GPIO.PUD_UP)
OneBitDelay = 1/baudrate
def setBaudrate(BaudRate):
global Baudrate,OneBitDelay
Baudrate = BaudRate
OneBitDelay = 1/Baudrate
def mytimer():
global timeout_exit
timeout_exit = True
def read(byte = 0):
global Tx,Rx,OneBitDelay,timeout,timeout_exit
data_array = ""
if timeout != float('inf'):
timer = threading.Timer(timeout, mytimer)
timer.start()
while GPIO.input(Rx):
if timeout_exit:
timeout_exit = False
return None
data = readValue = ""
if byte == 0:
while True:
time.sleep(OneBitDelay/baudrate) ## I think synchronization problem arries due to this delay
for count in range(0,8):
readValue = readValue + str(GPIO.input(Rx))
time.sleep(OneBitDelay)
if readValue != "11111111":
print("Received binary ",readValue)
data = data + chr(int(readValue, 2))
readValue = ""
else:
return data
else:
for r in range(0,int(byte/8)):
for count in range(0,8):
readValue = readValue + str(GPIO.input(Rx))
time.sleep(OneBitDelay)
data = data + chr(int(readValue, 2))
readValue = ""
return(data)
def write(data):
global OneBitDelay
if type(data) == int:
data = str(data)
data = getbinarystring(data)
dataTemp =""
for r in range(0,data.count(" ")+1):
dataTemp = dataTemp + data.split()[r].zfill(8)
for sendBit in range(0,len(dataTemp)):
GPIO.output(Tx, int(dataTemp[sendBit]))
time.sleep(OneBitDelay)
GPIO.output(Tx, True)
time.sleep(.005) ## I think synchronization problem aeries due to this delay
def getbinarystring(data):
return ' '.join(format(ord(x), 'b') for x in data)
Then I wrote a simple read.py and write.py code to transmit and receive data. but I am not getting whatever I send. also I am getting different data at different time. at lower baudrate this code works but at higher baudrate it's not working.
what are the mistakes I am making?? please help to improve synchronization.
for any kind of help thanks in advance.
write.py
import myuart,time
myuart.begin(tx=4,rx =17,Baudrate = 9600)
while True:
myuart.write("hello")
time.sleep(1)
read.py
import myuart,time
myuart.begin(tx=4,rx =17,Baudrate = 9600)
while True:
print myuart.read()

Python Serial: having trouble reading the port

I'm attempting to read the values of some GPIO. Here's the code:
import serial
import codecs
import time
ser = serial.Serial(port = 'COM4', baudrate = 9600, \
parity = serial.PARITY_NONE, \
stopbits = serial.STOPBITS_ONE, \
bytesize = serial.EIGHTBITS, \
timeout = 0, \
)
print('connected to: ',ser.name)
ser.close()
def SSend(input):
ser.write(codecs.decode(input, "hex_codec")) #send as ASCII
print('sent: ', input)
def ReadIO():
#open the port
try:
ser.open()
except:
print('error opening serial port')
exit()
#flush the buffers
ser.flushInput()
ser.flushOutput()
#write data to read from GPIO
#causes SC18IM to return a byte containing each of the 8 I/O values
SSend(b'4950')
time.sleep(0.1) #allow time for the data to be received
#read the data
serialData = False
serialData = ser.readline()
ser.close()
return serialData
while 1:
print(ReadIO())
time.sleep(0.5)
This prints the following:
sent:
b'4950'
b''
(I am expecting back either 0x00 or 0x20 instead of an empty byte)
I know my hardware is good as is what I'm sending because it get back what I expect when using Realterm and have successful write commands in my script elsewhere.
I had some luck using this
#read the data
serialData = False
for c in ser.readline():
print('in loop')
print(c)
serialData = c
ser.close()
However, I don't really understand why it worked and it only appears to work intermittently.
Thanks for reading.
readline() assumes that there is some end-of-line symbol, like \n or \r. You should read data byte-wise:
serialData = ''
while ser.inWaiting() > 0:
c=ser.read(1)
# or c=ser.read(1).decode('latin1')
serialData += c

Python UART between 2 Raspberry Pis

I'm trying to send strings between two Raspberry Pis via UART. So far, one Pi is able to transmit a string and the second pi is only able to receive. I'm trying send a "command" from one Pi to the other, then the second Pi will receive the "command" and then send "sensor data" back to the first Pi. However, this doesn't seem to work. I'm unable to both send and receive data.
Any help would be greatly appreciated.
The Raspberry Pi that is sending the command:
import serial
ser = serial.Serial(
port = '/dev/ttyAMA0',\
baudrate = 115200,\
bytesize = serial.EIGHTBITS,\
timeout = 0)
dat = ''
while True:
#asks user for input
command = raw_input()
#terminates command with null
ser.write(command + '\0')
#reads data per char
for c in ser.read():
#appends string
dat += c
#terminates at null char
if c == '\0':
print(dat)
dat = ''
break
ser.close()
This RPi that receives command and then sends sensor data:
import serial
ser = serial.Serial(
'/dev/ttyAMA0' ,\
baudrate = 115200 ,\
bytesize = serial.EIGHTBITS ,\
timeout = 0)
dat = ''
sen1 = 'sen1\x00'
sen2 = 'sen2\x00'
com1 = 'hello'
com2 = 'this thing works!'
com3 = 'error!'
while True:
#reads data per char
for c in ser.read():
#appends string
dat += c
#terminates at null char
if c == '\0':
#decides which sensor to choose
if dat == sen1:
print(com1)
ser.write(com1 + '\0')
dat = ''
break
elif dat == sen2:
print(com2)
ser.write(com2 + '\0')
dat = ''
break
else:
print(com3)
ser.write(com3 + '\0')
dat = ''
ser.close()
The cause is most likely your zero timeout. You've set read() to non-blocking as a result, so your sender Pi's for loops will most likely read nothing (or only a byte) and will terminate before everything's arrived. Also iterating over ser.read() doesn't really make sense since it returns only a byte anyway by default.
Increase timeout to some non-zero value.
ser = serial.Serial(
'/dev/ttyAMA0' ,\
baudrate = 115200 ,\
bytesize = serial.EIGHTBITS ,\
timeout = 0.1)
Assuming you want the response to a command received, before another command is sent, this should work for the sender:
while True:
#asks user for input
command = raw_input()
#terminates command with null
ser.write(command + '\0')
dat = []
lastRead = time.time()
while time.time() - lastRead < 0.1:
while ser.inWaiting() > 0:
dat.append(ser.read())
lastRead = time.time()
if dat and (dat[-1] == '\0'):
print(''.join(dat[:-1]))
If 100ms or more passes before another byte is available, the while loop breaks and the last received byte is checked to know if its a null byte. Something similar should work for your receiver:
while True:
dat = []
lastRead = time.time()
while time.time() - lastRead < 0.1:
while ser.inWaiting() > 0:
dat.append(ser.read())
lastRead = time.time()
dat = ''.join(dat)
# begin your comparisons here

Categories

Resources