En ésta ocasión vamos a ver como comunicarnos desde el pc con arduino utilizando Python.

Para ello utilizamos el USB como puerto serie.

En el ejemplo utilizamos un sensor PIR, aunque una vez realizada la comunicación entre dispositivos es posible trabajar con todo el potencial de arduino.

Esquema de conexión Arduino

Esquema de conexiones Arduino sensor PIR. Software utilizado para el diseño fritzing

Si quieres saber más del sensor PIR puedes ver aquí un ejemplo sencillo del mismo.

Código Arduino

const int pinPIR = 2;         // pin de entrada del PIR
const int pinLED = 13;        // pin del LED que indica estado del sensor

int estadoPIR = 0;            // estado del pin, inicia a 0
int estadoLED = LOW;          // estado del LED

String sensorNAME= "living room";
String smsg="";

void setup() {
  // SENSOR PIR
  pinMode(pinLED, OUTPUT); // selecciona pin de salida, en este caso el pin 13 activa led integrado en placa
  pinMode(pinPIR, INPUT);  
  Serial.begin(115200);
  Serial.setTimeout(1);
  digitalWrite(pinLED, LOW); // apaga el led
}

void loop() {
   estadoPIR = digitalRead(pinPIR);
   if (estadoPIR == HIGH) {  // si detecta movimiento enciende el led      
      if (estadoLED == LOW) { // si previamente estaba apagado lo enciende
        estadoLED=HIGH;
        digitalWrite(pinLED, HIGH);  // enciende el led
        smsg=sensorNAME;
        Serial.print(smsg);
        delay(2000);                // waits for a second
        estadoLED=LOW;
        digitalWrite(pinLED, LOW); // apaga el led        
      }
   } else { // si no se detecta movimiento
      if (estadoLED == HIGH) { // si previamente estaba encendido lo apaga
        estadoLED=LOW;
        digitalWrite(pinLED, LOW); // apaga el led
      }
   }
   delay(1000);                // waits for a second
}

El código es simple, si se detecta algo por el sensor PIR enciende el led 2 segundos y escribe mensaje, por puerto serie.

Código Python

from datetime import datetime, timedelta
import time
import os
import sys
import serial
import time

def write_read(arduino):
	time.sleep(0.05)
	data=None
	INTERVAL=60000*10
	nextmillisMSG=int(round(time.time() * 1000))+INTERVAL
	while not data:
		currentmillis = int(round(time.time() * 1000))
		data = arduino.readline()
		if(currentmillis>nextmillisMSG):
			nextmillisMSG=currentmillis+INTERVAL
			return "TIMEOUT##"
	#
	return data.decode("utf-8") # se pasa de bytes a string


def main():
	nparam=len(sys.argv)

	sport="/dev/ttyACM1" # por defecto
	for i in range(1,nparam):
		stmp=sys.argv[i]
		if stmp=="-port":
			nport=sys.argv[i+1] # ACM0, ACM1, ...
			sport="/dev/tty{}".format(nport)
				
	arduino = serial.Serial(port=sport, baudrate=115200, timeout=.1)
	INTERVAL=60000
	nextmillisMSG=0
	lastmillis=0
	ncount=0
	sValue=""
	while True:
		smsg=""
		value = write_read(arduino)
		currentmillis = int(round(time.time() * 1000))
		stmp="{}: {}...".format(datetime.fromtimestamp(float(currentmillis)/1000).strftime('%Y-%m-%d %H:%M:%S'), value)
		#print(stmp)
		strtstampup = datetime.fromtimestamp(float(currentmillis)/1000).strftime('%Y-%m-%d %H:%M:%S')
		if value=="TIMEOUT##":
			strtstampini = datetime.fromtimestamp(float(firsttime)/1000).strftime('%Y-%m-%d %H:%M:%S')
			strtstamplast = datetime.fromtimestamp(float(lastmillis)/1000).strftime('%Y-%m-%d %H:%M:%S')
			if ncount>0:
				smsg="END {} {} to {}: {}, count:{}".format(sValue, strtstampini, strtstamplast, value, ncount)
			sValue=""
			ncount=0
		else:
			lastmillis=currentmillis
			if ncount==0:
				sValue=value
				firsttime=currentmillis
				smsg="INIT {}: {}".format(strtstampup, value)

			ncount+=1

		if smsg!="":
			# en lugar de por pantalla, el smsg puede enviarse via webservice o telegram
			print(smsg)

main()

El programa espera datos en el puerto serie, cuando recibe algo guarda el sello de tiempo y sigue escuchando.

Con el fin de no estar continuamente escribiendo por pantalla, una vez detectado movimiento continua escuchando, si no vuelve a detectar nada en 10 min (INTERVAL 60000*10) Da por finalizada la alerta, escribe datos de inicio y fin de la alarma y se mantiene a la escucha, esperando nueva señal de arduino.

Si durante en ese intervalo de 10min detecta de nuevo movimiento, incrementa el contador y resetea el intervalo otros 10min.

Puerto Serie

Generalmente el puerto serie será /dev/ttyACM0 o /dev/ttyACM1, el por defecto en código es /dev/ttyACM1, si bien por parámetros se puede pasar el puerto con «-port <PUERTO>», por ejemplo para ACM2: «-port ACM2.

Testeado en Raspberry Pi OS y Ubuntu.

Espero sea de utilidad, cualquier duda o aportación en comentarios!

Gracias y Feliz dia! 😉

Deja tu comentario