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.
Related
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);
My classmate and I have been working on this project based on this Instructables article https://www.instructables.com/id/Building-a-Simple-Pendulum-and-Measuring-Motion-Wi/, our idea is to make a pendulum, calculate the g force (from the pendulum's period) and then show its value on a LCD we got connected to the Arduino. We got the code up and running (it calculates the period), and we understood that the Arduino has to do some type of conversion (utf-8) to pass the values it gets from the potentiometer to Python. However when we try to send the value we get from calculating the period of the graph back to the arduino and show it on the LCD, it shows 634 or other similiar values, we tried to instead of the decode it does initially, go the other way around with encode, but it won't work. We can't check the value it is getting from the serial, because the serial monitor simply doesn't open while the python script is running. What is the most pratical way we can use to "transfer" floats calculated in a Python script to the Arduino, so that we can calculate g and show it on the screen. Many forums advice to instead of transferring the floats, convert them to strings since it would be easy for the arduino to receive, but we aren't sure that would even work. I'm sure this is a simple question, but we just can't seem to get it. If you find anything else wrong with the code please let me know, we know it's a bit sketchy. Thanks.
Python code:
arduino = serial.Serial('COM3', 115200, timeout=.1) #Open connection to Arduino
samples = 200 #We will take this many readings
angle_data = np.zeros(samples) #Creates a vector for our angle data
time_data = np.zeros(samples) #Creates a vector of same length for time
i = 0;
calibrate = 123 #Value to zero potentiometer reading when pendulum is motionless, read from Arduino
while i!=samples:
data = arduino.readline()[0:-2].decode('utf-8')
if data:
angle_data[i] = (float(data) - calibrate)*math.pi/180
time_data[i] = time.perf_counter()
print(angle_data[i])
i = i + 1
min = np.min(angle_data)
print (min)
min_pos, = np.where(angle_data == min)
min_x = time_data[min_pos]
print (min_x)
nos_left = int(min_pos)
max = 0;
for i in range(nos_left,200):
if angle_data[i] > max: max = angle_data[i]
print (max)
max_pos, = np.where(angle_data == max)
max_x = time_data[max_pos]
print (max_x)
period = (max_x - min_x) * 2
print (period)
gforce = (0.165 * 4 * (math.pi) * (math.pi)) / ((period) * (period))
print (gforce)
value_g = arduino.write(gforce)
plt.plot(time_data,angle_data,'ro')
plt.axis([0,time_data[samples-1],-math.pi,math.pi])
plt.xlabel("Time (seconds)")
plt.ylabel("Angle (Radians)")
plt.title("Pendulum Motion - Measured with Arduino and potentiometer")
plt.show()
arduino.close()
Arduino code
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
int period = 0;
void setup() {
lcd.begin(16, 2);
Serial.begin(115200); // use the same baud-rate as the python side
pinMode(A0,INPUT);
lcd.print(" Pendulo ");
int gforce = 0;
}
void loop() {
// set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with 0):
// print the number of seconds since reset:
int degrees;
degrees = getDegree();
Serial.println(degrees);
Serial.println("\n");
delay(50);
if (Serial.available() > 0) {
// read the incoming byte:
gforce = Serial.read();
Serial.print("I received: ");
Serial.println(gforce, DEC);
}
lcd.setCursor(0, 1);
lcd.print(gforce);
}
int getDegree()
{
int sensor_value = analogRead(A0);
float voltage;
voltage = (float)sensor_value*5/1023;
float degrees = (voltage*300)/5;
return degrees;
}
This appears to be a good case for the Arduino Serial's parseFloat() method:
if (Serial.available() > 0) {
/* instead of Serial.read(), use: */
gforce = Serial.parseFloat();
Serial.print("I received: ");
Serial.println(gforce, DEC);
}
Essentially, it pulls out anything that looks like a float within the received serial data, even if it's mixed with other non-numerical characters.
It also works with Software Serial.
This question already has answers here:
Serial communication between Arduino and Matlab is losing data
(2 answers)
Closed 4 years ago.
I am completely lost. I'm trying to print something on the Arduino's display using Python. I'm aware that this can be accomplished without Python by using:
lcd.write("my string");
But I'd like to use the pySerial library to do this.
This is my Python code:
import serial
arduino = serial.Serial('COM3', 9600)
myvar1 = "text"
arduino.write(myvar1.encode())
And this is the code I have on my Arduino:
// include the library code:
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 8, en = 9, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// initialize the serial communications:
Serial.begin(9600);
}
void loop() {
// when characters arrive over the serial port...
if (Serial.available()) {
// wait a bit for the entire message to arrive
delay(100);
// clear the screen
lcd.clear();
// read all the available characters
while (Serial.available() > 0) {
// display each character to the LCD
lcd.write(Serial.read());
}
}
}
Also, when I enter text using the Serial Monitor, it shows up on the Arduino like it should (Just has a little sideways "HI!" at the end but that's not a problem).
The serial data may be buffered by Python.
Try:
arduino.write(myvar1.encode())
arduino.flush()
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.
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.