Taller de Micropython

Programación fácil y para todos de microcontroladores

Sin conocimientos previos

Ordenador obligatorio

Conexión WiFI

QR

_images/qr.svg

Kits de componentes

Simulador online

Hello world

print(" ".join(["hello", "world"]))
  

Posibles problemas

  • 🐧 GNU/Linux. No está en el grupo dialout o no están las reglas de udev (ver solución).

  • 🪟 Windows y Mac. No están los drivers instalados (ver solución).

Sobre mí Nekmo

_images/cara.svg

Programador Python

Otras charlas...

_images/talks1.jpg _images/talks2.jpg
_images/python-malaga-logo-white.png _images/plytix-logo-white.svg

Microcontroladores

¿Qué son?

  • Ventajas

    • 🤏 Pequeños

    • 🤑 Económicos

    • 🪫 Bajo consumo

  • Desventajas

    • 🐢 Poco potentes

    • 😓 Programación más compleja

Algunos usos

  • ☁️ Domótica

  • 🤖 Robótica

  • 🔌 Electrónica

  • 🚧 Prototipos

  • ...

GIF robot

Variantes

  • ESP8266/ESP32

    • 🤑 Muy económico

    • 😄 Múltiples variantes

    • 👥 Gran comunidad

  • Raspberry Pi Pico

    • 💸 Económico

    • 🔨 Gran soporte

    • 📚 Bien documentado

ESP32

Dinero

Características

  • 💪 Doble núcleo

  • 🛜 Conectividad WiFi

  • 📡 Conectividad Bluetooth

  • 🔌 Múltiples pines GPIO

  • 📟 ADC / DAC

Micropython

_images/micropython-logo.svg

Primeros pasos

¿Por qué Micropython?

  • Ventajas

    • 😄 Fácil de aprender

    • 🚀 Prototipado rápido

    • 🔋 Pilas incluidas

  • Desventajas

    • 🐢 Más lento

    • 📦 Menos módulos

    • 📏 Menos memoria

Nos recolocamos

Lo básico de electrónica

  • ⚡ La mayoría de los componentes son polarizados.

  • 🌍 Todos los componentes deben ir a tierra (cable negro).

  • 💡 Usar resistencias con los LED.

Protoboard

_images/protoboard.png

Avisos de seguridad

  • 🚫 NUNCA cortocircuitar pines.

  • ⚠️ CUIDADO con el pin de 5V.

  • 👁️ Fijarse bien antes de conectar cables y componentes.

Demos

Encender un led

Identificar los pines

_images/datasheet.png

Conectar el led

_images/resistor.png _images/led.png

Código led

from machine import Pin
from time import sleep

led = Pin(1, Pin.OUT)

while True:
    led.on()
    sleep(0.5)
    led.off()
    sleep(0.5)
  

LED analógico

Código led analógico

from machine import Pin, PWM
from time import sleep

led = Pin(1)
pwm = PWM(led)


while True:
    for i in range(0, 1024, 10):
        pwm.duty(i)
        sleep(0.01)
    for i in range(1023, -1, -10):
        pwm.duty(i)
        sleep(0.01)
  

GIF luces LED

Conectar un botón

_images/switch.png

Código botón

from machine import Pin, UART
from time import sleep

button = Pin(1, Pin.IN, Pin.PULL_UP)


while True:
    state = not button.value()
    print(int(state))
    sleep(0.1)
  

GIF recreativa

Conectar un LED RGB

_images/resistor.png _images/rgb_led.png

Código LED RGB

from machine import Pin, PWM
from time import sleep
import urandom


r = PWM(Pin(1), freq=1000)
g = PWM(Pin(2), freq=1000)
b = PWM(Pin(3), freq=1000)


def set_color(red, green, blue):
    r.duty(red)
    g.duty(green)
    b.duty(blue)


while True:
    red = urandom.getrandbits(10)
    green = urandom.getrandbits(10)
    blue = urandom.getrandbits(10)
    set_color(red, green, blue)
    sleep(1)
  

GIF cientos de cables

Protocolos de comunicación

  • 1️⃣ OneWire (1 pin)

  • 2️⃣ I2C (2 pines)

  • 3️⃣ SPI (3/4+ pines)

  • 📟 UART (2+ pines)

Conectar un led WS2812

_images/resistor.png _images/apa106.png

Código LED WS2812

from machine import Pin
from apa106 import APA106
from time import sleep

NUM_LEDS = 3

pin = Pin(1)
leds = APA106(pin, NUM_LEDS)
colors = [
    (255, 0, 0),
    (0, 255, 0),
    (0, 0, 255),
]
offset = 0


