Using Python to read a nonfixed number of bytes through Serial - linux

I am trying to read a nonfixed number of bytes from the Serial port. I can use read to read a fixed number of bytes, putting in a larger number than the actual number of bytes present, will cause it to wait forever. Putting in a smaller number than the actual number of bytes present will crop some of the characters out. Using read_all, the output seems to be blank. Readline() is yielding syntax error. I ran out of ideas, any ideas? Here is my code:
import time
import datetime
import serial
import os
# public variables
sensors = [] # list of sensor readings
wait = True
sensor_count = 10 # the zero based count of sensors
def pwr_solenoid(solenoid0=0, solenoid1=0, solenoid2=0, solenoid3=0):
# Defaults are for low signal values
# compile output
output = '9{solenoid0}{solenoid1}{solenoid2}{solenoid3}' \
.format(solenoid0=solenoid0, solenoid1=solenoid1, solenoid2=solenoid2, solenoid3=solenoid3).encode()
with serial.Serial('/dev/ttyACM0', baudrate=9600) as ser:
print("created connection to '/dev/ttyACM0'\n")
print("going to send:\t'{}'".format(output))
ser.write(output)
ser.reset_output_buffer()
# for testing to console
print("Value sent to the uC:\t'{}'".format(output.decode()))
# ***** READ from UART *****
#ser.in_waiting >= 12:
raw = ser.read(16)
print("printing raw value of ser.read(16)\n")
print(raw)
val = str(ser.read_all().decode()) # (3).decode()[2:])
#printing val
print("\n printing val using read_all \n")
print(val)
val1 = raw.decode()
#printing val of raw.decode()
print("\n pringting val of raw.decode() \n")
print(val1)
# print("printing value of ser.readline()\n"
# serreadlin = ser.readline() This line generates an error cannot use readline()
# print(serreadlin)
# print("printing val\n")
# print(val)
# exit()

You can use:
import serial
import time
ser = serial.Serial(port='/dev/ttyUSB0', baudrate=115200, timeout=1)
while True:
val = ser.readline().strip()
if(val):
print (val)

Related

How to properly save temperature readings from thermal camera in CSV file, time vs. readings in one row

This code is for MLX90640 infrared thermal camera. It plots a real-time temperature map across 768 (24x32) pixels using a Raspberry Pi that operates at roughly 1 frame per second. It also saves temperature data in CSV file. it wrights row per second where column A time (HH:MM:SS) then 768 readings from column "B" to column "ACN" but the problem is data in the first and last columns are mixed with double quotes and brackets e.g column "A" is 18:03:38 "[39.1 and column "ACN" is 36.8]" I used pop method and del method to delete " [ ] " but both shows out of index range. Any idea what cause this problem.
import RPi.GPIO as GPIO
import time,board,busio
import numpy as np
import adafruit_mlx90640
import matplotlib.pyplot as plt
from adafruit_blinka import Enum, Lockable, agnostic
import csv
import datetime
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) # setup I2C for thermal camera
thermal_mapfile = str(datetime.datetime.now().date()) + '_' + str(datetime.datetime.now().time()).replace(':', '.')
thermal_mapfile = thermal_mapfile[:16] #limit thermal file name to 16 characters
print("Thermal cam is ON")
mlx = adafruit_mlx90640.MLX90640(i2c) # begin MLX90640 with I2C comm
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_2_HZ # set refresh rate 2Hz
mlx_shape = (24,32)
print("Initialized")
# setup the figure for plotting
plt.ion() # enables interactive plotting
fig,ax = plt.subplots(figsize=(12,7))
therm1 = ax.imshow(np.zeros(mlx_shape),vmin=0,vmax=60) #start plot with zeros
cbar = fig.colorbar(therm1) # setup colorbar for temps
cbar.set_label('Temperature [$^{\circ}$C]',fontsize=14) # colorbar label
t_array = []
frame = [0] * 768
t1 = time.monotonic()
while True:
try:
mlx.getFrame(frame) # read MLX temperatures into frame var
data_array = (np.reshape(frame,mlx_shape)) # reshape to 24x32
therm1.set_data(np.fliplr(data_array)) # flip left to right
therm1.set_clim(vmin=np.min(data_array),vmax=np.max(data_array)) # set bounds
cbar.update_normal(therm1) # update colorbar range
plt.title(f"Max Temp: {np.max(data_array):.1f}C")
plt.pause(0.001) # required
t_array.append(time.monotonic()-t1)
except ValueError:
continue # if error, just read again
for h in range(24):
for w in range(32):
t = frame[h*32 + w]
frame = list(np.around(np.array(frame),1)) #round array elements to one decimal point
with open("/home/pi/Thermal_Camera/"+thermal_mapfile+".csv","a") as thermalfile:
writer = csv.writer(thermalfile,delimiter=" ")
unix_time = time.time()
formatted_time = datetime.datetime.fromtimestamp(unix_time).strftime('%H:%M:%S')
writer.writerow([formatted_time,frame])
An example of what I am talking about:
import csv
import datetime
hdrs = ['dt','a', 'b', 'c']
data_list = [1, 2, 3]
#Case 1, passing a list directly.
with open('csv_list_test.csv', 'w') as csv_file:
csv_writer = csv.writer(csv_file, delimiter='|')
csv_writer.writerow(hdrs)
csv_writer.writerow([datetime.datetime.now().isoformat(), data_list])
cat csv_list_test.csv
dt|a|b|c
2023-01-24T17:17:44.961821|[1, 2, 3]
# Case 2, unpack list.
with open('csv_list_test.csv', 'w') as csv_file:
csv_writer = csv.writer(csv_file, delimiter='|')
csv_writer.writerow(hdrs)
csv_writer.writerow([datetime.datetime.now().isoformat(), *data_list])
cat csv_list_test.csv
dt|a|b|c
2023-01-24T17:18:32.337160|1|2|3
I use a delimiter that makes it easy to distinguish the columns. delimiter=" " is not a good idea.
In Case 1 you can see that the list is all in column a.
In Case 2 unpacking(*data_list) the list puts the individual elements in the appropriate columns.

