Receiving incorrect serial data on Raspberry Pi 2 - python

I've connected an ultrasonic distance sensor to a raspberry pi 2. When triggered the sensor is supposed to send the following 6 parameters back via serial:
frame header: 0xFF
data 1: 0x07
data 2: 0xD0
data 3: 0x01
data 4: 0x19
checksum: 0xF0
However when I'm trying to read the output I get something like this: ['\x00\xff\x01V\x00\xce']
Here are some information about the serial frame format of the sensor:
The checksum is calculated like this:
SUM =( Frame header + Data_H+ Data_L+ Temp_H+ Temp_L)&0x00FF
Note: The checksum keeps the low accumulative value of 8 bits only;
And this is the code I've written so far:
import RPi.GPIO as GPIO
import time
from serial import Serial
GPIO.setmode(GPIO.BCM) #GPIO mode
GPIO_TRIGGER = 18 #assign GPIO pins
GPIO.setup(GPIO_TRIGGER, GPIO.OUT) #direction of GPIO-Pins (IN / OUT)
data_output=[]
def uss_funct():
ser = Serial('/dev/ttyAMA0', baudrate=9600, bytesize=8, parity='N', stopbits=1)
# set trigger HIGH, sensor is waiting for falling edge
time.sleep(0.01000)
GPIO.output(GPIO_TRIGGER, True)
# set trigger LOW after 10ms -> Falling Edge
time.sleep(0.01000)
GPIO.output(GPIO_TRIGGER, False)
# set trigger back HIGH after 2ms, as LOW is supposed to be between 0.1-10ms
time.sleep(0.00200)
GPIO.output(GPIO_TRIGGER, True)
#read from rx
data_output.append(ser.read(6))
ser.close()
#clean up GPIO pins
GPIO.cleanup()
print (data_output)
if __name__ == '__main__':
uss_funct()

The checksum can be calculated quite easily, but your problem is that the data is out of sync. The first byte needs to be 0xff. Here is some code to find the front of the data (0xff), then calculate the temperature, distance and checksum:
data_output = ser.read(6)
# the first byte should be 0xff
if len(data_output) == 6 and \
data_output[0] != 0xff and 0xff in data_output:
# find where 0xff is in the data stream
still_needed = data_output.index(0xff)
# read more data, we are out of sync
data_output = data_output[still_needed:] + ser.read(still_needed)
# must get 6 bytes, and the first needs to be 0xff
if len(data_output) != 6 or data_output[0] != 0xff:
good_data = False
else:
# verify the checksum
good_data = (0 == (sum(data_output) & 0xff))
if good_data:
distance = data_output[1] * 256 + data_output[2]
temperature = data_output[3] * 256 + data_output[4]
Be sure to initialize the serial object with a timeout:
from serial import Serial
ser = Serial(..., timeout=1)
I have no way to test this, so buyer beware.

Related

UART communication Raspberry Pi Pico to Raspberry Pi

I am trying to communicate with a raspberry pi pico with my raspberry pi 4 over uart. The below code does transmit data, but I am only receiving data from the print statement.
import os
import utime
from machine import ADC
temp_sensor = ADC(4) # Default connection of temperature sensor
def temperature():
# get raw sensor data
raw_sensor_data = temp_sensor.read_u16()
# convert raw value to equivalent voltage
sensor_voltage = (raw_sensor_data / 65535)*3.3
# convert voltage to temperature (celcius)
temperature = 27. - (sensor_voltage - 0.706)/0.001721
return temperature
#print setup information :
print("OS Name : ",os.uname())
uart = machine.UART(0, baudrate = 9600)
print("UART Info : ", uart)
utime.sleep(3)
while True:
temp = temperature()
print(str(temp))
uart.write(str(temp))
utime.sleep(1)
And the code on my raspberry pi 4 is:
import serial
import time
import numpy as np
import matplotlib.pyplot as plt
#ser = serial.Serial('COM14',9600)
ser = serial.Serial('/dev/ttyACM0', 9600)
time.sleep(1)
while True:
# read two bytes of data
#data = (ser.read(8))
data = (ser.readline())
# convert bytestring to unicode transformation format -8 bit
temperature = str(data).encode("utf-8")
#print("Pico's Core Temperature : " + temperature + " Degree Celcius")
print(temperature)
The output in the terminal on my RPI 4 is:
27.2332
26.443
26.443
26.564
There is an extra new line between. If I remove print(str(temp)) from the pico code I get nothing. I can put just about anything in uart.write(str(temp)) and still receive the print statement, but without the uart.write() I will receive nothing.
extra new line: this problem is just because the print ends with new line you can change print(str(temp)) to print(str(temp), end="") in raspberry pi pico code
with respect to your second problem I don't think that uart.write(str(temp))is doing something useful. print statement is the way to send data to raspberry pi
A way I use to send data to raspberry pi is:
raspberry pi pico send the number of chars of the message then send the message
while True:
temp = temperature()
print(len(str(temp)))
utime.sleep(1)
print(str(temp))
utime.sleep(1)
the length would be between 1 and 9 so raspberry pi will receive 1 char
in raspberry pi code
while True:
# read length of data
length = int(ser.read(1).encode("utf-8"))
# read the data
data = (ser.read(length))
#convert bytestring to unicode transformation format -8 bit
temperature = str(data).encode("utf-8")
print(temperature)

