Micropython

Programación fácil y para todos de microcontroladores

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

Micropython

_images/micropython-logo.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

Micropython

_images/micropython-logo.svg

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

Primeros pasos

  • Flashear siguiendo la web de Micropython

  • 📝 IDE web (ViperIDE) o local (Thonny)

Demos

Encender un led

Identificar los pines

_images/datasheet.png

Conectar el led

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

from machine import Pin, PWM
from time import sleep

led = PWM(Pin(1), freq=1000)

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

GIF luces LED

Conectar un botón

Código botón

from machine import Pin
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

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

Código LED WS2812

import apa106
from machine import Pin
from time import sleep

NUM_LEDS = 3
PIN_NUM = 1

leds = apa106.APA106(Pin(PIN_NUM), NUM_LEDS)
colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]
positions = list(range(NUM_LEDS))

while True:
    for i in range(NUM_LEDS):
        leds[i] = colors[positions[i]]
    leds.write()
    positions = [(pos + 1) % NUM_LEDS for pos in positions]
    sleep(0.5)
  

I2C

Conectar sensor y pantalla I2C

Código sensor y pantalla I2C

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

i2c = I2C(0, scl=Pin(1), sda=Pin(2))
print(i2c.scan())
oled = ssd1306.SSD1306_I2C(128, 64, i2c, 0x3C)
sensor = sht4x.SHT4X(i2c, 0x44)

while True:
    temperature, humidity = sensor.measurements
    oled.fill(0)
    oled.text("Temp: {:.1f} C".format(temperature), 0, 0)
    oled.text("Hum:  {:.1f} %".format(humidity), 0, 20)
    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!

¡Muchas gracias a todos!

Recursos

QR

_images/qr.svg

Python Málaga

Contactar