how do i strip down a tuple from sqlite so i can use it as a float in python?

i am trying to use a single data reading from a sqlite3 file it is returned to me in the following way (25.5,) format. my next part of the script i want to be able to trigger a GPIO pin output to turn on a relay when the temperature drops below a certain point and off again once it gets above another point. my code is as follows
import RPi.GPIO as GPIO
import time
import sqlite3
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
#GPIO.setup(18, GPIO.OUT)
# Set up all variables #
temp_min = 25.375
temp_max = 25.5
#############
# Main Loop #
#############
while True:
def display_5sec_data():
conn = sqlite3.connect('ds18b20.db')
c = conn.cursor()
c.execute("SELECT (display1) FROM aquarium2 ORDER BY rowid DESC LIMIT 1")
data1 = c.fetchone()
conn.close()
#return data1
print(data1)
Display = display_temp()
data1= (display_5sec_data())
if data1 <= 25.25 : # if temp is less or equal to 25 deg
print("heater on")
#GPIO.output(18, GPIO.HIGH)
if data1 >= 25.80 :
print("heater off")
#GPIO.output(18, GPIO.LOW)
time.sleep(10)
display_5sec_data()
any help would be great.
Sorted was an easy fix just wished i had played a little bit more with it. i just need to add float to the if statement
here is the code.
if float(data1[0]) >= 25.60 :
print("heater off")
bus.write_pin(11, 0)
bus.write_pin(10, 0)
time.sleep(120)

Remove Carriage Return from the final print statement