Python 'ser.write' permanently stalls program on Windows, possible errors?

I am communicating in my python code to arduino, transmitting a number of bytes serially. The below code is my main function that works until after the first or second 'ser.wrte' function. Confusingly the program works correctly on mac with no errors but has the above issue with any laptop running windows (versions 7 and 10 have been tested with no success) is there any code-based reason for this, or is it due to a windows related serial port issue?
#Communicates to arduino via serial port
def pump():
print('****************')
if len(seq) == 0:
print("EmptySeqError: please store patterns in the sequence before sending it!")
return
#######################
port = "COM17"
macport = "/dev/cu.usbmodem1411"
baudrate = 9600
#######################
try:
ser = serial.Serial(port, baudrate, timeout=0.1) #, write_timeout=0.1)
except serial.SerialException:
print('SerialException: cannot create serial object')
return
else:
if ser.isOpen():
print('serial port {} is opened successfully!'.format(ser.name))
for json in seq:
MSB = int(json['Hex Code MSB'], 16)
LSB = int(json['Hex Code LSB'], 16)
V = int(json['Voltage'], 16) #For voltage transmission
Vlsb = V & 0xff #Voltage LSB
Vmsb = (V>>8) & 0xff #Voltage MSB
print(V, 'in hex =', hex(V))
print(Vlsb, 'in hex =', hex(Vlsb))
print(Vmsb, 'in hex =', hex(Vmsb))
#X = int(json['Xhigh'], 16)
#Y = int(json['Ybase'], 16)
#Z = int(json['Zsec'], 16)
HD = int(json['High Delay'], 16)
LD = int(json['Low Delay'], 16)
print("**************")
print("(MSB/LSB) number of bytes written: ", ser.write(bytes([MSB, LSB])))
print("(Voltage) number of bytes written: ", ser.write(bytes([Vmsb,Vlsb])))
print("(HD/LD) number of bytes written: ", ser.write(bytes([HD, LD])))
print("serial is closing...")
sys.stdout.flush()
ser.close()
#End of sending

Pyserial - RS232 9600,8,N,1 send and receive data

I need to communicate and pass values to a serial connected device using RS232 Protocol. I need to pass commands through the 8 bytes of data and then be able to receive the response afterwards.. Im not sure how to write this in PySerial so if anyone can help out it would be great (9600 Baud, 8 data bits, No parity, and 1 stop bit.)
import serial
ser = serial.Serial('/dev/ttyUSB0') # open serial port
print(ser.name) # check which port was really used
ser.write(b'hello') # write a string
ser.close() # close port
The Timer Manager Command structure consists of one start byte, one command byte, five bytes of data, and a one byte checksum. Each message packet is formatted as follows:
BYTE 0 BYTE 1 BYTE 2 BYTE 3 BYTE 4 BYTE 5 BYTE 6 BYTE 7
200 COMMAND DATA1 DATA2 DATA3 DATA4 DATA5 CK SUM
Im looking to receive the following back from the machine:
If command was successfully received, the Timer Manager will respond with:
BYTE 0 BYTE 1 BYTE 2
6 0 6
The actual data that I want to send is this
Data i need to pass to the timer is structured this way:
BYTE 0 BYTE 1 BYTE 2 BYTE 3 BYTE 4 BYTE 5 BYTE 6 BYTE 7
200 31 4 0 0 0 0 235
Is this passed via bytearray ?
ser.write( bytearray(200,31,4,0,0,0,0,235) );
I generally have something like this to do binary IO over a serial port:
from timeit import default_timer as clk
from serial import Serial, SerialException
class TimeManager(object):
def __init__(self, port, baudrate=9600):
self.ser = Serial(port, baudrate=baudrate)
self.ser.open()
self.ser.flushInput()
self.ser.flushOutput()
def send(self, tx):
tx = bytearray(tx)
try:
self.ser.write(tx)
self.ser.flush()
except SerialException as e:
if e.args == (5, "WriteFile", "Access is denied."):
# This occurs on win32 when a USB serial port is
# unplugged and replugged. It should be fixed by
# closing and reopening the port, which should happen
# in the error handling of our caller.
raise IOError(errno.ENOENT, "Serial port disappeared.",
self.ser.portstr)
else:
raise
def receive(self):
rx = bytearray()
delay = 10e-3 # s
timeout = 1 # s
end_time = clk() + timeout
while True:
time_remaining = end_time - clk()
if time_remaining < 0:
break
rx += self.ser.read(self.ser.inWaiting())
if 0 in rx:
break
time.sleep(delay)
if time_remaining <= 0:
raise IOError(errno.ETIMEDOUT, "Communication timed out.")
return rx
tm = TimeManager("/dev/ttyS0")
My device sends null terminated messages (the if 0 in rx: line). You'd have to figure out a similar condition for your messages.
First of all, due to the fact that you use RS232, you must set the ASCII characters you wanna send in variables. And then, when you got in a variable all the sentence you want to send, sent it decoding it into bytes.
It would be something like this.
def sendserial(sendstring):
ser.port(yourport)
try:
ser.open()
except Exception as e:
flag=1
if ser.isOpen():
try:
ser.flushInput()
ser.flushOutput()
ser.write(bytes(sendstring,'iso-8859-1'))
#iso 8859-1 is the only encode that works for me
time.sleep(0.5)
numOfLines = 0
while True:
resp = bytes.decode(ser.readline())
result = ord(str(response))
if result == ord(ACK)
#I set previously the ACK var to the ASCII symbol that the machine returns
response = 'Y'
else:
response = 'N'
numOfLines = numOfLines +1
if (numOfLines>=1):
break
ser.close()
except Exception as e1:
print('Communication error...:' + str(e1))
else:
pass
return(response)

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

