MicroPython sin IoT


GPIO del ESP32

Mapa de los pines en el Arduino Nano ESP32 

2024-07-07 20_10_30-Exploring the Arduino Nano ESP32 _ MicroPython & IoT Cloud - YouTube.png
Extraído de Youtube Exploring the Arduino Nano ESP32

Como podemos observar, nuestro objetivo pues es el GPIO0

¿Dónde está físicamente los GPIO ?

Pues como podemos ver en este esquema el GPIO0 está en el pin BOOT1

2024-07-07 20_14_06-Alvik User Manual _ Arduino Documentation.png
Fuente CC-BY-SA https://docs.arduino.cc/tutorials/alvik/user-manual/

Como puedes observar, si cortocircuitas B1 = GPI0 = D15 con GND enciende el led RGB en color verdel esto pasa si Pones la placa en modo Bootloader.

Parpadeo LED ESP32

Objetivo

Vamos a hacer que parpadee el RGB integrado que tiene el ESP32 concretamente el color verde. 

Programa
#extraido de https://youtu.be/R51tf66es9w?t=1540

from machine import Pin
import time

myLED = Pin(0,Pin.OUT)

while True:
  myLED.value(0)
  time.sleep(0.5)
  myLED.value(1)
  time.sleep(0.5)
Aclaraciones
¿Y si queremos que parpadee el RGB en color ROJO qué cambiamos?

Easy peasy, cambiamos myLED = Pin (0, Pin.OUT) por myLED = Pin (46, Pin.OUT)

Que como puedes ver coincide también con un pin de poner en modo Bootloader: el BOOT0

Curiosidad: Por eso si se resetea Arduino Alvik (al encender, o al hacer dos clicks en el botón) se encienden y se apagan varias veces el led RGB en colores rojo y verde, pues se están activando los BOOTs

¿Y si queremos que parpadee el led color VERDE que hay al lado del USB (LED BUILTIN) ? ¿Qué cambiamos?

Easy peasy, cambiamos myLED = Pin (0, Pin.OUT) por myLED = Pin (48, Pin.OUT)

Resultado:

Parpadeo leds Alvik

El programa
from arduino_alvik import ArduinoAlvik
from time import sleep
import sys

alvik = ArduinoAlvik()
alvik.begin()
sleep(5)

while True:
  alvik.left_led.set_color(1, 0, 0)
  alvik.right_led.set_color(1, 0, 0)
  sleep(1)
  alvik.left_led.set_color(0, 0, 0)
  alvik.right_led.set_color(0, 0, 0)
  sleep(1)

Origen: CC-BY-SA https://courses.arduino.cc/explore-robotics-micropython/lessons/getting-started/

Resultado

Danza

Programa
from arduino_alvik import ArduinoAlvik
from time import sleep
import sys

alvik = ArduinoAlvik()
alvik.begin()
sleep(5)

while True:
  #Drive forward
  alvik.set_wheels_speed(10,10)
  sleep(2)
  #Turn left
  alvik.set_wheels_speed(0,20)
  sleep(2)
  #Turn right
  alvik.set_wheels_speed(20,0)
  sleep(2)
  #Drive backwards
  alvik.set_wheels_speed(-10,-10)
  sleep(2)

De CC-BY-SA https://courses.arduino.cc/explore-robotics-micropython/lessons/getting-started/

Vídeo

Más caña

La instrucción  alvik.set_wheels_speed(0,20) significa que da 0 rpm a la rueda izquierda y 20rpm a la derecha, donde rpm significa revoluciones por minuto ¿y si multiplicamos todos los rpm por 10?

Control con la mano

Aquí trataremos de hacer que ALVIK responda a la posición de nuestra mano a través de el sensor ultrasonidos que tiene en frente suyo. Tendrá que intentar permanecer en una distancia intermedia con lo que tiene enfrente suyo.

ESTE PROGRAMA ESTA POR DEFECTO (marcado con el led verde) cuando instalas el firmware). Ver https://libros.catedu.es/books/arduino-alvik/page/que-es-arduino-alvik