import re
import sys
def isValid(s):
pattern_= re.compile("[12][\d]{12}$")
return pattern_.match(s)
loop = int(input ())
output=[]
for _ in range(0, loop):
ele = int(input())
output.append(ele)
entries = ''
for x in output :
entries += str(x)+ ''
print (output ) #['0123456789012']
print (entries ) #0123456789012
print(type(entries )) #str
print(type(output )) #list
# Driver Code
for _ in range(loop):
for x in entries:
if (isValid(x)):
sys.stdout.write ("Valid Number")
break
else :
sys.stdout.write ("Invalid Number")
break
Phones Numbers starts with the digit 1 or 2 followed by exactly 12 digits i.e Phones Numbers comprises of 13 digits.
For each Phone Number, print "Valid" or "Invalid" in a new line.
The list is taking wrong input
The output generated is,
2
0123456789012
1123456789012
[123456789012, 1123456789012]
123456789012 1123456789012
<class 'str'>
<class 'list'>
Invalid NumberInvalid Number
[Program finished]
Also, I have searched on stack before posting. This looked different issue. If anything matches the error on stack please redirect me there.
2
1123456789012
0123456778901
Valid Number
Invalid Number
[Program finished]
This is what it should look like
import re
def isValid(s):
pattern_= re.compile(r'[1|2][0-9]{12}$')
return pattern_.match(s)
loop = int(input())
# no of times loops to run
output = []
for _ in range(0, loop):
output.append(input())
entries = ''
for x in output :
entries += x + ''
result = []
# Driver Code
for val in output:
if isValid(val):
result.append('Valid Number')
else:
result.append ('Invalid Number')
for i in range(len(result )-1):
print(result[i])
print(result[-1], end = " ")
This should work too.
print first converts the object to a string (if it is not already a string). It will also put a space before the object if it is not the start of a line and a newline character at the end.
When using stdout, you need to convert the object to a string yourself (by calling "str", for example) and there is no newline character.
May I also suggest to rephrase your question as it's not a logic issue but a syntax issue.
Comment:
Checked with single and multiple inputs.
Works.
Try using the below regex
def is_valid(s):
pattern_= re.compile(r'[1|2][0-9]{12}$')
return pattern_.match(s)
I am not sure, why you are appending the numbers to the entities variable. I have changed the code a bit and the regex is working fine.
def is_valid(s):
pattern_= re.compile(r'[1|2][0-9]{12}$')
return pattern_.match(s)
loop = int(input())
output = []
for _ in range(0, loop):
output.append(input())
entries = ''
for x in output :
entries += x + ''
print (output ) # ['0123456789012']
print (entries ) # 0123456789012
print(type(entries )) # str
print(type(output )) # list
# Driver Code
for val in output:
if isValid(val):
print('Valid Number')
else:
print('Invalid Number')
Input:
5
1234567891234
1893456879354
2897347838389
0253478642678
6249842352985
Output:
['1234567891234', '1893456879354', '2897347838389', '0253478642678', '6249842352985']
12345678912341893456879354289734783838902534786426786249842352985
<class 'str'>
<class 'list'>
Valid Number
Valid Number
Valid Number
Invalid Number
Invalid Number
import sys
import re
def isValid(s):
pattern_= re.compile(r'[1|2][0-9]{12}$')
return pattern_.match(s)
loop = int(input())
output = []
for _ in range(0, loop):
output.append(input())
entries = ''
for x in output :
entries += x + ''
print (output ) # ['0123456789012']
print (entries ) # 0123456789012
print(type(entries )) # str
print(type(output )) # list
# Driver Code
for val in output:
if isValid(val):
sys.stdout.write('Valid Number')
else:
sys.stdout.write('Invalid Number')
produces
1
1234567891234
['1234567891234']
1234567891234
<class 'str'>
<class 'list'>
Valid Number
[Program finished]
print always returns carriage.
Whereas sys.stdout.write doesn't.
The challenge was resolved hence.

How to avoid MPU9250 FIFO overflow?

