Está en la página 1de 34

1 Clase

BLINKING LED EN RASPBERRY PI

El blinking LED es una sencilla secuencia de comandos con nuestro lenguaje al uso, que a
partir de aquí será Python, en el que buscamos hacer una secuencia de encendido y apagado
de un simple LED. La idea es conseguir un led intermitente con una cadencia dada.
En el capítulo anterior vimos cómo hacer esto desde comando directos y ahora queremos
hacer un programa que nos permita repetir esto, sin tener que escribirlo a mano cada vez todo
eso. Es decir, que un programa consiste en registrar unas instrucciones, para poderlas repetir
en el futuro tantas veces como necesitemos.
También es importante para los nuevos, entender que en un programa es como una receta
precisa de pasos consecutivos que se van ejecutando uno después de otro, y en el orden que
lo especificamos (Mientras no digamos otra cosa)
Por eso el blinking LED nos sirve para entender que para conseguir una luz intermitente, basta
con hacer una secuencia en la que:

• Encendemos el led.
• Esperamos un tiempo dado.
• Apagamos el led
• Esperamos un tiempo dado.
• Vuelta a empezar.
En la sesión anterior vimos cómo hacer esto a mano y hoy vamos a pasar a ver cómo
hacemos más menos lo mismo con un sencillo programa que podamos guardar para su uso
posterior en el futuro.
Vamos a usar el mismo montaje hardware que usamos en la sesión anterior:
Empecemos abriendo el IDLE de Python 3 en nuestra Raspberry Pi. Ahora, vamos a escribir
nuestro primer programa. Haz File\ New File en el menú del IDLE. Te saldrá un documento en
blanco donde puedes editar tus programas. Ahora podemos escribir aquí nuestras
instrucciones, guardarlo y ejecutarlo en el futuro.
Para poder pasar a instrucciónes el algoritmo que marcamos un poco más arriba, tenemos
empezar importando la librerías GPIO para poder dar las ordenes de encendido y apagado,
algo que ya tenéis dominado.

import RPi.GPIO as gpio

Después usaremos las mismas instrucciones que en la sesión anterior para encender y
apagar el LED pero antes necesitamos poder usar una función que nos permita hacer la
temporización. ¿Y adivinas qué? Hay una librería que podemos importar para eso:
import time

Esta librería dispone de instrucciones que nos permitan gestionar plazos e indicar
a Python que espere un tiempo antes de encender o apagar el LED. Enseguida veremos
cómo.
Ahora tenemos que declarar en Python que sistema de referenciar pines vamos a usar, y que
queremos definir el pin 12 como salida, tal y como vimos en la sesión anterior:

gpio.setmode(gpio.BOARD)
gpio.setup(12, gpio.OUT)

Y ahora nos falta escribir propiamente las instrucciones que encienden el LED, y esperan
medio segundo antes de apagarlo:

gpio.output(12, True)
time.sleep(0.5)

Y ahora cuando queremos apagar:

gpio.output(12, False)
time.sleep(0.5)

La instrucción time.sleep, hace las mismas funciones que el delay en Arduino, pero se le pasa
el valor en segundos para la espera que queremos. Así 0.5 supone medio segundo.
Si vamos escribiendo todo esto en nuestro primer programa, tendremos algo así:

Fijaros que en esta ocasión al no escribirlo en el intérprete, Python no ha ejecutado nada de


lo que escribimos, sino que simplemente, vamos creando un fichero de texto con nuestro
programa que correremos un poco más tarde.
Salvemos ahora el programa con \\File\ Save as y llama blink a tu programa. Python le añadirá
la extensión. py
Hemos guardado nuestro primer programa.¡ Enhorabuena!, falta ejecutarlo ahora. Para ello
podemos usar el menú \Run\runModule, o bien pulsar F5 para lanzar su ejecución.
Python irá interpretando y ejecutando todas las instrucciones en secuencia y si encuentra
algún error os devolverá un divertido mensaje de error de los que hacen las delicias de los
novatos. Algo así como:
Cuando os ocurra esto (Uy sí. Os va a pasar y mucho) tenéis que leer lo que os dice y
procurar interpretar el mensaje para corregir el error. En mi caso está claro que le he pedido
importar Rpi.GPIO en lugar de RPi.GPIO, recordad que las mayúsculas cuentan.
Así que tenéis que corregir el error, salvar de nuevo el programa y darle de nuevo a F5 para
que lo ejecutéis (Tantas veces como sea necesario hasta que no haya errores. Os va a
encantar). Y estad atentos porque lo único que va a hacer es encender y apagar el LED una
única vez, así que no lo perdáis de vista.