Controlling LED's with PCA9685

I have bought an Adafruit PCA9685 and completed the library installation, however, I have no clue of how to Program it. I want to base it on the following code I wrote:
import RPi.GPIO as GPIO
import time
import sys
from pubnub import Pubnub
GPIO.setmode(GPIO.BCM)
PIN_LIVING = 22
PIN_PORCH = 17
PIN_FIREPLACE = 27
GPIO.setup(PIN_LIVING,GPIO.OUT)
GPIO.setup(PIN_PORCH,GPIO.OUT)
GPIO.setup(PIN_FIREPLACE,GPIO.OUT)
FREQ = 100 # frequency in Hz
FIRE_FREQ = 30 # flickering effect
# Duty Cycle (0 <= dc <=100)
living = GPIO.PWM(PIN_LIVING, FREQ)
living.start(0)
porch = GPIO.PWM(PIN_PORCH, FREQ)
porch.start(0)
fire = GPIO.PWM(PIN_FIREPLACE, FIRE_FREQ)
fire.start(0)
# PubNub
pubnub = Pubnub(publish_key='demo', subscribe_key='demo')
channel = 'pi-house'
def _callback(m, channel):
print(m)
dc = m['brightness'] *10
if m['item'] == 'light-living':
living.ChangeDutyCycle(dc)
elif m['item'] == 'light-porch':
porch.ChangeDutyCycle(dc)
elif m['item'] == 'fireplace':
fire.ChangeDutyCycle(dc)
def _error(m):
print(m)
pubnub.subscribe(channels='pi-house', callback=_callback, error=_error)
try:
while 1:
pass
except KeyboardInterrupt:
GPIO.cleanup()
sys.exit(1)
I dont know if on this its similar. I bought it because I wanted to be able to control more LED's with PWM from the Raspberry pi. I looked into it and found all kinds of weird commands and terms specific to this Chip.
Thanks!
First, If you look at page 29 of the data sheet (fig. 15) it shows that for Direct LED connection, you need to connect your LEDs inverted. i.e. connect the ground of the LED to the PWM line on the PCA9685 and the positive of the LED to the V+
Code is pretty simple (below is for an Arduino) And you use the function pwm.setPWM(uint8_t num, uint16_t on, uint16_t off) to turn the LEDs on and off and to different levels of brightness.
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
void setup()
{
Serial.begin(9600);
pwm.begin();
pwm.setPWMFreq(1600); //This is the maximum PWM frequency
pwm.setPWM(1,0,4095); //this turns on the LED connected to channel one (I suspect the only line you're really looking for)
}
Hope that answers your question!
See below how to do this in python
import Adafruit_PCA9685
pwm = Adafruit_PCA9685.PCA9685()
pwm.set_pwm_freq(60)
# Demo using LED on Channel 12 of the PCA9685
# Wire up the LED on Channel 12 such that
# Shortleg of LED goes to GND and
# Long leg goes to PWM pin on channel 12
pwm.set_pwm(12,0,4095) # Full bright
time.sleep(5)
pwm.set_pwm(12,1024,3072) # half bright
time.sleep(5)
pwm.set_pwm(12,0,0) #off
time.sleep(5)

Categories

Resources