Sending multiple sensor data from arduino to python,any idea? - python

So I have this problem,I'm trying to send sensor data from arduino to python through serial communication.
But the output is a kind of wierd.
Does anyone have an idea on this?
Arduino code: to send sensor data
void setup(){
Serial.begin(9600);
}
void loop(){
int sensor1 = 20;
int sensor2 = 40;
int sensor3 = 60;
Serial.write(sensor1);
}
python code: to receive sent data from arduino
import serial,time
ser = serial.Serial("/dev/ttyACM1",9600,timeout=1)
while True:
data = ser.read()
time.sleep(1)
print("data:",data)
output :
data: b'\x14'
target :
data: 20
second target : sending multiple sensor data in a single serial.write().
data: 20 40 60

By using Serial.write() on the arduino side, you are sending the sensor integers as single byte value characters, (as mentioned here in the reference) but on the receiving side seem to be expecting whole lines of input (readline()). The value printed, b'\x14' (hexadecimal 14) is decimal 20, so the transmission was actually correct. You can solve your problem by sending actual text integers from the arduino with:
Serial.println(sensor1);

Related

How to store data in different variable in python coming from arduino?

Here, I am able to sent data from Arduino to python. But, here Arduino sent data of TWO variable A0 and A1. And in python side, this all data store in one variable named data. Now how can I split data of A0 and A1 from data in python ?
Arduino Code :
void setup()
{
Serial.begin(9600);
}
void loop()
{
int A0 = analogRead(A0);
int A1 = analogRead(A1);
Serial.print(A0);
Serial.print("\t");
Serial.print(A1);
Serial.println();
}
Python Code :
import serial
arduino = serial.Serial('COM12', 9600, timeout = .1)
while True:
data = arduino.readline()
if data:
print data
It has nothing to do with Arduino; you just need to split a string (data) into multiple (2) integers.
So a0, a1 = map(int, data.split()) will work.

Interpret serialdata in python

I'm currently struggling with an issue. I have an arduino sending serialdata to my raspberry pi. The raspberry pi reads the data and stores it in a database. What i'm struggling with is to get data in the correct order. If i start the script at the correct time, the values get read properly. If i don't they get mixed up.
I have a headerByte sent from the arduino, this value is 999 and it is the first value to be sent each time. Is there a way in python to make 999 the marker for the beginning of every read? My variables will never exceed 999 so this will not be a problem.
Python code:
import serial
import time
values = []
serialArduino = serial.Serial('/dev/ttyACM0', baudrate=9600, timeout=1)
voltageRead = serialArduino.readline()
currentRead = serialArduino.readline()
while True:
voltageRead = serialArduino.readline()
currentRead = serialArduino.readline()
print"V=", voltageRead, "A=", currentRead
Arduino Code:
void loop() {
float voltageRead = analogRead(A0);
float ampsRead = analogRead(A1);
float calculatedVoltage = voltageRead / 103;
float calculatedCurrent = ampsRead / 1;
int headerByte = 999;
Serial.println(headerByte);
Serial.println(calculatedVoltage);
Serial.println(calculatedCurrent);
delay(1000);
}
Your method isn't particularly efficient; you could send everything as a struct from the Arduino (header + data) and parse it on the RPi side with the struct module though your way does have the advantage of simplicity. But, if 999 is the highest value you expect in your readings, then it makes more sense to use a number greater than 999 like 1000. And 999 isn't really a byte.
That said, if "1000" is your header, you can simply check for the header's presence like this:
HEADER = "1000"
serialArduino = serial.Serial('/dev/ttyACM0', baudrate=9600, timeout=1)
while True:
if serialArduino.readline().rstrip() == HEADER: # check for header
voltageRead = serialArduino.readline() # read two lines
currentRead = serialArduino.readline()
print"V=", voltageRead, "A=", currentRead

.append() method with pyserial and arduino gives me ridiculous output

I' m basically trying to get voltage from arduino, and make an array from them.
Arduino code is below:
void setup() {
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(A0);
float voltage = sensorValue*(5.0/1023);
Serial.println(voltage);
}
On serial monitor, everything seems fine.
When i try to make an array with python, used this code:
import serial
ser = serial.Serial("COM5", 9600)
voltage = []
while True:
volt = ser.readline()
voltage.insert(volt)
print voltage
Just gave me something but not an array from voltage measurements. I also tried .apppend() and .extend(), same results.

Writing data to arduino python