• Recibireis un agradable mensaje de error explicándoos que ese pin esta en uso (De las
ejecuciones anteriores y que puedes deshabilitar las advertencias con la instrucción
gpio.setwarnings(False), pero no te preocupes de eso ahora y fíjate que efectivamente, el LED
se ilumina y apaga una sola vez.
Caramba toda esa pila de líneas para hacer un blinking LED y… ¿Solo conseguimos que se
encienda y apague una miserable vez?
Pues me temo que es lo que le habéis dicho en vuestro programa… y nada más. Para los
novatos conviene recordar que el ordenador tiene la desagradable costumbre de hacer
exactamente lo que le dices y no lo que querías decirle.
Las personas tenemos la costumbre de interpretar lo que nos dicen, tratando de contentar a
quien nos habla y por eso algunas veces hacemos lo que creemos que nos quieren pedir y no
lo que nos han pedido.
Pero esto eta muy fuera del alcance de los ordenadores hoy por hoy, y por eso tenemos que
aprender a programar con un lenguaje formal como Python. Para asegurarnos de que lo que
decimos no admite interpretación posible: Solo se puede entender de una manera.
Lo primero que llamará la atención a los que vienen de C++ o Java, es que no hay punto y
como al final de la línea, solo intro. Python entiende que el intro es suficiente indicio de fin de
instrucción (me encanta lo vago que era quien lo diseño así)

ITERANDO INSTRUCCIONES

Por tanto, nuestra primera versión del programa justo enciende y apaga una vez el LED. En
Arduino el loop se ejecutaba sin pausa, pero Raspberry es un entorno un poco más
tradicional en esto y no existe el loop (Pero ya veremos que podemos montarlo nosotros
mismos).
Pero podemos cambiar nuestro programa y hacer que se encienda y apague, digamos 10
veces seguidas. ¿Cómo haríamos algo así?
La primera idea es copiar 10 veces seguidas las 4 instrucciones que encienden y apagan el
LED. Esto es humano, pero nos hemos metido a programadores, porque somos vagos y no
queremos trabajar y me canso solo de pensar en copiar algo 10 veces. Y porque si queremos
hacerlo 256 veces ya me contarás.
Como en todos los lenguajes, la instrucción for repite un bucle un numero de veces dado, y su
estructura en Python es muy sencilla, empecemos con un pequeño ejemplo.
Suponte que quiero escribir los números del 1 al 10, Crea un nuevo programa en Python que
podemos llamar ciclo y ejecútalo con estas instrucciones:

for x in range ( 1, 10):


print(x)
El resultado inmediato, al ejecutar, será:

La instrucción for va dando a la variable x valores comprendidos entre 1 y 10 de uno en uno


pero aunque empieza en 1, el ultimo valor que toma es 9 no 10. Mucho ojo con esto, que es
una manía de Python.
Cuando hacemos la iteración x va tomando valores consecutivos que le mandamos imprimir y
por eso se imprimen los valores del 1 al 9.
Seguro que os habéis dado cuenta de que no hay punto y coma al final ni tampoco llaves
como en C++. Pero hay unos dos puntos (:) al final del for que es mandatorio y vale la pena
que hablemos de esto, porque si lo omites es un error de sintaxis.
Cuando en Python vas a usar una instrucción que se aplica a una o más líneas que vienen a
continuación, no necesitas llaves o punto y coma, pero si necesitas indicarle que hay un
bloque de instrucciones a continuación median el símbolo dos puntos “:”
Además, y esto es importante, el bloque a ejecutar se marca por un indentado común entre las
líneas que componen el bloque. Seguramente te habrás dado cuenta de que en cuanto has
puesto los dos puntos Python ha saltado directamente a una nueva indentación con el nuevo
intro.
En C++ los bloques de instrucciones se delimitaban entre llaves, pero en Python son las
indentaciones las que hacen esa función. Esto es una clave de Python porque te obliga a usar
la indentacion de un modo sistemático, lo que hace que los programas sean muy fáciles de
leer y organizar.
Vamos a insistir un poco con esto. Imagínate este programa:
for x in range ( 1, 10):
print(x)
print( 2* x)

La salida en pantalla será esta:

Todo normal según decimos. Imprime un número en cada línea y su doble en la


siguiente. ¿Pero que crees que hara esto?
for x in range ( 1, 10):
print(x)
print( 2* x)
Como puedes ver, a cambiar la indentación, Python entiende que el bloque for solo afecta a la
primera línea print(x). Hace la iteración, imprime lo valores del 1 al 9 tranquilamente y al
acabar ejecuta la línea print(2 * x) una única vez e imprime el 18.
Así que cuidado. Recuerda que en Python, la indentación juega una función clave delimitando
la estructura de tus programas ¿Vale? Es muy intuitivo y te acostumbraras enseguida.

• Así que nada de andar cambiando los espaciados del indentado alegremente, si no te gusta el
que viene por defecto a base de espacios en blanco, porque te explotará en la cara.
• Se puede cambiar desde las opciones del IDLE, pero de momento quédate como estás y
empieza a familiarizarte con Python sin cosas raras.
Volviendo a nuestro LED, ¿Cómo hacemos para que se encienda y apague 10 veces? Pues
con un bucle for en el que le demos el conjunto de instrucciones que veíamos antes:
import RPi.GPIO as gpio
import time

gpio.setmode(gpio.BOARD)
gpio.setup(12, gpio.OUT)

for x in range ( 0, 10):


gpio.output(12, True)
time.sleep(0.5)

gpio.output(12, False)
time.sleep(0.5)
2 Clase

MAS SOBRE PYTHON Y FOR.

Ya hemos visto varias opciones posibles con for, parece que no hay mucho más que ver, pero
el caso es que aún queda alguna munición que disparar.
En la última sesión vimos cómo usar el range en combinación con el for y vimos que podíamos
usarlo cómodamente para generar números dentro de un rango de acuerdo a unas ciertas
reglas y vimos que podías usar listas de números enteros crecientes o decrecientes e incluso
usar un escalón o salto entre dos números consecutivos en el rango, como en:
Range es muy cómodo de usar cuando los números que queremos asignar cumplen una
cierta progresión numérica, pero un poco menos útil cuando los números que queremos no
siguen ninguna relación y por eso en la sesión anterior usamos la numeración de los
pines GPIO en el modo BCM o broadcom, para conseguir 10 GPIO consecutivos que pudiese
incluir en la instrucción for range.
Pero tengo que confesaros un secreto. En realidad os engañe un poco (Y me encanta, que
queréis que os diga). Os presenté las cosas de ese modo porque es lo que alguien que venga
de C++ o Java espera que sea el for, pero Python es mucho más versátil de lo que parece a
primera vista, y en esa cláusula hay un pequeño secreto.
Python puede iterar lo que hay en el “for x in range”, al especificar un rango numérico… pero
tambien puede recorrer una lista de números sin más, como por ejemplo:

>>> for x in (3,4,6,2,8,14):


print (2*x)
6
8
12
4
16
28

Fíjate que ni siquiera necesita que los números sean consecutivos. Le basta con que le
pasemos lo que en Python se llama un elemento iterable. En este caso una lista, de las que
tendremos que hablar largo y tendido en un futuro próximo, pero que consiste simplemente en
una colección de números separados por comas entre paréntesis.
Así pues, nuestro programa Blink_2 de la sesión anterior, no necesita que usemos 10 pines
consecutivos para que la instrucción for los recorra cómodamente. Podriamos escribirlo de
esta otra manera que es completamente equivalente:

import RPi.GPIO as gpio


import time
gpio.setmode(gpio.BCM)

for x in range ( 16, 26):


gpio.setup(x, gpio.OUT)

for x in range ( 16, 26):


gpio.output(x, True)
time.sleep(0.15)
gpio.output(x, False)
time.sleep(0.15)

Sino que tranquilamente podíamos haber elegido el modo de numeración GPIO externo con

gpio.setmode(gpio.BOARD)

A condición después de pasarle al for la numeración externa de los pinos alegremente, tanto si
son consecutivos como si no, con lo que podríamos sustituir las líneas:

gpio.setmode(gpio.BCM)
for x in range ( 16, 26):

Por estas otras:

gpio.setmode(gpio.BOARD)
for x in (36, 11, 12, 35, 38, 40, 15, 16, 18, 22 ):

Sin que se note la diferencia (No te fíes de mi pruébalo), Pero claro está, si hago eso en la
primera sesión vacío la plazo en un momento y en cambio ahora ya estáis familiarizados con
la instrucción for. ¿Qué te parece? ¿A que es elegante?
Para mi gusto, la primera forma que usamos en la última sesión, es mucho más elegante que
una enumeración de pines, pero si por cualquier motivo prefieres usar una de las dos formas
de referenciar los GPIO tiene una solución tan sencilla como esta.

EL FOR Y LOS STRINGS

No hemos entrado con los Strings aun. Pero para los que son nuevos, diremos que un String
es una colección de caracteres entrecomillados, o sea un texto como por ejemplo:

A = “Buenos días”

Volveremos mucho más detenidamente sobre los Strings, en un futuro próximo, pero no
quería dejar pasar la ocasión de mostraros que otro ejemplo de lista iterable con un for puede
ser una lista de Strings, que simplemente es una lista de textos entre comillas, separados por
comas:

>>> for x in ("uno","dos","tres","cuatro"):


print(x)
uno
dos
tres
cuatro

De nuevo Python da muestras de ser especial, no le importa mucho lo que le pases siempre
que contenga elementos que él pueda recorrer. Por eso cuando hacemos una cláusula del tipo
de:

for x in range(6):
print(x)

Lo importante es el in, porque es lo que la instrucción for, va a iterar. El range lo que hace es
generar sobre la marcha esa lista de números de acuerdo al patrón que le especificamos.
Pero no creas que solo podemos usar cosas así. For acepta jugar con Strings de un modo
muy cómodo, como por ejemplo haciendo lo siguiente:

a = "Buenos dias"
for x in range(len(a)):
print(a[x])
B
u
e
n
o
s

d
i
a
s

Para los que hayáis programado en C++, como los que venís de Arduino, lo de arriba tiene
mucho sentido porque veis la variable a como una String que recorremos hasta su longitud
final.
• len(a) es una funcion Python que devuelve el numero de caracteres que hay en la variable en
cuestión.
Sin embargo Python puede descolocaros un poco con algo como esto, que es exactamente
igual que lo anterior:

a = "Buenos dias"
for x in range(len(a)):
print(x)
B
u
e
n
o
s

d
i
a
s

Python entiende que una String es un elemento iterable, y por ello va recorriendo sus
caracteres constituyentes en orden y sin cortarse un pelo.
Este modo de aceptar listas (y otras cosas iterables) es algo que le da a Python una potencia
sorprendente que es muy útil en muchas ocasiones.

EL BUCLE WHILE

La instrucción for, efectúa un bloque de instrucciones, que siguen a los dos puntos, un número
definido de veces. Pero a veces, no sabemos muy bien cuantas veces debemos ejecutar el
bloque de instrucciones porque queremos que salga cuándo se cumpla una condición dada.
Por ejemplo, podemos hacer un programa que nos pida un número y lo eleve al cuadrado.
Podemos repetir esto hasta que se cumpla una condición de salida, por ejemplo que el
número que le damos sea 0.
El programa repetirá el bucle pidiéndonos números que el elevará al cuadrado alegremente y
sin ningún sentido hasta que le demos el número 0, en cuyo caso entenderá que queremos
librarnos ya de semejante sandez.
Afortunadamente todos los lenguajes de programación disponen de una instrucción como esta
y en el 90% de los casos se llama While. Podríamos usarla para empezar escribiendo un
programa muy sencillo como este:
# Calculo de los cuadrados con condición de salida

while(True):
a = input("Dáme un numero: ")
a= int(a)
print("El cuadrado de ",a," es: ", a*a)
print("-----------")

En primer lugar, fíjate que hemos usado el símbolo “#” para indicar que lo que sigue es un
comentario hasta el cambio de línea.

• Recuerda que es muy buena política escribir comentarios en tus programas, porque si vuelves
a ellos al cabo de 3 meses no recordaras nada de lo que hoy te parece evidente.
• Hazte un favor y comenta profusamente tus programas. Me lo agradecerás.
La siguiente línea:

while(True):

Indica que repitamos lo que vienen el bloque de instrucciones a continuación ad infinitum, es


decir que para salir de aquí tenemos que romper la ejecución del programa. Luego veremos
cómo.
La idea es que la instrucción while evalúa a true o false la condición que le pasamos entre
paréntesis. Si es true, ejecuta el bloque. Si es falsa, simplemente termina la ejecución del
bucle.
Como en todas las instrucciones que afectan a bloques de múltiples instrucciones, al final de
la línea hay un símbolo “:” para indicarlo. No incluirlo sería un error fulminante.
Por ultimo lo que recogemos con input es siempre un String de texto, y tenemos que
convertirlo a numero si queremos operar con él, para eso es int(a)
Por último, este programa continuará aburriéndote a base de pedirte números para elevarlos
al cuadrado y tú te vas a cansar mucho antes que él. Pero no hay modo de terminar este
programa si no es rompiéndolo, porque no especificamos ninguna condición de salida.
Por eso vamos a tener que terminar el programa por las malas con [CTRL]+D o [CTRL]+C,
algo que podéis usar si en el futuro os encontráis en una situación como esta.
Dáme un numero:
Traceback (most recent call last):
File “C:/Python35/cuadrado.py”, line 5, in <module>
a = input(“Dáme un numero: “)
File “C:\Python35\lib\idlelib\PyShell.py”, line 1386, in readline
line = self._line_buffer or self.shell.readline()
KeyboardInterrupt
¿Y cómo podemos modificar el programa para que haya una salida un poco más
elegante? Basta con especificar por ejemplo que cuando a tenga el valor 0, termine.
Podríamos escribir algo como esto:
# Calculo de los cuadrados con condición de salida
a= 1

while(a > 0):


a = input("Dáme un numero: ")
a= int(a)
print("El cuadrado de ",a," es: ", a*a)
print("-----------")

Hacemos que a tenga un valor inicial de 1, para que se cumpla la primera vez la condición de
que se ejecuta el bucle y todo sigue si ritmo hasta que demos el valor 0:

Dáme un numero: 7
El cuadrado de 7 es: 49
Dáme un numero: 3
El cuadrado de 3 es: 9
Dáme un numero: 0
El cuadrado de 0 es: 0
3 Clase
RASPBERRY PI Y LOS PULSADORES.

En capítulos previos hemos visto cómo usar los GPIO de nuestras Raspberry Pi para activar
señales digitales al exterior, como por ejemplo encender o apagar un LED. Es decir hemos
visto cómo usar los GPIO como puertas de salida digitales.
En este capítulo vamos ver cómo usar los GPIO para leer señales digitales del exterior, es
decir usarlas como entradas digitales, y para ello nada mejor que ver cómo podemos hacer
para leer un humilde pulsador digital.
Estos pulsadores son de lo más sencillos y simplemente pueden adoptar dos estados posibles
abiertos cuando no están pulsados y cerrados cuando lo están.
Aparentemente nada hay más inocente que un pulsador, pero pronto iréis viendo que estos
componentes son diabólicos y consiguen marearte con una facilidad que suele sorprender a
los novicios despistados. Pero hacedme caso. La capacidad de un humilde pulsador para
generarte dolores de cabeza es proverbial.
Aunque parecen componentes inocentes, pueden marearte de mil formas distintas y por eso
procuraremos ir viendo paso a paso alguno de los problemas típicos que aparecen y también
las soluciones clásicas para evitar discos problemas
Esta sesión va, pues, de cómo leer señales del exterior y de paso como vamos a usar un
pulsador para generar esas señales a leer, ver cómo usarlos con un mínimo de problemas.

HABLEMOS DE PULSADORES

Cuando un pulsador se activa, lo normal es que cierre un circuito y si el otro extremos está
conectado a digamos tensión, leemos ese valor, y consideramos un HIGH en la lectura.

Muchos de estos pulsadores que podemos encontrar en el mercado disponen de un par de


contactos unidos internamente, como en la imagen que os pongo arriba. Al pulsar el contacto
el circuito se cierra y con nuestra Raspberry podemos leer el valor que hay en RPI, para
reconocer que el botón ha sido activado. Tenemos una medida clara de tensión alta o Vcc.
Hasta aquí no hay problema, pero ¿Qué pasa cuando dejas de pulsar el botón? Como el
contacto está abierto no leemos tensión y por tanto suponemos que la lectura es 0V o tensión
Low.
Pero queridos amigos, este es uno de esos casos en los que suponer cosas puede marearte
porque lo que leemos en el caso de pulsador abierto no tiene por qué ser 0. Es lo que en la
jerga llamamos contacto flotante y su valor de lectura es imprevisible y poco más o menos
aleatorio.
¿Te resulta difícil de creer? Claro, porque todos pensamos que la ausencia de tensión es 0,
pero no. Esto es rotundamente falso. Lo cierto es que ese hilo RPI, al no estar conectado al
GND del circuito del botón, está flotando, es decir baila alegremente de tensión provocado por
influencias externas como emisiones de radio o simple electrostática, y las lecturas que hagas
tienen más que ver con el azar que con un valor real.
Recuerda que necesitamos asegurar que el GND de todos los componentes es el mismo, so
pena de quemar algo. Y esto nos lleva a la vieja cuestión de las medidas de tensión son como
las medidas de altura del agua, que dependen de donde lo midas, porque necesitas una
referencia de base (¿Qué altura tiene el agua en una bañera de un 5º piso?)
Todo este rollo viene a que si queremos tener una medida clara leyendo un pulsador,
necesitamos asegurar que no hay un contacto flotante y para eso se suele usar un circuito
más o menos así:

Fíjate que si el pulsador está abierto, el input será HIGH o 5V porque forzamos la lectura de la
tensión a través de R1 y R2. Pero si pulsas el contacto, la entrada leerá 0V o LOW, porque la
tensión se desviará a GND impidiendo que la tensión suba en R2 (Por eso hemos puesto R1,
para evitar un corto)
En la jerga, cuando conectamos R1 a Vcc, decimos que es un circuito con resistencia Pull Up,
porque cuando está abierto leemos valor alto (De ahí lo de Up).Pero también podemos invertir
los 5V y GND, con lo cual crearíamos un circuito de Pull Down, ya que leeríamos GND o 0 al
estar abierto y HIGH al pulsar.
Aunque te pueda parecer un poco raro ahora, dale una pensada y verás como lo ves claro
enseguida, es más, si te resulta extraño, prueba a montar esos circuitos y lo compruebas.
Para leer un pulsador siempre necesitamos un circuito de Pull Up o Pull Down, lo que resulta
bastante engorroso y más aún, las resistencias adicionales cuestan pasta, por lo que si a ti te
molesta, no te digo a los que fabrican electrónica a gran escala.
Por eso casi todos los controladores modernos como Arduino o Raspberry Pi incluyen un
truco para evitar ese engorro y pueden activar ellos mismos resistencias internas de Pull up
que te evitan incluirlas en tu circuito.
¿Y porque no hemos empezado por ahí, en lugar de contarme toda esa historia de
miedo? Pues básicamente porque si no entiendes la necesidad de los Pull Up, no entenderás
cuando debes usarlos y te vas a llevar más de un chasco con los botones (Y otras cosas).
Pero no te creas que los problemas de los pulsadores se acaban ahí, ¡Para nada! Otra de las
malas costumbres de los pulsadores, es que el contacto no se cierra sin más cuando pulsas,
No señor.
Más bien rebotan varias veces, haciendo positivos y negativos repetidos hasta que se
estabilizan y ya marcan un valor estable. Si esto te suena raro, es porque nosotros somos
demasiado lentos para apreciarlo, pero tu Arduino o Raspberry pueden detectarlos porque
son varios miles de veces más rápidos que tú y yo, y pueden contar esos rebotes y si lo haces
te llevaras una sorpresa.
Por eso hay que limpiar un poco el rebote (Bouncing en inglés) y a la técnica para limpiarlo se
llama debouncing en la jerga habitual del gremio.
En esta sesión vamos a ver como leer correctamente un pulsador con su Pull Up y como
hacer el debouncing del mismo. Pero no te asustes que usaremos las resistencias internas de
la Raspberry para ello en lugar de usar resistencias externas.

LEYENDO UN PULSADOR

Vamos a empezar por proponeros un pequeño circuito con un pulsador y un Led. La idea es
poder ver como el Led se ilumina cuando pulsamos el botón o al revés. Y para ello podemos
montar algo como esto:
He usado la nomenclatura BCM para los pines y ahora ya podemos pasar a ver el programa,
pero antes conviene que hablemos de lo que son los Cobbler, para evitar que nuestra
Raspberry pase a mejor vida.

EL COBBLER

En el último ejemplo hemos sacado 3 cablecitos de nuestra Raspberry, pero a medida que
vuestros montajes se vayan complicando la cosa va a empeorar y complicarse más. Hemos
ido conectando los diferentes pines a las conexiones que nos interesaban, pero naturalmente
hay un problema que consiste en que la Raspberry no rotula el nombre de los pines en la
placa, lo que nos obliga a contar los GPIO donde conectamos.
Esto es algo que en el futuro procuraremos evitar, porque ciertos errores a la hora de contar
pines pueden llevarnos a un pequeño chispazo y un entierro lamentable de nuestra
buena amiga la Raspi y al precio que van, conviene reducir las defunciones al mínimo.
El caso es que yo tengo aprecio a mi Raspberry, porque lleva conmigo muchas batallas y por
eso cuando vayamos a conectar más allá de 3 o 4 GPIO a nuestro proyecto, voy a usar a
partir de ahora un Cobbler como este:
Su uso no es imprescindible, claro está, pero tiene la ventaja de que podemos sacar un
conector plano de nuestra Raspberry y pasarlo al Cobbler que lo insertamos en la protoboard
y desde ahí sacar los cables a nuestros circuitos.
No es a prueba de errores, pero normalmente los Cobbler llevan rotulados los nombres de los
pines a usar lo que ayuda a no equivocarse, por lo que es un aditamento que os recomiendo
sin reservas porque seguramente os ahorrara cambiar de Raspberry cada tanto tiempo.
Nosotros podemos publicar los circuitos que vayamos probando sin dibujar directamente
el Cobbler, pero creedme, yo siempre lo uso en medio para evitar desgracias.
En mi caso el circuito ya montado con todo, Led y pulsador queda más o menos así:
Bueno pues una vez dicho esto y evitado en la medida de lo posible un inútil derramamiento
de Raspis, podemos seguir con los programas para leer el pulsador

PROGRAMAS PARA LEER EL PULSADOR

Para poner en marcha el programa vamos a presentar una nueva instrucción de Python 3
llamada if. Si estáis habituados a cualquier otro lenguaje, los condicionales con if son
similares en Python (Aunque también tiene sus ventajillas, como no)
Para quienes os acerquéis por primera vez a la programación, vale la pena comentar que en
muchas ocasiones en tus programas necesitas comprobar si una condición dada se cumple o
no. Y en función de ello tomar un curso de acción u otro. Y ese es el caso para saber si un
botón ha sido pulsado.
La instrucción if tiene en su forma más básica algo parecido a esto:

If condición:
Instrucción 1
Instrucción 2
....

Si la condición se cumple (Es evaluable a True) se ejecutan las instrucciones que vienen en el
bloque a continuación (Fíjate que acaba en : como siempre que puede ir un bloque de
instrucciones) y en caso contrario ignora el bloque y continua la ejecución a partir de este.
Como es nuestro primer uso no voy a complicar más el tema por ahora, pero en otro momento
veremos que tiene más opciones disponibles.
Empezamos el programa con los import precisos que ya conocemos de sesiones previas:

import RPi.GPIO as GPIO


import time
GPIO.setmode(GPIO.BCM)

Ahora tenemos que informar a nuestra Raspberry que vamos a usar nuestro pin 24 como
entrada:

GPIO.setup(24, GPIO.IN)

Esta es la forma más habitual de definir un pin de la Raspberry como de entrada, pero tiene el
molesto inconveniente de necesitar usar una resistencia de Pull up o pull down para operar
correctamente, como ya comentábamos arriba.
Afortunadamente, nuestra Raspberry incluye una orden para activar estas resistencias de Pull
up internamente y olvidarnos de hardware adicional, haciendo la definición del pin de marras
de esta manera

GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP)

