Probably simple coding error : once I control separately the reading of the sensor, one set doesn't fully work

Hi everyone,
First time posting, I'm not sure if I'm in the correct place, sorry if I'm not. I'm quite a beginner in using Arduino and I ran into a problem I can't find how to solve.

I'm coding a pretty basic code : the objective is to get the data from a sensor and send it to a bigger python program to use it later on. My sensor is a ultrasound sensor that detects whether there is a tube and whether it's filled with water.

I first coded only on arduino to make sure it works the way I want, then implemented the communication with my python code using py.serial.

Here's the first code that I used to understand the sensor:

int TubeState = 0;  //initialisation var tube
int LiquidState = 0;  //Initialisation varliquid
int TubePin = 2;    //Tube on pin 2
int LiquidPin = 3;  //Liquid on pin 3

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(TubePin, INPUT);    //Initialisation pin as input
  pinMode(LiquidPin, INPUT);    //Initialisation pin as input
}

void loop() {
  TubeState = digitalRead(TubePin);   //read tube presence
  LiquidState = digitalRead(LiquidPin);   //read liquid presebce

    if (TubeState == 0) {   //if no tube
      Serial.println("no tube");
    }
    else {    //if tube here
      Serial.println("tube ok");
    }
    if (LiquidState == 0) {   //if no liquid
      Serial.println("No liquid");
    }
    else {    //if liquid here
      Serial.println("liquid ok");
    }
    delay(1000);
  }

That code works. But once I try to just read the data and send it to python, the reading for the tube works fine, but not for the liquid state :

int TubeState = 0;  //initialisation var tube
int LiquidState = 0;  //Initialisation var liquid
int TubePin = 2;    //Tube on pin 2
int LiquidPin = 3;  //Liquid on pin 3

void setup() {
  Serial.begin(9600);   // Initialisation serial com
  delay(1000);          // wait 1 sec
  pinMode(TubePin, INPUT);    //Initialisation pin as input
  pinMode(LiquidPin, INPUT);    //Initialisation pin as input

// This is a communication test, used only once at initialisation hence why I put it there
  if (Serial.available() > 0) {  //Check if command from python
    String command = Serial.readStringUntil('\n');  // read python command
    if (command == "test") {Serial.write(1);}  // if command = "test"
    else {Serial.write("Mauvaise commande pour le test");}}  // send back error message
  else {Serial.write(0);}  //send back "0" for no received command
}

void loop() {
  if (Serial.available() > 0) {  // check if command from python
    String command = Serial.readStringUntil('\n');  // read it
// From here it doesn't work
    if (command == "bulle") {   
      while (true) {
        if (Serial.available() > 0) {  // check if there's a new command since
          command = Serial.readStringUntil('\n');
          if (command == "exit") {   // if "exit", stop
            break;
          }        }
        // read liquid state
        LiquidState = digitalRead(LiquidPin);
        Serial.println(LiquidState);  // send data to python
        delay(50);  // wait for next reading
      }    }
// From here it works again
    if (command == "tube") {     
      while (true) {
        if (Serial.available() > 0) {  
          command = Serial.readStringUntil('\n');
          if (command == "exit") {   
            break;
          }        }
        // read tube state and send it
        TubeState = digitalRead(TubePin);
        Serial.println(TubeState);  
        delay(50); 
      }    }      
    // If exit received, get out of loop
    if (command == "exit") {    } // juste sortie de boucle if
  }
}

The output of that code to the "tube" command send back the correct data : 0 if there's no tube, 1 if there's one. But for the commande "bulle", it always give 0, whether there's liquid or not (it should send 0 if there's no liquid, and 1 if there is). I checked directly in the serial monitor of Arduino.

I know that while(true) is not the greatest coding line, but I need the sensor to collect data as fast as possible, then send everything back to my pyhton code once it received the "exit" command.

For information, here's my python code (not integrated to the main task, just to get the data for now):

import serial
import time

capt = serial.Serial('COM5',9600,timeout=5)
time.sleep(1.7)

def testcomm(test):
    out = 0
    com = (test + '\n').encode()  
    capt.write(com)  
    time.sleep(1)  
 
    if capt.in_waiting > 0:
        testout = capt.readline()  
    else:
        print("Transfert ligne commande impossible arduino -> python")
    if testout == b'\x01':
        out = 1
    time.sleep(0.5)
    capt.reset_output_buffer()  # Clear the output buffer
    return out

