Best way to catch Low State of GPIO in an endless script - raspberry-pi

Can you please tell me what's the best way to catch a low state (or falling-edge more precisely) of GPIO in an endless script?
To be clear I will run this script at boot (in the bg) and everytime when a user will push a button (connected to this GPIO) this will put this pin at LOW state. I want to detect each one of them and perform actions at every push.
I already have this code but it will consume to much CPU I think... I need sth like an interrupt in my mind :
import RPi.GPIO as GPIO
#Set GPIO numbering scheme to pinnumber
GPIO.setmode(GPIO.BCM)
#setup pin 4 as an input
GPIO.setup(4,GPIO.IN)
# To read the state
While true:
state = GPIO.input(4)
if state:
print('on')
else:
print('off')
EDIT
Here the pinout by BCM or BOARD, I will work with BCM
As you can the the pin number is 4 because my push button is on GPIO4.
Still get off all the time with your code or constant detection of edge event with the code of #jp-jee
EDIT
#!/usr/bin/env python3
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(4,GPIO.IN)
def Callback(channel):
print('pushed')
GPIO.add_event_detect(4, GPIO.FALLING, callback = Callback, bouncetime = 300)
while(True):
time.sleep(1)
Now my code print always pushed when the button is released and print nothing when I push it...

Take a look at the documentation of raspberry-gpio-python.
What you want is GPIO.add_event_detect(channel, GPIO.RISING) in combination with a callback function.
Since you're using a button, you also need to consider bouncing.
In the end, you will end up with something like this (taken from the linked website):
def my_callback(channel):
print('This is a edge event callback function!')
GPIO.add_event_detect(channel, GPIO.FALLING, callback=my_callback, bouncetime=200)

Have you tried to use interrupts?
import time
import RPi.GPIO as GPIO
GPIO.setup(4, GPIO.IN)
def Callback(channel):
state = GPIO.input(channel)
if state:
print('on')
else:
print('off')
GPIO.add_event_detect(4, GPIO.FALLING, callback = Callback, bouncetime = 300)
while(True):
time.sleep(1)

Related

Sending commands to uart on python

I am trying to write a pyserial command to the uart port to control the robot arm.
I have some manual:
manual for arm
manual command example
I use pyserial like that:
import serial
from time import sleep
port = serial.Serial("/dev/ttyUSB0", baudrate=9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=8, timeout=1)
port.write(b"\x055\x55\x0B\x03\x02\x20\x03\x02\xB0\x04\x09\xFC\x03\xaa")
sleep(0.3)
#port.write(b"\x05")
#sleep(0.3)
#port.write(b"\x06")
#sleep(0.03)
#port.write(b"\x08\x01\x00")
print('send')
At first I tried to run it in one line, the buzzer will beep that the command was accepted, but the hand does not move.
Then I tried to split the Header separately for the Length in the next line and the Command with Parameters in the next.
Tell me how you can send these commands to the port, maybe there is something ready to do this in Python?
LSC Series Servo Controller Communication Protocol V1.2 manual says:
If the user transmits the correct data to the servo
controller, the blue LED 2 on the controller will flash one time, indicating that the
correct data have been received. If the user transmits the wrong data, then the blue
LED2 will not have any reaction and will keep the bright, then the buzzer will beepbeep twice to remind the user of the data error.
The only thing in that manual about that buzzer is that it beeps 2 times if there is a data error...

How to add conditional statement to a flame sensor?