Que puedes leer como: Define el pin 24 como de entrada y para leerlo activa una resistencia
interna de pull up. En Raspberry, a diferencia de Arduino, que solo permitía activar
resistencias internas de pull up, también podemos activarlas de pull down usando el
asombroso comando:

GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

Y ahora para leer nuestro botón, basta con leer el GPIO 24 y asignarlo a una variable como
Status con la instrucción:

Status = GPIO.input(24)

El programa completo puede quedar algo parecido a esto:

import RPi.GPIO as GPIO


import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP)

while True:
Status = GPIO.input(24)
if Status == False:
print(”Botón pulsado.”)
time.sleep(0.2)
Después de las definiciones, usamos un bucle while para que lea de forma continua el valor
del GPIO y se asigna a la variable Status.
Como hemos activado una resistencia de pull up para leer el botón, devolverá un valor HIGH
cuando este sin pulsar y False cuando se pulse. Por eso lo que hacemos con el if es
comprobar si el status es False, y en caso afirmativo sacamos un mensajito diciendo que
hemos pulsado sin más.
Para los que vienen de C++ o Java, de nuevo fijaros que marcamos el bloque simplemente
como un indentado después del símbolo : . Y al igual de en C++, para comprobar si Status es
False la instrucción es:

if Status == False:

Y no esto otro:

if Status = False:

Algo que da a los novatos muchos dolores de cabeza al principio. La primera instrucción
comprueba si Status es True o False, pero la segunda asigna el valor False a Status si o si, y
una vez hecho decide si es verdadero o Falso el valor. Y como acabamos de hacer que Status
es False la condición no se cumplirá nunca y nunca veréis escrito el resultado de que han
pulsado el botón
Dicho así parece un trabalenguas, por lo que os animo a que le dediquéis un momento a
pensarlo y a ser posible que hagáis el programa con estas dos líneas para que veáis el
resultado. Es más fácil de lo que parece.
Por último, los lectores avispados, se habrán percatado de que hay una instrucción
sospechosa al final del bloque:

time.sleep(0.2)

La idea es que para evitar rebotes, dormimos a nuestra Raspberry durante 2 décimas de
segundo para impedir que pueda leer repetidamente la entrada GPIO y detectando los
correspondientes rebotes.
Al dormir un poco la lectura le impedimos que le dé tiempo a ver los rebotes que suelen tardar
menos de esos 0,2 segundos que le dormimos.
Cuando probéis el circuito, veréis que cunado pulsas el botón te saca un simple mensaje de
se ha pulsado el botón y poco más.
¿Cómo hacemos para que además el LED indique el estado del contacto? Esto ya deberías
saber hacerlo tomando instrucciones de las últimas sesiones y te recomiendo que intentes
hacerlo por ti mismo, pero por si acaso aquí está una solución:
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(23, GPIO.OUT )