def sendcommand2(command, stoptime):
    data = []
    capt.write((command + '\n').encode())
    time.sleep(stoptime)
    capt.write(('exit\n').encode())
    if capt.in_waiting > 0:
        back = capt.readlines()
        for i in range(len(back)):
            data_temp = back[i].decode('utf-8').strip()
            data.append(data_temp)
        print(f"Réponse reçue {command}: {data}")
    else : 
        print('Data empty')  
    return data
    
test1 = testcomm('test')
if test1 == 1 :
    data_t = sendcommand2('tube',2)
    data_b = sendcommand2('bulle',2) 
    capt.reset_output_buffer()  
capt.close()

TLDR : My Arduino code works individually, but when I try to read the data separately and send them to python, one of the two data stops working correctly.

Change the order of these pairs of calls so the delay() acts as a debounce for the digitalRead() calls.

Hi,
I tried as you said, the results is still the same : tube works fine, but not bulle (value is always 0 even when it should be 1).

So after reseaching a lot more, I found how to solve it, but I don't understand why it works. In the original code and hardware I got, there is a selftest part. I thought that as I was not using it, it wasn't necessary to keep it in the code. But when I tried my code with the variables declared, it works correctly again:

int TubeState = 0;  // Initialisation var tube
int LiquidState = 0;  // Initialisation var liquid
int TubePin = 2;     // Présence tube sur pin 2
int LiquidPin = 3;   // Présence liquide sur pin 3

// in the initial code
int SelftestActivation = 0; //Initialisation var for autotest
int SelftestPin = 7;  //Pin for autotest on pin 7
int SelftestCmd = 13; //bouton autotest sur pin 13 

void setup() {
  Serial.begin(9600);   // Initialisation de la communication série
//  delay(1000);          // Attendre 1 seconde
  pinMode(TubePin, INPUT);    // Initialisation pin digitale présence tube en entrée
  pinMode(LiquidPin, INPUT);  // Initialisation pin digitale présence liquide en entrée
// in the initial code
  pinMode(SelftestPin, OUTPUT);    //
  pinMode(SelftestCmd, INPUT);    //
  
  if (Serial.available() > 0) {  // Vérifie s'il y a des données envoyées depuis Python
    String command = Serial.readStringUntil('\n');  // Lit la commande envoyée par Python
    if (command == "test") {
      Serial.write(1); // Si la commande reçue est "test"
    }
    else {
      Serial.write("Mauvaise commande pour le test"); // Envoie mauvaise commande en retour
    }
  }
  else {
    Serial.write(0); // Envoie 0 si pas de commande reçue
  }
}

void loop() {
  if (Serial.available() > 0) {  // Vérifie s'il y a des données envoyées depuis Python
    String command = Serial.readStringUntil('\n');  // Lire la commande envoyée par Python

    if (command == "bulle") {     // Si la commande est "bulle", commencer la lecture
      while (true) {
        if (Serial.available() > 0) {  // Vérifie si une nouvelle commande est envoyée
          command = Serial.readStringUntil('\n');
          if (command == "exit") {   // Si la commande est "exit", arrêter la lecture
            break;
          }
        }
        // Lire l'état du tube et envoyer la donnée immédiatement
        LiquidState = digitalRead(LiquidPin);
        delay(50);  // Attente avant la prochaine lecture (ajuster selon besoin)
        Serial.println(LiquidState);  // Envoyer la donnée à Python
      }
    }
    else if (command == "tube") {     // Si la commande est "tube", commencer la lecture du tube
      while (true) {
        if (Serial.available() > 0) {  // Vérifie si une nouvelle commande est envoyée
          command = Serial.readStringUntil('\n');
          if (command == "exit") {   // Si la commande est "exit", arrêter la lecture
            break;
          }
        }
        // Lire l'état du tube et envoyer la donnée immédiatement
        TubeState = digitalRead(TubePin);
        delay(50);  // Attente avant la prochaine lecture (ajuster selon besoin)
        Serial.println(TubeState);  // Envoyer la donnée à Python
      }
    }
    // Une fois que "exit" est reçu, arrêter la lecture et sortir de la boucle
    if (command == "exit") {    } // juste sortie de boucle if
  }
}

I'm sorry, most of the comment are in French.
Well, anyway it works now, but I don't really understand why. So if someone does know, i'd be happy to learn.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.