Python GPIO triggering LED with Pushbutton - python

I am trying to control and LED on an Raspberry Pi.
I want the LED to light up when I push a button, and maintain that state until I push the button again.
I have implemented the code below and it works quite fine. However, I am getting problems when I am not fast enough in pushing the button or hold the button.
import RPi.GPIO as GPIO
from time import sleep
inpin = 16
outpin = 20
GPIO.setmode(GPIO.BCM)
counter = 0
GPIO.setup(outpin, GPIO.OUT)
GPIO.setup(inpin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
try:
while True:
if GPIO.input(inpin):
if counter == 0:
print "port is low"
GPIO.output(outpin, 0)
counter = 0
else:
print "port is high"
GPIO.output(outpin, 1)
counter = 1
else:
if counter == 1:
print "port is low"
GPIO.output(outpin, 0)
counter = 0
else:
print "port is high"
GPIO.output(outpin, 1)
counter = 1
sleep(0.1)
finally:
GPIO.cleanup()
Implementing it the way "TessellatingHeckler" suggested works perfect.
Even with multiple inputs and outputs it works perfect.
Important things are the "elif" loops to guarantee fast changing states.
Here's the working code:
import RPi.GPIO as GPIO
from time import sleep
GPIO.setmode(GPIO.BCM)
GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(20, GPIO.OUT)
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(27, GPIO.OUT)
btn1_button = 'up'
btn1_light = 'off'
btn2_button = 'up'
btn2_button = 'off'
def LED1(output):
GPIO.output(20, output)
def LED2(output):
GPIO.output(27, output)
while True:
######################## BUTTON 1 ########################
if (btn1_button == 'up' and btn1_light == 'off'):
if not GPIO.input(16):
print "LED1 ON"
LED1(1)
btn1_button = 'down'
btn1_light = 'on'
elif (btn1_button == 'down' and btn1_light == 'on'):
if GPIO.input(16):
btn1_button = 'up'
elif (btn1_button == 'up' and btn1_light == 'on'):
if not GPIO.input(16):
print "LED1 OFF"
LED1(0)
btn1_button = 'down'
btn1_light = 'off'
elif (btn1_button == 'down' and btn1_light == 'off'):
if GPIO.input(16):
btn1_button = 'up'
###########################################################
####################### BUTTON 2 ##########################
if (btn2_button == 'up' and btn2_light == 'off'):
if not GPIO.input(17):
print "LED2 ON"
LED2(1)
btn2_button = 'down'
btn2_light = 'on'
elif (btn2_button == 'down' and btn2_light == 'on'):
if GPIO.input(17):
btn2_button = 'up'
elif (btn2_button == 'up' and btn2_light == 'on'):
if not GPIO.input(17):
print "LED2 OFF"
LED2(0)
btn2_button = 'down'
btn2_light = 'off'
elif (btn2_button == 'down' and btn2_light == 'off'):
if GPIO.input(17):
btn2_button = 'up'
sleep(0.1)
###########################################################
GPIO.cleanup()

You wrote this plan in words:
Button pressed, light goes on
Button pressed, light goes off
But what you've written in code is more like:
10x per second,
If the button is up, do nothing
If the button is pressed, toggle the light
Which is quite different. Hold the button for more than 1/10th of a second and it starts to go weird. What I meant by my comment is that your code goes through the loop and every time it tries to update everything; you're tracking what happened the last time through the loop, which means you can't hold anything more than one loop duration. Instead you need to separate the loop from the state tracking, so the state can stay the same over and over, and only let the dog eat the biscuit when the button changes.
It's the button which drives the system state, not time passing. The system can be in 4 possible states, like this:
(Button=Up, Light=Off) <----------------
| |
| Button pushed down |
\/ |
(Button=Down, Light=/On/) |
| |
| Button released |
\/ |
(Button=Up, Light=On) |
| |
| Button pushed down |
\/ |
(Button=Down, Light=/Off/) |
| / \
| Button released |
| |
-------------------------------
If you explicitly code those states and follow the sequence, let the button be the only thing allowing you to go from one to the next ... you can't possibly get any weird behaviour from holding the button too long. I hope. Your current code jumps from (Button=Down, Light=On) to (Button=Down, Light=Off) and back again.
My code here is untested, and I'm not completely sure which way the GPIO.input() goes when the button is pressed and released. I assume it's 0/False most of the time and 1/True when the button is pressed.
import RPi.GPIO as GPIO
from time import sleep
inpin = 16
outpin = 20
GPIO.setmode(GPIO.BCM)
GPIO.setup(outpin, GPIO.OUT)
GPIO.setup(inpin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
button='up'
light='off'
while True:
if (button=='up' and light=='off'):
# wait for button press before changing anything
if not GPIO.input(inpin):
GPIO.output(outpin, 1)
button='down';
light='on'
elif (button=='down' and light=='on'):
# stay in this state until button released
if GPIO.input(inpin):
button='up'
elif (button=='up' and light=='on'):
if not GPIO.input(inpin):
GPIO.output(outpin, 0)
button='down'
light='off'
elif (button=='down' and light=='off'):
if GPIO.input(inpin):
button='up'
sleep(0.1)
So, button and light track the state of the system. Every time through the loop, only one of the if blocks will match, and it will mostly do nothing until it gets the button change that makes the state change to the next one.
First time through, the first block matches, it checks for a button press. It keeps doing that.
You press the button, now the first block lights the LED and updates the state.
Now, every time through the loop, (button=='down' and light=='on') matches. It's in state 2 and it stays in that state for as long as you press the button. Every time through the loop it looks for the button release, and that's the only thing that can trigger any state change.
etc.

Try the following, This eliminates "led-on" problem at start:
import RPi.GPIO as GPIO
from time import sleep
inpin = 11
outpin = 7
GPIO.setmode(GPIO.BOARD)
GPIO.setup(outpin, GPIO.OUT)
GPIO.setup(inpin, GPIO.IN)
x=0
y=0
try:
while True:
if (x==0 and y==0):
# wait for button press before changing anything
if GPIO.input(inpin) == 0:
GPIO.output(outpin, 0)
x=0
y=1
print("led off")
elif (x==0 and y==1):
# stay in this state until button released
if GPIO.input(inpin) == 1:
x = 1
elif (x==1 and y==1):
if GPIO.input(inpin) == 0:
GPIO.output(outpin, 1)
x=1
y=0
print("led on")
elif (x==1 and y==0):
if GPIO.input(inpin) == 1:
x=0
sleep(0.1)
except KeyboardInterrupt:
GPIO.output(outpin, 0)
GPIO.cleanup()

Related

how do I loop servo motor and stop and loop again?

I bought mg995 servo motor but it seems controlling is different from the mg90 because it is digital.
What I want to do is spinning mg995 loop, stops when I press ctrl+c and starts loop again when I press the enter. the code is below but it won't loop again after servo1.stop()
from cmath import inf
from PIL import Image
import numpy as np
import RPi.GPIO as GPIO
from time import sleep
################# -----------------------------
GPIO.setmode(GPIO.BCM)
servo1_pin = 18
GPIO.setup(servo1_pin, GPIO.OUT)
servo1 = GPIO.PWM(servo1_pin, 50)
servo1.start(0)
servo_min_duty = 3
servo_max_duty = 12
def set_servo_degree(servo_num, degree):
if degree > 180:
degree = 180
elif degree < 0:
degree = 0
duty = servo_min_duty+(degree*(servo_max_duty-servo_min_duty)/180.0)
if servo_num == 1:
servo1.ChangeDutyCycle(duty)
#################-------------------------------
try:
while True:
set_servo_degree(1, 0)
except KeyboardInterrupt:
servo1.stop() # after servo stops, it won't start again.
print("should be end")
pass
go_button = input('go? press enter!')
if go_button == "":
## after press the enter, starts loop again.
try:
while True:
set_servo_degree(1, 0)
else:
break()
sleep(2)
GPIO.cleanup()
thank you!
The while loop should be outside of the set_servo_degree function.
The modified part of your code is as below
servo_num = 1
servo_deg = 0
while True:
try:
set_servo_degree(servo_num, servo_deg)
except KeyboardInterrupt:
servo1.stop()
go_button = input('go? press enter!')
if go_button == "":
set_servo_degree(servo_num, servo_deg)
else:
break
sleep(2)
GPIO.cleanup()

python - how to make a function to check if button pressed once or twice?

I am trying to make a task for school with Python. But the problem is that I don't understand how the following function works: So we are trying to make a smarthome with lights and relays(now we use LED). If we push the button once, lights go on, if we push twice within 1.5sec: all lights go on and so on...
Also we have to make a function when lights are already on...
So my question is "How do I tell or let python know that I pushed the button once or twice or more or hold it so it does a function?"
This is my code (we work with on the air uploading to Raspberry Pi
#!/usr/bin/env
__author__ = "Zino Henderickx"
__version__ = "1.0"
# LIBRARIES
from gpiozero import LED
from gpiozero import Button
from gpiozero.pins.pigpio import PiGPIOFactory
import time
IP = PiGPIOFactory('192.168.0.207')
# LED's
LED1 = LED(17, pin_factory=IP)
LED2 = LED(27, pin_factory=IP)
LED3 = LED(22, pin_factory=IP)
LED4 = LED(10, pin_factory=IP)
# BUTTONS
BUTTON1 = Button(5, pin_factory=IP)
BUTTON2 = Button(6, pin_factory=IP)
BUTTON3 = Button(13, pin_factory=IP)
BUTTON4 = Button(19, pin_factory=IP)
# LISTS
led [10, 17, 22, 27]
button [5, 6, 13, 19]
def button_1():
if BUTTON1.value == 1:
LED1.on()
time.sleep(0.50)
if BUTTON1.value == 0:
LED1.on()
time.sleep(0.50)
def button_2():
if BUTTON2.value == 1:
LED2.on()
time.sleep(0.50)
if BUTTON2.value == 0:
LED2.on()
time.sleep(0.50)
def button_3():
if BUTTON3.value == 1:
LED3.on()
time.sleep(0.50)
if BUTTON3.value == 0:
LED3.on()
time.sleep(0.50)
def button_4():
if BUTTON4.value == 1:
LED4.on()
time.sleep(0.50)
if BUTTON4.value == 0:
LED4.on()
time.sleep(0.50)
def check_button():
while True:
for i in range(BUTTON1):
toggle_button(i)
def main():
set_up_led()
set_up_button()
check_button()
# MAIN START PROGRAM
if __name__ == "__main__":
main()
Have you thought about setting up some sort of timer that goes off as soon as a button is pressed? This would then trigger a loop that will check for a given time if the button is pressed again or not. If the time has elapsed, the loop ends and it executes one instruction, and if the button has been reset, the program executes the other instruction.
import time
#define max_time to consider a double execution
max_time = 1
while 1:
time.sleep(0.001) # do not use all the cpu power
# make a loop to test for the button being pressed
if button == pressed:
when_pressed = time.time()
while time.time() - when_pressed < max_time:
time.sleep(0.001) # do not use all the cpu power
if button == pressed:
# Instructions 2
#Instructions 1

Wait for input during several iterations of a loop in python

I'm trying to write a python code to control the voltage of the GPIO Pins.
The idea behind it is that in a frequency of 1KHz if half of the time the pin is off and half of the time it is on than the voltage will be 50%.
I need to keep the while loop running while waiting for user input so that I can change the speed of the motor.
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(4, GPIO.OUT)
# The higher the number for speed the slower the motor will rotate
def motor(speed):
i = 0
run = True
# Runs until user tells it to stop
while run == True:
# Pins should vary at every second
time.sleep(0.001)
i += 1
if i % speed == 0:
GPIO.output(4, GPIO.HIGH)
else:
GPIO.output(4, GPIO.LOW)
# This block is causing the issue
# I need the loop to keep running while waiting for the input
if i % speed * 10 == 0:
com = int(input("Enter 0 to quit"))
if com == -1:
GPIO.output(4, GPIO.LOW)
break
GPIO.output(4, GPIO.LOW)
run = True;
while (run):
speed = int(input("Select Speed"))
if speed == 0:
run = False
else:
motor(speed)
GPIO.cleanup()

Change led blinking interval with button input in python

I want to change the blinking time of LED with every button press.
The code i written in python do not respond to button input clicks. what chages does it need?looks like callback isnt working
import RPi.GPIO as GPIO
from time import sleep
inbutton = 13
outpin = 7
z = 1
def init():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(outpin, GPIO.OUT)
GPIO.setup(inbutton, GPIO.IN, pull_up_down=GPIO.PUD_UP)
global z
z = 1
def zest():
global z
if z == 1:
z = 2
while z == 2:
GPIO.output(outpin, 1)
print("led on")
sleep(1)
GPIO.output(outpin, 0)
print("led off")
sleep(1)
elif z == 2:
z = 1
while z == 1:
GPIO.output(outpin, 1)
print("led on")
sleep(2)
GPIO.output(outpin, 0)
print("led off")
sleep(2)
def loop():
GPIO.add_event_detect(inbutton, GPIO.FALLING, callback=zest(), bouncetime=1000)
if __name__ == '__main__':
init()
try:
while True:
loop()
except KeyboardInterrupt:
GPIO.output(outpin, 0)
GPIO.cleanup()
On running LED blinks with 1second interval. but dont respond to button click.experts out there please have a look.
Change this line:
GPIO.add_event_detect(inbutton, GPIO.FALLING, callback=zest(), bouncetime=1000)
to this:
GPIO.add_event_detect(inbutton, GPIO.FALLING, callback=zest, bouncetime=1000)
As you have it, the callback is called once when registering it and registered callback is saved as None since that is what was returned by zest().
The callback also needs to accept a single argument: channel. So change your function definition to:
def zest(channel):

Raspberry PI: 2 buttons, 2 LEDs

I'm trying to make a Python program with Raspberry Pi that when I push a button, only the red LED brightens, and when I press another button, only the green LED brightens. When no buttons are pushed, all the LEDs are off. But when I try to run it, both LEDs stay on, and when I press the button, the monitor says I pressed it, but nothing changes. What can I do to fix this? I'm 100% certain there are no wiring problems, and the monitor shows no errors. BTW, here's the code:
import RPi.GPIO as GPIO
import time
GPIO.setwarnings(False)
red_walk_LED = 16
green_traf_LED = 15
Btn_one = 22 # pin12 --- button
Btn_two = 29 # pin29 --- 2nd button
# GLOBAL VARIABLES
red_Led_status = 1
Green_Led_status = 1
flag_btn_one_pushed = 0
flag_btn_two_pushed = 0
def all_leds_off():
GPIO.output(green_traf_LED, GPIO.HIGH)
GPIO.output(yellow_traf_LED, GPIO.HIGH)
GPIO.output(red_traf_LED, GPIO.HIGH)
GPIO.output(red_walk_LED, GPIO.HIGH)
GPIO.output(white_walk_LED, GPIO.HIGH)
def setup():
global green_LED_frequence
global red_LED_frequence
GPIO.setmode(GPIO.BOARD) # Numbers GPIOs by physical location
#set LEDs as outputs
GPIO.setup(green_traf_LED, GPIO.OUT)
GPIO.setup(red_traf_LED, GPIO.OUT)
GPIO.setup(Btn_one, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Set BtnPin's mode as input, and pull up to high level(3.3V)
GPIO.setup(Btn_two, GPIO.IN, pull_up_down=GPIO.PUD_UP)
red_LED_frequence = GPIO.PWM(red_traf_LED, 1000) # set Frequece to 1KHz
green_LED_frequence = GPIO.PWM(green_traf_LED, 1000)
red_LED_frequence.start(0) # Duty Cycle = 0
green_LED_frequence.start(0)
def Btn_one_push(ev=None):
print('OK, the 1st button was pushed')
global red_Led_status #we are allowed to change these variables in this function
global my_counter
global flag_btn_one_pushed
global red_LED_frequence
red_Led_status = not red_Led_status #change LED status 0-1 or 1-0
flag_btn_one_pushed = 1
my_delay = 0.2
GPIO.output(green_traf_LED, GPIO.HIGH)
if red_Led_status == 1: #1-on
print('ok, reds on')
for dc in range(0, 101, 4): # Increase duty cycle: 0~100
red_LED_frequence.ChangeDutyCycle(dc) # Change duty cycle
time.sleep(0.02)
for dc in range(100, -1, -4): # Decrease duty cycle: 100~0
red_LED_frequence.ChangeDutyCycle(dc)
time.sleep(0.02)
all_leds_off() #turn all LEDs off!!
flag_btn_pushed = 0
def Btn_two_push(ev=None):
print('OK, the 2nd button was pushed')
global Green_Led_status
global flag_btn_two_pushed
global green_LED_frequence
Green_Led_status = not Green_Led_status #change LED status 0-1 or 1-0
flag_btn_two_pushed = 1
my_delay = 0.2
GPIO.output(red_traf_LED, GPIO.HIGH)
if Green_Led_status == 1: #1-on
print('This is supposed to work!')
for dc in range(0, 101, 4): # Increase duty cycle: 0~100
print(green_LED_frequence)
green_LED_frequence.ChangeDutyCycle(dc) # Change duty cycle
time.sleep(0.08)
for dc in range(100, -1, -4): # Decrease duty cycle: 100~0
green_LED_frequence.ChangeDutyCycle(dc)
time.sleep(0.08)
all_leds_off() #turn all LEDs off!!
flag_btn_two_pushed = 0
def loop():
global flag_btn_one_pushed
global flag_btn_two_pushed
GPIO.add_event_detect(Btn_one, GPIO.FALLING, callback=Btn_one_push) # wait for change in GPIO 0-1 or 1-0
GPIO.add_event_detect(Btn_two, GPIO.FALLING, callback=Btn_two_push)
while True: #when the button isn't pushed, do this
all_leds_off()
else:
pass
def destroy():
all_leds_off()
GPIO.cleanup() # Release resource
if __name__ == '__main__': # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
destroy()
You should try removing these lines:
while True: #when the button isn't pushed, do this
all_leds_off()
else:
pass
and replacing them with:
all_leds_off()
The callbacks should be fired every button press.
Here is another example to look at:
https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=102631&p=760629
Also, have you tried some simple snippets of code to individually turn the LED's on and off and detect the button presses to prove that's its not a wiring problem? It doesn't take much to get the wiring wrong!

Categories