image.pngFuente https://docs.arduino.cc/tutorials/alvik/getting-started/ AuthorJose Garcia CC-BY-SA

from arduino_alvik import ArduinoAlvik
from time import sleep
import sys

alvik = ArduinoAlvik()
alvik.begin()
sleep(5)

#ESTABLECER VELOCIDAD

speed = 30

#IMPRIMIR VALORES Y ESTABLECER VARIABLES
while True:
    try:
        center = alvik.get_distance_top()
        print(center)
        sleep(0.01)

        #Si la mano esta cerca, Alvik se va hacia atras
        if center <= 12:
            alvik.set_wheels_speed(-speed, -speed)
        #Si la mano esta lejos, Alvik se acerca
        elif center <= 30 and center >= 18:
            alvik.set_wheels_speed(speed, speed)
        #Si la mano esta en una distancia de 12-18, Alvik se queda quieto
        else:
            alvik.set_wheels_speed(0, 0)

  #INTERRUPCIÓN DEL USUARIO
    except KeyboardInterrupt as e:
        print('over')
        alvik.stop()
        sys.exit()

Sigue líneas

Vamos a crear un programa SIGUE LÍNEAS. El objetivo es que el robot ALVIK sea capaz de seguir cualquier trazado de líneas utilizando sus sensores IR

image.pngFuente https://docs.arduino.cc/tutorials/alvik/getting-started/ AuthorJose Gracia CC-BY-SA

Para poder conseguirlo simplemente tendremos que establecer distintas condiciones de que hacer dependiendo de que sensor del robot detecta el trazado negro.

En este programa también hemos hecho que el robot nos trasmita los valores de los distintos sensores y que el usuario pueda interrumpir el proceso (todo suponiendo que el robot está conectado al equipo).

from arduino_alvik import ArduinoAlvik
from time import sleep
import sys

alvik = ArduinoAlvik()
alvik.begin()
sleep(5)

#VELOCIDAD DEL ROBOT
base_speed = 30

#IMPRIMIR VALORES DE LOS SENSORES
while True:
    try:
        ir_left, ir_center, ir_right = alvik.get_line_sensors()
        print(ir_left, ir_center, ir_right)
        sleep(0.01)
        
        #Condiciones de giro, avance y parar
        if ir_center > 300:
            alvik.set_wheels_speed(base_speed, base_speed)
        elif ir_left > 300:
            alvik.set_wheels_speed(0, base_speed)
        elif ir_right > 300:
            alvik.set_wheels_speed(base_speed, 0)
        else:
            alvik.set_wheels_speed(0, 0)
          
  #INTERRUPCION DEL USUARIO
    except KeyboardInterrupt as e:
        print('over')
        alvik.stop()
        sys.exit()

No va muy preciso, el código es mejorable:

Más preciso (agradecimientos a Mario Monteagudo Alda CP Ejea)

from arduino import *
from arduino_alvik import ArduinoAlvik

alvik = ArduinoAlvik()

def setup():
  alvik.begin()
  delay(1000)
 
def loop():
 
  global base, iteracion
 
  iz, ce, de = alvik.get_line_sensors()
  error = ((1*iz+2*ce+3*de)/(iz+ce+de))-2

  if ((ce > 400) and (de > 400)):
    alvik.left_led.set_color(1, 1, 0)
    alvik.right_led.set_color(1, 1, 0)
    base = 0
    ajuste = 30
    iteracion = 25
    
  elif ((ce > 400) and (iz > 400)):
    alvik.left_led.set_color(1, 1, 0)
    alvik.right_led.set_color(1, 1, 0)
    base = 0
    ajuste = -30
    iteracion = 25  
    
  elif (abs(error) < 0.75) and (iteracion == 0):  
    alvik.left_led.set_color(0, 0, 1)
    alvik.right_led.set_color(0, 0, 1)
    base = 60
    ajuste = 25 * error + 40 * error * abs(error) + 80 * error * error * error
    
  elif (abs(error) < 0.75):  
    alvik.left_led.set_color(0, 1, 0)
    alvik.right_led.set_color(0, 1, 0)
    base = 40
    ajuste = 20 * error + 40 * error * abs(error) + 80 * error * error * error
    iteracion = iteracion -1
    
  elif error > 0:
    alvik.left_led.set_color(1, 0, 0)
    alvik.right_led.set_color(1, 0, 0)
    base = 0
    ajuste = 60
    iteracion = 25
    
  else:
    alvik.left_led.set_color(1, 0, 0)
    alvik.right_led.set_color(1, 0, 0)
    base = 0
    ajuste = -60
    iteracion = 25
 
  veIz = base + ajuste
  veDe = base - ajuste

  alvik.set_wheels_speed(veIz,veDe)

  delay(50)

