Read continuous data from serial port with pyserial - python

I have strings being continuously sent from my arduino.
For example, I am sending an integer (0-1023) line by line, so it should be:
"51\r\n233\r\n37\r\n166\r\n"
And infinitely long as it is continuously streaming.
I am currently using pyserial's function readline() to read the data, but constantly see broken/missing bytes. For example, instead of "37\r\n" followed with "11\r\n", it will get "3\r11\r\n" or even "3711\r\n"!
Here's my full Python-end code:
import serial
import time
if __name__ == '__main__':
ser = serial.Serial('COM3', baudrate=1000000)
data = []
time0 = time.time()
while (time.time() - time0 < 5): # Read data for 5 seconds
data.append(ser.readline())
ser.close()
For those interested, the (probably relevant) arduino code is simply:
#define FASTADC 1 // Flag for prescale 16
// Code pasted for modifying ADCSRA
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
void setup() {
Serial.begin(1000000);
#if FASTADC
// set prescale to 16
sbi(ADCSRA,ADPS2) ;
cbi(ADCSRA,ADPS1) ;
cbi(ADCSRA,ADPS0) ;
#endif
}
void loop() {
int val;
val = analogRead(A0);
Serial.println(val);
}
As you can see from the code, the baud rate, parity, stop bit were both set to 1,000,000; None; 1.

Related

Write data to register with i2c in python