while True:
input_state = GPIO.input(24)
if input_state == False:
GPIO.output(23, True) # Enciende el LED
print('Botón pulsado')
time.sleep(0.3)
GPIO.output(23, False) # Apaga el LED

4 Clase

OPERANDO CON EL TIPO BOOL

El tipo Bool puede tomar solo dos valores, que en programación llamaremos True y False.
Los novatos suelen preguntar algo como ¿No es un poco excesivo tener todo un tipo para algo
tan sencillo? Y la respuesta corta es: No señor.
El tipo Bool es imprescindible para todo tipo de problemas de lógica y para poder plantear de
forma univoca cualquier problema de toma de decisiones en tus programas, de modo que no
admita interpretaciones (Algo que es el fundamento básico de todos los programas)
De acuerdo pues ¿Cómo definimos una variable Bool en Python? Sencillamente asignándola
el valor True o False.

>>> a = True
>>> b = False
>>> print(a)
True
>>> type(a)
<class 'bool'>

Una vez que tenemos definidas un par de variables de tipo Bool podemos operar con ellas con
bastante comodidad mediante los operadores lógicos que básicamente son AND, OR y NOT.
El operador AND devuelve True si ambos valores son True, y False si cualquiera de ellos es
False. En cambio el Operador OR devuelve el valor TRUE si cualquiera de ellos o ambos, es
True:

>>> a and b
False
>>> a or b
True

Habitualmente se parece mucho a nuestra forma de hablar cuando dices que la puerta la
pueden abrir o bien Pedro o bien Ana, si ambos tienen llave, Pero no te fíes y revisa la lógica
detrás de las frases que nosotros no siempre somos todo lo estrictos hablando como lo es un
ordenador.
El siguiente operador es el NOT, que resulta bastante fácil de entender: Es lo contrario del
valor actual:

>>> print(a,b)
True False
>>> print(not a, not b)
False True

El objetivo de todo esto es que al final, puedas tomar decisiones en tus programas. Ya vimos
en una sesión anterior que podíamos utilizar la instrucción if para tomar decisiones en tu
programa y ejecutar unas instrucciones u otras en función de la condición que le pasábamos.
Si haces un poco memoria recordaras que planteábamos algo asi:

If (condición)
………………..
…………………
Más instrucciones

La condición que le pasamos a la instrucción if DEBE poderse evaluar a un valor Bool, para
determinar unívocamente si las intrucciones que siguen deben o no ejecutarse. Debe ser un
True o False y nada de grises borrosos. Lo uno o lo otro. Y a veces tendrás que operar con
condiciones múltiples que ligaras con los operadores AND, OR y NOT.
De hecho es un buen momento para ampliar la instrucción if, con más opciones. Puedes usar
la cláusula else:

a = input ("Dame un numero")


if int(a) > 5:
print("Es mayor de 5")
else:
print("Es un número pequeño")

Como en tantos lenguajes, la cláusula else complementa el if, haciendo que si la condición
que se le pasa es cierta ejecuta las instrucciones a continuación, y en caso de ser falsa,
ejecuta el bloque de instrucciones que sigue al else. Nunca se ejecutaran ambos bloques:
Sera uno u otro pero no ambos, y por eso es necesario que la condición que le pasemos sea
clara.
• Fíjate que tanto if como else llevan dos puntos al final. Todas las cláusulas que aceptan
bloques deben finalizar con dos puntos
Pero en Python la instrucción if acepta aún más cláusulas para facilitar la vida a los
programadores. Veamos la instrucción elif:

a = int(input("Dame un numero: "))


if a < 0:
print ("Es negativo.")
elif a == 0:
print("Es cero patatero.")
elif a > 0:
print("Es positivo.")

Cuando corras el programa verás que va comprobando las distintas condiciones de los elif
hasta que encuentra una True y la ejecuta, obviando las demás:

Dame un numero: 0
Es cero patatero.

Elif permite ir evaluando a True o False una serie de condiciones dispersas en secuencia para
realizar unas acciones u otras en función de las condiciones que le pasemos. Es un sistema
cómodo de aplicar condiciones múltiples y actuar en consecuencia. Y por supuesto se puede
combinar los elif con el else al final.
Por ejemplo, complicando un poco (Solo un poco) el programa podemos ilustrar un ejemplo de
todo a la vez incluyendo el uso de and:
a = int(input("Dame un número: "))
if a > 0 and a < 10:
print ("Es pequeño.")
elif a>=10 and a < 100:
print("Es mediano.")
elif a >= 100:
print("Es grande.")
else:
print("Debe ser negativo.")

