MicroPython

La versión reducida del intérprete de Python.


Introducción

MicroPython es una implementación completa del lenguaje de programación Python, en su versión 3, que se ejecuta directamente en hardware integrado como las Raspberry Pi Pico, que permite trabajar en un entorno interactivo (REPL) para ejecutar comandos a través de USB Serial.

Instalación

La instalación del intérprete es algo sui generis. Uno descraga el intérprte en un formato específico para la Raspberry Pi, que debe ser montada como un dispositivo de almacenamiento (ojo con el botón BOOTSEL que debe ser presionado al conectar la placa al cable USB). Esto facilita el drag and drop del archivo descargado. El archivo copiado provoca que la placa reinicie y entonces queda el intérprete andando1.

Lo único desagradable de este proceso, es que en el computador anfitrión se dispara una advertencia sobre la desconexión inapropiada del dispositivo de almacenamiento.


Ejemplos

Esta es una copia de los proyectos que tengo en mi perfil en Wokwi (el cual parece no tener forma de proporcionar un enlace público al portafolio de proyectos, de aquí que coloque esta copia; pero sí permite obtener una liga a cada uno, click en el título de cada ejemplo). Cada ejemplo incluye el código Python, el JSON de la defición del simulador (por lo que cada uno puede ser usado en la tarjeta física o en el simulador provisto por Wokwi), y una imagen del circuito.

LED

Este es equivalente del «Hello, world!». Un sencillo programa para ver la interacción del intérprete de Python con un canal de salida (por defecto la consola) y la operación sobre un simple componente electrónico, un LED.

Código

from machine import Pin
from utime import sleep

print("Hello, Pi Pico!")

led = Pin(5, Pin.OUT)
while True:
  led.toggle()
  sleep(0.5)

Notas

  • Para quienes venimos de entornos Python más grandes un primer impulso puede ser buscar e instalar bibliotecas. Al menos para este ejemplo, no es necesario instalar nada adicional. Las bibliotecas usadas ya están incluidos en la distribución del intérprete.
  • El valor en Pin(), corresponde a la numeración de pines de la tarjeta de pines, que inicia desde cero.

JSON

{
  "version": 1,
  "author": "Anonymous maker",
  "editor": "wokwi",
  "parts": [
    {
      "type": "wokwi-pi-pico",
      "id": "pico",
      "top": 0,
      "left": 0,
      "rotate": 0,
      "hide": false,
      "attrs": {}
    },
    {
      "type": "wokwi-led",
      "id": "led1",
      "top": -2.67,
      "left": -65.33,
      "rotate": 0,
      "hide": false,
      "attrs": { "color": "red" }
    }
  ],
  "connections": [
    [ "pico:GP0", "$serialMonitor:RX", "", [] ],
    [ "pico:GP1", "$serialMonitor:TX", "", [] ],
    [ "pico:GP5", "led1:A", "green", [ "h0" ] ],
    [ "pico:GND.2", "led1:C", "black", [ "h0" ] ]
  ]
}

Imagen de la simulación

Traffic Lights v1.0

Este ejemplo simula un semáforo de tránsito: Tres luces en un ciclo continuo encendiendo determinado tiempo cada luz.

Código

from machine import Pin
from utime import sleep
  
ledRed = Pin(1, Pin.OUT)
ledYellow = Pin(5, Pin.OUT)
ledGreen = Pin(9, Pin.OUT)

while True:
  ledGreen.toggle()
  sleep(3)
  ledGreen.toggle()
  ledYellow.toggle()
  sleep(1)
  ledYellow.toggle()
  ledRed.toggle()
  sleep(3)
  ledRed.toggle()

Notas

  • Buscando simular a un semáforo real, el tiempo para el LED amarillo es menor al de los otros dos.

JSON

{
  "version": 1,
  "author": "Dr. Eduardo Rene Rodriguez Avila",
  "editor": "wokwi",
  "parts": [
    {
      "type": "wokwi-pi-pico",
      "id": "pico",
      "top": 20,
      "left": 60,
      "attrs": { "env": "micropython-20231227-v1.22.0" }
    },
    {
      "type": "wokwi-led",
      "id": "led1",
      "top": 3,
      "left": 0,
      "attrs": { "color": "red" }
    },
    {
      "type": "wokwi-led",
      "id": "led2",
      "top": 48,
      "left": 0,
      "attrs": { "color": "yellow" }
    },
    {
      "type": "wokwi-led",
      "id": "led3",
      "top": 98,
      "left": 0,
      "attrs": { "color": "green" }
    }
  ],
  "connections": [
    [ "pico:GND.1", "led1:C", "black", [] ],
    [ "pico:GP1", "led1:A", "blue", [] ],
    [ "pico:GND.2", "led2:C", "black", [] ],
    [ "pico:GP5", "led2:A", "blue", [] ],
    [ "pico:GND.3", "led3:C", "black", [] ],
    [ "pico:GP9", "led3:A", "blue", [] ],
    [ "$serialMonitor:RX", "pico:GP0", "", [] ]
  ],
    "dependencies": {}
}