I'm trying to write data from python to serial with this sketch
import serial
import smtplib
import time
s=serial.Serial('/dev/tty.usbserial-AH01LLHS',9600)
precx=500
ist=30
i=0
while True:
s.write('1')
stringa=s.readline()
array=stringa.split(',')
x=int(array[0])
y=int(array[1])
z=int(array[2])
print(x,y,z)
if(precx!=500):
diffx=abs(x-precx)
diffy=abs(y-precy)
diffz=abs(z-precz)
if((diffx>ist)|(diffy>ist)|(diffz>ist)):
print('Ohu god',i)
i+=1
#time.sleep(2)
precx=x
precy=y
precz=z
But when I execute the program I see nothing on the console, and the Arduino Rx led is off.
This is my Arduino sketch (nano atmega 328):
//Add the SPI library so we can communicate with the ADXL345 sensor
#include <SPI.h>
//Assign the Chip Select signal to pin 10.
int CS=10;
//This is a list of some of the registers available on the ADXL345.
//To learn more about these and the rest of the registers on the ADXL345, read the datasheet!
char POWER_CTL = 0x2D; //Power Control Register
char DATA_FORMAT = 0x31;
char DATAX0 = 0x32; //X-Axis Data 0
char DATAX1 = 0x33; //X-Axis Data 1
char DATAY0 = 0x34; //Y-Axis Data 0
char DATAY1 = 0x35; //Y-Axis Data 1
char DATAZ0 = 0x36; //Z-Axis Data 0
char DATAZ1 = 0x37; //Z-Axis Data 1
//This buffer will hold values read from the ADXL345 registers.
char values[10];
//These variables will be used to hold the x,y and z axis accelerometer values.
int x,y,z;
boolean snd;
void setup(){
//Initiate an SPI communication instance.
SPI.begin();
//Configure the SPI connection for the ADXL345.
SPI.setDataMode(SPI_MODE3);
//Create a serial connection to display the data on the terminal.
Serial.begin(9600);
//Set up the Chip Select pin to be an output from the Arduino.
pinMode(CS, OUTPUT);
//Before communication starts, the Chip Select pin needs to be set high.
digitalWrite(CS, HIGH);
//Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
writeRegister(DATA_FORMAT, 0x01);
//Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
writeRegister(POWER_CTL, 0x08); //Measurement mode
}
void loop(){
//snd=true;
//Reading 6 bytes of data starting at register DATAX0 will retrieve the x,y and z acceleration values from the ADXL345.
//The results of the read operation will get stored to the values[] buffer.
readRegister(DATAX0, 6, values);
//The ADXL345 gives 10-bit acceleration values, but they are stored as bytes (8-bits). To get the full value, two bytes must be combined for each axis.
//The X value is stored in values[0] and values[1].
x = ((int)values[1]<<8)|(int)values[0];
//The Y value is stored in values[2] and values[3].
y = ((int)values[3]<<8)|(int)values[2];
//The Z value is stored in values[4] and values[5].
z = ((int)values[5]<<8)|(int)values[4];
if (Serial.available() > 0) {
if(Serial.read()=='1'){
snd=true;
}
else{
snd=false;
}
}
if(snd){
//Print the results to the terminal.
Serial.print(x, DEC);
Serial.print(',');
Serial.print(y, DEC);
Serial.print(',');
Serial.print(z, DEC);
Serial.println("");
delay(10);
}
}
//This function will write a value to a register on the ADXL345.
//Parameters:
// char registerAddress - The register to write a value to
// char value - The value to be written to the specified register.
void writeRegister(char registerAddress, char value){
//Set Chip Select pin low to signal the beginning of an SPI packet.
digitalWrite(CS, LOW);
//Transfer the register address over SPI.
SPI.transfer(registerAddress);
//Transfer the desired register value over SPI.
SPI.transfer(value);
//Set the Chip Select pin high to signal the end of an SPI packet.
digitalWrite(CS, HIGH);
}
//This function will read a certain number of registers starting from a specified address and store their values in a buffer.
//Parameters:
// char registerAddress - The register addresse to start the read sequence from.
// int numBytes - The number of registers that should be read.
// char * values - A pointer to a buffer where the results of the operation should be stored.
void readRegister(char registerAddress, int numBytes, char * values){
//Since we're performing a read operation, the most significant bit of the register address should be set.
char address = 0x80 | registerAddress;
//If we're doing a multi-byte read, bit 6 needs to be set as well.
if(numBytes > 1)address = address | 0x40;
//Set the Chip select pin low to start an SPI packet.
digitalWrite(CS, LOW);
//Transfer the starting register address that needs to be read.
SPI.transfer(address);
//Continue to read registers until we've read the number specified, storing the results to the input buffer.
for(int i=0; i<numBytes; i++){
values[i] = SPI.transfer(0x00);
}
//Set the Chips Select pin high to end the SPI packet.
digitalWrite(CS, HIGH);
}
Thanks in advance.
You should definitely check the suggestions from the comments:
make the program simpler so that it always sends values without "flow control" (using the "1" byte you send),
use a serial monitor to check the output.
First, you shall check if you add a s.flush() before and after your s.write('1') helps. Then you may want to add flush() in your arduino code too.
To me it really looks like a starving issue at the initialization of your "flow control" algorithm. On the paper it looks good, but in real life, it may not. Very often, the Arduino sends a lot of garbage when it starts filling up the host serial port's buffer. And the other way around may be true. So instead of having a 1 on the arduino side, you may get a !##$##%##%!##$ that's totally useless.
So on either side, before getting in the loops, you should add an init protocol. The arduino sends READY, the host sends READY, you flush out everything until you get READY on both sides. Something that would look like:
void setup() {
Serial.begin(9600);
Serial.println('READY');
Serial.flush();
char ch1 = 0, ch2 = 0;
char incomingByte = 0;
while (ch1 != 'O' && ch2 != 'K') {
ch1 = Serial.read();
if (ch1 == 'O' && ch2 == 'K')
break;
ch2 = Serial.read();
}
}
and on the python side:
with serial.Serial('/dev/tty.usbserial-AH01LLHS',9600) as s:
s.flush()
ready = ""
while ready != "READY":
ready = s.readline()
s.flush()
while True:
# ... you stuff
of course that's only an idea of what you may do. You can make it more sophisticated, or way more simple. But before making such flow control, you really need to create a meeting point.