Hemos ido pasando condiciones al if y elif que son eliminatorias, es decir solo una puede ser
cierta, y para ello hemos tenido que aplicar condiciones que limiten el valor de los números
entre unos márgenes y eso nos obliga a utilizar una condición compuesta por dos condiciones.
Si cualquiera de ellas se cumple disparamos el mensaje pertinente y si ninguna es cierta el
último else, dispara y supone que el número es negativo.
La combinación de if, elif, else es una construcción excepcionalmente útil para comprobar
condiciones concatenadas y más aún para hacerlo de un modo ordenado. (Los que vengáis
de C++ o Java, veréis que es mucho más práctica que la instrucción Switch y con más
posibilidades).

EVALUANDO CONDICIONES

Los chicos listos os habréis fijado que hemos hablado de variables Bool que aceptan los
valores True o False y de que se puede operar con ellas usando AND, OR y NOT y sin mediar
palabra os he metido de matute unas ciertas condiciones que no tenían nada que ver con
esto.
Por ejemplo hemos usado condiciones como:

if a > 0 and a < 10:

Donde ninguno de los operandos son una variable Bool, y sin embargo Python se lo ha
tragado tranquilamente y probablemente la mayor parte de los que lo habéis leído os ha
parecido tan normal.
El motivo es que para nosotros es muy intuitivo aceptar como ciertas o falsas el resultado de
las comparaciones, y por eso los lenguajes de programación se aprovechan y nos permiten
escribirlas de un modo que nos resulta natural, calculando el resultado de la comparación a
True o False y pasándole ese resultado a la función if.
Pero necesitamos comentar un poco que operadores tenemos para hacerlas y que reglas
siguen. En primer lugar podemos usar los siguientes operadores entre números para
compararlos:
> Mayor que
>= Mayor o igual que
< Menor que
<= Menor o igual que
== Igual que
!= Diferente que
Fijaros especialmente en la comparación de igualdad, si sois novatos porque suele ser algo
que despista mucho. Si escribes un programa así, te vas a llevar una sorpresa:

if a = 6:

Esto dispara un ladrido inmediato del compilador porque no acepta el operador de asignación
=, como operador de comparación (A diferencia de C++ que hubiera tragado tranquilamente)
pero hay ocasiones en que puedes llevarte una sorpresita con esto.
Conviene anotar aquí, que los operadores de comparación suelen estar sobrecargados
(Overloaded) para realizar una función u otra dependiendo del tipo de los operandos. Por
ejemplo si se usan con tipos String (De los que aún no hemos hablado, pero que tendremos
que hacerlo pronto) puede dar resultados extraños al principio:
>>> a="Buenos"
>>> b="Días"
>>> a >b
False

Este extraño resultado se debe a que las comparaciones entre Strings se hacen por orden
alfabético y por eso la B de Buenos va antes de la D de Días, y Python considera por tanto,
que la D es mayor porque va después que la a.
Puede parecer extraño pero resulta muy útil en algunas ocasiones como iremos viendo poco a
poco.
5 Clase
RASPBERRY PI Y LAS SALIDAS ANALÓGICAS

Hasta ahora hemos usado señales digitales en nuestra relación con el mundo exterior,tanto
para para leer como para enviar mensajes. Pero naturalmente, el mundo exterior es más bien
analógico la mayor parte de las veces y necesitamos algún medio de enviar y recibir señales
analógicas a nuestros dispositivos externos.
Por ejemplo ya vimos que con una señal digital podemos encender y apagar un LED pero
¿Qué pasa si tenemos el día caprichoso y queremos variar el brillo de nuestro led (Dimming)?
Pues naturalmente que de algún modo tendremos que enviar una señal proporcional al valor
de intensidad que queremos producir en la intensidad del led… y aquí salta el primer
problema: Puedo enviar unos y ceros pero no enviar medios valores o tercios… así que
¿Ahora qué?
Para los que venís del mundo Arduino o electrónico la solución es obvia: una señal PWM.
Pero para los que están empezando con esto, necesitamos comentar un poco que es algo de
nombre tan amenazador y de paso como controlarlo con nuestra vieja Raspberry.
Y esta es una de esas ocasiones en que para poder continuar tenemos que empezar con uno
de esos rollitos teóricos que tanto nos gustan y que espero no asusten a nadie, porque como
siempre es una idea muy sencilla, y astuta, que nos resuelve un problema peliagudo mediante
un ingenioso truco que os aseguro que es mucho más fácil de lo que parece al principio.

LAS SEÑALES PWM

Suponte que tienes el grifo abierto, llenándote un vaso de agua y te das cuenta de que estas
a punto de alcanzar el límite. Normalmente no cerramos de golpe el grifo para cortarlo. Más
bien giras el grifo controladamente para controlar el volumen de agua que pasa y disminuir el
caudal saliente.
Y a medida que te acercas al límite continuas girando el grifo y disminuyendo el paso de agua
para poder afinar con precisión en la altura exacta de agua que deseas en el vaso.
Estoy seguro de que tienes dominado el procedimiento. Es tan habitual que no pensamos
mucho en ello. En realidad estás haciendo una regulación automática del flujo de agua,
controlando el caudal que permites y como lo haces con un grifo mecánico, estas modificando
de modo analógico el caudal de agua que el permites salir.
Pero, si intentamos hacer algo así con un sistema digital tenemos un pequeño lio, porque
digitalmente puedo abrir el grifo (1) o cerrarlo (0) pero no puedo modificar el flujo de una
manera sencilla.
Podemos claro está, abrir y cerrar el grifo rápida y sucesivamente para r permitiendo que
pequeños chorros de agua vayan saliendo y si somos un poco hábiles conseguiremos una
buena aproximación a llenar el vaso sin derramarlo, pero suena un poco raro ¿No? Tenemos
que ser rápidos y precisos. Algo que no se nos suele dar muy bien pero que curiosamente a
los ordenadores se les da genial.
Por eso, cuando tenemos que usar un sistema digital que simule una señal analógica
podemos usar una señal PWM (Pulse Width Modulation) donde hacemos exactamente eso:
Abrir y cerrar con rapidez el grifo electrónico con suficiente velocidad para que engañemos a
nuestros sentidos.