def cleanup():
  alvik.stop()

base = 40
iteracion = 0

start(setup, loop, cleanup)

Autor Mario Monteagudo Alda CP Ejea

Evita obstáculos

Programa

El núcleo del programa es la función api

get_distance(unit: str = 'cm')

Es sorprendente el sensor TOF como puede leer no sólo diréctamente sino a los lados :

El programa es extraido de https://docs.arduino.cc/tutorials/alvik/getting-started/ AuthorJose Garcia

from arduino_alvik import ArduinoAlvik
from time import sleep_ms
import sys

alvik = ArduinoAlvik()
alvik.begin()
sleep_ms(5000)  # waiting for the robot to setup
distance = 20
degrees = 45.00
speed = 50.00

while (True):

    distance_l, distance_cl, distance_c, distance_r, distance_cr  = alvik.get_distance()
    sleep_ms(50)
    print(distance_c)

    if distance_c < distance:
        alvik.rotate(degrees, 'deg')
    elif distance_cl < distance:
        alvik.rotate(degrees, 'deg')
    elif distance_cr < distance:
        alvik.rotate(degrees, 'deg')
    elif distance_l < distance:
        alvik.rotate(degrees, 'deg')
    elif distance_r < distance:
        alvik.rotate(degrees, 'deg')
    else:
        alvik.drive(speed, 0.0, linear_unit='cm/s')
Resultado

El código es mejorable, pues que rote 45 grados tantas veces puede hacer que se quede "enganchado" en una esquina, ver el final del vídeo:

Programas de test

En el repositorio https://github.com/arduino/arduino-alvik-mpy/tree/main/examples podemos encontrar ejemplos para ver el uso de los diferentes sensores y actuadores, por ejemplo

Sensor name Part name Test program name
RGB Color detection APDS 9660 read_color_sensor.py
ToF 8x8 Array - up to 350 cm LSM6DSOX read_tof.py
IMU - 6 degree VL53L7CX read_imu.py
3x Line follower custom made line_follower.py
7x Touch sensor AT42QT2120 read_touch.py
Actuator name Part name Test program name
Geared motors w/ encoder GM12-N20VA-08255-150-EN wheels_positions.py
RGB LEDs RGB LEDs leds_settings.py
Detector de color

Modificación del read_color_sensor.py

from arduino_alvik import ArduinoAlvik
from time import sleep_ms
import sys

alvik = ArduinoAlvik()
alvik.begin()

while True:
    try:
        r, g, b = alvik.get_color()
        h, s, v = alvik.get_color('hsv')
        print(f'RED: {r}, Green: {g}, Blue: {b}, HUE: {h}, SAT: {s}, VAL: {v}')
        print(f'COLOR LABEL:')
        print ({alvik.get_color_label()})
        sleep_ms(1000)
    except KeyboardInterrupt as e:
        print('over')
        alvik.stop()
        sys.exit()

Detector TOF

Si ejecutamos read_tof.py

from arduino_alvik import ArduinoAlvik
from time import sleep_ms
import sys

alvik = ArduinoAlvik()
alvik.begin()

while True:
    try:
        L, CL, C, CR, R = alvik.get_distance()
        T = alvik.get_distance_top()
        B = alvik.get_distance_bottom()
        print(f'T: {T} | B: {B} | L: {L} | CL: {CL} | C: {C} | CR: {CR} | R: {R}')
        sleep_ms(100)
    except KeyboardInterrupt as e:
        print('over')
        alvik.stop()
        sys.exit()

Detecta hasta los obstáculos por arriba