Imagen de la simulación

Multithreding v1

Este ejemplo permite apreciar el uso de los dos cores con que cuenta el RB Pico. Actualmente en Wokwi, hay un problema con el uso de los threadings que hace que el simulador se alente terriblemente. En lo que respecta a la tarjeta el problema es la terminación de lo que podemos considerar es el thread que queda en segundo plano (ver notas).

Código

"""
Basic multi thread example
"""

from machine import Pin
from time import sleep
import _thread

terminate = False


def core1_thread():
    global terminate
    LEDblue = Pin(5, Pin.OUT)
    counter = 1
    while counter < 20 and not terminate:
        LEDblue.toggle()
        print("Core 1: " + str(counter))
        counter += 2
        sleep(2)
        

def core0_thread():
    global terminate
    LEDred = Pin(1, Pin.OUT)
    counter = 0
    while counter < 20 and not terminate:
        LEDred.toggle()
        print("Core 0: " + str(counter))
        counter += 2
        sleep(1)

second_thread = _thread.start_new_thread(core1_thread, ())

core0_thread()

try:
    while True:
        sleep(1)
except KeyboardInterrupt:
    terminate = True
    sleep(0.3)
    print("Terminating core 1")


Notas

  • Este ejempllo hace uso de la biblioteca _thread.
  • El ejemplo define dos funciones, cada una representa un proceso que es asignado a cada núcleo de procesameinto (core).
  • Cada proceso cuenta con un contador que es incremementado para tener un control de terminación del proceso en cuestión. Cada proceso muestra el avance del contador en pantalla y se queda en espera por una cantidad se segundos (sleep).
  • En cada iteración, se conmuta el estado del LED asociado.
  • Después de la definición de cada función, podrá verse el llamado a cada una de éstas. La llamada de la función que quedará en segundo plano, se hace asignándola a una función (¿será necesario esto? Es un punto a revisar).
  • La llamada a la función que «queda en primer plano» se hace directamente (sin asignar a una variable). Este llamado queda (aparentemente) en el proceso principal del intérprete de Python.
  • El bloque try ... except se agregó para dar una forma de poder terminar el proceso en segundo plano, ya que se observó que el núcleo de éste no queda disponible. La adición de la bandera terminate permitió poder tener una forma de capturar la señal de interrupción (CTRL+C) y permitir la terminación del proceso cambiando el valor de la bandera (supongo que habrá forma s más limpias o elegante de hacer esto… pro el momento asì queda).

JSON

{
  "version": 1,
  "author": "Eduardo Rene Rodriguez Avila",
  "editor": "wokwi",
  "parts": [
    {
      "type": "board-pi-pico-w",
      "id": "pico",
      "top": 0,
      "left": 0,
      "attrs": { "env": "micropython-20231227-v1.22.0" }
    },
    {
      "type": "wokwi-led",
      "id": "led1",
      "top": -22.8,
      "left": -101.8,
      "attrs": { "color": "red" }
    },
    {
      "type": "wokwi-led",
      "id": "led2",
      "top": 25.2,
      "left": -101.8,
      "attrs": { "color": "blue" }
    }
  ],
  "connections": [
    [ "led1:A", "pico:GP1", "green", [ "v0" ] ],
    [ "led1:C", "pico:GND.1", "green", [ "v0" ] ],
    [ "pico:GP5", "led2:A", "green", [ "h0" ] ],
    [ "led2:C", "pico:GND.2", "green", [ "v0" ] ]
  ],
  "dependencies": {}
}

Imagen de la simulación


Referencias

  1. «MicroPython», Raspberry Pi Documentation, web. Visited: 2024.09.05. URl: https://www.raspberrypi.com/documentation/microcontrollers/micropython.html.

Twitter Wordpress eMail
© Todos los derechos reservados.
Dr. Eduardo René Rodríguez Avila
Creación: 2024.09.05
Última actualización: 2024.09.25
El contenido de este sitio puede ser copiado y reproducido libremente mientras no sea alterado y se cite su origen. Marcas y productos registrados son citados por referencia y sin fines de lucro o dolo. Todas las opiniones son a título personal del o los autores de éstas y, salvo sea expresado de otro modo, deben considerarse como registro y expresión de la experiencia de uso de aquello que es tratado. Para conocer más sobre la posición de privacidad y responsabilidad de lo que se presenta en este sitio web y como ha sido obtenido, consulte la declaración al respecto.