I need to change value in MLX96014 temperature sensors eeprom with raspberry pi and python. I can read its ram and eeprom without problems, but I cant write to it. Also every python MLX96014 library that I find dont have this function implemented for some reason. I tried to do this with arduino and it works great with this function:
void Adafruit_MLX90614::write16(uint8_t a, uint16_t v) {
// a is register address
// v value to write to eeprom
// _addr is device address (0x5a)
uint8_t pec;
uint8_t pecbuf[4];
pecbuf[0] = _addr << 1;
pecbuf[1] = a;
pecbuf[2] = v & 0xff;
pecbuf[3] = v >> 8;
pec = crc8(pecbuf, sizeof pecbuf);
Wire.beginTransmission(_addr); // start transmission to device
Wire.write(a); // sends register address to write
Wire.write(v & 0xff); // lo
Wire.write(v >> 8); // hi
Wire.write(pec); // pec
Wire.endTransmission(true); // end transmission
}
So I tried to rewrite this function in python:
import board
import busio as io
import adafruit_mlx90614
import time
from smbus2 import SMBus, i2c_msg
import crc8
import sys
i2c = io.I2C(board.SCL, board.SDA, frequency=100000)
mlx = adafruit_mlx90614.MLX90614(i2c)
buf = bytearray(4)
buf[0] = 0x5a<<1
buf[1] = 0x24
buf[2] = 0 & 0xff
buf[3] = 0 >>8
pec = crc8.crc8()
pec.update(buf)
pec = pec.hexdigest() # = 0x28
i2c.writeto(0x5a, bytes([0x24]), stop=False)
buffer = bytearray(3)
buffer[0] = 0 & 0xFF
buffer[1] = (0 >> 8) & 0xFF
buffer[2] = 0x28
i2c.writeto(0x5a, buffer, stop=True)
i2cbus = SMBus(1)
emissivity=i2cbus.read_word_data(0x5a,0x24)
print(emissivity) # prints 65535 which is default
Code executes without errors. i2c.writeto() returns "None". So what im missing there?
Edit:
I found this (link) in datasheet but it confuses me. In datasheet it says that write comand bit is low and read is high. But in example both operations uses low. Also it looks like im supposed to send 0xb4 byte instead of 0x5a, but where to put it in pyhton code? If I put it in i2c.writeto() first parameter then I get I/O error because module is on address 5a (i2cdetect shows that).
By the way, I dont have access to osciloscope right now.
communication example
I dont know exactly why provided python code doesnt work but I have tried other i2c library and it started working. Here is the code snippet:
import board
import busio as io
import crc8
import adafruit_mlx90614
import adafruit_bus_device.i2c_device as ada_i2c
import time
def change_emissivity(value,i2c):
new_emissivity=round(65535*value)
buf=bytearray(4)
buf[0]=0x24
buf[1]=0x00
buf[2]=0x00
buf[3]=0x28 # kai irasomi nuliai
device=ada_i2c.I2CDevice(i2c,0x5a)
with device:
device.write(buf)
time.sleep(0.01)
buf[0]=0x5a<<1
buf[1]=0x24
buf[2]=new_emissivity & 0xff
buf[3]=(new_emissivity >> 8) & 0xFF
pec=crc8.crc8()
pec.update(buf)
pec=int(pec.hexdigest(),base=16)
buf[0]=0x24
buf[1]=new_emissivity & 0xff
buf[2]=(new_emissivity >> 8) & 0xFF
buf[3]=pec
print(new_emissivity)
i2c = io.I2C(board.SCL, board.SDA, frequency=100000)
mlx = adafruit_mlx90614.MLX90614(i2c)
change_emissivity(0.8, i2c)
print("New emissivity: %.2f" %mlx._read_16(0x24))
while(True):
print("Ambient Temp: %.2f" %mlx.ambient_temperature
print("Object Temp: %.2f" %mlx.object_temperature
time.sleep(3)

How to read the serial port with a arduino over python?

import serial
ser= serial.Serial('com5',9600)
while 1:
Value_from_arduino = ser.readline()
Zustand = float(Value_from_arduino)
print(Zustand)
if Zustand == 1:
ser.write(0)
print('off')
elif Zustand == 0:
ser.write(1)
print(on)
This was the Python code, now here the arduino code.
char serialData;
int pin=12;
int pin2 = 5;
int Value;
void setup(){
pinMode(pin,OUTPUT);
pinMode(pin2,INPUT);
Serial.begin(9600);
}
void loop(){
Value = digitalRead(pin2);
Serial.println(Value);
delay(250);
while(Serial.available()){
serialData = Serial.read();
Serial.print(serialData);
if(serialData = '1'){
digitalWrite(pin,HIGH);
}
else if(serialData = '0'){
digitalWrite(pin,LOW);
}
}
}
My problem is, when i run my python code, it stops when he gets the Value 0 from my arduino.
Here is the report from python:
Zustand = float(Value_from_Arduino)
ValueError: could not convert string to float: b'\x000\r\n'
Python immediatly stops, but he puts the LED on.
The LED should be on if Python gets the value of 0, he do but then he just end run.
The LED should go on if value is 0 and of if value is 1.
You need to decode the serial bytes from the serial port.
Replace the Zustand = line in your code
Value_from_arduino = ser.readline()
Zustand = float(ser_bytes[0:len(Value_from_arduino )-2].decode("utf-8"))
Please check here https://makersportal.com/blog/2018/2/25/python-datalogger-reading-the-serial-output-from-arduino-to-analyze-data-using-pyserial
also try, if encodings doesn't work well
import struct
Zustand, = struct.unpack('<f',Value_from_arduino )
Finally i have found out please replace these lines of code
Steps -> Read,Decode to string, Strip /n and /r, Convert to float
please check here https://problemsolvingwithpython.com/11-Python-and-External-Hardware/11.04-Reading-a-Sensor-with-Python/
Value_from_arduino = ser.readline()
Value_from_arduino = Value_from_arduino.decode()
Value_from_arduino = Value_from_arduino.rstrip()
Zustand = float(Value_from_arduino)
Hope this Works..

Slow serial communication with Arduino and Python

In a project of mine, I have to take a picture from a camera connected to a Sony Spresense Arduino board which is linked to my computer via an USB port. I am not very experienced in Arduino and serial communication, not at all in fact, so I am asking for some help.
I want to read the data from the camera which is sent in hexadecimal from the Arduino to my computer via a Serial.begin at a given baud rate, processed by a Python program in order to collect the hex code, correct it (there have been some print errors which are now solved), and convert it to a JPEG image.
I am able to do it, but the serial communication part of my program where Python collects the data from the Arduino is significantly slow, it takes 34 seconds to obtain an image that weighs "only" 100 ko (I don't know if it's a lot to handle for an Arduino), at a baud rate of 115200. If I try to increase this number, the hex code collected shows some errors and the image can not be converted. I can also change the pixel resolution of the image, but I'd like to be able to work with HD pictures.
In detail, here is the code from the Arduino, I have found no other way than this to get the data from the camera (there is no designed function in the Spresense library for serial communication). The relevant part is at the end :
#include <SDHCI.h>
#include <stdio.h> /* for sprintf */
#include <Camera.h>
#define BAUDRATE (115200)
/**
* Print error message
*/
void printError(enum CamErr err)
{
Serial.print("Error: ");
switch (err)
{
case CAM_ERR_NO_DEVICE:
Serial.println("No Device");
break;
case CAM_ERR_ILLEGAL_DEVERR:
Serial.println("Illegal device error");
break;
case CAM_ERR_ALREADY_INITIALIZED:
Serial.println("Already initialized");
break;
case CAM_ERR_NOT_INITIALIZED:
Serial.println("Not initialized");
break;
case CAM_ERR_NOT_STILL_INITIALIZED:
Serial.println("Still picture not initialized");
break;
case CAM_ERR_CANT_CREATE_THREAD:
Serial.println("Failed to create thread");
break;
case CAM_ERR_INVALID_PARAM:
Serial.println("Invalid parameter");
break;
case CAM_ERR_NO_MEMORY:
Serial.println("No memory");
break;
case CAM_ERR_USR_INUSED:
Serial.println("Buffer already in use");
break;
case CAM_ERR_NOT_PERMITTED:
Serial.println("Operation not permitted");
break;
default:
break;
}
}
void CamCB(CamImage img)
{
/* Check the img instance is available or not. */
if (img.isAvailable())
{
/* If you want RGB565 data, convert image data format to RGB565 */
img.convertPixFormat(CAM_IMAGE_PIX_FMT_RGB565);
}
else
{
Serial.print("Failed to get video stream image\n");
}
}
/**
* #brief Initialize camera
*/
void setup()
{
CamErr err;
/* Open serial communications and wait for port to open */
Serial.begin(BAUDRATE);
while (!Serial)
{
; /* wait for serial port to connect. Needed for native USB port only */
}
/* begin() without parameters means that
* number of buffers = 1, 30FPS, QVGA, YUV 4:2:2 format */
Serial.println("Prepare camera");
err = theCamera.begin();
if (err != CAM_ERR_SUCCESS)
{
printError(err);
}
/* Start video stream.
* If received video stream data from camera device,
* camera library call CamCB.
*/
Serial.println("Start streaming");
err = theCamera.startStreaming(true, CamCB);
if (err != CAM_ERR_SUCCESS)
{
printError(err);
}
/* Auto white balance configuration */
// Serial.println("Set Auto white balance parameter");
err = theCamera.setAutoWhiteBalanceMode(CAM_WHITE_BALANCE_DAYLIGHT);
if (err != CAM_ERR_SUCCESS)
{
printError(err);
}
/* Set parameters about still picture.
* In the following case, QUADVGA and JPEG.
*/
Serial.println("Set still picture format");
// err = theCamera.setStillPictureImageFormat(
// CAM_IMGSIZE_QUADVGA_H,
// CAM_IMGSIZE_QUADVGA_V,
// CAM_IMAGE_PIX_FMT_JPG);
//err = theCamera.setStillPictureImageFormat(320, 240, CAM_IMAGE_PIX_FMT_JPG);
err = theCamera.setStillPictureImageFormat(CAM_IMGSIZE_QUADVGA_H, CAM_IMGSIZE_QUADVGA_V, CAM_IMAGE_PIX_FMT_JPG);
if (err != CAM_ERR_SUCCESS)
{
printError(err);
}
/**
* #brief Take picture with format JPEG per second
*/
/******** Affichage serie ********/
/* une ligne de vide et l'image */
Serial.println(" ");
CamImage img = theCamera.takePicture();
/* Check availability of the img instance. */
/* If any error was occured, the img is not available. */
if (img.isAvailable())
{
/*Indicateur de debut img : FFD8FF (Magic number of the jpeg format) */
for(int i=0;i<img.getImgSize();i++)
{
Serial.print(*(img.getImgBuff()+i),HEX); //img.getImgBuff() gets the data address of the picture, so the * before.
Serial.print(";");
}
/*End indicator : FFD9FF (Magic number of jpeg format) */
}
}
void loop()
{
// put your main code here, to run repeatedly:
sleep(1);
}
And here is the Python code :
## Serial collecting the data of the picture taken by the camera
import serial
from serial import Serial
import binascii
import string
from PIL import Image
import time
start_time = time.time()
ser = serial.Serial('COM3', baudrate=115200, timeout=1)
# writing the data in a text file
data = open("data.txt", "w")
data.write(str(ser.readlines()))
## Correcting the data
data = open("data.txt", "r")
string = str(data.readlines())
# spliting the string into a list
# I chose to use the ";" to split the different hex couples in the Arduino program
tab=string.split(";")
tab[0] = 'FF'
tab.pop(-1)
N = len(tab)
# correcting the arguments that are not couples :
# Indeed, when Arduino encounter a couple starting with a 0,
# it omits it, so I have to add it back manually
for i in range(N):
if len(tab[i]) == 1:
tab[i] = '0' + tab[i]
newdata = open("newdata.txt", "w")
# writing the new data in a text file
for s in tab:
newdata.write(s)
newdata.close()
data.close()
## Converting the hex data into a JPEG file
file = open("newdata.txt", "r")
data= file.read()
# conversion
data = binascii.a2b_hex(data)
# creation of the JPEG file
with open('imagenew.jpg', 'wb') as image_file:
image_file.write(data)
file.close()
img = Image.open('imagenew.jpg')
img.show()
print("--- %s seconds ---" % (time.time() - start_time))
If you have any idea or any advice in order to speed up this process I am taking it. I heard that there are some flow control and buffer stories here and there, but I am quite lost when I try to find something relevant to my situation. Thanks in advance.

Python I2C communication TTP229

I need to read 2 different bytes from TTP229 (16 keys or 8 keys touch pad detector).
I use I2C In Python. TTP229 datasheet PDF.
I can't read the second byte, but I can get the first byte.
Python code:
import smbus
bus = smbus.SMBus(1)
adressTTP229 = 0x57 #0xAF>>1
byte1 = bus.read_byte(adressTTP229)
byte2 = bus.read_byte(adressTTP229)
byte1 is always equal to byte2.
This Arduino code, works ok:
#include <Wire.h>
#define ttp229 (0xAF>>1)
void setup() {
Serial.begin(9600); // start serial for output
Wire.begin();
}
void loop() {
delay(50);
bool isNewData = false;
Wire.requestFrom(ttp229,2,true);
while (Wire.available()) {
uint16_t b1 = Wire.read(); // receive a first byte
uint16_t b2 = Wire.read(); // receive a second byte
if (b1==b2 && b2==0) {break;}
//...
}
}
How do I use Arduino's requestFrom() function in Python?
try:
import smbus, time
bus = smbus.SMBus(1)
while True:
print bus.read_word(0xAF)
time.sleep(0.1)
dont change address, bus doe the conversion, and if you read byte you will always get the same first byte. you want to read a word = 2 bytes at once
not tested, but might work, have it ordered and will test

Python Netlink Multicast Communication in Kernels above 4

I was trying to reproduce the example from a previous SO post on a kernel above 4 (4.1):
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netlink.h>
#include <net/netlink.h>
#include <net/net_namespace.h>
/* Protocol family, consistent in both kernel prog and user prog. */
#define MYPROTO NETLINK_USERSOCK
/* Multicast group, consistent in both kernel prog and user prog. */
#define MYGRP 31
static struct sock *nl_sk = NULL;
static void send_to_user(void)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
char *msg = "Hello from kernel";
int msg_size = strlen(msg) + 1;
int res;
pr_info("Creating skb.\n");
skb = nlmsg_new(NLMSG_ALIGN(msg_size + 1), GFP_KERNEL);
if (!skb) {
pr_err("Allocation failure.\n");
return;
}
nlh = nlmsg_put(skb, 0, 1, NLMSG_DONE, msg_size + 1, 0);
strcpy(nlmsg_data(nlh), msg);
pr_info("Sending skb.\n");
res = nlmsg_multicast(nl_sk, skb, 0, MYGRP, GFP_KERNEL);
if (res < 0)
pr_info("nlmsg_multicast() error: %d\n", res);
else
pr_info("Success.\n");
}
static int __init hello_init(void)
{
pr_info("Inserting hello module.\n");
nl_sk = netlink_kernel_create(&init_net, MYPROTO, NULL);
if (!nl_sk) {
pr_err("Error creating socket.\n");
return -10;
}
send_to_user();
netlink_kernel_release(nl_sk);
return 0;
}
static void __exit hello_exit(void)
{
pr_info("Exiting hello module.\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
However, compilation works fine, but when I insert the module, it returns:
nlmsg_multicast() error: -3
I dont even know, where I can lookup the error codes to learn, what -3 means in this context (I searched here, but was unable to find anything useful, regarding the error code).
Just to be sure, I post the userland code (Python) also:
EDITED due to a comment: (but still not working)
#!/usr/bin/env python
import socket
import os
import time
sock = socket.socket(socket.AF_NETLINK, socket.SOCK_DGRAM, socket.NETLINK_USERSOCK)
# 270 is SOL_NETLINK and 1 is NETLINK_ADD_MEMBERSHIP
sock.setsockopt(270, 1, 31)
while 1:
try:
print sock.recvfrom(1024)
except socket.error, e:
print 'Exception'
You forgot to bind the socket. :-)
I'm not very fluent with Python, so use this only as a starting point (between the socket and the setsockopt):
sock.bind((0, 0))
That prints me a bunch of garbage, among which I can see
Hello from kernel
By the way: When nlmsg_multicast() throws ESRCH, it's usually (or maybe always) because there were no clients listening.
First open the client, then try to send the message from the kernel.
Otherwise you can always ignore that error code it that makes sense for your use case.

Categories

Resources