I wanted to output 'flame detected' or 'no flame detected' but I don't know how to implement this in a code. I've seen codes from google but they are using
GPIO.add_event_detect(17,GPIO.RISING, callback = mycallback, bouncetime = 600)
which only works when it is detecting flame.
In your example you are detecting a rising edge (the pin goes from low to high). A falling edge is the opposite so you could fire a separate callback with:
GPIO.add_event_detect(17, GPIO.FALLING, callback=other_callback, bouncetime=600)
However, I'd suggest you use GPIO Zero instead of RPi.GPIO as you may find it more intuitive:
from gpiozero import InputDevice
sensor = InputDevice(17)
while True:
sensor.wait_for_active()
print("Fire!")
sensor.wait_for_inactive()
print("No fire")
You might find that the logic is reversed (says "fire" when there's no fire) in which case use InputDevice(17, pull_up=True)
Alternatively to the code above you could use if sensor.is_active or use the callbacks mechanism sensor.when_activated = callback. See the gpiozero docs for more info.

Raspberry Pi how to trigger event on pull-down interrupt pin

I have a sensor with the interrupt output connected to a input pin on my RaspberryPi. My goal is to trigger an event from the sensor interrupt. The data sheet for my sensor says that once an interrupt is triggered on the sensor, the interrupt status register will have the appropriate bit set to 1 and stay that way until it is cleared; while the status register has a status bit of 1, the interrupt pad on the sensor will be pulled down.
My problem is that I can see the status register correctly reflect an interrupt when I physically trigger the sensor. But when I read the pin from my Pi, I never see any change reflected. Here's the gist of my code:
import Sensor
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(11, GPIO.IN, pull_up_down = GPIO.PUD_UP)
s = Sensor.start()
while True:
print 'sensor int reg: ', s.readIntReg() # I do not clear interrupt
print 'pin value: ', GPIO.input(11)
The first print will change according to my interaction with the sensor as expected. The second print shows the pin holds 1 or 0 depending on whether it is set to pull up or down, respectively.
It seems like the problem lies in that whenever the interrupt fires, the sensor is pulling the pin down and the Pi is pulling it up... How should I handle this?
The sensor is the VCNL4010 [https://www.adafruit.com/products/466]
I suppose you have the gpio driver installed and active on the Pi?
Then you'll probably never see the interrupt triggering from the Python level since the kernel driver will service it (and reset the flag) already in the background.
I added a 10k external pull-up resistor with 3.3V and that did the trick... not sure why the internal pull-up on the Pi didn't do the same, perhaps I configured it wrong.
UPDATE: That turned out not to be the issue at all. I was neglecting to explicitly set the sensor to free run mode. Part of my code had the unintended side effect of setting that mode so in tweaking things for test sometimes it worked. The pull-up on the Pi works fine.

Raspberry Pi / GPIO.RISING triggers callback on .BOTH

I have a Raspberry Pi running Raspbian via NOOBS. I have a button wired to pins 1 and 11. I'm attempting to use GPIO's .add_event_detect and RPIO.RISING to call a function upon the button press. (The callback turns on an led for 2 seconds, and then turns it off.)
I'm finding that the RPIO.RISING function is calling the callback on both the button press (pin 11 goes from 0 to 1) AND the button release (pin 11 goes from 1 to 0). The light is being turned on twice, exactly as it would if I were using RPIO.BOTH.
I don't think that this is a hysteresis / noisy signal issue, because I can depress the button for many seconds, and then let go and see the callback called again.
Here is the example code:
import RPi.GPIO as GPIO ## Import GPIO library
import time
#configure all of the inputs / outputs properly
def config():
#initalize the GPIO pin numbering
GPIO.setmode(GPIO.BOARD) ## Use board pin numbering
#setup output pins
GPIO.setup(8, GPIO.OUT) ## Setup GPIO Pin 7 to OUT
GPIO.setup(10,GPIO.OUT)
GPIO.setup(12,GPIO.OUT)
#initialize the inputs for the button
GPIO.setup(11, GPIO.IN)
#create the button-watching function
GPIO.add_event_detect(11, GPIO.RISING, callback=execute_lights, bouncetime=800)
#the light-turning-on function. One press turns yellow. Second press turns green, then off.
def execute_lights(channel):
print "executing lights: "
#Turn on the light we want
GPIO.output(8,True)
#turn green off after 2 seconds
time.sleep(2)
GPIO.output(8,False)
Is there a software workaround that I can use to address this issue?
For whatever reason the implementation of bounctime is very strange.
If you hold and release your button WITHIN your set bounce time of 800ms, it should work OK. If you hold it longer, then you will get triggering on the release, sometimes. I had the same issue, thinking 'bounctime' was the time that the 'system' ignored all other inputs...like the 'settling' time for a switch. It's not. So as long as u press and release your button WITHIN your set bouncetime, you should fine it works OK.
Nick

Why does it take so long for background color to change?

I am running into a problem with a simple program that changes the color of the background when it receives a command from a different machine through TCP. It takes like thirty seconds to change the color. I am running this through the local network so it should be near instant response. I am using wxPython for the frame. I don't think I have overly complicated code. Relevant code:
threader=threading.Thread(target=self.threading)
threader.start()
def threading(self):
host="192.168.1.122"
port=4100
s=socket.socket()
s.bind((host,port))
s.listen(1)
c,addr=s.accept()
print "Connected"
while 1:
data=c.recv(1024)
if not data:
break
data=data.split("_")
reading=int(data[1])
pin=int(data[0])
if pin == 1:
if reading<20:
self.front_left.SetBackgroundColour("red")
elif pin == 2:
if reading<20:
self.front_right.SetBackgroundColour("red")
elif pin == 3:
if reading<20:
self.bottom_left.SetBackgroundColour("red")
elif pin == 4:
if reading<20:
self.bottom_right.SetBackgroundColour("red")
else:
pass
c.close()
I need this code to be instant as this will be going on a robot that will tell if objects are too close(which is why there is red background when it gets within 20 cm of object). Any help will be greatly appreciated!
It appears that you are attempting to update wxPython code from a thread. This action is unsupported / undefined in wxPython. You need to use thread-safe methods to update the wxPython UI, such as wx.CallAfter or wx.PostEvent. See the following wxPython wiki page for some examples:
http://wiki.wxpython.org/LongRunningTasks
Basically, you'll want to do something like this in your if statements:
wx.CallAfter(self.bottom_right.SetBackgroundColour, "red")