Imagínate que podemos medir el tiempo con precisión y dividimos un segundo en 500 partes,
más que de sobra para que nuestros sentidos no lo noten. Ahora jugamos con cuanto tiempo
mantenemos abierta la señal de tensión digital que ponemos.
La idea es que en cada parte vas a mantener la señal en alto un porcentaje del tipo total
posible (La anchura del pulso que hayamos elegido)
Si por cada división de las 500, mantenemos abierta la tensión (O el grifo que para el caso es
lo mismo) una porción de la misma, digamos un 5%, nos encontraremos con que la tensión
promedio a la salida (O tensión eficaz) es un 5% de la que supondría mantener siempre la
señal alta
Podemos jugar con el porcentaje de tiempo que mantenemos abierta la tensión de forma más
o menos arbitraria: 50% o 90% en el ejemplo de arriba.
Aunque te puede parecer raro, las señales eléctricas no se disipan de forma instantánea sino
que de alguna manera el mundo analógico del exterior percibe esto como una corriente que es
el una proporción de la tensión que supondría tener abierto siempre el valor máximo
El resultado final es que a la salida vemos una tensión que varía proporcionalmente al
porcentaje del tiempo que mantengo alta la señal, y estamos generando una muy buena
aproximación a una señal analógica mediante conmutar con rapidez la proporción de tiempos
en que la señal esta alta o baja.
¿Qué te parece el truco? Por eso lo llamamos modulación de ancho de pulsos (PWM)
porque el valor eficaz de la tensión de salida depende directamente del ancho del pulso, o si lo
prefieres de otro modo, de la proporción entre el ancho del pulso activo y el ancho de pulso a
0 voltios.
Naturalmente esto tiene que ser suficientemente rápido para que nuestro ojo no vea el truco,
pero fíjate que nuestro ojo detecta variaciones por encima de o alrededor de una décima de
segundo y aquí estamos hablando de cambio 500 veces por segundo.
Esa es una velocidad muy lenta para un circuito electrónico, pero que queda muy lejos de
nuestras posibilidades. Si le pasamos una señal así a un led, veremos algo parecido a esto

Una vez que entendamos el truco (Va, que no es para tanto) necesitamos definir un par de
variables que definan nuestro ciclo de modulación de pulsos o PWM, y como ya sabemos
cómo es esto, os encontrareis con algunos nombres raros que harán parecer todo muy
complicado, pero que va, es una tontería.
En primer lugar la frecuencia de la señal PWM: Hemos dicho arriba que podíamos dividir el
tiempo de un segundo en 500 pedazos y jugar con la extensión del pulso en cada pulso. Pues
oh sorpresa 500 es lo que llamamos la frecuencia base de la señal.
Podemos decidir partirlo en solo 20 (No es demasiado recomendable, porque está muy cerca
de la décima de segundo que percibe nuestro ojo) y entonces diríamos que la señal base es
de 20Hz ¿Qué te parece?
El siguiente término es el Duty Cycle, que es un porcentaje. Es la proporción entre el tiempo
que tenemos alta la señal y el máximo tiempo posible. O dicho de otro modo: si tengo la señal
con tensión alta un 60% del tiempo es un duty cycle del 60%.
Así que una vez visto todo esto, vamos a montar un pequeño circuito que modifique el brillo de
ese led, mediante nuestra Raspberry Pi y veremos como modificar las caracteristicas de la
señal PWM.

ESQUEMA DE MONTAJE

El esquema eléctrico del circuito es de lo más sencillo. Simplemente conectamos el GPIO 24al
positivo de un LED mediante una resistencia de 1K, y la otra pata a GND para cerrar el circuito

USANDO PWM CON PYTHON

Como siempre con Python, vamos a empezar importante la librería de control de los GPIO y
también la librería Time para regular el tiempo de encendido del led:

import RPi.GPIO as GPIO


import time
GPIO.setmode(GPIO.BCM)

Definimos el GPIO 24 como salida

GPIO.setup(24, GPIO.OUT)

Ahora necesitamos crear un objeto el pin 24 que gobernara la modulación PWM y vamos a
llamarla rojo porque ese es el color del led:

rojo = GPIO.PWM(24, 100)


rojo.start(100)

La idea es sencilla. Una vez definido el pin GPIO como salida creamos un objeto del
tipo PWM en el pin 24, con una frecuencia de ciclo de 100, o lo que es lo mismo dividimos en
100 partes un segundo y después lo iniciamos con el valor primero, 100 en este caso, o sea,
encendido a tope.
Esto es un tanto diferente de la manera como lo hacíamos con Arduino en que
especificábamos un porcentaje del ciclo y no podíamos cambiar la frecuencia, pero la idea de
fondo es la misma y no sería demasiado complicado definir una función que hiciese lo mismo
que en Arduino, pero todo llegará.
Ya solo falta ir modificando el duty cycle o porcentaje útil del pulso PWM (Como en Arduino)
mediante la instrucción:
rojo.ChangeDutyCycle( x )

Donde x es un numero entero entre 0 y 100. Veamos cómo quedaría un programa más o
menos completo que varíe la intensidad del led:

import RPi.GPIO as GPIO


import time
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

GPIO.setup(24, GPIO.OUT)
rojo = GPIO.PWM(24, 100)
rojo.start(100)

while True:
for i in range(100,-1,-1):
rojo.ChangeDutyCycle(100 - i)
time.sleep(0.02)
print("Ciclo completo")

Como veis, la idea de generar una señal PWM que simule una señal analógica es igual de
sencilla en Raspberry que en Arduino, pero tiene un par de diferencias como que hay que
definir e inicializar un objeto asociado a un pin previamente definido como salida, e indicarle la
frecuencia de la señal y el porcentaje del Duty Cycle, pero sigue siendo la misma idea

• Es la primera vez que usamos indentados anidados con Python. Esto es porque hasta ahora
no habiamos montado un programa con mas de un bucle.
• Lo importante aqui es que le dejes al editor de Python que marque el los indentados, porque si
lo haces tu, la cosa se va a liar.
• Fíjate que el ultimo print, está a la altura del for por lo que solo se ejecuta cuando este for
termina.

También podría gustarte