Raspberry Pi
Tutorial de Rapberry Pi en español.
- Juan Antonio Villalpando -
Volver al índice del tutorial
____________________________
6B.- Teclado keypad 4x4 con bus I2C. Pantalla LCD con bus I2C. Mover Servo.
GPIO2 es SDA
GPIO3 es SCL
- Este tutorial está basado en el ejemplo 4 del tutorial anterior (6 teclado).
- Se trata de escribir un número entre 0 y 180 en el teclado, ese número aparecerá en la pantalla LCD y además un servo se moverá a esos grados.
- Vamos a utilizar el Servo 9G que tiene un ángulo de movimiento desde 0º hasta 180º.
______________________________
1.- Conexión y script del Servo.
- Primero vamos a hacer funcionar el servo con este código obtenido de:
https://www.instructables.com/id/Servo-Motor-Control-With-Raspberry-Pi/
no necesita librería.
- Conectaremos el Servo a 5 V y el terminal de datos al terminal número 40 (GPIO21).
|
import RPi.GPIO as GPIO
from time import sleep
GPIO.setmode(GPIO.BOARD)
GPIO.setup(40,GPIO.OUT)
pwm=GPIO.PWM(40,50) # pin 40 a 50 Hz
pwm.start(0)
def SetAngle(angle):
duty = angle / 18 + 2
GPIO.output(40,True)
pwm.ChangeDutyCycle(duty)
sleep(1)
GPIO.output(40,False)
pwm.ChangeDutyCycle(0)
SetAngle(90) # Cámbia el ángulo
pwm.stop()
GPIO.cleanup()
|
- Vamos cambiando el número de SetAngle y observaremos que el Servo se situa en ese ángulo. Podemos establecer ángulos desde 0 hasta 180.
______________________________
2.- Conexión del teclado y pantalla LCD.
- Ahora vamos a añadir el teclado y la pantalla LCD, de manera que cuando escribamos un número del 0 al 180 con el teclado, y pulsemos la tecla #, el servo se moverá a ese ángulo.
- Añadido:
import I2C_LCD_driver
mylcd = I2C_LCD_driver.lcd()
mylcd.lcd_display_string(V, 1)
- El archivo de librería I2C_LCD_driver, debe estar en la misma carpeta que el tecladoLCD.py
- El archivo I2C_LCD_driver.py lo puedes obtener en el tutorial anterior sobre LCD. En ese archivo es donde se establece la dirección de la LCD, en nuestro caso la 0x27
|
#!/usr/bin/env python
import smbus
import sys
import time
import I2C_LCD_driver
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(40,GPIO.OUT)
class MyKeyboard:
#Modificado por Juan A. Villalpando http://kio4.com
KeyPadTable= [['D','C','B','A'] , ['#','9','6','3'], ['0','8','5','2'], ['*','7','4','1']]
RowID=[0,0,0,0,0,0,0,4,0,0,0,3,0,2,1,0]
CurrentKey=None
def SetAngle(self,angle):
pwm=GPIO.PWM(40,50) # pin 3 a 50 Hz
pwm.start(0)
duty = angle/18+2)
print(duty)
GPIO.output(40,True)
pwm.ChangeDutyCycle(duty)
time.sleep(1)
GPIO.output(40,False)
pwm.ChangeDutyCycle(0)
pwm.stop()
def __init__(self,I2CBus=1, I2CAddress=0x20):
self.I2CAddress = I2CAddress
self.I2CBus = I2CBus
self.bus = smbus.SMBus(self.I2CBus)
self.bus.write_byte(self.I2CAddress,0xff)
def ReadRawKey(self):
OutPin= 0x10
for Column in range(4):
self.bus.write_byte(self.I2CAddress,~OutPin)
key = self.RowID[self.bus.read_byte(self.I2CAddress) & 0x0f]
if key >0 :
return self.KeyPadTable[key-1][Column]
OutPin = OutPin * 2
return None
def ReadKey(self):
LastKey= self.CurrentKey;
while True:
NewKey= self.ReadRawKey()
if NewKey != LastKey:
time.sleep(0.01)
LastKey= NewKey
else:
break
if LastKey==self.CurrentKey:
return None
self.CurrentKey=LastKey
return self.CurrentKey
if __name__ == "__main__":
test = MyKeyboard()
mylcd = I2C_LCD_driver.lcd()
todo = ""
while True:
V = test.ReadKey()
if V != None:
todo = todo + V
mylcd.lcd_clear()
mylcd.lcd_display_string(todo, 1)
if V == '#':
sys.stdout.write(todo)
mylcd.lcd_display_string(todo[:-1], 1)
test.SetAngle(int(todo[:-1]))
#print(V)
sys.stdout.flush()
todo = ""
else:
time.sleep(0.001)
GPIO.cleanup()
|
________________________________________
Error: 1 positional argument but 2 were given
Ver
def SetAngle(self,angle):
Al invocar un método de un objeto mediante la sintaxis objeto.metodo() , el método en cuestión siempre recibe como primer parámetro el objeto en cuestión, además de todos los demás parámetros que quieras pasarle.
Esto implica más cosas a tener en cuenta y donde es fácil equivocarse (tarde o temprano a todos nos "muerde" alguno de estos problemas, a mí sobre todo el tercero):
-
Cuando declaras ese método dentro de la clase, debes siempre escribir un parámetro adicional a los que quieras que reciba. Este parámetro ha de ser el primero, y típicamente se llama self (aunque realmente podrías llamarlo como quieras, es mejor ceñirse a la norma).
-----------------------------------
- Si en algún momento recibimos el aviso " This channel is already in use, continuing anyway ", no afectará al código, podemos eliminar ese aviso escribiendo en el código
GPIO.setwarnings(False)
RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.
http://raspi.tv/2013/rpi-gpio-basics-3-how-to-exit-gpio-programs-cleanly-avoid-warnings-and-protect-your-pi
GPIO.cleanup()
___________________________________________________
|