Giro

Si ejecutamos read_imu.py

from arduino_alvik import ArduinoAlvik
from time import sleep_ms
import sys

alvik = ArduinoAlvik()
alvik.begin()

while True:
    try:
        ax, ay, az = alvik.get_accelerations()
        gx, gy, gz = alvik.get_gyros()
        print(f'ax: {ax}, ay: {ay}, az: {az}, gx: {gx}, gy: {gy}, gz: {gz}')
        sleep_ms(100)
    except KeyboardInterrupt as e:
        print('over')
        alvik.stop()
        sys.exit()

Vemos como el eje x cambia de -1  0  a 1 según la posición

Robótica para infantil

Se puede hacer un robot tipo Beebot, Colby, Escornabot.
Si no conocéis estos robots mirar el curso de Aularagon

bee-bot-2591033446.jpgescornabot-4126551417.jpg

Podemos cargar el siguiente programa, modificado de https://github.com/arduino/arduino-alvik-mpy/blob/main/examples/touch_move.py

from arduino_alvik import ArduinoAlvik
from time import sleep_ms
import sys

alvik = ArduinoAlvik()
alvik.begin()

alvik.left_led.set_color(1, 0, 0)
alvik.right_led.set_color(1, 0, 0)

distancia = 15

movements = []


def blink():
    alvik.left_led.set_color(1, 0, 1)
    alvik.right_led.set_color(1, 0, 1)
    sleep_ms(200)
    alvik.left_led.set_color(1, 0, 0)
    alvik.right_led.set_color(1, 0, 0)


def add_movement():
    global movements

    if alvik.get_touch_up():
        movements.append('forward')
        blink()
        while alvik.get_touch_up():
            sleep_ms(100)
    if alvik.get_touch_down():
        movements.append('backward')
        blink()
        while alvik.get_touch_down():
            sleep_ms(100)
    if alvik.get_touch_left():
        movements.append('left')
        blink()
        while alvik.get_touch_left():
            sleep_ms(100)
    if alvik.get_touch_right():
        movements.append('right')
        blink()
        while alvik.get_touch_right():
            sleep_ms(100)
    if alvik.get_touch_cancel():
        movements = []
        for i in range(0, 3):
            val = i % 2
            alvik.left_led.set_color(val, 0, 0)
            alvik.right_led.set_color(val, 0, 0)
            sleep_ms(200)
        while alvik.get_touch_cancel():
            sleep_ms(100)


def run_movement(movement):
    if movement == 'forward':
        alvik.move(distancia, blocking=False)
    if movement == 'backward':
        alvik.move(-distancia, blocking=False)
    if movement == 'left':
        alvik.rotate(90, blocking=False)
    if movement == 'right':
        alvik.rotate(-90, blocking=False)
    while not alvik.get_touch_cancel() and not alvik.is_target_reached():
        alvik.left_led.set_color(1, 0, 0)
        alvik.right_led.set_color(1, 0, 0)
        sleep_ms(100)
        alvik.left_led.set_color(0, 0, 0)
        alvik.right_led.set_color(0, 0, 0)
        sleep_ms(100)

while alvik.get_touch_ok():
    sleep_ms(50)

while not (alvik.get_touch_ok() and len(movements) != 0):
    add_movement()
    sleep_ms(50)

try:
    while True:
        alvik.left_led.set_color(0, 0, 0)
        alvik.right_led.set_color(0, 0, 0)
        for move in movements:
            run_movement(move)
            if alvik.get_touch_cancel():
                break

        movements = []

        while not (alvik.get_touch_ok() and len(movements) != 0):
            alvik.left_led.set_color(1, 0, 0)
            alvik.right_led.set_color(1, 0, 0)
            alvik.brake()
            add_movement()
            sleep_ms(100)
except KeyboardInterrupt as e:
    print('over')
    alvik.stop()
    sys.exit()

El resultado es que perfectamente se puede usar como robótica en infantil
Los robots Beebot, Colby, Escornabot. utilizan la distancia de 15cm de desplazamiento, justo lo mismo que los palos depresores de lengua, luego fácilmente uno puede hacer un circuito :