while True:
    for num_led in range(NUM_LEDS):
        next_color = colors[(num_led + offset) % NUM_LEDS]
        leds[num_led] = next_color
    leds.write()
    offset = (offset + 1) % NUM_LEDS
    sleep(0.5)
  

I2C

Conectar sensor y pantalla I2C

_images/sht41.png _images/ssd1306.png

Código sensor y pantalla I2C

from machine import Pin, I2C
from time import sleep
from ssd1306 import SSD1306_I2C
from sht4x import SHT4X


scl = Pin(1)
sda = Pin(2)
i2c = I2C(0, scl=scl, sda=sda)
print(i2c.scan())

oled = SSD1306_I2C(128, 64, i2c, 0x3C)
sensor = SHT4X(i2c, 0x44)


while True:
    temperature, humidity = sensor.measurements
    oled.fill(0)
    temperature_text = "Temp: {:.1f} C".format(temperature)
    humidity_text = "Hum:  {:.1f} %".format(humidity)
    oled.text(temperature_text, 0, 10)
    oled.text(humidity_text, 0, 30)
    oled.show()
    sleep(2)
  

WiFi y bluetooth

Código coche

import json
import time
import network
import web
from hardware import I2C
from hardware import Pin
from web import WebSocket
import uasyncio as asyncio

i2c0 = I2C(0, scl=Pin(26), sda=Pin(0), freq=400000)
i2c0.writeto_mem(0x38, 0x00, bytearray([0, 0, 0, 0]))

ap = network.WLAN(network.AP_IF)
ap.active(True)
ap.config(essid='roverc.pro', password='roverc.pro', authmode=network.AUTH_WPA_WPA2_PSK)

while not ap.active():
    time.sleep(1)

ip = ap.ifconfig()[0]
print('IP:', ip)

app = web.App(host='0.0.0.0', port=80)


def normalize_value(value: int | float) -> bytes:
    value = int(value)
    if value >= 128:
        value = 127  # The maximum value in positive is 127
    if value < 0:
        value = (256 + value)
    return value.to_bytes(1, "big")


def coords_to_mecano_wheels(x: int, y: int, maximum: int = 127):
    r1 = x + y
    r2 = -x + y
    r3 = -x + y
    r4 = x + y
    values = [r1, r2, r3, r4]
    max_val = max(abs(v) for v in values)
    if max_val > maximum:
        factor = maximum / max_val
        values = [v * factor for v in values]
    return [normalize_value(v) for v in values]


async def serve_static(w, filename, mimetype):
    # write http headers
    w.write('HTTP/1.0 200 OK\r\n')
    w.write(f'Content-Type: {mimetype}; charset=utf-8\r\n')
    w.write('\r\n')
    # write page body
    with open(filename, 'r') as f:
        w.write(f.read())
    # drain stream buffer
    await w.drain()


# root route handler
@app.route('/')
async def handler(r, w):
    return await serve_static(w, "index.html", "text/html")


# root route handler
@app.route('/joy.min.js')
async def serve_script(r, w):
    return await serve_static(w, "joy.min.js", "application/javascript")


# /ws WebSocket route handler
@app.route('/ws')
async def ws_handler(r, w):
    # upgrade connection to WebSocket
    ws = await WebSocket.upgrade(r, w)
    latest = None
    while True:
        evt = await ws.recv()
        if evt is None or evt['type'] == 'close':
            # handle closed stream/close event
            break
        elif evt['type'] == 'text':
            # print received messages and echo them
            print('Received:', evt['data'])
            data = json.loads(evt['data'])
            if "x" in data and "y" in data:
                x, y = data['x'], data['y']
                if (x, y) == latest:
                    continue
                try:
                    wheel1, wheel2, wheel3, wheel4 = coords_to_mecano_wheels(x, y)
                except OverflowError:
                    continue
                print("Wheels:", *(w[0] for w in (wheel1, wheel2, wheel3, wheel4)))
                i2c0.writeto_mem(0x38, 0x00, b"".join([wheel1, wheel2, wheel3, wheel4]))
                latest = x, y
            elif "claw" in data:
                value = 8 if data["claw"] else 87
                i2c0.writeto_mem(0x38, 0x10, value.to_bytes(1, 'big'))


# Start event loop and create server task
loop = asyncio.get_event_loop()
loop.create_task(app.serve())
loop.run_forever()
  

Demo coche

¡Pruébalo tú mismo!

ESP-Now

Demo dron

¡Muchas gracias a todos!

Recursos

Python Málaga

Contactar