How to use serial Data from Arduino to make if-statement in python?

Hi!

I wrote a code for the Arduino, in which the loop will start once the joystick button is pressed. The serial data will then be send to python and python stores the data in a csv file.

In the python script there are additional other data that are not coming from the arduino (camera file starts recording and load cell data).

Now I want the python script to start once joystick button is pressed as well, to make the arduino serial data sent to python and the python data synchronized.

So I thought maybe I could make something like "read serial data from arduino -> if pushbutton == 0 --> start the whole python script"

I kind of have no idea how I can do that, mabe someone could help me?

My arduino code:

#include <math.h>

const int Joystick_X = A0; 
const int Joystick_Y = A1;
const int pushbutton = 3;
int JoystickValue_X = 0; 
int JoystickValue_Y = 0;
const int middle_X = 512;
const int middle_Y = 512;
int pushbuttonState;
int JoystickValue_X_Y;

int tempsensor1 = A2;
int tempsensor2 = A3;
int tempsensor3 = A4;

int readVal1 = 0;
int readVal2 = 0;
int readVal3 = 0;

double Temp1 = 0;
double Temp2 = 0;
double Temp3 = 0;
int TempLimit;

double offset_degree;

double offset_degree1 = 2; // RT=26.0°C, difference
double offset_degree2 = 1;
double offset_degree3 = 2;

unsigned long startTime = 0;
unsigned long currentTime = 0;

//Define experiment (0 = manual, 1 = vollgas, 2 = , 3 = )
int experiment = 1; 

//Define functions--------------------------------------------------------------------
void manual_function() {
      JoystickValue_X = analogRead (Joystick_X);                        // [0, 1023]
      JoystickValue_X = constrain(JoystickValue_X, middle_X, 1023);     // [512, 1023]
      JoystickValue_X = map(JoystickValue_X, middle_X, 1023, 0, 1023);   // [0, 100]

 
      JoystickValue_Y = analogRead (Joystick_Y);                        // [0, 1023]
      JoystickValue_Y = constrain(JoystickValue_Y, middle_Y, 1023);     // [512, 1023]
      JoystickValue_Y = map(JoystickValue_Y, middle_Y, 1023, 0, 1023);   // [0, 100]

        Serial.print(Temp1);   
        Serial.print(";");      
        Serial.print(Temp2);  
        Serial.print(";");   
        Serial.print(Temp3); 
        Serial.print(";");
  
        Serial.print(JoystickValue_X);
        Serial.print(";");
        Serial.println(JoystickValue_Y);          
}



//Funktion Temperatur offset und Umrechung-----------------------------------------------------
double Thermistor(int RawADC, int sensor_number)
{
    double Temp;
    double offset_degree;
    Temp = log(10000.0 * ((1024.0 / RawADC - 1)));
    Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp )) * Temp );
    Temp = Temp - 273.15;            // Konvertierung von Kelvin in Celsius

    switch (sensor_number) {
  case 1:
    offset_degree = offset_degree1;
    break;
  case 2:
    offset_degree = offset_degree2;
    break;
   case 3:
    offset_degree = offset_degree3;
    break;
  default:
    offset_degree = 0;   
    break; 
}
    return Temp+offset_degree;
}
 
//-----------------------------------------------------------------------------------------------

void case_function( int JoystickInput_X, int JoystickInput_Y, int TempLimit, int TempValue) {
      
    if(currentTime < 45000L) {
    JoystickValue_X = JoystickInput_X;
    JoystickValue_Y = JoystickInput_Y;
        Serial.print(Temp1);   
        Serial.print(";");      
        Serial.print(Temp2);  
        Serial.print(";");   
        Serial.print(Temp3); 
        Serial.print(";");
  
        Serial.print(JoystickValue_X);
        Serial.print(";");
        Serial.println(JoystickValue_Y);  
    }
    else if ((currentTime > 45000L) && (TempValue > TempLimit)) {
     JoystickValue_X = 0;
     JoystickValue_Y = 0;
        Serial.print(Temp1);   
        Serial.print(";");      
        Serial.print(Temp2);  
        Serial.print(";");   
        Serial.print(Temp3); 
        Serial.print(";");
  
        Serial.print(JoystickValue_X);
        Serial.print(";");
        Serial.println(JoystickValue_Y);  
    }
    else if ((currentTime > 45000L) && (TempValue < TempLimit)) {
      Serial.print("Experiment done.");
      exit(0);
    }
    
}
//---------------------------------------------------------------------------------

void setup() {
  startTime = millis(); //internal timer
  
  pinMode(Joystick_X, INPUT); // X-axis
  pinMode(Joystick_Y, INPUT); // Y-axis
  pinMode(pushbutton,INPUT); // press button
  digitalWrite(pushbutton, INPUT_PULLUP);
  pushbuttonState = digitalRead(pushbutton);
      
  Serial.begin(9600); 
  while (digitalRead(pushbutton) == HIGH);

}

void loop() {
      currentTime = millis();
      
      readVal1 = analogRead(tempsensor1);
      Temp1 =  Thermistor(readVal1,1);

      readVal2 = analogRead(tempsensor2);
      Temp2 =  Thermistor(readVal2,2);

      readVal3 = analogRead(tempsensor3);
      Temp3 =  Thermistor(readVal3,3);

     switch(experiment) {
      case 0:
        manual_function();
        break;
    
    
       case 1:
         case_function(1023, 0, 25, Temp1);
         break;
    
       case 2:
         case_function(0, 1023, 23, Temp2);
         break;
    
       case 3:
         case_function(1023, 1023, 23, Temp3);
         break;
     
 }
       delay(250);
}