Manejando servos

Conexión

Se pueden conectar hasta dos servos, el A es el de arriba y el B es el de abajo

2024-07-11 13_06_45-Qué es Arduino Alvik _ Librería CATEDU.png

La api set_servo_positions

Nos permite controlar estos dos servos  indicando el primer argumento el ángulo (0-180) del A y en el segundo el del B set_servo_positions(a_position: int, b_position: int)

Programa

Extraído de https://docs.arduino.cc/tutorials/alvik/user-manual/#add-servo-motors 

from arduino_alvik import ArduinoAlvik

import time

alvik = ArduinoAlvik()

alvik.begin()

while True:
    alvik.set_servo_positions(0,0)
    time.sleep(2)
    alvik.set_servo_positions(90,180)
    time.sleep(2)
    alvik.set_servo_positions(180,90)
    time.sleep(2)
    alvik.set_servo_positions(90,0)
    time.sleep(2)
Resultado

Más ejemplos

Los puedes encontrar en https://courses.arduino.cc/explore-robotics-micropython/

2025-03-28 14_18_30-Lessons _ Explore Robotics in MicroPyton.png

2025-03-28 14_19_02-Lessons _ Explore Robotics in MicroPyton.png

2025-03-28 14_19_56-Lessons _ Explore Robotics in MicroPyton.png

I2C

El protocolo I2C se desarrolló originalmente en 1982 para receptores de TV, y su característica principal son dos líneas (aparte de la alimentación 3.3V-5V y masa):

Un dispositivo hace de Master y proporciona la señal de reloj. (Puede haber extraordinariamente más de un master) y los otros dispositivos, (en plural, con los mismos cables, aquí esta la ventaja) hacen de Slave y cada uno tiene asociado una dirección.

Ejemplos de I2C con Arduino:
- Conexión con pantalla LCD https://libros.catedu.es/books/programa-arduino-mediante-codigo/page/lcd
- Comunicación entre dos Arduinos https://dronebotworkshop.com/i2c-arduino-arduino/

En Arduino Alvik, los pines SDA y SCL están conectados en los pines 11 y 12 y de ahí salen por los conectores QWIIC y Grove :
datasheet_connectors.png

Podemos escanear los dispositivos I2C que están conectados y averiguar la dirección que tienen asociada :

from machine import I2C
from machine import Pin

i2c = I2C(0, scl=Pin(12, Pin.OUT), sda=Pin(11, Pin.OUT))

print()
print('Scan i2c bus...')
print()

devices = i2c.scan()

if len(devices) == 0:
    print("No i2c device !")
else:
    print('i2c devices found:',len(devices))
print()

for device in devices:
    print("Decimal address: ",device," | Hexa address: ",hex(device))

print()

Fuente : https://docs.arduino.cc/tutorials/alvik/user-manual/#grove-connectors

He conectado un OLED en el conector Grove

2025-05-07 13_24_53-WhatsApp.png

Y me ha salido que tenía dos dispositivos, el primero es interno del Alvik, que tiene dirección 43 y el segundo es el OLED conectado con la dirección 60 en decimal o 0x3c en hexadecimal que es la dirección por defecto en el OLED ssd1306:

2025-05-07 13_29_41-Arduino Lab for MicroPython.png

Si ejecutamos el siguiente script, vemos que necesita importar la librería ssd1306 (se puede ver en su repositorio, que es compatible con el display ssd1306 128x64 I2C y con ESP32 de Arduino).. Esta librería tiene las funciones necesarias para visualizar lo que uno quiera en el OLED. Funciones de esta librería

from machine import I2C
from machine import Pin
import ssd1306

i2c = I2C(0, scl=Pin(12, Pin.OUT), sda=Pin(11, Pin.OUT))

# dirección por defecto 0x3c
oled = ssd1306.SSD1306_I2C(128, 64, i2c)

while True:
  oled.text('HOLA CATEDU !', 10, 10)      
  oled.show()

Y el resultado es :

2025-05-07 13_35_08-WhatsApp.png

Si quieres por ejemplo esto :
hello_world.jpg
mira este código