Read latest character sent from Arduino in Python

I'm a beginner in both Arduino and Python, and I have an idea but I can't get it to work. Basically, when in Arduino a button is pressed, it sends "4" through the serial port. What I want in Python is as soon as it reads a 4, it should do something. This is what I got so far:
import serial
ser = serial.Serial('/dev/tty.usbserial-A900frF6', 9600)
var = 1
while var == 1:
if ser.inWaiting() > 0:
ser.readline(1)
print "hello"
But obviously this prints hello no matter what. What I would need is something like this:
import serial
ser = serial.Serial('/dev/tty.usbserial-A900frF6', 9600)
var = 1
while var == 1:
if ser.inWaiting() > 0:
ser.readline(1)
if last.read == "4":
print "hello"
But how can I define last.read?
I don't know a good way of synchronising the comms with readLine since it's not a blocking call. You can use ser.read(numBytes) which is a blocking call. You will need to know how many bytes Arduino is sending though to decode the byte stream correctly. Here is a simple example that reads 8 bytes and unpacks them into 2 unsigned shorts and a long (the <HHL part) in Python
try:
data = [struct.unpack('<HHL', handle.read(8)) for i in range(PACKETS_PER_TRANSMIT)]
except OSError:
self.emit(SIGNAL("connectionLost()"))
self.connected = False
Here's a reference to the struct.unpack()
The Arduino code that goes with that. It reads two analog sensor values and the micro timestamp and sends them over the serial.
unsigned int SensA, SensB;
byte out_buffer[64];
unsigned int buffer_head = 0;
unsigned int buffer_size = 64;
SensA = analogRead(SENSOR_A);
SensB = analogRead(SENSOR_B);
micr = micros();
out_buffer[buffer_head++] = (SensA & 0xFF);
out_buffer[buffer_head++] = (SensA >> 8) & 0xFF;
out_buffer[buffer_head++] = (SensB & 0xFF);
out_buffer[buffer_head++] = (SensB >> 8) & 0xFF;
out_buffer[buffer_head++] = (micr & 0xFF);
out_buffer[buffer_head++] = (micr >> 8) & 0xFF;
out_buffer[buffer_head++] = (micr >> 16) & 0xFF;
out_buffer[buffer_head++] = (micr >> 24) & 0xFF;
Serial.write(out_buffer, buffer_size);
The Arduino playground and Processing Forums are good places to look around for this sort of code as well.
UPDATE
I think I might have misled you with readLine not blocking. Either way, the above code should work. I also found this other thread on SO regarding the same subject.
UPDATE You don't need to use the analog sensors, that's just what the project I did happened to be using, you are of course free to pass what ever values over the serial. So what the Arduino code is doing is it has a buffer of type byte where the output is being stored before being sent. The sensor values and micros are then written to the buffer and the buffer sent over the serial. The (SensA & 0xFF) is a bit mask operator that takes the bit pattern of the SensA value and masks it with the bit pattern of 0xFF or 255 in decimal. Essetianlly this takes the first 8 bits from the 16 bit value of SensA which is an Arduino short. the next line does the same thing but shifts the bits right by 8 positions, thus taking the last 8 bits.
You'll need to understand bit patterns, bit masking and bit shifting for this. Then the buffer is written to the serial.
The Python code in turn does reads the bits from the serial port 8 bits at a time. Have a look at the struct.unpack docs. The for comprehension is just there to allow sending more than one set of values. Because the Arduino board and the Python code are running out of sync I added that to be able to send more than one "lines" per transmit. You can just replace that with struct.unpack('<HHL',handle.read(8)). Remember that the ´handle.read()´ takes a number of bytes where as the Arduino send code is dealing with bits.
I think it might work with this modifications:
import serial
ser = serial.Serial('/dev/tty.usbserial-A900frF6', 9600)
var = 1
while var == 1:
if (ser.inWaiting() > 0):
ser.readline(1)
print "hello"

Categories