My python code so far without the if statement:

import serial
from datetime import datetime
import cv2
import csv

#Camera Start------------------------------------------------------------------
webcam = cv2.VideoCapture(0) #laptop camera

frame_width = int(webcam.get(3))
frame_height = int(webcam.get(4))
size = (frame_width, frame_height)

result = cv2.VideoWriter('NameAsDateTime.avi', cv2.VideoWriter_fourcc(*'MJPG'), 10, size)


#Serial Data from Arduino---------------------------------------------------------
fileName = "temp_force_serialdata.csv"
ser = serial.Serial('COM4', 9600, timeout=1) #arduino port
file = open(fileName, "a")
#time.sleep(2)

#Serial Data from Loadcell--------------------------------------------------------
#dev = gsv8.gsv8("COM8", 115200) #load cell port


while True:
    ret, frame = webcam.read()

    if ret == True:
        result.write(frame)
        cv2.imshow("Test", frame)
        key = cv2.waitKey(20) & 0xFF
        if key == ord("q"):
            break

    #webcam.release()
    #cv2.destroyAllWindows()

    getData = ser.readline()
    dataString = getData.decode('utf-8')
    data = dataString.rstrip()

    dateTimeObj = datetime.now()
    timestampStr = dateTimeObj.strftime("%d-%b-%Y (%H:%M:%S)")

    sensor_data = data.split(";")
    sensor_data.append(timestampStr)

    readings = data.split(";")
    sensor_data.append(readings)

    # get load cell data
    #measurement = dev.ReadValue()
    #measurement_str = measurement.toString()
    #measurement_arr = measurement_str.split(";")
    #force_x = measurement_arr[1].split(":")[2]
    #force_y = measurement_arr[2].split(":")[1]
    #force_z = measurement_arr[3].split(":")[1]

    #entry = timestampStr + ',' + ','.join(readings) + ',' + force_x + ',' + force_y + ',' + force_z + '\n'
    entry = timestampStr + ',' + ','.join(readings) + '\n'
    print(entry)

    with open(fileName, 'a', encoding='UTF8') as f:
        f.write(entry)

    file.close()
    pass

Do you perhaps know how to specifically only read the pushbutton State into python?

If you want to pass the data to Python then the simplest way is probably to send it via a serial link

Which Arduino board are you using ?

yeah I am using serial.Serial(...) to receive arduinos data but I don't know how to use pushbuttonState as starting signal fpor python

I am using an arduino micro

Or better: the goal is to use pushbuttonState to initialize the start pf python script.

something like receive serial data from arduino --> if pushbuttonState == 0 --> read the rest of the data and start with the remaining python script

If I understand you correctly, when the button attached to the Arduino becomes pressed you want to send a message to a Python script running on the attached PC to do something

Is that correct ?

yes correct

Do you know how to open a serial port in Python and read data from it if it is available ?

yes I already have that part. So my python script already reads all the serial data from arduino, once i run the script.

Now I want it to only read the data when the pushbutton is pressed, so that arduino and python are kind of synchronized

I opened a new post regarding this matter and I included the whole code:

If you have some time, I'd be thankful you could take a look at it :slight_smile:

Surely what you want is to read data all the time and if the 'button became pressed' message is received then do something. This means that Python must look for and read serial data all the time

Your Arduino sketch just needs to wait in a loop until the button becomes pressed and when it does to send the 'button became pressed' message via the serial interface

The 'button became pressed' message could be something as simple as a single letter, which would be easy to test for in Python, or as complicated as you like as long as you can parse the input in Python

You already have a sketch that waits until the button becomes pressed. All you have to add is a line of code that prints the 'button became pressed' message immediately afterwards

1 Like

thats actually the part that I am not sure about how to do it. Like how do I get python to react to only one message from arduino? Like you said, it continuosly gets serial data but how can I write a line to tell pythin that if the "button pressed" message is there?

I have moved several posts from your other topic to here

1 Like

Your Python script needs to do something like this

data = ''
while 'start' not in data:
    data = ser.readline()
# code here will execute only after 'start' has been received

Pardon my Python if it is wrong, but you should get the idea

yes thats basically where I want to go.

What exactly is 'start'? is that once the void loop() starts, I assign a data called start to be printed out?
Something like:
void loop() {
boolean start = True;
...
}

What I might do at times is wait for a signal from the Arduino like the following

When you are ready to start Arduino sends "<>"

Serial.print("<>");

At the Python end open the port and wait

flush_system="<>".encode()

ser.open()

ser.read_until(flush_system)

you may need a timeout in case Python never receives the flush, and this suits your project because you have a means to resend (joystick input) if the flush is missed the first time.

do i need to add this line inside void loop()? Because I dont want it to be printed out in serial monitor

It is whatever text that you send from the Arduino

If you Serial.print("start"); when the button becomes pressed then you test for 'start' in Python but if you Serial.print("ahshdjqywb"); then you test for 'ahshdjqywb' in Python

You choose

I tried both methods (while start not in data and <>) and I actually did start only when the button is pressed, but afterwards it only gives me one line of serial data, so it seems like it doesnt finish the wohle void loop()

You should not really be using the same serial port as the Serial monitor. That way you can print debugging and/or information messages to the Serial monitor separately from the messages to Python

How you do this depends on which Arduino board you are using. Which board do you have ?