I'm now working with mpu9250 for my master thesis, but I'm quite new to hardware device. My goal is to collect the data at the sample rate and postprocess these data via allan deviation. So I just want to get the data from 512 bytes fifo, but when I'm trying to read out the data, it always overflows which annoying me a lot.
I know the method is to set the reading speed faster than the fifo writing speed, so I remove the time sleep in my loop, but it seems overflows sooner than before. I'm a little bit confused, because the reading speed depends on the writing speed.
#!/usr/bin/env python3
import os
import time
import sys
import struct
import csv
from datetime import datetime
from mpu9250_FIFO import MPU9250
from navio.leds import Led
def main():
# Initialize MPU9250
mpu = MPU9250()
mpu.bus_open(max_speed_hz=10000000) # Hz
sampleRate = 50
sampleRateDiv = int(1000 / sampleRate - 1)
mpu.initialize(sample_rate_div=sampleRateDiv, low_pass_filter_gt=0x01, low_pass_filter_a=0x01)
mpu.set_acc_scale(0x08) # +/-4G
mpu.set_gyro_scale(0x08) # +/-500dps
# Enable FIFO to collect data
mpu.enableFIFO(True)
# Test connection:
if mpu.testConnection():
print("Connection working.")
else:
print("Connection to one of the sensors is faulty.")
now = datetime.now().strftime('%d-%m-%Y_%H:%M:%S')
fname = '/home/pi/Python/meas_data/mpu9250_data_' + now + r'.txt'
with open(fname, 'w', 1) as data_imu:
# write headers to file
data_imu.write('Sample Rate: %d Hz\n' % sampleRate)
data_imu.write('mpu_accel_1, mpu_accel_2, mpu_accel_3, mpu_gyro_1, mpu_gyro_2, mpu_gyro_3, temp\n')
#print("----1----")
# Main loop
while True:
mpudata_a, mpudata_g, mpudata_temp = mpu.getFIFOData()
#print("----2----")
data = mpudata_a + mpudata_g + mpudata_temp
# print(data)
data_imu.write(str(data).replace("[", "").replace("]", "") + "\n")
# FIFO READ AND WRITE
# FIFO_R_W REGISTER:
# This register is used to read and write data from the FIFO buffer. Data is written to the FIFO
# in order of register number (from lowest to highest). If all the FIFO enable flags are enabled
# and all External Sensor Data registers (Registers 73 to 96) are associated with a Slave device,
# the contents of registers 59 through 96 will be written in order that the Sample Rate.
# The contents of the sensor data registers (Registers 59 to 96) are written into the FIFO buffer
# when their corresponding FIFO enable flags are set to 1 in FIFO_EN (Register 35). An additional
# flag for the sensor data registers associated with I2C Slave 3 can be found in I2C_MST_CTRL
# (Register 46).
# If the FIFO buffer has overflowed, the status bit FIFO_OFLOW_INT is automatically set to 1.
# This bit is located in INT_STATUS (Register 58). When the FIFO buffer has overflowed, the
# oldest data will be lost and new data will be written to the FIFO.
# If the FIFO buffer is empty, reading this register will return the last byte that was previously
# read from the FIFO until new data is available. The user should check FIFO_COUNT to ensure that
# the FIFO is not read when empty.
# -----------------------------------------------------------------------------------------------
def getFIFOData(self):
while True:
mpu_int_status = self.getIntStatus()
INT_FIFO_OFLOW_BIT = 0x10 # the 4th bit is set to 1 when FIFO buffer is overflowed
fifoCount = self.getFIFOCount()
#print("fifoCount:%d" % fifoCount)
if fifoCount < 14:
continue
# check for overflow (this shouldn't happen)
elif (mpu_int_status & 0x10 == 0x10) or fifoCount>=512:
print("fifoCount is: %d" % fifoCount)
print("FIFO is overflow!")
# print("Reset FIFO...")
# self.resetFIFO()
break
else:
packet_count = int(fifoCount/14)
# print("packet count:%d" % packet_count)
for i in range(0, packet_count):
response = self.ReadRegs(self.__MPUREG_FIFO_R_W, 14)
# print(response)
# Get Accelerometer values
for i in range(0, 3):
data = self.byte_to_float(response[i * 2:i * 2 + 2])
self.accelerometer_data[i] = self.G_SI * data / self.acc_divider
# print(self.accelerometer_data)
# Get temperature
i = 3
temp = self.byte_to_float(response[i * 2:i * 2 + 2])
self.temperature[i - 3] = (temp / 333.87) + 21.0
# print(self.temperature)
# Get gyroscope values
for i in range(4, 7):
data = self.byte_to_float(response[i * 2:i * 2 + 2])
self.gyroscope_data[i - 4] = (self.PI / 180) * data / self.gyro_divider
# print(self.gyroscope_data)
return self.accelerometer_data, self.gyroscope_data, self.temperature
def getIntStatus(self):
return self.ReadReg(self.__MPUREG_INT_STATUS)
def getFIFOCount(self):
response = self.ReadRegs(self.__MPUREG_FIFO_COUNTH, 2)
fifoCount = self.byte_to_float(response)
return fifoCount
def resetFIFO(self):
self.WriteReg(self.__MPUREG_USER_CTRL, 0x00)
self.WriteReg(self.__MPUREG_USER_CTRL, 0x04) # reset fifo mode
self.WriteReg(self.__MPUREG_USER_CTRL, 0x40) # FIFO_EN
print('fifo is reset!')
def enableFIFO(self, flag):
self.WriteReg(self.__MPUREG_FIFO_EN, 0x00)
if flag:
self.resetFIFO()
self.WriteReg(self.__MPUREG_FIFO_EN, 0xF8)
print('fifo is enabled!')
I hope to get a constant fifo reading without overflow.

While calculating median I am getting run time error for all the test cases in python 3

# Enter your code here. Read input from STDIN. Print output to STDOUT
from statistics import median
a=str(input())
l=a.split(' ')
for i,v in enumerate(l):
l[i]=float(v)
print('%.9f'%median(l))
Try with some data validation to check the error,
# Enter your code here. Read input from STDIN. Print output to STDOUT
from statistics import median
a = str(input('Enter the series of values - '))
try:
l = [float(value.strip()) for value in a.split(' ') if value.strip()]
except Exception as error:
print('Error while float conversion - {}'.format(error))
l = []
if l:
print('%.9f' % median(l))
else:
print('Enter valid inputs.')

Resources