Hi! I am trying to connect my Arduino Uno to two Python programs.
The main python program opens the serial.port communication with the Arduino and once it wants to execute the second code, it closes the serial.port communication so that the second code can open it.
When executing the first code, I am able to send data to my arduino and, the arduino is able to execute the desired commands. However, when closing the serial.port in order to execute the second code, I am able to send the data but Arduino is unable to execute the commands. Nevertheless, if I close my second code and open again the serial.port communication for the first code, everything works correctly.
My codes are really simple.
First code:
import serial # Para comunicación serial
import time # Para pausas temporales
from pynput import keyboard # Para escuchar eventos de teclado
import subprocess # Para ejecutar comandos del sistema
import re
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
# Configurar la conexión serial con Arduino
puerto_serial = serial.Serial('COM10', 9600)
time.sleep(2) # Esperar para que Arduino se inicie
finalizar = False # Para verificar si el programa debe finalizar
# Variable para almacenar la última tecla conocida
ultima_tecla = None
def on_press(key):
global finalizar
global ultima_tecla
try:
# Verificar si es una tecla imprimible
if hasattr(key, 'char') and key.char is not None:
char = key.char
# Finalizar si se presiona 'q'
if char == 'q':
print("Presionaste 'q', terminando...")
finalizar = True
return False
if ultima_tecla != 'q':
puerto_serial.write(b'q\n')
ultima_tecla = char
if char == 'a':
puerto_serial.write(b'a\n')
print("Flecha hacia arriba")
if ultima_tecla != 'a':
puerto_serial.write(b'a\n')
ultima_tecla = char
elif char == 'b':
puerto_serial.write(b'b\n')
print("Flecha hacia abajo")
if ultima_tecla != 'b':
puerto_serial.write(b'b\n')
ultima_tecla = char
elif char == 'l':
puerto_serial.write(b'l\n')
print("Flecha hacia la izquierda")
if ultima_tecla != 'l':
puerto_serial.write(b'l\n')
ultima_tecla = char
elif char == 'r':
puerto_serial.write(b'r\n')
print("Flecha hacia la derecha")
if ultima_tecla != 'r':
puerto_serial.write(b'r\n')
ultima_tecla = char
elif char == 'p':
puerto_serial.write(b'p\n')
print("Flecha para parar")
if ultima_tecla != 'p':
puerto_serial.write(b'p\n')
ultima_tecla = char
elif char == 'w':
puerto_serial.write(b'm\n')
if puerto_serial.is_open:
puerto_serial.close()
print("Puerto serial cerrado.")
archivo_a_ejecutar = r'C:/Users/Lara\Desktop/TFG/comprobar_lectura_x.py'
process = subprocess.Popen(['python', archivo_a_ejecutar])
process.wait() # Esperar a que el proceso termine
if process.returncode is not None: # Verificar si el proceso ha terminado
puerto_serial.open()
except Exception as e:
print(f"Error al procesar tecla: {e}")
# Iniciar el Listener para capturar eventos de teclado
with keyboard.Listener(on_press=on_press) as listener:
listener.join() # Mantener el Listener hasta que se presione 'q'
# Cerrar el puerto serial al finalizar
if puerto_serial.is_open:
puerto_serial.close()
print("Puerto serial cerrado.")
Second code that constants the comprobar_lectura_x.py:
import time
import subprocess
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import serial
import cv2
import keyboard
puerto_serial = serial.Serial('COM10', 9600)
# Variable para almacenar el último número del archivo
ultimo_numero = ""
ultimo_valor = ""
def imprimir_ultimo_numero(data):
global ultimo_numero, ultimo_valor
if data and data != ultimo_numero: # Verificar si hay datos y si son diferentes al último número
ultimo_numero = obtener_ultimo_numero(data)
print("Último número:", ultimo_numero)
if ultimo_numero == '1':
print("Flecha hacia arriba")
puerto_serial.write(b'a\n')
if ultimo_valor != '1':
puerto_serial.write(b'a\n')
ultimo_valor = ultimo_numero
elif ultimo_numero == '2':
print("Flecha hacia abajo")
puerto_serial.write(b'b\n')
if ultimo_valor != '2':
puerto_serial.write(b'b\n')
ultimo_valor = ultimo_numero
elif ultimo_numero == '3':
print("Flecha hacia izquierda")
puerto_serial.write(b'l\n')
if ultimo_valor != '3':
puerto_serial.write(b'l\n')
ultimo_valor = ultimo_numero
elif ultimo_numero == '4':
print("Flecha hacia derecha")
puerto_serial.write(b'r\n')
if ultimo_valor != '4':
puerto_serial.write(b'r\n')
ultimo_valor = ultimo_numero
elif ultimo_numero == '0':
print("PARAR")
puerto_serial.write(b'p\n')
if ultimo_valor != '0':
puerto_serial.write(b'p\n')
ultimo_valor = ultimo_numero
else:
print("Posición no reconocida")
puerto_serial.write(b'p\n')
ultimo_valor = ultimo_numero
def obtener_ultimo_numero(data):
# Eliminar no numéricos a la derecha
data = ''.join(filter(str.isdigit, data))
if not data:
return '0'
# último número de la cadena
return data[-1]
class MyHandler(FileSystemEventHandler):
def on_modified(self, event):
if event.src_path.endswith("x_value.txt"):
data = leer_archivo(event.src_path)
imprimir_ultimo_numero(data)
def leer_archivo(filename):
with open(filename) as fh:
line = fh.read()
return line
archivo_a_ejecutar = r'C:/Users/Lara\Desktop/TFG/Control_Arduino_witmotion.py'
#archivo_a_ejecutar = r'C:/Users/Lara\Desktop/TFG/comprobar_generar_lectura.py'
process = subprocess.Popen(['python', archivo_a_ejecutar])
ultimo_valor = '0'
event_handler = MyHandler()
observer = Observer()
observer.schedule(event_handler, path='.', recursive=False)
observer.start()
try:
while True:
if keyboard.is_pressed('q'):
print("Exiting program...")
# Terminate the subprocess
process.terminate()
break
time.sleep(0.1) # Add a small delay to reduce CPU usage
except KeyboardInterrupt:
observer.stop()
# Cerrar el puerto serial al finalizar
if puerto_serial.is_open:
puerto_serial.close()
print("Puerto serial cerrado.")
where the Control_Arduino_witmotion simply generates the values to be read on the x_value.txt file.
The arduino code generated PWM signals depending on the received character. For both python programs, the Arduino is able to read the characters but, for the second one, it does not generate the signals.
My arduino code is the following:
/ Definición de pines
const int pwmPin1 = 6;
const int pwmPin2 = 5;
const int pinX = A0; // Para el eje X del joystick
const int pinY = A1; // Para el eje Y del joystick
const int pinControl1 = 3; // Control de dirección
const int pinControl2 = 10; // Control de dirección
// Definición de modos
enum Mode { NONE, EYE, VOICE, MOVEMENT, JOYSTICK, STOP };
Mode currentMode = STOP;
// Velocidad predeterminada
int velocidad_fija = 20;
void move_backward() {
analogWrite(pwmPin1, velocidad_fija);
digitalWrite(pinControl1, HIGH); // Control hacia atrás
}
void move_forward() {
analogWrite(pwmPin1, velocidad_fija);
digitalWrite(pinControl1, LOW); // Control hacia adelante
}
void move_left() {
analogWrite(pwmPin2, velocidad_fija);
digitalWrite(pinControl2, LOW); // Control hacia la izquierda
}
void move_right() {
analogWrite(pwmPin2, velocidad_fija);
digitalWrite(pinControl2, HIGH); // Control hacia la derecha
}
void move_stop() {
analogWrite(pwmPin1, 100); // Detener PWM
analogWrite(pwmPin2, 100);
digitalWrite(pinControl1, LOW);
digitalWrite(pinControl2, LOW);
}
void setup() {
Serial.begin(9600); // Comunicación serial
// Configuración de pines
pinMode(pwmPin1, OUTPUT);
pinMode(pwmPin2, OUTPUT);
pinMode(pinX, INPUT);
pinMode(pinY, INPUT);
pinMode(pinControl1, OUTPUT);
pinMode(pinControl2, OUTPUT);
move_stop(); // Detener por defecto
}
void loop() {
if (Serial.available() > 0) {
String command = Serial.readStringUntil('\n'); // Leer comando serie
command.trim(); // Limpiar caracteres extra
if (command.startsWith("f")) {
String speedValue = command.substring(1); // Obtener valor después de 'v'
int newSpeed = speedValue.toInt(); // Convertir a número entero
if (newSpeed >= 0 && newSpeed <= 255) { // Validar rango para PWM
velocidad_fija = newSpeed; // Actualizar velocidad fija
Serial.println("Velocidad establecida a " + String(velocidad_fija));
} else {
Serial.println("Valor de velocidad fuera de rango.");
}
return; // Retornar para evitar otros comandos
}
// Cambiar modo según comando recibido
char cmd = command.charAt(0);
switch (cmd) {
case 'j':
currentMode = JOYSTICK;
break;
case 'v':
currentMode = VOICE;
break;
case 'a':
move_forward(); // Mover hacia adelante
Serial.println("Moving Forward");
break;
case 'b':
move_backward(); // Mover hacia atrás
Serial.println("Moving Backward");
break;
case 'l':
move_left(); // Mover hacia la izquierda
Serial.println("Moving Left");
break;
case 'r':
move_right(); // Mover hacia la derecha
Serial.println("Moving Right");
break;
case 'p':
move_stop(); // Detener
Serial.println("Stop");
break;
case 'm': // Modo de movimiento
currentMode = MOVEMENT;
break;
default:
break;
}
}
if (currentMode == JOYSTICK) {
handle_joystick(); // Control por joystick
} else if (currentMode == MOVEMENT) {
handle_movement('p'); // Control por movimiento
} else if (currentMode == STOP) {
move_stop(); // Detener movimiento
}
}
void handle_joystick() {
int xValue = analogRead(pinX);
int yValue = analogRead(pinY);
if (yValue > 400 && yValue < 600 && xValue < 600 && xValue > 500) {
move_stop(); // Detener
}
if (yValue > 1000 && xValue < 700 && xValue > 300) {
move_backward(); // Mover hacia atrás
} else if (yValue < 100 && xValue < 700 && xValue > 300) {
move_forward(); // Mover hacia adelante
}
if (xValue < 50 && yValue < 700 && yValue > 300) {
move_left(); // Mover hacia la izquierda
} else if (xValue > 1000 && yValue < 700 && yValue > 300) {
move_right(); // Mover hacia la derecha
}
}
void handle_movement(char command) {
switch (command) {
case 'a':
move_forward(); // Mover hacia adelante
Serial.println("Moving Forward");
break;
case 'b':
move_backward(); // Mover hacia atrás
Serial.println("Moving Backward");
break;
case 'l':
move_left(); // Mover hacia la izquierda
Serial.println("Moving Left");
break;
case 'r':
move_right(); // Mover hacia la derecha
Serial.println("Moving Right");
break;
case 'p':
move_stop(); // Detener
Serial.println("Stop");
break;
}
}